Merge remote-tracking branch 'origin/temp8' into temp8-logviewer

# Conflicts:
#	src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs
#	src/Umbraco.Web.UI.Client/gulpfile.js
#	src/Umbraco.Web.UI/config/trees.Release.config
#	src/Umbraco.Web.UI/config/trees.config
This commit is contained in:
Warren Buckley
2019-01-21 11:17:14 +00:00
690 changed files with 12673 additions and 20562 deletions

View File

@@ -0,0 +1,52 @@
'use strict';
module.exports = {
sources: {
//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" }
},
//js files for backoffie
//processed in the js task
js: {
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
controllers: { files: ["./src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" },
directives: { files: ["./src/common/directives/**/*.js"], out: "umbraco.directives.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" }
},
//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/"}
},
//globs for file-watching
globs:{
views: "./src/views/**/*.html",
less: "./src/less/**/*.less",
js: "./src/*.js",
lib: "./lib/**/*",
assets: "./src/assets/**"
}
},
root: "../Umbraco.Web.UI/Umbraco/",
targets: {
js: "js/",
lib: "lib/",
views: "views/",
css: "assets/css/",
assets: "assets/"
}
};

View File

@@ -0,0 +1,10 @@
'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

@@ -0,0 +1,10 @@
'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(["dependencies", "js", "less", "views"], cb);
});

View File

@@ -0,0 +1,288 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var MergeStream = require('merge-stream');
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 () {
//as we do multiple things in this task, we merge the multiple streams
var stream = new MergeStream();
// Pick the dependencies we need from each package
// so we don't just ship with a lot of files that aren't needed
const nodeModules = [
{
"name": "ace-builds",
"src": [
"./node_modules/ace-builds/src-min-noconflict/ace.js",
"./node_modules/ace-builds/src-min-noconflict/ext-language_tools.js",
"./node_modules/ace-builds/src-min-noconflict/ext-searchbox.js",
"./node_modules/ace-builds/src-min-noconflict/ext-settings_menu.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/text.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/javascript.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/css.js",
"./node_modules/ace-builds/src-min-noconflict/theme-chrome.js",
"./node_modules/ace-builds/src-min-noconflict/mode-razor.js",
"./node_modules/ace-builds/src-min-noconflict/mode-javascript.js",
"./node_modules/ace-builds/src-min-noconflict/mode-css.js",
"./node_modules/ace-builds/src-min-noconflict/worker-javascript.js",
"./node_modules/ace-builds/src-min-noconflict/worker-css.js"
],
"base": "./node_modules/ace-builds"
},
{
"name": "angular",
"src": ["./node_modules/angular/angular.js"],
"base": "./node_modules/angular"
},
{
"name": "angular-cookies",
"src": ["./node_modules/angular-cookies/angular-cookies.js"],
"base": "./node_modules/angular-cookies"
},
{
"name": "angular-dynamic-locale",
"src": [
"./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js",
"./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js.map"
],
"base": "./node_modules/angular-dynamic-locale/dist"
},
{
"name": "angular-sanitize",
"src": ["./node_modules/angular-sanitize/angular-sanitize.js"],
"base": "./node_modules/angular-sanitize"
},
{
"name": "angular-touch",
"src": ["./node_modules/angular-touch/angular-touch.js"],
"base": "./node_modules/angular-touch"
},
{
"name": "angular-ui-sortable",
"src": ["./node_modules/angular-ui-sortable/dist/sortable.js"],
"base": "./node_modules/angular-ui-sortable/dist"
},
{
"name": "angular-route",
"src": ["./node_modules/angular-route/angular-route.js"],
"base": "./node_modules/angular-route"
},
{
"name": "angular-animate",
"src": ["./node_modules/angular-animate/angular-animate.js"],
"base": "./node_modules/angular-animate"
},
{
"name": "angular-i18n",
"src": [
"./node_modules/angular-i18n/angular-i18n.js",
"./node_modules/angular-i18n/angular-locale_*.js"
],
"base": "./node_modules/angular-i18n"
},
{
"name": "angular-local-storage",
"src": [
"./node_modules/angular-local-storage/dist/angular-local-storage.min.js",
"./node_modules/angular-local-storage/dist/angular-local-storage.min.js.map"
],
"base": "./node_modules/angular-local-storage/dist"
},
{
"name": "angular-messages",
"src": ["./node_modules/angular-messages/angular-messages.js"],
"base": "./node_modules/angular-messages"
},
{
"name": "angular-mocks",
"src": ["./node_modules/angular-mocks/angular-mocks.js"],
"base": "./node_modules/angular-mocks"
},
{
"name": "animejs",
"src": ["./node_modules/animejs/anime.min.js"],
"base": "./node_modules/animejs"
},
{
"name": "bootstrap-social",
"src": ["./node_modules/bootstrap-social/bootstrap-social.css"],
"base": "./node_modules/bootstrap-social"
},
{
"name": "angular-chart.js",
"src": ["./node_modules/angular-chart.js/dist/angular-chart.min.js"],
"base": "./node_modules/angular-chart.js/dist"
},
{
"name": "chart.js",
"src": ["./node_modules/chart.js/dist/chart.min.js"],
"base": "./node_modules/chart.js/dist"
},
{
"name": "clipboard",
"src": ["./node_modules/clipboard/dist/clipboard.min.js"],
"base": "./node_modules/clipboard/dist"
},
{
"name": "jsdiff",
"src": ["./node_modules/diff/dist/diff.min.js"],
"base": "./node_modules/diff/dist"
},
{
"name": "flatpickr",
"src": [
"./node_modules/flatpickr/dist/flatpickr.js",
"./node_modules/flatpickr/dist/flatpickr.css"
],
"base": "./node_modules/flatpickr/dist"
},
{
"name": "font-awesome",
"src": [
"./node_modules/font-awesome/fonts/*",
"./node_modules/font-awesome/css/font-awesome.min.css"
],
"base": "./node_modules/font-awesome"
},
{
"name": "jquery",
"src": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery/dist/jquery.min.map"
],
"base": "./node_modules/jquery/dist"
},
{
"name": "jquery-ui",
"src": ["./node_modules/jquery-ui-dist/jquery-ui.min.js"],
"base": "./node_modules/jquery-ui-dist"
},
{
"name": "jquery-ui-touch-punch",
"src": ["./node_modules/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js"],
"base": "./node_modules/jquery-ui-touch-punch"
},
{
"name": "lazyload-js",
"src": ["./node_modules/lazyload-js/lazyload.min.js"],
"base": "./node_modules/lazyload-js"
},
{
"name": "moment",
"src": ["./node_modules/moment/min/moment.min.js"],
"base": "./node_modules/moment/min"
},
{
"name": "moment",
"src": ["./node_modules/moment/locale/*.js"],
"base": "./node_modules/moment/locale"
},
{
"name": "ng-file-upload",
"src": ["./node_modules/ng-file-upload/dist/ng-file-upload.min.js"],
"base": "./node_modules/ng-file-upload/dist"
},
{
"name": "nouislider",
"src": [
"./node_modules/nouislider/distribute/nouislider.min.js",
"./node_modules/nouislider/distribute/nouislider.min.css"
],
"base": "./node_modules/nouislider/distribute"
},
{
"name": "signalr",
"src": ["./node_modules/signalr/jquery.signalR.js"],
"base": "./node_modules/signalr"
},
{
"name": "spectrum",
"src": [
"./node_modules/spectrum-colorpicker/spectrum.js",
"./node_modules/spectrum-colorpicker/spectrum.css"
],
"base": "./node_modules/spectrum-colorpicker"
},
{
"name": "tinymce",
"src": [
"./node_modules/tinymce/tinymce.min.js",
"./node_modules/tinymce/plugins/**",
"./node_modules/tinymce/skins/**",
"./node_modules/tinymce/themes/**"
],
"base": "./node_modules/tinymce"
},
{
"name": "typeahead.js",
"src": ["./node_modules/typeahead.js/dist/typeahead.bundle.min.js"],
"base": "./node_modules/typeahead.js/dist"
},
{
"name": "underscore",
"src": ["node_modules/underscore/underscore-min.js"],
"base": "./node_modules/underscore"
}
];
// add streams for node modules
nodeModules.forEach(module => {
stream.add(
gulp.src(module.src,
{ base: module.base })
.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)
.pipe(gulp.dest(config.root + config.targets.lib))
);
//Copies all static assets into /root / assets folder
//css, fonts and image files
stream.add(
gulp.src(config.sources.globs.assets)
.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({
plugins: [
{removeViewBox: true},
{cleanupIDs: false}
]
})
]))
.pipe(gulp.dest(config.root + config.targets.assets))
);
// 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
stream.add(
gulp.src("src/canvasdesigner/editors/*.less")
.pipe(gulp.dest(config.root + config.targets.assets + "/less"))
);
// Todo: check if we need these fileSize
stream.add(
gulp.src("src/views/propertyeditors/grid/config/*.*")
.pipe(gulp.dest(config.root + config.targets.views + "/propertyeditors/grid/config"))
);
stream.add(
gulp.src("src/views/dashboard/default/*.jpg")
.pipe(gulp.dest(config.root + config.targets.views + "/dashboard/default"))
);
return stream;
});

View File

@@ -0,0 +1,10 @@
'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) {
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
});

View File

@@ -0,0 +1,55 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var connect = require('gulp-connect');
var open = require('gulp-open');
var gulpDocs = require('gulp-ngdocs');
/**************************
* Build Backoffice UI API documentation
**************************/
gulp.task('docs', [], function (cb) {
var options = {
html5Mode: false,
startPage: '/api',
title: "Umbraco Backoffice UI API Documentation",
dest: 'docs/api',
styles: ['docs/umb-docs.css'],
image: "https://our.umbraco.com/assets/images/logo.svg"
}
return gulpDocs.sections({
api: {
glob: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'],
api: true,
title: 'API Documentation'
}
})
.pipe(gulpDocs.process(options))
.pipe(gulp.dest('docs/api'));
cb();
});
gulp.task('connect:docs', function (cb) {
connect.server({
root: 'docs/api',
livereload: true,
fallback: 'docs/api/index.html',
port: 8880
});
cb();
});
gulp.task('open:docs', function (cb) {
var options = {
uri: 'http://localhost:8880/index.html'
};
gulp.src(__filename)
.pipe(open(options));
cb();
});

View File

@@ -0,0 +1,10 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var runSequence = require('run-sequence');
// Docserve - build and open the back office documentation
gulp.task('docserve', function(cb) {
runSequence('docs', 'connect:docs', 'open:docs', cb);
});

View File

@@ -0,0 +1,13 @@
'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('fastdev', function(cb) {
global.isProd = false;
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
});

View File

@@ -0,0 +1,29 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
var processJs = require('../util/processJs');
/**************************
* Copies all angular JS files into their seperate umbraco.*.js file
**************************/
gulp.task('js', function () {
//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))
);
_.forEach(config.sources.js, function (group) {
stream.add (processJs(group.files, group.out) );
});
return stream;
});

View File

@@ -0,0 +1,20 @@
'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 () {
var stream = new MergeStream();
_.forEach(config.sources.less, function (group) {
stream.add( processLess(group.files, group.out) );
});
return stream;
});

View File

@@ -0,0 +1,26 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var karmaServer = require('karma').Server;
/**************************
* Build tests
**************************/
// Karma test
gulp.task('test:unit', function() {
new karmaServer({
configFile: __dirname + "/test/config/karma.conf.js",
keepalive: true
})
.start();
});
gulp.task('test:e2e', function() {
new karmaServer({
configFile: __dirname + "/test/config/e2e.js",
keepalive: true
})
.start();
});

View File

