Merge branch '7.2.0' of https://github.com/umbraco/Umbraco-CMS into 7.2.0

This commit is contained in:
antoine
2014-06-30 19:29:38 +02:00
25 changed files with 1046 additions and 533 deletions

View File

@@ -6,7 +6,7 @@ module.exports = function (grunt) {
grunt.registerTask('dev', ['jshint:dev', 'build', 'webserver', 'open:dev', 'watch']);
//run by the watch task
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:tuning','copy:vs','karma:unit']);
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:tuning','copy:vs']);
grunt.registerTask('watch-less', ['recess:build', 'recess:installer', 'recess:tuning','copy:tuning', 'copy:assets', 'copy:vs']);
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
grunt.registerTask('watch-packages', ['copy:packages']);
@@ -125,12 +125,6 @@ module.exports = function (grunt) {
{
dest: '<%= distdir %>/lib/lazyload/lazyload.min.js',
src: 'bower_components/rgrove-lazyload/lazyload.js'
},
{
dest: '<%= distdir %>/lib/ace/',
src: '**',
expand: true,
cwd: 'bower_components/ace-builds/src-min-noconflict/'
}
]
},
@@ -171,12 +165,15 @@ module.exports = function (grunt) {
//then we need to figure out how to not copy all the test stuff either!?
{ dest: '<%= vsdir %>/assets', src: '**', expand: true, cwd: '<%= distdir %>/assets' },
{ dest: '<%= vsdir %>/js', src: '**', expand: true, cwd: '<%= distdir %>/js' },
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' },
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' }
]
},
vsLibs: {
files: [
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' }
]
},
packages: {
files: [{ dest: '<%= vsdir %>/../App_Plugins', src : '**', expand: true, cwd: 'src/packages/' }]
}

View File

@@ -1,3 +1,10 @@
/*
http://vitalets.github.io/checklist-model/
<label ng-repeat="role in roles">
<input type="checkbox" checklist-model="user.roles" checklist-value="role.id"> {{role.text}}
</label>
*/
angular.module('umbraco.directives')
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
// contains

View File

@@ -7,7 +7,7 @@
// Sortabel
// -------------------------
.usky-grid .ui-sortable-helper {
border: dashed 1px #000;
border: dashed 1px #$000;
background: #ccc;
opacity: 0.4;
height: 50px !important;
@@ -241,7 +241,7 @@
// CONTROL PLACEHOLDER
// -------------------------
.usky-grid .usky-control-placeholder {
min-height: 100px;
min-height: 50px;
position: relative;
text-align: center;
text-align: -moz-center;
@@ -493,7 +493,7 @@
}
.usky-grid .usky-control{
margin: 30px;
margin: 15px 30px 0px 10px;
padding: 5px;
}
@@ -519,7 +519,7 @@
margin: 20px;
}
.usky-grid .uSky-templates-template .tb:hover {
.usky-grid .uSky-templates-template a.tb:hover {
border:5px solid @blue;
}
@@ -532,7 +532,7 @@
cursor:pointer;
position: relative;
}
.usky-grid .uSky-templates-template .tr {
height: 100%;
position: relative;
@@ -548,6 +548,10 @@
border-right: 1px dashed @grayLight !important;
}
.usky-grid a.uSky-templates-column:hover, .usky-grid a.uSky-templates-column.selected{
background-color: @blue;
}
/**************************************************************************************************/
/* template column */
@@ -576,10 +580,82 @@
border: 2px solid @grayLight;
margin:0px;
background-color: @grayLighter;
}
}
.usky-grid .mainTdpt {
height: 35px;
border: 1px dashed @grayLight;
margin:0px;
background-color: rgba(228, 228, 228, 0.41);
}
}
/**************************************************************************************************/
/* Configuration specific styles */
/**************************************************************************************************/
.usky-grid-configuration .uSky-templates{
text-align: left;
}
.usky-grid-configuration ul{
display: block;
}
.usky-grid-configuration ul li{
display: block;
width: auto;
text-align: left;
}
.usky-grid-configuration .uSky-templates .uSky-templates-template{
margin: 0px 20px 20px 0px;
width: 60px;
}
.usky-grid-configuration .uSky-templates .uSky-templates-template .tb{
height: 50px;
border-width: 2px !important;
padding: 0px;
border-spacing:2px;
}
.usky-grid-configuration .uSky-templates .uSky-templates-template .tb:hover{
border-width: 2px !important;
}
.usky-grid-configuration .uSky-templates-column{
display: block;
float: left;
margin-left: -1px;
}
.usky-grid-configuration .uSky-templates-column.last{
margin-right: -1px;
}
.usky-grid-configuration .uSky-templates-column.add{
text-align: center;
font-size: 20px;
line-height: 70px;
color: #ccc;
text-decoration: none
}
.usky-grid-configuration .uSky-templates-rows .uSky-templates-row{
margin: 0px 50px 20px 0px;
width: 60px;
}
.usky-grid-configuration .uSky-templates-rows .uSky-templates-row .tb{
border-width: 2px !important;
padding: 0px;
border-spacing:2px;
}
.usky-grid-configuration .uSky-templates-rows .mainTdpt{
height: 10px !important;
}
.usky-grid-configuration a.uSky-templates-column{height: 70px !important;}

View File

