Files
Umbraco-CMS/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js

551 lines
18 KiB
JavaScript

angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GridController",
function ($scope, $http, assetsService, $rootScope, dialogService, gridService, mediaResource, imageHelper, $timeout) {
// Grid status variables
$scope.currentRow = null;
$scope.currentCell = null;
$scope.currentToolsControl = null;
$scope.currentControl = null;
$scope.openRTEToolbarId = null;
$scope.hasSettings = false;
// *********************************************
// Sortable options
// *********************************************
$scope.sortableOptions = {
distance: 10,
cursor: "move",
placeholder: 'ui-sortable-placeholder',
handle: '.cell-tools-move',
forcePlaceholderSize: true,
tolerance: "pointer",
zIndex: 999999999999999999,
scrollSensitivity: 100,
cursorAt: {
top: 45,
left: 90
},
start: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
});
},
stop: function (e, ui) {
ui.item.parents(".usky-column").find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
});
}
};
var notIncludedRte = [];
var cancelMove = false;
$scope.sortableOptionsCell = {
distance: 10,
cursor: "move",
placeholder: "ui-sortable-placeholder",
handle: '.cell-tools-move',
connectWith: ".usky-cell",
forcePlaceholderSize: true,
tolerance:"pointer",
zIndex: 999999999999999999,
scrollSensitivity: 100,
cursorAt: {
top: 45,
left: 90
},
over: function (event, ui) {
allowedEditors = $(event.target).scope().area.allowed;
if ($.inArray(ui.item.scope().control.editor.alias, allowedEditors) < 0 && allowedEditors) {
ui.placeholder.hide();
cancelMove = true;
}
else {
ui.placeholder.show();
cancelMove = false;
}
},
update: function (event, ui) {
if (!ui.sender) {
if (cancelMove) {
ui.item.sortable.cancel();
}
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr('id'));
}
});
}
else {
$(event.target).find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr('id'));
}
});
}
},
start: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
notIncludedRte = [];
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
});
},
stop: function (e, ui) {
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr('id'));
}
});
$timeout(function () {
_.forEach(notIncludedRte, function (id) {
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.execCommand('mceAddEditor', false, id);
console.info("stop " + id);
});
}, 500, false);
}
};
// *********************************************
// Add items overlay menu
// *********************************************
$scope.overlayMenu = {
show: false,
style: {},
area: undefined,
key: undefined
};
$scope.addItemOverlay = function(event, area, index, key){
$scope.overlayMenu.area = area;
$scope.overlayMenu.index = index;
$scope.overlayMenu.style = {};
$scope.overlayMenu.key = key;
//todo calculate position...
var offset = $(event.target).offset();
var height = $(window).height();
var width = $(window).width();
if((height-offset.top) < 250){
$scope.overlayMenu.style.bottom = 0;
$scope.overlayMenu.style.top = "initial";
}else if(offset.top < 300){
$scope.overlayMenu.style.top = 190;
}
$scope.overlayMenu.show = true;
};
$scope.closeItemOverlay = function () {
$scope.currentControl = null;
$scope.overlayMenu.show = false;
$scope.overlayMenu.key = undefined;
};
// *********************************************
// 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.setWarnighlightRow = function (row) {
$scope.currentWarnhighlightRow = row;
};
$scope.disableWarnhighlightRow = function () {
$scope.currentWarnhighlightRow = null;
};
$scope.setInfohighlightRow = function (row) {
$scope.currentInfohighlightRow = row;
};
$scope.disableInfohighlightRow = function () {
$scope.currentInfohighlightRow = 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 (section, layout) {
//copy the selected layout into the rows collection
var row = angular.copy(layout);
// Init row value
row = $scope.initRow(row);
// Push the new row
if(row){
section.rows.push(row);
}
};
$scope.removeRow = function (section, $index) {
if (section.rows.length > 0) {
section.rows.splice($index, 1);
$scope.currentRow = null;
$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;
}
});
};
// *********************************************
// Area management functions
// *********************************************
$scope.setCurrentCell = function (cell) {
$scope.currentCell = cell;
};
$scope.disableCurrentCell = function () {
$scope.currentCell = null;
};
$scope.cellPreview = function(cell){
if(cell && cell.$allowedEditors){
var editor = cell.$allowedEditors[0];
return editor.icon;
}else{
return "icon-layout";
}
};
$scope.setInfohighlightArea = function (cell) {
$scope.currentInfohighlightArea = cell;
};
$scope.disableInfohighlightArea = function () {
$scope.currentInfohighlightArea = null;
};
// *********************************************
// 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.setWarnhighlightControl = function (Control) {
$scope.currentWarnhighlightControl = Control;
};
$scope.disableWarnhighlightControl = function (Control) {
$scope.currentWarnhighlightControl = null;
};
$scope.setInfohighlightControl = function (Control) {
$scope.currentInfohighlightControl = Control;
};
$scope.disableInfohighlightControl = function (Control) {
$scope.currentInfohighlightControl = null;
};
$scope.setUniqueId = function (cell, index) {
return guid();
};
var guid = (function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
})();
$scope.addControl = function (editor, cell, index){
$scope.closeItemOverlay();
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) {
$scope.currentControl = null;
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;
//settings indicator shortcut
if($scope.model.config.items.config || $scope.model.config.items.styles){
$scope.hasSettings = 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;
}
});
}
if(clear){
$scope.model.value = undefined;
}
};
$scope.initSection = function(section){
section.$percentage = $scope.percentage(section.grid);
var layouts = $scope.model.config.items.layouts;
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(!section.rows){
section.rows = [];
}else{
_.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);
}else{
section.rows[index] = initd;
}
}
});
}
};
// *********************************************
// Init layout / row
// *********************************************
$scope.initRow = function(row){
//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; });
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){
var currentArea = row.areas[areaIndex];
area.config = currentArea.config;
area.styles = currentArea.styles;
//copy over existing controls into the new areas
if(row.areas.length > areaIndex && row.areas[areaIndex].controls){
area.controls = currentArea.controls;
_.forEach(area.controls, function(control, controlIndex){
$scope.initControl(control, controlIndex);
});
}else{
area.controls = [];
}
//set width
area.$percentage = $scope.percentage(area.grid);
area.$uniqueId = $scope.setUniqueId();
//set editor permissions
if(!area.allowed || area.allowAll === true){
area.$allowedEditors = $scope.availableEditors;
area.$allowsRTE = true;
}else{
area.$allowedEditors = _.filter($scope.availableEditors, function(editor){
return _.indexOf(area.allowed, editor.alias) >= 0;
});
if(_.indexOf(area.allowed,"rte")>=0){
area.$allowsRTE = true;
}
}
});
//replace the old row
original.$initialized = true;
//set a disposable unique ID
original.$uniqueId = $scope.setUniqueId();
//set a no disposable unique ID (util for row styling)
original.id = !row.id ? $scope.setUniqueId() : row.id;
return original;
}
};
// *********************************************
// Init control
// *********************************************
$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();
});
});