@@ -0,0 +1,25 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var _ = require('lodash');
var MergeStream = require('merge-stream');
gulp.task('views', function () {
var stream = new MergeStream();
_.forEach(config.sources.views, function (group) {
console.log("copying " + group.files + " to " + config.root + config.targets.views + group.folder)
stream.add (
gulp.src(group.files)
.pipe( gulp.dest(config.root + config.targets.views + group.folder) )
);
});
return stream;
});

View File

@@ -0,0 +1,58 @@
'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,18 @@
'use strict';
var notify = require('gulp-notify');
module.exports = function(error) {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify.onError({
title: 'Compile Error',
message: '<%= error.message %>'
}).apply(this, args);
// Keep gulp from hanging on this task
this.emit('end');
};

View File

@@ -0,0 +1,32 @@
var config = require('../config');
var gulp = require('gulp');
var eslint = require('gulp-eslint');
var babel = require("gulp-babel");
var sort = require('gulp-sort');
var concat = require('gulp-concat');
var wrap = require("gulp-wrap-js");
module.exports = function(files, out) {
var task = gulp.src(files);
if (global.isProd === true) {
// check for js errors
task = task.pipe(eslint());
// outputs the lint results to the console
task = task.pipe(eslint.format());
}
// sort files in stream by path or any custom sort comparator
task = task.pipe(babel())
.pipe(sort())
.pipe(concat(out))
.pipe(wrap('(function(){\n%= body %\n})();'))
.pipe(gulp.dest(config.root + config.targets.js));
return task;
};

View File

@@ -0,0 +1,33 @@
var config = require('../config');
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var less = require('gulp-less');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var cleanCss = require("gulp-clean-css");
var rename = require('gulp-rename');
module.exports = function(files, out) {
var processors = [
autoprefixer,
cssnano({zindex: false})
];
var task = gulp.src(files)
.pipe(less());
if (global.isProd === true) {
task = task.pipe(cleanCss());
}
task = task.pipe(postcss(processors))
.pipe(rename(out))
.pipe(gulp.dest(config.root + config.targets.css));
return task;
};

View File

@@ -0,0 +1,9 @@
'use strict';
var path = require('path');
// Filters out non .js files. Prevents
// accidental inclusion of possible hidden files
module.exports = function(name) {
return /(\.(js)$)/i.test(path.extname(name));
};

View File

@@ -1,597 +1,16 @@
var gulp = require('gulp');
var watch = require('gulp-watch');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var wrap = require("gulp-wrap-js");
var sort = require('gulp-sort');
var connect = require('gulp-connect');
var open = require('gulp-open');
var babel = require("gulp-babel");
var runSequence = require('run-sequence');
var imagemin = require('gulp-imagemin');
var _ = require('lodash');
var MergeStream = require('merge-stream');
// js
var eslint = require('gulp-eslint');
//Less + css
var postcss = require('gulp-postcss');
var less = require('gulp-less');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var cleanCss = require("gulp-clean-css");
// Documentation
var gulpDocs = require('gulp-ngdocs');
// Testing
var karmaServer = require('karma').Server;
/***************************************************************
Helper functions
***************************************************************/
function processJs(files, out) {
return gulp.src(files)
// check for js errors
.pipe(eslint())
// outputs the lint results to the console
.pipe(eslint.format())
// sort files in stream by path or any custom sort comparator
.pipe(babel())
.pipe(sort())
.pipe(concat(out))
.pipe(wrap('(function(){\n%= body %\n})();'))
.pipe(gulp.dest(root + targets.js));
console.log(out + " compiled");
}
function processLess(files, out) {
var processors = [
autoprefixer,
cssnano({zindex: false})
];
return gulp.src(files)
.pipe(less())
.pipe(cleanCss())
.pipe(postcss(processors))
.pipe(rename(out))
.pipe(gulp.dest(root + targets.css));
console.log(out + " compiled");
}
/***************************************************************
Paths and destinations
Each group is iterated automatically in the setup tasks below
***************************************************************/
var sources = {
//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" }
},
//js files for backoffie
//processed in the js task
js: {
preview: { files: ["src/preview/**/*.js"], out: "umbraco.preview.js" },
installer: { files: ["src/installer/**/*.js"], out: "umbraco.installer.js" },
controllers: { files: ["src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" },
directives: { files: ["src/common/directives/**/*.js"], out: "umbraco.directives.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" }
},
//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"}
},
//globs for file-watching
globs:{
views: "./src/views/**/*.html",
less: "./src/less/**/*.less",
js: "./src/*.js",
lib: "./lib/**/*",
assets: "./src/assets/**"
}
};
var root = "../Umbraco.Web.UI/Umbraco/";
var targets = {
js: "js/",
lib: "lib/",
views: "views/",
css: "assets/css/",
assets: "assets/"
};
/**************************
* Main tasks for the project to prepare backoffice files
**************************/
// Build - build the files ready for production
gulp.task('build', function(cb) {
runSequence(["dependencies", "js", "less", "views"], cb);
});
// Dev - build the files ready for development and start watchers
gulp.task('dev', function(cb) {
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
});
// Docserve - build and open the back office documentation
gulp.task('docserve', function(cb) {
runSequence('docs', 'connect:docs', 'open:docs', cb);
});
/**************************
* Task processes and copies all dependencies, either installed by npm or stored locally in the project
**************************/
gulp.task('dependencies', function () {
//as we do multiple things in this task, we merge the multiple streams
var stream = new MergeStream();
// Pick the dependencies we need from each package
// so we don't just ship with a lot of files that aren't needed
const nodeModules = [
{
"name": "ace-builds",
"src": [
"./node_modules/ace-builds/src-min-noconflict/ace.js",
"./node_modules/ace-builds/src-min-noconflict/ext-language_tools.js",
"./node_modules/ace-builds/src-min-noconflict/ext-searchbox.js",
"./node_modules/ace-builds/src-min-noconflict/ext-settings_menu.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/text.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/javascript.js",
"./node_modules/ace-builds/src-min-noconflict/snippets/css.js",
"./node_modules/ace-builds/src-min-noconflict/theme-chrome.js",
"./node_modules/ace-builds/src-min-noconflict/mode-razor.js",
"./node_modules/ace-builds/src-min-noconflict/mode-javascript.js",
"./node_modules/ace-builds/src-min-noconflict/mode-css.js",
"./node_modules/ace-builds/src-min-noconflict/worker-javascript.js",
"./node_modules/ace-builds/src-min-noconflict/worker-css.js"
],
"base": "./node_modules/ace-builds"
},
{
"name": "angular",
"src": ["./node_modules/angular/angular.js"],
"base": "./node_modules/angular"
},
{
"name": "angular-cookies",
"src": ["./node_modules/angular-cookies/angular-cookies.js"],
"base": "./node_modules/angular-cookies"
},
{
"name": "angular-dynamic-locale",
"src": [
"./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js",
"./node_modules/angular-dynamic-locale/dist/tmhDynamicLocale.min.js.map"
],
"base": "./node_modules/angular-dynamic-locale/dist"
},
{
"name": "angular-sanitize",
"src": ["./node_modules/angular-sanitize/angular-sanitize.js"],
"base": "./node_modules/angular-sanitize"
},
{
"name": "angular-touch",
"src": ["./node_modules/angular-touch/angular-touch.js"],
"base": "./node_modules/angular-touch"
},
{
"name": "angular-ui-sortable",
"src": ["./node_modules/angular-ui-sortable/dist/sortable.js"],
"base": "./node_modules/angular-ui-sortable/dist"
},
{
"name": "angular-route",
"src": ["./node_modules/angular-route/angular-route.js"],
"base": "./node_modules/angular-route"
},
{
"name": "angular-animate",
"src": ["./node_modules/angular-animate/angular-animate.js"],
"base": "./node_modules/angular-animate"
},
{
"name": "angular-chart.js",
"src": ["./node_modules/angular-chart.js/dist/angular-chart.min.js"],
"base": "./node_modules/angular-chart.js/dist"
},
{
"name": "angular-i18n",
"src": [
"./node_modules/angular-i18n/angular-i18n.js",
"./node_modules/angular-i18n/angular-locale_*.js"
],
"base": "./node_modules/angular-i18n"
},
{
"name": "angular-local-storage",
"src": [
"./node_modules/angular-local-storage/dist/angular-local-storage.min.js",
"./node_modules/angular-local-storage/dist/angular-local-storage.min.js.map"
],
"base": "./node_modules/angular-local-storage/dist"
},
{
"name": "angular-messages",
"src": ["./node_modules/angular-messages/angular-messages.js"],
"base": "./node_modules/angular-messages"
},
{
"name": "angular-mocks",
"src": ["./node_modules/angular-mocks/angular-mocks.js"],
"base": "./node_modules/angular-mocks"
},
{
"name": "animejs",
"src": ["./node_modules/animejs/anime.min.js"],
"base": "./node_modules/animejs"
},
{
"name": "bootstrap-social",
"src": ["./node_modules/bootstrap-social/bootstrap-social.css"],
"base": "./node_modules/bootstrap-social"
},
{
"name": "angular-chart.js",
"src": ["./node_modules/angular-chart.js/dist/angular-chart.min.js"],
"base": "./node_modules/angular-chart.js/dist"
},
{
"name": "chart.js",
"src": ["./node_modules/chart.js/dist/chart.min.js"],
"base": "./node_modules/chart.js/dist"
},
{
"name": "chart.js",
"src": ["./node_modules/chart.js/dist/Chart.min.js"],
"base": "./node_modules/chart.js/dist"
},
{
"name": "clipboard",
"src": ["./node_modules/clipboard/dist/clipboard.min.js"],
"base": "./node_modules/clipboard/dist"
},
{
"name": "jsdiff",
"src": ["./node_modules/diff/dist/diff.min.js"],
"base": "./node_modules/diff/dist"
},
{
"name": "flatpickr",
"src": [
"./node_modules/flatpickr/dist/flatpickr.js",
"./node_modules/flatpickr/dist/flatpickr.css"
],
"base": "./node_modules/flatpickr/dist"
},
{
"name": "font-awesome",
"src": [
"./node_modules/font-awesome/fonts/*",
"./node_modules/font-awesome/css/font-awesome.min.css"
],
"base": "./node_modules/font-awesome"
},
{
"name": "jquery",
"src": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery/dist/jquery.min.map"
],
"base": "./node_modules/jquery/dist"
},
{
"name": "jquery-ui",
"src": ["./node_modules/jquery-ui-dist/jquery-ui.min.js"],
"base": "./node_modules/jquery-ui-dist"
},
{
"name": "jquery-ui-touch-punch",
"src": ["./node_modules/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js"],
"base": "./node_modules/jquery-ui-touch-punch"
},
{
"name": "lazyload-js",
"src": ["./node_modules/lazyload-js/lazyload.min.js"],
"base": "./node_modules/lazyload-js"
},
{
"name": "moment",
"src": ["./node_modules/moment/min/moment.min.js"],
"base": "./node_modules/moment/min"
},
{
"name": "moment",
"src": ["./node_modules/moment/locale/*.js"],
"base": "./node_modules/moment/locale"
},
{
"name": "ng-file-upload",
"src": ["./node_modules/ng-file-upload/dist/ng-file-upload.min.js"],
"base": "./node_modules/ng-file-upload/dist"
},
{
"name": "nouislider",
"src": [
"./node_modules/nouislider/distribute/nouislider.min.js",
"./node_modules/nouislider/distribute/nouislider.min.css"
],
"base": "./node_modules/nouislider/distribute"
},
{
"name": "signalr",
"src": ["./node_modules/signalr/jquery.signalR.js"],
"base": "./node_modules/signalr"
},
{
"name": "spectrum",
"src": [
"./node_modules/spectrum-colorpicker/spectrum.js",
"./node_modules/spectrum-colorpicker/spectrum.css"
],
"base": "./node_modules/spectrum-colorpicker"
},
{
"name": "tinymce",
"src": [
"./node_modules/tinymce/tinymce.min.js",
"./node_modules/tinymce/plugins/**",
"./node_modules/tinymce/skins/**",
"./node_modules/tinymce/themes/**"
],
"base": "./node_modules/tinymce"
},
{
"name": "typeahead.js",
"src": ["./node_modules/typeahead.js/dist/typeahead.bundle.min.js"],
"base": "./node_modules/typeahead.js/dist"
},
{
"name": "underscore",
"src": ["node_modules/underscore/underscore-min.js"],
"base": "./node_modules/underscore"
}
];
// add streams for node modules
nodeModules.forEach(module => {
stream.add(
gulp.src(module.src,
{ base: module.base })
.pipe(gulp.dest(root + targets.lib + "/" + module.name))
);
});
//copy over libs which are not on npm (/lib)
stream.add(
gulp.src(sources.globs.lib)
.pipe(gulp.dest(root + targets.lib))
);
//Copies all static assets into /root / assets folder
//css, fonts and image files
stream.add(
gulp.src(sources.globs.assets)
.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({
plugins: [
{removeViewBox: true},
{cleanupIDs: false}
]
})
]))
.pipe(gulp.dest(root + targets.assets))
);
// 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
stream.add(
gulp.src("src/canvasdesigner/editors/*.less")
.pipe(gulp.dest(root + targets.assets + "/less"))
);
// Todo: check if we need these fileSize
stream.add(
gulp.src("src/views/propertyeditors/grid/config/*.*")
.pipe(gulp.dest(root + targets.views + "/propertyeditors/grid/config"))
);
stream.add(
gulp.src("src/views/dashboard/default/*.jpg")
.pipe(gulp.dest(root + targets.views + "/dashboard/default"))
);
return stream;
});
/**************************
* Copies all angular JS files into their seperate umbraco.*.js file
**************************/
gulp.task('js', function () {
//we run multiple streams, so merge them all together
var stream = new MergeStream();
stream.add(
gulp.src(sources.globs.js)
.pipe(gulp.dest(root + targets.js))
);
_.forEach(sources.js, function (group) {
stream.add (processJs(group.files, group.out) );
});
return stream;
});
gulp.task('less', function () {
var stream = new MergeStream();
_.forEach(sources.less, function (group) {
stream.add( processLess(group.files, group.out) );
});
return stream;
});
gulp.task('views', function () {
var stream = new MergeStream();
_.forEach(sources.views, function (group) {
console.log("copying " + group.files + " to " + root + targets.views + group.folder)
stream.add (
gulp.src(group.files)
.pipe( gulp.dest(root + targets.views + group.folder) )
);
});
return stream;
});
gulp.task('watch', function () {
var stream = new MergeStream();
var watchInterval = 500;
//Setup a watcher for all groups of javascript files
_.forEach(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(sources.globs.less, { ignoreInitial: true, interval: watchInterval }, function () {
gulp.run(['less']);
})
);
//watch all views - copy single file changes
stream.add(
watch(sources.globs.views, { interval: watchInterval })
.pipe(gulp.dest(root + targets.views))
);
//watch all app js files that will not be merged - copy single file changes
stream.add(
watch(sources.globs.js, { interval: watchInterval })
.pipe(gulp.dest(root + targets.js))
);
return stream;
});
/**************************
* Build Backoffice UI API documentation
**************************/
gulp.task('docs', [], function (cb) {
var options = {
html5Mode: false,
startPage: '/api',
title: "Umbraco Backoffice UI API Documentation",
dest: 'docs/api',
styles: ['docs/umb-docs.css'],
image: "https://our.umbraco.com/assets/images/logo.svg"
}
return gulpDocs.sections({
api: {
glob: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'],
api: true,
title: 'API Documentation'
}
})
.pipe(gulpDocs.process(options))
.pipe(gulp.dest('docs/api'));
cb();
});
gulp.task('connect:docs', function (cb) {
connect.server({
root: 'docs/api',
livereload: true,
fallback: 'docs/api/index.html',
port: 8880
});
cb();
});
gulp.task('open:docs', function (cb) {
var options = {
uri: 'http://localhost:8880/index.html'
};
gulp.src(__filename)
.pipe(open(options));
cb();
});
/**************************
* Build tests
**************************/
// Karma test
gulp.task('test:unit', function() {
new karmaServer({
configFile: __dirname + "/test/config/karma.conf.js",
keepalive: true
})
.start();
});
gulp.task('test:e2e', function() {
new karmaServer({
configFile: __dirname + "/test/config/e2e.js",
keepalive: true
})
.start();
});
'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.
*/
global.isProd = true;
require('./gulp');

