From adfdbaec46cfe9c2013e0dafbd94f845d5307453 Mon Sep 17 00:00:00 2001 From: per ploug Date: Wed, 5 Nov 2014 15:44:29 +0100 Subject: [PATCH] Adds support for grid row configuration and styling --- .../editors/umbRawModel.directive.js | 99 +++++++++++++++++++ .../src/less/gridview.less | 68 +++++++------ .../prevalueeditors/imagepicker.controller.js | 14 +++ .../views/prevalueeditors/imagepicker.html | 14 +++ .../grid/config/grid.default.config.js | 44 ++++++++- .../grid/dialogs/config.controller.js | 73 ++++++++++++++ .../propertyeditors/grid/dialogs/config.html | 40 ++++++++ .../grid/dialogs/editconfig.controller.js | 15 +++ .../grid/dialogs/editconfig.html | 31 ++++++ .../propertyeditors/grid/grid.controller.js | 30 ++++-- .../src/views/propertyeditors/grid/grid.html | 32 +++--- .../grid/grid.prevalues.controller.js | 76 +++++++++++++- .../propertyeditors/grid/grid.prevalues.html | 96 +++++++++++++----- 13 files changed, 550 insertions(+), 82 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/editors/umbRawModel.directive.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbRawModel.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbRawModel.directive.js new file mode 100644 index 0000000000..9b479b60ae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/editors/umbRawModel.directive.js @@ -0,0 +1,99 @@ +/* +example usage: + +jsonEditing is a string which we edit in a textarea. we try parsing to JSON with each change. when it is valid, propagate model changes via ngModelCtrl + +use isolate scope to prevent model propagation when invalid - will update manually. cannot replace with template, or will override ngModelCtrl, and not hide behind facade + +will override element type to textarea and add own attribute ngModel tied to jsonEditing + */ + +angular.module("umbraco.directives") + .directive('umbRawModel', function () { + return { + restrict: 'A', + require: 'ngModel', + template: '', + replace : true, + scope: { + model: '=umbRawModel', + validateOn:'=' + }, + link: function (scope, element, attrs, ngModelCtrl) { + + function setEditing (value) { + scope.jsonEditing = angular.copy( jsonToString(value)); + } + + function updateModel (value) { + scope.model = stringToJson(value); + } + + function setValid() { + ngModelCtrl.$setValidity('json', true); + } + + function setInvalid () { + ngModelCtrl.$setValidity('json', false); + } + + function stringToJson(text) { + try { + return angular.fromJson(text); + } catch (err) { + setInvalid(); + return text; + } + } + + function jsonToString(object) { + // better than JSON.stringify(), because it formats + filters $$hashKey etc. + // NOTE that this will remove all $-prefixed values + return angular.toJson(object, true); + } + + function isValidJson(model) { + var flag = true; + try { + angular.fromJson(model); + } catch (err) { + flag = false; + } + return flag; + } + + //init + setEditing(scope.model); + + var onInputChange = function(newval,oldval){ + if (newval !== oldval) { + if (isValidJson(newval)) { + setValid(); + updateModel(newval); + } else { + setInvalid(); + } + } + }; + + if(scope.validateOn){ + element.on(scope.validateOn, function(){ + scope.$apply(function(){ + onInputChange(scope.jsonEditing); + }); + }); + }else{ + //check for changes going out + scope.$watch('jsonEditing', onInputChange, true); + } + + //check for changes coming in + scope.$watch('model', function (newval, oldval) { + if (newval !== oldval) { + setEditing(newval); + } + }, true); + + } + }; + }); diff --git a/src/Umbraco.Web.UI.Client/src/less/gridview.less b/src/Umbraco.Web.UI.Client/src/less/gridview.less index 6fff036806..17d5f5742d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/gridview.less +++ b/src/Umbraco.Web.UI.Client/src/less/gridview.less @@ -5,7 +5,7 @@ overflow-y:hidden!important; } - IFRAME {overflow:hidden;} + IFRAME {overflow:hidden;} // Sortabel @@ -29,7 +29,7 @@ background: none !important; color: #999 !important; padding: 0 !important; - margin: 0 !important; + margin: 0 !important; } .usky-grid .ui-sortable-helper .cell-tools{ @@ -66,7 +66,7 @@ .usky-grid .right { float:right; } - + // general layout components // ------------------------- @@ -108,10 +108,10 @@ text-align: center; } - .usky-grid .mainTb { + .usky-grid .mainTb { border-collapse: separate; } - .usky-grid .mainTd { + .usky-grid .mainTd { position:relative; } @@ -120,10 +120,10 @@ // COLUMN // ------------------------- .usky-grid .usky-column { - + } .usky-grid .usky-column.last { - + } @@ -206,6 +206,11 @@ cursor: move } +.usky-grid .cell-tools-edit{ + position: absolute; + top: 80px; + right: 5px; +} // CONTROL @@ -216,9 +221,9 @@ -webkit-transition: all .20s ease-in-out;*/ position:relative; display:block; - + /* - border: 1px dashed rgba(255, 0, 0, .0); + border: 1px dashed rgba(255, 0, 0, .0); border-bottom-width: 1px; */ @@ -247,7 +252,7 @@ } .usky-grid .usky-control-inner{ - min-height: 60px; + min-height: 60px; } @@ -255,7 +260,7 @@ // CONTROL PLACEHOLDER // ------------------------- .usky-grid .usky-control-placeholder { - min-height: 50px; + min-height: 20px; position: relative; text-align: center; text-align: -moz-center; @@ -266,7 +271,7 @@ font-size: 14px; opacity: 0.7; text-align: left; padding: 5px; border:1px solid rgba(182, 182, 182, 0.3); - height: 50px; + height: 20px; } .usky-grid .usky-control-placeholder:hover .placeholder{ @@ -293,7 +298,7 @@ .usky-grid .usky-editor-placeholder i{ color: @grayLight; font-size: 85px; - line-height: 85px; + line-height: 85px; display: block; margin-bottom: 10px; } @@ -326,7 +331,7 @@ resize: none; font-style: italic; } - + .usky-grid .cellPanelRte { min-height:60px; } @@ -382,7 +387,7 @@ } - + .usky-grid ul { @@ -450,7 +455,7 @@ background-color: #F7F7F7 !important; } - + // MEDIA EDITOR // ------------------------- .usky-grid .fullSizeImage { @@ -488,18 +493,18 @@ /**************************************************************************************************/ .usky-grid .usky-cell{ - + } .usky-grid .usky-row{ - + } .usky-grid .usky-control{ margin: 10px 0 0 0; padding: 5px; } - + .usky-grid .usky-templates-columns{ margin-top: 30px; } @@ -526,7 +531,7 @@ overflow:hidden; width:100%; } - + .usky-grid .uSky-templates-template { display:inline-block; width:100px; @@ -538,9 +543,9 @@ border:5px solid @blue; } - .usky-grid .uSky-templates-template .tb { - width:100%; - height:150px; + .usky-grid .uSky-templates-template .tb { + width:100%; + height:150px; padding:10px; background-color: @grayLighter; border: 5px solid @grayLight; @@ -548,11 +553,11 @@ position: relative; } - .usky-grid .uSky-templates-template .tr { + .usky-grid .uSky-templates-template .tr { height: 100%; position: relative; } - + .usky-grid .uSky-templates-template .tb .uSky-templates-column { height:100%; border: 1px dashed @grayLight; @@ -583,7 +588,7 @@ } - .usky-grid .mainTbpt:hover { + .usky-grid .mainTbpt:hover { border-color:@blue; } @@ -592,13 +597,13 @@ border-spacing: 3px; border-collapse: separate; height: 35px; - border: 2px solid @grayLight; + border: 2px solid @grayLight; margin:0px; background-color: @grayLighter; - } - .usky-grid .mainTdpt { + } + .usky-grid .mainTdpt { height: 35px; - border: 1px dashed @grayLight; + border: 1px dashed @grayLight; margin:0px; background-color: rgba(228, 228, 228, 0.41); overflow: hidden; @@ -674,7 +679,7 @@ /**************************************************************************************************/ .usky-grid-configuration .uSky-templates{ text-align: left; -} +} .usky-grid-configuration ul{ display: block; @@ -737,4 +742,3 @@ } .usky-grid-configuration a.uSky-templates-column{height: 70px !important;} - diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js new file mode 100644 index 0000000000..8537e8e029 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.controller.js @@ -0,0 +1,14 @@ +function imageFilePickerController($scope, dialogService, mediaHelper) { + + $scope.pick = function() { + dialogService.mediaPicker({ + multiPicker: false, + callback: function(data) { + $scope.model.value = mediaHelper.resolveFile(data, false); + } + }); + }; + +} + +angular.module('umbraco').controller("Umbraco.PrevalueEditors.ImageFilePickerController",imageFilePickerController); diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html new file mode 100644 index 0000000000..f9a9aa74ea --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html @@ -0,0 +1,14 @@ +
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/config/grid.default.config.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/config/grid.default.config.js index c52c529041..466429ad9f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/config/grid.default.config.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/config/grid.default.config.js @@ -1,11 +1,45 @@ var uSkyGridConfig = [ { + + style:[ + { + label: "Set a background image", + description: "Set a row background", + key: "background-image", + view: "imagepicker", + modifier: "url({0})" + }, + + { + label: "Set a font color", + description: "Pick a color", + key: "color", + view: "colorpicker" + } + ], + + config:[ + { + label: "Preview", + description: "Display a live preview", + key: "preview", + view: "boolean" + }, + + { + label: "Class", + description: "Set a css class", + key: "class", + view: "textstring" + } + ], + layouts: [ { grid: 12, percentage: 100, - - + + rows: [ { name: "Single column", @@ -13,7 +47,7 @@ var uSkyGridConfig = [ grid: 12, percentage: 100 }] - }, + }, { name: "Article", @@ -96,7 +130,7 @@ var uSkyGridConfig = [ { grid: 9, percentage: 70, - + cellModels: [ { models: [{ @@ -326,4 +360,4 @@ var uSkyGridConfig = [ } ] } -]; \ No newline at end of file +]; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js new file mode 100644 index 0000000000..85eca5171b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js @@ -0,0 +1,73 @@ +angular.module("umbraco") + .controller("Umbraco.PropertyEditors.GridController.Dialogs.Config", + function ($scope, $http) { + + var placeHolder = "{0}"; + var addModifier = function(val, modifier){ + if (!modifier || modifier.indexOf(placeHolder) < 0) { + return val; + } else { + return modifier.replace(placeHolder, val); + } + } + + var stripModifier = function (val, modifier) { + if (!val || !modifier || modifier.indexOf(placeHolder) < 0) { + return val; + } else { + var paddArray = modifier.split(placeHolder); + if(paddArray.length == 1){ + if (modifier.indexOf(placeHolder) === 0) { + return val.slice(0, -paddArray[0].length); + } else { + return val.slice(paddArray[0].length, 0); + } + }else{ + return val.slice(paddArray[0].length, -paddArray[1].length); + } + } + } + + + $scope.styles = angular.copy($scope.dialogOptions.config.items.styles); + $scope.config = angular.copy($scope.dialogOptions.config.items.config); + + var element = $scope.dialogOptions.gridItem; + if(angular.isObject(element.config)){ + _.each($scope.config, function(cfg){ + var val = element.config[cfg.key]; + if(val){ + cfg.value = stripModifier(val, cfg.modifier); + } + }); + } + + if(angular.isObject(element.styles)){ + _.each($scope.styles, function(style){ + var val = element.styles[style.key]; + if(val){ + style.value = stripModifier(val, style.modifier); + } + }); + } + + + $scope.saveAndClose = function(){ + var styleObject = {}; + var configObject = {}; + + _.each($scope.styles, function(style){ + if(style.value){ + styleObject[style.key] = addModifier(style.value, style.modifier); + } + }); + _.each($scope.config, function (cfg) { + if (cfg.value) { + configObject[cfg.key] = addModifier(cfg.value, cfg.modifier); + } + }); + + $scope.submit({config: configObject, styles: styleObject}); + }; + + }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html new file mode 100644 index 0000000000..d54ba2a087 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html @@ -0,0 +1,40 @@ + +
+ + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js new file mode 100644 index 0000000000..f1016f6c79 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js @@ -0,0 +1,15 @@ +angular.module("umbraco") + .controller("Umbraco.PropertyEditors.GridPrevalueEditorController.Dialogs.EditConfig", + function ($scope, $http) { + + $scope.renderModel = {}; + $scope.renderModel.name = $scope.dialogOptions.name; + $scope.renderModel.config = $scope.dialogOptions.config; + + $scope.saveAndClose = function(isValid){ + if(isValid){ + $scope.submit($scope.renderModel.config); + } + }; + + }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html new file mode 100644 index 0000000000..5877f7a0af --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html @@ -0,0 +1,31 @@ +
+
+ + + + + +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index bb57669cbc..7e019170d4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -99,8 +99,8 @@ angular.module("umbraco") start: function (e, ui) { ui.item.find('.mceNoEditor').each(function () { - notIncludedRte = [] - tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id')) + notIncludedRte = []; + tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id')); }); }, @@ -119,7 +119,7 @@ angular.module("umbraco") }, 500, false); } - } + }; // ********************************************* // Add items overlay menu @@ -218,18 +218,32 @@ angular.module("umbraco") if(row){ section.rows.push(row); } - }; $scope.removeRow = function (section, $index) { if (section.rows.length > 0) { section.rows.splice($index, 1); $scope.openRTEToolbarId = null; - $scope.initContent(); } }; + $scope.editGridItemSettings = function (gridItem) { + + dialogService.open( + { + template: "views/propertyeditors/grid/dialogs/config.html", + gridItem: gridItem, + config: $scope.model.config, + callback: function(data){ + + gridItem.styles = data.styles; + gridItem.config = data.config; + + } + }); + + }; // ********************************************* // Cell management functions @@ -401,6 +415,7 @@ angular.module("umbraco") _.forEach(section.rows, function(row, index){ if(!row.$initialized){ var initd = $scope.initRow(row); + //if init fails, remove if(!initd){ section.rows.splic(index, 1); @@ -420,12 +435,15 @@ angular.module("umbraco") //merge the layout data with the original config data //if there are no config info on this, splice it out - var original = _.find($scope.model.config.items.layouts, function(o){ return o.name === row.name; }); + var original = _.find($scope.model.config.items.layouts, function (o) { return o.name === row.name; }); + if(!original){ return null; }else{ //make a copy to not touch the original config original = angular.copy(original); + original.styles = row.styles; + original.config = row.config; //sync area configuration _.each(original.areas, function(area, areaIndex){ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html index 83cee8ac1c..0a3ba6e7ae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html @@ -1,6 +1,7 @@
+
@@ -41,9 +42,8 @@
+ ng-mouseenter="setCurrentRow(row)" + ng-mouseleave="disableCurrentRow()">
@@ -52,8 +52,8 @@
+ ng-mouseenter="setCurrentRemoveControl(row)" + ng-mouseleave="disableCurrentRemoveControl(row)"> Are you sure? @@ -65,17 +65,24 @@
+ +
+ + + +
+
+ ng-class="{last:$last,first:$first, warnhighlight:currentRemoveControl == row, infohighlight:currentMovedRow == row}"> +
@@ -89,7 +96,6 @@
-
@@ -168,7 +174,6 @@
-
-
@@ -27,7 +26,7 @@
{{template.name}}
- {{template.sections.length}} layout areas
+ {{template.sections.length}} sections
Delete layout
@@ -39,20 +38,21 @@
+
Layout
- +
@@ -74,8 +74,7 @@
@@ -163,10 +162,10 @@
-
+
@@ -188,7 +187,7 @@
{{layout.name}}
- {{layout.areas.length}} columns
+ {{layout.areas.length}} cells
Delete row
@@ -214,7 +213,7 @@ - +
@@ -236,15 +235,12 @@
-
Modify column
- +
- {{currentArea.grid}} - @@ -252,7 +248,6 @@ -
- + Delete column + ng-click="deleteArea($index)"> Delete cell
- -
-
+
+ + + + + + + + + + + + + + + +