@@ -185,33 +185,3 @@
.umb-modal .breadcrumb input {
height: 12px
}
/* YSOD */
/* These styles are an exact replica of a real .Net YSOD */
.umb-modal .ysod {
font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;padding:5px;
}
.umb-modal .ysod > div {
font-family: Arial, Helvetica, Geneva, SunSans-Regular, sans-serif;
line-height: 13px;
font-size: 11px;
}
.umb-modal .ysod hr {
margin: 0px;
color: silver;
background-color: silver;
height: 1px;
}
.umb-modal .ysod p {font-family:"Verdana";font-weight:normal;color:black;}
.umb-modal .ysod b {font-family:"Verdana";font-weight:bold;color:black;}
.umb-modal .ysod h1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red;padding: 0px;text-transform: none !important;margin: 0px; }
.umb-modal .ysod h2 { font-style:italic; font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon; }
.umb-modal .ysod pre {border:none;font-family:"Consolas","Lucida Console",Monospace;font-size:13px;margin:0;padding:0.5em;line-height:17px;}
.umb-modal .ysod .marker {font-weight: bold; color: black;text-decoration: none;}
.umb-modal .ysod .version {color: gray;}
.umb-modal .ysod .error {margin-bottom: 10px;}
.umb-modal .ysod .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:pointer; }
.umb-modal .ysod table {background-color:#ffffcc;width:100%;}
.umb-modal .ysod table pre {background-color: inherit;}
.umb-modal .ysod table code {background-color: inherit;}
.umb-modal .ysod a.btn { margin-top:10px;margin-right:10px;float:right;}

View File

@@ -1,28 +1,28 @@
<div class="umb-modalcolumn ysod" ng-controller="Umbraco.Dialogs.YsodController">
<div class="umb-panel ysod" ng-controller="Umbraco.Dialogs.YsodController">
<a href="" ng-click="closeDialog()" class="btn">Close</a>
<div class="umb-panel-body with-footer no-header">
<h1>{{error.errorMsg}}</h1>
<hr />
<h2>{{error.data.ExceptionMessage || error.data.Message}}</h2>
<div>
<b>Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
<br />
<br />
<b>Exception Details: </b>{{error.data.ExceptionType}}: {{error.data.ExceptionMessage}}
<br />
<br />
<b>Stack Trace:</b>
<br />
<br />
<table>
<tr>
<td>
<pre>{{error.data.StackTrace}}</pre>
</td>
</tr>
<h3 style="padding-left: 20px" class="headline red">Received an error from the server</h3>
<umb-pane>
<h4>{{error.errorMsg}}</h4>
<p>{{error.data.ExceptionMessage || error.data.Message}}</p>
</umb-pane>
<umb-pane>
<h5>Exception Details: </h5>
{{error.data.ExceptionType}}: {{error.data.ExceptionMessage}}
</umb-pane>
<umb-pane>
<h5>Stacktrace: </h5>
<pre style="white-space: pre-wrap; overflow-x: auto;">{{error.data.StackTrace}}</pre>
</umb-pane>
</div>
</div>
<div class="umb-panel-footer">
<a href ng-click="close()" class="btn pull-right">
<localize key="general_close">Close</localize>
</a>
</div>
</umb-panel>

View File

@@ -1,7 +1,7 @@
<div class="umb-property">
<div class="control-group umb-control-group" ng-class="{error: !formValid()}">
<div class="control-group umb-control-group" ng-class="{error: !formValid(), hidelabel:hideLabel=='true'}">
<div class="umb-el-wrap">
<label class="control-label" for="{{alias}}">
<label ng-if="hideLabel!=='true'" class="control-label" for="{{alias}}">
{{labelstring}}
<small>{{description}}</small>
</label>

View File

@@ -1,29 +1,33 @@
var uSkyGridConfig = [
{
columns: [
layouts: [
{
grid: 12,
percentage: 100,
cellModels: [
rows: [
{
name: "Single column",
models: [{
grid: 12,
percentage: 100
}]
}, {
columns: [{
grid: 12,
percentage: 100
}]
},
{
name: "Article",
models: [{
grid: 4,
percentage: 33.3,
allowed: ["media","quote"]
}, {
grid: 8,
percentage: 66.6,
allowed: ["rte"]
}]
models: [{
grid: 4,
percentage: 33.3,
allowed: ["media","quote"]
}, {
grid: 8,
percentage: 66.6,
allowed: ["rte"]
}]
},
{
name: "Article, reverse",
models: [
@@ -92,6 +96,7 @@ var uSkyGridConfig = [
{
grid: 9,
percentage: 70,
cellModels: [
{
models: [{

View File

@@ -1,4 +1,4 @@
<div
unique-id="control.uniqueId"
unique-id="control.$uniqueId"
value="control.value"
grid-rte configuration="model.config.rte"></div>

View File

@@ -2,261 +2,332 @@ angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GridController",
function ($scope, $http, assetsService, $rootScope, dialogService, gridService, mediaResource, imageHelper, $timeout) {
var gridConfigPath = $scope.model.config.items.gridConfigPath;
// Grid status variables
$scope.currentRow = null;
$scope.currentCell = null;
$scope.currentToolsControl = null;
$scope.currentControl = null;
$scope.openRTEToolbarId = null;
if(!gridConfigPath){
gridConfigPath = "views/propertyeditors/grid/grid.default.config.js";
}
// *********************************************
// Sortable options
// *********************************************
assetsService.loadJs(gridConfigPath).then(function(){
$scope.sortableOptions = {
distance: 10,
cursor: "move",
placeholder: 'ui-sortable-placeholder',
handle: '.cell-tools-move',
start: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
// Grid config
$scope.uSkyGridConfig = uSkyGridConfig;
});
},
stop: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
});
}
};
// Grid status variables
$scope.currentRow = null;
$scope.currentCell = null;
$scope.currentToolsControl = null;
$scope.currentControl = null;
// *********************************************
// Template management functions
// *********************************************
$scope.addTemplate = function (template) {
$scope.model.value = angular.copy(template);
//default row data
_.forEach($scope.model.value.sections, function(section){
$scope.initSection(section);
});
};
// *********************************************
// Row management function
// *********************************************
$scope.setCurrentRow = function (row) {
$scope.currentRow = row;
};
$scope.disableCurrentRow = function () {
$scope.currentRow = null;
};
$scope.getAllowedLayouts = function(column){
var layouts = $scope.model.config.items.layouts;
if(column.allowed && column.allowed.length > 0){
return _.filter(layouts, function(layout){
return _.indexOf(column.allowed, layout.name) >= 0;
});
}else{
return layouts;
}
};
$scope.addRow = function (column, layout) {
//copy the selected layout into the rows collection
var row = angular.copy(layout);
$scope.initRow(row);
column.rows.push(row);
};
$scope.removeRow = function (section, $index) {
if (section.rows.length > 0) {
section.rows.splice($index, 1);
$scope.openRTEToolbarId = null;
gridService.getGridEditors().then(function(response){
$scope.availableEditors = response.data;
$scope.initContent();
}
};
// *********************************************
// Cell management functions
// *********************************************
$scope.setCurrentCell = function (cell) {
$scope.currentCell = cell;
};
$scope.disableCurrentCell = function (cell) {
$scope.currentCell = null;
};
$scope.cellPreview = function(cell){
if(cell && cell.$allowedEditors){
var editor = cell.$allowedEditors[0];
return editor.icon;
}else{
return "icon-layout";
}
};
// *********************************************
// Control management functions
// *********************************************
$scope.setCurrentControl = function (Control) {
$scope.currentControl = Control;
};
$scope.disableCurrentControl = function (Control) {
$scope.currentControl = null;
};
$scope.setCurrentToolsControl = function (Control) {
$scope.currentToolsControl = Control;
};
$scope.disableCurrentToolsControl = function (Control) {
$scope.currentToolsControl = null;
};
$scope.setCurrentRemoveControl = function (Control) {
$scope.currentRemoveControl = Control;
};
$scope.disableCurrentRemoveControl = function (Control) {
$scope.currentRemoveControl = null;
};
$scope.setCurrentMoveControl = function (Control) {
$scope.currentMoveControl = Control;
};
$scope.disableCurrentMoveControl = function (Control) {
$scope.currentMoveControl = null;
};
$scope.setUniqueId = function (cell, index) {
var date = new Date();
var components = [
date.getYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
];
return components.join("");
};
$scope.addControl = function (editor, cell, index){
var newControl = {
value: null,
editor: editor
};
if (index === undefined) {
index = cell.controls.length;
}
//populate control
$scope.initControl(newControl, index+1);
cell.controls.splice(index + 1, 0, newControl);
};
$scope.addTinyMce = function(cell){
var rte = $scope.getEditor("rte");
$scope.addControl(rte, cell);
};
$scope.getEditor = function(alias){
return _.find($scope.availableEditors, function(editor){return editor.alias === alias});
};
$scope.removeControl = function (cell, $index) {
cell.controls.splice($index, 1);
};
$scope.percentage = function(spans){
return ((spans/12)*100).toFixed(1);
};
// *********************************************
// INITIALISATION
// these methods are called from ng-init on the template
// so we can controll their first load data
//
// intialisation sets non-saved data like percentage sizing, allowed editors and
// other data that should all be pre-fixed with $ to strip it out on save
// *********************************************
// *********************************************
// Init template + sections
// *********************************************
$scope.initContent = function() {
var clear = true;
if ($scope.model.value && $scope.model.value.sections && $scope.model.value.sections.length > 0) {
_.forEach($scope.model.value.sections, function(section){
$scope.initSection(section);
//we do this to ensure that the grid can be reset by deleting the last row
if(section.rows.length > 0){
clear = false;
}
});
// *********************************************
// Sortable options
// *********************************************
}
$scope.sortableOptions = {
distance: 10,
cursor: "move",
placeholder: 'ui-sortable-placeholder',
handle: '.cell-tools-move',
start: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
if(clear){
$scope.model.value = undefined;
}
};
});
},
stop: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
});
}
};
$scope.initSection = function(section){
section.$percentage = $scope.percentage(section.grid);
// *********************************************
// Template management functions
// *********************************************
var layouts = $scope.model.config.items.layouts;
$scope.checkContent = function() {
var isEmpty = true;
if ($scope.model.value &&
$scope.model.value.columns) {
angular.forEach($scope.model.value.columns, function (value, key) {
if ( value.rows && value.rows.length > 0) {
isEmpty = false;
}
});
}
if(section.allowed && section.allowed.length > 0){
section.$allowedLayouts = _.filter(layouts, function(layout){
return _.indexOf(section.allowed, layout.name) >= 0;
});
}else{
section.$allowedLayouts = layouts;
}
if (isEmpty)
{
$scope.model.value = undefined;
}
if(!section.rows){
section.rows = [];
}else{
_.forEach(section.rows, function(row){
$scope.initRow(row);
});
}
};
}
$scope.addTemplate = function (template) {
$scope.model.value = {
gridWidth: "",
columns: []
};
// *********************************************
// Init layout / row
// *********************************************
$scope.initRow = function(row){
if(!row.areas){
row.areas = [];
}
angular.forEach(template.columns, function (value, key) {
var newCol = angular.copy(value);
newCol.rows = [];
$scope.model.value.columns.splice($scope.model.value.columns.length + 1, 0, newCol);
//set a disposable unique ID
row.$uniqueId = $scope.setUniqueId();
//populate with data
_.forEach(row.areas, function(area){
if(!area.controls){
area.controls = [];
}else{
_.forEach(area.controls, function(control, index){
$scope.initControl(control, index);
});
}
// *********************************************
// Row management function
// *********************************************
$scope.setCurrentRow = function (row) {
$scope.currentRow = row;
}
$scope.disableCurrentRow = function () {
$scope.currentRow = null;
}
$scope.addRow = function (column, cellModel) {
area.$percentage = $scope.percentage(area.grid);
column.rows.splice(column.rows.length + 1, 0,
{
uniqueId: $scope.setUniqueId(),
cells: [],
cssClass: ''
if(!area.allowed){
area.$allowedEditors = $scope.availableEditors;
area.$allowsRTE = true;
}else{
area.$allowedEditors = _.filter($scope.availableEditors, function(editor){
return _.indexOf(area.allowed, editor.alias) >= 0;
});
for (var i = 0; i < cellModel.models.length; i++) {
var cells = column.rows[column.rows.length - 1].cells;
var model = angular.copy(cellModel.models[i]);
cells.splice(
cells.length + 1, 0,
{
model: model,
controls: []
});
}
};
$scope.removeRow = function (column, $index) {
if (column.rows.length > 0) {
column.rows.splice($index, 1);
$scope.openRTEToolbarId = null;
$scope.checkContent();
if(_.indexOf(area.allowed,"rte")>=0){
area.$allowsRTE = true;
}
}
// *********************************************
// Cell management functions
// *********************************************
$scope.setCurrentCell = function (cell) {
$scope.currentCell = cell;
}
$scope.disableCurrentCell = function (cell) {
$scope.currentCell = null;
}
$scope.cellPreview = function(cell){
if($scope.availableEditors && cell && cell.allowed && angular.isArray(cell.allowed)){
var editor = $scope.getEditor(cell.allowed[0]);
return editor.icon;
}else{
return "icon-layout";
}
}
// *********************************************
// Control management functions
// *********************************************
$scope.setCurrentControl = function (Control) {
$scope.currentControl = Control;
};
$scope.disableCurrentControl = function (Control) {
$scope.currentControl = null;
};
$scope.setCurrentToolsControl = function (Control) {
$scope.currentToolsControl = Control;
};
$scope.disableCurrentToolsControl = function (Control) {
$scope.currentToolsControl = null;
};
$scope.setCurrentRemoveControl = function (Control) {
$scope.currentRemoveControl = Control;
};
$scope.disableCurrentRemoveControl = function (Control) {
$scope.currentRemoveControl = null;
};
$scope.setCurrentMoveControl = function (Control) {
$scope.currentMoveControl = Control;
};
$scope.disableCurrentMoveControl = function (Control) {
$scope.currentMoveControl = null;
};
$scope.setUniqueId = function (cell, index) {
var date = new Date();
var components = [
date.getYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
];
return components.join("");
};
$scope.setEditorPath = function(control){
control.editorPath = "views/propertyeditors/grid/editors/" + control.editor.view + ".html";
};
$scope.addControl = function (editor, cell, index){
var newId = $scope.setUniqueId();
var newControl = {
uniqueId: newId,
value: null,
editor: editor
};
if (index === undefined) {
index = cell.controls.length;
}
cell.controls.splice(index + 1, 0, newControl);
};
$scope.addTinyMce = function(cell){
var rte = _.find($scope.availableEditors, function(editor){return editor.alias === "rte";});
$scope.addControl(rte, cell);
};
$scope.getEditor = function(alias){
return _.find($scope.availableEditors, function(editor){return editor.alias === alias});
};
$scope.removeControl = function (cell, $index) {
cell.controls.splice($index, 1);
};
$scope.allowedControl = function (editor, cell){
if(cell.model.allowed && angular.isArray(cell.model.allowed)){
return _.contains(cell.model.allowed, editor.alias);
}else{
return true;
}
};
// *********************************************
// Init grid
// *********************************************
/* init grid data */
if ($scope.model.value && $scope.model.value != "") {
if (!$scope.model.config.items.enableGridWidth) {
$scope.model.value.gridWidth = $scope.model.config.items.defaultGridWith;
}
}
$scope.checkContent();
});
};
// *********************************************
// asset styles
// *********************************************
// Init control
// *********************************************
//assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/jquery-ui-1.10.4.custom/css/ui-lightness/jquery-ui-1.10.4.custom.min.css");
//assetsService.loadCss($scope.model.config.items.approvedBackgroundCss);
$scope.initControl = function(control, index){
control.$index = index;
control.$uniqueId = $scope.setUniqueId();
if(!control.$editorPath){
//if its a path
if(_.indexOf(control.editor.view, "/") >= 0){
control.$editorPath = control.editor.view;
}else{
//use convention
control.$editorPath = "views/propertyeditors/grid/editors/" + control.editor.view + ".html";
}
}
};
gridService.getGridEditors().then(function(response){
$scope.availableEditors = response.data;
$scope.contentReady = true;
// *********************************************
// Init grid
// *********************************************
$scope.initContent();
});
});

View File

@@ -1,17 +1,18 @@
<div ng-controller="Umbraco.PropertyEditors.GridController" class="usky-grid">
<div ng-if="contentReady">
<!-- Template picker -->
<div class="uSky-templates tb" ng-show="!model.value || model.value == ''">
<div class="tr">
<div class="td middle">
<div class="uSky-templates-template" ng-repeat="template in uSkyGridConfig" style="">
<div class="uSky-templates-template"
ng-repeat="template in model.config.items.templates" style="">
<div class="tb" ng-click="addTemplate(template)">
<div class="tr">
<div class="td uSky-templates-column"
ng-class="{last:$last}"
ng-repeat="column in template.columns"
style="width:{{ column.percentage }}%">
ng-repeat="section in template.sections"
style="width:{{ section.$percentage }}%">
</div>
</div>
</div>
@@ -25,21 +26,22 @@
<!-- template picker end -->
<!-- Grids -->
<div class="usky-grid-width" style="width:{{ model.value.gridWidth }}px">
<div class="usky-grid-width">
<div class="tb">
<!-- for each column in model -->
<div
class="usky-column td"
ng-class="{last:$index==model.value.columns.length-1}"
ng-repeat="column in model.value.columns"
style="width:{{column .percentage}}%">
ng-class="{last:$last}"
ng-repeat="section in model.value.sections"
ng-init="initSection(section)"
style="width:{{section.$percentage}}%">
<div ui-sortable="sortableOptions" ng-model="column.rows">
<div ui-sortable="sortableOptions" ng-model="section.rows">
<!-- for each row in column -->
<!-- for each row in template section -->
<div
ng-repeat="row in column.rows"
ng-repeat="row in section.rows"
class="usky-row"
ng-mouseover="setCurrentRow(row)"
ng-mouseleave="disableCurrentRow()"
@@ -58,7 +60,7 @@
<span ng-if="deletePrompt">
Are you sure?
<a href style="text-decoration: underline" ng-click="removeRow(column, $index)">Yes</a>
<a href style="text-decoration: underline" ng-click="removeRow(section, $index)">Yes</a>
</span>
<i ng-if="!deletePrompt" class="icon icon-trash"></i>
@@ -85,43 +87,43 @@
<!-- cells in row -->
<div
style="width:{{ cell.model.percentage }}%"
ng-class="{last:$index==row.cells.length-1,first:$first}"
style="width:{{ area.$percentage }}%"
ng-class="{last:$last,first:$first}"
class="td mainTd usky-cell"
ng-repeat="cell in row.cells">
ng-repeat="area in row.areas">
<!-- if cell is empty tools -->
<!-- if area is empty tools -->
<div
class="usky-control usky-control-placeholder"
ng-if="cell.controls.length == 0">
ng-if="area.controls.length == 0">
<div
ng-if="cell.model.allowed && cell.model.allowed.length === 1"
ng-init="singleEditor = getEditor(cell.model.allowed[0])"
ng-if="area.allowed && area.allowed.length === 1"
ng-init="singleEditor = area.$allowedEditors[0]"
class="cell-tools-add-single single-editor-{{singleEditor.alias}}">
<a href ng-click="addControl(singleEditor, cell)">
<a href ng-click="addControl(singleEditor, area)">
<i class="icon {{singleEditor.icon}}"></i>
<div class="help-text">{{singleEditor.name}}</div>
</a>
<p class="placeholder" ng-click="addControl(singleEditor, cell)">
<p class="placeholder" ng-if="area.$allowsRTE" ng-click="addControl(singleEditor, area)">
Start writing here...
</p>
</div>
<div ng-if="!cell.model.allowed || cell.model.allowed.length > 1">
<div ng-if="!area.allowed || area.allowed.length > 1">
<p class="placeholder" ng-click="addTinyMce(cell)">
<p class="placeholder" ng-if="area.$allowsRTE" ng-click="addTinyMce(area)">
Start writing here...
</p>
<div class="cell-tools-add">
<div
class="iconBox"
ng-repeat="editor in availableEditors track by editor.alias"
ng-click="addControl(editor,cell)"
ng-show="allowedControl(editor, cell)">
ng-repeat="editor in area.$allowedEditors track by editor.alias"
ng-click="addControl(editor,area)">
<i class="icon {{editor.icon}}"></i>
</div>
</div>
@@ -131,33 +133,30 @@
<!-- Controls in cell -->
<div
ng-repeat="control in cell.controls"
ng-class="{last:$index==cell.controls.length-1,
removingControl:currentRemoveControl == control,
toolsControl:currentToolsControl == control,
selectedControl:currentControl == control}"
ng-repeat="control in area.controls"
ng-class="{last:$last,
removingControl:currentRemoveControl == control,
toolsControl:currentToolsControl == control,
selectedControl:currentControl == control}"
ng-mouseover="setCurrentControl(control)"
ng-mouseleave="disableCurrentControl(control)"
ng-init="setEditorPath(control); controlIndex = $index;"
class="usky-control">
<!-- Filled cell tools -->
<div class="cell-tools"
ng-animate="'fade'"
ng-if="control && ( currentControl == control)">
<div class="cell-tools-add"
ng-if="cell.model.max === undefined || cell.model.max < cell.controls.length"
ng-if="area.max === undefined || area.max < area.controls.length"
ng-mouseover="setCurrentToolsControl(control)"
ng-mouseleave="disableCurrentToolsControl(control)">
<div
class="iconBox"
ng-repeat="editor in availableEditors"
ng-click="addControl(editor,cell, controlIndex)"
ng-show="(currentToolsControl == control) && allowedControl(editor, cell)">
ng-repeat="editor in area.$allowedEditors"
ng-click="addControl(editor,area, control.$index)"
ng-show="(currentToolsControl == control)">
<i class="icon {{editor.icon}}"></i>
</div>
@@ -176,7 +175,7 @@
<span ng-if="deletePrompt">
Are you sure?
<a href style="text-decoration: underline" ng-click="removeControl(cell, controlIndex)">Yes</a>
<a href style="text-decoration: underline" ng-click="removeControl(area, control.$index)">Yes</a>
</span>
<i ng-if="!deletePrompt" class="icon icon-trash"></i>
@@ -186,10 +185,11 @@
<!-- Redering the editor for specific control -->
<div
ng-if="control && control.editorPath"
ng-include="control.editorPath"
ng-if="control && control.$editorPath"
ng-include="control.$editorPath"
class="usky-cell usky-cell-{{control.editor.view}}">
</div>
</div>
<!-- Controls repeat end -->
@@ -207,21 +207,25 @@
</div>
<!-- row sortable end -->
<!-- column tools -->
<div class="usky-templates-columns tb">
<div class="tr">
<div class="td middle">
<ul>
<li ng-repeat="cellModel in column.cellModels">
<div class="tb mainTbpt" ng-click="addRow(column, cellModel)">
<li ng-repeat="layout in section.$allowedLayouts">
<div class="tb mainTbpt" ng-click="addRow(section, layout)">
<div class="tr">
<div style="width:{{ cell.percentage; }}%" class="middle mainTdpt td" ng-repeat="cell in cellModel.models">
<i class="icon {{cellPreview(cell)}}"></i>
<div
style="width:{{ area.$percentage}}%"
class="middle mainTdpt td"
ng-repeat="area in layout.areas">
<i class="icon {{cellPreview(area)}}"></i>
</div>
</div>
</div>
<small>{{cellModel.name}}</small>
<small>{{layout.name}}</small>
</li>
</ul>
@@ -238,9 +242,8 @@
</div>
<!-- column repeat end -->
</div>
</div>
<!-- grid wrapper end -->
</div>
</div>

View File

@@ -2,39 +2,248 @@ angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GridPrevalueEditorController",
function ($scope, $http, assetsService, $rootScope, dialogService, mediaResource, gridService, imageHelper, $timeout) {
var emptyModel = {
enableGridWidth: true,
defaultGridWith: "",
enableBackground: true,
enableSkipTopMargin: true,
defaultSkipTopMargin: false,
enableSkipBottomMargin: true,
defaultSkipBottomMargin: false,
enableSkipLeftMargin: true,
defaultSkipLeftMargin: false,
enableSkipRightMargin: true,
defaultSkipRightMargin: false,
enableSkipControlMargin: true,
defaultSkipControlMargin: false,
enableFullScreen: true,
defaultFullScreen: false,
enableBoxed: true,
defaultBoxed: false,
enableRte: true,
enableMedia: true,
enableMacro: true,
enabledEditors: [ "rte", "media", "macro" ],
enableMultiCells: true,
approvedBackgroundCss: "",
gridConfigPath: "views/propertyeditors/grid/config/grid.default.config.js"
}
var emptyModel = {
templates:[
{
name: "1 column",
sections: [
{
grid: 12,
}
]
},
{
name: "2 column",
sections: [
{
grid: 4,
},
{
grid: 8
}
]
},
{
name: "2 column reversed",
sections: [
{
grid: 8,
},
{
grid: 4
}
]
}
],
layouts:[
{
name: "Headline",
areas: [
{
grid: 12,
editors: ["headline"]
}
]
},
{
name: "Article",
areas: [
{
grid: 4
},
{
grid: 8
}
]
}
]
};
/****************
template
*****************/
$scope.configureTemplate = function(template){
if($scope.currentTemplate && $scope.currentTemplate === template){
delete $scope.currentTemplate;
}else{
//if no template is passed in, we can assume we are adding a new one
if(template === undefined){
template = {
name: "",
sections:[
]
};
$scope.model.value.templates.push(template);
}
$scope.currentTemplate = template;
}
};
$scope.deleteTemplate = function(index){
$scope.model.value.templates.splice(index, 1);
};
$scope.closeTemplate = function(){
//clean-up
_.forEach($scope.currentTemplate.sections, function(section, index){
if(section.grid <= 0){
$scope.currentTemplate.sections.splice(index, 1);
}
});
$scope.currentTemplate = undefined;
};
/****************
Section
*****************/
$scope.configureSection = function(section, template){
if($scope.currentSection && $scope.currentSection === section){
delete $scope.currentSection;
}else{
if(section === undefined){
var space = ($scope.availableTemplateSpace > 4) ? 4 : $scope.availableTemplateSpace;
section = {
grid: space
};
template.sections.push(section);
}
$scope.currentSection = section;
}
};
$scope.deleteSection = function(index){
$scope.currentTemplate.sections.splice(index, 1);
};
$scope.closeSection = function(){
$scope.currentSection = undefined;
};
/****************
layout
*****************/
$scope.configureLayout = function(layout){
if($scope.currentLayout && $scope.currentLayout === layout){
delete $scope.currentLayout;
}else{
//if no template is passed in, we can assume we are adding a new one
if(layout === undefined){
layout = {
name: "",
areas:[
]
};
$scope.model.value.layouts.push(layout);
}
$scope.currentLayout = layout;
}
};
$scope.deleteLayout = function(index){
$scope.model.value.layouts.splice(index, 1);
};
$scope.closeLayout = function(){
//clean-up
_.forEach($scope.currentLayout.areas, function(area, index){
if(area.grid <= 0){
$scope.currentLayout.areas.splice(index, 1);
}
});
$scope.currentLayout = undefined;
};
/****************
area
*****************/
$scope.configureArea = function(area, layout){
if($scope.currentArea && $scope.currentArea === area){
delete $scope.currentArea;
}else{
if(area === undefined){
var space = ($scope.availableLayoutSpace > 4) ? 4 : $scope.availableLayoutSpace;
area = {
grid: space
};
layout.areas.push(area);
}
$scope.currentArea = area;
}
};
$scope.deleteArea = function(index){
$scope.currentLayout.areas.splice(index, 1);
};
$scope.closeArea = function(){
$scope.currentArea = undefined;
};
/****************
utillities
*****************/
$scope.scaleUp = function(section, max){
var add = (max > 2) ? 2 : max;
section.grid = section.grid+add;
};
$scope.scaleDown = function(section){
var remove = (section.grid > 2) ? 2 : section.grid;
section.grid = section.grid-remove;
};
$scope.toggleCollection = function(collection){
if(collection === undefined){
collection = [];
}else{
delete collection;
}
}
$scope.percentage = function(spans){
return ((spans/12)*100).toFixed(1);
};
/****************
watchers
*****************/
$scope.$watch("currentTemplate", function(template){
if(template){
var total = 0;
_.forEach(template.sections, function(section){
total = (total + section.grid);
});
$scope.availableTemplateSpace = 12 - total;
}
}, true);
$scope.$watch("currentLayout", function(layout){
if(layout){
var total = 0;
_.forEach(layout.areas, function(area){
total = (total + area.grid);
});
$scope.availableLayoutSpace = 12 - total;
}
}, true);
/****************
editors
*****************/
gridService.getGridEditors().then(function(response){
$scope.editors = response.data;
});
/* init grid data */
if (!$scope.model.value || $scope.model.value == "") {
if (!$scope.model.value || $scope.model.value === "" || !$scope.model.value.templates) {
$scope.model.value = emptyModel;
}

View File

@@ -1,109 +1,290 @@
<div ng-controller="Umbraco.PropertyEditors.GridPrevalueEditorController">
<div ng-controller="Umbraco.PropertyEditors.GridPrevalueEditorController" class="usky-grid usky-grid-configuration">
<p><strong>Config file path:</strong></p>
<table cellpadding="20" style="margin-bottom:20px">
<tr>
<td>
<input ng-model="model.value.gridConfigPath" type="text" style="width:500px;">
</td>
</tr>
</table>
<div style="width: 600px">
<div class="control-group uSky-templates" ng-if="!currentTemplate">
<umb-control-group label="Template grids" description="Grids are the overall layout for the grid editor, usually you only need one or two overall templates" hide-label="false">
<!--<p><strong>Allowed row settings:</strong></p>
<table cellpadding="20" style="margin-bottom:20px">
<tr>
<td>
<p><i class="icon icon-paint-roller"></i>&nbsp;Enable/Disable row background</p>
<input ng-model="model.value.enableBackground" type="checkbox">
<label for="">Enable</label>
</td>
<td>
<p><i class="icon icon-navigation-top"></i>&nbsp;Enable/Disable top margin</p>
<input ng-model="model.value.enableSkipTopMargin" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultSkipTopMargin" type="checkbox">
<label for="">Default value</label>
</td>
<td>
<p><i class="icon icon-navigation-bottom"></i>&nbsp;Enable/Disable bottom margin</p>
<input ng-model="model.value.enableSkipBottomMargin" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultSkipBottomMargin" type="checkbox">
<label for="">Default value</label>
<ul class="unstyled"
ui-sortable
ng-model="model.value.templates">
<li ng-repeat="template in model.value.templates">
</td>
</tr>
<tr>
<td>
<p><i class="icon icon-navigation-first"></i>&nbsp;Enable/Disable left margin</p>
<input ng-model="model.value.enableSkipLeftMargin" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultSkipLeftMargin" type="checkbox">
<label for="">Default value</label>
</td>
<td>
<p><i class="icon icon-navigation-last"></i>&nbsp;Enable/Disable right margin</p>
<input ng-model="model.value.enableSkipRightMargin" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultSkipRightMargin" type="checkbox">
<label for="">Default value</label>
</td>
<td>
<p><i class="icon icon-fullscreen"></i>&nbsp;Enable/Disable control margin</p>
<input ng-model="model.value.enableSkipControlMargin" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultSkipControlMargin" type="checkbox">
<label for="">Default value</label>
</td>
</tr>
<tr>
<td>
<p><i class="icon icon-width"></i>&nbsp;Enable/Disable full screen</p>
<input ng-model="model.value.enableFullScreen" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultFullScreen" type="checkbox">
<label for="">Default value</label>
</td>
<td>
<p><i class="icon icon-frame"></i>&nbsp;Enable/Disable boxed</p>
<input ng-model="model.value.enableBoxed" type="checkbox">
<label for="">Enable</label>
<br />
<input ng-model="model.value.defaultBoxed" type="checkbox">
<label for="">Default value</label>
</td>
</tr>
</table>-->
<div class="uSky-templates-template" style="float: left">
<a href class="tb" ng-click="configureTemplate(template)">
<div class="tr">
<div class="td uSky-templates-column"
ng-class="{last:$last}"
ng-repeat="section in template.sections"
style="width:{{ percentage(section.grid) }}%">
</div>
</div>
</a>
</div>
<!--<p><strong>Allowed editors:</strong></p>
<table cellpadding="20" style="margin-bottom:20px">
<tr>
<td>
<p ng-repeat="editor in editors">
<input type="checkbox"
checklist-model="model.value.enabledEditors"
checklist-value="editor.alias">
&nbsp;<i class="icon {{editor.icon}}"></i>&nbsp; {{editor.name}}
</p>
</td>
</tr>
</table>-->
<p><strong>Others settings:</strong></p>
<table cellpadding="20" style="margin-bottom:20px">
<tr>
<td>
<p><input ng-model="model.value.enableMultiCells" type="checkbox">&nbsp;<i class="icon icon-edit"></i>&nbsp;Multiple controls in cell</p>
<!--<p>Approved background stylesheet path:&nbsp;<input ng-model="model.value.approvedBackgroundCss" type="text" style="width:300px;"></p>-->
</td>
</tr>
</table>
<div>
<a ng-click="configureTemplate(template)" href>{{template.name}}</a><br/>
<small>{{template.sections.length}} configurable sections</small><br/>
<a class="btn btn-small btn-link" href ng-click="deleteTemplate($index)"><i class="icon-delete red"></i> Delete template </a>
</div>
<br style="clear: both"/>
</li>
</ul>
<button class="btn btn-small"
prevent-default
ng-click="configureTemplate()"><i class="icon-add"></i>Add template</button>
</div>
<div ng-if="currentTemplate">
<h5>Template</h5>
<umb-control-group label="Name" hide-label="false">
<input type="text" class="" ng-model="currentTemplate.name" />
</umb-control-group>
<umb-control-group label="Sections" description="Choose a section from the grid to edit" hide-label="false">
<div class="uSky-templates-template"
style="margin: 0; width: 350px; position: relative;">
<div class="tb" style="height: 70px; border-width: 2px; padding: 2px">
<div class="tr">
<a class="td uSky-templates-column"
ng-class="{last:$last, selected:section==currentSection}"
ng-repeat="section in currentTemplate.sections"
ng-click="configureSection(section, currentTemplate)"
style="width:{{ percentage(section.grid) }}%">
</a>
<a class="td uSky-templates-column add" ng-if="availableTemplateSpace > 0"
ng-click="configureSection(undefined, currentTemplate)"
style="width:{{ percentage(availableTemplateSpace) }}%">
<i class="icon icon-add"></i>
</a>
</div>
</div>
</div>
<div ng-if="currentSection" style="padding-bottom: 50px;">
<h5>Modify template Section</h5>
<umb-control-group label="Size" hide-label="false">
<div class="grid-size-scaler">
<a href ng-click="scaleDown(currentSection)">
<i class="icon icon-remove"></i>
</a>
{{currentSection.grid}}
<a href ng-click="scaleUp(currentSection, availableTemplateSpace)">
<i class="icon icon-add"></i>
</a>
</div>
</umb-control-group>
<umb-control-group hide-label="true">
<ul class="unstyled">
<li>
<label>
<input type="checkbox"
ng-model="currentSection.allowAll"
ng-checked="currentSection.allowed === undefined"
ng-change="toggleCollection(currentSection.allowed, currentSection.allowAll)" />
Allow all layouts
</label>
</li>
</ul>
<div ng-if="currentSection.allowAll === false">
<hr />
<div class="control-group uSky-templates-rows">
<ul class="unstyled"
ui-sortable
ng-model="model.value.templates">
<li ng-repeat="layout in model.value.layouts">
<input type="checkbox"
checklist-model="currentSection.allowed"
checklist-value="layout.name"
style="float: left; margin-right: 10px;">
<div class="uSky-templates-row" style="float: left">
<a href class="tb mainTbpt">
<div class="tr">
<div style="width:{{ percentage(area.grid); }}%" class="middle mainTdpt td" ng-repeat="area in layout.areas">
<i class="icon {{areaPreview(area)}}"></i>
</div>
</div>
</a>
</div>
<div>
{{layout.name}}<br/>
<small>{{layout.areas.length}} configurable areas</small><br/>
</div>
<br style="clear: both"/>
</li>
</ul>
</div>
</div>
</umb-control-group>
<button prevent-default ng-click="closeSection()" class="btn btn-small">Finish editing section</button>
<a class="btn btn-small btn-link"
href
ng-click="deleteSection($index)"><i class="icon-delete red"></i> Delete section </a>
</div>
</umb-control-group>
<umb-control-group hide-label="false" ng-if="!currentSection">
<button prevent-default ng-click="closeTemplate()" class="btn btn-small">
Finish editing template
</button>
</umb-control-group>
</div>
</umb-control-group>
</div>
<div style="max-width: 600px">
<div class="control-group uSky-templates" ng-if="!currentLayout">
<umb-control-group
label="Layouts"
description="Layouts are predefined layouts of editors arranged in a row of cells with different editors associated"
hide-label="false">
<div class="control-group uSky-templates-rows">
<ul class="unstyled"
ui-sortable
ng-model="model.value.templates">
<li ng-repeat="layout in model.value.layouts">
<div class="uSky-templates-row" style="float: left">
<a href class="tb mainTbpt" ng-click="configureLayout(layout)">
<div class="tr">
<div style="width:{{ percentage(area.grid); }}%" class="middle mainTdpt td" ng-repeat="area in layout.areas">
<i class="icon {{areaPreview(area)}}"></i>
</div>
</div>
</a>
</div>
<div>
<a ng-click="configureLayout(layout)" href>{{layout.name}}</a><br/>
<small>{{layout.areas.length}} configurable areas</small><br/>
<a class="btn btn-small btn-link" href ng-click="deleteLayout($index)"><i class="icon-delete red"></i> Delete layout </a>
</div>
<br style="clear: both"/>
</li>
</ul>
<button class="btn btn-small"
prevent-default
ng-click="configureLayout()"><i class="icon-add"></i>Add layout</button>
</div>
</umb-control-group>
</div>
<div ng-if="currentLayout">
<h5>Layout</h5>
<umb-control-group
label="Name"
hide-label="false">
<input type="text" class="" ng-model="currentLayout.name" />
</umb-control-group>
<umb-control-group label="Layout areas" hide-label="false" description="Choose an area from the layout to edit">
<div class="uSky-templates-template"
style="margin: 0; width: 350px; position: relative;">
<div class="tb" style="height: 70px; border-width: 2px; padding: 2px">
<div class="tr">
<a class="td uSky-templates-column"
ng-class="{last:$last, selected:area==currentArea}"
ng-repeat="area in currentLayout.areas"
ng-click="configureArea(area, currentLayout)"
style="width:{{ percentage(area.grid) }}%">
</a>
<a class="td uSky-templates-column add" ng-if="availableLayoutSpace > 0"
ng-click="configureArea(undefined, currentLayout)"
style="width:{{ percentage(availableLayoutSpace) }}%">
<i class="icon icon-add"></i>
</a>
</div>
</div>
</div>
<div ng-if="currentArea" style="padding-bottom: 50px;">
<h5>Modify layout area</h5>
<umb-control-group label="Size" hide-label="false">
<div class="grid-size-scaler">
<a href ng-click="scaleDown(currentArea)">
<i class="icon icon-remove"></i>
</a>
{{currentArea.grid}}
<a href ng-click="scaleUp(currentArea, availableLayoutSpace)">
<i class="icon icon-add"></i>
</a>
</div>
</umb-control-group>
<umb-control-group hide-label="true">
<ul class="unstyled">
<li>
<label>
<input type="checkbox"
ng-model="currentArea.allowAll"
ng-checked="currentArea.allowed === undefined"
ng-change="toggleCollection(currentArea.allowed, currentArea.allowAll)" />
Allow all editors
</label>
</li>
</ul>
<div ng-if="currentArea.allowAll === false">
<hr />
<ul class="unstyled">
<li ng-repeat="editor in editors">
<label>
<input type="checkbox"
checklist-model="currentArea.allowed"
checklist-value="editor.alias">
<i class="icon {{editor.icon}}"></i> {{editor.name}}
</label>
</li>
</ul>
</div>
</umb-control-group>
<button prevent-default ng-click="closeArea()" class="btn btn-small">Finish editing area</button>
<a class="btn btn-small btn-link"
href
ng-click="deleteArea($index)"><i class="icon-delete red"></i> Delete area </a>
</div>
</umb-control-group>
<umb-control-group hide-label="false" ng-if="!currentArea">
<button prevent-default ng-click="closeLayout()" class="btn btn-small">Finish editing layout</button>
</umb-control-group>
</div>
</div>
</div>