View File

@@ -5115,6 +5115,12 @@
"integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
"dev": true
},
"fs": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz",
"integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg=",
"dev": true
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -6119,6 +6125,12 @@
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
"growly": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true
},
"gulp": {
"version": "3.9.1",
"resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz",
@@ -6916,6 +6928,102 @@
}
}
},
"gulp-notify": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz",
"integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==",
"dev": true,
"requires": {
"ansi-colors": "^1.0.1",
"fancy-log": "^1.3.2",
"lodash.template": "^4.4.0",
"node-notifier": "^5.2.1",
"node.extend": "^2.0.0",
"plugin-error": "^0.1.2",
"through2": "^2.0.3"
},
"dependencies": {
"arr-diff": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
"integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
"dev": true,
"requires": {
"arr-flatten": "^1.0.1",
"array-slice": "^0.2.3"
}
},
"arr-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
"integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
"dev": true
},
"array-slice": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
"integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
"dev": true
},
"extend-shallow": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
"integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
"dev": true,
"requires": {
"kind-of": "^1.1.0"
}
},
"kind-of": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
"dev": true
},
"lodash.template": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz",
"integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=",
"dev": true,
"requires": {
"lodash._reinterpolate": "~3.0.0",
"lodash.templatesettings": "^4.0.0"
}
},
"lodash.templatesettings": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz",
"integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=",
"dev": true,
"requires": {
"lodash._reinterpolate": "~3.0.0"
}
},
"node.extend": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz",
"integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==",
"dev": true,
"requires": {
"has": "^1.0.3",
"is": "^3.2.1"
}
},
"plugin-error": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
"integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
"dev": true,
"requires": {
"ansi-cyan": "^0.1.1",
"ansi-red": "^0.1.1",
"arr-diff": "^1.0.1",
"arr-union": "^2.0.1",
"extend-shallow": "^1.1.2"
}
}
}
},
"gulp-open": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/gulp-open/-/gulp-open-3.0.1.tgz",
@@ -9368,6 +9476,18 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node-notifier": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz",
"integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==",
"dev": true,
"requires": {
"growly": "^1.3.0",
"semver": "^5.5.0",
"shellwords": "^0.1.1",
"which": "^1.3.0"
}
},
"node-releases": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.5.tgz",
@@ -13158,7 +13278,7 @@
},
"pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
"resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
"integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
"dev": true
},
@@ -14124,6 +14244,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shellwords": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
"dev": true
},
"sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
@@ -15712,7 +15838,7 @@
"dependencies": {
"lru-cache": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
"resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
"integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=",
"dev": true
}

View File

@@ -2,7 +2,10 @@
"private": true,
"scripts": {
"test": "karma start test/config/karma.conf.js --singlerun",
"build": "gulp"
"build": "gulp build",
"dev": "gulp dev",
"fastdev": "gulp fastdev",
"docs": "gulp docs"
},
"dependencies": {
"ace-builds": "1.4.2",
@@ -62,6 +65,7 @@
"gulp-watch": "5.0.1",
"gulp-wrap": "0.14.0",
"gulp-wrap-js": "0.4.1",
"gulp-notify": "^3.0.0",
"jasmine-core": "3.3.0",
"karma": "3.1.1",
"karma-jasmine": "2.0.1",
@@ -70,6 +74,7 @@
"lodash": "4.17.11",
"marked": "^0.5.2",
"merge-stream": "1.0.1",
"run-sequence": "2.2.1"
"run-sequence": "2.2.1",
"fs": "0.0.2"
}
}

View File

@@ -215,9 +215,15 @@
* @param {any} selectedVariant
*/
function openSplitView(selectedVariant) {
var selectedCulture = selectedVariant.language.culture;
//Find the whole variant model based on the culture that was chosen
var variant = _.find(vm.content.variants, function (v) {
return v.language.culture === selectedCulture;
});
insertVariantEditor(vm.editors.length, initVariant(variant, vm.editors.length));
//only the content app can be selected since no other apps are shown, and because we copy all of these apps
//to the "editors" we need to update this across all editors
for (var e = 0; e < vm.editors.length; e++) {
@@ -233,13 +239,6 @@
}
}
//Find the whole variant model based on the culture that was chosen
var variant = _.find(vm.content.variants, function (v) {
return v.language.culture === selectedCulture;
});
insertVariantEditor(vm.editors.length, initVariant(variant, vm.editors.length));
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
editor.collapsed = true;
editor.loading = true;
@@ -260,6 +259,8 @@
vm.editors.splice(editorIndex, 1);
//remove variant from open variants
vm.openVariants.splice(editorIndex, 1);
//update the current culture to reflect the last open variant (closing the split view corresponds to selecting the other variant)
$location.search("cculture", vm.openVariants[0]);
splitViewChanged();
}, 400);
}
@@ -270,7 +271,7 @@
* @param {any} editorIndex The index of the editor being changed
*/
function selectVariant(variant, editorIndex) {
// prevent variants already open in a split view to be opened
if(vm.openVariants.indexOf(variant.language.culture) !== -1) {
return;

View File

@@ -130,8 +130,7 @@
if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) {
configureViewModel();
//this is required to re-validate
vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length);
reValidate()
}
}
@@ -182,6 +181,8 @@
else {
vm.onValueChanged({ value: [] });
}
reValidate();
}
/**
@@ -189,7 +190,7 @@
*/
function validateMandatory() {
return {
isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0),
isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0)|| (vm.value != null && vm.value.length > 0),
errorMsg: "Value cannot be empty",
errorKey: "required"
};
@@ -271,6 +272,10 @@
});
}
function reValidate() {
//this is required to re-validate
vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length);
}
}

View File

@@ -44,6 +44,7 @@ the directive will use {@link umbraco.directives.directive:umbLockedField umbLoc
@param {string} alias (<code>binding</code>): The model where the alias is bound.
@param {string} aliasFrom (<code>binding</code>): The model to generate the alias from.
@param {string} validationPosition (<code>binding</code>): The position of the validation. Set to <code>'left'</code> or <code>'right'</code>.
@param {boolean=} enableLock (<code>binding</code>): Set to <code>true</code> to add a lock next to the alias from where it can be unlocked and changed.
**/
@@ -57,6 +58,7 @@ angular.module("umbraco.directives")
alias: '=',
aliasFrom: '=',
enableLock: '=?',
validationPosition: '=?',
serverValidationField: '@'
},
link: function (scope, element, attrs, ctrl) {

View File

@@ -33,10 +33,11 @@ Use this directive to generate color swatches to pick from.
scope.useColorClass = false;
}
scope.setColor = function (color) {
scope.setColor = function (color, $index, $event) {
scope.selectedColor = color;
if (scope.onSelect) {
scope.onSelect(color);
scope.onSelect(color, $index, $event);
$event.stopPropagation();
}
};
}
@@ -50,7 +51,7 @@ Use this directive to generate color swatches to pick from.
colors: '=?',
size: '@',
selectedColor: '=',
onSelect: '&',
onSelect: '=',
useLabel: '=',
useColorClass: '=?'
},

View File

