diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js
index 80f54a83b..5e06bb675 100644
--- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js
+++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js
@@ -1,28 +1,30 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutForm", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- $scope.edit = function () {
- $scope.$root.editElement($scope.element).then(function (args) {
- if (args.cancel)
- return;
- $scope.element.data = decodeURIComponent(args.element.data);
- $scope.element.name = args.elementEditorModel.name;
- $scope.element.formBindingContentType = args.elementEditorModel.formBindingContentType;
- $scope.$apply();
- });
- };
- },
- templateUrl: environment.templateUrl("Form"),
- replace: true
- };
- });
+ .directive("orcLayoutForm", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ $scope.edit = function () {
+ $scope.$root.editElement($scope.element).then(function (args) {
+ if (args.cancel)
+ return;
+ $scope.element.data = decodeURIComponent(args.element.data);
+ $scope.element.name = args.elementEditorModel.name;
+ $scope.element.formBindingContentType = args.elementEditorModel.formBindingContentType;
+ $scope.$apply();
+ });
+ };
+ },
+ templateUrl: environment.templateUrl("Form"),
+ replace: true
+ };
+ }
+ ]);
var LayoutEditor;
(function ($, LayoutEditor) {
diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js.bundle b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js.bundle
index 80ce1e564..4e288f06b 100644
--- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js.bundle
+++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.js.bundle
@@ -4,7 +4,7 @@
true
- false
+ true
diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.min.js b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.min.js
index 24a36ca23..837b77fdf 100644
--- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.min.js
+++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Forms.min.js
@@ -1 +1 @@
-angular.module("LayoutEditor").directive("orcLayoutForm",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y";n.edit=function(){n.$root.editElement(n.element).then(function(t){t.cancel||(n.element.data=decodeURIComponent(t.element.data),n.element.name=t.elementEditorModel.name,n.element.formBindingContentType=t.elementEditorModel.formBindingContentType,n.$apply())})}},templateUrl:i.templateUrl("Form"),replace:!0}});var LayoutEditor;(function(n,t){t.Form=function(i,r,u,f,e,o,s,h,c,l,a,v){var y,p;t.Element.call(this,"Form",i,r,u,f,e);t.Container.call(this,["Grid","Content"],v);y=this;this.isContainable=!0;this.dropTargetClass="layout-common-holder";this.contentType=h;this.contentTypeLabel=c;this.contentTypeClass=l;this.name=o||"Untitled";this.formBindingContentType=s;this.hasEditor=a;this.toObject=function(){var n=this.elementToObject();return n.name=this.name,n.formBindingContentType=this.formBindingContentType,n.children=this.childrenToObject(),n};p=this.getEditorObject;this.getEditorObject=function(){var t=p();return n.extend(t,{FormName:this.name,FormBindingContentType:this.formBindingContentType})};this.setChildren=function(n){this.children=n;_(this.children).each(function(n){n.parent=y;y.linkChild(n)})};this.linkChild=function(t){var i=t.getEditorObject;t.getEditorObject=function(){var t=i();return n.extend(t,{FormBindingContentType:y.formBindingContentType})}};this.setChildren(v)};t.Form.from=function(n){return new t.Form(n.data,n.htmlId,n.htmlClass,n.htmlStyle,n.isTemplated,n.name,n.formBindingContentType,n.contentType,n.contentTypeLabel,n.contentTypeClass,n.hasEditor,t.childrenFrom(n.children))};t.registerFactory("Form",function(n){return t.Form.from(n)})})(jQuery,LayoutEditor||(LayoutEditor={}));
\ No newline at end of file
+angular.module("LayoutEditor").directive("orcLayoutForm",["$compile","scopeConfigurator","environment",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y";n.edit=function(){n.$root.editElement(n.element).then(function(t){t.cancel||(n.element.data=decodeURIComponent(t.element.data),n.element.name=t.elementEditorModel.name,n.element.formBindingContentType=t.elementEditorModel.formBindingContentType,n.$apply())})}},templateUrl:i.templateUrl("Form"),replace:!0}}]);var LayoutEditor;(function(n,t){t.Form=function(i,r,u,f,e,o,s,h,c,l,a,v){var y,p;t.Element.call(this,"Form",i,r,u,f,e);t.Container.call(this,["Grid","Content"],v);y=this;this.isContainable=!0;this.dropTargetClass="layout-common-holder";this.contentType=h;this.contentTypeLabel=c;this.contentTypeClass=l;this.name=o||"Untitled";this.formBindingContentType=s;this.hasEditor=a;this.toObject=function(){var n=this.elementToObject();return n.name=this.name,n.formBindingContentType=this.formBindingContentType,n.children=this.childrenToObject(),n};p=this.getEditorObject;this.getEditorObject=function(){var t=p();return n.extend(t,{FormName:this.name,FormBindingContentType:this.formBindingContentType})};this.setChildren=function(n){this.children=n;_(this.children).each(function(n){n.parent=y;y.linkChild(n)})};this.linkChild=function(t){var i=t.getEditorObject;t.getEditorObject=function(){var t=i();return n.extend(t,{FormBindingContentType:y.formBindingContentType})}};this.setChildren(v)};t.Form.from=function(n){return new t.Form(n.data,n.htmlId,n.htmlClass,n.htmlStyle,n.isTemplated,n.name,n.formBindingContentType,n.contentType,n.contentTypeLabel,n.contentTypeClass,n.hasEditor,t.childrenFrom(n.children))};t.registerFactory("Form",function(n){return t.Form.from(n)})})(jQuery,LayoutEditor||(LayoutEditor={}));
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Layouts/Directives/Form.js b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Layouts/Directives/Form.js
index 12870d7a2..6c84433ce 100644
--- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Layouts/Directives/Form.js
+++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Scripts/Layouts/Directives/Form.js
@@ -1,25 +1,27 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutForm", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- $scope.edit = function () {
- $scope.$root.editElement($scope.element).then(function (args) {
- if (args.cancel)
- return;
- $scope.element.data = decodeURIComponent(args.element.data);
- $scope.element.name = args.elementEditorModel.name;
- $scope.element.formBindingContentType = args.elementEditorModel.formBindingContentType;
- $scope.$apply();
- });
- };
- },
- templateUrl: environment.templateUrl("Form"),
- replace: true
- };
- });
\ No newline at end of file
+ .directive("orcLayoutForm", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ $scope.edit = function () {
+ $scope.$root.editElement($scope.element).then(function (args) {
+ if (args.cancel)
+ return;
+ $scope.element.data = decodeURIComponent(args.element.data);
+ $scope.element.name = args.elementEditorModel.name;
+ $scope.element.formBindingContentType = args.elementEditorModel.formBindingContentType;
+ $scope.$apply();
+ });
+ };
+ },
+ templateUrl: environment.templateUrl("Form"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/ResourceManifest.cs b/src/Orchard.Web/Modules/Orchard.Layouts/ResourceManifest.cs
index 4188906b9..3c5704d2c 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/ResourceManifest.cs
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/ResourceManifest.cs
@@ -9,9 +9,8 @@ namespace Orchard.Layouts {
manifest.DefineScript("AngularSanitize").SetUrl("Lib/angular-sanitize.js").SetDependencies("Angular");
manifest.DefineScript("AngularResource").SetUrl("Lib/angular-resource.js").SetDependencies("Angular");
manifest.DefineScript("Layouts.Models").SetUrl("Models.min.js", "Models.js").SetDependencies("jQuery", "Underscore");
-
- // For some reason the minified version doesn't work and causes AngularJS to complain about some directive not being found, so we're only registering the debug version of LayoutEditor.js.
- manifest.DefineScript("Layouts.LayoutEditor").SetUrl(/*"LayoutEditor.min.js",*/ "LayoutEditor.js").SetDependencies("Layouts.Models", "AngularResource", "AngularSanitize", "Angular", "jQuery", "Underscore");
+
+ manifest.DefineScript("Layouts.LayoutEditor").SetUrl("LayoutEditor.min.js", "LayoutEditor.js").SetDependencies("Layouts.Models", "AngularResource", "AngularSanitize", "Angular", "jQuery", "Underscore");
}
}
}
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js
index 3d1e82837..5a260a36b 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js
@@ -21,889 +21,913 @@ var LayoutEditor;
angular
.module("LayoutEditor")
- .factory("clipboard", function() {
- return {
- setData: LayoutEditor.Clipboard.setData,
- getData: LayoutEditor.Clipboard.getData,
- disable: LayoutEditor.Clipboard.disable
- };
- });
+ .factory("clipboard", [
+ function() {
+ return {
+ setData: LayoutEditor.Clipboard.setData,
+ getData: LayoutEditor.Clipboard.getData,
+ disable: LayoutEditor.Clipboard.disable
+ };
+ }
+ ]);
})(LayoutEditor || (LayoutEditor = {}));
angular
.module("LayoutEditor")
- .factory("scopeConfigurator", function ($timeout, clipboard) {
- return {
+ .factory("scopeConfigurator", ["$timeout", "clipboard",
+ function ($timeout, clipboard) {
+ return {
- configureForElement: function ($scope, $element) {
+ configureForElement: function ($scope, $element) {
- $element.find(".layout-panel").click(function (e) {
- e.stopPropagation();
- });
+ $element.find(".layout-panel").click(function (e) {
+ e.stopPropagation();
+ });
- $element.parent().keydown(function (e) {
- var handled = false;
- var resetFocus = false;
- var element = $scope.element;
+ $element.parent().keydown(function (e) {
+ var handled = false;
+ var resetFocus = false;
+ var element = $scope.element;
- if (element.editor.isDragging || element.editor.inlineEditingIsActive)
- return;
+ if (element.editor.isDragging || element.editor.inlineEditingIsActive)
+ return;
- // If the "real" clipboard works, then the pseudo-clipboard will have been disabled.
- if (!clipboard.disabled) {
- var focusedElement = element.editor.focusedElement;
- if (!!focusedElement) {
- // Pseudo clipboard handling for browsers not allowing real clipboard operations.
- if (e.ctrlKey) {
- switch (e.which) {
- case 67: // C
- focusedElement.copy(clipboard);
- break;
- case 88: // X
- focusedElement.cut(clipboard);
- break;
- case 86: // V
- focusedElement.paste(clipboard);
- break;
+ // If the "real" clipboard works, then the pseudo-clipboard will have been disabled.
+ if (!clipboard.disabled) {
+ var focusedElement = element.editor.focusedElement;
+ if (!!focusedElement) {
+ // Pseudo clipboard handling for browsers not allowing real clipboard operations.
+ if (e.ctrlKey) {
+ switch (e.which) {
+ case 67: // C
+ focusedElement.copy(clipboard);
+ break;
+ case 88: // X
+ focusedElement.cut(clipboard);
+ break;
+ case 86: // V
+ focusedElement.paste(clipboard);
+ break;
+ }
}
}
}
- }
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 46) { // Del
- $scope.delete(element);
- handled = true;
- } else if (!e.ctrlKey && !e.shiftKey && !e.altKey && (e.which == 32 || e.which == 27)) { // Space or Esc
- $element.find(".layout-panel-action-properties").first().click();
- handled = true;
- }
-
- if (element.type == "Content") { // This is a content element.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 13) { // Enter
- $element.find(".layout-panel-action-edit").first().click();
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 46) { // Del
+ $scope.delete(element);
handled = true;
- }
- }
-
- if (!!element.children) { // This is a container.
- if (!e.ctrlKey && !e.shiftKey && e.altKey && e.which == 40) { // Alt+Down
- if (element.children.length > 0)
- element.children[0].setIsFocused();
+ } else if (!e.ctrlKey && !e.shiftKey && !e.altKey && (e.which == 32 || e.which == 27)) { // Space or Esc
+ $element.find(".layout-panel-action-properties").first().click();
handled = true;
}
- if (element.type == "Column") { // This is a column.
- var connectAdjacent = !e.ctrlKey;
- if (e.which == 37) { // Left
- if (e.altKey)
- element.expandLeft(connectAdjacent);
- if (e.shiftKey)
- element.contractRight(connectAdjacent);
- handled = true;
- } else if (e.which == 39) { // Right
- if (e.altKey)
- element.contractLeft(connectAdjacent);
- if (e.shiftKey)
- element.expandRight(connectAdjacent);
+ if (element.type == "Content") { // This is a content element.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 13) { // Enter
+ $element.find(".layout-panel-action-edit").first().click();
handled = true;
}
}
- }
- if (!!element.parent) { // This is a child.
- if (e.altKey && e.which == 38) { // Alt+Up
- element.parent.setIsFocused();
- handled = true;
- }
-
- if (element.parent.type == "Row") { // Parent is a horizontal container.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Left
- element.parent.moveFocusPrevChild(element);
+ if (!!element.children) { // This is a container.
+ if (!e.ctrlKey && !e.shiftKey && e.altKey && e.which == 40) { // Alt+Down
+ if (element.children.length > 0)
+ element.children[0].setIsFocused();
handled = true;
}
- else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Right
- element.parent.moveFocusNextChild(element);
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Ctrl+Left
- element.moveUp();
- resetFocus = true;
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Ctrl+Right
- element.moveDown();
- handled = true;
- }
- }
- else { // Parent is a vertical container.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Up
- element.parent.moveFocusPrevChild(element);
- handled = true;
- }
- else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Down
- element.parent.moveFocusNextChild(element);
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Ctrl+Up
- element.moveUp();
- resetFocus = true;
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Ctrl+Down
- element.moveDown();
- handled = true;
- }
- }
- }
- if (handled) {
- e.preventDefault();
- }
-
- e.stopPropagation();
-
- $scope.$apply(); // Event is not triggered by Angular directive but raw event handler on element.
-
- // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
- if (resetFocus) {
- window.setTimeout(function () {
- $scope.$apply(function () {
- element.editor.focusedElement.setIsFocused();
- });
- }, 100);
- }
- });
-
- $scope.element.setIsFocusedEventHandlers.push(function () {
- $element.parent().focus();
- });
-
- $scope.delete = function (element) {
- element.delete();
- }
- },
-
- configureForContainer: function ($scope, $element) {
- var element = $scope.element;
-
- //$scope.isReceiving = false; // True when container is receiving an external element via drag/drop.
- $scope.getShowChildrenPlaceholder = function () {
- return $scope.element.children.length === 0 && !$scope.element.getIsDropTarget();
- };
-
- $scope.sortableOptions = {
- cursor: "move",
- delay: 150,
- disabled: element.getIsSealed(),
- distance: 5,
- //handle: element.children.length < 2 ? ".imaginary-class" : false, // For some reason doesn't get re-evaluated after adding more children.
- start: function (e, ui) {
- $scope.$apply(function () {
- element.setIsDropTarget(true);
- element.editor.isDragging = true;
- });
- // Make the drop target placeholder as high as the item being dragged.
- ui.placeholder.height(ui.item.height() - 4);
- ui.placeholder.css("min-height", 0);
- },
- stop: function (e, ui) {
- $scope.$apply(function () {
- element.editor.isDragging = false;
- element.setIsDropTarget(false);
- });
- },
- over: function (e, ui) {
- if (!!ui.sender && !!ui.sender[0].isToolbox) {
- if (!!ui.sender[0].dropTargetTimeout) {
- $timeout.cancel(ui.sender[0].dropTargetTimeout);
- ui.sender[0].dropTargetTimeout = null;
- }
- $timeout(function () {
- if (element.type == "Row") {
- // If there was a previous drop target and it was a row, roll back any pending column adds to it.
- var previousDropTarget = element.editor.dropTargetElement;
- if (!!previousDropTarget && previousDropTarget.type == "Row")
- previousDropTarget.rollbackAddColumn();
+ if (element.type == "Column") { // This is a column.
+ var connectAdjacent = !e.ctrlKey;
+ if (e.which == 37) { // Left
+ if (e.altKey)
+ element.expandLeft(connectAdjacent);
+ if (e.shiftKey)
+ element.contractRight(connectAdjacent);
+ handled = true;
+ } else if (e.which == 39) { // Right
+ if (e.altKey)
+ element.contractLeft(connectAdjacent);
+ if (e.shiftKey)
+ element.expandRight(connectAdjacent);
+ handled = true;
}
- element.setIsDropTarget(false);
- });
- ui.sender[0].dropTargetTimeout = $timeout(function () {
- if (element.type == "Row") {
- var receivedColumn = ui.item.sortable.model;
- var receivedColumnWidth = Math.floor(12 / (element.children.length + 1));
- receivedColumn.width = receivedColumnWidth;
- receivedColumn.offset = 0;
- element.beginAddColumn(receivedColumnWidth);
- // Make the drop target placeholder the correct width and as high as the highest existing column in the row.
- var maxHeight = _.max(_($element.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function (e) {
- return $(e).height();
- }));
- for (i = 1; i <= 12; i++)
- ui.placeholder.removeClass("col-xs-" + i);
- ui.placeholder.addClass("col-xs-" + receivedColumn.width);
- if (maxHeight > 0) {
- ui.placeholder.height(maxHeight);
- ui.placeholder.css("min-height", 0);
- }
- else {
- ui.placeholder.height(0);
- ui.placeholder.css("min-height", "");
- }
- }
- element.setIsDropTarget(true);
- }, 150);
- }
- },
- receive: function (e, ui) {
- if (!!ui.sender && !!ui.sender[0].isToolbox) {
- $scope.$apply(function () {
- var receivedElement = ui.item.sortable.model;
- if (!!receivedElement) {
- if (element.type == "Row")
- element.commitAddColumn();
- // Should ideally call LayoutEditor.Container.addChild() instead, but since this handler
- // is run *before* the ui-sortable directive's handler, if we try to add the child to the
- // array that handler will get an exception when trying to do the same.
- // Because of this, we need to invoke "setParent" so that specific container types can perform element speficic initialization.
- receivedElement.setEditor(element.editor);
- receivedElement.setParent(element);
- if (receivedElement.type == "Content" && !!receivedElement.hasEditor) {
- $scope.$root.editElement(receivedElement).then(function (args) {
- if (!args.cancel) {
- receivedElement.data = decodeURIComponent(args.element.data);
- receivedElement.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
- }
- $timeout(function () {
- if (!!args.cancel)
- receivedElement.delete();
- else
- receivedElement.setIsFocused();
- //$scope.isReceiving = false;
- element.setIsDropTarget(false);
-
- });
- return;
- });
- }
- }
- $timeout(function () {
- //$scope.isReceiving = false;
- element.setIsDropTarget(false);
- if (!!receivedElement)
- receivedElement.setIsFocused();
- });
- });
- }
- }
- };
-
- $scope.click = function (child, e) {
- if (!child.editor.isDragging)
- child.setIsFocused();
- e.stopPropagation();
- };
-
- $scope.getClasses = function (child) {
- var result = ["layout-element"];
-
- if (!!child.children) {
- result.push("layout-container");
- if (child.getIsSealed())
- result.push("layout-container-sealed");
- }
-
- result.push("layout-" + child.type.toLowerCase());
-
- if (!!child.dropTargetClass)
- result.push(child.dropTargetClass);
-
- // TODO: Move these to either the Column directive or the Column model class.
- if (child.type == "Row") {
- result.push("row");
- if (!child.canAddColumn())
- result.push("layout-row-full");
- }
- if (child.type == "Column") {
- result.push("col-xs-" + child.width);
- result.push("col-xs-offset-" + child.offset);
- }
- if (child.type == "Content")
- result.push("layout-content-" + child.contentTypeClass);
-
- if (child.getIsActive())
- result.push("layout-element-active");
- if (child.getIsFocused())
- result.push("layout-element-focused");
- if (child.getIsSelected())
- result.push("layout-element-selected");
- if (child.getIsDropTarget())
- result.push("layout-element-droptarget");
- if (child.isTemplated)
- result.push("layout-element-templated");
-
- return result;
- };
- }
- }
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutEditor", function (environment) {
- return {
- restrict: "E",
- scope: {},
- controller: function ($scope, $element, $attrs, $compile, clipboard) {
- if (!!$attrs.model)
- $scope.element = eval($attrs.model);
- else
- throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");
-
- $scope.click = function (canvas, e) {
- if (!canvas.editor.isDragging)
- canvas.setIsFocused();
- e.stopPropagation();
- };
-
- $scope.getClasses = function (canvas) {
- var result = ["layout-element", "layout-container", "layout-canvas"];
-
- if (canvas.getIsActive())
- result.push("layout-element-active");
- if (canvas.getIsFocused())
- result.push("layout-element-focused");
- if (canvas.getIsSelected())
- result.push("layout-element-selected");
- if (canvas.getIsDropTarget())
- result.push("layout-element-droptarget");
- if (canvas.isTemplated)
- result.push("layout-element-templated");
-
- return result;
- };
-
- // An unfortunate side-effect of the next hack on line 54 is that the created elements aren't added to the DOM yet, so we can't use it to get to the parent ".layout-desiger" element.
- // Work around: access that element directly (which efectively turns multiple layout editors on a single page impossible).
- // //var layoutDesignerHost = $element.closest(".layout-designer").data("layout-designer-host");
- var layoutDesignerHost = $(".layout-designer").data("layout-designer-host");
-
- $scope.$root.layoutDesignerHost = layoutDesignerHost;
-
- layoutDesignerHost.element.on("replacecanvas", function (e, args) {
- var editor = $scope.element;
- var canvasData = {
- data: args.canvas.data,
- htmlId: args.canvas.htmlId,
- htmlClass: args.canvas.htmlClass,
- htmlStyle: args.canvas.htmlStyle,
- isTemplated: args.canvas.isTemplated,
- children: args.canvas.children
- };
-
- // HACK: Instead of simply updating the $scope.element with a new instance, we need to replace the entire orc-layout-editor markup
- // in order for angular to rebind starting with the Canvas element. Otherwise, for some reason, it will rebind starting with the first child of Canvas.
- // You can see this happening when setting a breakpoint in ScopeConfigurator where containers are initialized with drag & drop: on page load, the first element
- // is a Canvas (good), but after having selected another template, the first element is (typically) a Grid (bad).
- // Simply recompiling the orc-layout-editor directive will cause the entire thing to be generated, which works just fine as well (even though not is nice as simply leveraging model binding).
- layoutDesignerHost.editor = window.layoutEditor = new LayoutEditor.Editor(editor.config, canvasData);
- var template = "";
- var html = $compile(template)($scope);
- $(".layout-editor-holder").html(html);
- });
-
- $scope.$root.editElement = function (element) {
- var host = $scope.$root.layoutDesignerHost;
- return host.editElement(element);
- };
-
- $scope.$root.addElement = function (contentType) {
- var host = $scope.$root.layoutDesignerHost;
- return host.addElement(contentType);
- };
-
- $scope.toggleInlineEditing = function () {
- if (!$scope.element.inlineEditingIsActive) {
- $scope.element.inlineEditingIsActive = true;
- $element.find(".layout-toolbar-container").show();
- var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
- var firstContentEditorId = $(selector).first().attr("id");
- tinymce.init({
- selector: selector,
- theme: "modern",
- schema: "html5",
- plugins: [
- "advlist autolink lists link image charmap print preview hr anchor pagebreak",
- "searchreplace wordcount visualblocks visualchars code fullscreen",
- "insertdatetime media nonbreaking table contextmenu directionality",
- "emoticons template paste textcolor colorpicker textpattern",
- "fullscreen autoresize"
- ],
- toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",
- convert_urls: false,
- valid_elements: "*[*]",
- // Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
- extended_valid_elements: "script[type|defer|src|language]",
- statusbar: false,
- skin: "orchardlightgray",
- inline: true,
- fixed_toolbar_container: "#layout-editor-" + $scope.$id + " .layout-toolbar-container",
- init_instance_callback: function (editor) {
- if (editor.id == firstContentEditorId)
- tinymce.execCommand("mceFocus", false, editor.id);
}
- });
- }
- else {
- tinymce.remove("#layout-editor-" + $scope.$id + " .layout-content-markup");
- $element.find(".layout-toolbar-container").hide();
- $scope.element.inlineEditingIsActive = false;
- }
- };
+ }
- $(document).on("cut copy paste", function (e) {
- // The real clipboard is supported, so disable the peudo clipboard.
- clipboard.disable();
- var focusedElement = $scope.element.focusedElement;
- if (!!focusedElement) {
- $scope.$apply(function () {
- switch (e.type) {
- case "copy":
- focusedElement.copy(e.originalEvent.clipboardData);
- break;
- case "cut":
- focusedElement.cut(e.originalEvent.clipboardData);
- break;
- case "paste":
- focusedElement.paste(e.originalEvent.clipboardData);
- break;
+ if (!!element.parent) { // This is a child.
+ if (e.altKey && e.which == 38) { // Alt+Up
+ element.parent.setIsFocused();
+ handled = true;
}
- });
+
+ if (element.parent.type == "Row") { // Parent is a horizontal container.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Left
+ element.parent.moveFocusPrevChild(element);
+ handled = true;
+ }
+ else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Right
+ element.parent.moveFocusNextChild(element);
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Ctrl+Left
+ element.moveUp();
+ resetFocus = true;
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Ctrl+Right
+ element.moveDown();
+ handled = true;
+ }
+ }
+ else { // Parent is a vertical container.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Up
+ element.parent.moveFocusPrevChild(element);
+ handled = true;
+ }
+ else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Down
+ element.parent.moveFocusNextChild(element);
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Ctrl+Up
+ element.moveUp();
+ resetFocus = true;
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Ctrl+Down
+ element.moveDown();
+ handled = true;
+ }
+ }
+ }
+
+ if (handled) {
+ e.preventDefault();
+ }
+
+ e.stopPropagation();
+
+ $scope.$apply(); // Event is not triggered by Angular directive but raw event handler on element.
// HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
- window.setTimeout(function () {
- $scope.$apply(function () {
- if (!!$scope.element.focusedElement)
- $scope.element.focusedElement.setIsFocused();
- });
- }, 100);
-
- e.preventDefault();
- }
- });
- },
- templateUrl: environment.templateUrl("Editor"),
- replace: true,
- link: function (scope, element) {
- // No clicks should propagate from the TinyMCE toolbars.
- element.find(".layout-toolbar-container").click(function (e) {
- e.stopPropagation();
- });
- // Intercept mousedown on editor while in inline editing mode to
- // prevent current editor from losing focus.
- element.mousedown(function (e) {
- if (scope.element.inlineEditingIsActive) {
- e.preventDefault();
- e.stopPropagation();
- }
- })
- // Unfocus and unselect everything on click outside of canvas.
- $(window).click(function (e) {
- // Except when in inline editing mode.
- if (!scope.element.inlineEditingIsActive) {
- scope.$apply(function () {
- scope.element.activeElement = null;
- scope.element.focusedElement = null;
- });
- }
- });
- }
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutCanvas", function (scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element, $attrs) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Canvas"),
- replace: true
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutChild", function ($compile) {
- return {
- restrict: "E",
- scope: { element: "=" },
- link: function (scope, element) {
- var template = "";
- var html = $compile(template)(scope);
- $(element).replaceWith(html);
- }
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutColumn", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Column"),
- replace: true,
- link: function (scope, element, attrs) {
- element.find(".layout-column-resize-bar").draggable({
- axis: "x",
- helper: "clone",
- revert: true,
- start: function (e, ui) {
- scope.$apply(function () {
- scope.element.editor.isResizing = true;
- });
- },
- drag: function (e, ui) {
- var columnElement = element.parent();
- var columnSize = columnElement.width() / scope.element.width;
- var connectAdjacent = !e.ctrlKey;
- if ($(e.target).hasClass("layout-column-resize-bar-left")) {
- var delta = ui.offset.left - columnElement.offset().left;
- if (delta < -columnSize && scope.element.canExpandLeft(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.expandLeft(connectAdjacent);
+ if (resetFocus) {
+ window.setTimeout(function () {
+ $scope.$apply(function () {
+ element.editor.focusedElement.setIsFocused();
});
- }
- else if (delta > columnSize && scope.element.canContractLeft(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.contractLeft(connectAdjacent);
- });
- }
+ }, 100);
}
- else if ($(e.target).hasClass("layout-column-resize-bar-right")) {
- var delta = ui.offset.left - columnElement.width() - columnElement.offset().left;
- if (delta > columnSize && scope.element.canExpandRight(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.expandRight(connectAdjacent);
- });
- }
- else if (delta < -columnSize && scope.element.canContractRight(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.contractRight(connectAdjacent);
- });
- }
- }
-
- },
- stop: function (e, ui) {
- scope.$apply(function () {
- scope.element.editor.isResizing = false;
- });
- }
- });
- }
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutContent", function ($sce, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- $scope.edit = function () {
- $scope.$root.editElement($scope.element).then(function (args) {
- $scope.$apply(function () {
- if (args.cancel)
- return;
-
- $scope.element.data = decodeURIComponent(args.element.data);
- $scope.element.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
- });
- });
- };
- $scope.updateContent = function (e) {
- $scope.element.setHtml(e.target.innerHTML);
- };
-
- // Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
- $scope.element.setHtml = function (html) {
- $scope.element.html = html;
- $scope.element.htmlUnsafe = $sce.trustAsHtml(html);
- };
-
- $scope.element.setHtml(decodeURIComponent($scope.element.html.replace(/\+/g, "%20")));
- },
- templateUrl: environment.templateUrl("Content"),
- replace: true,
- link: function (scope, element) {
- // Mouse down events must not be intercepted by drag and drop while inline editing is active,
- // otherwise clicks in inline editors will have no effect.
- element.find(".layout-content-markup").mousedown(function (e) {
- if (scope.element.editor.inlineEditingIsActive) {
- e.stopPropagation();
- }
- });
- }
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutGrid", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Grid"),
- replace: true
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutRow", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "x";
- $scope.sortableOptions["ui-floating"] = true;
- },
- templateUrl: environment.templateUrl("Row"),
- replace: true
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutPopup", function () {
- return {
- restrict: "A",
- link: function (scope, element, attrs) {
- var popup = $(element);
- var trigger = popup.closest(".layout-popup-trigger");
- var parentElement = popup.closest(".layout-element");
- trigger.click(function () {
- popup.toggle();
- if (popup.is(":visible")) {
- popup.position({
- my: attrs.orcLayoutPopupMy || "left top",
- at: attrs.orcLayoutPopupAt || "left bottom+4px",
- of: trigger
- });
- popup.find("input").first().focus();
- }
- });
- popup.click(function (e) {
- e.stopPropagation();
- });
- parentElement.click(function (e) {
- popup.hide();
- });
- popup.keydown(function (e) {
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 27) // Esc
- popup.hide();
- e.stopPropagation();
- });
- }
- };
- });
-angular
- .module("LayoutEditor")
- .directive("orcLayoutToolbox", function ($compile, environment) {
- return {
- restrict: "E",
- controller: function ($scope, $element) {
-
- $scope.resetElements = function () {
-
- $scope.gridElements = [
- LayoutEditor.Grid.from({
- toolboxIcon: "\uf00a",
- toolboxLabel: "Grid",
- toolboxDescription: "Empty grid.",
- children: []
- })
- ];
-
- $scope.rowElements = [
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (1 column)",
- toolboxDescription: "Row with 1 column.",
- children: LayoutEditor.Column.times(1)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (2 columns)",
- toolboxDescription: "Row with 2 columns.",
- children: LayoutEditor.Column.times(2)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (3 columns)",
- toolboxDescription: "Row with 3 columns.",
- children: LayoutEditor.Column.times(3)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (4 columns)",
- toolboxDescription: "Row with 4 columns.",
- children: LayoutEditor.Column.times(4)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (6 columns)",
- toolboxDescription: "Row with 6 columns.",
- children: LayoutEditor.Column.times(6)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (12 columns)",
- toolboxDescription: "Row with 12 columns.",
- children: LayoutEditor.Column.times(12)
- }), LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (empty)",
- toolboxDescription: "Empty row.",
- children: []
- })
- ];
-
- $scope.columnElements = [
- LayoutEditor.Column.from({
- toolboxIcon: "\uf0db",
- toolboxLabel: "Column",
- toolboxDescription: "Empty column.",
- width: 1,
- offset: 0,
- children: []
- })
- ];
-
- $scope.contentElementCategories = _($scope.element.config.categories).map(function (category) {
- return {
- name: category.name,
- elements: _(category.contentTypes).map(function (contentType) {
- var type = contentType.type;
- var factory = LayoutEditor.factories[type] || LayoutEditor.factories["Content"];
- var item = {
- isTemplated: false,
- contentType: contentType.id,
- contentTypeLabel: contentType.label,
- contentTypeClass: contentType.typeClass,
- data: null,
- hasEditor: contentType.hasEditor,
- html: contentType.html
- };
- var element = factory(item);
- element.toolboxIcon = contentType.icon || "\uf1c9";
- element.toolboxLabel = contentType.label;
- element.toolboxDescription = contentType.description;
- return element;
- })
- };
});
- };
+ $scope.element.setIsFocusedEventHandlers.push(function () {
+ $element.parent().focus();
+ });
- $scope.resetElements();
-
- $scope.getSortableOptions = function (type) {
- var editorId = $element.closest(".layout-editor").attr("id");
- var parentClasses;
- var placeholderClasses;
- var floating = false;
-
- switch (type) {
- case "Grid":
- parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
- placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
- break;
- case "Row":
- parentClasses = [".layout-grid"];
- placeholderClasses = "layout-element layout-container layout-row row ui-sortable-placeholder";
- break;
- case "Column":
- parentClasses = [".layout-row:not(.layout-row-full)"];
- placeholderClasses = "layout-element layout-container layout-column ui-sortable-placeholder";
- floating = true; // To ensure a smooth horizontal-list reordering. https://github.com/angular-ui/ui-sortable#floating
- break;
- case "Content":
- parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
- placeholderClasses = "layout-element layout-content ui-sortable-placeholder";
- break;
+ $scope.delete = function (element) {
+ element.delete();
}
+ },
- return {
+ configureForContainer: function ($scope, $element) {
+ var element = $scope.element;
+
+ //$scope.isReceiving = false; // True when container is receiving an external element via drag/drop.
+ $scope.getShowChildrenPlaceholder = function () {
+ return $scope.element.children.length === 0 && !$scope.element.getIsDropTarget();
+ };
+
+ $scope.sortableOptions = {
cursor: "move",
- connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "),
- placeholder: placeholderClasses,
- "ui-floating": floating,
- create: function (e, ui) {
- e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox.
- },
+ delay: 150,
+ disabled: element.getIsSealed(),
+ distance: 5,
+ //handle: element.children.length < 2 ? ".imaginary-class" : false, // For some reason doesn't get re-evaluated after adding more children.
start: function (e, ui) {
$scope.$apply(function () {
- $scope.element.isDragging = true;
+ element.setIsDropTarget(true);
+ element.editor.isDragging = true;
});
+ // Make the drop target placeholder as high as the item being dragged.
+ ui.placeholder.height(ui.item.height() - 4);
+ ui.placeholder.css("min-height", 0);
},
stop: function (e, ui) {
$scope.$apply(function () {
- $scope.element.isDragging = false;
- $scope.resetElements();
+ element.editor.isDragging = false;
+ element.setIsDropTarget(false);
});
},
over: function (e, ui) {
- $scope.$apply(function () {
- $scope.element.canvas.setIsDropTarget(false);
- });
+ if (!!ui.sender && !!ui.sender[0].isToolbox) {
+ if (!!ui.sender[0].dropTargetTimeout) {
+ $timeout.cancel(ui.sender[0].dropTargetTimeout);
+ ui.sender[0].dropTargetTimeout = null;
+ }
+ $timeout(function () {
+ if (element.type == "Row") {
+ // If there was a previous drop target and it was a row, roll back any pending column adds to it.
+ var previousDropTarget = element.editor.dropTargetElement;
+ if (!!previousDropTarget && previousDropTarget.type == "Row")
+ previousDropTarget.rollbackAddColumn();
+ }
+ element.setIsDropTarget(false);
+ });
+ ui.sender[0].dropTargetTimeout = $timeout(function () {
+ if (element.type == "Row") {
+ var receivedColumn = ui.item.sortable.model;
+ var receivedColumnWidth = Math.floor(12 / (element.children.length + 1));
+ receivedColumn.width = receivedColumnWidth;
+ receivedColumn.offset = 0;
+ element.beginAddColumn(receivedColumnWidth);
+ // Make the drop target placeholder the correct width and as high as the highest existing column in the row.
+ var maxHeight = _.max(_($element.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function (e) {
+ return $(e).height();
+ }));
+ for (i = 1; i <= 12; i++)
+ ui.placeholder.removeClass("col-xs-" + i);
+ ui.placeholder.addClass("col-xs-" + receivedColumn.width);
+ if (maxHeight > 0) {
+ ui.placeholder.height(maxHeight);
+ ui.placeholder.css("min-height", 0);
+ }
+ else {
+ ui.placeholder.height(0);
+ ui.placeholder.css("min-height", "");
+ }
+ }
+ element.setIsDropTarget(true);
+ }, 150);
+ }
},
- }
- };
+ receive: function (e, ui) {
+ if (!!ui.sender && !!ui.sender[0].isToolbox) {
+ $scope.$apply(function () {
+ var receivedElement = ui.item.sortable.model;
+ if (!!receivedElement) {
+ if (element.type == "Row")
+ element.commitAddColumn();
+ // Should ideally call LayoutEditor.Container.addChild() instead, but since this handler
+ // is run *before* the ui-sortable directive's handler, if we try to add the child to the
+ // array that handler will get an exception when trying to do the same.
+ // Because of this, we need to invoke "setParent" so that specific container types can perform element speficic initialization.
+ receivedElement.setEditor(element.editor);
+ receivedElement.setParent(element);
+ if (receivedElement.type == "Content" && !!receivedElement.hasEditor) {
+ $scope.$root.editElement(receivedElement).then(function (args) {
+ if (!args.cancel) {
+ receivedElement.data = decodeURIComponent(args.element.data);
+ receivedElement.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
+ }
+ $timeout(function () {
+ if (!!args.cancel)
+ receivedElement.delete();
+ else
+ receivedElement.setIsFocused();
+ //$scope.isReceiving = false;
+ element.setIsDropTarget(false);
- var layoutIsCollapsedCookieName = "layoutToolboxCategory_Layout_IsCollapsed";
- $scope.layoutIsCollapsed = $.cookie(layoutIsCollapsedCookieName) === "true";
+ });
+ return;
+ });
+ }
+ }
+ $timeout(function () {
+ //$scope.isReceiving = false;
+ element.setIsDropTarget(false);
+ if (!!receivedElement)
+ receivedElement.setIsFocused();
+ });
+ });
+ }
+ }
+ };
- $scope.toggleLayoutIsCollapsed = function (e) {
- $scope.layoutIsCollapsed = !$scope.layoutIsCollapsed;
- $.cookie(layoutIsCollapsedCookieName, $scope.layoutIsCollapsed, { expires: 365 }); // Remember collapsed state for a year.
- e.preventDefault();
- e.stopPropagation();
- };
- },
- templateUrl: environment.templateUrl("Toolbox"),
- replace: true
- };
- });
+ $scope.click = function (child, e) {
+ if (!child.editor.isDragging)
+ child.setIsFocused();
+ e.stopPropagation();
+ };
+
+ $scope.getClasses = function (child) {
+ var result = ["layout-element"];
+
+ if (!!child.children) {
+ result.push("layout-container");
+ if (child.getIsSealed())
+ result.push("layout-container-sealed");
+ }
+
+ result.push("layout-" + child.type.toLowerCase());
+
+ if (!!child.dropTargetClass)
+ result.push(child.dropTargetClass);
+
+ // TODO: Move these to either the Column directive or the Column model class.
+ if (child.type == "Row") {
+ result.push("row");
+ if (!child.canAddColumn())
+ result.push("layout-row-full");
+ }
+ if (child.type == "Column") {
+ result.push("col-xs-" + child.width);
+ result.push("col-xs-offset-" + child.offset);
+ }
+ if (child.type == "Content")
+ result.push("layout-content-" + child.contentTypeClass);
+
+ if (child.getIsActive())
+ result.push("layout-element-active");
+ if (child.getIsFocused())
+ result.push("layout-element-focused");
+ if (child.getIsSelected())
+ result.push("layout-element-selected");
+ if (child.getIsDropTarget())
+ result.push("layout-element-droptarget");
+ if (child.isTemplated)
+ result.push("layout-element-templated");
+
+ return result;
+ };
+ }
+ };
+ }
+ ]);
angular
.module("LayoutEditor")
- .directive("orcLayoutToolboxGroup", function ($compile, environment) {
- return {
- restrict: "E",
- scope: { category: "=" },
- controller: function ($scope, $element) {
- var isCollapsedCookieName = "layoutToolboxCategory_" + $scope.category.name + "_IsCollapsed";
- $scope.isCollapsed = $.cookie(isCollapsedCookieName) === "true";
- $scope.toggleIsCollapsed = function (e) {
- $scope.isCollapsed = !$scope.isCollapsed;
- $.cookie(isCollapsedCookieName, $scope.isCollapsed, { expires: 365 }); // Remember collapsed state for a year.
- e.preventDefault();
- e.stopPropagation();
- };
- },
- templateUrl: environment.templateUrl("ToolboxGroup"),
- replace: true
- };
- });
+ .directive("orcLayoutEditor", ["environment",
+ function (environment) {
+ return {
+ restrict: "E",
+ scope: {},
+ controller: function ($scope, $element, $attrs, $compile, clipboard) {
+ if (!!$attrs.model)
+ $scope.element = eval($attrs.model);
+ else
+ throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");
+
+ $scope.click = function (canvas, e) {
+ if (!canvas.editor.isDragging)
+ canvas.setIsFocused();
+ e.stopPropagation();
+ };
+
+ $scope.getClasses = function (canvas) {
+ var result = ["layout-element", "layout-container", "layout-canvas"];
+
+ if (canvas.getIsActive())
+ result.push("layout-element-active");
+ if (canvas.getIsFocused())
+ result.push("layout-element-focused");
+ if (canvas.getIsSelected())
+ result.push("layout-element-selected");
+ if (canvas.getIsDropTarget())
+ result.push("layout-element-droptarget");
+ if (canvas.isTemplated)
+ result.push("layout-element-templated");
+
+ return result;
+ };
+
+ // An unfortunate side-effect of the next hack on line 54 is that the created elements aren't added to the DOM yet, so we can't use it to get to the parent ".layout-desiger" element.
+ // Work around: access that element directly (which efectively turns multiple layout editors on a single page impossible).
+ // //var layoutDesignerHost = $element.closest(".layout-designer").data("layout-designer-host");
+ var layoutDesignerHost = $(".layout-designer").data("layout-designer-host");
+
+ $scope.$root.layoutDesignerHost = layoutDesignerHost;
+
+ layoutDesignerHost.element.on("replacecanvas", function (e, args) {
+ var editor = $scope.element;
+ var canvasData = {
+ data: args.canvas.data,
+ htmlId: args.canvas.htmlId,
+ htmlClass: args.canvas.htmlClass,
+ htmlStyle: args.canvas.htmlStyle,
+ isTemplated: args.canvas.isTemplated,
+ children: args.canvas.children
+ };
+
+ // HACK: Instead of simply updating the $scope.element with a new instance, we need to replace the entire orc-layout-editor markup
+ // in order for angular to rebind starting with the Canvas element. Otherwise, for some reason, it will rebind starting with the first child of Canvas.
+ // You can see this happening when setting a breakpoint in ScopeConfigurator where containers are initialized with drag & drop: on page load, the first element
+ // is a Canvas (good), but after having selected another template, the first element is (typically) a Grid (bad).
+ // Simply recompiling the orc-layout-editor directive will cause the entire thing to be generated, which works just fine as well (even though not is nice as simply leveraging model binding).
+ layoutDesignerHost.editor = window.layoutEditor = new LayoutEditor.Editor(editor.config, canvasData);
+ var template = "";
+ var html = $compile(template)($scope);
+ $(".layout-editor-holder").html(html);
+ });
+
+ $scope.$root.editElement = function (element) {
+ var host = $scope.$root.layoutDesignerHost;
+ return host.editElement(element);
+ };
+
+ $scope.$root.addElement = function (contentType) {
+ var host = $scope.$root.layoutDesignerHost;
+ return host.addElement(contentType);
+ };
+
+ $scope.toggleInlineEditing = function () {
+ if (!$scope.element.inlineEditingIsActive) {
+ $scope.element.inlineEditingIsActive = true;
+ $element.find(".layout-toolbar-container").show();
+ var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
+ var firstContentEditorId = $(selector).first().attr("id");
+ tinymce.init({
+ selector: selector,
+ theme: "modern",
+ schema: "html5",
+ plugins: [
+ "advlist autolink lists link image charmap print preview hr anchor pagebreak",
+ "searchreplace wordcount visualblocks visualchars code fullscreen",
+ "insertdatetime media nonbreaking table contextmenu directionality",
+ "emoticons template paste textcolor colorpicker textpattern",
+ "fullscreen autoresize"
+ ],
+ toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",
+ convert_urls: false,
+ valid_elements: "*[*]",
+ // Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
+ extended_valid_elements: "script[type|defer|src|language]",
+ statusbar: false,
+ skin: "orchardlightgray",
+ inline: true,
+ fixed_toolbar_container: "#layout-editor-" + $scope.$id + " .layout-toolbar-container",
+ init_instance_callback: function (editor) {
+ if (editor.id == firstContentEditorId)
+ tinymce.execCommand("mceFocus", false, editor.id);
+ }
+ });
+ }
+ else {
+ tinymce.remove("#layout-editor-" + $scope.$id + " .layout-content-markup");
+ $element.find(".layout-toolbar-container").hide();
+ $scope.element.inlineEditingIsActive = false;
+ }
+ };
+
+ $(document).on("cut copy paste", function (e) {
+ // The real clipboard is supported, so disable the peudo clipboard.
+ clipboard.disable();
+ var focusedElement = $scope.element.focusedElement;
+ if (!!focusedElement) {
+ $scope.$apply(function () {
+ switch (e.type) {
+ case "copy":
+ focusedElement.copy(e.originalEvent.clipboardData);
+ break;
+ case "cut":
+ focusedElement.cut(e.originalEvent.clipboardData);
+ break;
+ case "paste":
+ focusedElement.paste(e.originalEvent.clipboardData);
+ break;
+ }
+ });
+
+ // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
+ window.setTimeout(function () {
+ $scope.$apply(function () {
+ if (!!$scope.element.focusedElement)
+ $scope.element.focusedElement.setIsFocused();
+ });
+ }, 100);
+
+ e.preventDefault();
+ }
+ });
+ },
+ templateUrl: environment.templateUrl("Editor"),
+ replace: true,
+ link: function (scope, element) {
+ // No clicks should propagate from the TinyMCE toolbars.
+ element.find(".layout-toolbar-container").click(function (e) {
+ e.stopPropagation();
+ });
+ // Intercept mousedown on editor while in inline editing mode to
+ // prevent current editor from losing focus.
+ element.mousedown(function (e) {
+ if (scope.element.inlineEditingIsActive) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ })
+ // Unfocus and unselect everything on click outside of canvas.
+ $(window).click(function (e) {
+ // Except when in inline editing mode.
+ if (!scope.element.inlineEditingIsActive) {
+ scope.$apply(function () {
+ scope.element.activeElement = null;
+ scope.element.focusedElement = null;
+ });
+ }
+ });
+ }
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutCanvas", ["scopeConfigurator", "environment",
+ function (scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element, $attrs) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Canvas"),
+ replace: true
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutChild", ["$compile",
+ function ($compile) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ link: function (scope, element) {
+ var template = "";
+ var html = $compile(template)(scope);
+ $(element).replaceWith(html);
+ }
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutColumn", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Column"),
+ replace: true,
+ link: function (scope, element, attrs) {
+ element.find(".layout-column-resize-bar").draggable({
+ axis: "x",
+ helper: "clone",
+ revert: true,
+ start: function (e, ui) {
+ scope.$apply(function () {
+ scope.element.editor.isResizing = true;
+ });
+ },
+ drag: function (e, ui) {
+ var columnElement = element.parent();
+ var columnSize = columnElement.width() / scope.element.width;
+ var connectAdjacent = !e.ctrlKey;
+ if ($(e.target).hasClass("layout-column-resize-bar-left")) {
+ var delta = ui.offset.left - columnElement.offset().left;
+ if (delta < -columnSize && scope.element.canExpandLeft(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.expandLeft(connectAdjacent);
+ });
+ }
+ else if (delta > columnSize && scope.element.canContractLeft(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.contractLeft(connectAdjacent);
+ });
+ }
+ }
+ else if ($(e.target).hasClass("layout-column-resize-bar-right")) {
+ var delta = ui.offset.left - columnElement.width() - columnElement.offset().left;
+ if (delta > columnSize && scope.element.canExpandRight(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.expandRight(connectAdjacent);
+ });
+ }
+ else if (delta < -columnSize && scope.element.canContractRight(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.contractRight(connectAdjacent);
+ });
+ }
+ }
+
+ },
+ stop: function (e, ui) {
+ scope.$apply(function () {
+ scope.element.editor.isResizing = false;
+ });
+ }
+ });
+ }
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutContent", ["$sce", "scopeConfigurator", "environment",
+ function ($sce, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ $scope.edit = function () {
+ $scope.$root.editElement($scope.element).then(function (args) {
+ $scope.$apply(function () {
+ if (args.cancel)
+ return;
+
+ $scope.element.data = decodeURIComponent(args.element.data);
+ $scope.element.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
+ });
+ });
+ };
+ $scope.updateContent = function (e) {
+ $scope.element.setHtml(e.target.innerHTML);
+ };
+
+ // Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
+ $scope.element.setHtml = function (html) {
+ $scope.element.html = html;
+ $scope.element.htmlUnsafe = $sce.trustAsHtml(html);
+ };
+
+ $scope.element.setHtml(decodeURIComponent($scope.element.html.replace(/\+/g, "%20")));
+ },
+ templateUrl: environment.templateUrl("Content"),
+ replace: true,
+ link: function (scope, element) {
+ // Mouse down events must not be intercepted by drag and drop while inline editing is active,
+ // otherwise clicks in inline editors will have no effect.
+ element.find(".layout-content-markup").mousedown(function (e) {
+ if (scope.element.editor.inlineEditingIsActive) {
+ e.stopPropagation();
+ }
+ });
+ }
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutGrid", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Grid"),
+ replace: true
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutRow", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "x";
+ $scope.sortableOptions["ui-floating"] = true;
+ },
+ templateUrl: environment.templateUrl("Row"),
+ replace: true
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutPopup", [
+ function () {
+ return {
+ restrict: "A",
+ link: function (scope, element, attrs) {
+ var popup = $(element);
+ var trigger = popup.closest(".layout-popup-trigger");
+ var parentElement = popup.closest(".layout-element");
+ trigger.click(function () {
+ popup.toggle();
+ if (popup.is(":visible")) {
+ popup.position({
+ my: attrs.orcLayoutPopupMy || "left top",
+ at: attrs.orcLayoutPopupAt || "left bottom+4px",
+ of: trigger
+ });
+ popup.find("input").first().focus();
+ }
+ });
+ popup.click(function (e) {
+ e.stopPropagation();
+ });
+ parentElement.click(function (e) {
+ popup.hide();
+ });
+ popup.keydown(function (e) {
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 27) // Esc
+ popup.hide();
+ e.stopPropagation();
+ });
+ }
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutToolbox", ["$compile", "environment",
+ function ($compile, environment) {
+ return {
+ restrict: "E",
+ controller: function ($scope, $element) {
+
+ $scope.resetElements = function () {
+
+ $scope.gridElements = [
+ LayoutEditor.Grid.from({
+ toolboxIcon: "\uf00a",
+ toolboxLabel: "Grid",
+ toolboxDescription: "Empty grid.",
+ children: []
+ })
+ ];
+
+ $scope.rowElements = [
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (1 column)",
+ toolboxDescription: "Row with 1 column.",
+ children: LayoutEditor.Column.times(1)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (2 columns)",
+ toolboxDescription: "Row with 2 columns.",
+ children: LayoutEditor.Column.times(2)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (3 columns)",
+ toolboxDescription: "Row with 3 columns.",
+ children: LayoutEditor.Column.times(3)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (4 columns)",
+ toolboxDescription: "Row with 4 columns.",
+ children: LayoutEditor.Column.times(4)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (6 columns)",
+ toolboxDescription: "Row with 6 columns.",
+ children: LayoutEditor.Column.times(6)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (12 columns)",
+ toolboxDescription: "Row with 12 columns.",
+ children: LayoutEditor.Column.times(12)
+ }), LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (empty)",
+ toolboxDescription: "Empty row.",
+ children: []
+ })
+ ];
+
+ $scope.columnElements = [
+ LayoutEditor.Column.from({
+ toolboxIcon: "\uf0db",
+ toolboxLabel: "Column",
+ toolboxDescription: "Empty column.",
+ width: 1,
+ offset: 0,
+ children: []
+ })
+ ];
+
+ $scope.contentElementCategories = _($scope.element.config.categories).map(function (category) {
+ return {
+ name: category.name,
+ elements: _(category.contentTypes).map(function (contentType) {
+ var type = contentType.type;
+ var factory = LayoutEditor.factories[type] || LayoutEditor.factories["Content"];
+ var item = {
+ isTemplated: false,
+ contentType: contentType.id,
+ contentTypeLabel: contentType.label,
+ contentTypeClass: contentType.typeClass,
+ data: null,
+ hasEditor: contentType.hasEditor,
+ html: contentType.html
+ };
+ var element = factory(item);
+ element.toolboxIcon = contentType.icon || "\uf1c9";
+ element.toolboxLabel = contentType.label;
+ element.toolboxDescription = contentType.description;
+ return element;
+ })
+ };
+ });
+
+ };
+
+ $scope.resetElements();
+
+ $scope.getSortableOptions = function (type) {
+ var editorId = $element.closest(".layout-editor").attr("id");
+ var parentClasses;
+ var placeholderClasses;
+ var floating = false;
+
+ switch (type) {
+ case "Grid":
+ parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
+ placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
+ break;
+ case "Row":
+ parentClasses = [".layout-grid"];
+ placeholderClasses = "layout-element layout-container layout-row row ui-sortable-placeholder";
+ break;
+ case "Column":
+ parentClasses = [".layout-row:not(.layout-row-full)"];
+ placeholderClasses = "layout-element layout-container layout-column ui-sortable-placeholder";
+ floating = true; // To ensure a smooth horizontal-list reordering. https://github.com/angular-ui/ui-sortable#floating
+ break;
+ case "Content":
+ parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
+ placeholderClasses = "layout-element layout-content ui-sortable-placeholder";
+ break;
+ }
+
+ return {
+ cursor: "move",
+ connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "),
+ placeholder: placeholderClasses,
+ "ui-floating": floating,
+ create: function (e, ui) {
+ e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox.
+ },
+ start: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.isDragging = true;
+ });
+ },
+ stop: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.isDragging = false;
+ $scope.resetElements();
+ });
+ },
+ over: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.canvas.setIsDropTarget(false);
+ });
+ },
+ }
+ };
+
+ var layoutIsCollapsedCookieName = "layoutToolboxCategory_Layout_IsCollapsed";
+ $scope.layoutIsCollapsed = $.cookie(layoutIsCollapsedCookieName) === "true";
+
+ $scope.toggleLayoutIsCollapsed = function (e) {
+ $scope.layoutIsCollapsed = !$scope.layoutIsCollapsed;
+ $.cookie(layoutIsCollapsedCookieName, $scope.layoutIsCollapsed, { expires: 365 }); // Remember collapsed state for a year.
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ },
+ templateUrl: environment.templateUrl("Toolbox"),
+ replace: true
+ };
+ }
+ ]);
+angular
+ .module("LayoutEditor")
+ .directive("orcLayoutToolboxGroup", ["$compile", "environment",
+ function ($compile, environment) {
+ return {
+ restrict: "E",
+ scope: { category: "=" },
+ controller: function ($scope, $element) {
+ var isCollapsedCookieName = "layoutToolboxCategory_" + $scope.category.name + "_IsCollapsed";
+ $scope.isCollapsed = $.cookie(isCollapsedCookieName) === "true";
+ $scope.toggleIsCollapsed = function (e) {
+ $scope.isCollapsed = !$scope.isCollapsed;
+ $.cookie(isCollapsedCookieName, $scope.isCollapsed, { expires: 365 }); // Remember collapsed state for a year.
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ },
+ templateUrl: environment.templateUrl("ToolboxGroup"),
+ replace: true
+ };
+ }
+ ]);
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js
index ff8c51e02..af9c861e6 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js
@@ -1 +1 @@
-angular.module("LayoutEditor",["ngSanitize","ngResource","ui.sortable"]);var LayoutEditor;(function(n){var t=function(){var n=this;this.clipboardData={};this.setData=function(t,i){n.clipboardData[t]=i};this.getData=function(t){return n.clipboardData[t]};this.disable=function(){this.disabled=!0}};n.Clipboard=new t;angular.module("LayoutEditor").factory("clipboard",function(){return{setData:n.Clipboard.setData,getData:n.Clipboard.getData,disable:n.Clipboard.disable}})})(LayoutEditor||(LayoutEditor={}));angular.module("LayoutEditor").factory("scopeConfigurator",function(n,t){return{configureForElement:function(n,i){i.find(".layout-panel").click(function(n){n.stopPropagation()});i.parent().keydown(function(r){var f=!1,s=!1,u=n.element,e,o;if(!u.editor.isDragging&&!u.editor.inlineEditingIsActive){if(!t.disabled&&(e=u.editor.focusedElement,!!e&&r.ctrlKey))switch(r.which){case 67:e.copy(t);break;case 88:e.cut(t);break;case 86:e.paste(t)}r.ctrlKey||r.shiftKey||r.altKey||r.which!=46?r.ctrlKey||r.shiftKey||r.altKey||r.which!=32&&r.which!=27||(i.find(".layout-panel-action-properties").first().click(),f=!0):(n.delete(u),f=!0);u.type=="Content"&&(r.ctrlKey||r.shiftKey||r.altKey||r.which!=13||(i.find(".layout-panel-action-edit").first().click(),f=!0));!u.children||(r.ctrlKey||r.shiftKey||!r.altKey||r.which!=40||(u.children.length>0&&u.children[0].setIsFocused(),f=!0),u.type=="Column"&&(o=!r.ctrlKey,r.which==37?(r.altKey&&u.expandLeft(o),r.shiftKey&&u.contractRight(o),f=!0):r.which==39&&(r.altKey&&u.contractLeft(o),r.shiftKey&&u.expandRight(o),f=!0)));!u.parent||(r.altKey&&r.which==38&&(u.parent.setIsFocused(),f=!0),u.parent.type=="Row"?r.ctrlKey||r.shiftKey||r.altKey||r.which!=37?r.ctrlKey||r.shiftKey||r.altKey||r.which!=39?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=37?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=39||(u.moveDown(),f=!0):(u.moveUp(),s=!0,f=!0):(u.parent.moveFocusNextChild(u),f=!0):(u.parent.moveFocusPrevChild(u),f=!0):r.ctrlKey||r.shiftKey||r.altKey||r.which!=38?r.ctrlKey||r.shiftKey||r.altKey||r.which!=40?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=38?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=40||(u.moveDown(),f=!0):(u.moveUp(),s=!0,f=!0):(u.parent.moveFocusNextChild(u),f=!0):(u.parent.moveFocusPrevChild(u),f=!0));f&&r.preventDefault();r.stopPropagation();n.$apply();s&&window.setTimeout(function(){n.$apply(function(){u.editor.focusedElement.setIsFocused()})},100)}});n.element.setIsFocusedEventHandlers.push(function(){i.parent().focus()});n.delete=function(n){n.delete()}},configureForContainer:function(t,r){var u=t.element;t.getShowChildrenPlaceholder=function(){return t.element.children.length===0&&!t.element.getIsDropTarget()};t.sortableOptions={cursor:"move",delay:150,disabled:u.getIsSealed(),distance:5,start:function(n,i){t.$apply(function(){u.setIsDropTarget(!0);u.editor.isDragging=!0});i.placeholder.height(i.item.height()-4);i.placeholder.css("min-height",0)},stop:function(){t.$apply(function(){u.editor.isDragging=!1;u.setIsDropTarget(!1)})},over:function(t,f){!f.sender||!f.sender[0].isToolbox||(!f.sender[0].dropTargetTimeout||(n.cancel(f.sender[0].dropTargetTimeout),f.sender[0].dropTargetTimeout=null),n(function(){if(u.type=="Row"){var n=u.editor.dropTargetElement;!n||n.type!="Row"||n.rollbackAddColumn()}u.setIsDropTarget(!1)}),f.sender[0].dropTargetTimeout=n(function(){var n,t,e;if(u.type=="Row"){for(n=f.item.sortable.model,t=Math.floor(12/(u.children.length+1)),n.width=t,n.offset=0,u.beginAddColumn(t),e=_.max(_(r.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function(n){return $(n).height()})),i=1;i<=12;i++)f.placeholder.removeClass("col-xs-"+i);f.placeholder.addClass("col-xs-"+n.width);e>0?(f.placeholder.height(e),f.placeholder.css("min-height",0)):(f.placeholder.height(0),f.placeholder.css("min-height",""))}u.setIsDropTarget(!0)},150))},receive:function(i,r){!r.sender||!r.sender[0].isToolbox||t.$apply(function(){var i=r.item.sortable.model;!i||(u.type=="Row"&&u.commitAddColumn(),i.setEditor(u.editor),i.setParent(u),i.type!="Content"||!i.hasEditor||t.$root.editElement(i).then(function(t){t.cancel||(i.data=decodeURIComponent(t.element.data),i.setHtml(decodeURIComponent(t.element.html.replace(/\+/g,"%20"))));n(function(){t.cancel?i.delete():i.setIsFocused();u.setIsDropTarget(!1)});return}));n(function(){u.setIsDropTarget(!1);!i||i.setIsFocused()})})}};t.click=function(n,t){n.editor.isDragging||n.setIsFocused();t.stopPropagation()};t.getClasses=function(n){var t=["layout-element"];return!n.children||(t.push("layout-container"),n.getIsSealed()&&t.push("layout-container-sealed")),t.push("layout-"+n.type.toLowerCase()),!n.dropTargetClass||t.push(n.dropTargetClass),n.type=="Row"&&(t.push("row"),n.canAddColumn()||t.push("layout-row-full")),n.type=="Column"&&(t.push("col-xs-"+n.width),t.push("col-xs-offset-"+n.offset)),n.type=="Content"&&t.push("layout-content-"+n.contentTypeClass),n.getIsActive()&&t.push("layout-element-active"),n.getIsFocused()&&t.push("layout-element-focused"),n.getIsSelected()&&t.push("layout-element-selected"),n.getIsDropTarget()&&t.push("layout-element-droptarget"),n.isTemplated&&t.push("layout-element-templated"),t}}}});angular.module("LayoutEditor").directive("orcLayoutEditor",function(n){return{restrict:"E",scope:{},controller:function($scope,$element,$attrs,$compile,clipboard){if(!$attrs.model)throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");else $scope.element=eval($attrs.model);$scope.click=function(n,t){n.editor.isDragging||n.setIsFocused();t.stopPropagation()};$scope.getClasses=function(n){var t=["layout-element","layout-container","layout-canvas"];return n.getIsActive()&&t.push("layout-element-active"),n.getIsFocused()&&t.push("layout-element-focused"),n.getIsSelected()&&t.push("layout-element-selected"),n.getIsDropTarget()&&t.push("layout-element-droptarget"),n.isTemplated&&t.push("layout-element-templated"),t};var layoutDesignerHost=$(".layout-designer").data("layout-designer-host");$scope.$root.layoutDesignerHost=layoutDesignerHost;layoutDesignerHost.element.on("replacecanvas",function(n,t){var u=$scope.element,f={data:t.canvas.data,htmlId:t.canvas.htmlId,htmlClass:t.canvas.htmlClass,htmlStyle:t.canvas.htmlStyle,isTemplated:t.canvas.isTemplated,children:t.canvas.children},i,r;layoutDesignerHost.editor=window.layoutEditor=new LayoutEditor.Editor(u.config,f);i="";r=$compile(i)($scope);$(".layout-editor-holder").html(r)});$scope.$root.editElement=function(n){var t=$scope.$root.layoutDesignerHost;return t.editElement(n)};$scope.$root.addElement=function(n){var t=$scope.$root.layoutDesignerHost;return t.addElement(n)};$scope.toggleInlineEditing=function(){if($scope.element.inlineEditingIsActive)tinymce.remove("#layout-editor-"+$scope.$id+" .layout-content-markup"),$element.find(".layout-toolbar-container").hide(),$scope.element.inlineEditingIsActive=!1;else{$scope.element.inlineEditingIsActive=!0;$element.find(".layout-toolbar-container").show();var n="#layout-editor-"+$scope.$id+" .layout-content-h-t-m-l .layout-content-markup[data-templated=false]",t=$(n).first().attr("id");tinymce.init({selector:n,theme:"modern",schema:"html5",plugins:["advlist autolink lists link image charmap print preview hr anchor pagebreak","searchreplace wordcount visualblocks visualchars code fullscreen","insertdatetime media nonbreaking table contextmenu directionality","emoticons template paste textcolor colorpicker textpattern","fullscreen autoresize"],toolbar:"undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",convert_urls:!1,valid_elements:"*[*]",extended_valid_elements:"script[type|defer|src|language]",statusbar:!1,skin:"orchardlightgray",inline:!0,fixed_toolbar_container:"#layout-editor-"+$scope.$id+" .layout-toolbar-container",init_instance_callback:function(n){n.id==t&&tinymce.execCommand("mceFocus",!1,n.id)}})}};$(document).on("cut copy paste",function(n){clipboard.disable();var t=$scope.element.focusedElement;!t||($scope.$apply(function(){switch(n.type){case"copy":t.copy(n.originalEvent.clipboardData);break;case"cut":t.cut(n.originalEvent.clipboardData);break;case"paste":t.paste(n.originalEvent.clipboardData)}}),window.setTimeout(function(){$scope.$apply(function(){!$scope.element.focusedElement||$scope.element.focusedElement.setIsFocused()})},100),n.preventDefault())})},templateUrl:n.templateUrl("Editor"),replace:!0,link:function(n,t){t.find(".layout-toolbar-container").click(function(n){n.stopPropagation()});t.mousedown(function(t){n.element.inlineEditingIsActive&&(t.preventDefault(),t.stopPropagation())});$(window).click(function(){n.element.inlineEditingIsActive||n.$apply(function(){n.element.activeElement=null;n.element.focusedElement=null})})}}});angular.module("LayoutEditor").directive("orcLayoutCanvas",function(n,t){return{restrict:"E",scope:{element:"="},controller:function(t,i){n.configureForElement(t,i);n.configureForContainer(t,i);t.sortableOptions.axis="y"},templateUrl:t.templateUrl("Canvas"),replace:!0}});angular.module("LayoutEditor").directive("orcLayoutChild",function(n){return{restrict:"E",scope:{element:"="},link:function(t,i){var r="",u=n(r)(t);$(i).replaceWith(u)}}});angular.module("LayoutEditor").directive("orcLayoutColumn",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y"},templateUrl:i.templateUrl("Column"),replace:!0,link:function(n,t){t.find(".layout-column-resize-bar").draggable({axis:"x",helper:"clone",revert:!0,start:function(){n.$apply(function(){n.element.editor.isResizing=!0})},drag:function(i,r){var e=t.parent(),o=e.width()/n.element.width,u=!i.ctrlKey,f;$(i.target).hasClass("layout-column-resize-bar-left")?(f=r.offset.left-e.offset().left,f<-o&&n.element.canExpandLeft(u)?n.$apply(function(){n.element.expandLeft(u)}):f>o&&n.element.canContractLeft(u)&&n.$apply(function(){n.element.contractLeft(u)})):$(i.target).hasClass("layout-column-resize-bar-right")&&(f=r.offset.left-e.width()-e.offset().left,f>o&&n.element.canExpandRight(u)?n.$apply(function(){n.element.expandRight(u)}):f<-o&&n.element.canContractRight(u)&&n.$apply(function(){n.element.contractRight(u)}))},stop:function(){n.$apply(function(){n.element.editor.isResizing=!1})}})}}});angular.module("LayoutEditor").directive("orcLayoutContent",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(i,r){t.configureForElement(i,r);i.edit=function(){i.$root.editElement(i.element).then(function(n){i.$apply(function(){n.cancel||(i.element.data=decodeURIComponent(n.element.data),i.element.setHtml(decodeURIComponent(n.element.html.replace(/\+/g,"%20"))))})})};i.updateContent=function(n){i.element.setHtml(n.target.innerHTML)};i.element.setHtml=function(t){i.element.html=t;i.element.htmlUnsafe=n.trustAsHtml(t)};i.element.setHtml(decodeURIComponent(i.element.html.replace(/\+/g,"%20")))},templateUrl:i.templateUrl("Content"),replace:!0,link:function(n,t){t.find(".layout-content-markup").mousedown(function(t){n.element.editor.inlineEditingIsActive&&t.stopPropagation()})}}});angular.module("LayoutEditor").directive("orcLayoutGrid",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y"},templateUrl:i.templateUrl("Grid"),replace:!0}});angular.module("LayoutEditor").directive("orcLayoutRow",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="x";n.sortableOptions["ui-floating"]=!0},templateUrl:i.templateUrl("Row"),replace:!0}});angular.module("LayoutEditor").directive("orcLayoutPopup",function(){return{restrict:"A",link:function(n,t,i){var r=$(t),u=r.closest(".layout-popup-trigger"),f=r.closest(".layout-element");u.click(function(){r.toggle();r.is(":visible")&&(r.position({my:i.orcLayoutPopupMy||"left top",at:i.orcLayoutPopupAt||"left bottom+4px",of:u}),r.find("input").first().focus())});r.click(function(n){n.stopPropagation()});f.click(function(){r.hide()});r.keydown(function(n){n.ctrlKey||n.shiftKey||n.altKey||n.which!=27||r.hide();n.stopPropagation()})}}});angular.module("LayoutEditor").directive("orcLayoutToolbox",function(n,t){return{restrict:"E",controller:function(n,t){n.resetElements=function(){n.gridElements=[LayoutEditor.Grid.from({toolboxIcon:"",toolboxLabel:"Grid",toolboxDescription:"Empty grid.",children:[]})];n.rowElements=[LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (1 column)",toolboxDescription:"Row with 1 column.",children:LayoutEditor.Column.times(1)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (2 columns)",toolboxDescription:"Row with 2 columns.",children:LayoutEditor.Column.times(2)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (3 columns)",toolboxDescription:"Row with 3 columns.",children:LayoutEditor.Column.times(3)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (4 columns)",toolboxDescription:"Row with 4 columns.",children:LayoutEditor.Column.times(4)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (6 columns)",toolboxDescription:"Row with 6 columns.",children:LayoutEditor.Column.times(6)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (12 columns)",toolboxDescription:"Row with 12 columns.",children:LayoutEditor.Column.times(12)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (empty)",toolboxDescription:"Empty row.",children:[]})];n.columnElements=[LayoutEditor.Column.from({toolboxIcon:"",toolboxLabel:"Column",toolboxDescription:"Empty column.",width:1,offset:0,children:[]})];n.contentElementCategories=_(n.element.config.categories).map(function(n){return{name:n.name,elements:_(n.contentTypes).map(function(n){var i=n.type,r=LayoutEditor.factories[i]||LayoutEditor.factories.Content,u={isTemplated:!1,contentType:n.id,contentTypeLabel:n.label,contentTypeClass:n.typeClass,data:null,hasEditor:n.hasEditor,html:n.html},t=r(u);return t.toolboxIcon=n.icon||"",t.toolboxLabel=n.label,t.toolboxDescription=n.description,t})}})};n.resetElements();n.getSortableOptions=function(i){var e=t.closest(".layout-editor").attr("id"),r,u,f=!1;switch(i){case"Grid":r=[".layout-canvas",".layout-column",".layout-common-holder"];u="layout-element layout-container layout-grid ui-sortable-placeholder";break;case"Row":r=[".layout-grid"];u="layout-element layout-container layout-row row ui-sortable-placeholder";break;case"Column":r=[".layout-row:not(.layout-row-full)"];u="layout-element layout-container layout-column ui-sortable-placeholder";f=!0;break;case"Content":r=[".layout-canvas",".layout-column",".layout-common-holder"];u="layout-element layout-content ui-sortable-placeholder"}return{cursor:"move",connectWith:_(r).map(function(n){return"#"+e+" "+n+":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"}).join(", "),placeholder:u,"ui-floating":f,create:function(n){n.target.isToolbox=!0},start:function(){n.$apply(function(){n.element.isDragging=!0})},stop:function(){n.$apply(function(){n.element.isDragging=!1;n.resetElements()})},over:function(){n.$apply(function(){n.element.canvas.setIsDropTarget(!1)})}}};var i="layoutToolboxCategory_Layout_IsCollapsed";n.layoutIsCollapsed=$.cookie(i)==="true";n.toggleLayoutIsCollapsed=function(t){n.layoutIsCollapsed=!n.layoutIsCollapsed;$.cookie(i,n.layoutIsCollapsed,{expires:365});t.preventDefault();t.stopPropagation()}},templateUrl:t.templateUrl("Toolbox"),replace:!0}});angular.module("LayoutEditor").directive("orcLayoutToolboxGroup",function(n,t){return{restrict:"E",scope:{category:"="},controller:function(n){var t="layoutToolboxCategory_"+n.category.name+"_IsCollapsed";n.isCollapsed=$.cookie(t)==="true";n.toggleIsCollapsed=function(i){n.isCollapsed=!n.isCollapsed;$.cookie(t,n.isCollapsed,{expires:365});i.preventDefault();i.stopPropagation()}},templateUrl:t.templateUrl("ToolboxGroup"),replace:!0}});
\ No newline at end of file
+angular.module("LayoutEditor",["ngSanitize","ngResource","ui.sortable"]);var LayoutEditor;(function(n){var t=function(){var n=this;this.clipboardData={};this.setData=function(t,i){n.clipboardData[t]=i};this.getData=function(t){return n.clipboardData[t]};this.disable=function(){this.disabled=!0}};n.Clipboard=new t;angular.module("LayoutEditor").factory("clipboard",[function(){return{setData:n.Clipboard.setData,getData:n.Clipboard.getData,disable:n.Clipboard.disable}}])})(LayoutEditor||(LayoutEditor={}));angular.module("LayoutEditor").factory("scopeConfigurator",["$timeout","clipboard",function(n,t){return{configureForElement:function(n,i){i.find(".layout-panel").click(function(n){n.stopPropagation()});i.parent().keydown(function(r){var f=!1,s=!1,u=n.element,e,o;if(!u.editor.isDragging&&!u.editor.inlineEditingIsActive){if(!t.disabled&&(e=u.editor.focusedElement,!!e&&r.ctrlKey))switch(r.which){case 67:e.copy(t);break;case 88:e.cut(t);break;case 86:e.paste(t)}r.ctrlKey||r.shiftKey||r.altKey||r.which!=46?r.ctrlKey||r.shiftKey||r.altKey||r.which!=32&&r.which!=27||(i.find(".layout-panel-action-properties").first().click(),f=!0):(n.delete(u),f=!0);u.type=="Content"&&(r.ctrlKey||r.shiftKey||r.altKey||r.which!=13||(i.find(".layout-panel-action-edit").first().click(),f=!0));!u.children||(r.ctrlKey||r.shiftKey||!r.altKey||r.which!=40||(u.children.length>0&&u.children[0].setIsFocused(),f=!0),u.type=="Column"&&(o=!r.ctrlKey,r.which==37?(r.altKey&&u.expandLeft(o),r.shiftKey&&u.contractRight(o),f=!0):r.which==39&&(r.altKey&&u.contractLeft(o),r.shiftKey&&u.expandRight(o),f=!0)));!u.parent||(r.altKey&&r.which==38&&(u.parent.setIsFocused(),f=!0),u.parent.type=="Row"?r.ctrlKey||r.shiftKey||r.altKey||r.which!=37?r.ctrlKey||r.shiftKey||r.altKey||r.which!=39?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=37?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=39||(u.moveDown(),f=!0):(u.moveUp(),s=!0,f=!0):(u.parent.moveFocusNextChild(u),f=!0):(u.parent.moveFocusPrevChild(u),f=!0):r.ctrlKey||r.shiftKey||r.altKey||r.which!=38?r.ctrlKey||r.shiftKey||r.altKey||r.which!=40?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=38?!r.ctrlKey||r.shiftKey||r.altKey||r.which!=40||(u.moveDown(),f=!0):(u.moveUp(),s=!0,f=!0):(u.parent.moveFocusNextChild(u),f=!0):(u.parent.moveFocusPrevChild(u),f=!0));f&&r.preventDefault();r.stopPropagation();n.$apply();s&&window.setTimeout(function(){n.$apply(function(){u.editor.focusedElement.setIsFocused()})},100)}});n.element.setIsFocusedEventHandlers.push(function(){i.parent().focus()});n.delete=function(n){n.delete()}},configureForContainer:function(t,r){var u=t.element;t.getShowChildrenPlaceholder=function(){return t.element.children.length===0&&!t.element.getIsDropTarget()};t.sortableOptions={cursor:"move",delay:150,disabled:u.getIsSealed(),distance:5,start:function(n,i){t.$apply(function(){u.setIsDropTarget(!0);u.editor.isDragging=!0});i.placeholder.height(i.item.height()-4);i.placeholder.css("min-height",0)},stop:function(){t.$apply(function(){u.editor.isDragging=!1;u.setIsDropTarget(!1)})},over:function(t,f){!f.sender||!f.sender[0].isToolbox||(!f.sender[0].dropTargetTimeout||(n.cancel(f.sender[0].dropTargetTimeout),f.sender[0].dropTargetTimeout=null),n(function(){if(u.type=="Row"){var n=u.editor.dropTargetElement;!n||n.type!="Row"||n.rollbackAddColumn()}u.setIsDropTarget(!1)}),f.sender[0].dropTargetTimeout=n(function(){var n,t,e;if(u.type=="Row"){for(n=f.item.sortable.model,t=Math.floor(12/(u.children.length+1)),n.width=t,n.offset=0,u.beginAddColumn(t),e=_.max(_(r.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function(n){return $(n).height()})),i=1;i<=12;i++)f.placeholder.removeClass("col-xs-"+i);f.placeholder.addClass("col-xs-"+n.width);e>0?(f.placeholder.height(e),f.placeholder.css("min-height",0)):(f.placeholder.height(0),f.placeholder.css("min-height",""))}u.setIsDropTarget(!0)},150))},receive:function(i,r){!r.sender||!r.sender[0].isToolbox||t.$apply(function(){var i=r.item.sortable.model;!i||(u.type=="Row"&&u.commitAddColumn(),i.setEditor(u.editor),i.setParent(u),i.type!="Content"||!i.hasEditor||t.$root.editElement(i).then(function(t){t.cancel||(i.data=decodeURIComponent(t.element.data),i.setHtml(decodeURIComponent(t.element.html.replace(/\+/g,"%20"))));n(function(){t.cancel?i.delete():i.setIsFocused();u.setIsDropTarget(!1)});return}));n(function(){u.setIsDropTarget(!1);!i||i.setIsFocused()})})}};t.click=function(n,t){n.editor.isDragging||n.setIsFocused();t.stopPropagation()};t.getClasses=function(n){var t=["layout-element"];return!n.children||(t.push("layout-container"),n.getIsSealed()&&t.push("layout-container-sealed")),t.push("layout-"+n.type.toLowerCase()),!n.dropTargetClass||t.push(n.dropTargetClass),n.type=="Row"&&(t.push("row"),n.canAddColumn()||t.push("layout-row-full")),n.type=="Column"&&(t.push("col-xs-"+n.width),t.push("col-xs-offset-"+n.offset)),n.type=="Content"&&t.push("layout-content-"+n.contentTypeClass),n.getIsActive()&&t.push("layout-element-active"),n.getIsFocused()&&t.push("layout-element-focused"),n.getIsSelected()&&t.push("layout-element-selected"),n.getIsDropTarget()&&t.push("layout-element-droptarget"),n.isTemplated&&t.push("layout-element-templated"),t}}}}]);angular.module("LayoutEditor").directive("orcLayoutEditor",["environment",function(n){return{restrict:"E",scope:{},controller:function($scope,$element,$attrs,$compile,clipboard){if(!$attrs.model)throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");else $scope.element=eval($attrs.model);$scope.click=function(n,t){n.editor.isDragging||n.setIsFocused();t.stopPropagation()};$scope.getClasses=function(n){var t=["layout-element","layout-container","layout-canvas"];return n.getIsActive()&&t.push("layout-element-active"),n.getIsFocused()&&t.push("layout-element-focused"),n.getIsSelected()&&t.push("layout-element-selected"),n.getIsDropTarget()&&t.push("layout-element-droptarget"),n.isTemplated&&t.push("layout-element-templated"),t};var layoutDesignerHost=$(".layout-designer").data("layout-designer-host");$scope.$root.layoutDesignerHost=layoutDesignerHost;layoutDesignerHost.element.on("replacecanvas",function(n,t){var u=$scope.element,f={data:t.canvas.data,htmlId:t.canvas.htmlId,htmlClass:t.canvas.htmlClass,htmlStyle:t.canvas.htmlStyle,isTemplated:t.canvas.isTemplated,children:t.canvas.children},i,r;layoutDesignerHost.editor=window.layoutEditor=new LayoutEditor.Editor(u.config,f);i="";r=$compile(i)($scope);$(".layout-editor-holder").html(r)});$scope.$root.editElement=function(n){var t=$scope.$root.layoutDesignerHost;return t.editElement(n)};$scope.$root.addElement=function(n){var t=$scope.$root.layoutDesignerHost;return t.addElement(n)};$scope.toggleInlineEditing=function(){if($scope.element.inlineEditingIsActive)tinymce.remove("#layout-editor-"+$scope.$id+" .layout-content-markup"),$element.find(".layout-toolbar-container").hide(),$scope.element.inlineEditingIsActive=!1;else{$scope.element.inlineEditingIsActive=!0;$element.find(".layout-toolbar-container").show();var n="#layout-editor-"+$scope.$id+" .layout-content-h-t-m-l .layout-content-markup[data-templated=false]",t=$(n).first().attr("id");tinymce.init({selector:n,theme:"modern",schema:"html5",plugins:["advlist autolink lists link image charmap print preview hr anchor pagebreak","searchreplace wordcount visualblocks visualchars code fullscreen","insertdatetime media nonbreaking table contextmenu directionality","emoticons template paste textcolor colorpicker textpattern","fullscreen autoresize"],toolbar:"undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",convert_urls:!1,valid_elements:"*[*]",extended_valid_elements:"script[type|defer|src|language]",statusbar:!1,skin:"orchardlightgray",inline:!0,fixed_toolbar_container:"#layout-editor-"+$scope.$id+" .layout-toolbar-container",init_instance_callback:function(n){n.id==t&&tinymce.execCommand("mceFocus",!1,n.id)}})}};$(document).on("cut copy paste",function(n){clipboard.disable();var t=$scope.element.focusedElement;!t||($scope.$apply(function(){switch(n.type){case"copy":t.copy(n.originalEvent.clipboardData);break;case"cut":t.cut(n.originalEvent.clipboardData);break;case"paste":t.paste(n.originalEvent.clipboardData)}}),window.setTimeout(function(){$scope.$apply(function(){!$scope.element.focusedElement||$scope.element.focusedElement.setIsFocused()})},100),n.preventDefault())})},templateUrl:n.templateUrl("Editor"),replace:!0,link:function(n,t){t.find(".layout-toolbar-container").click(function(n){n.stopPropagation()});t.mousedown(function(t){n.element.inlineEditingIsActive&&(t.preventDefault(),t.stopPropagation())});$(window).click(function(){n.element.inlineEditingIsActive||n.$apply(function(){n.element.activeElement=null;n.element.focusedElement=null})})}}}]);angular.module("LayoutEditor").directive("orcLayoutCanvas",["scopeConfigurator","environment",function(n,t){return{restrict:"E",scope:{element:"="},controller:function(t,i){n.configureForElement(t,i);n.configureForContainer(t,i);t.sortableOptions.axis="y"},templateUrl:t.templateUrl("Canvas"),replace:!0}}]);angular.module("LayoutEditor").directive("orcLayoutChild",["$compile",function(n){return{restrict:"E",scope:{element:"="},link:function(t,i){var r="",u=n(r)(t);$(i).replaceWith(u)}}}]);angular.module("LayoutEditor").directive("orcLayoutColumn",["$compile","scopeConfigurator","environment",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y"},templateUrl:i.templateUrl("Column"),replace:!0,link:function(n,t){t.find(".layout-column-resize-bar").draggable({axis:"x",helper:"clone",revert:!0,start:function(){n.$apply(function(){n.element.editor.isResizing=!0})},drag:function(i,r){var e=t.parent(),o=e.width()/n.element.width,u=!i.ctrlKey,f;$(i.target).hasClass("layout-column-resize-bar-left")?(f=r.offset.left-e.offset().left,f<-o&&n.element.canExpandLeft(u)?n.$apply(function(){n.element.expandLeft(u)}):f>o&&n.element.canContractLeft(u)&&n.$apply(function(){n.element.contractLeft(u)})):$(i.target).hasClass("layout-column-resize-bar-right")&&(f=r.offset.left-e.width()-e.offset().left,f>o&&n.element.canExpandRight(u)?n.$apply(function(){n.element.expandRight(u)}):f<-o&&n.element.canContractRight(u)&&n.$apply(function(){n.element.contractRight(u)}))},stop:function(){n.$apply(function(){n.element.editor.isResizing=!1})}})}}}]);angular.module("LayoutEditor").directive("orcLayoutContent",["$sce","scopeConfigurator","environment",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(i,r){t.configureForElement(i,r);i.edit=function(){i.$root.editElement(i.element).then(function(n){i.$apply(function(){n.cancel||(i.element.data=decodeURIComponent(n.element.data),i.element.setHtml(decodeURIComponent(n.element.html.replace(/\+/g,"%20"))))})})};i.updateContent=function(n){i.element.setHtml(n.target.innerHTML)};i.element.setHtml=function(t){i.element.html=t;i.element.htmlUnsafe=n.trustAsHtml(t)};i.element.setHtml(decodeURIComponent(i.element.html.replace(/\+/g,"%20")))},templateUrl:i.templateUrl("Content"),replace:!0,link:function(n,t){t.find(".layout-content-markup").mousedown(function(t){n.element.editor.inlineEditingIsActive&&t.stopPropagation()})}}}]);angular.module("LayoutEditor").directive("orcLayoutGrid",["$compile","scopeConfigurator","environment",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="y"},templateUrl:i.templateUrl("Grid"),replace:!0}}]);angular.module("LayoutEditor").directive("orcLayoutRow",["$compile","scopeConfigurator","environment",function(n,t,i){return{restrict:"E",scope:{element:"="},controller:function(n,i){t.configureForElement(n,i);t.configureForContainer(n,i);n.sortableOptions.axis="x";n.sortableOptions["ui-floating"]=!0},templateUrl:i.templateUrl("Row"),replace:!0}}]);angular.module("LayoutEditor").directive("orcLayoutPopup",[function(){return{restrict:"A",link:function(n,t,i){var r=$(t),u=r.closest(".layout-popup-trigger"),f=r.closest(".layout-element");u.click(function(){r.toggle();r.is(":visible")&&(r.position({my:i.orcLayoutPopupMy||"left top",at:i.orcLayoutPopupAt||"left bottom+4px",of:u}),r.find("input").first().focus())});r.click(function(n){n.stopPropagation()});f.click(function(){r.hide()});r.keydown(function(n){n.ctrlKey||n.shiftKey||n.altKey||n.which!=27||r.hide();n.stopPropagation()})}}}]);angular.module("LayoutEditor").directive("orcLayoutToolbox",["$compile","environment",function(n,t){return{restrict:"E",controller:function(n,t){n.resetElements=function(){n.gridElements=[LayoutEditor.Grid.from({toolboxIcon:"",toolboxLabel:"Grid",toolboxDescription:"Empty grid.",children:[]})];n.rowElements=[LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (1 column)",toolboxDescription:"Row with 1 column.",children:LayoutEditor.Column.times(1)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (2 columns)",toolboxDescription:"Row with 2 columns.",children:LayoutEditor.Column.times(2)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (3 columns)",toolboxDescription:"Row with 3 columns.",children:LayoutEditor.Column.times(3)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (4 columns)",toolboxDescription:"Row with 4 columns.",children:LayoutEditor.Column.times(4)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (6 columns)",toolboxDescription:"Row with 6 columns.",children:LayoutEditor.Column.times(6)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (12 columns)",toolboxDescription:"Row with 12 columns.",children:LayoutEditor.Column.times(12)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (empty)",toolboxDescription:"Empty row.",children:[]})];n.columnElements=[LayoutEditor.Column.from({toolboxIcon:"",toolboxLabel:"Column",toolboxDescription:"Empty column.",width:1,offset:0,children:[]})];n.contentElementCategories=_(n.element.config.categories).map(function(n){return{name:n.name,elements:_(n.contentTypes).map(function(n){var i=n.type,r=LayoutEditor.factories[i]||LayoutEditor.factories.Content,u={isTemplated:!1,contentType:n.id,contentTypeLabel:n.label,contentTypeClass:n.typeClass,data:null,hasEditor:n.hasEditor,html:n.html},t=r(u);return t.toolboxIcon=n.icon||"",t.toolboxLabel=n.label,t.toolboxDescription=n.description,t})}})};n.resetElements();n.getSortableOptions=function(i){var e=t.closest(".layout-editor").attr("id"),r,u,f=!1;switch(i){case"Grid":r=[".layout-canvas",".layout-column",".layout-common-holder"];u="layout-element layout-container layout-grid ui-sortable-placeholder";break;case"Row":r=[".layout-grid"];u="layout-element layout-container layout-row row ui-sortable-placeholder";break;case"Column":r=[".layout-row:not(.layout-row-full)"];u="layout-element layout-container layout-column ui-sortable-placeholder";f=!0;break;case"Content":r=[".layout-canvas",".layout-column",".layout-common-holder"];u="layout-element layout-content ui-sortable-placeholder"}return{cursor:"move",connectWith:_(r).map(function(n){return"#"+e+" "+n+":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"}).join(", "),placeholder:u,"ui-floating":f,create:function(n){n.target.isToolbox=!0},start:function(){n.$apply(function(){n.element.isDragging=!0})},stop:function(){n.$apply(function(){n.element.isDragging=!1;n.resetElements()})},over:function(){n.$apply(function(){n.element.canvas.setIsDropTarget(!1)})}}};var i="layoutToolboxCategory_Layout_IsCollapsed";n.layoutIsCollapsed=$.cookie(i)==="true";n.toggleLayoutIsCollapsed=function(t){n.layoutIsCollapsed=!n.layoutIsCollapsed;$.cookie(i,n.layoutIsCollapsed,{expires:365});t.preventDefault();t.stopPropagation()}},templateUrl:t.templateUrl("Toolbox"),replace:!0}}]);angular.module("LayoutEditor").directive("orcLayoutToolboxGroup",["$compile","environment",function(n,t){return{restrict:"E",scope:{category:"="},controller:function(n){var t="layoutToolboxCategory_"+n.category.name+"_IsCollapsed";n.isCollapsed=$.cookie(t)==="true";n.toggleIsCollapsed=function(i){n.isCollapsed=!n.isCollapsed;$.cookie(t,n.isCollapsed,{expires:365});i.preventDefault();i.stopPropagation()}},templateUrl:t.templateUrl("ToolboxGroup"),replace:!0}}]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Canvas.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Canvas.js
index adc64cb95..40100caa0 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Canvas.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Canvas.js
@@ -1,15 +1,17 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutCanvas", function (scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element, $attrs) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Canvas"),
- replace: true
- };
- });
\ No newline at end of file
+ .directive("orcLayoutCanvas", ["scopeConfigurator", "environment",
+ function (scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element, $attrs) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Canvas"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Child.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Child.js
index baf371e6a..8cbc59046 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Child.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Child.js
@@ -1,13 +1,15 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutChild", function ($compile) {
- return {
- restrict: "E",
- scope: { element: "=" },
- link: function (scope, element) {
- var template = "";
- var html = $compile(template)(scope);
- $(element).replaceWith(html);
- }
- };
- });
\ No newline at end of file
+ .directive("orcLayoutChild", ["$compile",
+ function ($compile) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ link: function (scope, element) {
+ var template = "";
+ var html = $compile(template)(scope);
+ $(element).replaceWith(html);
+ }
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Column.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Column.js
index 377ffe497..20cadbc58 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Column.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Column.js
@@ -1,64 +1,66 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutColumn", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Column"),
- replace: true,
- link: function (scope, element, attrs) {
- element.find(".layout-column-resize-bar").draggable({
- axis: "x",
- helper: "clone",
- revert: true,
- start: function (e, ui) {
- scope.$apply(function () {
- scope.element.editor.isResizing = true;
- });
- },
- drag: function (e, ui) {
- var columnElement = element.parent();
- var columnSize = columnElement.width() / scope.element.width;
- var connectAdjacent = !e.ctrlKey;
- if ($(e.target).hasClass("layout-column-resize-bar-left")) {
- var delta = ui.offset.left - columnElement.offset().left;
- if (delta < -columnSize && scope.element.canExpandLeft(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.expandLeft(connectAdjacent);
- });
+ .directive("orcLayoutColumn", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Column"),
+ replace: true,
+ link: function (scope, element, attrs) {
+ element.find(".layout-column-resize-bar").draggable({
+ axis: "x",
+ helper: "clone",
+ revert: true,
+ start: function (e, ui) {
+ scope.$apply(function () {
+ scope.element.editor.isResizing = true;
+ });
+ },
+ drag: function (e, ui) {
+ var columnElement = element.parent();
+ var columnSize = columnElement.width() / scope.element.width;
+ var connectAdjacent = !e.ctrlKey;
+ if ($(e.target).hasClass("layout-column-resize-bar-left")) {
+ var delta = ui.offset.left - columnElement.offset().left;
+ if (delta < -columnSize && scope.element.canExpandLeft(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.expandLeft(connectAdjacent);
+ });
+ }
+ else if (delta > columnSize && scope.element.canContractLeft(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.contractLeft(connectAdjacent);
+ });
+ }
}
- else if (delta > columnSize && scope.element.canContractLeft(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.contractLeft(connectAdjacent);
- });
+ else if ($(e.target).hasClass("layout-column-resize-bar-right")) {
+ var delta = ui.offset.left - columnElement.width() - columnElement.offset().left;
+ if (delta > columnSize && scope.element.canExpandRight(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.expandRight(connectAdjacent);
+ });
+ }
+ else if (delta < -columnSize && scope.element.canContractRight(connectAdjacent)) {
+ scope.$apply(function () {
+ scope.element.contractRight(connectAdjacent);
+ });
+ }
}
- }
- else if ($(e.target).hasClass("layout-column-resize-bar-right")) {
- var delta = ui.offset.left - columnElement.width() - columnElement.offset().left;
- if (delta > columnSize && scope.element.canExpandRight(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.expandRight(connectAdjacent);
- });
- }
- else if (delta < -columnSize && scope.element.canContractRight(connectAdjacent)) {
- scope.$apply(function () {
- scope.element.contractRight(connectAdjacent);
- });
- }
- }
- },
- stop: function (e, ui) {
- scope.$apply(function () {
- scope.element.editor.isResizing = false;
- });
- }
- });
- }
- };
- });
\ No newline at end of file
+ },
+ stop: function (e, ui) {
+ scope.$apply(function () {
+ scope.element.editor.isResizing = false;
+ });
+ }
+ });
+ }
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Content.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Content.js
index 5a891a1a8..e7f822dc1 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Content.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Content.js
@@ -1,44 +1,46 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutContent", function ($sce, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- $scope.edit = function () {
- $scope.$root.editElement($scope.element).then(function (args) {
- $scope.$apply(function () {
- if (args.cancel)
- return;
+ .directive("orcLayoutContent", ["$sce", "scopeConfigurator", "environment",
+ function ($sce, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ $scope.edit = function () {
+ $scope.$root.editElement($scope.element).then(function (args) {
+ $scope.$apply(function () {
+ if (args.cancel)
+ return;
- $scope.element.data = decodeURIComponent(args.element.data);
- $scope.element.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
+ $scope.element.data = decodeURIComponent(args.element.data);
+ $scope.element.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
+ });
});
+ };
+ $scope.updateContent = function (e) {
+ $scope.element.setHtml(e.target.innerHTML);
+ };
+
+ // Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
+ $scope.element.setHtml = function (html) {
+ $scope.element.html = html;
+ $scope.element.htmlUnsafe = $sce.trustAsHtml(html);
+ };
+
+ $scope.element.setHtml(decodeURIComponent($scope.element.html.replace(/\+/g, "%20")));
+ },
+ templateUrl: environment.templateUrl("Content"),
+ replace: true,
+ link: function (scope, element) {
+ // Mouse down events must not be intercepted by drag and drop while inline editing is active,
+ // otherwise clicks in inline editors will have no effect.
+ element.find(".layout-content-markup").mousedown(function (e) {
+ if (scope.element.editor.inlineEditingIsActive) {
+ e.stopPropagation();
+ }
});
- };
- $scope.updateContent = function (e) {
- $scope.element.setHtml(e.target.innerHTML);
- };
-
- // Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
- $scope.element.setHtml = function (html) {
- $scope.element.html = html;
- $scope.element.htmlUnsafe = $sce.trustAsHtml(html);
- };
-
- $scope.element.setHtml(decodeURIComponent($scope.element.html.replace(/\+/g, "%20")));
- },
- templateUrl: environment.templateUrl("Content"),
- replace: true,
- link: function (scope, element) {
- // Mouse down events must not be intercepted by drag and drop while inline editing is active,
- // otherwise clicks in inline editors will have no effect.
- element.find(".layout-content-markup").mousedown(function (e) {
- if (scope.element.editor.inlineEditingIsActive) {
- e.stopPropagation();
- }
- });
- }
- };
- });
\ No newline at end of file
+ }
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Editor.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Editor.js
index 869db07e0..47b98a025 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Editor.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Editor.js
@@ -1,172 +1,174 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutEditor", function (environment) {
- return {
- restrict: "E",
- scope: {},
- controller: function ($scope, $element, $attrs, $compile, clipboard) {
- if (!!$attrs.model)
- $scope.element = eval($attrs.model);
- else
- throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");
+ .directive("orcLayoutEditor", ["environment",
+ function (environment) {
+ return {
+ restrict: "E",
+ scope: {},
+ controller: function ($scope, $element, $attrs, $compile, clipboard) {
+ if (!!$attrs.model)
+ $scope.element = eval($attrs.model);
+ else
+ throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");
- $scope.click = function (canvas, e) {
- if (!canvas.editor.isDragging)
- canvas.setIsFocused();
- e.stopPropagation();
- };
-
- $scope.getClasses = function (canvas) {
- var result = ["layout-element", "layout-container", "layout-canvas"];
-
- if (canvas.getIsActive())
- result.push("layout-element-active");
- if (canvas.getIsFocused())
- result.push("layout-element-focused");
- if (canvas.getIsSelected())
- result.push("layout-element-selected");
- if (canvas.getIsDropTarget())
- result.push("layout-element-droptarget");
- if (canvas.isTemplated)
- result.push("layout-element-templated");
-
- return result;
- };
-
- // An unfortunate side-effect of the next hack on line 54 is that the created elements aren't added to the DOM yet, so we can't use it to get to the parent ".layout-desiger" element.
- // Work around: access that element directly (which efectively turns multiple layout editors on a single page impossible).
- // //var layoutDesignerHost = $element.closest(".layout-designer").data("layout-designer-host");
- var layoutDesignerHost = $(".layout-designer").data("layout-designer-host");
-
- $scope.$root.layoutDesignerHost = layoutDesignerHost;
-
- layoutDesignerHost.element.on("replacecanvas", function (e, args) {
- var editor = $scope.element;
- var canvasData = {
- data: args.canvas.data,
- htmlId: args.canvas.htmlId,
- htmlClass: args.canvas.htmlClass,
- htmlStyle: args.canvas.htmlStyle,
- isTemplated: args.canvas.isTemplated,
- children: args.canvas.children
+ $scope.click = function (canvas, e) {
+ if (!canvas.editor.isDragging)
+ canvas.setIsFocused();
+ e.stopPropagation();
};
- // HACK: Instead of simply updating the $scope.element with a new instance, we need to replace the entire orc-layout-editor markup
- // in order for angular to rebind starting with the Canvas element. Otherwise, for some reason, it will rebind starting with the first child of Canvas.
- // You can see this happening when setting a breakpoint in ScopeConfigurator where containers are initialized with drag & drop: on page load, the first element
- // is a Canvas (good), but after having selected another template, the first element is (typically) a Grid (bad).
- // Simply recompiling the orc-layout-editor directive will cause the entire thing to be generated, which works just fine as well (even though not is nice as simply leveraging model binding).
- layoutDesignerHost.editor = window.layoutEditor = new LayoutEditor.Editor(editor.config, canvasData);
- var template = "";
- var html = $compile(template)($scope);
- $(".layout-editor-holder").html(html);
- });
+ $scope.getClasses = function (canvas) {
+ var result = ["layout-element", "layout-container", "layout-canvas"];
- $scope.$root.editElement = function (element) {
- var host = $scope.$root.layoutDesignerHost;
- return host.editElement(element);
- };
+ if (canvas.getIsActive())
+ result.push("layout-element-active");
+ if (canvas.getIsFocused())
+ result.push("layout-element-focused");
+ if (canvas.getIsSelected())
+ result.push("layout-element-selected");
+ if (canvas.getIsDropTarget())
+ result.push("layout-element-droptarget");
+ if (canvas.isTemplated)
+ result.push("layout-element-templated");
- $scope.$root.addElement = function (contentType) {
- var host = $scope.$root.layoutDesignerHost;
- return host.addElement(contentType);
- };
+ return result;
+ };
- $scope.toggleInlineEditing = function () {
- if (!$scope.element.inlineEditingIsActive) {
- $scope.element.inlineEditingIsActive = true;
- $element.find(".layout-toolbar-container").show();
- var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
- var firstContentEditorId = $(selector).first().attr("id");
- tinymce.init({
- selector: selector,
- theme: "modern",
- schema: "html5",
- plugins: [
- "advlist autolink lists link image charmap print preview hr anchor pagebreak",
- "searchreplace wordcount visualblocks visualchars code fullscreen",
- "insertdatetime media nonbreaking table contextmenu directionality",
- "emoticons template paste textcolor colorpicker textpattern",
- "fullscreen autoresize"
- ],
- toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",
- convert_urls: false,
- valid_elements: "*[*]",
- // Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
- extended_valid_elements: "script[type|defer|src|language]",
- statusbar: false,
- skin: "orchardlightgray",
- inline: true,
- fixed_toolbar_container: "#layout-editor-" + $scope.$id + " .layout-toolbar-container",
- init_instance_callback: function (editor) {
- if (editor.id == firstContentEditorId)
- tinymce.execCommand("mceFocus", false, editor.id);
- }
- });
- }
- else {
- tinymce.remove("#layout-editor-" + $scope.$id + " .layout-content-markup");
- $element.find(".layout-toolbar-container").hide();
- $scope.element.inlineEditingIsActive = false;
- }
- };
+ // An unfortunate side-effect of the next hack on line 54 is that the created elements aren't added to the DOM yet, so we can't use it to get to the parent ".layout-desiger" element.
+ // Work around: access that element directly (which efectively turns multiple layout editors on a single page impossible).
+ // //var layoutDesignerHost = $element.closest(".layout-designer").data("layout-designer-host");
+ var layoutDesignerHost = $(".layout-designer").data("layout-designer-host");
- $(document).on("cut copy paste", function (e) {
- // The real clipboard is supported, so disable the peudo clipboard.
- clipboard.disable();
- var focusedElement = $scope.element.focusedElement;
- if (!!focusedElement) {
- $scope.$apply(function () {
- switch (e.type) {
- case "copy":
- focusedElement.copy(e.originalEvent.clipboardData);
- break;
- case "cut":
- focusedElement.cut(e.originalEvent.clipboardData);
- break;
- case "paste":
- focusedElement.paste(e.originalEvent.clipboardData);
- break;
- }
- });
+ $scope.$root.layoutDesignerHost = layoutDesignerHost;
- // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
- window.setTimeout(function () {
- $scope.$apply(function () {
- if (!!$scope.element.focusedElement)
- $scope.element.focusedElement.setIsFocused();
+ layoutDesignerHost.element.on("replacecanvas", function (e, args) {
+ var editor = $scope.element;
+ var canvasData = {
+ data: args.canvas.data,
+ htmlId: args.canvas.htmlId,
+ htmlClass: args.canvas.htmlClass,
+ htmlStyle: args.canvas.htmlStyle,
+ isTemplated: args.canvas.isTemplated,
+ children: args.canvas.children
+ };
+
+ // HACK: Instead of simply updating the $scope.element with a new instance, we need to replace the entire orc-layout-editor markup
+ // in order for angular to rebind starting with the Canvas element. Otherwise, for some reason, it will rebind starting with the first child of Canvas.
+ // You can see this happening when setting a breakpoint in ScopeConfigurator where containers are initialized with drag & drop: on page load, the first element
+ // is a Canvas (good), but after having selected another template, the first element is (typically) a Grid (bad).
+ // Simply recompiling the orc-layout-editor directive will cause the entire thing to be generated, which works just fine as well (even though not is nice as simply leveraging model binding).
+ layoutDesignerHost.editor = window.layoutEditor = new LayoutEditor.Editor(editor.config, canvasData);
+ var template = "";
+ var html = $compile(template)($scope);
+ $(".layout-editor-holder").html(html);
+ });
+
+ $scope.$root.editElement = function (element) {
+ var host = $scope.$root.layoutDesignerHost;
+ return host.editElement(element);
+ };
+
+ $scope.$root.addElement = function (contentType) {
+ var host = $scope.$root.layoutDesignerHost;
+ return host.addElement(contentType);
+ };
+
+ $scope.toggleInlineEditing = function () {
+ if (!$scope.element.inlineEditingIsActive) {
+ $scope.element.inlineEditingIsActive = true;
+ $element.find(".layout-toolbar-container").show();
+ var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
+ var firstContentEditorId = $(selector).first().attr("id");
+ tinymce.init({
+ selector: selector,
+ theme: "modern",
+ schema: "html5",
+ plugins: [
+ "advlist autolink lists link image charmap print preview hr anchor pagebreak",
+ "searchreplace wordcount visualblocks visualchars code fullscreen",
+ "insertdatetime media nonbreaking table contextmenu directionality",
+ "emoticons template paste textcolor colorpicker textpattern",
+ "fullscreen autoresize"
+ ],
+ toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",
+ convert_urls: false,
+ valid_elements: "*[*]",
+ // Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
+ extended_valid_elements: "script[type|defer|src|language]",
+ statusbar: false,
+ skin: "orchardlightgray",
+ inline: true,
+ fixed_toolbar_container: "#layout-editor-" + $scope.$id + " .layout-toolbar-container",
+ init_instance_callback: function (editor) {
+ if (editor.id == firstContentEditorId)
+ tinymce.execCommand("mceFocus", false, editor.id);
+ }
});
- }, 100);
+ }
+ else {
+ tinymce.remove("#layout-editor-" + $scope.$id + " .layout-content-markup");
+ $element.find(".layout-toolbar-container").hide();
+ $scope.element.inlineEditingIsActive = false;
+ }
+ };
- e.preventDefault();
- }
- });
- },
- templateUrl: environment.templateUrl("Editor"),
- replace: true,
- link: function (scope, element) {
- // No clicks should propagate from the TinyMCE toolbars.
- element.find(".layout-toolbar-container").click(function (e) {
- e.stopPropagation();
- });
- // Intercept mousedown on editor while in inline editing mode to
- // prevent current editor from losing focus.
- element.mousedown(function (e) {
- if (scope.element.inlineEditingIsActive) {
- e.preventDefault();
+ $(document).on("cut copy paste", function (e) {
+ // The real clipboard is supported, so disable the peudo clipboard.
+ clipboard.disable();
+ var focusedElement = $scope.element.focusedElement;
+ if (!!focusedElement) {
+ $scope.$apply(function () {
+ switch (e.type) {
+ case "copy":
+ focusedElement.copy(e.originalEvent.clipboardData);
+ break;
+ case "cut":
+ focusedElement.cut(e.originalEvent.clipboardData);
+ break;
+ case "paste":
+ focusedElement.paste(e.originalEvent.clipboardData);
+ break;
+ }
+ });
+
+ // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
+ window.setTimeout(function () {
+ $scope.$apply(function () {
+ if (!!$scope.element.focusedElement)
+ $scope.element.focusedElement.setIsFocused();
+ });
+ }, 100);
+
+ e.preventDefault();
+ }
+ });
+ },
+ templateUrl: environment.templateUrl("Editor"),
+ replace: true,
+ link: function (scope, element) {
+ // No clicks should propagate from the TinyMCE toolbars.
+ element.find(".layout-toolbar-container").click(function (e) {
e.stopPropagation();
- }
- })
- // Unfocus and unselect everything on click outside of canvas.
- $(window).click(function (e) {
- // Except when in inline editing mode.
- if (!scope.element.inlineEditingIsActive) {
- scope.$apply(function () {
- scope.element.activeElement = null;
- scope.element.focusedElement = null;
- });
- }
- });
- }
- };
- });
\ No newline at end of file
+ });
+ // Intercept mousedown on editor while in inline editing mode to
+ // prevent current editor from losing focus.
+ element.mousedown(function (e) {
+ if (scope.element.inlineEditingIsActive) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ })
+ // Unfocus and unselect everything on click outside of canvas.
+ $(window).click(function (e) {
+ // Except when in inline editing mode.
+ if (!scope.element.inlineEditingIsActive) {
+ scope.$apply(function () {
+ scope.element.activeElement = null;
+ scope.element.focusedElement = null;
+ });
+ }
+ });
+ }
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Grid.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Grid.js
index 4ec328388..c87c27352 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Grid.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Grid.js
@@ -1,15 +1,17 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutGrid", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "y";
- },
- templateUrl: environment.templateUrl("Grid"),
- replace: true
- };
- });
\ No newline at end of file
+ .directive("orcLayoutGrid", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "y";
+ },
+ templateUrl: environment.templateUrl("Grid"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Popup.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Popup.js
index c47992290..75167e286 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Popup.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Popup.js
@@ -1,34 +1,36 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutPopup", function () {
- return {
- restrict: "A",
- link: function (scope, element, attrs) {
- var popup = $(element);
- var trigger = popup.closest(".layout-popup-trigger");
- var parentElement = popup.closest(".layout-element");
- trigger.click(function () {
- popup.toggle();
- if (popup.is(":visible")) {
- popup.position({
- my: attrs.orcLayoutPopupMy || "left top",
- at: attrs.orcLayoutPopupAt || "left bottom+4px",
- of: trigger
- });
- popup.find("input").first().focus();
- }
- });
- popup.click(function (e) {
- e.stopPropagation();
- });
- parentElement.click(function (e) {
- popup.hide();
- });
- popup.keydown(function (e) {
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 27) // Esc
+ .directive("orcLayoutPopup", [
+ function () {
+ return {
+ restrict: "A",
+ link: function (scope, element, attrs) {
+ var popup = $(element);
+ var trigger = popup.closest(".layout-popup-trigger");
+ var parentElement = popup.closest(".layout-element");
+ trigger.click(function () {
+ popup.toggle();
+ if (popup.is(":visible")) {
+ popup.position({
+ my: attrs.orcLayoutPopupMy || "left top",
+ at: attrs.orcLayoutPopupAt || "left bottom+4px",
+ of: trigger
+ });
+ popup.find("input").first().focus();
+ }
+ });
+ popup.click(function (e) {
+ e.stopPropagation();
+ });
+ parentElement.click(function (e) {
popup.hide();
- e.stopPropagation();
- });
- }
- };
- });
\ No newline at end of file
+ });
+ popup.keydown(function (e) {
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 27) // Esc
+ popup.hide();
+ e.stopPropagation();
+ });
+ }
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Row.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Row.js
index 090990e24..b49eb86c1 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Row.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Row.js
@@ -1,16 +1,18 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutRow", function ($compile, scopeConfigurator, environment) {
- return {
- restrict: "E",
- scope: { element: "=" },
- controller: function ($scope, $element) {
- scopeConfigurator.configureForElement($scope, $element);
- scopeConfigurator.configureForContainer($scope, $element);
- $scope.sortableOptions["axis"] = "x";
- $scope.sortableOptions["ui-floating"] = true;
- },
- templateUrl: environment.templateUrl("Row"),
- replace: true
- };
- });
\ No newline at end of file
+ .directive("orcLayoutRow", ["$compile", "scopeConfigurator", "environment",
+ function ($compile, scopeConfigurator, environment) {
+ return {
+ restrict: "E",
+ scope: { element: "=" },
+ controller: function ($scope, $element) {
+ scopeConfigurator.configureForElement($scope, $element);
+ scopeConfigurator.configureForContainer($scope, $element);
+ $scope.sortableOptions["axis"] = "x";
+ $scope.sortableOptions["ui-floating"] = true;
+ },
+ templateUrl: environment.templateUrl("Row"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Toolbox.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Toolbox.js
index 0719c6c4f..f3edc0917 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Toolbox.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/Toolbox.js
@@ -1,168 +1,170 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutToolbox", function ($compile, environment) {
- return {
- restrict: "E",
- controller: function ($scope, $element) {
+ .directive("orcLayoutToolbox", ["$compile", "environment",
+ function ($compile, environment) {
+ return {
+ restrict: "E",
+ controller: function ($scope, $element) {
- $scope.resetElements = function () {
+ $scope.resetElements = function () {
- $scope.gridElements = [
- LayoutEditor.Grid.from({
- toolboxIcon: "\uf00a",
- toolboxLabel: "Grid",
- toolboxDescription: "Empty grid.",
- children: []
- })
- ];
-
- $scope.rowElements = [
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (1 column)",
- toolboxDescription: "Row with 1 column.",
- children: LayoutEditor.Column.times(1)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (2 columns)",
- toolboxDescription: "Row with 2 columns.",
- children: LayoutEditor.Column.times(2)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (3 columns)",
- toolboxDescription: "Row with 3 columns.",
- children: LayoutEditor.Column.times(3)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (4 columns)",
- toolboxDescription: "Row with 4 columns.",
- children: LayoutEditor.Column.times(4)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (6 columns)",
- toolboxDescription: "Row with 6 columns.",
- children: LayoutEditor.Column.times(6)
- }),
- LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (12 columns)",
- toolboxDescription: "Row with 12 columns.",
- children: LayoutEditor.Column.times(12)
- }), LayoutEditor.Row.from({
- toolboxIcon: "\uf0c9",
- toolboxLabel: "Row (empty)",
- toolboxDescription: "Empty row.",
- children: []
- })
- ];
-
- $scope.columnElements = [
- LayoutEditor.Column.from({
- toolboxIcon: "\uf0db",
- toolboxLabel: "Column",
- toolboxDescription: "Empty column.",
- width: 1,
- offset: 0,
- children: []
- })
- ];
-
- $scope.contentElementCategories = _($scope.element.config.categories).map(function (category) {
- return {
- name: category.name,
- elements: _(category.contentTypes).map(function (contentType) {
- var type = contentType.type;
- var factory = LayoutEditor.factories[type] || LayoutEditor.factories["Content"];
- var item = {
- isTemplated: false,
- contentType: contentType.id,
- contentTypeLabel: contentType.label,
- contentTypeClass: contentType.typeClass,
- data: null,
- hasEditor: contentType.hasEditor,
- html: contentType.html
- };
- var element = factory(item);
- element.toolboxIcon = contentType.icon || "\uf1c9";
- element.toolboxLabel = contentType.label;
- element.toolboxDescription = contentType.description;
- return element;
+ $scope.gridElements = [
+ LayoutEditor.Grid.from({
+ toolboxIcon: "\uf00a",
+ toolboxLabel: "Grid",
+ toolboxDescription: "Empty grid.",
+ children: []
})
- };
- });
+ ];
- };
+ $scope.rowElements = [
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (1 column)",
+ toolboxDescription: "Row with 1 column.",
+ children: LayoutEditor.Column.times(1)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (2 columns)",
+ toolboxDescription: "Row with 2 columns.",
+ children: LayoutEditor.Column.times(2)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (3 columns)",
+ toolboxDescription: "Row with 3 columns.",
+ children: LayoutEditor.Column.times(3)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (4 columns)",
+ toolboxDescription: "Row with 4 columns.",
+ children: LayoutEditor.Column.times(4)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (6 columns)",
+ toolboxDescription: "Row with 6 columns.",
+ children: LayoutEditor.Column.times(6)
+ }),
+ LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (12 columns)",
+ toolboxDescription: "Row with 12 columns.",
+ children: LayoutEditor.Column.times(12)
+ }), LayoutEditor.Row.from({
+ toolboxIcon: "\uf0c9",
+ toolboxLabel: "Row (empty)",
+ toolboxDescription: "Empty row.",
+ children: []
+ })
+ ];
- $scope.resetElements();
+ $scope.columnElements = [
+ LayoutEditor.Column.from({
+ toolboxIcon: "\uf0db",
+ toolboxLabel: "Column",
+ toolboxDescription: "Empty column.",
+ width: 1,
+ offset: 0,
+ children: []
+ })
+ ];
- $scope.getSortableOptions = function (type) {
- var editorId = $element.closest(".layout-editor").attr("id");
- var parentClasses;
- var placeholderClasses;
- var floating = false;
+ $scope.contentElementCategories = _($scope.element.config.categories).map(function (category) {
+ return {
+ name: category.name,
+ elements: _(category.contentTypes).map(function (contentType) {
+ var type = contentType.type;
+ var factory = LayoutEditor.factories[type] || LayoutEditor.factories["Content"];
+ var item = {
+ isTemplated: false,
+ contentType: contentType.id,
+ contentTypeLabel: contentType.label,
+ contentTypeClass: contentType.typeClass,
+ data: null,
+ hasEditor: contentType.hasEditor,
+ html: contentType.html
+ };
+ var element = factory(item);
+ element.toolboxIcon = contentType.icon || "\uf1c9";
+ element.toolboxLabel = contentType.label;
+ element.toolboxDescription = contentType.description;
+ return element;
+ })
+ };
+ });
- switch (type) {
- case "Grid":
- parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
- placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
- break;
- case "Row":
- parentClasses = [".layout-grid"];
- placeholderClasses = "layout-element layout-container layout-row row ui-sortable-placeholder";
- break;
- case "Column":
- parentClasses = [".layout-row:not(.layout-row-full)"];
- placeholderClasses = "layout-element layout-container layout-column ui-sortable-placeholder";
- floating = true; // To ensure a smooth horizontal-list reordering. https://github.com/angular-ui/ui-sortable#floating
- break;
- case "Content":
- parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
- placeholderClasses = "layout-element layout-content ui-sortable-placeholder";
- break;
- }
+ };
- return {
- cursor: "move",
- connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "),
- placeholder: placeholderClasses,
- "ui-floating": floating,
- create: function (e, ui) {
- e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox.
- },
- start: function (e, ui) {
- $scope.$apply(function () {
- $scope.element.isDragging = true;
- });
- },
- stop: function (e, ui) {
- $scope.$apply(function () {
- $scope.element.isDragging = false;
- $scope.resetElements();
- });
- },
- over: function (e, ui) {
- $scope.$apply(function () {
- $scope.element.canvas.setIsDropTarget(false);
- });
- },
- }
- };
+ $scope.resetElements();
- var layoutIsCollapsedCookieName = "layoutToolboxCategory_Layout_IsCollapsed";
- $scope.layoutIsCollapsed = $.cookie(layoutIsCollapsedCookieName) === "true";
+ $scope.getSortableOptions = function (type) {
+ var editorId = $element.closest(".layout-editor").attr("id");
+ var parentClasses;
+ var placeholderClasses;
+ var floating = false;
- $scope.toggleLayoutIsCollapsed = function (e) {
- $scope.layoutIsCollapsed = !$scope.layoutIsCollapsed;
- $.cookie(layoutIsCollapsedCookieName, $scope.layoutIsCollapsed, { expires: 365 }); // Remember collapsed state for a year.
- e.preventDefault();
- e.stopPropagation();
- };
- },
- templateUrl: environment.templateUrl("Toolbox"),
- replace: true
- };
- });
\ No newline at end of file
+ switch (type) {
+ case "Grid":
+ parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
+ placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
+ break;
+ case "Row":
+ parentClasses = [".layout-grid"];
+ placeholderClasses = "layout-element layout-container layout-row row ui-sortable-placeholder";
+ break;
+ case "Column":
+ parentClasses = [".layout-row:not(.layout-row-full)"];
+ placeholderClasses = "layout-element layout-container layout-column ui-sortable-placeholder";
+ floating = true; // To ensure a smooth horizontal-list reordering. https://github.com/angular-ui/ui-sortable#floating
+ break;
+ case "Content":
+ parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
+ placeholderClasses = "layout-element layout-content ui-sortable-placeholder";
+ break;
+ }
+
+ return {
+ cursor: "move",
+ connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "),
+ placeholder: placeholderClasses,
+ "ui-floating": floating,
+ create: function (e, ui) {
+ e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox.
+ },
+ start: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.isDragging = true;
+ });
+ },
+ stop: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.isDragging = false;
+ $scope.resetElements();
+ });
+ },
+ over: function (e, ui) {
+ $scope.$apply(function () {
+ $scope.element.canvas.setIsDropTarget(false);
+ });
+ },
+ }
+ };
+
+ var layoutIsCollapsedCookieName = "layoutToolboxCategory_Layout_IsCollapsed";
+ $scope.layoutIsCollapsed = $.cookie(layoutIsCollapsedCookieName) === "true";
+
+ $scope.toggleLayoutIsCollapsed = function (e) {
+ $scope.layoutIsCollapsed = !$scope.layoutIsCollapsed;
+ $.cookie(layoutIsCollapsedCookieName, $scope.layoutIsCollapsed, { expires: 365 }); // Remember collapsed state for a year.
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ },
+ templateUrl: environment.templateUrl("Toolbox"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/ToolboxGroup.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/ToolboxGroup.js
index 6b2bc1355..7de7c3b70 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/ToolboxGroup.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Directives/ToolboxGroup.js
@@ -1,20 +1,22 @@
angular
.module("LayoutEditor")
- .directive("orcLayoutToolboxGroup", function ($compile, environment) {
- return {
- restrict: "E",
- scope: { category: "=" },
- controller: function ($scope, $element) {
- var isCollapsedCookieName = "layoutToolboxCategory_" + $scope.category.name + "_IsCollapsed";
- $scope.isCollapsed = $.cookie(isCollapsedCookieName) === "true";
- $scope.toggleIsCollapsed = function (e) {
- $scope.isCollapsed = !$scope.isCollapsed;
- $.cookie(isCollapsedCookieName, $scope.isCollapsed, { expires: 365 }); // Remember collapsed state for a year.
- e.preventDefault();
- e.stopPropagation();
- };
- },
- templateUrl: environment.templateUrl("ToolboxGroup"),
- replace: true
- };
- });
\ No newline at end of file
+ .directive("orcLayoutToolboxGroup", ["$compile", "environment",
+ function ($compile, environment) {
+ return {
+ restrict: "E",
+ scope: { category: "=" },
+ controller: function ($scope, $element) {
+ var isCollapsedCookieName = "layoutToolboxCategory_" + $scope.category.name + "_IsCollapsed";
+ $scope.isCollapsed = $.cookie(isCollapsedCookieName) === "true";
+ $scope.toggleIsCollapsed = function (e) {
+ $scope.isCollapsed = !$scope.isCollapsed;
+ $.cookie(isCollapsedCookieName, $scope.isCollapsed, { expires: 365 }); // Remember collapsed state for a year.
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ },
+ templateUrl: environment.templateUrl("ToolboxGroup"),
+ replace: true
+ };
+ }
+ ]);
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/Clipboard.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/Clipboard.js
index 70ba97241..b0be0d474 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/Clipboard.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/Clipboard.js
@@ -20,11 +20,13 @@
angular
.module("LayoutEditor")
- .factory("clipboard", function() {
- return {
- setData: LayoutEditor.Clipboard.setData,
- getData: LayoutEditor.Clipboard.getData,
- disable: LayoutEditor.Clipboard.disable
- };
- });
+ .factory("clipboard", [
+ function() {
+ return {
+ setData: LayoutEditor.Clipboard.setData,
+ getData: LayoutEditor.Clipboard.getData,
+ disable: LayoutEditor.Clipboard.disable
+ };
+ }
+ ]);
})(LayoutEditor || (LayoutEditor = {}));
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/ScopeConfigurator.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/ScopeConfigurator.js
index fd41a58ba..dd5fbd221 100644
--- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/ScopeConfigurator.js
+++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor/Services/ScopeConfigurator.js
@@ -1,317 +1,319 @@
angular
.module("LayoutEditor")
- .factory("scopeConfigurator", function ($timeout, clipboard) {
- return {
+ .factory("scopeConfigurator", ["$timeout", "clipboard",
+ function ($timeout, clipboard) {
+ return {
- configureForElement: function ($scope, $element) {
+ configureForElement: function ($scope, $element) {
- $element.find(".layout-panel").click(function (e) {
- e.stopPropagation();
- });
+ $element.find(".layout-panel").click(function (e) {
+ e.stopPropagation();
+ });
- $element.parent().keydown(function (e) {
- var handled = false;
- var resetFocus = false;
- var element = $scope.element;
+ $element.parent().keydown(function (e) {
+ var handled = false;
+ var resetFocus = false;
+ var element = $scope.element;
- if (element.editor.isDragging || element.editor.inlineEditingIsActive)
- return;
+ if (element.editor.isDragging || element.editor.inlineEditingIsActive)
+ return;
- // If the "real" clipboard works, then the pseudo-clipboard will have been disabled.
- if (!clipboard.disabled) {
- var focusedElement = element.editor.focusedElement;
- if (!!focusedElement) {
- // Pseudo clipboard handling for browsers not allowing real clipboard operations.
- if (e.ctrlKey) {
- switch (e.which) {
- case 67: // C
- focusedElement.copy(clipboard);
- break;
- case 88: // X
- focusedElement.cut(clipboard);
- break;
- case 86: // V
- focusedElement.paste(clipboard);
- break;
+ // If the "real" clipboard works, then the pseudo-clipboard will have been disabled.
+ if (!clipboard.disabled) {
+ var focusedElement = element.editor.focusedElement;
+ if (!!focusedElement) {
+ // Pseudo clipboard handling for browsers not allowing real clipboard operations.
+ if (e.ctrlKey) {
+ switch (e.which) {
+ case 67: // C
+ focusedElement.copy(clipboard);
+ break;
+ case 88: // X
+ focusedElement.cut(clipboard);
+ break;
+ case 86: // V
+ focusedElement.paste(clipboard);
+ break;
+ }
}
}
}
- }
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 46) { // Del
- $scope.delete(element);
- handled = true;
- } else if (!e.ctrlKey && !e.shiftKey && !e.altKey && (e.which == 32 || e.which == 27)) { // Space or Esc
- $element.find(".layout-panel-action-properties").first().click();
- handled = true;
- }
-
- if (element.type == "Content") { // This is a content element.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 13) { // Enter
- $element.find(".layout-panel-action-edit").first().click();
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 46) { // Del
+ $scope.delete(element);
handled = true;
- }
- }
-
- if (!!element.children) { // This is a container.
- if (!e.ctrlKey && !e.shiftKey && e.altKey && e.which == 40) { // Alt+Down
- if (element.children.length > 0)
- element.children[0].setIsFocused();
+ } else if (!e.ctrlKey && !e.shiftKey && !e.altKey && (e.which == 32 || e.which == 27)) { // Space or Esc
+ $element.find(".layout-panel-action-properties").first().click();
handled = true;
}
- if (element.type == "Column") { // This is a column.
- var connectAdjacent = !e.ctrlKey;
- if (e.which == 37) { // Left
- if (e.altKey)
- element.expandLeft(connectAdjacent);
- if (e.shiftKey)
- element.contractRight(connectAdjacent);
- handled = true;
- } else if (e.which == 39) { // Right
- if (e.altKey)
- element.contractLeft(connectAdjacent);
- if (e.shiftKey)
- element.expandRight(connectAdjacent);
+ if (element.type == "Content") { // This is a content element.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 13) { // Enter
+ $element.find(".layout-panel-action-edit").first().click();
handled = true;
}
}
+
+ if (!!element.children) { // This is a container.
+ if (!e.ctrlKey && !e.shiftKey && e.altKey && e.which == 40) { // Alt+Down
+ if (element.children.length > 0)
+ element.children[0].setIsFocused();
+ handled = true;
+ }
+
+ if (element.type == "Column") { // This is a column.
+ var connectAdjacent = !e.ctrlKey;
+ if (e.which == 37) { // Left
+ if (e.altKey)
+ element.expandLeft(connectAdjacent);
+ if (e.shiftKey)
+ element.contractRight(connectAdjacent);
+ handled = true;
+ } else if (e.which == 39) { // Right
+ if (e.altKey)
+ element.contractLeft(connectAdjacent);
+ if (e.shiftKey)
+ element.expandRight(connectAdjacent);
+ handled = true;
+ }
+ }
+ }
+
+ if (!!element.parent) { // This is a child.
+ if (e.altKey && e.which == 38) { // Alt+Up
+ element.parent.setIsFocused();
+ handled = true;
+ }
+
+ if (element.parent.type == "Row") { // Parent is a horizontal container.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Left
+ element.parent.moveFocusPrevChild(element);
+ handled = true;
+ }
+ else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Right
+ element.parent.moveFocusNextChild(element);
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Ctrl+Left
+ element.moveUp();
+ resetFocus = true;
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Ctrl+Right
+ element.moveDown();
+ handled = true;
+ }
+ }
+ else { // Parent is a vertical container.
+ if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Up
+ element.parent.moveFocusPrevChild(element);
+ handled = true;
+ }
+ else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Down
+ element.parent.moveFocusNextChild(element);
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Ctrl+Up
+ element.moveUp();
+ resetFocus = true;
+ handled = true;
+ }
+ else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Ctrl+Down
+ element.moveDown();
+ handled = true;
+ }
+ }
+ }
+
+ if (handled) {
+ e.preventDefault();
+ }
+
+ e.stopPropagation();
+
+ $scope.$apply(); // Event is not triggered by Angular directive but raw event handler on element.
+
+ // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
+ if (resetFocus) {
+ window.setTimeout(function () {
+ $scope.$apply(function () {
+ element.editor.focusedElement.setIsFocused();
+ });
+ }, 100);
+ }
+ });
+
+ $scope.element.setIsFocusedEventHandlers.push(function () {
+ $element.parent().focus();
+ });
+
+ $scope.delete = function (element) {
+ element.delete();
}
+ },
- if (!!element.parent) { // This is a child.
- if (e.altKey && e.which == 38) { // Alt+Up
- element.parent.setIsFocused();
- handled = true;
- }
+ configureForContainer: function ($scope, $element) {
+ var element = $scope.element;
- if (element.parent.type == "Row") { // Parent is a horizontal container.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Left
- element.parent.moveFocusPrevChild(element);
- handled = true;
- }
- else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Right
- element.parent.moveFocusNextChild(element);
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 37) { // Ctrl+Left
- element.moveUp();
- resetFocus = true;
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 39) { // Ctrl+Right
- element.moveDown();
- handled = true;
- }
- }
- else { // Parent is a vertical container.
- if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Up
- element.parent.moveFocusPrevChild(element);
- handled = true;
- }
- else if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Down
- element.parent.moveFocusNextChild(element);
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 38) { // Ctrl+Up
- element.moveUp();
- resetFocus = true;
- handled = true;
- }
- else if (e.ctrlKey && !e.shiftKey && !e.altKey && e.which == 40) { // Ctrl+Down
- element.moveDown();
- handled = true;
- }
- }
- }
+ //$scope.isReceiving = false; // True when container is receiving an external element via drag/drop.
+ $scope.getShowChildrenPlaceholder = function () {
+ return $scope.element.children.length === 0 && !$scope.element.getIsDropTarget();
+ };
- if (handled) {
- e.preventDefault();
- }
-
- e.stopPropagation();
-
- $scope.$apply(); // Event is not triggered by Angular directive but raw event handler on element.
-
- // HACK: Workaround because of how Angular treats the DOM when elements are shifted around - input focus is sometimes lost.
- if (resetFocus) {
- window.setTimeout(function () {
+ $scope.sortableOptions = {
+ cursor: "move",
+ delay: 150,
+ disabled: element.getIsSealed(),
+ distance: 5,
+ //handle: element.children.length < 2 ? ".imaginary-class" : false, // For some reason doesn't get re-evaluated after adding more children.
+ start: function (e, ui) {
$scope.$apply(function () {
- element.editor.focusedElement.setIsFocused();
+ element.setIsDropTarget(true);
+ element.editor.isDragging = true;
});
- }, 100);
- }
- });
-
- $scope.element.setIsFocusedEventHandlers.push(function () {
- $element.parent().focus();
- });
-
- $scope.delete = function (element) {
- element.delete();
- }
- },
-
- configureForContainer: function ($scope, $element) {
- var element = $scope.element;
-
- //$scope.isReceiving = false; // True when container is receiving an external element via drag/drop.
- $scope.getShowChildrenPlaceholder = function () {
- return $scope.element.children.length === 0 && !$scope.element.getIsDropTarget();
- };
-
- $scope.sortableOptions = {
- cursor: "move",
- delay: 150,
- disabled: element.getIsSealed(),
- distance: 5,
- //handle: element.children.length < 2 ? ".imaginary-class" : false, // For some reason doesn't get re-evaluated after adding more children.
- start: function (e, ui) {
- $scope.$apply(function () {
- element.setIsDropTarget(true);
- element.editor.isDragging = true;
- });
- // Make the drop target placeholder as high as the item being dragged.
- ui.placeholder.height(ui.item.height() - 4);
- ui.placeholder.css("min-height", 0);
- },
- stop: function (e, ui) {
- $scope.$apply(function () {
- element.editor.isDragging = false;
- element.setIsDropTarget(false);
- });
- },
- over: function (e, ui) {
- if (!!ui.sender && !!ui.sender[0].isToolbox) {
- if (!!ui.sender[0].dropTargetTimeout) {
- $timeout.cancel(ui.sender[0].dropTargetTimeout);
- ui.sender[0].dropTargetTimeout = null;
- }
- $timeout(function () {
- if (element.type == "Row") {
- // If there was a previous drop target and it was a row, roll back any pending column adds to it.
- var previousDropTarget = element.editor.dropTargetElement;
- if (!!previousDropTarget && previousDropTarget.type == "Row")
- previousDropTarget.rollbackAddColumn();
- }
+ // Make the drop target placeholder as high as the item being dragged.
+ ui.placeholder.height(ui.item.height() - 4);
+ ui.placeholder.css("min-height", 0);
+ },
+ stop: function (e, ui) {
+ $scope.$apply(function () {
+ element.editor.isDragging = false;
element.setIsDropTarget(false);
});
- ui.sender[0].dropTargetTimeout = $timeout(function () {
- if (element.type == "Row") {
- var receivedColumn = ui.item.sortable.model;
- var receivedColumnWidth = Math.floor(12 / (element.children.length + 1));
- receivedColumn.width = receivedColumnWidth;
- receivedColumn.offset = 0;
- element.beginAddColumn(receivedColumnWidth);
- // Make the drop target placeholder the correct width and as high as the highest existing column in the row.
- var maxHeight = _.max(_($element.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function (e) {
- return $(e).height();
- }));
- for (i = 1; i <= 12; i++)
- ui.placeholder.removeClass("col-xs-" + i);
- ui.placeholder.addClass("col-xs-" + receivedColumn.width);
- if (maxHeight > 0) {
- ui.placeholder.height(maxHeight);
- ui.placeholder.css("min-height", 0);
- }
- else {
- ui.placeholder.height(0);
- ui.placeholder.css("min-height", "");
- }
- }
- element.setIsDropTarget(true);
- }, 150);
- }
- },
- receive: function (e, ui) {
- if (!!ui.sender && !!ui.sender[0].isToolbox) {
- $scope.$apply(function () {
- var receivedElement = ui.item.sortable.model;
- if (!!receivedElement) {
- if (element.type == "Row")
- element.commitAddColumn();
- // Should ideally call LayoutEditor.Container.addChild() instead, but since this handler
- // is run *before* the ui-sortable directive's handler, if we try to add the child to the
- // array that handler will get an exception when trying to do the same.
- // Because of this, we need to invoke "setParent" so that specific container types can perform element speficic initialization.
- receivedElement.setEditor(element.editor);
- receivedElement.setParent(element);
- if (receivedElement.type == "Content" && !!receivedElement.hasEditor) {
- $scope.$root.editElement(receivedElement).then(function (args) {
- if (!args.cancel) {
- receivedElement.data = decodeURIComponent(args.element.data);
- receivedElement.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
- }
- $timeout(function () {
- if (!!args.cancel)
- receivedElement.delete();
- else
- receivedElement.setIsFocused();
- //$scope.isReceiving = false;
- element.setIsDropTarget(false);
-
- });
- return;
- });
- }
+ },
+ over: function (e, ui) {
+ if (!!ui.sender && !!ui.sender[0].isToolbox) {
+ if (!!ui.sender[0].dropTargetTimeout) {
+ $timeout.cancel(ui.sender[0].dropTargetTimeout);
+ ui.sender[0].dropTargetTimeout = null;
}
$timeout(function () {
- //$scope.isReceiving = false;
+ if (element.type == "Row") {
+ // If there was a previous drop target and it was a row, roll back any pending column adds to it.
+ var previousDropTarget = element.editor.dropTargetElement;
+ if (!!previousDropTarget && previousDropTarget.type == "Row")
+ previousDropTarget.rollbackAddColumn();
+ }
element.setIsDropTarget(false);
- if (!!receivedElement)
- receivedElement.setIsFocused();
});
- });
+ ui.sender[0].dropTargetTimeout = $timeout(function () {
+ if (element.type == "Row") {
+ var receivedColumn = ui.item.sortable.model;
+ var receivedColumnWidth = Math.floor(12 / (element.children.length + 1));
+ receivedColumn.width = receivedColumnWidth;
+ receivedColumn.offset = 0;
+ element.beginAddColumn(receivedColumnWidth);
+ // Make the drop target placeholder the correct width and as high as the highest existing column in the row.
+ var maxHeight = _.max(_($element.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function (e) {
+ return $(e).height();
+ }));
+ for (i = 1; i <= 12; i++)
+ ui.placeholder.removeClass("col-xs-" + i);
+ ui.placeholder.addClass("col-xs-" + receivedColumn.width);
+ if (maxHeight > 0) {
+ ui.placeholder.height(maxHeight);
+ ui.placeholder.css("min-height", 0);
+ }
+ else {
+ ui.placeholder.height(0);
+ ui.placeholder.css("min-height", "");
+ }
+ }
+ element.setIsDropTarget(true);
+ }, 150);
+ }
+ },
+ receive: function (e, ui) {
+ if (!!ui.sender && !!ui.sender[0].isToolbox) {
+ $scope.$apply(function () {
+ var receivedElement = ui.item.sortable.model;
+ if (!!receivedElement) {
+ if (element.type == "Row")
+ element.commitAddColumn();
+ // Should ideally call LayoutEditor.Container.addChild() instead, but since this handler
+ // is run *before* the ui-sortable directive's handler, if we try to add the child to the
+ // array that handler will get an exception when trying to do the same.
+ // Because of this, we need to invoke "setParent" so that specific container types can perform element speficic initialization.
+ receivedElement.setEditor(element.editor);
+ receivedElement.setParent(element);
+ if (receivedElement.type == "Content" && !!receivedElement.hasEditor) {
+ $scope.$root.editElement(receivedElement).then(function (args) {
+ if (!args.cancel) {
+ receivedElement.data = decodeURIComponent(args.element.data);
+ receivedElement.setHtml(decodeURIComponent(args.element.html.replace(/\+/g, "%20")));
+ }
+ $timeout(function () {
+ if (!!args.cancel)
+ receivedElement.delete();
+ else
+ receivedElement.setIsFocused();
+ //$scope.isReceiving = false;
+ element.setIsDropTarget(false);
+
+ });
+ return;
+ });
+ }
+ }
+ $timeout(function () {
+ //$scope.isReceiving = false;
+ element.setIsDropTarget(false);
+ if (!!receivedElement)
+ receivedElement.setIsFocused();
+ });
+ });
+ }
}
- }
- };
+ };
- $scope.click = function (child, e) {
- if (!child.editor.isDragging)
- child.setIsFocused();
- e.stopPropagation();
- };
+ $scope.click = function (child, e) {
+ if (!child.editor.isDragging)
+ child.setIsFocused();
+ e.stopPropagation();
+ };
- $scope.getClasses = function (child) {
- var result = ["layout-element"];
+ $scope.getClasses = function (child) {
+ var result = ["layout-element"];
- if (!!child.children) {
- result.push("layout-container");
- if (child.getIsSealed())
- result.push("layout-container-sealed");
- }
+ if (!!child.children) {
+ result.push("layout-container");
+ if (child.getIsSealed())
+ result.push("layout-container-sealed");
+ }
- result.push("layout-" + child.type.toLowerCase());
+ result.push("layout-" + child.type.toLowerCase());
- if (!!child.dropTargetClass)
- result.push(child.dropTargetClass);
+ if (!!child.dropTargetClass)
+ result.push(child.dropTargetClass);
- // TODO: Move these to either the Column directive or the Column model class.
- if (child.type == "Row") {
- result.push("row");
- if (!child.canAddColumn())
- result.push("layout-row-full");
- }
- if (child.type == "Column") {
- result.push("col-xs-" + child.width);
- result.push("col-xs-offset-" + child.offset);
- }
- if (child.type == "Content")
- result.push("layout-content-" + child.contentTypeClass);
+ // TODO: Move these to either the Column directive or the Column model class.
+ if (child.type == "Row") {
+ result.push("row");
+ if (!child.canAddColumn())
+ result.push("layout-row-full");
+ }
+ if (child.type == "Column") {
+ result.push("col-xs-" + child.width);
+ result.push("col-xs-offset-" + child.offset);
+ }
+ if (child.type == "Content")
+ result.push("layout-content-" + child.contentTypeClass);
- if (child.getIsActive())
- result.push("layout-element-active");
- if (child.getIsFocused())
- result.push("layout-element-focused");
- if (child.getIsSelected())
- result.push("layout-element-selected");
- if (child.getIsDropTarget())
- result.push("layout-element-droptarget");
- if (child.isTemplated)
- result.push("layout-element-templated");
+ if (child.getIsActive())
+ result.push("layout-element-active");
+ if (child.getIsFocused())
+ result.push("layout-element-focused");
+ if (child.getIsSelected())
+ result.push("layout-element-selected");
+ if (child.getIsDropTarget())
+ result.push("layout-element-droptarget");
+ if (child.isTemplated)
+ result.push("layout-element-templated");
- return result;
- };
- }
+ return result;
+ };
+ }
+ };
}
- });
\ No newline at end of file
+ ]);
\ No newline at end of file