Merge remote-tracking branch 'origin/v8/dev' into grid-editor-name-templates

This commit is contained in:
elitsa
2019-10-25 11:30:18 +02:00
108 changed files with 6362 additions and 5940 deletions

View File

@@ -3,26 +3,26 @@
module.exports = {
sources: {
//less files used by backoffice and preview
//processed in the less task
// less files used by backoffice and preview
// processed in the less task
less: {
installer: { files: ["./src/less/installer.less"], out: "installer.css" },
nonodes: { files: ["./src/less/pages/nonodes.less"], out: "nonodes.style.min.css"},
preview: { files: ["./src/less/canvas-designer.less"], out: "canvasdesigner.css" },
umbraco: { files: ["./src/less/belle.less"], out: "umbraco.css" },
rteContent: { files: ["./src/less/rte-content.less"], out: "rte-content.css" }
installer: { files: "./src/less/installer.less", watch: "./src/less/**/*.less", out: "installer.css" },
nonodes: { files: "./src/less/pages/nonodes.less", watch: "./src/less/**/*.less", out: "nonodes.style.min.css"},
preview: { files: "./src/less/canvas-designer.less", watch: "./src/less/**/*.less", out: "canvasdesigner.css" },
umbraco: { files: "./src/less/belle.less", watch: "./src/less/**/*.less", out: "umbraco.css" },
rteContent: { files: "./src/less/rte-content.less", watch: "./src/less/**/*.less", out: "rte-content.css" }
},
//js files for backoffie
//processed in the js task
// js files for backoffice
// processed in the js task
js: {
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
filters: { files: ["./src/common/filters/**/*.js"], out: "umbraco.filters.js" },
resources: { files: ["./src/common/resources/**/*.js"], out: "umbraco.resources.js" },
services: { files: ["./src/common/services/**/*.js"], out: "umbraco.services.js" },
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" },
preview: { files: "./src/preview/**/*.js", out: "umbraco.preview.js" },
installer: { files: "./src/installer/**/*.js", out: "umbraco.installer.js" },
filters: { files: "./src/common/filters/**/*.js", out: "umbraco.filters.js" },
resources: { files: "./src/common/resources/**/*.js", out: "umbraco.resources.js" },
services: { files: "./src/common/services/**/*.js", out: "umbraco.services.js" },
security: { files: "./src/common/interceptors/**/*.js", out: "umbraco.interceptors.js" },
//the controllers for views
controllers: {
files: [
@@ -42,13 +42,16 @@ module.exports = {
],
out: "umbraco.directives.js"
}
},
//selectors for copying all views into the build
//processed in the views task
views:{
umbraco: {files: ["./src/views/**/*.html"], folder: ""},
installer: {files: ["./src/installer/steps/*.html"], folder: "install/"}
views: {files: "./src/views/**/*.html", folder: ""},
directives: {files: "./src/common/directives/**/*.html", folder: ""},
components: {files: "./src/common/components/**/*.html", folder: ""},
installer: {files: "./src/installer/steps/*.html", folder: "install/"}
},
//globs for file-watching

View File

@@ -1,10 +0,0 @@
'use strict';
var fs = require('fs');
var onlyScripts = require('./util/scriptFilter');
var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts);
tasks.forEach(function(task) {
require('./tasks/' + task);
});

View File

@@ -1,10 +0,0 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var runSequence = require('run-sequence');
// Build - build the files ready for production
gulp.task('build', function(cb) {
runSequence(["js", "dependencies", "less", "views"], "test:unit", cb);
});

View File

@@ -10,7 +10,7 @@ var imagemin = require('gulp-imagemin');
/**************************
* Task processes and copies all dependencies, either installed by npm or stored locally in the project
**************************/
gulp.task('dependencies', function () {
function dependencies() {
//as we do multiple things in this task, we merge the multiple streams
var stream = new MergeStream();
@@ -244,21 +244,21 @@ gulp.task('dependencies', function () {
nodeModules.forEach(module => {
stream.add(
gulp.src(module.src,
{ base: module.base })
{ base: module.base, allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.lib + "/" + module.name))
);
});
//copy over libs which are not on npm (/lib)
stream.add(
gulp.src(config.sources.globs.lib)
gulp.src(config.sources.globs.lib, { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.lib))
);
//Copies all static assets into /root / assets folder
//css, fonts and image files
var assetsTask = gulp.src(config.sources.globs.assets);
var assetsTask = gulp.src(config.sources.globs.assets, { allowEmpty: true });
if (global.isProd === true) {
assetsTask = assetsTask.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
@@ -277,21 +277,23 @@ gulp.task('dependencies', function () {
stream.add(assetsTask);
// Copies all the less files related to the preview into their folder
//these are not pre-processed as preview has its own less combiler client side
//these are not pre-processed as preview has its own less compiler client side
stream.add(
gulp.src("src/canvasdesigner/editors/*.less")
gulp.src("src/canvasdesigner/editors/*.less", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.assets + "/less"))
);
// Todo: check if we need these fileSize
// TODO: check if we need these fileSize
stream.add(
gulp.src("src/views/propertyeditors/grid/config/*.*")
gulp.src("src/views/propertyeditors/grid/config/*.*", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.views + "/propertyeditors/grid/config"))
);
stream.add(
gulp.src("src/views/dashboard/default/*.jpg")
gulp.src("src/views/dashboard/default/*.jpg", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.views + "/dashboard/default"))
);
return stream;
});
};
module.exports = { dependencies: dependencies };

View File

@@ -1,13 +0,0 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var runSequence = require('run-sequence');
// Dev - build the files ready for development and start watchers
gulp.task('dev', function (cb) {
global.isProd = false;
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
});

View File

@@ -9,21 +9,24 @@ var MergeStream = require('merge-stream');
var processJs = require('../util/processJs');
/**************************
* Copies all angular JS files into their seperate umbraco.*.js file
* Copies all angular JS files into their separate umbraco.*.js file
**************************/
gulp.task('js', function () {
function js() {
//we run multiple streams, so merge them all together
var stream = new MergeStream();
stream.add(
gulp.src(config.sources.globs.js)
.pipe(gulp.dest(config.root + config.targets.js))
);
gulp.src(config.sources.globs.js).pipe( gulp.dest(config.root + config.targets.js) )
);
_.forEach(config.sources.js, function (group) {
stream.add (processJs(group.files, group.out) );
});
_.forEach(config.sources.js, function (group) {
stream.add(
processJs(group.files, group.out)
);
});
return stream;
});
};
module.exports = { js: js };

View File

@@ -1,14 +1,13 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
var processLess = require('../util/processLess');
gulp.task('less', function () {
function less() {
var stream = new MergeStream();
@@ -17,4 +16,6 @@ gulp.task('less', function () {
});
return stream;
});
};
module.exports = { less: less };

View File

@@ -0,0 +1,22 @@
'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 };

View File

@@ -1,32 +1,27 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var karmaServer = require('karma').Server;
var runSequence = require('run-sequence');
/**************************
* Build tests
**************************/
// Karma test
gulp.task('runTests', function(cb) {
runSequence("js", "test:unit", cb);
});
function testUnit() {
gulp.task('test:unit', function () {
new karmaServer({
return new karmaServer({
configFile: __dirname + "/../../test/config/karma.conf.js",
keepalive: true
})
.start();
});
};
gulp.task('test:e2e', function() {
new karmaServer({
function testE2e() {
return new karmaServer({
configFile: __dirname + "/../../test/config/e2e.js",
keepalive: true
})
.start();
});
};
module.exports = { testUnit: testUnit, testE2e: testE2e };

View File

@@ -6,7 +6,7 @@ var gulp = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
gulp.task('views', function () {
function views() {
var stream = new MergeStream();
@@ -22,4 +22,7 @@ gulp.task('views', function () {
});
return stream;
});
};
module.exports = { views: views };

View File

@@ -1,58 +0,0 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
var processJs = require('../util/processJs');
var watch = require('gulp-watch');
gulp.task('watch', function () {
var stream = new MergeStream();
var watchInterval = 500;
//Setup a watcher for all groups of javascript files
_.forEach(config.sources.js, function (group) {
if(group.watch !== false){
stream.add(
watch(group.files, { ignoreInitial: true, interval: watchInterval }, function (file) {
console.info(file.path + " has changed, added to: " + group.out);
processJs(group.files, group.out);
})
);
}
});
stream.add(
//watch all less files and trigger the less task
watch(config.sources.globs.less, { ignoreInitial: true, interval: watchInterval }, function () {
gulp.run(['less']);
})
);
//watch all views - copy single file changes
stream.add(
watch(config.sources.globs.views, { interval: watchInterval })
.pipe(gulp.dest(config.root + config.targets.views))
);
//watch all app js files that will not be merged - copy single file changes
stream.add(
watch(config.sources.globs.js, { interval: watchInterval })
.pipe(gulp.dest(config.root + config.targets.js))
);
return stream;
});

View File

@@ -0,0 +1,49 @@
'use strict';
const config = require('../config');
const {watch, parallel, dest, src} = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
var processJs = require('../util/processJs');
var processLess = require('../util/processLess');
//const { less } = require('./less');
//const { views } = require('./views');
function watchTask(cb) {
var watchInterval = 500;
//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) });
}
});
//Setup a watcher for all groups of LESS files
_.forEach(config.sources.less, function (group) {
if(group.watch !== false) {
watch(group.watch, { ignoreInitial: true, interval: watchInterval }, function Less_Group_Compile() { processLess(group.files, group.out) });
}
});
//Setup a watcher for all groups of view files
var viewWatcher;
_.forEach(config.sources.views, function (group) {
if(group.watch !== false) {
viewWatcher = watch(group.files, { ignoreInitial: true, interval: watchInterval });
viewWatcher.on('change', function(path, stats) {
console.log("copying " + group.files + " to " + config.root + config.targets.views + group.folder);
src(group.files).pipe( dest(config.root + config.targets.views + group.folder) )
});
}
});
return cb();
};
module.exports = { watchTask: watchTask };

View File

@@ -11,6 +11,8 @@ var embedTemplates = require('gulp-angular-embed-templates');
module.exports = function (files, out) {
console.log("JS: ", files, " -> ", config.root + config.targets.js + out)
var task = gulp.src(files);
// check for js errors

View File

@@ -15,7 +15,9 @@ module.exports = function(files, out) {
autoprefixer,
cssnano({zindex: false})
];
console.log("LESS: ", files, " -> ", config.root + config.targets.js + out)
var task = gulp.src(files)
.pipe(less())
.pipe(cleanCss())

View File

@@ -1,16 +1,49 @@
'use strict';
/*
* gulpfile.js
* ===========
* Rather than manage one giant configuration file responsible
* for creating multiple tasks, each task has been broken out into
* its own file in gulp/tasks. Any file in that folder gets automatically
* required by the loop in ./gulp/index.js (required below).
*
* To add a new task, simply add a new task file to gulp/tasks.
*/
* gulpfile.js
* ===========
* This is now using Gulp 4, each child task is now a child function in its own corresponding file.
*
* To add a new task, simply add a new task file to gulp/tasks folder, add a require statement below to include the one or more methods
* and then add the exports command to add the new item into the task menu.
*/
global.isProd = true;
require('./gulp');
const { src, dest, series, parallel, lastRun } = require('gulp');
const { dependencies } = require('./gulp/tasks/dependencies');
const { js } = require('./gulp/tasks/js');
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');
var onlyScripts = require('./gulp/util/scriptFilter');
try {
if (fs.existsSync('./gulp/overwrites/')) {
var overwrites = fs.readdirSync('./gulp/overwrites/').filter(onlyScripts);
overwrites.forEach(function(overwrite) {
require('./gulp/overwrites/' + overwrite);
});
}
} catch (err) {
console.error(err)
}
// ***********************************************************
// These Exports are the new way of defining Tasks in Gulp 4.x
// ***********************************************************
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);
exports.testUnit = series(testUnit);
exports.testE2e = series(testE2e);

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +1,84 @@
{
"private": true,
"scripts": {
"test": "karma start test/config/karma.conf.js --singlerun",
"build": "gulp build",
"dev": "gulp dev",
"fastdev": "gulp fastdev"
},
"dependencies": {
"ace-builds": "1.4.2",
"angular": "1.7.5",
"angular-animate": "1.7.5",
"angular-aria": "1.7.5",
"angular-chart.js": "^1.1.1",
"angular-cookies": "1.7.5",
"angular-dynamic-locale": "0.1.37",
"angular-i18n": "1.7.5",
"angular-local-storage": "0.7.1",
"angular-messages": "1.7.5",
"angular-mocks": "1.7.5",
"angular-route": "1.7.5",
"angular-sanitize": "1.7.5",
"angular-touch": "1.7.5",
"angular-ui-sortable": "0.19.0",
"animejs": "2.2.0",
"bootstrap-social": "5.1.1",
"chart.js": "^2.7.3",
"clipboard": "2.0.4",
"diff": "3.5.0",
"flatpickr": "4.5.2",
"font-awesome": "4.7.0",
"jquery": "^3.4.0",
"jquery-ui-dist": "1.12.1",
"jquery-ui-touch-punch": "0.2.3",
"lazyload-js": "1.0.0",
"moment": "2.22.2",
"ng-file-upload": "12.2.13",
"nouislider": "14.0.2",
"npm": "^6.4.1",
"signalr": "2.4.0",
"spectrum-colorpicker": "1.8.0",
"tinymce": "4.9.2",
"typeahead.js": "0.11.1",
"underscore": "1.9.1"
},
"devDependencies": {
"@babel/core": "7.1.6",
"@babel/preset-env": "7.1.6",
"autoprefixer": "9.3.1",
"cssnano": "4.1.7",
"fs": "0.0.2",
"gulp": "^3.9.1",
"gulp-angular-embed-templates": "^2.3.0",
"gulp-babel": "8.0.0",
"gulp-clean-css": "4.0.0",
"gulp-cli": "^2.0.1",
"gulp-concat": "2.6.1",
"gulp-eslint": "^5.0.0",
"gulp-imagemin": "^4.1.0",
"gulp-less": "4.0.1",
"gulp-notify": "^3.0.0",
"gulp-postcss": "8.0.0",
"gulp-rename": "1.4.0",
"gulp-sort": "2.0.0",
"gulp-watch": "5.0.1",
"gulp-wrap": "0.14.0",
"gulp-wrap-js": "0.4.1",
"jasmine-core": "3.3.0",
"karma": "3.1.1",
"karma-jasmine": "2.0.1",
"karma-junit-reporter": "^1.2.0",
"karma-phantomjs-launcher": "1.0.4",
"less": "3.9.0",
"lodash": "4.17.13",
"marked": "^0.6.1",
"merge-stream": "1.0.1",
"run-sequence": "2.2.1",
"caniuse-lite": "^1.0.30000966"
}
}
{
"private": true,
"scripts": {
"test": "gulp runTests",
"unit": "gulp testUnit",
"e2e": "gulp testE2e",
"build": "gulp build",
"dev": "gulp dev",
"fastdev": "gulp fastdev",
"watch": "gulp watch"
},
"dependencies": {
"ace-builds": "1.4.2",
"angular": "1.7.5",
"angular-animate": "1.7.5",
"angular-aria": "1.7.5",
"angular-chart.js": "^1.1.1",
"angular-cookies": "1.7.5",
"angular-dynamic-locale": "0.1.37",
"angular-i18n": "1.7.5",
"angular-local-storage": "0.7.1",
"angular-messages": "1.7.5",
"angular-mocks": "1.7.5",
"angular-route": "1.7.5",
"angular-sanitize": "1.7.5",
"angular-touch": "1.7.5",
"angular-ui-sortable": "0.19.0",
"animejs": "2.2.0",
"bootstrap-social": "5.1.1",
"chart.js": "^2.8.0",
"clipboard": "2.0.4",
"diff": "3.5.0",
"flatpickr": "4.5.2",
"font-awesome": "4.7.0",
"jquery": "^3.4.1",
"jquery-ui-dist": "1.12.1",
"jquery-ui-touch-punch": "0.2.3",
"lazyload-js": "1.0.0",
"moment": "2.22.2",
"ng-file-upload": "12.2.13",
"nouislider": "14.0.2",
"npm": "6.12.0",
"signalr": "2.4.0",
"spectrum-colorpicker": "1.8.0",
"tinymce": "4.9.2",
"typeahead.js": "0.11.1",
"underscore": "1.9.1"
},
"devDependencies": {
"@babel/core": "7.6.4",
"@babel/preset-env": "7.6.3",
"autoprefixer": "9.6.5",
"caniuse-lite": "^1.0.30001002",
"cssnano": "4.1.10",
"fs": "0.0.2",
"gulp": "4.0.2",
"gulp-angular-embed-templates": "^2.3.0",
"gulp-babel": "8.0.0",
"gulp-clean-css": "4.2.0",
"gulp-cli": "^2.2.0",
"gulp-concat": "2.6.1",
"gulp-eslint": "6.0.0",
"gulp-imagemin": "6.1.1",
"gulp-less": "4.0.1",
"gulp-notify": "^3.0.0",
"gulp-postcss": "8.0.0",
"gulp-rename": "1.4.0",
"gulp-sort": "2.0.0",
"gulp-watch": "5.0.1",
"gulp-wrap": "0.15.0",
"gulp-wrap-js": "0.4.1",
"jasmine-core": "3.5.0",
"karma": "4.4.1",
"karma-jasmine": "2.0.1",
"karma-junit-reporter": "2.0.1",
"karma-phantomjs-launcher": "1.0.4",
"karma-spec-reporter": "0.0.32",
"less": "3.10.3",
"lodash": "4.17.15",
"marked": "^0.7.0",
"merge-stream": "2.0.0",
"run-sequence": "2.2.1"
}
}

View File

@@ -26,6 +26,7 @@
@param {string} value Set the value of the radiobutton.
@param {string} name Set the name of the radiobutton.
@param {string} text Set the text for the radiobutton label.
@param {string} labelKey Set a dictinary/localization string for the checkbox label
@param {boolean} disabled Set the radiobutton to be disabled.
@param {boolean} required Set the radiobutton to be required.
@param {callback} onChange Callback when the value of the radiobutton change by interaction.
@@ -39,15 +40,27 @@
var vm = this;
vm.$onInit = onInit;
vm.change = change;
function onInit() {
// If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [
if (vm.labelKey) {
localizationService.localize(vm.labelKey).then(function (data) {
if(data.indexOf('[') === -1){
vm.text = data;
}
});
}
}
function change() {
if (vm.onChange) {
$timeout(function () {
vm.onChange({ model: vm.model, value: vm.value });
}, 0);
}
}
}
}
var component = {
@@ -60,6 +73,7 @@
value: "@",
name: "@",
text: "@",
labelKey: "@?",
disabled: "<",
required: "<",
onChange: "&?"

View File

@@ -1,5 +1,4 @@
/**
@ngdoc directive
@name umbraco.directives.directive:umbOverlay*
@deprecated
@restrict E

View File

@@ -131,13 +131,24 @@ Use this directive to render a date time picker
return console.warn('Unable to find any flatpickr installation');
}
var fpInstance;
setUpCallbacks();
if (!ctrl.options.locale) {
ctrl.options.locale = userLocale;
}
var fpInstance = new fpLib(element, ctrl.options);
// handle special keydown events
ctrl.options.onKeyDown = function (selectedDates, dateStr, instance, event) {
var code = event.keyCode || event.which;
if (code === 13) {
// close the datepicker on enter (this happens when entering time)
fpInstance.close()
}
};
fpInstance = new fpLib(element, ctrl.options);
if (ctrl.onSetup) {
ctrl.onSetup({

View File

@@ -419,7 +419,7 @@
};
scope.canRemoveGroup = function(group){
return _.find(group.properties, function(property) { return property.locked === true; }) == null;
return group.inherited !== true && _.find(group.properties, function(property) { return property.locked === true; }) == null;
}
scope.removeGroup = function(groupIndex) {
@@ -475,6 +475,23 @@
/* ---------- PROPERTIES ---------- */
scope.addPropertyToActiveGroup = function () {
var group = _.find(scope.model.groups, group => group.tabState === "active");
if (!group && scope.model.groups.length) {
group = scope.model.groups[0];
}
if (!group || !group.name) {
return;
}
var property = _.find(group.properties, property => property.propertyState === "init");
if (!property) {
return;
}
scope.addProperty(property, group);
}
scope.addProperty = function(property, group) {
// set property sort order

View File

@@ -1,161 +1,143 @@
(function() {
'use strict';
(function () {
'use strict';
function ListViewSettingsDirective(dataTypeResource, dataTypeHelper, listViewPrevalueHelper) {
function ListViewSettingsDirective(dataTypeResource, dataTypeHelper, editorService, listViewPrevalueHelper) {
function link(scope) {
function link(scope) {
scope.dataType = {};
scope.editDataTypeSettings = false;
scope.customListViewCreated = false;
scope.dataType = {};
scope.customListViewCreated = false;
const checkForCustomListView = () => scope.dataType.name === "List View - " + scope.modelAlias;
/* ---------- INIT ---------- */
/* ---------- INIT ---------- */
function activate() {
const activate = () => {
if(scope.enableListView) {
if (scope.enableListView) {
dataTypeResource.getByName(scope.listViewName)
.then(function(dataType) {
dataTypeResource.getByName(scope.listViewName)
.then(dataType => {
scope.dataType = dataType;
scope.dataType = dataType;
listViewPrevalueHelper.setPrevalues(dataType.preValues);
scope.customListViewCreated = checkForCustomListView();
});
} else {
scope.dataType = {};
}
}
/* ----------- LIST VIEW SETTINGS --------- */
const showSettingsOverlay = () => {
const overlay = {
view: 'views/components/umb-list-view-settings-overlay.html',
hideDescription: true,
hideIcon: true,
size: 'medium',
dataType: scope.dataType,
title: 'List view settings',
submit: model => {
const preValues = dataTypeHelper.createPreValueProps(model.dataType.preValues);
// store data type
dataTypeResource.save(model.dataType, preValues, false)
.then(dataType => scope.dataType = dataType);
editorService.close();
},
close: () => editorService.close()
};
editorService.open(overlay);
};
/* ---------- CUSTOM LIST VIEW ---------- */
scope.createCustomListViewDataType = () => {
scope.loading = true;
dataTypeResource.createCustomListView(scope.modelAlias).then(dataType => {
// store data type
scope.dataType = dataType;
// set list view name on scope
scope.listViewName = dataType.name;
// change state to custom list view
scope.customListViewCreated = true;
// show settings overlay
showSettingsOverlay();
scope.loading = false;
});
};
scope.removeCustomListDataType = () => {
scope.loading = true;
// delete custom list view data type
dataTypeResource.deleteById(scope.dataType.id).then(dataType => {
// set list view name on scope
scope.listViewName = `List View - ${scope.contentType === 'documentType' ? 'Content' : 'Media'}`;
// get default data type
dataTypeResource.getByName(scope.listViewName)
.then(defaultDataType => {
// store data type
scope.dataType = defaultDataType;
// change state to default list view
scope.customListViewCreated = false;
scope.loading = false;
});
});
};
scope.toggle = () => scope.enableListView = !scope.enableListView;
scope.showSettingsOverlay = () => showSettingsOverlay();
/* ----------- SCOPE WATCHERS ----------- */
const unbindEnableListViewWatcher = scope.$watch('enableListView', newValue => {
if (newValue !== undefined) {
activate();
}
listViewPrevalueHelper.setPrevalues(dataType.preValues);
scope.customListViewCreated = checkForCustomListView();
});
} else {
scope.dataType = {};
// clean up
scope.$on('$destroy', () => unbindEnableListViewWatcher());
}
}
/* ----------- LIST VIEW SETTINGS --------- */
scope.toggleEditListViewDataTypeSettings = function() {
scope.editDataTypeSettings = !scope.editDataTypeSettings;
};
scope.saveListViewDataType = function() {
var preValues = dataTypeHelper.createPreValueProps(scope.dataType.preValues);
dataTypeResource.save(scope.dataType, preValues, false).then(function(dataType) {
// store data type
scope.dataType = dataType;
// hide settings panel
scope.editDataTypeSettings = false;
});
};
/* ---------- CUSTOM LIST VIEW ---------- */
scope.createCustomListViewDataType = function() {
dataTypeResource.createCustomListView(scope.modelAlias).then(function(dataType) {
// store data type
scope.dataType = dataType;
// set list view name on scope
scope.listViewName = dataType.name;
// change state to custom list view
scope.customListViewCreated = true;
// show settings panel
scope.editDataTypeSettings = true;
});
};
scope.removeCustomListDataType = function() {
scope.editDataTypeSettings = false;
// delete custom list view data type
dataTypeResource.deleteById(scope.dataType.id).then(function(dataType) {
// set list view name on scope
if(scope.contentType === "documentType") {
scope.listViewName = "List View - Content";
} else if(scope.contentType === "mediaType") {
scope.listViewName = "List View - Media";
}
// get default data type
dataTypeResource.getByName(scope.listViewName)
.then(function(dataType) {
// store data type
scope.dataType = dataType;
// change state to default list view
scope.customListViewCreated = false;
});
});
};
scope.toggle = function(){
if(scope.enableListView){
scope.enableListView = false;
return;
}
scope.enableListView = true;
};
/* ----------- SCOPE WATCHERS ----------- */
var unbindEnableListViewWatcher = scope.$watch('enableListView', function(newValue){
if(newValue !== undefined) {
activate();
}
});
// clean up
scope.$on('$destroy', function(){
unbindEnableListViewWatcher();
});
/* ----------- METHODS ---------- */
function checkForCustomListView() {
return scope.dataType.name === "List View - " + scope.modelAlias;
}
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/umb-list-view-settings.html',
scope: {
enableListView: "=",
listViewName: "=",
modelAlias: "=",
contentType: "@"
},
link: link
};
return directive;
}
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/umb-list-view-settings.html',
scope: {
enableListView: "=",
listViewName: "=",
modelAlias: "=",
contentType: "@"
},
link: link
};
return directive;
}
angular.module('umbraco.directives').directive('umbListViewSettings', ListViewSettingsDirective);
angular.module('umbraco.directives').directive('umbListViewSettings', ListViewSettingsDirective);
})();

View File

@@ -17,9 +17,9 @@ angular.module("umbraco.directives")
var observer = new MutationObserver(domChange);
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: false };
var config = { attributes: true, childList: true, subtree: true };
function domChange(mutationsList, observer){
function domChange(mutationsList, observer) {
for(var mutation of mutationsList) {
//DOM items have been added or removed
@@ -43,4 +43,4 @@ angular.module("umbraco.directives")
}
};
});
});

View File

@@ -251,7 +251,7 @@ When building a custom infinite editor view you can use the same components as a
*
* @param {Object} editor rendering options
* @param {String} editor.view Path to view
* @param {String} editor.size Sets the size of the editor ("small"). If nothing is set it will use full width.
* @param {String} editor.size Sets the size of the editor ("small" || "medium"). If nothing is set it will use full width.
*/
function open(editor) {
@@ -567,6 +567,7 @@ When building a custom infinite editor view you can use the same components as a
* @param {Boolean} editor.multiPicker Pick one or multiple items
* @param {Boolean} editor.onlyImages Only display files that have an image file-extension
* @param {Boolean} editor.disableFolderSelect Disable folder selection
* @param {Boolean} editor.disableFocalPoint Disable focal point editor for selected media
* @param {Array} editor.updatedMediaNodes A list of ids for media items that have been updated through the media picker
* @param {Callback} editor.submit Submits the editor
* @param {Callback} editor.close Closes the editor

View File

@@ -15,7 +15,8 @@
'[tabindex]',
'audio[controls]',
'video[controls]',
'[contenteditable]:not([contenteditable="false"])'
'[contenteditable]:not([contenteditable="false"])',
'iframe[data-mce-style]'
];
var candidateSelector = candidateSelectors.join(',');

View File

@@ -1489,6 +1489,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
onlyImages: true,
showDetails: true,
disableFolderSelect: true,
disableFocalPoint: true,
startNodeId: startNodeId,
startNodeIsVirtual: startNodeIsVirtual,
dataTypeKey: args.model.dataTypeKey,

View File

@@ -338,3 +338,31 @@ input[type="submit"].btn {
text-decoration: none;
}
}
// Icon buttons
// ------------------------------
// 31 July 19, Nathan Woulfe says: Reset styles for cases where button shows an icon only (eg edit/remove property on document type)
// This is lifted from umb-group-builder.less
.btn-icon {
border: none;
font-size: 18px;
position: relative;
cursor: pointer;
color: @ui-icon;
margin: 0;
padding: 5px 10px;
width: auto;
overflow: visible;
background: transparent;
line-height: normal;
outline: 0;
-webkit-appearance: none;
&:hover, &:focus {
color: @ui-icon-hover;
}
}

View File

@@ -1,82 +1,86 @@
.umb-editors {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
.absolute();
overflow: hidden;
.umb-editor {
box-shadow: 0px 0 30px 0 rgba(0,0,0,.3);
}
}
.umb-editor {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
.absolute();
background: @brownGrayLight;
z-index: @zIndexEditor;
}
.umb-editor--infiniteMode {
transform: none;
will-change: transform;
transition: transform 400ms ease-in-out;
&.moveRight {
transform: translateX(110%);
&--infiniteMode {
transform: none;
will-change: transform;
transition: transform 400ms ease-in-out;
&.umb-editor--moveRight {
transform: translateX(110%);
}
}
}
.umb-editor--outOfRange {
transform: none;
display: none;
will-change: auto;
transition: display 0s 320ms;
}
.umb-editor--level0 {
transform: none;
}
.umb-editor--level1 {
transform: translateX(60px);
}
.umb-editor--level2 {
transform: translateX(120px);
}
.umb-editor--level3 {
transform: translateX(180px);
}
.umb-editor--n1 {
right:60px;
}
.umb-editor--n2 {
right:120px;
}
.umb-editor--n3 {
right:180px;
}
// hide all infinite editors by default
// will be shown through animation
.umb-editors .umb-editor {
box-shadow: 0px 0 30px 0 rgba(0,0,0,.3);
}
.umb-editor--small {
width: 500px;
will-change: transform;
left: auto;
&--outOfRange {
transform: none;
display: none;
will-change: auto;
transition: display 0s 320ms;
}
.umb-editor-container {
max-width: 500px;
&--level0 {
transform: none;
}
}
// use a loop to build the editor levels
@iterations: 3;
@step: 60px;
.level-loop (@i) when (@i > 0) {
@x: @i * @step;
.umb-editor--level@{i} {
transform: translateX(@x);
}
.umb-editor--n@{i} {
right:@x;
}
.level-loop(@i - 1);
}
.level-loop(@iterations);
// and also use a loop to build editor sizes - easily extended with new sizes by adding to the map
@editorSizes:
small 500px,
medium 800px;
.create-editor-sizes(@iterator:1) when(@iterator <= length(@editorSizes)) {
.umb-editor {
@size: extract(extract(@editorSizes, @iterator), 1);
@value: extract(extract(@editorSizes, @iterator), 2);
&--@{size} {
width: @value;
will-change: transform;
left: auto;
.umb-editor--container {
max-width: @value;
}
}
}
.create-editor-sizes(@iterator + 1);
}
.create-editor-sizes();
.umb-editor__overlay {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
.absolute();
background: rgba(0,0,0,0.4);
z-index: @zIndexEditor;
visibility: hidden;
@@ -85,7 +89,7 @@
}
#contentcolumn > .umb-editor__overlay,
.--notInFront .umb-editor__overlay {
.umb-editor--notInFront .umb-editor__overlay {
visibility: visible;
opacity: 1;
transition: opacity 320ms 20ms, visibility 0s;

View File

@@ -20,11 +20,11 @@
}
.umb-overlay .umb-overlay-header {
border-bottom: 1px solid @purple-l3;
border-bottom: 1px solid @gray-9;
margin-top: 0;
flex-grow: 0;
flex-shrink: 0;
padding: 20px 30px 0;
padding: 20px 20px 0;
}
.umb-overlay__section-header {
@@ -48,11 +48,11 @@
}
.umb-overlay__title {
font-size: @fontSizeLarge;
font-size: 16px;
color: @black;
line-height: 20px;
line-height: 16px;
font-weight: bold;
margin: 7px 0;
margin: 5px 0;
}
.umb-overlay__subtitle {
@@ -66,8 +66,8 @@
flex-shrink: 1;
flex-basis: auto;
position: relative;
padding: 0 30px;
margin-bottom: 10px;
padding: 20px;
background: @white;
max-height: calc(100vh - 170px);
overflow-y: auto;
}
@@ -75,11 +75,11 @@
.umb-overlay-drawer {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 31px;
padding: 10px 20px;
flex-basis: 33px;
padding: 8px 20px;
margin: 0;
background: @gray-10;
border-top: 1px solid @purple-l3;
background: @white;
border-top: 1px solid @gray-9;
}
.umb-overlay-drawer.-auto-height {
@@ -140,7 +140,6 @@
.umb-overlay.umb-overlay-target .umb-overlay-drawer {
border: none;
background: transparent;
padding: 0 30px 20px;
}
/* ---------- OVERLAY RIGHT ---------- */
@@ -158,7 +157,7 @@
}
.umb-overlay.umb-overlay-right .umb-overlay-header {
flex-basis: 100px;
flex-basis: 70px;
box-sizing: border-box;
}

View File

@@ -8,6 +8,14 @@
.umb-breadcrumbs__ancestor {
display: flex;
min-height: 25px;
}
.umb-breadcrumbs__action {
background: transparent;
border: 0 none;
padding: 0;
margin-top: -4px;
}
.umb-breadcrumbs__ancestor-link,
@@ -38,7 +46,6 @@
input.umb-breadcrumbs__add-ancestor {
height: 25px;
margin-top: -2px;
margin-left: 3px;
margin: 0 0 0 3px;
width: 100px;
}

View File

@@ -15,7 +15,7 @@
&__text {
margin: 0 0 0 26px;
position: relative;
top: 0;
top: 1px;
user-select: none;
}
@@ -24,7 +24,7 @@
top: 0;
left: 0;
opacity: 0;
&:hover ~ .umb-form-check__state .umb-form-check__check {
border-color: @inputBorderFocus;
}
@@ -36,7 +36,7 @@
background: @ui-option-type-hover;
}
}
&:checked ~ .umb-form-check__state {
.umb-form-check__check {
// This only happens if the state has a radiobutton modifier
@@ -62,8 +62,7 @@
}
}
}
.tabbing-active &.umb-form-check--radiobutton &__input:focus ~ .umb-form-check__state .umb-form-check__check {
//outline: 2px solid @inputBorderTabFocus;
border: 2px solid @inputBorderTabFocus;
@@ -76,6 +75,11 @@
border-color: white;
}
// add spacing between when flexed/inline, equal to the width of the input
.flex & + & {
margin-left:@checkboxWidth;
}
&__state {
display: flex;
height: 18px;

View File

@@ -367,7 +367,6 @@ input.umb-group-builder__group-title-input:disabled:hover {
overflow: visible;
background: transparent;
line-height: normal;
outline: 0;
-webkit-appearance: none;
&:hover, &:focus {

View File

@@ -1,54 +1,76 @@
.umb-list-view-settings__box {
background: @gray-10;
border: 1px solid @gray-7;
display: flex;
animation: fadeIn 0.5s;
padding: 15px;
position: relative;
background: @gray-10;
display: flex;
flex: 1;
padding: 15px;
position: relative;
border-radius: @baseBorderRadius;
.btn-link {
font-size: 13px;
padding: 0;
}
}
.umb-list-view-settings__trigger {
margin-bottom: 20px;
}
.umb-list-view-settings__box.-open {
border-bottom: transparent;
}
.umb-list-view-settings__content {
display: flex;
margin-bottom: 20px;
}
.umb-list-view-settings__list-view-icon {
font-size: 20px;
color: @gray-7;
margin-right: 10px;
font-size: 20px;
color: @gray-7;
margin-right: 10px;
}
.umb-list-view-settings__name {
margin-right: 5px;
font-size: 14px;
font-weight: bold;
float: left;
font-size: 14px;
font-weight: bold;
}
.umb-list-view-settings__create-new {
font-size: 13px;
color: @ui-action-type;
}
.umb-list-view-settings__create-new:hover {
color: @ui-action-type-hover;
border-color: @ui-action-type-hover;
color: @ui-action-type;
}
.umb-list-view-settings__remove-new {
font-size: 13px;
color: @red;
color: @red;
}
.umb-list-view-settings__settings {
border: 1px dashed @gray-7;
border-top: none;
padding: 20px;
// display `columns displayed` table as a list-view layout
.umb-list-view-settings__overlay {
.btn {
vertical-align: top;
}
.btn-icon {
padding: 0;
}
table {
width: 100%;
}
tbody tr {
background: @gray-10;
border-bottom: 1px solid #fff;
}
th {
text-align: left;
}
td {
padding: 10px 15px 10px 0;
&:first-child {
padding-left: 15px;
}
.ui-sortable-handle {
min-height: 37px;
display: flex;
width:0;
align-items: center;
}
}
}

View File

@@ -234,8 +234,46 @@
margin-left: 10px;
}
.form-horizontal .umb-nested-content--narrow .controls-row
{
.umb-nested-content__placeholder {
height: 22px;
padding: 4px 6px;
border: 1px dashed #d8d7d9;
background: 0 0;
cursor: pointer;
color: #1b264f;
-webkit-animation: fadeIn .5s;
animation: fadeIn .5s;
text-align: center;
&--selected {
border: 1px solid #d8d7d9;
text-align: left;
}
}
.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;
}

View File

@@ -203,9 +203,9 @@
.list-view-layout__name-text {
margin-right: 3px;
}
.list-view-layout__system {
font-size: 10px;
font-size: 10px;
font-weight: normal;
}
@@ -236,6 +236,8 @@
}
.list-view-add-layout {
width:100%;
background:0 0;
margin-top: 10px;
color: @ui-action-discreet-type;
border: 1px dashed @ui-action-discreet-border;

View File

@@ -116,8 +116,9 @@ h5.-black {
margin: 20px;
}
.umb-control-group {
border-bottom: 1px solid @gray-11;
padding-bottom: 20px;
border-bottom: 1px solid @gray-11;
padding-bottom: 20px;
padding-top: 20px;
}
.umb-control-group.-no-border {

View File

@@ -308,7 +308,14 @@
opacity: @opacity / 100;
}
// Position
.absolute() {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
}
// BACKGROUNDS
// --------------------------------------------------

View File

@@ -83,10 +83,6 @@
}
}
.umb-rte .mce-fullscreen {
position:absolute;
}
.umb-rte .mce-toolbar .mce-btn-group {
padding: 0;
}
@@ -165,3 +161,7 @@
border: 1px solid #d8d7d9;
max-width: none;
}
.mce-fullscreen {
position: absolute;
}

View File

@@ -118,6 +118,7 @@ ul.sections-tray {
text-decoration: none;
display: block;
position: relative;
outline: none;
&::after {
content: "";
@@ -131,6 +132,13 @@ ul.sections-tray {
top: 0;
left: 0;
}
&:focus .section__name {
.tabbing-active & {
border: 1px solid;
border-color: @gray-9;
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
(function () {
"use strict";
function CompositionsController($scope, $location, $filter, overlayService) {
function CompositionsController($scope, $location, $filter, overlayService, localizationService) {
var vm = this;
var oldModel = null;
@@ -68,19 +68,23 @@
or the confirm checkbox has been checked */
if (compositionRemoved) {
vm.allowSubmit = false;
const dialog = {
view: "views/common/infiniteeditors/compositions/overlays/confirmremove.html",
submitButtonLabelKey: "general_ok",
closeButtonLabelKey: "general_cancel",
submit: function (model) {
$scope.model.submit($scope.model);
overlayService.close();
},
close: function () {
overlayService.close();
}
};
overlayService.open(dialog);
localizationService.localize("general_remove").then(function(value) {
const dialog = {
view: "views/common/infiniteeditors/compositions/overlays/confirmremove.html",
title: value,
submitButtonLabelKey: "general_ok",
submitButtonStyle: "danger",
closeButtonLabelKey: "general_cancel",
submit: function (model) {
$scope.model.submit($scope.model);
overlayService.close();
},
close: function () {
overlayService.close();
}
};
overlayService.open(dialog);
});
return;
}

View File

@@ -1,6 +1,9 @@
<div>
<h5 class="red"><i class="icon-alert"></i>Warning</h5>
<p>Removing a composition will delete all the associated property data. Once you save the document type there's no way back, are you sure?</p>
<div class="umb-alert umb-alert--warning mb2">
<localize key="contentTypeEditor_compositionRemoveWarning"></localize>
</div>
<localize key="defaultdialogs_confirmSure"></localize>
</div>

View File

@@ -48,13 +48,14 @@
<li ng-repeat="systemDataType in value | orderBy:'name'"
data-element="editor-{{systemDataType.name}}"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)">
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
ng-click="vm.pickEditor(systemDataType)"
class="cursor-pointer">
<span class="umb-card-grid-item" title="{{ systemDataType.name }}">
<span>
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{ systemDataType.name }}
</span>
</a>
</span>
</li>
</ul>
</div>
@@ -66,16 +67,17 @@
<li ng-repeat="dataType in value | orderBy:'name'"
data-element="editor-{{dataType.name}}"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)">
ng-click="vm.pickDataType(dataType)"
class="cursor-pointer">
<div ng-if="dataType.loading" class="umb-card-grid-item__loading">
<div class="umb-button__progress"></div>
</div>
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
<span class="umb-card-grid-item" title="{{ dataType.name }}">
<span>
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{ dataType.name }}
</span>
</a>
</span>
</li>
</ul>
</div>
@@ -93,16 +95,17 @@
<ul class="umb-card-grid -four-in-row" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="dataType in result.dataTypes | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)">
ng-click="vm.pickDataType(dataType)"
class="cursor-pointer">
<div ng-if="dataType.loading" class="umb-card-grid-item__loading">
<div class="umb-button__progress"></div>
</div>
<a class="umb-card-grid-item" href="" title="{{dataType.name}}">
<span class="umb-card-grid-item" title="{{dataType.name}}">
<span>
<i class="{{dataType.icon}}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{dataType.name}}
</span>
</a>
</span>
</li>
</ul>
</div>
@@ -116,13 +119,14 @@
<ul class="umb-card-grid -four-in-row" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="systemDataType in result.dataTypes | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)">
<a class="umb-card-grid-item" href="" title="{{systemDataType.name}}">
ng-click="vm.pickEditor(systemDataType)"
class="cursor-pointer">
<span class="umb-card-grid-item" title="{{systemDataType.name}}">
<span>
<i class="{{systemDataType.icon}}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{systemDataType.name}}
</span>
</a>
</span>
</li>
</ul>
</div>

View File

@@ -23,6 +23,7 @@
placeholder="@general_url"
class="umb-property-editor umb-textstring"
ng-model="model.target.url"
umb-auto-focus
ng-disabled="model.target.id || model.target.udi" />
</umb-control-group>

View File

@@ -28,6 +28,7 @@ angular.module("umbraco")
var dialogOptions = $scope.model;
$scope.disableFolderSelect = (dialogOptions.disableFolderSelect && dialogOptions.disableFolderSelect !== "0") ? true : false;
$scope.disableFocalPoint = (dialogOptions.disableFocalPoint && dialogOptions.disableFocalPoint !== "0") ? true : false;
$scope.onlyImages = (dialogOptions.onlyImages && dialogOptions.onlyImages !== "0") ? true : false;
$scope.onlyFolders = (dialogOptions.onlyFolders && dialogOptions.onlyFolders !== "0") ? true : false;
$scope.showDetails = (dialogOptions.showDetails && dialogOptions.showDetails !== "0") ? true : false;
@@ -137,7 +138,8 @@ angular.module("umbraco")
$scope.target = node;
if (ensureWithinStartNode(node)) {
selectMedia(node);
$scope.target.url = mediaHelper.resolveFile(node);
$scope.target.url = mediaHelper.resolveFileFromEntity(node);
$scope.target.thumbnail = mediaHelper.resolveFileFromEntity(node, true);
$scope.target.altText = altText;
openDetailsDialog();
}
@@ -333,22 +335,26 @@ angular.module("umbraco")
}
function openDetailsDialog() {
localizationService.localize("defaultdialogs_editSelectedMedia").then(function (data) {
vm.mediaPickerDetailsOverlay = {
show: true,
title: data,
disableFocalPoint: $scope.disableFocalPoint,
submit: function (model) {
$scope.model.selection.push($scope.target);
$scope.model.submit($scope.model);
vm.mediaPickerDetailsOverlay = {
show: true,
submit: function (model) {
vm.mediaPickerDetailsOverlay.show = false;
vm.mediaPickerDetailsOverlay = null;
},
close: function (oldModel) {
vm.mediaPickerDetailsOverlay.show = false;
vm.mediaPickerDetailsOverlay = null;
$scope.model.selection.push($scope.target);
$scope.model.submit($scope.model);
vm.mediaPickerDetailsOverlay.show = false;
vm.mediaPickerDetailsOverlay = null;
},
close: function (oldModel) {
vm.mediaPickerDetailsOverlay.show = false;
vm.mediaPickerDetailsOverlay = null;
}
};
close();
}
};
});
};
var debounceSearchMedia = _.debounce(function () {

View File

@@ -1,198 +1,224 @@
<div ng-controller="Umbraco.Editors.MediaPickerController as vm">
<umb-editor-view >
<umb-editor-view >
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-container>
<umb-editor-container>
<form id="fileupload" method="POST" enctype="multipart/form-data" umb-image-upload="options">
<form id="fileupload" method="POST" enctype="multipart/form-data" umb-image-upload="options">
<div on-drag-leave="vm.dragLeave()" on-drag-end="vm.dragLeave()" on-drag-enter="vm.dragEnter()">
<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-mediapicker-upload">
<umb-load-indicator
ng-if="vm.loading">
</umb-load-indicator>
<umb-load-indicator
ng-if="vm.loading">
</umb-load-indicator>
<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"
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">
<label>
<input type="checkbox" ng-model="showChilds" ng-change="vm.toggle()" />
<localize key="general_includeFromsubFolders">Include subfolders in search</localize>
</label>
<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 class="upload-button">
<umb-button
type="button"
label-key="general_upload"
action="vm.upload()"
disabled="lockedFolder"
button-style="action">
</umb-button>
</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="row umb-control-group" ng-show="!vm.searchOptions.filter">
<ul class="umb-breadcrumbs">
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
<button type="button" class="umb-breadcrumbs__action" ng-click="vm.gotoFolder()">
<localize key="treeHeaders_media">Media</localize>
</button>
<span class="umb-breadcrumbs__separator" aria-hidden="true">&#47;</span>
</li>
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
<button type="button" class="umb-breadcrumbs__action" ng-click="vm.gotoFolder(item)">{{item.name}}</button>
<span class="umb-breadcrumbs__separator" aria-hidden="true">&#47;</span>
</li>
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
<button type="button" class="umb-breadcrumbs__action" ng-hide="model.showFolderInput" ng-click="model.showFolderInput = true">
<i class="icon icon-add small" aria-hidden="true"></i>
<span class="sr-only">
<localize key="visuallyHiddenTexts_createNewFolder">Create new folder</localize>
</span>
</button>
<input type="text"
class="umb-breadcrumbs__add-ancestor"
ng-show="model.showFolderInput"
ng-model="model.newFolderName"
ng-keydown="enterSubmitFolder($event)"
ng-blur="vm.submitFolder()"
focus-when="{{model.showFolderInput}}"
/>
</li>
</ul>
<div class="umb-loader" ng-if="model.creatingFolder"></div>
</div>
<umb-file-dropzone
ng-if="vm.acceptedMediatypes.length > 0 && !vm.loading && !lockedFolder"
accepted-mediatypes="vm.acceptedMediatypes"
parent-id="{{currentFolder.id}}"
files-uploaded="vm.onUploadComplete"
files-queued="vm.onFilesQueue"
accept="{{vm.acceptedFileTypes}}"
max-file-size="{{vm.maxFileSize}}"
hide-dropzone="{{ !activeDrag && (images.length > 0 || vm.searchOptions.filter !== '') }}"
compact="{{ images.length > 0 }}">
</umb-file-dropzone>
<umb-media-grid
ng-if="!vm.loading"
items="images"
on-click="vm.clickHandler"
on-click-name="vm.clickItemName"
on-click-edit="vm.editMediaItem(item)"
allow-on-click-edit="{{allowMediaEdit}}"
item-max-width="150"
item-max-height="150"
item-min-width="100"
item-min-height="100"
disable-folder-select={{disableFolderSelect}}
only-images={{onlyImages}}
only-folders={{onlyFolders}}
include-sub-folders={{showChilds}}
current-folder-id="{{currentFolder.id}}">
</umb-media-grid>
<div class="flex justify-center">
<umb-pagination
ng-if="vm.searchOptions.totalPages > 0 && !vm.loading"
page-number="vm.searchOptions.pageNumber"
total-pages="vm.searchOptions.totalPages"
on-change="vm.changePagination(pageNumber)">
</umb-pagination>
</div>
<umb-empty-state ng-if="vm.searchOptions.filter && images.length === 0 && !vm.loading && !activeDrag" position="center">
<localize key="general_searchNoResult"></localize>
</umb-empty-state>
</div>
<div class="row umb-control-group" ng-show="!vm.searchOptions.filter">
<ul class="umb-breadcrumbs">
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
<a href ng-click="vm.gotoFolder()" prevent-default><localize key="treeHeaders_media">Media</localize></a>
<span class="umb-breadcrumbs__separator">&#47;</span>
</li>
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
<a href ng-click="vm.gotoFolder(item)" prevent-default>{{item.name}}</a>
<span class="umb-breadcrumbs__separator">&#47;</span>
</li>
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
<a role="button" aria-label="Create new folder" ng-hide="model.showFolderInput" ng-click="model.showFolderInput = true">
<i class="icon icon-add small"></i>
</a>
<input type="text" class="umb-breadcrumbs__add-ancestor" ng-show="model.showFolderInput" ng-model="model.newFolderName" ng-keydown="enterSubmitFolder($event)"
ng-blur="vm.submitFolder()" focus-when="{{model.showFolderInput}}" />
</li>
</ul>
<div class="umb-loader" ng-if="model.creatingFolder"></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>
</h5>
<input type="text" localize="placeholder" placeholder="@general_url" class="umb-property-editor umb-textstring" ng-model="target.url" />
</div>
<umb-file-dropzone
ng-if="vm.acceptedMediatypes.length > 0 && !vm.loading && !lockedFolder"
accepted-mediatypes="vm.acceptedMediatypes"
parent-id="{{currentFolder.id}}"
files-uploaded="vm.onUploadComplete"
files-queued="vm.onFilesQueue"
accept="{{vm.acceptedFileTypes}}"
max-file-size="{{vm.maxFileSize}}"
hide-dropzone="{{ !activeDrag && (images.length > 0 || vm.searchOptions.filter !== '') }}"
compact="{{ images.length > 0 }}">
</umb-file-dropzone>
<umb-media-grid
ng-if="!vm.loading"
items="images"
on-click="vm.clickHandler"
on-click-name="vm.clickItemName"
on-click-edit="vm.editMediaItem(item)"
allow-on-click-edit="{{allowMediaEdit}}"
item-max-width="150"
item-max-height="150"
item-min-width="100"
item-min-height="100"
disable-folder-select={{disableFolderSelect}}
only-images={{onlyImages}}
only-folders={{onlyFolders}}
include-sub-folders={{showChilds}}
current-folder-id="{{currentFolder.id}}">
</umb-media-grid>
<div class="flex justify-center">
<umb-pagination
ng-if="vm.searchOptions.totalPages > 0 && !vm.loading"
page-number="vm.searchOptions.pageNumber"
total-pages="vm.searchOptions.totalPages"
on-change="vm.changePagination(pageNumber)">
</umb-pagination>
<div class="umb-control-group">
<h5>
<localize key="@content_altTextOptional"></localize>
</h5>
<input type="text" class="umb-property-editor umb-textstring" ng-model="target.altText" />
</div>
<umb-empty-state ng-if="vm.searchOptions.filter && images.length === 0 && !vm.loading && !activeDrag" position="center">
<localize key="general_searchNoResult"></localize>
</umb-empty-state>
</div>
<umb-overlay ng-if="vm.mediaPickerDetailsOverlay.show" model="vm.mediaPickerDetailsOverlay" position="right">
<div class="umb-control-group">
<div ng-if="target.url">
<umb-image-gravity
src="target.url"
center="target.focalPoint"
on-value-changed="vm.focalPointChanged(left, top)">
</umb-image-gravity>
</div>
<div ng-if="cropSize">
<div ng-if="vm.mediaPickerDetailsOverlay.disableFocalPoint && target.thumbnail">
<h5>
<localize key="general_preview">Preview</localize>
</h5>
<umb-image-thumbnail center="target.focalPoint"
src="target.url"
height="{{cropSize.height}}"
width="{{cropSize.width}}"
max-size="400">
</umb-image-thumbnail>
<img ng-src="{{target.thumbnail}}" alt="{{target.name}}" />
</div>
<div ng-if="!vm.mediaPickerDetailsOverlay.disableFocalPoint">
<h5>
<localize key="@general_focalPoint">Focal point</localize>
</h5>
<div ng-if="target.url">
<umb-image-gravity src="target.url"
center="target.focalPoint"
on-value-changed="vm.focalPointChanged(left, top)">
</umb-image-gravity>
</div>
<div ng-if="cropSize">
<h5>
<localize key="general_preview">Preview</localize>
</h5>
<umb-image-thumbnail center="target.focalPoint"
src="target.url"
height="{{cropSize.height}}"
width="{{cropSize.width}}"
max-size="400">
</umb-image-thumbnail>
</div>
</div>
</div>
</div>
</umb-overlay>
<div class="umb-control-group">
<label>
<localize key="@general_url"></localize>
</label>
<input type="text" localize="placeholder" placeholder="@general_url" class="umb-property-editor umb-textstring" ng-model="target.url"
ng-disabled="target.id" />
</div>
</form>
<div class="umb-control-group">
<label>
<localize key="@content_altTextOptional"></localize>
</label>
<input type="text" class="umb-property-editor umb-textstring" ng-model="target.altText" />
</div>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
</umb-overlay>
<umb-button
action="vm.close()"
button-style="link"
shortcut="esc"
label-key="general_close"
type="button">
</umb-button>
</form>
<umb-button
button-style="success"
label-key="buttons_select"
type="button"
disabled="model.selection.length === 0"
action="vm.submit(model)">
</umb-button>
</umb-editor-container>
</umb-editor-footer-content-right>
</umb-editor-footer>
<umb-editor-footer>
<umb-editor-footer-content-right>
</umb-editor-view>
<umb-button
action="vm.close()"
button-style="link"
shortcut="esc"
label-key="general_close"
type="button">
</umb-button>
<umb-button
button-style="success"
label-key="buttons_select"
type="button"
disabled="model.selection.length === 0"
action="vm.submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
</div>

View File

@@ -12,7 +12,9 @@
</li>
<li data-element="section-expand" class="expand" ng-class="{ 'open': showTray === true }" ng-show="needTray">
<a href ng-click="trayClick()"><i></i><i></i><i></i></a>
<a href="#" ng-click="trayClick()" prevent-default>
<span class="section__name"><i></i><i></i><i></i></span>
</a>
<ul id="applications-tray" class="sections-tray shadow-depth-2" ng-if="showTray" on-outside-click="trayClick()">
<li ng-repeat="section in sections | limitTo: overflowingSections" ng-class="{current: section.alias == currentSection}">

View File

@@ -31,6 +31,7 @@
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
ng-disabled="nameDisabled"
umb-auto-focus
focus-on-filled="true"
val-server-field="{{serverValidationNameField}}"
required
aria-required="true"

View File

@@ -35,6 +35,7 @@
ng-model="name"
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
umb-auto-focus
focus-on-filled="true"
val-server-field="Name"
required
autocomplete="off" />

View File

@@ -3,10 +3,11 @@
<div class="umb-editor"
ng-repeat="model in editors"
ng-class="{'umb-editor--small': model.size === 'small',
'umb-editor--medium': model.size === 'medium',
'umb-editor--animating': model.animating,
'--notInFront': model.inFront !== true,
'umb-editor--notInFront': model.inFront !== true,
'umb-editor--infiniteMode': model.infiniteMode,
'moveRight': model.moveRight,
'umb-editor--moveRight': model.moveRight,
'umb-editor--n0': model.styleIndex === 0,
'umb-editor--n1': model.styleIndex === 1,
'umb-editor--n2': model.styleIndex === 2,

View File

@@ -1,13 +1,13 @@
<ul role="tablist" class="umb-tabs-nav">
<li class="umb-tab" role="tab" aria-selected="true" tabindex="0" ng-repeat="tab in vm.tabs | limitTo: vm.maxTabs" data-element="tab-{{tab.alias}}" ng-class="{'umb-tab--active': tab.active, 'umb-tab--error': tabHasError}" val-tab>
<a ng-href="" ng-click="vm.clickTab($event, tab)">{{ tab.label }}</a>
<li ng-click="vm.clickTab($event, tab)" class="umb-tab" role="tab" aria-selected="true" tabindex="0" ng-repeat="tab in vm.tabs | limitTo: vm.maxTabs" data-element="tab-{{tab.alias}}" ng-class="{'umb-tab--active': tab.active, 'umb-tab--error': tabHasError}" val-tab>
<a>{{ tab.label }}</a>
</li>
<li data-element="tab-expand" class="umb-tab umb-tab--expand" ng-class="{ 'open': vm.showTray }" ng-show="vm.needTray">
<a ng-href="" ng-click="vm.toggleTray()"><i></i><i></i><i></i></a>
<li data-element="tab-expand" class="umb-tab umb-tab--expand" tabindex="0" ng-click="vm.toggleTray()" ng-class="{ 'open': vm.showTray }" ng-show="vm.needTray">
<a ng-href=""><i></i><i></i><i></i></a>
<umb-dropdown class="umb-tabs-tray" ng-if="vm.showTray" on-close="vm.hideTray()">
<umb-dropdown-item ng-repeat="tab in vm.tabs | limitTo: vm.overflowingTabs" ng-class="{'umb-tabs-tray-item--active': tab.active}">
<a ng-href="" href="" ng-click="vm.clickTab($event, tab)">{{ tab.label }}</a>
<umb-dropdown-item ng-repeat="tab in vm.tabs | limitTo: vm.overflowingTabs" ng-class="{'umb-tabs-tray-item--active': tab.active}" tabindex="0" ng-click="vm.clickTab($event, tab)">
<a ng-href="">{{ tab.label }}</a>
</umb-dropdown-item>
</umb-dropdown>
</li>

View File

@@ -1,5 +1,5 @@
<li class="umb-tree-item" data-element="tree-item-{{::node.dataElement}}" ng-class="getNodeCssClass(node)" on-right-click="altSelect(node, $event)">
<div class="umb-tree-item__inner" ng-swipe-right="options(node, $event)" ng-dblclick="load(node)" >
<div class="umb-tree-item__inner" ng-swipe-right="options(node, $event)" ng-dblclick="load(node)" tabindex="-1">
<button data-element="tree-item-expand"
class="umb-tree-item__arrow umb-outline btn-reset"
ng-class="{'icon-navigation-right': !node.expanded || node.metaData.isContainer, 'icon-navigation-down': node.expanded && !node.metaData.isContainer}"
@@ -9,7 +9,7 @@
<span class="sr-only">Expand child items for {{node.name}}</span>
</button>
<i class="icon umb-tree-icon sprTree" ng-class="::node.cssClass" title="{{::node.title}}" ng-click="select(node, $event)" ng-style="::node.style"></i>
<i class="icon umb-tree-icon sprTree" ng-class="::node.cssClass" title="{{::node.title}}" ng-click="select(node, $event)" ng-style="::node.style" tabindex="-1"></i>
<span class="umb-tree-item__annotation"></span>
<a class="umb-tree-item__label umb-outline" ng-href="#/{{::node.routePath}}" ng-click="select(node, $event)" title="{{::node.title}}">{{node.name}}</a>

View File

@@ -37,6 +37,8 @@
<localize key="contentTypeEditor_noGroups"></localize>
</div>
<a ng-if="!sortingMode" hotkey="alt+shift+p" ng-click="addPropertyToActiveGroup()"></a>
<ul class="umb-group-builder__groups" ui-sortable="sortableOptionsGroup" ng-model="model.groups">
<li ng-repeat="tab in model.groups" ng-class="{'umb-group-builder__group-sortable': sortingMode}" data-element="group-{{tab.name}}">
@@ -47,7 +49,7 @@
</a>
<!-- TAB ACTIVE OR INACTIVE STATE -->
<div class="umb-group-builder__group" ng-if="tab.tabState !== 'init'" ng-class="{'-active':tab.tabState=='active', '-inherited': tab.inherited, 'umb-group-builder__group-handle -sortable': sortingMode && !tab.inherited}" ng-click="activateGroup(tab)">
<div class="umb-group-builder__group" ng-if="tab.tabState !== 'init'" ng-class="{'-active':tab.tabState=='active', '-inherited': tab.inherited, 'umb-group-builder__group-handle -sortable': sortingMode && !tab.inherited}" tabindex="0" ng-focus="activateGroup(tab)">
<div class="umb-group-builder__group-title-wrapper">
@@ -119,8 +121,6 @@
data-element="property-add"
class="umb-group-builder__group-add-property"
ng-if="property.propertyState=='init' && !sortingMode"
hotkey="alt+shift+p"
hotkey-when="{{tab.tabState === 'active' && property.propertyState=='init'}}"
ng-click="addProperty(property, tab)"
ng-focus="activateGroup(tab)"
focus-when="{{property.focus}}">
@@ -135,7 +135,7 @@
<ng-form name="propertyTypeForm">
<div class="control-group -no-margin" ng-if="!sortingMode">
<div class="umb-group-builder__property-meta-alias" ng-if="property.inherited || property.locked">{{ property.alias }}</div>
<div class="umb-group-builder__property-meta-alias umb-locked-field__text cursor-not-allowed" style="padding-left: 1px" ng-if="property.inherited || property.locked">{{ property.alias }}</div>
<umb-locked-field
ng-if="!property.inherited && !property.locked"
locked="locked"

View File

@@ -0,0 +1,37 @@
<umb-editor-view>
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-description="model.hideDescription"
hide-icon="model.hideIcon">
</umb-editor-header>
<umb-editor-container class="umb-list-view-settings__overlay">
<form name="listViewSettingsForm" novalidate val-form-manager>
<umb-box>
<umb-box-content>
<!-- list view settings -->
<umb-property property="preValue" ng-repeat="preValue in model.dataType.preValues">
<umb-property-editor model="preValue" is-pre-value="true"></umb-property-editor>
</umb-property>
</umb-box-content>
</umb-box>
</form>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button
type="button"
button-style="link"
label-key="general_close"
action="model.close()">
</umb-button>
<umb-button
type="button"
button-style="success"
label-key="buttons_saveListView"
action="model.submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>

View File

@@ -9,35 +9,41 @@
</div>
<!-- list view enabled -->
<div ng-if="enableListView">
<div class="umb-list-view-settings__box" ng-class="{'-open': editDataTypeSettings}">
<div class="umb-list-view-settings__content">
<div ng-if="enableListView" class="flex">
<div class="umb-list-view-settings__box">
<div class="flex">
<i class="umb-list-view-settings__list-view-icon icon-list"></i>
<div>
<div>
<div class="umb-list-view-settings__name">{{ dataType.name }} <em ng-if="!customListViewCreated">(<localize key="general_default">default</localize>)</em></div>
<a href="" ng-click="toggleEditListViewDataTypeSettings()"><i class="umb-list-view-settings__settings-icon icon-settings"></i></a>
<div class="umb-list-view-settings__name">
{{ dataType.name }}
<em ng-if="!customListViewCreated">(<localize key="general_default">default</localize>)</em>
</div>
<a href="" class="umb-list-view-settings__create-new" ng-if="!customListViewCreated" ng-click="createCustomListViewDataType()"><localize key="editcontenttype_createListView">Create custom list view</localize></a>
<a href="" class="umb-list-view-settings__remove-new" ng-if="customListViewCreated" ng-click="removeCustomListDataType()"><localize key="editcontenttype_removeListView">Remove custom list view</localize></a>
<button
type="button"
class="btn-link umb-list-view-settings__create-new"
ng-if="!customListViewCreated"
ng-click="createCustomListViewDataType()">
<localize key="editcontenttype_createListView">Create custom list view</localize>
</button>
<button
type="button"
class="btn-link umb-list-view-settings__remove-new"
ng-if="customListViewCreated"
ng-click="removeCustomListDataType()">
<localize key="editcontenttype_removeListView">Remove custom list view</localize>
</button>
</div>
</div>
</div>
<!-- list view settings -->
<div class="umb-list-view-settings__settings form-horizontal" ng-if="editDataTypeSettings" ng-class="{'-open': editDataTypeSettings}">
<umb-property property="preValue" ng-repeat="preValue in dataType.preValues">
<umb-property-editor model="preValue" is-pre-value="true"></umb-property-editor>
</umb-property>
<div class="text-right">
<button type="button" class="btn btn-link" ng-click="toggleEditListViewDataTypeSettings()"><localize key="general_close">Close</localize></button>
<button type="button" class="btn btn-success" ng-click="saveListViewDataType()"><localize key="buttons_saveListView"></localize></button>
<umb-load-indicator ng-show="loading"></umb-load-indicator>
</div>
<div class="umb-group-builder__property-actions">
<div class="umb-group-builder__property-action">
<button
class="btn-icon icon-settings"
ng-click="showSettingsOverlay()"
aria-label="Edit"></button>
</div>
</div>
</div>
</div>

View File

@@ -4,7 +4,6 @@
function ContentSortController($scope, $filter, $routeParams, contentResource, navigationService) {
var vm = this;
var parentId = $scope.currentNode.parentId ? $scope.currentNode.parentId : "-1";
var id = $scope.currentNode.id;
vm.loading = false;
@@ -42,7 +41,7 @@
vm.saveButtonState = "busy";
var args = {
parentId: parentId,
parentId: id,
sortedIds: _.map(vm.children, function(child){ return child.id; })
};

View File

@@ -24,8 +24,6 @@
text="{{ variant.language.name }}"
/>
<div>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db umb-list-item__description umb-list-item__description--checkbox" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - </span>

View File

@@ -48,8 +48,6 @@
<div>
<span class="db umb-list-item__description umb-list-item__description--checkbox" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<span>{{variant.language.name}}</span>
<span class="db umb-list-item__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
@@ -60,6 +58,7 @@
</span>
<umb-variant-notification-list notifications="variant.notifications"></umb-variant-notification-list>
</span>
</div>
</div>

View File

@@ -29,10 +29,9 @@
/>
<div>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-list-item__description umb-list-item__description--checkbox" variant="variant"></umb-variant-state>
<span class="db umb-list-item__description umb-list-item__description--checkbox" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
<span class="db" ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>

View File

@@ -24,10 +24,9 @@
/>
<div>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-list-item__description umb-list-item__description--checkbox" variant="variant"></umb-variant-state>
<span class="db umb-list-item__description umb-list-item__description--checkbox" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>

View File

@@ -177,7 +177,7 @@
</umb-dropdown-item>
<umb-dropdown-item>
<a ng-href="https://www.google.co.uk/?q=site:our.umbraco.org {{ log.RenderedMessage }}&safe=off#q=site:our.umbraco.org {{ log.RenderedMessage }} {{ log.Properties['SourceContext'].Value }}&safe=off" target="_blank" title="Search Our Umbraco forums using Google">
<a ng-href="https://www.google.co.uk/?q=site:our.umbraco.com {{ log.RenderedMessage }}&safe=off#q=site:our.umbraco.com {{ log.RenderedMessage }} {{ log.Properties['SourceContext'].Value }}&safe=off" target="_blank" title="Search Our Umbraco forums using Google">
<img src="https://www.google.com/favicon.ico" width="16" height="16" /> Search Our Umbraco with Google
</a>
</umb-dropdown-item>

View File

@@ -4,7 +4,6 @@
function MediaSortController($scope, $filter, mediaResource, navigationService) {
var vm = this;
var parentId = $scope.currentNode.parentId ? $scope.currentNode.parentId : "-1";
var id = $scope.currentNode.id;
vm.loading = false;
@@ -42,7 +41,7 @@
vm.saveButtonState = "busy";
var args = {
parentId: parentId,
parentId: id,
sortedIds: _.map(vm.children, function(child){ return child.id; })
};

View File

@@ -28,6 +28,7 @@
view: "views/packages/overlays/delete.html",
package: createdPackage,
submitButtonLabelKey: "contentTypeEditor_yesDelete",
submitButtonStyle:"danger",
submit: function (model) {
performDelete(index, createdPackage);
overlayService.close();

View File

@@ -187,7 +187,7 @@
<div class="umb-package-details__owner-profile-avatar">
<umb-avatar
size="m"
img-src="{{ 'https://our.umbraco.org' + vm.package.ownerInfo.ownerAvatar }}">
img-src="{{ 'https://our.umbraco.com' + vm.package.ownerInfo.ownerAvatar }}">
</umb-avatar>
</div>

View File

@@ -69,9 +69,17 @@
}).then(function (saved) {
// create macro if needed
if($routeParams.create && $routeParams.nomacro !== "true") {
macroResource.createPartialViewMacroWithFile(saved.virtualPath, saved.name).then(function(created) {
macroResource.createPartialViewMacroWithFile(saved.virtualPath, saved.name).then(function (created) {
navigationService.syncTree({
tree: "macros",
path: '-1,new',
forceReload: true,
activate: false
});
completeSave(saved);
}, angular.noop);
} else {
completeSave(saved);
}

View File

@@ -42,6 +42,11 @@ function TreeSourceTypePickerController($scope, contentTypeResource, mediaTypeRe
var editor = {
multiPicker: true,
filterCssClass: "not-allowed not-published",
filter: function (item) {
// filter out folders (containers), element types (for content) and already selected items
return item.nodeType === "container" || item.metaData.isElement || !!_.findWhere(vm.itemTypes, { udi: item.udi });
},
submit: function (model) {
var newItemTypes = _.map(model.selection,
function(selected) {

View File

@@ -2,24 +2,24 @@
<div class="control-group">
<select ng-model="selectedField" ng-change="changeField()" val-highlight="{{hasError}}">
<option ng-repeat="field in systemFields" value="_system_{{field.value}}">{{field.name}}</option>
<option ng-repeat="field in systemFields" value="_system_{{field.value}}" ng-bind="field.name"></option>
<option class="select-dash" disabled="disabled">----</option>
<option ng-repeat="alias in propertyAliases" value="{{alias}}">{{alias}}</option>
<option ng-repeat="alias in propertyAliases" value="{{alias}}" ng-bind="alias"></option>
</select>
<button type="button" class="btn" ng-click="addField()">
<localize key="general_add">Add</localize>
</button>
<span class="help-inline">{{errorMsg}}</span>
<span class="help-inline" ng-bind="errorMsg"</span>
</div>
<div class="control-group">
<table ng-show="model.value.length > 0" class="table">
<table ng-show="model.value.length > 0">
<thead>
<tr>
<td style="width:20px;"></td>
<th style="width:220px;">Alias</th>
<td></td>
<th>Alias</th>
<th>Header</th>
<th><localize key="template_template">Template</localize></th>
<td style="width:100px;"></td>
<td></td>
</tr>
</thead>
<tbody ui-sortable="sortableOptions" ng-model="model.value">
@@ -28,11 +28,11 @@
<i class="icon icon-navigation handle"></i>
</td>
<td>
<span class="alias-value" ng-if="!val.isSystem">{{val.alias}}</span>
<span class="alias-value" ng-if="val.isSystem == 1">
{{val.alias}}
</span>
<em ng-show="val.isSystem == 1"><small>(system field)</small></em>
<div class="list-view-layout__name flex-column content-start">
<span class="list-view-layout__name-text" ng-if="!val.isSystem" ng-bind="val.alias"></span>
<span class="list-view-layout__name-text" ng-if="val.isSystem == 1" ng-bind="val.alias"></span>
<span class="list-view-layout__system" ng-show="val.isSystem == 1">(system field)</span>
</div>
</td>
<td>
<ng-form name="headerForm" ng-if="!val.isSystem">
@@ -52,7 +52,7 @@
</ng-form>
</td>
<td>
<button type="button" class="btn btn-danger" ng-click="removeField(val)">Remove</button>
<button type="button" class="btn-icon icon-trash" ng-click="removeField(val)" aria-label="Remove"></button>
</td>
</tr>
</tbody>

View File

@@ -4,13 +4,13 @@
<div class="list-view-layout" ng-repeat="layout in model.value">
<i class="icon-navigation list-view-layout__sort-handle"></i>
<i class="icon-navigation list-view-layout__sort-handle" aria-label="Sort"></i>
<div>
<a ng-if="layout.isSystem !== 1" href="" ng-click="vm.openIconPicker(layout)" class="list-view-layout__icon" umb-auto-focus>
<button ng-if="layout.isSystem !== 1" type="button" ng-click="vm.openIconPicker(layout)" class="list-view-layout__icon" umb-auto-focus>
<i class="{{ layout.icon }}"></i>
</a>
</button>
<div ng-if="layout.isSystem === 1" class="list-view-layout__icon">
<i class="{{ layout.icon }}"></i>
@@ -29,7 +29,7 @@
</div>
<div>
<input ng-if="layout.isSystem === 1" type="checkbox" ng-model="layout.selected" />
<umb-checkbox ng-if="layout.isSystem === 1" model="layout.selected" />
<div class="list-view-layout__remove" ng-if="layout.isSystem !== 1">
<i class="icon-trash" ng-click="vm.showPrompt(layout)"></i>
<umb-confirm-action
@@ -43,7 +43,7 @@
</div>
<a href="" class="list-view-add-layout" ng-click="vm.addLayout()">Add layout</a>
<button type="button" class="list-view-add-layout" ng-click="vm.addLayout()">Add layout</button>
</div>

View File

@@ -1,15 +1,9 @@
<div>
<ng-form name="listViewOrderDirectionForm">
<label class="radio">
<input type="radio" name="orderDirection" value="asc" ng-model="model.value" />
Ascending <code>[a-z]</code>
</label>
<label class="radio">
<input type="radio" name="orderDirection" value="desc" ng-model="model.value" />
Descending <code>[z-a]</code>
</label>
<ng-form name="listViewOrderDirectionForm" class="flex">
<umb-radiobutton name="orderDirection" value="asc" model="model.value" text="Ascending [a-z]" required></umb-radiobutton>
<umb-radiobutton name="orderDirection" value="desc" model="model.value" text="Descending [z-a]" required></umb-radiobutton>
<span ng-messages="listViewOrderDirectionForm.orderDirection.$error" show-validation-on-submit >
<span ng-messages="listViewOrderDirectionForm.orderDirection.$error" show-validation-on-submit>
<span class="help-inline" ng-message="required">Required</span>
</span>
</ng-form>

View File

@@ -2,8 +2,46 @@
"$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 + ")";
}
});
});
}
function ($scope, ncResources) {
$scope.add = function () {
$scope.model.value.push({
@@ -57,42 +95,66 @@
}
};
$scope.docTypeTabs = {};
ncResources.getContentTypes().then(function (docTypes) {
$scope.model.docTypes = docTypes;
// Count doctype name occurrences
var docTypeNameOccurrences = _.countBy(docTypes, 'name');
// Populate document type tab dictionary
// And append alias to name if multiple doctypes have the same name
docTypes.forEach(function (value) {
$scope.docTypeTabs[value.alias] = value.tabs;
value.displayName = value.name;
if (docTypeNameOccurrences[value.name] > 1) {
value.displayName += " (" + value.alias + ")";
}
$scope.placeholder = function (config) {
return _.find($scope.model.elemTypes, function (elType) {
return elType.alias === config.ncAlias;
});
});
}
$scope.selectableDocTypesFor = function (config) {
// return all doctypes that are:
$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.docTypes, function (docType) {
return docType.alias === config.ncAlias || !_.find($scope.model.value, function(c) {
return docType.alias === c.ncAlias;
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();
}
}
]);
@@ -141,7 +203,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
$scope.hasContentTypes = $scope.model.config.contentTypes.length > 0;
$scope.labels = {};
localizationService.localizeMany(["grid_addElement", "content_createEmpty"]).then(function(data) {
localizationService.localizeMany(["grid_addElement", "content_createEmpty"]).then(function (data) {
$scope.labels.grid_addElement = data[0];
$scope.labels.content_createEmpty = data[1];
});
@@ -179,14 +241,14 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
$scope.overlayMenu.show = false;
$scope.overlayMenu = null;
},
submit: function(model) {
if(model && model.selectedItem) {
submit: function (model) {
if (model && model.selectedItem) {
$scope.addNode(model.selectedItem.alias);
}
$scope.overlayMenu.show = false;
$scope.overlayMenu = null;
},
close: function() {
close: function () {
$scope.overlayMenu.show = false;
$scope.overlayMenu = null;
}
@@ -218,22 +280,22 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
icon: iconHelper.convertFromLegacyIcon(node.icon)
});
});
$scope.overlayMenu.title = $scope.overlayMenu.pasteItems.length > 0 ? $scope.labels.grid_addElement : $scope.labels.content_createEmpty;
$scope.overlayMenu.clickClearPaste = function($event) {
$scope.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.
};
if ($scope.overlayMenu.availableItems.length === 1 && $scope.overlayMenu.pasteItems.length === 0) {
// only one scaffold type - no need to display the picker
$scope.addNode($scope.scaffolds[0].contentTypeAlias);
return;
}
$scope.overlayMenu.show = true;
};
@@ -324,10 +386,10 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
if ($scope.nodes[idx].name !== name) {
$scope.nodes[idx].name = name;
}
return name;
};
$scope.getIcon = function (idx) {
var scaffold = $scope.getScaffold($scope.model.value[idx].ncContentTypeAlias);
return scaffold && scaffold.icon ? iconHelper.convertFromLegacyIcon(scaffold.icon) : "icon-folder";
@@ -335,7 +397,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
$scope.sortableOptions = {
axis: "y",
cursor: "move",
handle:'.umb-nested-content__header-bar',
handle: '.umb-nested-content__header-bar',
distance: 10,
opacity: 0.7,
tolerance: "pointer",
@@ -377,15 +439,15 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
return contentType.ncAlias === alias;
});
}
$scope.showCopy = clipboardService.isSupported();
$scope.showPaste = false;
$scope.clickCopy = function($event, node) {
$scope.clickCopy = function ($event, node) {
syncCurrentNode();
clipboardService.copy("elementType", node.contentTypeAlias, node);
$event.stopPropagation();
}
@@ -395,27 +457,27 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
if (newNode === undefined) {
return;
}
// generate a new key.
newNode.key = String.CreateGuid();
$scope.nodes.push(newNode);
$scope.setDirty();
//updateModel();// done by setting current node...
$scope.currentNode = newNode;
}
function checkAbilityToPasteContent() {
$scope.showPaste = clipboardService.hasEntriesOfType("elementType", contentTypeAliases);
}
eventsService.on("clipboardService.storageUpdate", checkAbilityToPasteContent);
var notSupported = [
"Umbraco.Tags",
"Umbraco.UploadField",
"Umbraco.ImageCropper"
"Umbraco.Tags",
"Umbraco.UploadField",
"Umbraco.ImageCropper"
];
// Initialize
@@ -495,24 +557,24 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
}
$scope.inited = true;
checkAbilityToPasteContent();
}
}
function createNode(scaffold, fromNcEntry) {
var node = angular.copy(scaffold);
node.key = fromNcEntry && fromNcEntry.key ? fromNcEntry.key : String.CreateGuid();
var variant = node.variants[0];
for (var t = 0; t < variant.tabs.length; t++) {
var tab = variant.tabs[t];
for (var p = 0; p < tab.properties.length; p++) {
var prop = tab.properties[p];
prop.propertyAlias = prop.alias;
prop.alias = $scope.model.alias + "___" + prop.alias;
// Force validation to occur server side as this is the
@@ -522,7 +584,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
mandatory: false,
pattern: ""
};
if (fromNcEntry && fromNcEntry[prop.propertyAlias]) {
prop.value = fromNcEntry[prop.propertyAlias];
}
@@ -533,7 +595,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
return node;
}
function convertNodeIntoNCEntry(node) {
var obj = {
key: node.key,
@@ -551,16 +613,16 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
}
return obj;
}
function syncCurrentNode() {
if ($scope.realCurrentNode) {
$scope.$broadcast("ncSyncVal", { key: $scope.realCurrentNode.key });
}
}
function updateModel() {
syncCurrentNode();
if ($scope.inited) {
var newValues = [];
for (var i = 0; i < $scope.nodes.length; i++) {
@@ -582,7 +644,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
$scope.$on("$destroy", function () {
unsubscribe();
});
}
]);

View File

@@ -3,7 +3,7 @@
<table class="table table-striped">
<thead>
<tr>
<th/>
<th />
<th>
<localize key="contentTypeEditor_elementType">Element Type</localize>
</th>
@@ -22,14 +22,22 @@
<i class="icon icon-navigation handle"></i>
</td>
<td>
<select id="{{model.alias}}_doctype_select"
ng-options="dt.alias as dt.displayName for dt in selectableDocTypesFor(config) | orderBy: 'name'"
ng-model="config.ncAlias" required></select>
{{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>
<localize key="content_nestedContentAddElementType" ng-if="!ph">Add element type</localize>
</div>
</td>
<td>
<select id="{{model.alias}}_tab_select"
ng-options="t for t in docTypeTabs[config.ncAlias]"
ng-model="config.ncTabAlias" required></select>
ng-options="t for t in elemTypeTabs[config.ncAlias]"
ng-model="config.ncTabAlias" required></select>
</td>
<td>
<input type="text" ng-model="config.nameTemplate" />
@@ -49,15 +57,15 @@
<i class="icon icon-help-alt medium umb-nested-content__help-icon" ng-click="showHelpText = !showHelpText"></i>
</div>
</div>
<br/>
<br />
<div class="umb-nested-content__help-text" ng-show="showHelpText">
<p>
<b><localize key="general_group">Group</localize>:</b><br/>
<b><localize key="general_group">Group</localize>:</b><br />
Select the group whose properties should be displayed. If left blank, the first group on the element type will be used.
</p>
<p>
<b><localize key="template_template">Template</localize>:</b><br/>
Enter an angular expression to evaluate against each item for its name. Use <code ng-non-bindable>{{$index}}</code> to display the item index
<b><localize key="template_template">Template</localize>:</b><br />
Enter an angular expression to evaluate against each item for its name. Use <code ng-non-bindable>{{$index}}</code> to display the item index
</p>
</div>
</div>

View File

@@ -105,6 +105,7 @@
var sectionPicker = {
selection: currentSelection,
submit: function (model) {
vm.userGroup.sections = model.selection;
editorService.close();
},
close: function () {
@@ -168,7 +169,8 @@
angular.copy(vm.userGroup.users, currentSelection);
var userPicker = {
selection: currentSelection,
submit: function () {
submit: function (model) {
vm.userGroup.users = model.selection;
editorService.close();
},
close: function () {

View File

@@ -71,6 +71,7 @@
sections="userGroup.sections"
content-start-node="userGroup.contentStartNode"
media-start-node="userGroup.mediaStartNode"
allow-remove="true"
on-remove="model.removeSelectedItem($index, model.user.userGroups)">
</umb-user-group-preview>

View File

@@ -359,6 +359,8 @@
<localize key="general_add">Add</localize>
</a>
<input type="hidden" ng-model="vm.newUser.userGroupsValidation" ng-required="!vm.newUser.userGroups.length" />
</umb-control-group>
<umb-control-group label="@general_message" ng-if="vm.usersViewState === 'inviteUser'" label-for="message" required="true">

View File

@@ -13,7 +13,7 @@ var app = angular.module('umbraco', [
'ngSanitize',
//'ngMessages',
'tmh.dynamicLocale',
'tmh.dynamicLocale'
//'ngFileUpload',
//'LocalStorageModule',
//'chart.js'

View File

@@ -51,9 +51,23 @@ module.exports = function (config) {
exclude: [],
// use dolts reporter, as travis terminal does not support escaping sequences
// possible values: 'dots', 'progress', 'junit', 'teamcity'
// possible values: 'dots', 'progress', 'junit', 'spec'
// ***
// progress: Outputs a simple list like: "Executed 128 of 144 SUCCESS (0 secs / 0.814 secs)"
// spec: Outputs a more verbose report which is more useful for debugging if one of the tests fails.
// ***
// CLI --reporters progress
reporters: ['progress', 'junit'],
reporters: ['spec', 'junit'],
specReporter: {
maxLogLines: 5, // limit number of lines logged per test
suppressErrorSummary: true, // do not print error summary
suppressFailed: false, // do not print information about failed tests
suppressPassed: false, // do not print information about passed tests
suppressSkipped: true, // do not print information about skipped tests
showSpecTiming: false // print the time elapsed for each spec
},
// web server port
// CLI --port 9876
@@ -102,7 +116,9 @@ module.exports = function (config) {
plugins: [
require('karma-jasmine'),
require('karma-phantomjs-launcher'),
require('karma-junit-reporter')
require('karma-junit-reporter'),
require('karma-spec-reporter')
],
// the default configuration

View File

@@ -37,7 +37,7 @@ describe('Drop down controller tests', function () {
$routeParams: routeParams
});
//this should be the expected format based on the changes made to the sortable prevalues
// this should be the expected format based on the changes made to the sortable prevalues
expect(scope.model.config.items[0].value).toBe("value0");
expect(scope.model.config.items[1].value).toBe("value1");
expect(scope.model.config.items[2].value).toBe("value2");

View File

@@ -0,0 +1,69 @@
(function () {
describe('truncate filter', function() {
var $truncate;
var testCases = [
{input:'test', noOfChars:5, appendDots:true, expectedResult: 'test'},
{input:'test ', noOfChars:4, appendDots:true, expectedResult: 'test…'},
{input:'test a long text with space', noOfChars:5, appendDots:true, expectedResult: 'test …'},
{input:'scenarios is a long word', noOfChars:5, appendDots:true, expectedResult: 'scena…'},
{input:'scenarios is a long word', noOfChars:10, appendDots:true, expectedResult: 'scenarios …'},
{input:'test', noOfChars:5, appendDots:false, expectedResult: 'test'},
{input:'test a long text with space', noOfChars:5, appendDots:false, expectedResult: 'test '},
{input:'scenarios is a long word', noOfChars:5, appendDots:false, expectedResult: 'scena'},
{input:'scenarios is a long word', noOfChars:10, appendDots:false, expectedResult: 'scenarios '}
];
var testCasesNew = [
{value:'test', wordwise:false, max:20, tail:'...', expectedResult: 'test'},
{value:'LoremIpsumLoremIpsumLoremIpsum',wordwise:false, max:20, tail:null, expectedResult: 'LoremIpsumLoremIpsum…'}
];
beforeEach(module('umbraco'));
beforeEach(inject(function($filter) {
$truncate = $filter('truncate');
}));
it('empty string as input is expected to give an empty string', function() {
expect($truncate('', 5, true)).toBe('');
});
it('null as input is expected to give an empty string', function() {
expect($truncate(null, 5, true)).toBe('');
});
it('undefined as input is expected to give an empty string', function() {
expect($truncate(undefined, 5, true)).toBe('');
});
it('null as noOfChars to result in \'test\'', function() {
expect($truncate('test', null, true)).toBe('test');
});
it('undefined as noOfChars to result in \'test\'', function() {
expect($truncate('test', undefined, true)).toBe('test');
});
it('null as appendDots to behave as false', function() {
expect($truncate('test', 5, null)).toBe('test');
});
testCases.forEach(function(test){
it('Expects \'' + test.input + '\' to be truncated as \''+ test.expectedResult + '\', when noOfChars=' + test.noOfChars + ', and appendDots=' + test.appendDots, function() {
console.log($truncate(test.input, test.noOfChars, test.appendDots));
expect($truncate(test.input, test.noOfChars, test.appendDots)).toBe(test.expectedResult);
});
});
testCasesNew.forEach(function(test){
it('Expects \'' + test.value + '\' to be truncated as \''+ test.expectedResult + '\', when wordwise=' + test.wordwise + ', and max=' + test.max + ', and tail=' + test.tail, function() {
expect($truncate(test.value, test.wordwise, test.max, test.tail)).toBe(test.expectedResult);
});
});
});
}());