@@ -40,6 +40,7 @@ Use this directive to render a value with a lock next to it. When the lock is cl
@param {boolean=} locked (<code>binding</code>): <Code>true</code> by default. Set to <code>false</code> to unlock the text.
@param {string=} placeholderText (<code>binding</code>): If ngModel is empty this text will be shown.
@param {string=} regexValidation (<code>binding</code>): Set a regex expression for validation of the field.
@param {string} validationPosition (<code>binding</code>): The position of the validation. Set to <code>'left'</code> or <code>'right'</code>.
@param {string=} serverValidationField (<code>attribute</code>): Set a server validation field.
**/
@@ -70,7 +71,11 @@ Use this directive to render a value with a lock next to it. When the lock is cl
// if locked state is not defined as an attr set default state
if (scope.placeholderText === undefined || scope.placeholderText === null) {
scope.placeholderText = "Enter value...";
}
}
if (scope.validationPosition === undefined || scope.validationPosition === null) {
scope.validationPosition = "left";
}
}
@@ -93,9 +98,10 @@ Use this directive to render a value with a lock next to it. When the lock is cl
templateUrl: 'views/components/umb-locked-field.html',
scope: {
ngModel: "=",
locked: "=?",
locked: "=?",
placeholderText: "=?",
regexValidation: "=?",
regexValidation: "=?",
validationPosition: "=?",
serverValidationField: "@"
},
link: link

View File

@@ -0,0 +1,24 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:no-password-manager
* @attribte
* @function
* @description
* Added attributes to block password manager elements should as LastPass
* @example
* <example module="umbraco.directives">
* <file name="index.html">
* <input type="text" no-password-manager />
* </file>
* </example>
**/
angular.module("umbraco.directives")
.directive('noPasswordManager', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.attr("data-lpignore", "true");
}
}
});

View File

@@ -11,24 +11,24 @@ angular.module('umbraco.mocks').
var menu = [
{ name: "Create", cssclass: "plus", alias: "create", metaData: {} },
{ seperator: true, name: "Delete", cssclass: "remove", alias: "delete", metaData: {} },
{ separator: true, name: "Delete", cssclass: "remove", alias: "delete", metaData: {} },
{ name: "Move", cssclass: "move", alias: "move", metaData: {} },
{ name: "Copy", cssclass: "copy", alias: "copy", metaData: {} },
{ name: "Sort", cssclass: "sort", alias: "sort", metaData: {} },
{ seperator: true, name: "Publish", cssclass: "globe", alias: "publish", metaData: {} },
{ separator: true, name: "Publish", cssclass: "globe", alias: "publish", metaData: {} },
{ name: "Rollback", cssclass: "undo", alias: "rollback", metaData: {} },
{ seperator: true, name: "Permissions", cssclass: "lock", alias: "permissions", metaData: {} },
{ separator: true, name: "Permissions", cssclass: "lock", alias: "permissions", metaData: {} },
{ name: "Audit Trail", cssclass: "time", alias: "audittrail", metaData: {} },
{ name: "Notifications", cssclass: "envelope", alias: "notifications", metaData: {} },
{ seperator: true, name: "Hostnames", cssclass: "home", alias: "hostnames", metaData: {} },
{ separator: true, name: "Hostnames", cssclass: "home", alias: "hostnames", metaData: {} },
{ name: "Public Access", cssclass: "group", alias: "publicaccess", metaData: {} },
{ seperator: true, name: "Reload", cssclass: "refresh", alias: "users", metaData: {} },
{ separator: true, name: "Reload", cssclass: "refresh", alias: "users", metaData: {} },
{ seperator: true, name: "Empty Recycle Bin", cssclass: "trash", alias: "emptyrecyclebin", metaData: {} }
{ separator: true, name: "Empty Recycle Bin", cssclass: "trash", alias: "emptyrecyclebin", metaData: {} }
];
var result = {
@@ -94,7 +94,7 @@ angular.module('umbraco.mocks').
jsAction: "umbracoMenuActions.CreateChildEntity"
}
},
{ seperator: true, name: "Reload", cssclass: "refresh", alias: "users", metaData: {} }
{ separator: true, name: "Reload", cssclass: "refresh", alias: "users", metaData: {} }
];
return [200, menu, null];

View File

@@ -203,7 +203,6 @@ angular.module('umbraco.mocks').
"defaultdialogs_siterepublishHelp": "The website cache will be refreshed. All published content will be updated, while unpublished content will stay unpublished.",
"defaultdialogs_tableColumns": "Number of columns",
"defaultdialogs_tableRows": "Number of rows",
"defaultdialogs_templateContentAreaHelp": "<strong>Set a placeholder id</strong> by setting an ID on your placeholder you can inject content into this template from child templates, by refering this ID using a <code>&lt;asp:content /&gt;</code> element.",
"defaultdialogs_templateContentPlaceHolderHelp": "<strong>Select a placeholder id</strong> from the list below. You can only choose Id's from the current template's master.",
"defaultdialogs_thumbnailimageclickfororiginal": "Click on the image to see full size",
"defaultdialogs_treepicker": "Pick item",
@@ -453,13 +452,11 @@ angular.module('umbraco.mocks').
"notifications_notifications": "Notifications",
"packager_chooseLocalPackageText": " Choose Package from your machine, by clicking the Browse<br /> button and locating the package. Umbraco packages usually have a '.umb' or '.zip' extension. ",
"packager_packageAuthor": "Author",
"packager_packageDemonstration": "Demonstration",
"packager_packageDocumentation": "Documentation",
"packager_packageMetaData": "Package meta data",
"packager_packageName": "Package name",
"packager_packageNoItemsHeader": "Package doesn't contain any items",
"packager_packageNoItemsText": "This package file doesn't contain any items to uninstall.<br/><br/> You can safely remove this from the system by clicking 'uninstall package' below.",
"packager_packageNoUpgrades": "No upgrades available",
"packager_packageOptions": "Package options",
"packager_packageReadme": "Package readme",
"packager_packageRepository": "Package repository",
@@ -468,13 +465,7 @@ angular.module('umbraco.mocks').
"packager_packageUninstalledText": "The package was successfully uninstalled",
"packager_packageUninstallHeader": "Uninstall package",
"packager_packageUninstallText": "You can unselect items you do not wish to remove, at this time, below. When you click 'confirm uninstall' all checked-off items will be removed.<br /> <span style='color: Red; font-weight: bold;'>Notice:</span> any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, so uninstall with caution. If in doubt, contact the package author.",
"packager_packageUpgradeDownload": "Download update from the repository",
"packager_packageUpgradeHeader": "Upgrade package",
"packager_packageUpgradeInstructions": "Upgrade instructions",
"packager_packageUpgradeText": " There's an upgrade available for this package. You can download it directly from the Umbraco package repository.",
"packager_packageVersion": "Package version",
"packager_packageVersionHistory": "Package version history",
"packager_viewPackageWebsite": "View package website",
"paste_doNothing": "Paste with full formatting (Not recommended)",
"paste_errorMessage": "The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web.",
"paste_removeAll": "Paste as raw text without any formatting at all",
@@ -641,7 +632,7 @@ angular.module('umbraco.mocks').
"templateEditor_urlEncodeHelp": "Will format special characters in URLs",
"templateEditor_usedIfAllEmpty": "Will only be used when the field values above are empty",
"templateEditor_usedIfEmpty": "This field will only be used if the primary field is empty",
"templateEditor_withTime": "Yes, with time. Seperator: ",
"templateEditor_withTime": "Yes, with time. Separator: ",
"translation_details": "Translation details",
"translation_DownloadXmlDTD": "Download xml DTD",
"translation_fields": "Fields",

View File

@@ -20,14 +20,14 @@ function macroResource($q, $http, umbRequestHelper) {
* @param {int} macroId The macro id to get parameters for
*
*/
getMacroParameters: function (macroId) {
getMacroParameters: function(macroId) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"macroApiBaseUrl",
"GetMacroParameters",
[{ macroId: macroId }])),
'Failed to retrieve macro parameters for macro with id ' + macroId);
$http.get(
umbRequestHelper.getApiUrl(
"macroRenderingApiBaseUrl",
"GetMacroParameters",
[{ macroId: macroId }])),
'Failed to retrieve macro parameters for macro with id ' + macroId);
},
/**
@@ -43,13 +43,14 @@ function macroResource($q, $http, umbRequestHelper) {
* @param {Array} macroParamDictionary A dictionary of macro parameters
*
*/
getMacroResultAsHtmlForEditor: function (macroAlias, pageId, macroParamDictionary) {
getMacroResultAsHtmlForEditor: function(macroAlias, pageId, macroParamDictionary) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"macroApiBaseUrl",
"GetMacroResultAsHtmlForEditor"), {
"macroRenderingApiBaseUrl",
"GetMacroResultAsHtmlForEditor"),
{
macroAlias: macroAlias,
pageId: pageId,
macroParams: macroParamDictionary
@@ -67,17 +68,61 @@ function macroResource($q, $http, umbRequestHelper) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"macroApiBaseUrl",
"CreatePartialViewMacroWithFile"), {
virtualPath: virtualPath,
filename: filename
}
"macroRenderingApiBaseUrl",
"CreatePartialViewMacroWithFile"),
{
virtualPath: virtualPath,
filename: filename
}
),
'Failed to create macro "' + filename + '"'
);
},
createMacro: function(name) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"macroApiBaseUrl",
"Create?name=" + name)
),
'Failed to create macro "' + name + '"'
);
},
getPartialViews: function() {
return umbRequestHelper.resourcePromise(
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetPartialViews"),
"Failed to get partial views")
);
},
getParameterEditors: function() {
return umbRequestHelper.resourcePromise(
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetParameterEditors"),
"Failed to get parameter editors")
);
},
getById: function(id) {
return umbRequestHelper.resourcePromise(
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetById", { "id": id }), "Failed to get macro")
);
},
saveMacro: function(macro) {
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "Save"), macro)
);
},
deleteById: function(id) {
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "deleteById", { "id": id }))
);
}
};
};
}
angular.module('umbraco.resources').factory('macroResource', macroResource);

View File

@@ -19,7 +19,7 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"packageInstallApiBaseUrl",
"packageApiBaseUrl",
"GetInstalled")),
'Failed to get installed packages');
},
@@ -33,15 +33,6 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) {
'Failed to validate package ' + name);
},
deleteCreatedPackage: function (packageId) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"packageInstallApiBaseUrl",
"DeleteCreatedPackage", { packageId: packageId })),
'Failed to delete package ' + packageId);
},
uninstall: function(packageId) {
return umbRequestHelper.resourcePromise(
$http.post(
@@ -151,6 +142,94 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) {
"packageInstallApiBaseUrl",
"CleanUp"), umbPackage),
'Failed to install package. Error during the step "CleanUp" ');
},
/**
* @ngdoc method
* @name umbraco.resources.packageInstallResource#getCreated
* @methodOf umbraco.resources.packageInstallResource
*
* @description
* Gets a list of created packages
*/
getAllCreated: function() {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"GetCreatedPackages")),
'Failed to get created packages');
},
/**
* @ngdoc method
* @name umbraco.resources.packageInstallResource#getCreatedById
* @methodOf umbraco.resources.packageInstallResource
*
* @description
* Gets a created package by id
*/
getCreatedById: function(id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"GetCreatedPackageById",
{ id: id })),
'Failed to get package');
},
getInstalledById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"GetInstalledPackageById",
{ id: id })),
'Failed to get package');
},
getEmpty: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"getEmpty")),
'Failed to get scaffold');
},
/**
* @ngdoc method
* @name umbraco.resources.packageInstallResource#savePackage
* @methodOf umbraco.resources.packageInstallResource
*
* @description
* Creates or updates a package
*/
savePackage: function (umbPackage) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"PostSavePackage"), umbPackage),
'Failed to create package');
},
/**
* @ngdoc method
* @name umbraco.resources.packageInstallResource#deleteCreatedPackage
* @methodOf umbraco.resources.packageInstallResource
*
* @description
* Detes a created package
*/
deleteCreatedPackage: function (packageId) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"packageApiBaseUrl",
"DeleteCreatedPackage", { packageId: packageId })),
'Failed to delete package ' + packageId);
}
};
}

View File

