Merge branch 'v8/dev' into pr/7004
This commit is contained in:
@@ -259,19 +259,18 @@ function dependencies() {
|
||||
//css, fonts and image files
|
||||
|
||||
var assetsTask = gulp.src(config.sources.globs.assets, { allowEmpty: true });
|
||||
if (global.isProd === true) {
|
||||
assetsTask = assetsTask.pipe(imagemin([
|
||||
imagemin.gifsicle({interlaced: true}),
|
||||
imagemin.jpegtran({progressive: true}),
|
||||
imagemin.optipng({optimizationLevel: 5}),
|
||||
imagemin.svgo({
|
||||
plugins: [
|
||||
{removeViewBox: true},
|
||||
{cleanupIDs: false}
|
||||
]
|
||||
})
|
||||
]));
|
||||
}
|
||||
assetsTask = assetsTask.pipe(imagemin([
|
||||
imagemin.gifsicle({interlaced: true}),
|
||||
imagemin.jpegtran({progressive: true}),
|
||||
imagemin.optipng({optimizationLevel: 5}),
|
||||
imagemin.svgo({
|
||||
plugins: [
|
||||
{removeViewBox: true},
|
||||
{cleanupIDs: false}
|
||||
]
|
||||
})
|
||||
]));
|
||||
|
||||
assetsTask = assetsTask.pipe(gulp.dest(config.root + config.targets.assets));
|
||||
|
||||
stream.add(assetsTask);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var through2 = require('through2');
|
||||
|
||||
function createEmptyStream() {
|
||||
var pass = through2.obj();
|
||||
process.nextTick(pass.end.bind(pass));
|
||||
return pass;
|
||||
}
|
||||
|
||||
/**************************
|
||||
* Copies all angular JS files into their separate umbraco.*.js file
|
||||
**************************/
|
||||
function removeProductionMode() {
|
||||
|
||||
global.isProd = false;
|
||||
|
||||
return createEmptyStream();
|
||||
};
|
||||
|
||||
module.exports = { removeProductionMode: removeProductionMode };
|
||||
@@ -20,7 +20,7 @@ function watchTask(cb) {
|
||||
//Setup a watcher for all groups of JS files
|
||||
_.forEach(config.sources.js, function (group) {
|
||||
if(group.watch !== false) {
|
||||
watch(group.files, { ignoreInitial: true, interval: watchInterval }, function JS_Group_Compile() { return processJs(group.files, group.out); });
|
||||
watch(group.files, { ignoreInitial: true, interval: watchInterval }, function JS_Group_Compile() { return processJs(group.files, group.out);});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -23,11 +23,10 @@ module.exports = function (files, out) {
|
||||
// sort files in stream by path or any custom sort comparator
|
||||
task = task.pipe(babel())
|
||||
.pipe(sort());
|
||||
|
||||
if (global.isProd === true) {
|
||||
//in production, embed the templates
|
||||
task = task.pipe(embedTemplates({ basePath: "./src/", minimize: { loose: true } }))
|
||||
}
|
||||
|
||||
//in production, embed the templates
|
||||
task = task.pipe(embedTemplates({ basePath: "./src/", minimize: { loose: true } }))
|
||||
|
||||
task = task.pipe(concat(out))
|
||||
.pipe(wrap('(function(){\n%= body %\n})();'))
|
||||
.pipe(gulp.dest(config.root + config.targets.js));
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
* and then add the exports command to add the new item into the task menu.
|
||||
*/
|
||||
|
||||
global.isProd = true;
|
||||
|
||||
const { src, dest, series, parallel, lastRun } = require('gulp');
|
||||
|
||||
const { dependencies } = require('./gulp/tasks/dependencies');
|
||||
@@ -20,7 +18,6 @@ const { less } = require('./gulp/tasks/less');
|
||||
const { testE2e, testUnit } = require('./gulp/tasks/test');
|
||||
const { views } = require('./gulp/tasks/views');
|
||||
const { watchTask } = require('./gulp/tasks/watchTask');
|
||||
const { removeProductionMode } = require('./gulp/tasks/removeProductionMode');
|
||||
|
||||
// Load local overwrites, can be used to overwrite paths in your local setup.
|
||||
var fs = require('fs');
|
||||
@@ -41,7 +38,6 @@ try {
|
||||
// ***********************************************************
|
||||
exports.build = series(parallel(dependencies, js, less, views), testUnit);
|
||||
exports.dev = series(parallel(dependencies, js, less, views), watchTask);
|
||||
exports.fastdev = series(removeProductionMode, parallel(dependencies, js, less, views), watchTask);
|
||||
exports.watch = series(watchTask);
|
||||
//
|
||||
exports.runTests = series(js, testUnit);
|
||||
|
||||
@@ -195,6 +195,7 @@ Use this directive to construct a header inside the main editor window.
|
||||
@param {string=} icon Show and edit the content icon. Opens an overlay to change the icon.
|
||||
@param {boolean=} hideIcon Set to <code>true</code> to hide icon.
|
||||
@param {string=} alias show and edit the content alias.
|
||||
@param {boolean=} aliasLocked Set to <code>true</code> to lock the alias.
|
||||
@param {boolean=} hideAlias Set to <code>true</code> to hide alias.
|
||||
@param {string=} description Add a description to the content.
|
||||
@param {boolean=} hideDescription Set to <code>true</code> to hide description.
|
||||
@@ -239,12 +240,13 @@ Use this directive to construct a header inside the main editor window.
|
||||
if (scope.editorfor) {
|
||||
localizeVars.push(scope.editorfor);
|
||||
}
|
||||
localizationService.localizeMany(localizeVars).then(function (data) {
|
||||
localizationService.localizeMany(localizeVars).then(function(data) {
|
||||
setAccessibilityForEditor(data);
|
||||
scope.loading = false;
|
||||
});
|
||||
} else {
|
||||
scope.loading = false;
|
||||
}
|
||||
|
||||
scope.goBack = function () {
|
||||
if (scope.onBack) {
|
||||
scope.onBack();
|
||||
@@ -346,6 +348,7 @@ Use this directive to construct a header inside the main editor window.
|
||||
icon: "=",
|
||||
hideIcon: "@",
|
||||
alias: "=",
|
||||
aliasLocked: "<",
|
||||
hideAlias: "=",
|
||||
description: "=",
|
||||
hideDescription: "@",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbProperty', function (umbPropEditorHelper, userService) {
|
||||
.directive('umbProperty', function (userService) {
|
||||
return {
|
||||
scope: {
|
||||
property: "=",
|
||||
@@ -16,22 +16,30 @@ angular.module("umbraco.directives")
|
||||
replace: true,
|
||||
templateUrl: 'views/components/property/umb-property.html',
|
||||
link: function (scope) {
|
||||
|
||||
scope.propertyActions = [];
|
||||
|
||||
userService.getCurrentUser().then(function (u) {
|
||||
var isAdmin = u.userGroups.indexOf('admin') !== -1;
|
||||
scope.propertyAlias = (Umbraco.Sys.ServerVariables.isDebuggingEnabled === true || isAdmin) ? scope.property.alias : null;
|
||||
});
|
||||
},
|
||||
//Define a controller for this directive to expose APIs to other directives
|
||||
controller: function ($scope, $timeout) {
|
||||
controller: function ($scope) {
|
||||
|
||||
var self = this;
|
||||
|
||||
|
||||
//set the API properties/methods
|
||||
|
||||
self.property = $scope.property;
|
||||
self.setPropertyError = function (errorMsg) {
|
||||
$scope.property.propertyErrorMessage = errorMsg;
|
||||
};
|
||||
|
||||
self.setPropertyActions = function(actions) {
|
||||
$scope.propertyActions = actions;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -65,6 +65,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use
|
||||
vm.reloadNode = reloadNode;
|
||||
vm.syncTree = syncTree;
|
||||
vm.loadChildren = loadChildren;
|
||||
vm.hasTree = hasTree;
|
||||
|
||||
//wire up the exposed api object for hosting controllers
|
||||
if ($scope.api) {
|
||||
@@ -72,6 +73,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use
|
||||
$scope.api.load = vm.load;
|
||||
$scope.api.reloadNode = vm.reloadNode;
|
||||
$scope.api.syncTree = vm.syncTree;
|
||||
$scope.api.hasTree = vm.hasTree;
|
||||
}
|
||||
|
||||
//flag to track the last loaded section when the tree 'un-loads'. We use this to determine if we should
|
||||
@@ -203,6 +205,25 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use
|
||||
});
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function hasTree(treeAlias) {
|
||||
|
||||
if (!$scope.tree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null";
|
||||
}
|
||||
|
||||
if (!treeAlias) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var treeRoots = getTreeRootNodes();
|
||||
var foundTree = _.find(treeRoots, function (node) {
|
||||
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
|
||||
});
|
||||
|
||||
return foundTree !== undefined;
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function loadActiveTree(treeAlias) {
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ function confirmDirective() {
|
||||
onCancel: '=',
|
||||
caption: '@',
|
||||
confirmButtonStyle: '@',
|
||||
confirmDisabled: '<?',
|
||||
confirmLabelKey: '@'
|
||||
},
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
@@ -549,7 +549,9 @@
|
||||
property.dataTypeIcon = propertyModel.dataTypeIcon;
|
||||
property.dataTypeName = propertyModel.dataTypeName;
|
||||
property.validation.mandatory = propertyModel.validation.mandatory;
|
||||
property.validation.mandatoryMessage = propertyModel.validation.mandatoryMessage;
|
||||
property.validation.pattern = propertyModel.validation.pattern;
|
||||
property.validation.patternMessage = propertyModel.validation.patternMessage;
|
||||
property.showOnMemberProfile = propertyModel.showOnMemberProfile;
|
||||
property.memberCanEdit = propertyModel.memberCanEdit;
|
||||
property.isSensitiveValue = propertyModel.isSensitiveValue;
|
||||
@@ -632,7 +634,9 @@
|
||||
propertyState: "init",
|
||||
validation: {
|
||||
mandatory: false,
|
||||
pattern: null
|
||||
mandatoryMessage: null,
|
||||
pattern: null,
|
||||
patternMessage: null
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -389,7 +389,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
(umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"PostRenameContainer",
|
||||
{ id: id, name: name })),
|
||||
{ id: id, name: encodeURIComponent(name) })),
|
||||
"Failed to rename the folder with id " + id);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,203 +1,264 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.clipboardService
|
||||
*
|
||||
* @requires notificationsService
|
||||
* @requires eventsService
|
||||
*
|
||||
* @description
|
||||
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService) {
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
if (localStorageService.isSupported === false) {
|
||||
return null;
|
||||
}
|
||||
var dataJSON;
|
||||
var dataString = localStorageService.get(STORAGE_KEY);
|
||||
if (dataString != null) {
|
||||
dataJSON = JSON.parse(dataString);
|
||||
}
|
||||
|
||||
if(dataJSON == null) {
|
||||
dataJSON = new Object();
|
||||
}
|
||||
|
||||
if(dataJSON.entries === undefined) {
|
||||
dataJSON.entries = [];
|
||||
}
|
||||
|
||||
return dataJSON;
|
||||
}
|
||||
|
||||
var saveStorage = function(storage) {
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copy
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
|
||||
* @param {string} alias A string defining the alias of the data to store, example: 'product'
|
||||
* @param {object} data A object containing the properties to be saved.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copy = function(type, alias, data) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
var shallowCloneData = Object.assign({}, data);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
|
||||
delete shallowCloneData.key;
|
||||
delete shallowCloneData.$$hashKey;
|
||||
|
||||
var key = data.key || data.$$hashKey || console.error("missing unique key for this content");
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== key;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:key, type:type, alias:alias, data:shallowCloneData};
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.success("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#supported
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @description
|
||||
* Determins wether the current browser is able to performe its actions.
|
||||
*/
|
||||
service.isSupported = function() {
|
||||
return localStorageService.isSupported;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#hasEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data test for.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to test for.
|
||||
*
|
||||
* @description
|
||||
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
|
||||
*/
|
||||
service.hasEntriesOfType = function(type, aliases) {
|
||||
|
||||
if(service.retriveEntriesOfType(type, aliases).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return (entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
return filteretEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of data of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveDataOfType = function(type, aliases) {
|
||||
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to remove.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to remove.
|
||||
*
|
||||
* @description
|
||||
* Removes entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.clearEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return !(entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
storage.entries = filteretEntries;
|
||||
|
||||
saveStorage(storage);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.clipboardService
|
||||
*
|
||||
* @requires notificationsService
|
||||
* @requires eventsService
|
||||
*
|
||||
* @description
|
||||
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService, iconHelper) {
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
if (localStorageService.isSupported === false) {
|
||||
return null;
|
||||
}
|
||||
var dataJSON;
|
||||
var dataString = localStorageService.get(STORAGE_KEY);
|
||||
if (dataString != null) {
|
||||
dataJSON = JSON.parse(dataString);
|
||||
}
|
||||
|
||||
if(dataJSON == null) {
|
||||
dataJSON = new Object();
|
||||
}
|
||||
|
||||
if(dataJSON.entries === undefined) {
|
||||
dataJSON.entries = [];
|
||||
}
|
||||
|
||||
return dataJSON;
|
||||
}
|
||||
|
||||
var saveStorage = function(storage) {
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var prepareEntryForStorage = function(entryData) {
|
||||
|
||||
var shallowCloneData = Object.assign({}, entryData);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
|
||||
delete shallowCloneData.key;
|
||||
delete shallowCloneData.$$hashKey;
|
||||
|
||||
return shallowCloneData;
|
||||
}
|
||||
|
||||
var isEntryCompatible = function(entry, type, allowedAliases) {
|
||||
return entry.type === type
|
||||
&&
|
||||
(
|
||||
(entry.alias && allowedAliases.filter(allowedAlias => allowedAlias === entry.alias).length > 0)
|
||||
||
|
||||
(entry.aliases && entry.aliases.filter(entryAlias => allowedAliases.filter(allowedAlias => allowedAlias === entryAlias).length > 0).length === entry.aliases.length)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copy
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
|
||||
* @param {string} alias A string defining the alias of the data to store, example: 'product'
|
||||
* @param {object} entry A object containing the properties to be saved, this could be the object of a ElementType, ContentNode, ...
|
||||
* @param {string} displayLabel (optional) A string swetting the label to display when showing paste entries.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copy = function(type, alias, data, displayLabel) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
var uniqueKey = data.key || data.$$hashKey || console.error("missing unique key for this content");
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== uniqueKey;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:uniqueKey, type:type, alias:alias, data:prepareEntryForStorage(data), label:displayLabel || data.name, icon:iconHelper.convertFromLegacyIcon(data.icon)};
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.error("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copyArray
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementTypeArray', 'contentNodeArray'
|
||||
* @param {string} aliases An array of strings defining the alias of the data to store, example: ['banana', 'apple']
|
||||
* @param {object} datas An array of objects containing the properties to be saved, example: [ElementType, ElementType, ...]
|
||||
* @param {string} displayLabel A string setting the label to display when showing paste entries.
|
||||
* @param {string} displayIcon A string setting the icon to display when showing paste entries.
|
||||
* @param {string} uniqueKey A string prodiving an identifier for this entry, existing entries with this key will be removed to ensure that you only have the latest copy of this data.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copyArray = function(type, aliases, datas, displayLabel, displayIcon, uniqueKey) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Clean up each entry
|
||||
var copiedDatas = datas.map(data => prepareEntryForStorage(data));
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== uniqueKey;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:uniqueKey, type:type, aliases:aliases, data:copiedDatas, label:displayLabel, icon:displayIcon};
|
||||
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.error("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#supported
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @description
|
||||
* Determins wether the current browser is able to performe its actions.
|
||||
*/
|
||||
service.isSupported = function() {
|
||||
return localStorageService.isSupported;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#hasEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data test for.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to test for.
|
||||
*
|
||||
* @description
|
||||
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
|
||||
*/
|
||||
service.hasEntriesOfType = function(type, aliases) {
|
||||
|
||||
if(service.retriveEntriesOfType(type, aliases).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveEntriesOfType = function(type, allowedAliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return isEntryCompatible(entry, type, allowedAliases);
|
||||
}
|
||||
);
|
||||
|
||||
return filteretEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of data of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveDataOfType = function(type, aliases) {
|
||||
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to remove.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to remove.
|
||||
*
|
||||
* @description
|
||||
* Removes entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.clearEntriesOfType = function(type, allowedAliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return !isEntryCompatible(entry, type, allowedAliases);
|
||||
}
|
||||
);
|
||||
|
||||
storage.entries = filteretEntries;
|
||||
|
||||
saveStorage(storage);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
angular.module("umbraco.services").factory("clipboardService", clipboardService);
|
||||
|
||||
|
||||
@@ -338,6 +338,22 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.navigationService#hasTree
|
||||
* @methodOf umbraco.services.navigationService
|
||||
*
|
||||
* @description
|
||||
* Checks if a tree with the given alias exists.
|
||||
*
|
||||
* @param {String} treeAlias the tree alias to check
|
||||
*/
|
||||
hasTree: function (treeAlias) {
|
||||
return navReadyPromise.promise.then(function () {
|
||||
return mainTreeApi.hasTree(treeAlias);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Internal method that should ONLY be used by the legacy API wrapper, the legacy API used to
|
||||
have to set an active tree and then sync, the new API does this in one method by using syncTree
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
}
|
||||
|
||||
function confirmDelete(overlay) {
|
||||
overlay.confirmType = "delete";
|
||||
confirm(overlay);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,13 @@
|
||||
});
|
||||
if (cached) return cached[1];
|
||||
|
||||
nodeComputedStyle = nodeComputedStyle || this.doc.defaultView.getComputedStyle(node);
|
||||
if (!nodeComputedStyle) {
|
||||
if (node instanceof DocumentFragment) {
|
||||
return true;// though DocumentFragment doesn't directly have display 'none', we know that it will never be visible, and therefore we return true. (and do not cache this, cause it will change if appended to the DOM)
|
||||
} else {
|
||||
nodeComputedStyle = this.doc.defaultView.getComputedStyle(node);
|
||||
}
|
||||
}
|
||||
|
||||
var result = false;
|
||||
|
||||
|
||||
@@ -543,11 +543,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
'contenteditable': false
|
||||
},
|
||||
embed.preview);
|
||||
|
||||
if (activeElement) {
|
||||
|
||||
// Only replace if activeElement is an Embed element.
|
||||
if (activeElement && activeElement.nodeName.toUpperCase() === "DIV" && activeElement.classList.contains("embeditem")){
|
||||
activeElement.replaceWith(wrapper); // directly replaces the html node
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
editor.selection.setNode(wrapper);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function validationMessageService($q, localizationService) {
|
||||
|
||||
// Gets the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type's validation object
|
||||
// or a localised default.
|
||||
function getMandatoryMessage(validation) {
|
||||
if (!validation) {
|
||||
return $q.when("");
|
||||
}
|
||||
|
||||
if (validation.mandatoryMessage) {
|
||||
return $q.when(validation.mandatoryMessage);
|
||||
} else {
|
||||
return localizationService.localize("general_required").then(function (value) {
|
||||
return $q.when(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var service = {
|
||||
getMandatoryMessage: getMandatoryMessage
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('validationMessageService', validationMessageService);
|
||||
|
||||
|
||||
})();
|
||||
@@ -130,6 +130,7 @@
|
||||
@import "components/umb-media-grid.less";
|
||||
@import "components/umb-folder-grid.less";
|
||||
@import "components/umb-content-grid.less";
|
||||
@import "components/umb-contextmenu.less";
|
||||
@import "components/umb-layout-selector.less";
|
||||
@import "components/tooltip/umb-tooltip.less";
|
||||
@import "components/tooltip/umb-tooltip-list.less";
|
||||
@@ -138,6 +139,7 @@
|
||||
@import "components/umb-grid.less";
|
||||
@import "components/umb-empty-state.less";
|
||||
@import "components/umb-property-editor.less";
|
||||
@import "components/umb-property-actions.less";
|
||||
@import "components/umb-color-swatches.less";
|
||||
@import "components/check-circle.less";
|
||||
@import "components/umb-file-icon.less";
|
||||
@@ -188,6 +190,8 @@
|
||||
@import "components/users/umb-user-preview.less";
|
||||
@import "components/users/umb-user-picker-list.less";
|
||||
|
||||
@import "components/contextdialogs/umb-dialog-datatype-delete.less";
|
||||
|
||||
|
||||
// Utilities
|
||||
@import "utilities/layout/_display.less";
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
.umb-dialog-datatype-delete {
|
||||
|
||||
|
||||
.umb-dialog-datatype-delete__table-head-column-name {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.umb-table-body__icon {
|
||||
margin-right: 5px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.table tbody td > span {
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.table tbody p {
|
||||
line-height: 12px;
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody .icon {
|
||||
vertical-align: top;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
.umb-contextmenu {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
border: 1px solid @dropdownBorder;
|
||||
.box-shadow(0 5px 20px rgba(0,0,0,.3));
|
||||
border-bottom: 1px solid rgba(0,0,0,.2);
|
||||
|
||||
.sep {
|
||||
display: block;
|
||||
border-top: 1px solid @gray-9;
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.umb-contextmenu-item {
|
||||
|
||||
.icon {
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
line-height: @baseLineHeight;
|
||||
white-space: nowrap;
|
||||
|
||||
background-color: @ui-option;
|
||||
border: 0;
|
||||
padding: 7px 12px;
|
||||
color: @ui-option-type;
|
||||
width: 100%;
|
||||
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: @ui-option-type-hover;
|
||||
background-color: @ui-option-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&.-opens-dialog {
|
||||
.menu-label:after {
|
||||
// adds an ellipsis (...) after the menu label for actions that open a dialog
|
||||
content: '\2026';
|
||||
}
|
||||
}
|
||||
button:disabled {
|
||||
cursor: not-allowed;
|
||||
color: @ui-option-disabled-type;
|
||||
&:hover {
|
||||
color: @ui-option-disabled-type-hover;
|
||||
background-color: @ui-option;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -493,11 +493,11 @@ input.umb-group-builder__group-sort-value {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
color: @ui-action-type;
|
||||
|
||||
&:hover{
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color:@ui-action-type-hover;
|
||||
border-color:@ui-action-border-hover;
|
||||
color: @ui-action-type-hover;
|
||||
border-color: @ui-action-border-hover;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,13 @@ input.umb-group-builder__group-sort-value {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.editor-validation-pattern{
|
||||
.editor-validation-message {
|
||||
min-width: 100%;
|
||||
min-height: 25px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.editor-validation-pattern {
|
||||
border: 1px solid @gray-7;
|
||||
margin: 10px 0 0;
|
||||
padding: 6px;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.umb-nested-content {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -15,6 +14,17 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.umb-nested-content--mandatory {
|
||||
/*
|
||||
yeah so this is a pain, but we must be super specific in targeting the mandatory property labels,
|
||||
otherwise all properties within a reqired, nested, nested content property will all appear mandatory
|
||||
*/
|
||||
> ng-form > .control-group > .umb-el-wrap > .control-header label:after {
|
||||
content: '*';
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-nested-content-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -135,6 +145,8 @@
|
||||
|
||||
|
||||
.umb-nested-content__icon {
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
margin: 2px;
|
||||
@@ -170,6 +182,7 @@
|
||||
|
||||
.umb-nested-content__add-content {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px dashed @ui-action-discreet-border;
|
||||
@@ -235,7 +248,6 @@
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder {
|
||||
height: 22px;
|
||||
padding: 4px 6px;
|
||||
border: 1px dashed #d8d7d9;
|
||||
background: 0 0;
|
||||
@@ -246,33 +258,18 @@
|
||||
text-align: center;
|
||||
|
||||
&--selected {
|
||||
border: 1px solid #d8d7d9;
|
||||
border: none;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-name{
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder:hover {
|
||||
color: #2152a3;
|
||||
border-color: #2152a3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-icon-holder {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-icon {
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.form-horizontal .umb-nested-content--narrow .controls-row {
|
||||
margin-left: 40% !important;
|
||||
}
|
||||
|
||||
@@ -107,5 +107,5 @@
|
||||
.umb-panel-group__details-status-action-description {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
padding-left: 165px;
|
||||
padding-left:165px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
.umb-property-actions {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.umb-property-actions__toggle,
|
||||
.umb-property-actions__menu-open-toggle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
padding: 6px 6px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
|
||||
background-color: @ui-action-hover;
|
||||
|
||||
i {
|
||||
height: 3px !important;
|
||||
width: 3px !important;
|
||||
border-radius: 3px;
|
||||
background: @ui-action-type;
|
||||
display: inline-block;
|
||||
margin: 0 2px 0 0;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
i {
|
||||
background: @ui-action-type-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.umb-property-actions__menu-open-toggle {
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
outline: none;// this is not acceccible by keyboard, since we use the .umb-property-actions__toggle for that.
|
||||
|
||||
top: -15px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
|
||||
border: 1px solid @dropdownBorder;
|
||||
|
||||
border-bottom: 1px solid @gray-9;
|
||||
|
||||
.box-shadow(0 5px 20px rgba(0,0,0,.3));
|
||||
|
||||
background-color: white;
|
||||
|
||||
}
|
||||
|
||||
.umb-property .umb-property-actions {
|
||||
float: left;
|
||||
}
|
||||
.umb-property .umb-property-actions__toggle {
|
||||
margin-top: 2px;
|
||||
opacity: 0;
|
||||
transition: opacity 120ms;
|
||||
}
|
||||
.umb-property:hover .umb-property-actions__toggle,
|
||||
.umb-property .umb-property-actions__toggle:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
// Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered.
|
||||
.umb-property:hover .umb-property:not(:hover) .umb-property-actions__toggle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.umb-property-actions__menu {
|
||||
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
|
||||
display: block;
|
||||
|
||||
float: left;
|
||||
min-width: 160px;
|
||||
list-style: none;
|
||||
|
||||
.umb-contextmenu {
|
||||
|
||||
border-top-left-radius: 0;
|
||||
margin-top:1px;
|
||||
|
||||
}
|
||||
|
||||
.umb-contextmenu-item > button {
|
||||
|
||||
z-index:2;// need to stay on top of menu-toggle-open shadow.
|
||||
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,7 @@ input.umb-table__input {
|
||||
line-height: 20px;
|
||||
color: @ui-option-type;
|
||||
vertical-align: bottom;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-table-body__checkicon,
|
||||
|
||||
@@ -63,6 +63,10 @@ a.umb-user-details-details__back-link {
|
||||
|
||||
.umb-user-details-details__sidebar {
|
||||
flex: 0 0 @sidebarwidth;
|
||||
|
||||
.umb-button{
|
||||
margin-left:0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -101,6 +105,7 @@ a.umb-user-details-details__back-link {
|
||||
.umb-user-details-details__information-item {
|
||||
margin-bottom: 10px;
|
||||
font-size: 13px;
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.umb-user-details-details__information-item-label {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
.umb-healthcheck-help-text {
|
||||
line-height: 1.6em;
|
||||
max-width: 750px;
|
||||
}
|
||||
|
||||
.umb-healthcheck-action-bar {
|
||||
|
||||
@@ -528,7 +528,8 @@ input[type="checkbox"][readonly] {
|
||||
.help-inline {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding-left: 5px;
|
||||
padding-top: 4px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
div.help {
|
||||
|
||||
@@ -116,24 +116,42 @@ h5.-black {
|
||||
margin: 20px;
|
||||
}
|
||||
.umb-control-group {
|
||||
border-bottom: 1px solid @gray-11;
|
||||
padding-bottom: 20px;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
display:block;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: @gray-11;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-control-group.-no-border {
|
||||
border: none;
|
||||
&::after {
|
||||
margin-top: 0px;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-property:last-of-type .umb-control-group {
|
||||
border: none;
|
||||
margin-bottom: 0 !important;
|
||||
padding-bottom: 0;
|
||||
&::after {
|
||||
margin-top: 0px;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* BLOCK MODE */
|
||||
.block-form .umb-control-group {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0px;
|
||||
&::after {
|
||||
margin-top: 0px;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.block-form .umb-control-group label .help-block,
|
||||
@@ -163,7 +181,36 @@ h5.-black {
|
||||
}
|
||||
|
||||
.umb-control-group .umb-el-wrap {
|
||||
padding: 0
|
||||
padding: 0;
|
||||
}
|
||||
.form-horizontal .umb-control-group .control-header {
|
||||
float: left;
|
||||
width: 160px;
|
||||
padding-top: 5px;
|
||||
text-align: left;
|
||||
|
||||
.control-label {
|
||||
float: left;
|
||||
width: auto;
|
||||
padding-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.control-description {
|
||||
display: block;
|
||||
clear: both;
|
||||
max-width:480px;// avoiding description becoming too wide when its placed on top of property.
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.form-horizontal .umb-control-group .control-header {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* LABELS*/
|
||||
|
||||
@@ -97,7 +97,8 @@
|
||||
|
||||
.history-line {
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
top: 10px;
|
||||
bottom: 10px;
|
||||
margin: 0 0 0 14px;
|
||||
background-color: @gray-8;
|
||||
position: absolute;
|
||||
|
||||
@@ -415,8 +415,6 @@
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails.ui-sortable:not(.ui-sortable-disabled) {
|
||||
@@ -425,9 +423,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li:hover .umb-sortable-thumbnails__actions {
|
||||
.umb-sortable-thumbnails li:hover .umb-sortable-thumbnails__action {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action {
|
||||
@@ -443,6 +440,12 @@
|
||||
margin-left: 5px;
|
||||
text-decoration: none;
|
||||
.box-shadow(0 1px 2px rgba(0,0,0,0.25));
|
||||
opacity: 0;
|
||||
transition: opacity .1s ease-in-out;
|
||||
|
||||
.tabbing-active &:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action.-red {
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
|
||||
@ui-option-type: @blueExtraDark;
|
||||
@ui-option-type-hover: @blueMid;
|
||||
@ui-option: white;
|
||||
@ui-option-hover: @sand-7;
|
||||
|
||||
@ui-option-disabled-type: @gray-6;
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div ng-if="vm.availableGroups.length > 0">
|
||||
<div class="umb-control-group -no-border" ng-if="vm.availableGroups.length > 0">
|
||||
<ul class="umb-checkbox-list" ng-repeat="group in vm.availableGroups | filter:searchTerm">
|
||||
<li ng-show="vm.availableGroups.length > 1">
|
||||
<i class="icon-folder umb-checkbox-list__item-icon"></i>
|
||||
|
||||
@@ -15,42 +15,40 @@
|
||||
|
||||
<div on-drag-leave="vm.dragLeave()" on-drag-end="vm.dragLeave()" on-drag-enter="vm.dragEnter()">
|
||||
|
||||
<div class="umb-control-group umb-mediapicker-upload">
|
||||
<div class="umb-control-group">
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="vm.loading">
|
||||
</umb-load-indicator>
|
||||
<div class="umb-mediapicker-upload">
|
||||
<div class="form-search">
|
||||
<i class="icon-search" aria-hidden="true"></i>
|
||||
<input class="umb-search-field search-query -full-width-input"
|
||||
ng-model="vm.searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="vm.changeSearch()"
|
||||
type="text"
|
||||
umb-auto-focus
|
||||
no-dirty-check
|
||||
/>
|
||||
|
||||
<div class="form-search">
|
||||
<i class="icon-search" aria-hidden="true"></i>
|
||||
<input class="umb-search-field search-query -full-width-input"
|
||||
ng-model="vm.searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="vm.changeSearch()"
|
||||
type="text"
|
||||
umb-auto-focus
|
||||
no-dirty-check
|
||||
/>
|
||||
|
||||
<div class="form-search__toggle">
|
||||
<umb-checkbox
|
||||
model="showChilds"
|
||||
on-change="vm.toggle()"
|
||||
text="Include subfolders in search"
|
||||
label-key="general_includeFromsubFolders">
|
||||
</umb-checkbox>
|
||||
<div class="form-search__toggle">
|
||||
<umb-checkbox
|
||||
model="showChilds"
|
||||
on-change="vm.toggle()"
|
||||
text="Include subfolders in search"
|
||||
label-key="general_includeFromsubFolders">
|
||||
</umb-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="upload-button">
|
||||
<umb-button
|
||||
type="button"
|
||||
label-key="general_upload"
|
||||
action="vm.upload()"
|
||||
disabled="lockedFolder"
|
||||
button-style="action">
|
||||
</umb-button>
|
||||
<div class="upload-button">
|
||||
<umb-button
|
||||
type="button"
|
||||
label-key="general_upload"
|
||||
action="vm.upload()"
|
||||
disabled="lockedFolder"
|
||||
button-style="action">
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -120,6 +118,11 @@
|
||||
current-folder-id="{{currentFolder.id}}">
|
||||
</umb-media-grid>
|
||||
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="vm.loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination
|
||||
ng-if="vm.searchOptions.totalPages > 0 && !vm.loading"
|
||||
@@ -136,7 +139,7 @@
|
||||
</div>
|
||||
|
||||
<umb-overlay ng-if="vm.mediaPickerDetailsOverlay.show" model="vm.mediaPickerDetailsOverlay" position="right">
|
||||
|
||||
|
||||
<div class="umb-control-group" ng-if="!target.id">
|
||||
<h5>
|
||||
<localize key="@general_url"></localize>
|
||||
|
||||
@@ -81,39 +81,55 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group clearfix" ng-if="!model.property.locked">
|
||||
|
||||
|
||||
<h5><localize key="validation_validation"></localize></h5>
|
||||
|
||||
<label>
|
||||
|
||||
<label>
|
||||
<localize key="validation_fieldIsMandatory"></localize>
|
||||
</label>
|
||||
|
||||
<umb-toggle data-element="validation_mandatory"
|
||||
checked="model.property.validation.mandatory"
|
||||
on-click="vm.toggleValidation()"
|
||||
on-click="vm.toggleValidation()">
|
||||
focus-when="{{vm.focusOnMandatoryField}}"
|
||||
>
|
||||
</umb-toggle>
|
||||
|
||||
<label class="mt3">
|
||||
<input type="text"
|
||||
class="editor-validation-message"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_mandatoryMessage"
|
||||
ng-model="model.property.validation.mandatoryMessage"
|
||||
ng-if="model.property.validation.mandatory"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</input>
|
||||
|
||||
<label class="mt3">
|
||||
<localize key="validation_customValidation"></localize>
|
||||
</label>
|
||||
|
||||
|
||||
<select class="umb-dropdown" ng-options="validationType.name for validationType in vm.validationTypes" ng-model="vm.selectedValidationType" ng-change="vm.changeValidationType(vm.selectedValidationType)">
|
||||
<option value=""><localize key="validation_noValidation">No validation</localize></option>
|
||||
</select>
|
||||
|
||||
|
||||
<textarea class="editor-validation-pattern"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExp"
|
||||
ng-model="model.property.validation.pattern"
|
||||
ng-change="vm.changeValidationPattern()"
|
||||
ng-if="vm.showValidationPattern"
|
||||
umb-auto-resize
|
||||
focus-when="{{vm.focusOnPatternField}}"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</textarea>
|
||||
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExp"
|
||||
ng-model="model.property.validation.pattern"
|
||||
ng-change="vm.changeValidationPattern()"
|
||||
ng-if="vm.showValidationPattern"
|
||||
umb-auto-resize
|
||||
focus-when="{{vm.focusOnPatternField}}"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</textarea>
|
||||
|
||||
<input type="text"
|
||||
class="editor-validation-message"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExpMessage"
|
||||
ng-model="model.property.validation.patternMessage"
|
||||
ng-if="vm.showValidationPattern"
|
||||
ng-keypress="vm.submitOnEnter($event)" />
|
||||
|
||||
</div>
|
||||
<div class="umb-control-group clearfix" ng-if="model.contentType === 'documentType' && model.contentTypeAllowCultureVariant">
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
title="{{historyLabel}}">
|
||||
|
||||
<umb-button
|
||||
ng-hide="node.trashed"
|
||||
type="button"
|
||||
button-style="outline"
|
||||
action="openRollback()"
|
||||
@@ -168,9 +169,9 @@
|
||||
ng-change="updateTemplate(node.template)">
|
||||
<option value="">{{chooseLabel}}...</option>
|
||||
</select>
|
||||
<a href="" ng-show="allowChangeTemplate && node.template !== null" class="umb-node-preview__action" style="margin-left:15px;" ng-click="openTemplate()">
|
||||
<button ng-show="allowChangeTemplate && node.template !== null" class="umb-node-preview__action" style="margin-left:15px;" ng-click="openTemplate()">
|
||||
<localize key="general_open">Open</localize>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="umb-property-actions" ng-if="vm.actions.length > 0">
|
||||
<button type="button" class="btn-reset umb-outline umb-property-actions__toggle" ng-click="vm.toggle()" localize="title" title="propertyActions_tooltipForPropertyActionsMenu"><i></i><i></i><i></i></button>
|
||||
|
||||
<div class="umb-property-actions__menu" role="menu" ng-if="vm.isOpen" on-outside-click="vm.close()" on-close="vm.close()" deep-blur="vm.close()">
|
||||
<button class="umb-property-actions__menu-open-toggle" ng-click="vm.close()" tabindex="-1"><i></i><i></i><i></i></button>
|
||||
<ul class="umb-contextmenu">
|
||||
<li ng-repeat="action in vm.actions" role="menuitem" class="umb-contextmenu-item" ng-class="{'-opens-dialog': action.opensDialog}">
|
||||
<button type="button" class="btn-reset umb-outline" ng-click="vm.executeAction(action)" ng-disabled="action.isDisabled === true">
|
||||
<i class="icon icon-{{action.icon}}" aria-hidden="true"></i>
|
||||
<span class="menu-label"><localize key="{{::action.labelKey}}" tokens="action.labelTokens"></localize></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,61 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* A component to render the property action toggle
|
||||
*/
|
||||
|
||||
function umbPropertyActionsController(keyboardService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.isOpen = false;
|
||||
|
||||
function initDropDown() {
|
||||
keyboardService.bind("esc", vm.close);
|
||||
}
|
||||
function destroyDropDown() {
|
||||
keyboardService.unbind("esc");
|
||||
}
|
||||
|
||||
vm.toggle = function() {
|
||||
if (vm.isOpen === true) {
|
||||
vm.close();
|
||||
} else {
|
||||
vm.open();
|
||||
}
|
||||
}
|
||||
vm.open = function() {
|
||||
vm.isOpen = true;
|
||||
initDropDown();
|
||||
}
|
||||
vm.close = function() {
|
||||
vm.isOpen = false;
|
||||
destroyDropDown();
|
||||
}
|
||||
|
||||
vm.executeAction = function(action) {
|
||||
action.method();
|
||||
vm.close();
|
||||
}
|
||||
|
||||
vm.$onDestroy = function () {
|
||||
if (vm.isOpen === true) {
|
||||
destroyDropDown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var umbPropertyActionsComponent = {
|
||||
templateUrl: 'views/components/property/property-actions/umb-property-actions.html',
|
||||
bindings: {
|
||||
actions: "<"
|
||||
},
|
||||
controllerAs: 'vm',
|
||||
controller: umbPropertyActionsController
|
||||
};
|
||||
|
||||
angular.module('umbraco.directives').component('umbPropertyActions', umbPropertyActionsComponent);
|
||||
|
||||
})();
|
||||
@@ -6,19 +6,25 @@
|
||||
|
||||
<div class="umb-el-wrap">
|
||||
|
||||
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}" ng-attr-title="{{propertyAlias}}">
|
||||
|
||||
<div class="control-header">
|
||||
<small ng-if="showInherit" class="db" style="padding-top: 0; margin-bottom: 5px;">
|
||||
<localize key="contentTypeEditor_inheritedFrom"></localize> {{inheritsFrom}}
|
||||
</small>
|
||||
|
||||
{{property.label}}
|
||||
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}" ng-attr-title="{{propertyAlias}}">
|
||||
|
||||
<span ng-if="property.validation.mandatory">
|
||||
<strong class="umb-control-required">*</strong>
|
||||
</span>
|
||||
<small ng-bind-html="property.description | preserveNewLineInHtml"></small>
|
||||
</label>
|
||||
{{property.label}}
|
||||
|
||||
<span ng-if="property.validation.mandatory">
|
||||
<strong class="umb-control-required">*</strong>
|
||||
</span>
|
||||
|
||||
</label>
|
||||
|
||||
<umb-property-actions actions="propertyActions"></umb-property-actions>
|
||||
|
||||
<small class="control-description" ng-bind-html="property.description | preserveNewLineInHtml"></small>
|
||||
</div>
|
||||
|
||||
<div class="controls" ng-transclude>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
action="confirm()"
|
||||
button-style="{{confirmButtonStyle || 'primary'}}"
|
||||
state="confirmButtonState"
|
||||
disabled="confirmDisabled === true"
|
||||
label-key="{{confirmLabelKey || 'general_ok'}}">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<h3>Hours of Umbraco training videos are only a click away</h3>
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a href="https://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
|
||||
<h3><localize key="settingsDashboardVideos_trainingHeadline">Hours of Umbraco training videos are only a click away</localize></h3>
|
||||
<localize key="settingsDashboardVideos_trainingDescription">
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
|
||||
</localize>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<div ng-show="videos.length">
|
||||
<h4>To get you started:</h4>
|
||||
<h4><localize key="settingsDashboardVideos_getStarted">To get you started</localize>:</h4>
|
||||
<ul class="thumbnails" >
|
||||
<li class="span2" ng-repeat="video in videos">
|
||||
<div class="thumbnail" style="margin-right: 20px">
|
||||
|
||||
@@ -100,8 +100,12 @@
|
||||
<div class="umb-panel-group__details-check">
|
||||
|
||||
<div class="umb-panel-group__details-check-title">
|
||||
<div class="umb-panel-group__details-check-name">Search</div>
|
||||
<div class="umb-panel-group__details-check-description">Search the index and view the results</div>
|
||||
<div class="umb-panel-group__details-check-name">
|
||||
<localize key="general_search">Search</localize>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-check-description">
|
||||
<localize key="examineManagement_searchDescription">Search the index and view the results</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-group__details-status">
|
||||
@@ -225,7 +229,7 @@
|
||||
<div class="umb-panel-group__details-status-text">
|
||||
<div>{{vm.selectedIndex.healthStatus}}</div>
|
||||
<div ng-show="!vm.selectedIndex" class="color-red">
|
||||
The index cannot be read and will need to be rebuilt
|
||||
<localize key="examineManagement_indexCannotRead">The index cannot be read and will need to be rebuilt</localize>
|
||||
</div>
|
||||
<!--<div ng-if="status.description" ng-bind-html="status.description"></div>-->
|
||||
</div>
|
||||
@@ -377,13 +381,14 @@
|
||||
</div>
|
||||
|
||||
<div ng-show="vm.selectedIndex.processingAttempts >= 100">
|
||||
The process is taking longer than expected, check the umbraco log to see if there have been any errors during this operation
|
||||
<localize key="examineManagement_processIsTakingLonger">The process is taking longer than expected, check the umbraco log to see if there have been any errors during this operation</localize>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
|
||||
<div class="umb-panel-group__details-status-action-description" ng-show="!vm.selectedIndex.canRebuild">
|
||||
This index cannot be rebuilt because it has no assigned <code>IIndexPopulator</code>
|
||||
<localize key="examineManagement_indexCannotRebuild">This index cannot be rebuilt because it has no assigned </localize>
|
||||
<code><localize key="examineManagement_iIndexPopulator">IIndexPopulator</localize></code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,78 +4,70 @@
|
||||
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="bold">Health Check</h3>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="success"
|
||||
label="Check All Groups"
|
||||
action="vm.checkAllGroups(vm.groups)">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-help-text">
|
||||
<p>The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button.
|
||||
You can add your own health checks, have a look at <a href="https://our.umbraco.com/documentation/Extending/Healthcheck/" target="_blank" class="btn-link -underline">the documentation for more information</a> about custom health checks.</p>
|
||||
<p>
|
||||
The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button.
|
||||
You can add your own health checks, have a look at <a href="https://our.umbraco.com/documentation/Extending/Healthcheck/" target="_blank" class="btn-link -underline">the documentation for more information</a> about custom health checks.
|
||||
</p>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-status-actions">
|
||||
<umb-button type="button"
|
||||
button-style="success"
|
||||
label="Check All Groups"
|
||||
action="vm.checkAllGroups(vm.groups)">
|
||||
</umb-button>
|
||||
</div>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<div class="umb-healthcheck">
|
||||
|
||||
<div class="umb-air" ng-repeat="group in vm.groups">
|
||||
<button type="button" class="umb-healthcheck-group" ng-click="vm.openGroup(group);">
|
||||
|
||||
<div class="umb-healthcheck-title">{{group.name}}</div>
|
||||
<div class="umb-healthcheck-title">{{group.name}}</div>
|
||||
|
||||
<div class="umb-healthcheck-group__load-container" ng-if="group.loading">
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
<div class="umb-healthcheck-group__load-container" ng-if="group.loading">
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-messages"
|
||||
ng-hide="group.loading || !group.totalSuccess && !group.totalWarning && !group.totalError && !group.totalInfo">
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalSuccess > 0">
|
||||
<i class="icon-check color-green" aria-hidden="true"></i>
|
||||
{{ group.totalSuccess }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_passed">passed</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="umb-healthcheck-messages"
|
||||
ng-hide="group.loading || !group.totalSuccess && !group.totalWarning && !group.totalError && !group.totalInfo"
|
||||
>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalSuccess > 0">
|
||||
<i class="icon-check color-green" aria-hidden="true"></i>
|
||||
{{ group.totalSuccess }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_passed">passed</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalWarning > 0">
|
||||
<i class="icon-alert color-orange" aria-hidden="true"></i>
|
||||
{{ group.totalWarning }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_warning">warning</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalError > 0">
|
||||
<i class="icon-delete color-red" aria-hidden="true"></i>
|
||||
{{ group.totalError }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_failed">failed</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalInfo > 0">
|
||||
<i class="umb-healthcheck-status-icon icon-info" aria-hidden="true"></i>
|
||||
{{ group.totalInfo }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_suggestion">suggestion</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalWarning > 0">
|
||||
<i class="icon-alert color-orange" aria-hidden="true"></i>
|
||||
{{ group.totalWarning }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_warning">warning</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalError > 0">
|
||||
<i class="icon-delete color-red" aria-hidden="true"></i>
|
||||
{{ group.totalError }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_failed">failed</localize>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="umb-healthcheck-message" ng-if="group.totalInfo > 0">
|
||||
<i class="umb-healthcheck-status-icon icon-info" aria-hidden="true"></i>
|
||||
{{ group.totalInfo }}
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_suggestion">suggestion</localize>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-if="vm.viewState === 'details'">
|
||||
@@ -88,31 +80,25 @@
|
||||
</umb-editor-sub-header-content-left>
|
||||
</umb-editor-sub-header>
|
||||
|
||||
|
||||
<div class="umb-panel-group__details">
|
||||
|
||||
<div class="umb-panel-group__details-group">
|
||||
|
||||
<div class="umb-panel-group__details-group-title">
|
||||
<div class="umb-panel-group__details-group-name">{{ vm.selectedGroup.name }}</div>
|
||||
<umb-button
|
||||
type="button"
|
||||
action="vm.checkAllInGroup(vm.selectedGroup, vm.selectedGroup.checks)"
|
||||
label="Check group">
|
||||
<umb-button type="button" button-style="success"
|
||||
action="vm.checkAllInGroup(vm.selectedGroup, vm.selectedGroup.checks)"
|
||||
label="Check group">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-group__details-checks">
|
||||
|
||||
<div class="umb-panel-group__details-check" ng-repeat="check in vm.selectedGroup.checks">
|
||||
|
||||
<div class="umb-panel-group__details-check-title">
|
||||
<div class="umb-panel-group__details-check-name">{{ check.name }}</div>
|
||||
<div class="umb-panel-group__details-check-description">{{ check.description }}</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-group__details-status" ng-repeat="status in check.status">
|
||||
|
||||
<div class="umb-panel-group__details-status-icon-container" aria-hidden="true">
|
||||
<i class="umb-healthcheck-status-icon icon-check color-green" ng-if="status.resultType === 0"></i>
|
||||
<i class="umb-healthcheck-status-icon icon-alert icon-alert color-yellow" ng-if="status.resultType === 1"></i>
|
||||
@@ -121,7 +107,6 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-group__details-status-content">
|
||||
|
||||
<div class="umb-panel-group__details-status-text">
|
||||
<span class="sr-only" ng-if="status.resultType === 0">
|
||||
<localize key="visuallyHiddenTexts_checkPassed">Check passed</localize>:
|
||||
@@ -145,16 +130,15 @@
|
||||
|
||||
<div ng-if="action.valueRequired">
|
||||
<div><label class="bold">Set new value:</label></div>
|
||||
<input name="providedValue" type="text" ng-model="action.providedValue" required val-email/>
|
||||
<input name="providedValue" type="text" ng-model="action.providedValue" required val-email />
|
||||
</div>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="success"
|
||||
size="s"
|
||||
disabled="healthCheckAction.providedValue.$invalid"
|
||||
action="vm.executeAction(check, $parent.$index, action)"
|
||||
label="{{action.name}}">
|
||||
<umb-button type="button"
|
||||
button-style="success"
|
||||
size="s"
|
||||
disabled="healthCheckAction.providedValue.$invalid"
|
||||
action="vm.executeAction(check, $parent.$index, action)"
|
||||
label="{{action.name}}">
|
||||
</umb-button>
|
||||
|
||||
</ng-form>
|
||||
@@ -162,9 +146,7 @@
|
||||
<div class="umb-panel-group__details-status-action-description" ng-if="action.description" ng-bind-html="action.description"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="check.loading">
|
||||
@@ -173,13 +155,8 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
</div>
|
||||
<p>
|
||||
<span ng-show="vm.working">(wait)</span>
|
||||
<span ng-show="vm.working">(<localize key="nuCache_wait">wait</localize>)</span>
|
||||
</p>
|
||||
|
||||
<div class="umb-panel-group__details-group">
|
||||
<div class="umb-panel-group__details-group-title">
|
||||
<div class="umb-panel-group__details-group-name">Published Cache Status</div>
|
||||
<div class="umb-panel-group__details-group-name">
|
||||
<localize key="nuCache_publishedCacheStatus">Published Cache Status</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-checks">
|
||||
<div class="umb-panel-group__details-check">
|
||||
@@ -20,7 +22,9 @@
|
||||
</div>
|
||||
<div class="umb-panel-group__details-status-actions">
|
||||
<div class="umb-panel-group__details-status-action no-background no-left-padding">
|
||||
<button type="button" ng-click="vm.verify($event)" class="btn btn-danger">Refresh status</button>
|
||||
<button type="button" ng-click="vm.verify($event)" class="btn btn-danger">
|
||||
<localize key="nuCache_refreshStatus">Refresh status</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,53 +35,75 @@
|
||||
<br />
|
||||
<div class="umb-panel-group__details-group">
|
||||
<div class="umb-panel-group__details-group-title">
|
||||
<div class="umb-panel-group__details-group-name">Caches</div>
|
||||
<div class="umb-panel-group__details-group-name">
|
||||
<localize key="nuCache_caches">Caches</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-checks">
|
||||
<div class="umb-panel-group__details-check">
|
||||
<div class="umb-panel-group__details-check-title">
|
||||
<div class="umb-panel-group__details-check-name">Memory Cache</div>
|
||||
<div class="umb-panel-group__details-check-name">
|
||||
<localize key="nuCache_memoryCache">Memory Cache</localize>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-check-description">
|
||||
This button lets you reload the in-memory cache, by entirely reloading it from the database
|
||||
cache (but it does not rebuild that database cache). This is relatively fast.
|
||||
Use it when you think that the memory cache has not been properly refreshed, after some events
|
||||
triggered—which would indicate a minor Umbraco issue.
|
||||
(note: triggers the reload on all servers in an LB environment).
|
||||
<localize key="nuCache_memoryCacheDescription">
|
||||
This button lets you reload the in-memory cache, by entirely reloading it from the database
|
||||
cache (but it does not rebuild that database cache). This is relatively fast.
|
||||
Use it when you think that the memory cache has not been properly refreshed, after some events
|
||||
triggered—which would indicate a minor Umbraco issue.
|
||||
(note: triggers the reload on all servers in an LB environment).
|
||||
</localize>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-group__details-status-actions">
|
||||
<div class="umb-panel-group__details-status-action no-background no-left-padding">
|
||||
<button type="button" ng-click="vm.reload($event)" class="btn btn-danger">Reload</button>
|
||||
<button type="button" ng-click="vm.reload($event)" class="btn btn-danger">
|
||||
<localize key="nuCache_reload">Reload</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-panel-group__details-check-title top-border">
|
||||
<div class="umb-panel-group__details-check-name">Database Cache</div>
|
||||
<div class="umb-panel-group__details-check-name">
|
||||
<localize key="nuCache_databaseCache">Database Cache</localize>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-check-description">
|
||||
This button lets you rebuild the database cache, ie the content of the cmsContentNu table.
|
||||
<strong>Rebuilding can be expensive.</strong>
|
||||
Use it when reloading is not enough, and you think that the database cache has not been
|
||||
properly generated—which would indicate some critical Umbraco issue.
|
||||
<localize key="nuCache_databaseCacheDescription">
|
||||
This button lets you rebuild the database cache, ie the content of the cmsContentNu table.
|
||||
<strong>Rebuilding can be expensive.</strong>
|
||||
Use it when reloading is not enough, and you think that the database cache has not been
|
||||
properly generated—which would indicate some critical Umbraco issue.
|
||||
</localize>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-status-actions">
|
||||
<div class="umb-panel-group__details-status-action no-background no-left-padding">
|
||||
<button type="button" ng-click="vm.rebuild($event)" class="btn btn-danger">Rebuild</button>
|
||||
<button type="button" ng-click="vm.rebuild($event)" class="btn btn-danger">
|
||||
<localize key="nuCache_rebuild">Rebuild</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-panel-group__details-check-title top-border">
|
||||
<div class="umb-panel-group__details-check-name">Internals</div>
|
||||
<div class="umb-panel-group__details-check-name">
|
||||
<localize key="nuCache_internals">Internals</localize>
|
||||
</div>
|
||||
<div class="umb-panel-group__details-check-description">
|
||||
This button lets you trigger a NuCache snapshots collection (after running a fullCLR GC).
|
||||
Unless you know what that means, you probably do <em>not</em> need to use it.
|
||||
<localize key="nuCache_internalsDescription">
|
||||
This button lets you trigger a NuCache snapshots collection (after running a fullCLR GC).
|
||||
Unless you know what that means, you probably do <em>not</em> need to use it.
|
||||
</localize>
|
||||
|
||||
</div>
|
||||
<div class="umb-panel-group__details-status-actions">
|
||||
<div class="umb-panel-group__details-status-action no-background no-left-padding">
|
||||
<button type="button" ng-click="vm.collect($event)" class="btn btn-danger">Collect</button>
|
||||
<button type="button" ng-click="vm.collect($event)" class="btn btn-danger">
|
||||
<localize key="nuCache_collect">Collect</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,39 +6,51 @@
|
||||
|
||||
<umb-box ng-hide="vm.loading">
|
||||
<umb-box-content>
|
||||
<h3 class="bold">Performance profiling</h3>
|
||||
<h3 class="bold">
|
||||
<localize key="profiling_performanceProfiling">Performance profiling</localize>
|
||||
</h3>
|
||||
<div ng-show="vm.profilerEnabled">
|
||||
<div class="mb4">
|
||||
<p>
|
||||
Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.
|
||||
</p>
|
||||
<p>
|
||||
If you want to activate the profiler for a specific page rendering, simply add <b>umbDebug=true</b> to the querystring when requesting the page.
|
||||
</p>
|
||||
<p>
|
||||
If you want the profiler to be activated by default for all page renderings, you can use the toggle below.
|
||||
It will set a cookie in your browser, which then activates the profiler automatically.
|
||||
In other words, the profiler will only be active by default in <i>your</i> browser - not everyone else's.
|
||||
</p>
|
||||
<localize key="profiling_performanceProfilingDescription">
|
||||
<p>
|
||||
Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.
|
||||
</p>
|
||||
<p>
|
||||
If you want to activate the profiler for a specific page rendering, simply add <b>umbDebug=true</b> to the querystring when requesting the page.
|
||||
</p>
|
||||
<p>
|
||||
If you want the profiler to be activated by default for all page renderings, you can use the toggle below.
|
||||
It will set a cookie in your browser, which then activates the profiler automatically.
|
||||
In other words, the profiler will only be active by default in <i>your</i> browser - not everyone else's.
|
||||
</p>
|
||||
</localize>
|
||||
</div>
|
||||
<div class="mb4">
|
||||
<div class="flex items-center">
|
||||
<umb-toggle checked="vm.alwaysOn" id="profilerAlwaysOn" on-click="vm.toggle()"></umb-toggle>
|
||||
<label for="profilerAlwaysOn" class="mb0 ml2">Activate the profiler by default</label>
|
||||
<label for="profilerAlwaysOn" class="mb0 ml2">
|
||||
<localize key="profiling_activateByDefault">Activate the profiler by default</localize>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h4>Friendly reminder</h4>
|
||||
<p>
|
||||
You should never let a production site run in debug mode. Debug mode is turned off by setting <b>debug="false"</b> on the <b><compilation /></b> element in web.config.
|
||||
</p>
|
||||
<h4>
|
||||
<localize key="profiling_reminder">Friendly reminder</localize>
|
||||
</h4>
|
||||
<localize key="profiling_reminderDescription">
|
||||
<p>
|
||||
You should never let a production site run in debug mode. Debug mode is turned off by setting <b>debug="false"</b> on the <b><compilation /></b> element in web.config.
|
||||
</p>
|
||||
</localize>
|
||||
</div>
|
||||
<div ng-hide="vm.profilerEnabled">
|
||||
<p>
|
||||
Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.
|
||||
</p>
|
||||
<p>
|
||||
Debug mode is turned on by setting <b>debug="true"</b> on the <b><compilation /></b> element in web.config.
|
||||
</p>
|
||||
<localize key="profiling_profilerEnabledDescription">
|
||||
<p>
|
||||
Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.
|
||||
</p>
|
||||
<p>
|
||||
Debug mode is turned on by setting <b>debug="true"</b> on the <b><compilation /></b> element in web.config.
|
||||
</p>
|
||||
</localize>
|
||||
</div>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<h3 class="bold">Start here</h3>
|
||||
<p>This section contains the building blocks for your Umbraco site. Follow the below links to find out more about working with the items in the Settings section:</p>
|
||||
<h5>Find out more:</h5>
|
||||
<h3 class="bold">
|
||||
<localize key="settingsDashboard_start">Start here</localize>
|
||||
</h3>
|
||||
<localize key="settingsDashboard_startDescription">
|
||||
<p>This section contains the building blocks for your Umbraco site. Follow the below links to find out more about working with the items in the Settings section:</p>
|
||||
</localize>:
|
||||
<h5>
|
||||
<localize key="settingsDashboard_more">Find out more</localize>:
|
||||
</h5>
|
||||
<ul>
|
||||
<li>Read more about working with the items in Settings <a class="btn-link -underline" href="https://our.umbraco.com/documentation/Getting-Started/Backoffice/Sections/" target="_blank">in the Documentation section</a> of Our Umbraco</li>
|
||||
<li>Ask a question in the <a class="btn-link -underline" href="https://our.umbraco.com/forum" target="_blank">Community Forum</a></li>
|
||||
<li>Watch our <a class="btn-link -underline" href="https://umbraco.tv" target="_blank">tutorial videos</a> (some are free, some require a subscription)</li>
|
||||
<li>Find out about our <a class="btn-link -underline" href="https://umbraco.com/products/" target="_blank">productivity boosting tools and commercial support</a></li>
|
||||
<li>Find out about real-life <a class="btn-link -underline" href="https://umbraco.com/training/" target="_blank">training and certification</a> opportunities</li>
|
||||
<li>
|
||||
<localize key="settingsDashboard_bulletPointOne">Read more about working with the items in Settings <a class="btn-link -underline" href="https://our.umbraco.com/documentation/Getting-Started/Backoffice/Sections/" target="_blank">in the Documentation section</a> of Our Umbraco</localize>
|
||||
</li>
|
||||
<li>
|
||||
<localize key="settingsDashboard_bulletPointTwo">Ask a question in the <a class="btn-link -underline" href="https://our.umbraco.com/forum" target="_blank">Community Forum</a></localize>
|
||||
</li>
|
||||
<li>
|
||||
<localize key="settingsDashboard_bulletPointThree">Watch our <a class="btn-link -underline" href="https://umbraco.tv" target="_blank">tutorial videos</a> (some are free, some require a subscription)</localize>
|
||||
</li>
|
||||
<li>
|
||||
<localize key="settingsDashboard_bulletPointFour">Find out about our <a class="btn-link -underline" href="https://umbraco.com/products/" target="_blank">productivity boosting tools and commercial support</a></localize>
|
||||
</li>
|
||||
<li>
|
||||
<localize key="settingsDashboard_bulletPointFive">Find out about real-life <a class="btn-link -underline" href="https://umbraco.com/training/" target="_blank">training and certification</a> opportunities</localize>
|
||||
</li>
|
||||
</ul>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
<h3>Hours of Umbraco training videos are only a click away</h3>
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
|
||||
<h3>
|
||||
<localize key="settingsDashboardVideos_trainingHeadline">Hours of Umbraco training videos are only a click away</localize>
|
||||
</h3>
|
||||
<localize key="settingsDashboardVideos_trainingDescription">
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
|
||||
</localize>
|
||||
|
||||
<div class="row-fluid"
|
||||
ng-init="init('https://umbraco.tv/videos/implementor/chapterrss?sort=no')"
|
||||
ng-controller="Umbraco.Dashboard.StartupVideosController">
|
||||
|
||||
<div ng-show="videos.length">
|
||||
<h4>To get you started:</h4>
|
||||
<h4>
|
||||
<localize key="settingsDashboardVideos_getStarted">To get you started</localize>:
|
||||
</h4>
|
||||
<ul class="thumbnails" >
|
||||
<li class="span2" ng-repeat="video in videos">
|
||||
<div class="thumbnail" style="margin-right: 20px">
|
||||
|
||||
@@ -51,6 +51,12 @@ function DataTypeDeleteController($scope, dataTypeResource, treeService, navigat
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
|
||||
vm.onReferenceClicked = function(event) {
|
||||
if (event.metaKey !== true) {
|
||||
navigationService.hideDialog();
|
||||
}
|
||||
};
|
||||
|
||||
vm.labels = {};
|
||||
localizationService
|
||||
.localize("editdatatype_acceptDeleteConsequence", [$scope.currentNode.name])
|
||||
|
||||
@@ -24,10 +24,6 @@ function DataTypeEditController($scope, $routeParams, appState, navigationServic
|
||||
alias: "selectedEditor",
|
||||
description: "Select a property editor",
|
||||
label: "Property editor"
|
||||
},
|
||||
selectedEditorId: {
|
||||
alias: "selectedEditorId",
|
||||
label: "Property editor alias"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -205,7 +201,7 @@ function DataTypeEditController($scope, $routeParams, appState, navigationServic
|
||||
|
||||
var labelKeys = [
|
||||
"general_settings",
|
||||
"references_tabName"
|
||||
"general_info"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
@@ -220,9 +216,9 @@ function DataTypeEditController($scope, $routeParams, appState, navigationServic
|
||||
},
|
||||
{
|
||||
"name": values[1],
|
||||
"alias": "references",
|
||||
"icon": "icon-molecular-network",
|
||||
"view": "views/datatypes/views/datatype.references.html"
|
||||
"alias": "info",
|
||||
"icon": "icon-info",
|
||||
"view": "views/datatypes/views/datatype.info.html"
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DataType.DeleteController as vm">
|
||||
<div class="umb-dialog umb-pane umb-dialog-datatype-delete" ng-controller="Umbraco.Editors.DataType.DeleteController as vm">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<ng-switch on="currentNode.nodeType">
|
||||
@@ -44,14 +44,14 @@
|
||||
<table class="table table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><localize key="general_name">Name</localize></th>
|
||||
<th class="umb-dialog-datatype-delete__table-head-column-name"><localize key="general_name">Name</localize></th>
|
||||
<th><localize key="general_properties">Properties</localize></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="relation in vm.references.documentTypes">
|
||||
<td><span title="{{::relation.name}}({{::relation.alias}})"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</span></td>
|
||||
<td><span><span class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}{{$last ? '' : ', '}}</span></span></td>
|
||||
<td><a title="{{::relation.name}}({{::relation.alias}})" href="#/settings/documentTypes/edit/{{::relation.id}}" ng-click="vm.onReferenceClicked($event)"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</a></td>
|
||||
<td><div><p class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}</p></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -68,14 +68,14 @@
|
||||
<table class="table table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><localize key="general_name">Name</localize></th>
|
||||
<th class="umb-dialog-datatype-delete__table-head-column-name"><localize key="general_name">Name</localize></th>
|
||||
<th><localize key="general_properties">Properties</localize></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="relation in vm.references.mediaTypes">
|
||||
<td><span title="{{::relation.name}}({{::relation.alias}})"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</span></td>
|
||||
<td><span><span class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}{{$last ? '' : ', '}}</span></span></td>
|
||||
<td><a title="{{::relation.name}}({{::relation.alias}})" href="#/settings/documentTypes/edit/{{::relation.id}}" ng-click="vm.onReferenceClicked($event)"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</a></td>
|
||||
<td><div><p class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}</p></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -92,14 +92,14 @@
|
||||
<table class="table table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><localize key="general_name">Name</localize></th>
|
||||
<th class="umb-dialog-datatype-delete__table-head-column-name"><localize key="general_name">Name</localize></th>
|
||||
<th><localize key="general_properties">Properties</localize></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="relation in vm.references.memberTypes">
|
||||
<td><span title="{{::relation.name}}({{::relation.alias}})"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</span></td>
|
||||
<td><span><span class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}{{$last ? '' : ', '}}</span></span></td>
|
||||
<td><a title="{{::relation.name}}({{::relation.alias}})" href="#/settings/documentTypes/edit/{{::relation.id}}" ng-click="vm.onReferenceClicked($event)"><i class="umb-table-body__icon {{relation.icon}}"></i>{{::relation.name}}</a></td>
|
||||
<td><div><p class="red" ng-repeat="property in relation.properties"><i class="icon icon-alert red"></i>{{::property.name}}</p></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.DataType.ReferencesController
|
||||
* @name Umbraco.Editors.DataType.InfoController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the references view of the datatype editor
|
||||
* The controller for the info view of the datatype editor
|
||||
*/
|
||||
function DataTypeReferencesController($scope, $routeParams, dataTypeResource, eventsService, $timeout) {
|
||||
function DataTypeInfoController($scope, $routeParams, dataTypeResource, eventsService, $timeout) {
|
||||
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
@@ -34,7 +34,7 @@ function DataTypeReferencesController($scope, $routeParams, dataTypeResource, ev
|
||||
// load data type references when the references tab is activated
|
||||
evts.push(eventsService.on("app.tabChange", function (event, args) {
|
||||
$timeout(function () {
|
||||
if (args.alias === "references") {
|
||||
if (args.alias === "info") {
|
||||
loadRelations();
|
||||
}
|
||||
});
|
||||
@@ -52,4 +52,4 @@ function DataTypeReferencesController($scope, $routeParams, dataTypeResource, ev
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DataType.ReferencesController", DataTypeReferencesController);
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DataType.InfoController", DataTypeInfoController);
|
||||
@@ -0,0 +1,140 @@
|
||||
<div ng-controller="Umbraco.Editors.DataType.InfoController as vm">
|
||||
|
||||
<div class="umb-package-details">
|
||||
<div class="umb-package-details__main-content">
|
||||
|
||||
|
||||
<umb-load-indicator ng-if="vm.view.loading === true"></umb-load-indicator>
|
||||
|
||||
|
||||
<umb-box ng-if="vm.view.loading === false && vm.hasReferences === false">
|
||||
<umb-box-header title-key="references_tabName"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-empty-state size="small">
|
||||
<localize key="references_DataTypeNoReferences">This Data Type has no references.</localize>
|
||||
</umb-empty-state>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
|
||||
<div ng-if="vm.view.loading === false && vm.hasReferences === true">
|
||||
|
||||
<!-- Document Types -->
|
||||
|
||||
<div ng-if="vm.references.documentTypes.length > 0" class="mb4">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByDocumentTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.documentTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/documentTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Media Types -->
|
||||
<div ng-if="vm.references.mediaTypes.length > 0" class="mb4">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMediaTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.mediaTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/mediaTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Member Types -->
|
||||
<div ng-if="vm.references.memberTypes.length > 0" class="mb4">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMemberTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.memberTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/memberTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-package-details__sidebar">
|
||||
<umb-box data-element="node-info-general">
|
||||
<umb-box-header title-key="general_general"></umb-box-header>
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-control-group label="Id" ng-if="model.showIdentifier">
|
||||
<div>{{model.content.id}}</div>
|
||||
<small>{{model.content.key}}</small>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Property Editor Alias" ng-if="model.content.selectedEditor">
|
||||
<div>{{model.content.selectedEditor}}</div>
|
||||
</umb-control-group>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -1,112 +0,0 @@
|
||||
<div ng-controller="Umbraco.Editors.DataType.ReferencesController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.view.loading === true"></umb-load-indicator>
|
||||
|
||||
<umb-box ng-if="vm.view.loading === false && vm.hasReferences === false">
|
||||
<umb-box-header title-key="references_tabName"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-empty-state size="small">
|
||||
<localize key="references_DataTypeNoReferences">This Data Type has no references.</localize>
|
||||
</umb-empty-state>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
|
||||
<div ng-if="vm.view.loading === false && vm.hasReferences === true">
|
||||
|
||||
<!-- Document Types -->
|
||||
|
||||
<div ng-if="vm.references.documentTypes.length > 0">
|
||||
|
||||
<h5 class="mt4" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByDocumentTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.documentTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/documentTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Media Types -->
|
||||
<div ng-if="vm.references.mediaTypes.length > 0">
|
||||
|
||||
<h5 class="mt4" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMediaTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.mediaTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/documentTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Member Types -->
|
||||
<div ng-if="vm.references.memberTypes.length > 0">
|
||||
|
||||
<h5 class="mt4" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMemberTypes"></localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell"><localize key="references_usedByProperties">Used in</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in vm.references.memberTypes">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell --noOverflow"><span>{{::reference.properties | umbCmsJoinArray:', ':'name'}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/settings/documentTypes/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -2,11 +2,6 @@
|
||||
|
||||
<umb-box-content>
|
||||
|
||||
<umb-control-group label="Id" ng-if="model.showIdentifier">
|
||||
<div>{{model.content.id}}</div>
|
||||
<small>{{model.content.key}}</small>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-property property="model.properties.selectedEditor">
|
||||
<div>
|
||||
<select name="selectedEditor"
|
||||
@@ -20,10 +15,6 @@
|
||||
|
||||
</umb-property>
|
||||
|
||||
<umb-property property="model.properties.selectedEditorId">
|
||||
<div>{{model.content.selectedEditor}}</div>
|
||||
</umb-property>
|
||||
|
||||
<umb-property property="preValue"
|
||||
ng-repeat="preValue in model.preValues">
|
||||
<umb-property-editor model="preValue" is-pre-value="true"></umb-property-editor>
|
||||
@@ -31,4 +22,4 @@
|
||||
|
||||
</umb-box-content>
|
||||
|
||||
</umb-box>
|
||||
</umb-box>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
<input type="text" name="folderName" ng-model="model.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
|
||||
<input type="text" name="folderName" maxlength="255" ng-model="model.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
|
||||
</umb-control-group>
|
||||
|
||||
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
<umb-control-group>
|
||||
<label for="collectionName" class="control-label">Name of the Parent Document Type</label>
|
||||
<input type="text" name="collectionName" id="collectionName" ng-model="model.collectionName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
|
||||
<input type="text" name="collectionName" id="collectionName" ng-model="model.collectionName" maxlength="255" class="umb-textstring textstring input-block-level" umb-auto-focus required />
|
||||
|
||||
<umb-checkbox ng-if="model.disableTemplates === false"
|
||||
name="collectionCreateTemplate"
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
<umb-control-group>
|
||||
<label for="collectionItemName" class="control-label">Name of the Item Document Type</label>
|
||||
<input type="text" name="collectionItemName" id="collectionItemName" ng-model="model.collectionItemName" class="umb-textstring textstring input-block-level" required />
|
||||
<input type="text" name="collectionItemName" id="collectionItemName" ng-model="model.collectionItemName" maxlength="255" class="umb-textstring textstring input-block-level" required />
|
||||
|
||||
<umb-checkbox ng-if="model.disableTemplates === false"
|
||||
name="collectionItemCreateTemplate"
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
var documentTypeId = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
var noTemplate = $routeParams.notemplate;
|
||||
var isElement = $routeParams.iselement;
|
||||
var allowVaryByCulture = $routeParams.culturevary;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
vm.save = save;
|
||||
@@ -63,6 +65,8 @@
|
||||
documentTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
noTemplate = $scope.model.notemplate;
|
||||
isElement = $scope.model.isElement;
|
||||
allowVaryByCulture = $scope.model.allowVaryByCulture;
|
||||
vm.submitButtonKey = "buttons_saveAndClose";
|
||||
vm.generateModelsKey = "buttons_generateModelsAndClose";
|
||||
}
|
||||
@@ -430,7 +434,14 @@
|
||||
contentType.defaultTemplate = contentTypeHelper.insertDefaultTemplatePlaceholder(contentType.defaultTemplate);
|
||||
contentType.allowedTemplates = contentTypeHelper.insertTemplatePlaceholder(contentType.allowedTemplates);
|
||||
}
|
||||
|
||||
// set isElement checkbox by default
|
||||
if (isElement) {
|
||||
contentType.isElement = true;
|
||||
}
|
||||
// set vary by culture checkbox by default
|
||||
if (allowVaryByCulture) {
|
||||
contentType.allowCultureVariant = true;
|
||||
}
|
||||
// convert icons for content type
|
||||
convertLegacyIcons(contentType);
|
||||
|
||||
@@ -508,11 +519,16 @@
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("editors.documentType.saved", function(name, args) {
|
||||
if(args.documentType.allowedTemplates.length > 0){
|
||||
navigationService.syncTree({ tree: "templates", path: [], forceReload: true })
|
||||
.then(function (syncArgs) {
|
||||
navigationService.reloadNode(syncArgs.node)
|
||||
});
|
||||
if(args.documentType.allowedTemplates.length > 0) {
|
||||
navigationService.hasTree("templates").then(function (treeExists) {
|
||||
if (treeExists) {
|
||||
navigationService.syncTree({ tree: "templates", path: [], forceReload: true })
|
||||
.then(function (syncArgs) {
|
||||
navigationService.reloadNode(syncArgs.node)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="language.fallbackLanguageId">{{vm.getLanguageById(language.fallbackLanguageId).name}}</span>
|
||||
<span ng-if="!language.fallbackLanguageId">(none)</span>
|
||||
<span ng-if="!language.fallbackLanguageId">
|
||||
(<localize key="languages_none">none</localize>)
|
||||
</span>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<umb-button ng-if="!language.isDefault"
|
||||
|
||||
@@ -20,16 +20,16 @@
|
||||
|
||||
<div class="umb-sortable-thumbnails__actions" data-element="sortable-thumbnail-actions">
|
||||
|
||||
<a role="button" aria-label="Remove" class="umb-sortable-thumbnails__action -red" data-element="action-remove" ng-click="remove()">
|
||||
<i class="icon icon-delete"></i>
|
||||
</a>
|
||||
<button aria-label="Remove" class="umb-sortable-thumbnails__action -red btn-reset" data-element="action-remove" ng-click="remove()">
|
||||
<i class="icon icon-delete" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li style="border: none;" class="add-wrapper unsortable" ng-hide="model.value">
|
||||
<a role="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link add-link-square" ng-click="add()" prevent-default>
|
||||
<i class="icon icon-add large"></i>
|
||||
</a>
|
||||
<button aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link add-link-square btn-reset" ng-click="add()" prevent-default>
|
||||
<i class="icon icon-add large" aria-hidden="true"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@ function ColorPickerController($scope, $timeout) {
|
||||
);
|
||||
return {
|
||||
isValid: isValid,
|
||||
errorMsg: "Value cannot be empty",
|
||||
errorMsg: $scope.model.validation.mandatoryMessage || "Value cannot be empty",
|
||||
errorKey: "required"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element, dateHelper) {
|
||||
function dateTimePickerController($scope, angularHelper, dateHelper, validationMessageService) {
|
||||
|
||||
let flatPickr = null;
|
||||
|
||||
@@ -62,6 +62,11 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
|
||||
|
||||
setDatePickerVal();
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.clearDate = function() {
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
|
||||
</div>
|
||||
|
||||
<span ng-messages="datePickerForm.datepicker.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valServer">{{datePickerForm.datepicker.errorMsg}}</span>
|
||||
<span class="help-inline" ng-message="pickerError"><localize key="validation_invalidDate">Invalid date</localize></span>
|
||||
</span>
|
||||
<div ng-messages="datePickerForm.datepicker.$error" show-validation-on-submit >
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
<p class="help-inline" ng-message="valServer">{{datePickerForm.datepicker.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="pickerError"><localize key="validation_invalidDate">Invalid date</localize></p>
|
||||
</div>
|
||||
|
||||
<p ng-if="model.config.offsetTime === '1' && serverTimeNeedsOffsetting && model.value" class="muted">
|
||||
<small><localize key="content_scheduledPublishServerTime">This translates to the following time on the server:</localize> {{serverTime}}</small><br />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleController",
|
||||
function($scope) {
|
||||
function ($scope, validationMessageService) {
|
||||
|
||||
//setup the default config
|
||||
var config = {
|
||||
@@ -89,4 +89,10 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo
|
||||
$scope.model.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.DropdownFlexibleController" ng-switch="model.config.multiple">
|
||||
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-default
|
||||
ng-change="updateSingleDropdownValue()"
|
||||
ng-model="model.singleDropdownValue"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory">
|
||||
<option></option>
|
||||
</select>
|
||||
<ng-form name="dropDownListForm">
|
||||
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-default
|
||||
ng-change="updateSingleDropdownValue()"
|
||||
ng-model="model.singleDropdownValue"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory">
|
||||
<option></option>
|
||||
</select>
|
||||
|
||||
<!--NOTE: This ng-switch is required because ng-multiple doesn't actually support dynamic bindings with multi-select lists -->
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-when="true"
|
||||
multiple
|
||||
ng-model="model.value"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory"></select>
|
||||
<!--NOTE: This ng-switch is required because ng-multiple doesn't actually support dynamic bindings with multi-select lists -->
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-when="true"
|
||||
multiple
|
||||
ng-model="model.value"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory"></select>
|
||||
|
||||
<div ng-messages="dropDownListForm.dropDownList.$error" show-validation-on-submit>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
function emailController($scope, validationMessageService) {
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function(value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.EmailController", emailController);
|
||||
@@ -1,4 +1,4 @@
|
||||
<div>
|
||||
<div ng-controller="Umbraco.PropertyEditors.EmailController">
|
||||
<ng-form name="emailFieldForm">
|
||||
<input type="email" name="textbox"
|
||||
ng-model="model.value"
|
||||
@@ -8,10 +8,10 @@
|
||||
ng-required="model.config.IsRequired || model.validation.mandatory"
|
||||
val-server="value" />
|
||||
|
||||
<span ng-messages="emailFieldForm.textbox.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></span>
|
||||
<span class="help-inline" ng-message="valServer">{{emailFieldForm.textbox.errorMsg}}</span>
|
||||
</span>
|
||||
<div ng-messages="emailFieldForm.textbox.$error" show-validation-on-submit >
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
<p class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></p>
|
||||
<p class="help-inline" ng-message="valServer">{{emailFieldForm.textbox.errorMsg}}</p>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,10 @@ angular.module("umbraco")
|
||||
ui.item.find(".umb-rte").each(function (key, value) {
|
||||
// remove all RTEs in the dragged row and save their settings
|
||||
var rteId = value.id;
|
||||
draggedRteSettings[rteId] = _.findWhere(tinyMCE.editors, { id: rteId }).settings;
|
||||
var editor = _.findWhere(tinyMCE.editors, { id: rteId });
|
||||
if (editor) {
|
||||
draggedRteSettings[rteId] = editor.settings;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -85,9 +88,17 @@ angular.module("umbraco")
|
||||
// reset all RTEs affected by the dragging
|
||||
ui.item.parents(".umb-column").find(".umb-rte").each(function (key, value) {
|
||||
var rteId = value.id;
|
||||
draggedRteSettings[rteId] = draggedRteSettings[rteId] || _.findWhere(tinyMCE.editors, { id: rteId }).settings;
|
||||
tinyMCE.execCommand("mceRemoveEditor", false, rteId);
|
||||
tinyMCE.init(draggedRteSettings[rteId]);
|
||||
var settings = draggedRteSettings[rteId];
|
||||
if (!settings) {
|
||||
var editor = _.findWhere(tinyMCE.editors, { id: rteId });
|
||||
if (editor) {
|
||||
settings = editor.settings;
|
||||
}
|
||||
}
|
||||
if (settings) {
|
||||
tinyMCE.execCommand("mceRemoveEditor", false, rteId);
|
||||
tinyMCE.init(settings);
|
||||
}
|
||||
});
|
||||
currentForm.$setDirty();
|
||||
}
|
||||
@@ -662,6 +673,7 @@ angular.module("umbraco")
|
||||
return ((spans / $scope.model.config.items.columns) * 100).toFixed(8);
|
||||
};
|
||||
|
||||
|
||||
$scope.clearPrompt = function (scopedObject, e) {
|
||||
scopedObject.deletePrompt = false;
|
||||
e.preventDefault();
|
||||
@@ -681,8 +693,15 @@ angular.module("umbraco")
|
||||
};
|
||||
|
||||
$scope.getTemplateName = function (control) {
|
||||
if (control.editor.nameExp) return control.editor.nameExp(control)
|
||||
return control.editor.name;
|
||||
var templateName = control.editor.name;
|
||||
if (control.editor.nameExp) {
|
||||
var valueOfTemplate = control.editor.nameExp(control);
|
||||
if (valueOfTemplate != "") {
|
||||
templateName += ": ";
|
||||
templateName += valueOfTemplate;
|
||||
}
|
||||
}
|
||||
return templateName;
|
||||
}
|
||||
|
||||
// *********************************************
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
</div>
|
||||
|
||||
<div class="cell-tools-remove row-tool">
|
||||
<i class="icon-trash" ng-click="togglePrompt(row)"></i>
|
||||
<i class="icon-trash" ng-click="togglePrompt(row)" localize="title" title="@delete"></i>
|
||||
<umb-confirm-action
|
||||
ng-if="row.deletePrompt"
|
||||
direction="left"
|
||||
@@ -200,7 +200,7 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-control-tool">
|
||||
<i class="umb-control-tool-icon icon-trash" ng-click="togglePrompt(control)"></i>
|
||||
<i class="umb-control-tool-icon icon-trash" ng-click="togglePrompt(control)" localize="title" title="@delete"></i>
|
||||
<umb-confirm-action ng-if="control.deletePrompt"
|
||||
direction="left"
|
||||
on-confirm="removeControl(area, $index)"
|
||||
|
||||
@@ -36,18 +36,18 @@
|
||||
</umb-file-icon>
|
||||
|
||||
<div class="umb-sortable-thumbnails__actions" data-element="sortable-thumbnail-actions">
|
||||
<a role="button" aria-label="Edit media" ng-if="allowEditMedia" class="umb-sortable-thumbnails__action" data-element="action-edit" ng-click="vm.editItem(media)">
|
||||
<i class="icon icon-edit"></i>
|
||||
</a>
|
||||
<a role="button" aria-label="Remove" class="umb-sortable-thumbnails__action -red" data-element="action-remove" ng-click="vm.remove($index)">
|
||||
<i class="icon icon-delete"></i>
|
||||
</a>
|
||||
<button aria-label="Edit media" ng-if="allowEditMedia" class="umb-sortable-thumbnails__action btn-reset" data-element="action-edit" ng-click="vm.editItem(media)">
|
||||
<i class="icon icon-edit" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button aria-label="Remove" class="umb-sortable-thumbnails__action -red btn-reset" data-element="action-remove" ng-click="vm.remove($index)">
|
||||
<i class="icon icon-delete" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li style="border: none;" class="add-wrapper unsortable" ng-if="vm.showAdd() && allowAddMedia">
|
||||
<a role="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link" ng-click="vm.add()" ng-class="{'add-link-square': (mediaItems.length === 0 || isMultiPicker)}" prevent-default>
|
||||
<i class="icon icon-add large"></i>
|
||||
</a>
|
||||
<button aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link btn-reset" ng-click="vm.add()" ng-class="{'add-link-square': (mediaItems.length === 0 || isMultiPicker)}" prevent-default>
|
||||
<i class="icon icon-add large" aria-hidden="true"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,323 +1,246 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.DocTypePickerController", [
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
"$scope",
|
||||
"Umbraco.PropertyEditors.NestedContent.Resources",
|
||||
"overlayService",
|
||||
"localizationService",
|
||||
"iconHelper",
|
||||
|
||||
function ($scope, ncResources, overlayService, localizationService, iconHelper) {
|
||||
var selectElementTypeModalTitle = "";
|
||||
|
||||
$scope.elemTypeTabs = [];
|
||||
|
||||
|
||||
init();
|
||||
|
||||
|
||||
function init() {
|
||||
localizationService.localize("content_nestedContentSelectElementTypeModalTitle").then(function (value) {
|
||||
selectElementTypeModalTitle = value;
|
||||
});
|
||||
|
||||
ncResources.getContentTypes().then(function (elemTypes) {
|
||||
$scope.model.elemTypes = elemTypes;
|
||||
|
||||
// convert legacy icons
|
||||
iconHelper.formatContentTypeIcons($scope.model.elemTypes);
|
||||
|
||||
// Count doctype name occurrences
|
||||
var elTypeNameOccurrences= _.countBy(elemTypes, 'name');
|
||||
|
||||
// Populate document type tab dictionary
|
||||
// And append alias to name if multiple doctypes have the same name
|
||||
elemTypes.forEach(function (value) {
|
||||
$scope.elemTypeTabs[value.alias] = value.tabs;
|
||||
|
||||
if (elTypeNameOccurrences[value.name] > 1) {
|
||||
value.name += " (" + value.alias + ")";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
$scope.add = function () {
|
||||
$scope.model.value.push({
|
||||
// As per PR #4, all stored content type aliases must be prefixed "nc" for easier recognition.
|
||||
// For good measure we'll also prefix the tab alias "nc"
|
||||
ncAlias: "",
|
||||
ncTabAlias: "",
|
||||
nameTemplate: ""
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.docTypes || !$scope.model.value || $scope.model.value.length < $scope.model.docTypes.length;
|
||||
}
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.model.value.splice(index, 1);
|
||||
}
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
cursor: "move",
|
||||
handle: ".handle",
|
||||
placeholder: 'sortable-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
helper: function (e, ui) {
|
||||
// When sorting table rows, the cells collapse. This helper fixes that: https://www.foliotek.com/devblog/make-table-rows-sortable-using-jquery-ui-sortable/
|
||||
ui.children().each(function () {
|
||||
$(this).width($(this).width());
|
||||
});
|
||||
return ui;
|
||||
},
|
||||
start: function (e, ui) {
|
||||
|
||||
var cellHeight = ui.item.height();
|
||||
|
||||
// Build a placeholder cell that spans all the cells in the row: https://stackoverflow.com/questions/25845310/jquery-ui-sortable-and-table-cell-size
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function () {
|
||||
// For each td or th try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1) {
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so td rather than tr - and set height of tr
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"></td>').height(cellHeight);
|
||||
angular
|
||||
.module('umbraco')
|
||||
.component('nestedContentPropertyEditor', {
|
||||
templateUrl: 'views/propertyeditors/nestedcontent/nestedcontent.propertyeditor.html',
|
||||
controller: NestedContentController,
|
||||
controllerAs: 'vm',
|
||||
require: {
|
||||
umbProperty: '?^umbProperty',
|
||||
umbVariantContent: '?^^umbVariantContent'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
$scope.placeholder = function (config) {
|
||||
return _.find($scope.model.elemTypes, function (elType) {
|
||||
return elType.alias === config.ncAlias;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.selectableElemTypesFor = function (config) {
|
||||
// return all elemTypes that are:
|
||||
// 1. either already selected for this config, or
|
||||
// 2. not selected in any other config
|
||||
return _.filter($scope.model.elemTypes, function (elType) {
|
||||
return elType.alias === config.ncAlias || !_.find($scope.model.value, function (c) {
|
||||
return elType.alias === c.ncAlias;
|
||||
});
|
||||
});
|
||||
}
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.value || _.some($scope.model.elemTypes, function (elType) {
|
||||
return !_.find($scope.model.value, function (c) {
|
||||
return elType.alias === c.ncAlias;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$scope.openElemTypeModal = function ($event, config) {
|
||||
|
||||
//we have to add the alias to the objects (they are stored as ncAlias)
|
||||
var selectedItems = _.each($scope.model.value, function (obj) {
|
||||
obj.alias = obj.ncAlias;
|
||||
return obj;
|
||||
})
|
||||
|
||||
var elemTypeSelectorOverlay = {
|
||||
view: "itempicker",
|
||||
title: selectElementTypeModalTitle,
|
||||
availableItems: $scope.selectableElemTypesFor(config),
|
||||
selectedItems: selectedItems,
|
||||
position: "target",
|
||||
event: $event,
|
||||
submit: function (model) {
|
||||
config.ncAlias = model.selectedItem.alias;
|
||||
overlayService.close();
|
||||
},
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
|
||||
overlayService.open(elemTypeSelectorOverlay);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!$scope.model.value) {
|
||||
$scope.model.value = [];
|
||||
$scope.add();
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.PropertyEditorController", [
|
||||
|
||||
"$scope",
|
||||
"$interpolate",
|
||||
"$filter",
|
||||
"$timeout",
|
||||
"contentResource",
|
||||
"localizationService",
|
||||
"iconHelper",
|
||||
"clipboardService",
|
||||
"eventsService",
|
||||
"overlayService",
|
||||
|
||||
function ($scope, $interpolate, $filter, $timeout, contentResource, localizationService, iconHelper, clipboardService, eventsService, overlayService, $routeParams, editorState) {
|
||||
function NestedContentController($scope, $interpolate, $filter, $timeout, contentResource, localizationService, iconHelper, clipboardService, eventsService, overlayService, $routeParams, editorState) {
|
||||
|
||||
var vm = this;
|
||||
var model = $scope.$parent.$parent.model;
|
||||
|
||||
var contentTypeAliases = [];
|
||||
_.each($scope.model.config.contentTypes, function (contentType) {
|
||||
_.each(model.config.contentTypes, function (contentType) {
|
||||
contentTypeAliases.push(contentType.ncAlias);
|
||||
});
|
||||
|
||||
_.each($scope.model.config.contentTypes, function (contentType) {
|
||||
_.each(model.config.contentTypes, function (contentType) {
|
||||
contentType.nameExp = !!contentType.nameTemplate
|
||||
? $interpolate(contentType.nameTemplate)
|
||||
: undefined;
|
||||
});
|
||||
|
||||
$scope.nodes = [];
|
||||
$scope.currentNode = undefined;
|
||||
$scope.realCurrentNode = undefined;
|
||||
$scope.scaffolds = undefined;
|
||||
$scope.sorting = false;
|
||||
$scope.inited = false;
|
||||
vm.nodes = [];
|
||||
vm.currentNode = null;
|
||||
vm.scaffolds = null;
|
||||
vm.sorting = false;
|
||||
vm.inited = false;
|
||||
|
||||
$scope.minItems = $scope.model.config.minItems || 0;
|
||||
$scope.maxItems = $scope.model.config.maxItems || 0;
|
||||
vm.minItems = model.config.minItems || 0;
|
||||
vm.maxItems = model.config.maxItems || 0;
|
||||
|
||||
if ($scope.maxItems === 0)
|
||||
$scope.maxItems = 1000;
|
||||
if (vm.maxItems === 0)
|
||||
vm.maxItems = 1000;
|
||||
|
||||
$scope.singleMode = $scope.minItems === 1 && $scope.maxItems === 1;
|
||||
$scope.showIcons = Object.toBoolean($scope.model.config.showIcons);
|
||||
$scope.wideMode = Object.toBoolean($scope.model.config.hideLabel);
|
||||
$scope.hasContentTypes = $scope.model.config.contentTypes.length > 0;
|
||||
vm.singleMode = vm.minItems === 1 && vm.maxItems === 1;
|
||||
vm.showIcons = Object.toBoolean(model.config.showIcons);
|
||||
vm.wideMode = Object.toBoolean(model.config.hideLabel);
|
||||
vm.hasContentTypes = model.config.contentTypes.length > 0;
|
||||
|
||||
$scope.labels = {};
|
||||
localizationService.localizeMany(["grid_addElement", "content_createEmpty"]).then(function (data) {
|
||||
$scope.labels.grid_addElement = data[0];
|
||||
$scope.labels.content_createEmpty = data[1];
|
||||
var labels = {};
|
||||
vm.labels = labels;
|
||||
localizationService.localizeMany(["grid_addElement", "content_createEmpty", "actions_copy"]).then(function (data) {
|
||||
labels.grid_addElement = data[0];
|
||||
labels.content_createEmpty = data[1];
|
||||
labels.copy_icon_title = data[2]
|
||||
});
|
||||
|
||||
function setCurrentNode(node) {
|
||||
vm.currentNode = node;
|
||||
updateModel();
|
||||
}
|
||||
|
||||
var copyAllEntries = function() {
|
||||
|
||||
syncCurrentNode();
|
||||
|
||||
// list aliases
|
||||
var aliases = vm.nodes.map((node) => node.contentTypeAlias);
|
||||
|
||||
// remove dublicates
|
||||
aliases = aliases.filter((item, index) => aliases.indexOf(item) === index);
|
||||
|
||||
var nodeName = "";
|
||||
|
||||
if(vm.umbVariantContent) {
|
||||
nodeName = vm.umbVariantContent.editor.content.name;
|
||||
}
|
||||
|
||||
localizationService.localize("clipboard_labelForArrayOfItemsFrom", [model.label, nodeName]).then(function(data) {
|
||||
clipboardService.copyArray("elementTypeArray", aliases, vm.nodes, data, "icon-thumbnail-list", model.id);
|
||||
});
|
||||
}
|
||||
|
||||
var copyAllEntriesAction = {
|
||||
labelKey: 'clipboard_labelForCopyAllEntries',
|
||||
labelTokens: [model.label],
|
||||
icon: 'documents',
|
||||
method: copyAllEntries,
|
||||
isDisabled: true
|
||||
}
|
||||
|
||||
|
||||
var removeAllEntries = function () {
|
||||
localizationService.localizeMany(["content_nestedContentDeleteAllItems", "general_delete"]).then(function (data) {
|
||||
overlayService.confirmDelete({
|
||||
title: data[1],
|
||||
content: data[0],
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
},
|
||||
submit: function () {
|
||||
vm.nodes = [];
|
||||
setDirty();
|
||||
updateModel();
|
||||
overlayService.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var removeAllEntriesAction = {
|
||||
labelKey: 'clipboard_labelForRemoveAllEntries',
|
||||
labelTokens: [],
|
||||
icon: 'trash',
|
||||
method: removeAllEntries,
|
||||
isDisabled: true
|
||||
}
|
||||
|
||||
|
||||
|
||||
// helper to force the current form into the dirty state
|
||||
$scope.setDirty = function () {
|
||||
if ($scope.propertyForm) {
|
||||
$scope.propertyForm.$setDirty();
|
||||
function setDirty() {
|
||||
if ($scope.$parent.$parent.propertyForm) {
|
||||
$scope.$parent.$parent.propertyForm.$setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addNode = function (alias) {
|
||||
var scaffold = $scope.getScaffold(alias);
|
||||
function addNode(alias) {
|
||||
var scaffold = getScaffold(alias);
|
||||
|
||||
var newNode = createNode(scaffold, null);
|
||||
|
||||
$scope.currentNode = newNode;
|
||||
$scope.setDirty();
|
||||
setCurrentNode(newNode);
|
||||
setDirty();
|
||||
};
|
||||
|
||||
$scope.openNodeTypePicker = function ($event) {
|
||||
if ($scope.nodes.length >= $scope.maxItems) {
|
||||
vm.openNodeTypePicker = function ($event) {
|
||||
if (vm.nodes.length >= vm.maxItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.overlayMenu = {
|
||||
vm.overlayMenu = {
|
||||
show: false,
|
||||
style: {},
|
||||
filter: $scope.scaffolds.length > 12 ? true : false,
|
||||
filter: vm.scaffolds.length > 12 ? true : false,
|
||||
orderBy: "$index",
|
||||
view: "itempicker",
|
||||
event: $event,
|
||||
clickPasteItem: function(item) {
|
||||
$scope.pasteFromClipboard(item.data);
|
||||
$scope.overlayMenu.show = false;
|
||||
$scope.overlayMenu = null;
|
||||
if (item.type === "elementTypeArray") {
|
||||
_.each(item.data, function (entry) {
|
||||
pasteFromClipboard(entry);
|
||||
});
|
||||
} else {
|
||||
pasteFromClipboard(item.data);
|
||||
}
|
||||
vm.overlayMenu.show = false;
|
||||
vm.overlayMenu = null;
|
||||
},
|
||||
submit: function (model) {
|
||||
if (model && model.selectedItem) {
|
||||
$scope.addNode(model.selectedItem.alias);
|
||||
addNode(model.selectedItem.alias);
|
||||
}
|
||||
$scope.overlayMenu.show = false;
|
||||
$scope.overlayMenu = null;
|
||||
vm.overlayMenu.show = false;
|
||||
vm.overlayMenu = null;
|
||||
},
|
||||
close: function () {
|
||||
$scope.overlayMenu.show = false;
|
||||
$scope.overlayMenu = null;
|
||||
vm.overlayMenu.show = false;
|
||||
vm.overlayMenu = null;
|
||||
}
|
||||
};
|
||||
|
||||
// this could be used for future limiting on node types
|
||||
$scope.overlayMenu.availableItems = [];
|
||||
_.each($scope.scaffolds, function (scaffold) {
|
||||
$scope.overlayMenu.availableItems.push({
|
||||
vm.overlayMenu.availableItems = [];
|
||||
_.each(vm.scaffolds, function (scaffold) {
|
||||
vm.overlayMenu.availableItems.push({
|
||||
alias: scaffold.contentTypeAlias,
|
||||
name: scaffold.contentTypeName,
|
||||
icon: iconHelper.convertFromLegacyIcon(scaffold.icon)
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.overlayMenu.availableItems.length === 0) {
|
||||
if (vm.overlayMenu.availableItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.overlayMenu.size = $scope.overlayMenu.availableItems.length > 6 ? "medium" : "small";
|
||||
vm.overlayMenu.size = vm.overlayMenu.availableItems.length > 6 ? "medium" : "small";
|
||||
|
||||
$scope.overlayMenu.pasteItems = [];
|
||||
var availableNodesForPaste = clipboardService.retriveDataOfType("elementType", contentTypeAliases);
|
||||
_.each(availableNodesForPaste, function (node) {
|
||||
$scope.overlayMenu.pasteItems.push({
|
||||
alias: node.contentTypeAlias,
|
||||
name: node.name, //contentTypeName
|
||||
data: node,
|
||||
icon: iconHelper.convertFromLegacyIcon(node.icon)
|
||||
vm.overlayMenu.pasteItems = [];
|
||||
|
||||
var singleEntriesForPaste = clipboardService.retriveEntriesOfType("elementType", contentTypeAliases);
|
||||
_.each(singleEntriesForPaste, function (entry) {
|
||||
vm.overlayMenu.pasteItems.push({
|
||||
type: "elementType",
|
||||
name: entry.label,
|
||||
data: entry.data,
|
||||
icon: entry.icon
|
||||
});
|
||||
});
|
||||
|
||||
var arrayEntriesForPaste = clipboardService.retriveEntriesOfType("elementTypeArray", contentTypeAliases);
|
||||
_.each(arrayEntriesForPaste, function (entry) {
|
||||
vm.overlayMenu.pasteItems.push({
|
||||
type: "elementTypeArray",
|
||||
name: entry.label,
|
||||
data: entry.data,
|
||||
icon: entry.icon
|
||||
});
|
||||
});
|
||||
|
||||
$scope.overlayMenu.title = $scope.overlayMenu.pasteItems.length > 0 ? $scope.labels.grid_addElement : $scope.labels.content_createEmpty;
|
||||
vm.overlayMenu.title = vm.overlayMenu.pasteItems.length > 0 ? labels.grid_addElement : labels.content_createEmpty;
|
||||
|
||||
$scope.overlayMenu.clickClearPaste = function ($event) {
|
||||
vm.overlayMenu.clickClearPaste = function ($event) {
|
||||
$event.stopPropagation();
|
||||
$event.preventDefault();
|
||||
clipboardService.clearEntriesOfType("elementType", contentTypeAliases);
|
||||
$scope.overlayMenu.pasteItems = [];// This dialog is not connected via the clipboardService events, so we need to update manually.
|
||||
clipboardService.clearEntriesOfType("elementTypeArray", contentTypeAliases);
|
||||
vm.overlayMenu.pasteItems = [];// This dialog is not connected via the clipboardService events, so we need to update manually.
|
||||
};
|
||||
|
||||
if ($scope.overlayMenu.availableItems.length === 1 && $scope.overlayMenu.pasteItems.length === 0) {
|
||||
if (vm.overlayMenu.availableItems.length === 1 && vm.overlayMenu.pasteItems.length === 0) {
|
||||
// only one scaffold type - no need to display the picker
|
||||
$scope.addNode($scope.scaffolds[0].contentTypeAlias);
|
||||
addNode(vm.scaffolds[0].contentTypeAlias);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.overlayMenu.show = true;
|
||||
vm.overlayMenu.show = true;
|
||||
};
|
||||
|
||||
$scope.editNode = function (idx) {
|
||||
if ($scope.currentNode && $scope.currentNode.key === $scope.nodes[idx].key) {
|
||||
$scope.currentNode = undefined;
|
||||
vm.editNode = function (idx) {
|
||||
if (vm.currentNode && vm.currentNode.key === vm.nodes[idx].key) {
|
||||
setCurrentNode(null);
|
||||
} else {
|
||||
$scope.currentNode = $scope.nodes[idx];
|
||||
setCurrentNode(vm.nodes[idx]);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteNode = function (idx) {
|
||||
$scope.nodes.splice(idx, 1);
|
||||
$scope.setDirty();
|
||||
function deleteNode(idx) {
|
||||
vm.nodes.splice(idx, 1);
|
||||
setDirty();
|
||||
updateModel();
|
||||
};
|
||||
$scope.requestDeleteNode = function (idx) {
|
||||
if ($scope.nodes.length <= $scope.model.config.minItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.model.config.confirmDeletes === true) {
|
||||
vm.requestDeleteNode = function (idx) {
|
||||
if (model.config.confirmDeletes === true) {
|
||||
localizationService.localizeMany(["content_nestedContentDeleteItem", "general_delete", "general_cancel", "contentTypeEditor_yesDelete"]).then(function (data) {
|
||||
const overlay = {
|
||||
title: data[1],
|
||||
@@ -329,7 +252,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
overlayService.close();
|
||||
},
|
||||
submit: function () {
|
||||
$scope.deleteNode(idx);
|
||||
deleteNode(idx);
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
@@ -337,23 +260,23 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
overlayService.open(overlay);
|
||||
});
|
||||
} else {
|
||||
$scope.deleteNode(idx);
|
||||
deleteNode(idx);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getName = function (idx) {
|
||||
vm.getName = function (idx) {
|
||||
|
||||
var name = "";
|
||||
|
||||
if ($scope.model.value[idx]) {
|
||||
if (model.value[idx]) {
|
||||
|
||||
var contentType = $scope.getContentTypeConfig($scope.model.value[idx].ncContentTypeAlias);
|
||||
var contentType = getContentTypeConfig(model.value[idx].ncContentTypeAlias);
|
||||
|
||||
if (contentType != null) {
|
||||
// first try getting a name using the configured label template
|
||||
if (contentType.nameExp) {
|
||||
// Run the expression against the stored dictionary value, NOT the node object
|
||||
var item = $scope.model.value[idx];
|
||||
var item = model.value[idx];
|
||||
|
||||
// Add a temporary index property
|
||||
item["$index"] = (idx + 1);
|
||||
@@ -368,8 +291,8 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
|
||||
// if we still do not have a name and we have multiple content types to choose from, use the content type name (same as is shown in the content type picker)
|
||||
if (!name && $scope.scaffolds.length > 1) {
|
||||
var scaffold = $scope.getScaffold(contentType.ncAlias);
|
||||
if (!name && vm.scaffolds.length > 1) {
|
||||
var scaffold = getScaffold(contentType.ncAlias);
|
||||
if (scaffold) {
|
||||
name = scaffold.contentTypeName;
|
||||
}
|
||||
@@ -383,18 +306,19 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
|
||||
// Update the nodes actual name value
|
||||
if ($scope.nodes[idx].name !== name) {
|
||||
$scope.nodes[idx].name = name;
|
||||
if (vm.nodes[idx].name !== name) {
|
||||
vm.nodes[idx].name = name;
|
||||
}
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
$scope.getIcon = function (idx) {
|
||||
var scaffold = $scope.getScaffold($scope.model.value[idx].ncContentTypeAlias);
|
||||
vm.getIcon = function (idx) {
|
||||
var scaffold = getScaffold(model.value[idx].ncContentTypeAlias);
|
||||
return scaffold && scaffold.icon ? iconHelper.convertFromLegacyIcon(scaffold.icon) : "icon-folder";
|
||||
}
|
||||
$scope.sortableOptions = {
|
||||
|
||||
vm.sortableOptions = {
|
||||
axis: "y",
|
||||
cursor: "move",
|
||||
handle: '.umb-nested-content__header-bar',
|
||||
@@ -405,46 +329,45 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
start: function (ev, ui) {
|
||||
updateModel();
|
||||
// Yea, yea, we shouldn't modify the dom, sue me
|
||||
$("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
|
||||
$("#umb-nested-content--" + model.id + " .umb-rte textarea").each(function () {
|
||||
tinymce.execCommand("mceRemoveEditor", false, $(this).attr("id"));
|
||||
$(this).css("visibility", "hidden");
|
||||
});
|
||||
$scope.$apply(function () {
|
||||
$scope.sorting = true;
|
||||
vm.sorting = true;
|
||||
});
|
||||
},
|
||||
update: function (ev, ui) {
|
||||
$scope.setDirty();
|
||||
setDirty();
|
||||
},
|
||||
stop: function (ev, ui) {
|
||||
$("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
|
||||
$("#umb-nested-content--" + model.id + " .umb-rte textarea").each(function () {
|
||||
tinymce.execCommand("mceAddEditor", true, $(this).attr("id"));
|
||||
$(this).css("visibility", "visible");
|
||||
});
|
||||
$scope.$apply(function () {
|
||||
$scope.sorting = false;
|
||||
vm.sorting = false;
|
||||
updateModel();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getScaffold = function (alias) {
|
||||
return _.find($scope.scaffolds, function (scaffold) {
|
||||
function getScaffold(alias) {
|
||||
return _.find(vm.scaffolds, function (scaffold) {
|
||||
return scaffold.contentTypeAlias === alias;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.getContentTypeConfig = function (alias) {
|
||||
return _.find($scope.model.config.contentTypes, function (contentType) {
|
||||
function getContentTypeConfig(alias) {
|
||||
return _.find(model.config.contentTypes, function (contentType) {
|
||||
return contentType.ncAlias === alias;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.showCopy = clipboardService.isSupported();
|
||||
vm.showCopy = clipboardService.isSupported();
|
||||
vm.showPaste = false;
|
||||
|
||||
$scope.showPaste = false;
|
||||
|
||||
$scope.clickCopy = function ($event, node) {
|
||||
vm.clickCopy = function ($event, node) {
|
||||
|
||||
syncCurrentNode();
|
||||
|
||||
@@ -452,7 +375,8 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
$scope.pasteFromClipboard = function(newNode) {
|
||||
|
||||
function pasteFromClipboard(newNode) {
|
||||
|
||||
if (newNode === undefined) {
|
||||
return;
|
||||
@@ -461,15 +385,15 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
// generate a new key.
|
||||
newNode.key = String.CreateGuid();
|
||||
|
||||
$scope.nodes.push(newNode);
|
||||
$scope.setDirty();
|
||||
vm.nodes.push(newNode);
|
||||
setDirty();
|
||||
//updateModel();// done by setting current node...
|
||||
|
||||
$scope.currentNode = newNode;
|
||||
setCurrentNode(newNode);
|
||||
}
|
||||
|
||||
function checkAbilityToPasteContent() {
|
||||
$scope.showPaste = clipboardService.hasEntriesOfType("elementType", contentTypeAliases);
|
||||
vm.showPaste = clipboardService.hasEntriesOfType("elementType", contentTypeAliases) || clipboardService.hasEntriesOfType("elementTypeArray", contentTypeAliases);
|
||||
}
|
||||
|
||||
eventsService.on("clipboardService.storageUpdate", checkAbilityToPasteContent);
|
||||
@@ -482,8 +406,8 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
|
||||
// Initialize
|
||||
var scaffoldsLoaded = 0;
|
||||
$scope.scaffolds = [];
|
||||
_.each($scope.model.config.contentTypes, function (contentType) {
|
||||
vm.scaffolds = [];
|
||||
_.each(model.config.contentTypes, function (contentType) {
|
||||
contentResource.getScaffold(-20, contentType.ncAlias).then(function (scaffold) {
|
||||
// make sure it's an element type before allowing the user to create new ones
|
||||
if (scaffold.isElement) {
|
||||
@@ -507,7 +431,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
|
||||
// Store the scaffold object
|
||||
$scope.scaffolds.push(scaffold);
|
||||
vm.scaffolds.push(scaffold);
|
||||
}
|
||||
|
||||
scaffoldsLoaded++;
|
||||
@@ -520,22 +444,22 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
|
||||
var initIfAllScaffoldsHaveLoaded = function () {
|
||||
// Initialize when all scaffolds have loaded
|
||||
if ($scope.model.config.contentTypes.length === scaffoldsLoaded) {
|
||||
if (model.config.contentTypes.length === scaffoldsLoaded) {
|
||||
// Because we're loading the scaffolds async one at a time, we need to
|
||||
// sort them explicitly according to the sort order defined by the data type.
|
||||
contentTypeAliases = [];
|
||||
_.each($scope.model.config.contentTypes, function (contentType) {
|
||||
_.each(model.config.contentTypes, function (contentType) {
|
||||
contentTypeAliases.push(contentType.ncAlias);
|
||||
});
|
||||
$scope.scaffolds = $filter("orderBy")($scope.scaffolds, function (s) {
|
||||
vm.scaffolds = $filter("orderBy")(vm.scaffolds, function (s) {
|
||||
return contentTypeAliases.indexOf(s.contentTypeAlias);
|
||||
});
|
||||
|
||||
// Convert stored nodes
|
||||
if ($scope.model.value) {
|
||||
for (var i = 0; i < $scope.model.value.length; i++) {
|
||||
var item = $scope.model.value[i];
|
||||
var scaffold = $scope.getScaffold(item.ncContentTypeAlias);
|
||||
if (model.value) {
|
||||
for (var i = 0; i < model.value.length; i++) {
|
||||
var item = model.value[i];
|
||||
var scaffold = getScaffold(item.ncContentTypeAlias);
|
||||
if (scaffold == null) {
|
||||
// No such scaffold - the content type might have been deleted. We need to skip it.
|
||||
continue;
|
||||
@@ -544,20 +468,21 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce min items
|
||||
if ($scope.nodes.length < $scope.model.config.minItems) {
|
||||
for (var i = $scope.nodes.length; i < $scope.model.config.minItems; i++) {
|
||||
$scope.addNode($scope.scaffolds[0].contentTypeAlias);
|
||||
// Auto-fill with elementTypes, but only if we have one type to choose from, and if this property is empty.
|
||||
if (vm.singleMode === true && vm.nodes.length === 0 && model.config.minItems > 0) {
|
||||
for (var i = vm.nodes.length; i < model.config.minItems; i++) {
|
||||
addNode(vm.scaffolds[0].contentTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is only one item, set it as current node
|
||||
if ($scope.singleMode || ($scope.nodes.length === 1 && $scope.maxItems === 1)) {
|
||||
$scope.currentNode = $scope.nodes[0];
|
||||
if (vm.singleMode || (vm.nodes.length === 1 && vm.maxItems === 1)) {
|
||||
setCurrentNode(vm.nodes[0]);
|
||||
}
|
||||
|
||||
$scope.inited = true;
|
||||
vm.inited = true;
|
||||
|
||||
updatePropertyActionStates();
|
||||
checkAbilityToPasteContent();
|
||||
}
|
||||
}
|
||||
@@ -576,10 +501,11 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
var prop = tab.properties[p];
|
||||
|
||||
prop.propertyAlias = prop.alias;
|
||||
prop.alias = $scope.model.alias + "___" + prop.alias;
|
||||
prop.alias = model.alias + "___" + prop.alias;
|
||||
// Force validation to occur server side as this is the
|
||||
// only way we can have consistency between mandatory and
|
||||
// regex validation messages. Not ideal, but it works.
|
||||
prop.ncMandatory = prop.validation.mandatory;
|
||||
prop.validation = {
|
||||
mandatory: false,
|
||||
pattern: ""
|
||||
@@ -591,7 +517,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
}
|
||||
|
||||
$scope.nodes.push(node);
|
||||
vm.nodes.push(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -614,37 +540,78 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function syncCurrentNode() {
|
||||
if ($scope.realCurrentNode) {
|
||||
$scope.$broadcast("ncSyncVal", { key: $scope.realCurrentNode.key });
|
||||
if (vm.currentNode) {
|
||||
$scope.$broadcast("ncSyncVal", { key: vm.currentNode.key });
|
||||
}
|
||||
}
|
||||
|
||||
function updateModel() {
|
||||
syncCurrentNode();
|
||||
|
||||
if ($scope.inited) {
|
||||
if (vm.inited) {
|
||||
var newValues = [];
|
||||
for (var i = 0; i < $scope.nodes.length; i++) {
|
||||
newValues.push(convertNodeIntoNCEntry($scope.nodes[i]));
|
||||
for (var i = 0; i < vm.nodes.length; i++) {
|
||||
newValues.push(convertNodeIntoNCEntry(vm.nodes[i]));
|
||||
}
|
||||
$scope.model.value = newValues;
|
||||
model.value = newValues;
|
||||
}
|
||||
|
||||
updatePropertyActionStates();
|
||||
}
|
||||
|
||||
$scope.$watch("currentNode", function (newVal) {
|
||||
updateModel();
|
||||
$scope.realCurrentNode = newVal;
|
||||
});
|
||||
function updatePropertyActionStates() {
|
||||
copyAllEntriesAction.isDisabled = !model.value || model.value.length === 0;
|
||||
removeAllEntriesAction.isDisabled = !model.value || model.value.length === 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var propertyActions = [
|
||||
copyAllEntriesAction,
|
||||
removeAllEntriesAction
|
||||
];
|
||||
|
||||
this.$onInit = function () {
|
||||
if (this.umbProperty) {
|
||||
this.umbProperty.setPropertyActions(propertyActions);
|
||||
}
|
||||
};
|
||||
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
updateModel();
|
||||
});
|
||||
|
||||
var watcher = $scope.$watch(
|
||||
function () {
|
||||
return vm.nodes.length;
|
||||
},
|
||||
function () {
|
||||
//Validate!
|
||||
if (vm.nodes.length < vm.minItems) {
|
||||
$scope.nestedContentForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.nestedContentForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
|
||||
if (vm.nodes.length > vm.maxItems) {
|
||||
$scope.nestedContentForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.nestedContentForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
unsubscribe();
|
||||
watcher();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
]);
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.DocTypePickerController", [
|
||||
|
||||
"$scope",
|
||||
"Umbraco.PropertyEditors.NestedContent.Resources",
|
||||
"overlayService",
|
||||
"localizationService",
|
||||
"iconHelper",
|
||||
|
||||
function ($scope, ncResources, overlayService, localizationService, iconHelper) {
|
||||
var selectElementTypeModalTitle = "";
|
||||
|
||||
$scope.elemTypeTabs = [];
|
||||
|
||||
|
||||
init();
|
||||
|
||||
|
||||
function init() {
|
||||
localizationService.localize("content_nestedContentSelectElementTypeModalTitle").then(function (value) {
|
||||
selectElementTypeModalTitle = value;
|
||||
});
|
||||
|
||||
ncResources.getContentTypes().then(function (elemTypes) {
|
||||
$scope.model.elemTypes = elemTypes;
|
||||
|
||||
// convert legacy icons
|
||||
iconHelper.formatContentTypeIcons($scope.model.elemTypes);
|
||||
|
||||
// Count doctype name occurrences
|
||||
var elTypeNameOccurrences= _.countBy(elemTypes, 'name');
|
||||
|
||||
// Populate document type tab dictionary
|
||||
// And append alias to name if multiple doctypes have the same name
|
||||
elemTypes.forEach(function (value) {
|
||||
$scope.elemTypeTabs[value.alias] = value.tabs;
|
||||
|
||||
if (elTypeNameOccurrences[value.name] > 1) {
|
||||
value.name += " (" + value.alias + ")";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
$scope.add = function () {
|
||||
$scope.model.value.push({
|
||||
// As per PR #4, all stored content type aliases must be prefixed "nc" for easier recognition.
|
||||
// For good measure we'll also prefix the tab alias "nc"
|
||||
ncAlias: "",
|
||||
ncTabAlias: "",
|
||||
nameTemplate: ""
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.docTypes || !$scope.model.value || $scope.model.value.length < $scope.model.docTypes.length;
|
||||
}
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.model.value.splice(index, 1);
|
||||
}
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
cursor: "move",
|
||||
handle: ".handle",
|
||||
placeholder: 'sortable-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
helper: function (e, ui) {
|
||||
// When sorting table rows, the cells collapse. This helper fixes that: https://www.foliotek.com/devblog/make-table-rows-sortable-using-jquery-ui-sortable/
|
||||
ui.children().each(function () {
|
||||
$(this).width($(this).width());
|
||||
});
|
||||
return ui;
|
||||
},
|
||||
start: function (e, ui) {
|
||||
|
||||
var cellHeight = ui.item.height();
|
||||
|
||||
// Build a placeholder cell that spans all the cells in the row: https://stackoverflow.com/questions/25845310/jquery-ui-sortable-and-table-cell-size
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function () {
|
||||
// For each td or th try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1) {
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so td rather than tr - and set height of tr
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"></td>').height(cellHeight);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.placeholder = function (config) {
|
||||
return _.find($scope.model.elemTypes, function (elType) {
|
||||
return elType.alias === config.ncAlias;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.selectableElemTypesFor = function (config) {
|
||||
// return all elemTypes that are:
|
||||
// 1. either already selected for this config, or
|
||||
// 2. not selected in any other config
|
||||
return _.filter($scope.model.elemTypes, function (elType) {
|
||||
return elType.alias === config.ncAlias || !_.find($scope.model.value, function (c) {
|
||||
return elType.alias === c.ncAlias;
|
||||
});
|
||||
});
|
||||
}
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.value || _.some($scope.model.elemTypes, function (elType) {
|
||||
return !_.find($scope.model.value, function (c) {
|
||||
return elType.alias === c.ncAlias;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$scope.openElemTypeModal = function ($event, config) {
|
||||
|
||||
//we have to add the alias to the objects (they are stored as ncAlias)
|
||||
var selectedItems = _.each($scope.model.value, function (obj) {
|
||||
obj.alias = obj.ncAlias;
|
||||
return obj;
|
||||
})
|
||||
|
||||
var elemTypeSelectorOverlay = {
|
||||
view: "itempicker",
|
||||
title: selectElementTypeModalTitle,
|
||||
availableItems: $scope.selectableElemTypesFor(config),
|
||||
selectedItems: selectedItems,
|
||||
position: "target",
|
||||
event: $event,
|
||||
submit: function (model) {
|
||||
config.ncAlias = model.selectedItem.alias;
|
||||
overlayService.close();
|
||||
},
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
|
||||
overlayService.open(elemTypeSelectorOverlay);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!$scope.model.value) {
|
||||
$scope.model.value = [];
|
||||
$scope.add();
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
@@ -24,12 +24,7 @@
|
||||
<td>
|
||||
{{ph = placeholder(config);""}}
|
||||
<div class="umb-nested-content__placeholder" ng-class="{'umb-nested-content__placeholder--selected':ph}" ng-click="openElemTypeModal($event, config)">
|
||||
<span class="umb-nested-content__placeholder-icon-holder" ng-if="ph">
|
||||
<i class="umb-nested-content__placeholder-icon {{ ph.icon }}"></i>
|
||||
</span>
|
||||
<span class="umb-nested-content__placeholder-name" ng-if="ph">
|
||||
{{ ph.name }}
|
||||
</span>
|
||||
<umb-node-preview ng-if="ph" icon="ph.icon" name="ph.name"></umb-node-preview>
|
||||
<localize key="content_nestedContentAddElementType" ng-if="!ph">Add element type</localize>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="umb-pane">
|
||||
<div ng-repeat="property in tab.properties" class="umb-nested-content-property-container">
|
||||
|
||||
<umb-property property="property" ng-class="{'umb-nested-content--not-supported': property.notSupported}" data-element="property-{{property.alias}}">
|
||||
<umb-property property="property" ng-class="{'umb-nested-content--not-supported': property.notSupported, 'umb-nested-content--mandatory': property.ncMandatory}" data-element="property-{{property.alias}}">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
<p ng-if="property.notSupported">{{property.notSupportedMessage}}</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,57 +1,5 @@
|
||||
<div id="umb-nested-content--{{model.id}}" class="umb-nested-content"
|
||||
ng-controller="Umbraco.PropertyEditors.NestedContent.PropertyEditorController"
|
||||
ng-class="{'umb-nested-content--narrow':!wideMode, 'umb-nested-content--wide':wideMode}">
|
||||
<div>
|
||||
|
||||
<umb-load-indicator ng-if="!inited"></umb-load-indicator>
|
||||
|
||||
<ng-form ng-if="inited">
|
||||
|
||||
<div class="umb-nested-content__items" ng-hide="nodes.length === 0" ui-sortable="sortableOptions" ng-model="nodes">
|
||||
|
||||
<div class="umb-nested-content__item" ng-repeat="node in nodes" ng-class="{ 'umb-nested-content__item--active' : $parent.realCurrentNode.key === node.key, 'umb-nested-content__item--single' : $parent.singleMode }">
|
||||
|
||||
<div class="umb-nested-content__header-bar" ng-click="$parent.editNode($index)" ng-hide="$parent.singleMode">
|
||||
|
||||
<div class="umb-nested-content__heading"><i ng-if="showIcons" class="icon" ng-class="$parent.getIcon($index)"></i><span class="umb-nested-content__item-name" ng-class="{'--has-icon': showIcons}" ng-bind="$parent.getName($index)"></span></div>
|
||||
|
||||
<div class="umb-nested-content__icons">
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--copy" title="{{copyIconTitle}}" ng-click="clickCopy($event, node);" ng-if="showCopy" prevent-default>
|
||||
<i class="icon icon-documents"></i>
|
||||
</a>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--delete" localize="title" title="general_delete" ng-class="{ 'umb-nested-content__icon--disabled': $parent.nodes.length <= $parent.minItems }" ng-click="$parent.requestDeleteNode($index); $event.stopPropagation();" prevent-default>
|
||||
<i class="icon icon-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-nested-content__content" ng-if="$parent.realCurrentNode.key === node.key && !$parent.sorting">
|
||||
<umb-nested-content-editor ng-model="node" tab-alias="ncTabAlias" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-hide="hasContentTypes">
|
||||
<div class="umb-nested-content__help-text">
|
||||
<localize key="content_nestedContentNoContentTypes"></localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-nested-content__footer-bar" ng-hide="hasContentTypes === false || nodes.length >= maxItems">
|
||||
<a href class="umb-nested-content__add-content" ng-class="{ '--disabled': !scaffolds.length }" ng-click="openNodeTypePicker($event)" prevent-default>
|
||||
<localize key="grid_addElement"></localize>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="overlayMenu.show"
|
||||
position="target"
|
||||
size="overlayMenu.size"
|
||||
view="overlayMenu.view"
|
||||
model="overlayMenu">
|
||||
</umb-overlay>
|
||||
<nested-content-property-editor></nested-content-property-editor>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<div id="umb-nested-content--{{model.id}}" class="umb-nested-content" ng-class="{'umb-nested-content--narrow':!vm.wideMode, 'umb-nested-content--wide':vm.wideMode}">
|
||||
|
||||
<umb-load-indicator ng-if="!vm.inited"></umb-load-indicator>
|
||||
|
||||
<ng-form name="nestedContentForm">
|
||||
|
||||
<div class="umb-nested-content__items" ng-hide="vm.nodes.length === 0" ui-sortable="vm.sortableOptions" ng-model="vm.nodes">
|
||||
|
||||
<div class="umb-nested-content__item" ng-repeat="node in vm.nodes" ng-class="{ 'umb-nested-content__item--active' : vm.currentNode.key === node.key, 'umb-nested-content__item--single' : vm.singleMode }">
|
||||
|
||||
<div class="umb-nested-content__header-bar" ng-click="vm.editNode($index)" ng-hide="vm.singleMode">
|
||||
|
||||
<div class="umb-nested-content__heading"><i ng-if="vm.showIcons" class="icon" ng-class="vm.getIcon($index)"></i><span class="umb-nested-content__item-name" ng-class="{'--has-icon': vm.showIcons}" ng-bind="vm.getName($index)"></span></div>
|
||||
|
||||
<div class="umb-nested-content__icons">
|
||||
<button type="button" class="umb-nested-content__icon umb-nested-content__icon--copy" title="{{vm.labels.copy_icon_title}}" ng-click="vm.clickCopy($event, node);" ng-if="vm.showCopy">
|
||||
<i class="icon icon-documents" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{vm.labels.copy_icon_title}}</span>
|
||||
</button>
|
||||
<button type="button" class="umb-nested-content__icon umb-nested-content__icon--delete" localize="title" title="general_delete" ng-click="vm.requestDeleteNode($index); $event.stopPropagation();">
|
||||
<i class="icon icon-trash" aria-hidden="true"></i>
|
||||
<span class="sr-only">
|
||||
<localize key="general_delete">Delete</localize>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-nested-content__content" ng-if="vm.currentNode.key === node.key && !vm.sorting">
|
||||
<umb-nested-content-editor ng-model="node" tab-alias="ncTabAlias" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-hide="vm.hasContentTypes">
|
||||
<div class="umb-nested-content__help-text">
|
||||
<localize key="content_nestedContentNoContentTypes"></localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-nested-content__footer-bar" ng-hide="vm.hasContentTypes === false">
|
||||
<button class="btn-reset umb-nested-content__add-content umb-focus" ng-class="{ '--disabled': (!vm.scaffolds.length || vm.nodes.length >= maxItems) }" ng-click="vm.openNodeTypePicker($event)" prevent-default>
|
||||
<localize key="grid_addElement"></localize>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<!--These are here because we need ng-form fields to validate against-->
|
||||
<input type="hidden" name="minCount" ng-model="vm.nodes" />
|
||||
<input type="hidden" name="maxCount" ng-model="vm.nodes" />
|
||||
|
||||
<div ng-messages="nestedContentForm.minCount.$error" show-validation-on-submit>
|
||||
<div class="help text-error" ng-message="minCount">
|
||||
<localize key="validation_entriesShort" tokens="[vm.minItems, vm.minItems - vm.nodes.length]" watch-tokens="true">Minimum %0% entries, needs <strong>%1%</strong> more.</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="nestedContentForm.minCount.$error === true || vm.nodes.length > vm.maxItems">
|
||||
<div class="help text-error">
|
||||
<localize key="validation_entriesExceed" tokens="[vm.maxItems, vm.nodes.length - vm.maxItems]" watch-tokens="true">Maximum %0% entries, <strong>%1%</strong> too many.</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.overlayMenu.show"
|
||||
position="target"
|
||||
size="vm.overlayMenu.size"
|
||||
view="vm.overlayMenu.view"
|
||||
model="vm.overlayMenu">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsController",
|
||||
function ($scope) {
|
||||
function ($scope, validationMessageService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -23,6 +23,12 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsContro
|
||||
|
||||
vm.viewItems = sortedItems;
|
||||
}
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<div class="umb-property-editor umb-radiobuttons" ng-controller="Umbraco.PropertyEditors.RadioButtonsController as vm">
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in vm.viewItems track by item.key">
|
||||
<umb-radiobutton name="{{model.alias}}" value="{{item.value}}" model="model.value" text="{{item.value}}" required="model.validation.mandatory && model.value == ''"></umb-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
<ng-form name="radioButtonsFieldForm">
|
||||
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in vm.viewItems track by item.key">
|
||||
<umb-radiobutton name="{{model.alias}}" value="{{item.value}}" model="model.value" text="{{item.value}}" required="model.validation.mandatory && model.value == ''"></umb-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div ng-messages="radioButtonsFieldForm[model.alias].$error" show-validation-on-submit>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function textAreaController($scope) {
|
||||
function textAreaController($scope, validationMessageService) {
|
||||
|
||||
// macro parameter editor doesn't contains a config object,
|
||||
// so we create a new one to hold any properties
|
||||
@@ -22,5 +22,11 @@ function textAreaController($scope) {
|
||||
}
|
||||
}
|
||||
$scope.model.change();
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textAreaController", textAreaController);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="{{model.config.rows || 10}}" class="umb-property-editor umb-textarea textstring" val-server="value" ng-keyup="model.change()" ng-required="model.validation.mandatory" aria-required="{{model.validation.mandatory}}"></textarea>
|
||||
|
||||
<span ng-messages="textareaFieldForm.textarea.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="required">{{mandatoryMessage}}</span>
|
||||
<span class="help-inline" ng-message="valServer">{{textareaFieldForm.textarea.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function textboxController($scope) {
|
||||
function textboxController($scope, validationMessageService) {
|
||||
// macro parameter editor doesn't contains a config object,
|
||||
// so we create a new one to hold any properties
|
||||
if (!$scope.model.config) {
|
||||
@@ -18,6 +18,11 @@ function textboxController($scope) {
|
||||
}
|
||||
}
|
||||
$scope.model.change();
|
||||
|
||||
|
||||
// Set the message to use for when a mandatory field isn't completed.
|
||||
// Will either use the one provided on the property type or a localised default.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function(value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textboxController", textboxController);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div ng-messages="textboxFieldForm.textbox.$error" show-validation-on-submit>
|
||||
<p class="sr-only" ng-message="valServer" tabindex="0">{{model.label}} {{textboxFieldForm.textbox.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="valServer" tabindex="0" aria-hidden="true">{{textboxFieldForm.textbox.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="required"><localize key="general_required">Required</localize></p>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
<div class="help" ng-if="model.count >= (model.config.maxChars*.8) && model.count <= model.config.maxChars">
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
rows="4">
|
||||
</textarea>
|
||||
<umb-button type="button"
|
||||
button-style="[info,block]"
|
||||
button-style="[action,block]"
|
||||
action="model.resendInvite()"
|
||||
state="model.resendInviteButtonState"
|
||||
label="Resend Invite"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
describe('umbRequestHelper tests', function () {
|
||||
var umbRequestHelper;
|
||||
|
||||
beforeEach(module('umbraco'));
|
||||
beforeEach(module('umbraco.services'));
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
@@ -33,4 +34,4 @@ describe('umbRequestHelper tests', function () {
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user