@@ -26,7 +26,7 @@ function relationResource($q, $http, umbRequestHelper) {
umbRequestHelper.getApiUrl(
"relationApiBaseUrl",
"GetByChildId",
[{ childId: id, relationTypeAlias: alias }])),
{ childId: id, relationTypeAlias: alias })),
"Failed to get relation by child ID " + id + " and type of " + alias);
},
@@ -62,4 +62,4 @@ function relationResource($q, $http, umbRequestHelper) {
};
}
angular.module('umbraco.resources').factory('relationResource', relationResource);
angular.module('umbraco.resources').factory('relationResource', relationResource);

View File

@@ -421,7 +421,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
*/
reBindChangedProperties: function (origContent, savedContent) {
//TODO: We should probably split out this logic to deal with media/members seperately to content
//TODO: We should probably split out this logic to deal with media/members separately to content
//a method to ignore built-in prop changes
var shouldIgnore = function (propName) {

View File

@@ -162,7 +162,7 @@ When building a custom infinite editor view you can use the same components as a
(function () {
"use strict";
function editorService(eventsService, keyboardService) {
function editorService(eventsService, keyboardService, $timeout) {
let editorsKeyboardShorcuts = [];
var editors = [];
@@ -245,10 +245,14 @@ When building a custom infinite editor view you can use the same components as a
// emit event to let components know an editor has been removed
eventsService.emit("appState.editors.close", args);
// rebind keyboard shortcuts for the new editor in focus
rebindKeyboardShortcuts();
// delay required to map the properties to the correct editor due
// to another delay in the closing animation of the editor
$timeout(function() {
// rebind keyboard shortcuts for the new editor in focus
rebindKeyboardShortcuts();
}, 0);
}
/**
@@ -748,6 +752,29 @@ When building a custom infinite editor view you can use the same components as a
open(editor);
}
/**
* @ngdoc method
* @name umbraco.services.editorService#memberPicker
* @methodOf umbraco.services.editorService
*
* @description
* Opens a member picker in infinite editing, the submit callback returns an array of selected items
*
* @param {Object} editor rendering options
* @param {Boolean} editor.multiPicker Pick one or multiple items
* @param {Function} editor.submit Callback function when the submit button is clicked. Returns the editor model object
* @param {Function} editor.close Callback function when the close button is clicked.
*
* @returns {Object} editor object
*/
function memberPicker(editor) {
editor.view = "views/common/infiniteeditors/treepicker/treepicker.html";
editor.size = "small";
editor.section = "member";
editor.treeAlias = "member";
open(editor);
}
///////////////////////
/**
@@ -824,7 +851,8 @@ When building a custom infinite editor view you can use the same components as a
userPicker: userPicker,
itemPicker: itemPicker,
macroPicker: macroPicker,
memberGroupPicker: memberGroupPicker
memberGroupPicker: memberGroupPicker,
memberPicker: memberPicker
};
return service;

View File

@@ -6,7 +6,6 @@
app.ready
app.authenticated
app.notAuthenticated
app.ysod
app.reInitialize
app.userRefresh
app.navigationReady

View File

@@ -110,7 +110,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
//Or, some strange server error
if (err.status === 400) {
//now we need to look through all the validation errors
if (err.data && (err.data.ModelState)) {
if (err.data && err.data.ModelState) {
//wire up the server validation errs
this.handleServerValidation(err.data.ModelState);
@@ -118,9 +118,11 @@ function formHelper(angularHelper, serverValidationManager, notificationsService
//execute all server validation events and subscribers
serverValidationManager.notifyAndClearAllSubscriptions();
}
else {
overlayService.ysod(err);
}
}
else {
//TODO: All YSOD handling should be done with an interceptor
overlayService.ysod(err);
}
},

View File

@@ -27,6 +27,11 @@
overlay.position = "center";
}
// use a default empty view if nothing is set
if(!overlay.view) {
overlay.view = "views/common/overlays/default/default.html";
}
// option to disable backdrop clicks
if(overlay.disableBackdropClick) {
backdropOptions.disableEventsOnClick = true;

View File

@@ -1316,7 +1316,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
startNodeIsVirtual: userData.startMediaIds.length !== 1,
submit: function (model) {
self.insertMediaInEditor(args.editor, model.selectedImages[0]);
self.insertMediaInEditor(args.editor, model.selection[0]);
editorService.close();
},
close: function () {

View File

@@ -64,7 +64,7 @@
var saveModel = _.pick(displayModel,
'compositeContentTypes', 'isContainer', 'allowAsRoot', 'allowedTemplates', 'allowedContentTypes',
'alias', 'description', 'thumbnail', 'name', 'id', 'icon', 'trashed',
'key', 'parentId', 'alias', 'path', 'allowCultureVariant');
'key', 'parentId', 'alias', 'path', 'allowCultureVariant', 'isElement');
//TODO: Map these
saveModel.allowedTemplates = _.map(displayModel.allowedTemplates, function (t) { return t.alias; });
@@ -262,7 +262,7 @@
saveModel[props[m]] = startId.id;
}
saveModel.parentId = -1;
saveModel.parentId = -1;
return saveModel;
},
@@ -293,7 +293,7 @@
});
saveModel.email = propEmail.value.trim();
saveModel.username = propLogin.value.trim();
saveModel.password = this.formatChangePasswordModel(propPass.value);
var selectedGroups = [];
@@ -336,7 +336,7 @@
/** formats the display model used to display the media to the model used to save the media */
formatMediaPostData: function (displayModel, action) {
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
// we don't want to post all of the data as it is unecessary.
var saveModel = {
id: displayModel.id,
@@ -354,7 +354,7 @@
/** formats the display model used to display the content to the model used to save the content */
formatContentPostData: function (displayModel, action) {
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
// we don't want to post all of the data as it is unecessary.
var saveModel = {
id: displayModel.id,
@@ -379,7 +379,7 @@
var propExpireDate = displayModel.removeDate;
var propReleaseDate = displayModel.releaseDate;
var propTemplate = displayModel.template;
saveModel.expireDate = propExpireDate ? propExpireDate : null;
saveModel.releaseDate = propReleaseDate ? propReleaseDate : null;
saveModel.templateAlias = propTemplate ? propTemplate : null;
@@ -389,8 +389,8 @@
/**
* This formats the server GET response for a content display item
* @param {} displayModel
* @returns {}
* @param {} displayModel
* @returns {}
*/
formatContentGetData: function(displayModel) {
@@ -418,7 +418,7 @@
}
});
});
//now assign this same invariant property instance to the same index of the other variants property array
for (var j = 1; j < displayModel.variants.length; j++) {

View File

@@ -3,7 +3,7 @@
* @name umbraco.services.umbRequestHelper
* @description A helper object used for sending requests to the server
**/
function umbRequestHelper($http, $q, notificationsService, eventsService, formHelper) {
function umbRequestHelper($http, $q, notificationsService, eventsService, formHelper, overlayService) {
return {
@@ -176,11 +176,9 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
//show a ysod dialog
if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
eventsService.emit('app.ysod',
{
errorMsg: 'An error occured',
data: response.data
});
const error = { errorMsg: 'An error occured', data: response.data };
//TODO: All YSOD handling should be done with an interceptor
overlayService.ysod(error);
}
else {
//show a simple error notification
@@ -290,11 +288,9 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
}
else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
//show a ysod dialog
eventsService.emit('app.ysod',
{
errorMsg: 'An error occured',
data: response.data
});
const error = { errorMsg: 'An error occured', data: response.data };
//TODO: All YSOD handling should be done with an interceptor
overlayService.ysod(error);
}
else {
//show a simple error notification

View File

@@ -103,14 +103,6 @@ function MainController($scope, $location, appState, treeService, notificationsS
}));
evts.push(eventsService.on("app.ysod", function (name, error) {
$scope.ysodOverlay = {
view: "ysod",
error: error,
show: true
};
}));
// events for search
evts.push(eventsService.on("appState.searchState.changed", function (e, args) {
if (args.key === "show") {

View File

@@ -1,4 +1,4 @@
angular.module("umbraco.install").factory('installerService', function($rootScope, $q, $timeout, $http, $location, $log){
angular.module("umbraco.install").factory('installerService', function ($rootScope, $q, $timeout, $http, $templateRequest){
var _status = {
index: 0,
@@ -16,17 +16,17 @@ angular.module("umbraco.install").factory('installerService', function($rootScop
};
//add to umbraco installer facts here
var facts = ['Umbraco helped millions of people watch a man jump from the edge of space',
'Over 440 000 websites are currently powered by Umbraco',
var facts = ["Umbraco helped millions of people watch a man jump from the edge of space",
"Over 500 000 websites are currently powered by Umbraco",
"At least 2 people have named their cat 'Umbraco'",
'On an average day, more than 1000 people download Umbraco',
'<a target="_blank" href="https://umbraco.tv">umbraco.tv</a> is the premier source of Umbraco video tutorials to get you started',
'You can find the world\'s friendliest CMS community at <a target="_blank" href="https://our.umbraco.com">our.umbraco.com</a>',
'You can become a certified Umbraco developer by attending one of the official courses',
'Umbraco works really well on tablets',
'You have 100% control over your markup and design when crafting a website in Umbraco',
'Umbraco is the best of both worlds: 100% free and open source, and backed by a professional and profitable company',
"There's a pretty big chance, you've visited a website powered by Umbraco today",
"On an average day more than 1000 people download Umbraco",
"<a target='_blank' href='https://umbraco.tv/'>umbraco.tv</a> is the premier source of Umbraco video tutorials to get you started",
"You can find the world's friendliest CMS community at <a target='_blank' href='https://our.umbraco.com/'>our.umbraco.com</a>",
"You can become a certified Umbraco developer by attending one of the official courses",
"Umbraco works really well on tablets",
"You have 100% control over your markup and design when crafting a website in Umbraco",
"Umbraco is the best of both worlds: 100% free and open source, and backed by a professional and profitable company",
"There's a pretty big chance you've visited a website powered by Umbraco today",
"'Umbraco-spotting' is the game of spotting big brands running Umbraco",
"At least 4 people have the Umbraco logo tattooed on them",
"'Umbraco' is the Danish name for an allen key",
@@ -106,19 +106,26 @@ angular.module("umbraco.install").factory('installerService', function($rootScop
//loads the needed steps and sets the intial state
init : function(){
service.status.loading = true;
if(!_status.all){
service.getSteps().then(function(response){
service.status.steps = response.data.steps;
service.status.index = 0;
_installerModel.installId = response.data.installId;
service.findNextStep();
if (!_status.all) {
//pre-load the error page, if an error occurs, the page might not be able to load
// so we want to make sure it's available in the templatecache first
$templateRequest("views/install/error.html").then(x => {
service.getSteps().then(response => {
service.status.steps = response.data.steps;
service.status.index = 0;
_installerModel.installId = response.data.installId;
service.findNextStep();
$timeout(function(){
service.status.loading = false;
service.status.configuring = true;
}, 2000);
});
}
$timeout(function() {
service.status.loading = false;
service.status.configuring = true;
},
2000);
});
});
}
},
//loads available packages from our.umbraco.com

View File

@@ -8,4 +8,14 @@
.umb-alert--info {
background-color: @turquoise-washed;
border: 1px solid @turquoise;
}
}
.umb-alert--warning {
background-color: @yellow-washed;
border: 1px solid @yellow;
}
.umb-alert--danger {
background-color: @red-washed;
border: 1px solid @red;
}

View File

@@ -125,6 +125,8 @@ body.touch .umb-tree {
position: inherit;
display: inherit;
list-style: none;
h6 {
padding: 10px 0 10px 20px;
font-weight: inherit;
@@ -137,7 +139,15 @@ body.touch .umb-tree {
}
&-item {
padding-left: 20px;
padding: 4px 0;
&:hover {
background-color: @gray-10;
}
&-link {
display: block;
}
}
&-link {

View File

@@ -28,7 +28,7 @@
color: @black;
}
.umb-breadcrumbs__seperator {
.umb-breadcrumbs__separator {
position: relative;
top: 1px;
margin-left: 5px;
@@ -41,4 +41,4 @@ input.umb-breadcrumbs__add-ancestor {
margin-top: -2px;
margin-left: 3px;
width: 100px;
}
}

View File

@@ -38,6 +38,7 @@ input.umb-locked-field__input {
transition: color 0.25s;
padding: 0;
height: auto;
max-width: 300px;
}
input.umb-locked-field__input:focus {

View File

@@ -15,7 +15,7 @@
height: 300px;
border: 2px dashed @gray-8;
border-radius: 3px;
background: @gray-10;
background: @white;
display: flex;
flex-direction: column;
justify-content: center;
@@ -74,7 +74,6 @@
// Info state
.umb-info-local-items {
border: 2px solid @gray-8;
border-radius: 3px;
background: @gray-10;
display: flex;
@@ -84,6 +83,8 @@
margin: 0 20px;
width: 100%;
max-width: 540px;
background: @white;
box-shadow: 0 1px 1px 0 rgba(0,0,0,.16);
}
.umb-info-local-items a {

View File

@@ -23,9 +23,7 @@
.umb-packages-search {
width: 100%;
background: @gray-10;
border-radius: 3px;
padding: 30px;
box-sizing: border-box;
}
@@ -49,60 +47,14 @@
}
.umb-packages {
margin: 0 -10px;
display: flex;
flex-wrap: wrap;
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
// Cards
.umb-package {
padding: 10px;
box-sizing: border-box;
flex: 0 0 100%;
max-width: 100%;
}
@media (min-width: 768px) {
.umb-package {
flex: 0 0 50%;
max-width: 50%;
}
}
@media (min-width: 1200px) {
.umb-package {
flex: 0 0 33.33%;
max-width: 33.33%;
}
}
@media (min-width: 1400px) {
.umb-package {
flex: 0 0 25%;
max-width: 25%;
}
}
@media (min-width: 1700px) {
.umb-package {
flex: 0 0 20%;
max-width: 20%;
}
}
@media (min-width: 1900px) {
.umb-package {
flex: 0 0 16.66%;
max-width: 16.66%;
}
}
@media (min-width: 2200px) {
.umb-package {
flex: 0 0 14.28%;
max-width: 14.28%;
}
}
.umb-package-link {
@@ -114,10 +66,11 @@
box-sizing: border-box;
height: 100%;
width: 100%;
border: 1px solid @gray-9;
border-radius: 3px;
text-decoration: none !important;
transition: border-color 100ms ease;
background-color: @white;
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16);
&:hover {
border-color: @turquoise;
@@ -151,15 +104,8 @@
// Info
.umb-package-info {
padding-right: 15px;
padding-bottom: 15px;
padding-left: 15px;
padding-top: 15px;
padding: 15px;
text-align: center;
background: @gray-10;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
border-top: 1px solid @gray-9;
}
@@ -251,6 +197,7 @@
border-bottom: 1px solid @gray-8;
border-right: 1px solid @gray-8;
padding: 10px 0;
background: @white;
}

View File

@@ -38,10 +38,12 @@
align-items: center;
}
.umb-stylesheet-rule-overlay {
textarea {
width: 300px;
height: 120px;
resize: none;
}
textarea.umb-stylesheet-rule-styles {
width: 300px;
height: 100px;
resize: none;
}
.umb-stylesheet-rule-preview {
line-height: normal;
}

View File

@@ -1,46 +1,67 @@
.umb-validation-label {
position: absolute;
top: 27px;
width: 200px;
padding: 1px 5px;
background: @red;
color: @white;
font-size: 11px;
line-height: 1.5em;
position: absolute;
top: 27px;
min-width: 100px;
max-width: 200px;
padding: 1px 5px;
background: @red;
color: @white;
font-size: 11px;
line-height: 1.5em;
}
.umb-validation-label:after {
bottom: 100%;
left: 10px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(255, 255, 255, 0);
border-bottom-color: @red;
border-width: 4px;
margin-left: -4px;
bottom: 100%;
left: 10px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(255, 255, 255, 0);
border-bottom-color: @red;
border-width: 4px;
margin-left: -4px;
}
.umb-validation-label.-left {
left: 0;
right: auto;
&:after {
left: 10px;
right: auto;
}
}
.umb-validation-label.-right {
right: 0;
left: auto;
&:after {
right: 10px;
left: auto;
}
}
.umb-validation-label.-arrow-left {
margin-left: 10px;
margin-left: 10px;
}
.umb-validation-label.-arrow-left:after {
right: 100%;
top: 50%;
left: auto;
bottom: auto;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(255, 255, 255, 0);
border-right-color: @red;
border-width: 4px;
margin-top: -4px;
right: 100%;
top: 50%;
left: auto;
bottom: auto;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(255, 255, 255, 0);
border-right-color: @red;
border-width: 4px;
margin-top: -4px;
}

View File

@@ -373,10 +373,6 @@
margin-bottom: 0;
}
.umb-panel-header-alias .umb-validation-label:after {
visibility: hidden;
}
.umb-panel-header-alias .umb-locked-field:after {
display: none;
}

View File

@@ -1,7 +1,5 @@
/*
Spacing
*/
@spacing-none: 0;
@@ -37,13 +35,11 @@
7 = 7th step in spacing scale
*/
.m-center {
margin-left: auto;
margin-right: auto;
}
.mt0 { margin-top: @spacing-none; }
.mt1 { margin-top: @spacing-extra-small; }
.mt2 { margin-top: @spacing-small; }
@@ -52,3 +48,12 @@
.mt5 { margin-top: @spacing-extra-large; }
.mt6 { margin-top: @spacing-extra-extra-large; }
.mt7 { margin-top: @spacing-extra-extra-extra-large; }
.mb0 { margin-bottom: @spacing-none; }
.mb1 { margin-bottom: @spacing-extra-small; }
.mb2 { margin-bottom: @spacing-small; }
.mb3 { margin-bottom: @spacing-medium; }
.mb4 { margin-bottom: @spacing-large; }
.mb5 { margin-bottom: @spacing-extra-large; }
.mb6 { margin-bottom: @spacing-extra-extra-large; }
.mb7 { margin-bottom: @spacing-extra-extra-extra-large; }

View File

@@ -149,14 +149,22 @@ app.config(function ($routeProvider) {
.when('/:section/:tree/:method?', {
//This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method.
template: "<div ng-include='templateUrl'></div>",
//This controller will execute for this route, then we replace the template dynamnically based on the current tree.
controller: function ($scope, $route, $routeParams, treeService) {
//This controller will execute for this route, then we replace the template dynamically based on the current tree.
controller: function ($scope, $routeParams, treeService) {
if (!$routeParams.method) {
$scope.templateUrl = "views/common/dashboard.html";
return;
}
// Here we need to figure out if this route is for a package tree and if so then we need
//special case for the package section
var packagePages = ["edit", "options"];
if ($routeParams.section.toLowerCase() === "packages" && $routeParams.tree.toLowerCase() === "packages" && packagePages.indexOf($routeParams.method.toLowerCase()) === -1) {
$scope.templateUrl = "views/packages/overview.html";
return;
}
// Here we need to figure out if this route is for a user's package tree and if so then we need
// to change it's convention view path to:
// /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html

View File

@@ -110,6 +110,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -75,6 +75,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -129,6 +129,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
</umb-editor-footer-content-right>
@@ -138,4 +139,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -52,6 +52,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -68,4 +69,4 @@
</form>
</umb-editor-view>
</div>
</div>

View File

@@ -54,6 +54,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -11,6 +11,8 @@ function IconPickerController($scope, iconHelper, localizationService) {
var vm = this;
vm.selectIcon = selectIcon;
vm.selectColor = selectColor;
vm.submit = submit;
vm.close = close;
vm.colors = [
@@ -47,11 +49,10 @@ function IconPickerController($scope, iconHelper, localizationService) {
});
// set a default color if nothing is passed in
vm.color = $scope.model.color ? $scope.model.color : vm.colors[0].value;
vm.color = $scope.model.color ? $scope.model.color : vm.colors[0].value;
// if an icon is passed in - preselect it
vm.icon = $scope.model.icon ? $scope.model.icon : undefined;
}
function setTitle() {
@@ -69,6 +70,10 @@ function IconPickerController($scope, iconHelper, localizationService) {
submit();
}
function selectColor(color, $index, $event) {
$scope.model.color = color;
}
function close() {
if($scope.model && $scope.model.close) {
$scope.model.close();
@@ -76,7 +81,7 @@ function IconPickerController($scope, iconHelper, localizationService) {
}
function submit() {
if($scope.model && $scope.model.submit) {
if ($scope.model && $scope.model.submit) {
$scope.model.submit($scope.model);
}
}

View File

@@ -36,7 +36,8 @@
use-color-class="true"
colors="vm.colors"
selected-color="vm.color"
size="s">
size="s"
on-select="vm.selectColor">
</umb-color-swatches>
</div>
@@ -68,11 +69,19 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
type="button"
button-style="success"
label-key="general_submit"
state="vm.saveButtonState"
action="vm.submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</form>
</form>

View File

@@ -47,6 +47,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
</umb-editor-footer-content-right>

View File

@@ -207,6 +207,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -44,6 +44,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
</umb-editor-footer-content-right>

View File

@@ -33,31 +33,51 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.showTarget = $scope.model.hideTarget !== true;
// this ensures that we only sync the tree once and only when it's ready
var oneTimeTreeSync = {
executed: false,
treeReady: false,
sync: function () {
// don't run this if:
// - it was already run once
// - the tree isn't ready yet
// - the model path hasn't been loaded yet
if (this.executed || !this.treeReady || !($scope.model.target && $scope.model.target.path)) {
return;
}
this.executed = true;
// sync the tree to the model path
$scope.dialogTreeApi.syncTree({
path: $scope.model.target.path,
tree: "content"
});
}
};
if (dialogOptions.currentTarget) {
$scope.model.target = dialogOptions.currentTarget;
// clone the current target so we don't accidentally update the caller's model while manipulating $scope.model.target
$scope.model.target = angular.copy(dialogOptions.currentTarget);
//if we have a node ID, we fetch the current node to build the form data
if ($scope.model.target.id || $scope.model.target.udi) {
//will be either a udi or an int
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
if (!$scope.model.target.path) {
// is it a content link?
if (!$scope.model.target.isMedia) {
// get the content path
entityResource.getPath(id, "Document").then(function (path) {
$scope.model.target.path = path;
//now sync the tree to this path
$scope.dialogTreeApi.syncTree({
path: $scope.model.target.path,
tree: "content"
});
oneTimeTreeSync.sync();
});
// get the content properties to build the anchor name list
contentResource.getById(id).then(function (resp) {
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
$scope.model.target.url = resp.urls[0];
});
}
// if a link exists, get the properties to build the anchor name list
contentResource.getById(id).then(function (resp) {
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
$scope.model.target.url = resp.urls[0];
});
} else if ($scope.model.target.url.length) {
// a url but no id/udi indicates an external link - trim the url to remove the anchor/qs
// only do the substring if there's a # or a ?
@@ -72,6 +92,11 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.anchorValues = dialogOptions.anchors;
}
function treeLoadedHandler(args) {
oneTimeTreeSync.treeReady = true;
oneTimeTreeSync.sync();
}
function nodeSelectHandler(args) {
if (args && args.event) {
args.event.preventDefault();
@@ -118,7 +143,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
startNodeIsVirtual: userData.startMediaIds.length !== 1,
submit: function (model) {
var media = model.selectedImages[0];
var media = model.selection[0];
$scope.model.target.id = media.id;
$scope.model.target.udi = media.udi;
@@ -127,6 +152,12 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.model.target.url = mediaHelper.resolveFile(media);
editorService.close();
// make sure the content tree has nothing highlighted
$scope.dialogTreeApi.syncTree({
path: "-1",
tree: "content"
});
},
close: function() {
editorService.close();
@@ -146,7 +177,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
// method to select a search result
$scope.selectResult = function (evt, result) {
result.selected = result.selected === true ? false : true;
nodeSelectHandler(evt, {
nodeSelectHandler({
event: evt,
node: result
});
@@ -159,6 +190,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
};
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeLoaded(treeLoadedHandler);
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
@@ -166,7 +198,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
// Mini list view
$scope.selectListViewNode = function (node) {
node.selected = node.selected === true ? false : true;
nodeSelectHandler({}, {
nodeSelectHandler({
node: node
});
};

View File

@@ -120,6 +120,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -41,7 +41,7 @@ angular.module("umbraco")
$scope.maxFileSize = umbracoSettings.maxFileSize + "KB";
$scope.model.selectedImages = [];
$scope.model.selection = [];
$scope.acceptedMediatypes = [];
mediaTypeHelper.getAllowedImagetypes($scope.startNodeId)
@@ -145,7 +145,7 @@ angular.module("umbraco")
$scope.gotoFolder = function(folder) {
if (!$scope.multiPicker) {
deselectAllImages($scope.model.selectedImages);
deselectAllImages($scope.model.selection);
}
if (!folder) {
@@ -212,19 +212,19 @@ angular.module("umbraco")
function selectImage(image) {
if (image.selected) {
for (var i = 0; $scope.model.selectedImages.length > i; i++) {
var imageInSelection = $scope.model.selectedImages[i];
for (var i = 0; $scope.model.selection.length > i; i++) {
var imageInSelection = $scope.model.selection[i];
if (image.key === imageInSelection.key) {
image.selected = false;
$scope.model.selectedImages.splice(i, 1);
$scope.model.selection.splice(i, 1);
}
}
} else {
if (!$scope.multiPicker) {
deselectAllImages($scope.model.selectedImages);
deselectAllImages($scope.model.selection);
}
image.selected = true;
$scope.model.selectedImages.push(image);
$scope.model.selection.push(image);
}
}
@@ -238,7 +238,7 @@ angular.module("umbraco")
$scope.onUploadComplete = function(files) {
$scope.gotoFolder($scope.currentFolder).then(function() {
if (files.length === 1 && $scope.model.selectedImages.length === 0) {
if (files.length === 1 && $scope.model.selection.length === 0) {
var image = $scope.images[$scope.images.length - 1];
$scope.target = image;
$scope.target.url = mediaHelper.resolveFile(image);
@@ -275,7 +275,7 @@ angular.module("umbraco")
$scope.mediaPickerDetailsOverlay.show = true;
$scope.mediaPickerDetailsOverlay.submit = function(model) {
$scope.model.selectedImages.push($scope.target);
$scope.model.selection.push($scope.target);
$scope.model.submit($scope.model);
$scope.mediaPickerDetailsOverlay.show = false;
@@ -384,11 +384,11 @@ angular.module("umbraco")
var folderImage = $scope.images[folderImageIndex];
var imageIsSelected = false;
if ($scope.model && angular.isArray($scope.model.selectedImages)) {
if ($scope.model && angular.isArray($scope.model.selection)) {
for (var selectedImageIndex = 0;
selectedImageIndex < $scope.model.selectedImages.length;
selectedImageIndex < $scope.model.selection.length;
selectedImageIndex++) {
var selectedImage = $scope.model.selectedImages[selectedImageIndex];
var selectedImage = $scope.model.selection[selectedImageIndex];
if (folderImage.key === selectedImage.key) {
imageIsSelected = true;

View File

@@ -55,12 +55,12 @@
<ul class="umb-breadcrumbs">
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder()" prevent-default>Media</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
<span class="umb-breadcrumbs__separator">&#47;</span>
</li>
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
<span class="umb-breadcrumbs__separator">&#47;</span>
</li>
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
@@ -171,6 +171,7 @@
<umb-button
action="close()"
button-style="link"
shortcut="esc"
label="Close"
type="button">
</umb-button>

View File

@@ -32,6 +32,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -67,6 +67,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -37,6 +37,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>

View File

@@ -155,6 +155,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>

View File

@@ -193,6 +193,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
@@ -209,4 +210,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -86,6 +86,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -101,4 +102,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -38,6 +38,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -51,4 +52,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -87,6 +87,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button

View File

@@ -54,6 +54,7 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController",
vm.toggleLanguageSelector = toggleLanguageSelector;
vm.selectLanguage = selectLanguage;
vm.onSearchResults = onSearchResults;
vm.selectResult = selectResult;
vm.hideSearch = hideSearch;
vm.closeMiniListView = closeMiniListView;
vm.selectListViewNode = selectListViewNode;

View File

@@ -90,6 +90,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>

View File

@@ -84,6 +84,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -97,4 +98,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -74,6 +74,7 @@
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -87,4 +88,4 @@
</umb-editor-view>
</div>
</div>

View File

@@ -5,7 +5,7 @@
<div class='umb-modalcolumn-body'>
<ul class="umb-actions">
<li data-element="action-{{action.alias}}" ng-click="executeMenuItem(action)" class="umb-action" ng-class="{sep:action.seperator, '-opens-dialog': action.opensDialog}" ng-repeat="action in menuActions">
<li data-element="action-{{action.alias}}" ng-click="executeMenuItem(action)" class="umb-action" ng-class="{sep:action.separator, '-opens-dialog': action.opensDialog}" ng-repeat="action in menuActions">
<a class="umb-action-link" prevent-default>
<i class="icon icon-{{action.cssclass}}"></i>
<span class="menu-label">{{action.name}}</span>

View File

@@ -7,15 +7,11 @@
<umb-box-content class="block-form">
<ul class="nav nav-stacked" style="margin-bottom: 0;">
<li ng-repeat="url in currentUrls">
<span ng-if="url.isUrl">
<a href="{{url.text}}" target="_blank" ng-if="url.isUrl">
<span ng-if="node.variants.length === 1 && url.culture" style="font-size: 13px; color: #cccccc; width: 50px;display: inline-block">{{url.culture}}</span>
<a href="{{url.text}}" target="_blank">
<i class="icon icon-window-popin"></i>
<span>{{url.text}}</span>
</a>
</span>
<i class="icon icon-out"></i>
<span>{{url.text}}</span>
</a>
<div ng-if="!url.isUrl" style="margin-top: 4px;">
<span ng-if="node.variants.length === 1 && url.culture" style="font-size: 13px; color: #cccccc; width: 50px;display: inline-block">{{url.culture}}</span>

View File

@@ -7,9 +7,9 @@
<!-- use callback to handle click -->
<a ng-if="!$last && allowOnOpen" href="#" ng-click="open(ancestor)" class="umb-breadcrumbs__ancestor-link" title="{{ancestor.name}}" prevent-default>{{ancestor.name}}</a>
<span ng-if="!$last" class="umb-breadcrumbs__seperator">&#47;</span>
<span ng-if="!$last" class="umb-breadcrumbs__separator">&#47;</span>
<span class="umb-breadcrumbs__ancestor-text" ng-if="$last" title="{{ancestor.name}}">{{ancestor.name}}</span>
</li>
</ul>
</ul>

View File

@@ -23,7 +23,8 @@
<div id="nameField" style="flex: 1 1 auto;">
<div class="umb-editor-header__name-wrapper">
<ng-form name="headerNameForm">
<input data-element="editor-name-field"
<input data-element="editor-name-field"
no-password-manager
title="{{key}}"
type="text"
class="umb-editor-header__name-input"
@@ -45,6 +46,7 @@
alias="$parent.alias"
alias-from="$parent.name"
enable-lock="true"
validation-position="'right'"
server-validation-field="Alias">
</umb-generate-alias>
@@ -53,6 +55,7 @@
<div class="umb-panel-header-name" ng-if="nameLocked" title="{{key}}">{{ name }}</div>
<input data-element="editor-description"
no-password-manager
type="text"
class="umb-panel-header-description"
localize="placeholder"

View File

@@ -9,7 +9,7 @@
</umb-button>
<umb-dropdown ng-if="dropdown.isOpen" class="umb-actions" on-close="dropdown.isOpen = false">
<umb-dropdown-item class="umb-action" ng-class="{'sep':action.seperatorm, '-opens-dialog': action.opensDialog}" ng-repeat="action in actions">
<umb-dropdown-item class="umb-action" ng-class="{'sep':action.separatorm, '-opens-dialog': action.opensDialog}" ng-repeat="action in actions">
<a href="" ng-click="executeMenuItem(action)" prevent-default>
<i class="icon icon-{{action.cssclass}}"></i>
<span class="menu-label">{{action.name}}</span>

View File

@@ -5,16 +5,16 @@
<umb-box-content class="block-form">
<umb-empty-state
ng-if="!nodeUrl || !nodeUrl.isUrl"
ng-if="!nodeUrl"
size="small">
<localize key="content_noMediaLink"></localize>
</umb-empty-state>
<ul ng-if="nodeUrl && nodeUrl.isUrl" class="nav nav-stacked" style="margin-bottom: 0;">
<ul ng-if="nodeUrl" class="nav nav-stacked" style="margin-bottom: 0;">
<li>
<a href="{{nodeUrl.text}}" target="_blank">
<i class="icon icon-window-popin"></i>
<span>{{nodeUrl.text}}</span>
<a href="{{nodeUrl}}" target="_blank">
<i class="icon icon-out"></i>
<span>{{nodeUrl}}</span>
</a>
</li>
</ul>

View File

@@ -6,9 +6,9 @@
<ul class="umb-tree">
<li class="root">
<ul class="umb-search-group">
<li ng-repeat="result in results">
<div style="padding-left: 20px" ng-class="{'umb-tree-node-checked' : result.selected}">
<a class="umb-search-group-item-link" ng-class="{first:$first}" ng-click="selectResultCallback($event, result)">
<li class="umb-search-group-item" ng-repeat="result in results">
<div ng-class="{'umb-tree-node-checked' : result.selected}">
<a href class="umb-search-group-item-link" ng-class="{first:$first}" ng-click="selectResultCallback($event, result)">
<div class="umb-search-group-item-name">
<i class="icon umb-tree-icon sprTree {{result.icon}}"></i>
{{result.name}}

View File

@@ -1,6 +1,6 @@
<div class="umb-color-swatches" ng-class="{ 'with-labels': useLabel }">
<button type="button" class="umb-color-box umb-color-box--{{size}} btn-{{color.value}}" ng-repeat="color in colors" title="{{useLabel || useColorClass ? (color.label || color.value) : ('#' + color.value)}}" hex-bg-inline="{{useColorClass === false}}" hex-bg-color="{{color.value}}" ng-class="{ 'active': color.value === selectedColor }" ng-click="setColor(color.value)">
<button type="button" class="umb-color-box umb-color-box--{{size}} btn-{{color.value}}" ng-repeat="color in colors" title="{{useLabel || useColorClass ? (color.label || color.value) : ('#' + color.value)}}" hex-bg-inline="{{useColorClass === false}}" hex-bg-color="{{color.value}}" ng-class="{ 'active': color.value === selectedColor }" ng-click="setColor(color.value, $index, $event)">
<div class="umb-color-box-inner">
<div class="check_circle" ng-if="color.value === selectedColor">
<i class="icon icon-check small"></i>

View File

@@ -5,8 +5,8 @@
locked="locked"
ng-model="alias"
placeholder-text="placeholderText"
validation-position="validationPosition"
server-validation-field="{{serverValidationField}}">
</umb-locked-field>
</div>
</div>

View File

@@ -11,6 +11,7 @@
</a>
<input type="text"
no-password-manager
class="umb-locked-field__input"
name="lockedField"
ng-model="ngModel"
@@ -29,9 +30,22 @@
</div>
<div ng-messages="lockedFieldForm.lockedField.$error" show-validation-on-submit>
<div class="umb-validation-label" ng-message="required"><localize key="general_required">Required</localize> <localize key="content_alias">alias</localize></div>
<div ng-if="regexValidation.length > 0" class="umb-validation-label" ng-message="valRegex"><localize key="general_invalid">Invalid</localize> <localize key="content_alias">alias</localize></div>
<div ng-if="serverValidationField.length > 0" class="umb-validation-label" ng-message="valServerField">{{lockedFieldForm.lockedField.errorMsg}}</div>
<div class="umb-validation-label"
ng-class="{ '-left': validationPosition === 'left', '-right': validationPosition === 'right' }"
ng-message="required">
<localize key="general_required">Required</localize> <localize key="content_alias">alias</localize>
</div>
<div class="umb-validation-label"
ng-class="{ '-left': validationPosition === 'left', '-right': validationPosition === 'right' }"
ng-if="regexValidation.length > 0"
ng-message="valRegex">
<localize key="general_invalid">Invalid</localize> <localize key="content_alias">alias</localize>
</div>
<div class="umb-validation-label"
ng-class="{ '-left': validationPosition === 'left', '-right': validationPosition === 'right' }"
ng-if="serverValidationField.length > 0"
ng-message="valServerField">{{lockedFieldForm.lockedField.errorMsg}}
</div>
</div>
</ng-form>

View File

@@ -65,6 +65,7 @@ function ContentDeleteController($scope, $timeout, contentResource, treeService,
//check if response is ysod
if (err.status && err.status >= 500) {
//TODO: All YSOD handling should be done with an interceptor
overlayService.ysod(err);
}
});

View File

@@ -1,5 +1,5 @@
angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController",
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, userService) {
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, userService, localizationService) {
$scope.source = _.clone($scope.currentNode);
@@ -20,6 +20,10 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
userService.getCurrentUser().then(function (userData) {
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
});
$scope.labels = {};
localizationService.localizeMany(["treeHeaders_content"]).then(function (data) {
$scope.labels.treeRoot = data[0];
});
function nodeSelectHandler(args) {
@@ -92,7 +96,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
$scope.relation = data[0];
if ($scope.relation.parentId === -1) {
$scope.target = { id: -1, name: "Root" };
$scope.target = { id: -1, name: $scope.labels.treeRoot };
} else {
$scope.loading = true;

View File

@@ -21,7 +21,7 @@
<p class="abstract" ng-hide="success">
<localize key="actions_chooseWhereToMove">Choose where to move</localize>
<strong>{{source.name}}</strong>
<localize key="actions_toInTheTreeStructureBelow">to in the tree structure below</localize>
<localize key="actions_toInTheTreeStructureBelow">to in the tree structure below</localize>
</p>
<div class="umb-loader-wrapper" ng-show="busy">
@@ -31,7 +31,7 @@
<div ng-hide="success">
<div ng-hide="miniListView">
<umb-tree-search-box
<umb-tree-search-box
hide-search-callback="hideSearch"
search-callback="onSearchResults"
search-from-id="{{searchInfo.searchFromId}}"

View File

@@ -25,6 +25,7 @@
vm.removeChild = removeChild;
vm.toggleAllowAsRoot = toggleAllowAsRoot;
vm.toggleAllowCultureVariants = toggleAllowCultureVariants;
vm.toggleIsElement = toggleIsElement;
/* ---------- INIT ---------- */
@@ -84,25 +85,18 @@
$scope.model.allowedContentTypes.splice(selectedChildIndex, 1);
}
/**
* Toggle the $scope.model.allowAsRoot value to either true or false
*/
function toggleAllowAsRoot(){
if($scope.model.allowAsRoot){
$scope.model.allowAsRoot = false;
return;
}
// note: "safe toggling" here ie handling cases where the value is undefined, etc
$scope.model.allowAsRoot = true;
function toggleAllowAsRoot() {
$scope.model.allowAsRoot = $scope.model.allowAsRoot ? false : true;
}
function toggleAllowCultureVariants() {
if ($scope.model.allowCultureVariant) {
$scope.model.allowCultureVariant = false;
return;
}
$scope.model.allowCultureVariant = $scope.model.allowCultureVariant ? false : true;
}
$scope.model.allowCultureVariant = true;
function toggleIsElement() {
$scope.model.isElement = $scope.model.isElement ? false : true;
}
}

View File

@@ -53,9 +53,25 @@
hotkey="alt+shift+v">
</umb-toggle>
</div>
</div>
</umb-box-content>
<div class="sub-view-columns">
<div class="sub-view-column-left">
<h5><localize key="contentTypeEditor_elementHeading" /></h5>
<small><localize key="contentTypeEditor_elementDescription" /></small>
</div>
<div class="sub-view-column-right">
<umb-toggle data-element="permissions-is-element"
checked="model.isElement"
on-click="vm.toggleIsElement()">
</umb-toggle>
</div>
</div>
</umb-box-content>
</umb-box>
</div>

View File

@@ -0,0 +1,9 @@
<div>
<div ng-if="model.language" class="umb-alert umb-alert--warning mb2">
<localize key="defaultdialogs_languagedeletewarning">This will delete the language</localize> <strong>{{model.language.name}} [{{model.language.culture}}]</strong>.
</div>
<localize key="defaultdialogs_confirmdelete"></localize>?
</div>

View File

@@ -1,7 +1,7 @@
(function () {
"use strict";
function LanguagesOverviewController($location, $timeout, navigationService, notificationsService, localizationService, languageResource, eventsService) {
function LanguagesOverviewController($location, $timeout, navigationService, localizationService, languageResource, eventsService, overlayService) {
var vm = this;
@@ -65,30 +65,47 @@
}
function deleteLanguage(language, event) {
var confirmed = confirm("Are you sure you want to delete " + language.name + "?");
if(confirmed) {
language.deleteButtonState = "busy";
languageResource.deleteById(language.id).then(function () {
const dialog = {
view: "views/languages/overlays/delete.html",
language: language,
submitButtonLabelKey: "contentTypeEditor_yesDelete",
submit: function (model) {
performDelete(model.language);
overlayService.close();
},
close: function () {
overlayService.close();
}
};
// emit event
var args = { language: language };
eventsService.emit("editors.languages.languageDeleted", args);
localizationService.localize("general_delete").then(value => {
dialog.title = value;
overlayService.open(dialog);
});
// remove from list
var index = vm.languages.indexOf(language);
vm.languages.splice(index, 1);
}, function (err) {
language.deleteButtonState = "error";
});
}
event.preventDefault()
event.stopPropagation();
}
function performDelete(language) {
language.deleteButtonState = "busy";
languageResource.deleteById(language.id).then(function () {
// emit event
var args = { language: language };
eventsService.emit("editors.languages.languageDeleted", args);
// remove from list
var index = vm.languages.indexOf(language);
vm.languages.splice(index, 1);
}, function (err) {
language.deleteButtonState = "error";
});
}
init();
}

View File

@@ -2,43 +2,41 @@
<umb-editor-view footer="false">
<umb-editor-header
name="vm.page.name"
name-locked="true"
hide-icon="true"
hide-description="true"
hide-alias="true">
<umb-editor-header name="vm.page.name"
name-locked="true"
hide-icon="true"
hide-description="true"
hide-alias="true">
</umb-editor-header>
<umb-editor-container>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<umb-editor-sub-header>
<umb-editor-sub-header-content-left>
<umb-button
button-style="success"
type="button"
action="vm.addLanguage()"
label-key="languages_addLanguage">
<umb-button button-style="success"
type="button"
action="vm.addLanguage()"
label-key="languages_addLanguage">
</umb-button>
</umb-editor-sub-header-content-left>
</umb-editor-sub-header>
<table class="table table-hover" ng-if="!vm.loading">
<thead>
<tr>
<th>Language</th>
<th><localize key="general_language">Language</localize></th>
<th>ISO</th>
<th>Default</th>
<th>Mandatory</th>
<th><localize key="general_default">Default</localize></th>
<th><localize key="general_mandatory">Mandatory</localize></th>
<th>Fallback</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="language in vm.languages" ng-click="vm.editLanguage(language)" style="cursor: pointer;">
<tr ng-repeat="language in vm.languages track by language.id" ng-click="vm.editLanguage(language)" style="cursor: pointer;">
<td>
<i class="icon-globe" style="color: #BBBABF; margin-right: 5px;"></i>
<span ng-class="{'bold': language.isDefault}">{{ language.name }}</span>
@@ -47,17 +45,15 @@
<span>{{ language.culture }}</span>
</td>
<td>
<umb-checkmark
ng-if="language.isDefault"
checked="language.isDefault"
size="xs">
<umb-checkmark ng-if="language.isDefault"
checked="language.isDefault"
size="xs">
</umb-checkmark>
</td>
<td>
<umb-checkmark
ng-if="language.isMandatory"
checked="language.isMandatory"
size="xs">
<umb-checkmark ng-if="language.isMandatory"
checked="language.isMandatory"
size="xs">
</umb-checkmark>
</td>
<td>
@@ -65,14 +61,13 @@
<span ng-if="!language.fallbackLanguageId">(none)</span>
</td>
<td style="text-align: right;">
<umb-button
ng-if="!language.isDefault"
type="button"
size="xxs"
button-style="danger"
state="language.deleteButtonState"
action="vm.deleteLanguage(language, $event)"
label-key="general_delete">
<umb-button ng-if="!language.isDefault"
type="button"
size="xxs"
button-style="danger"
state="language.deleteButtonState"
action="vm.deleteLanguage(language, $event)"
label-key="general_delete">
</umb-button>
</td>
</tr>

View File

@@ -0,0 +1,19 @@
<div ng-controller="Umbraco.Editors.Macros.CreateController as vm">
<div class="umb-pane">
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
</div>
<div class="umb-pane">
<form name="createDictionaryForm"
ng-submit="vm.createItem()"
val-form-manager>
<umb-control-group label="Enter a item-name" hide-label="true">
<input type="text" name="itemKey" ng-model="vm.itemKey" class="umb-textstring textstring input-block-level" required />
</umb-control-group>
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
</form>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Macros.DeleteController as vm">
<div class="umb-dialog-body" auto-scale="90">
<p class="umb-abstract">
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{vm.name}}</strong> ?
</p>
<umb-confirm on-confirm="vm.performDelete" on-cancel="cancel"></umb-confirm>
</div>
</div>

View File

@@ -0,0 +1,30 @@
<div data-element="editor-macros" ng-controller="Umbraco.Editors.Macros.EditController as vm">
<form name="macroForm" novalidate val-form-manager ng-submit="vm.save()">
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
<umb-editor-view ng-if="!vm.page.loading">
<umb-editor-header name="vm.macro.name"
alias="vm.macro.alias"
hide-description="true"
hide-icon="true"
navigation="vm.page.navigation">
</umb-editor-header>
<umb-editor-container class="form-horizontal">
<umb-editor-sub-views sub-views="vm.page.navigation" model="vm">
</umb-editor-sub-views>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button type="submit"
button-style="success"
state="vm.page.saveButtonState"
shortcut="ctrl+s"
label="Save"
label-key="buttons_save">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</form>
</div>

View File

@@ -0,0 +1,27 @@
(function() {
"use strict";
function ParameterEditorController($scope, formHelper) {
const vm = this;
vm.submit = submit;
vm.close = close;
function submit() {
if ($scope.model && $scope.model.submit && formHelper.submitForm({scope: $scope})) {
$scope.model.submit($scope.model);
}
}
function close() {
if ($scope.model && $scope.model.close) {
$scope.model.close();
}
}
}
angular.module("umbraco").controller("Umbraco.Editors.ParameterEditorController", ParameterEditorController);
})();

Some files were not shown because too many files have changed in this diff Show More