Merge branch 'temp8' into temp8-tree-sections-no-more-xml
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ _Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md).
|
||||
|
||||
When is Umbraco 8 coming?
|
||||
=========================
|
||||
When it's ready. We're done with the major parts of the architecture work and are focusing on three seperate tracks to prepare Umbraco 8 for release:
|
||||
When it's ready. We're done with the major parts of the architecture work and are focusing on three separate tracks to prepare Umbraco 8 for release:
|
||||
1) Editor Track (_currently in progress_). Without editors, there's no market for Umbraco. So we want to make sure that Umbraco 8 is full of love for editors.
|
||||
2) Partner Track. Without anyone implementing Umbraco, there's nothing for editors to update. So we want to make sure that Umbraco 8 is a joy to implement
|
||||
3) Contributor Track. Without our fabulous ecosystem of both individual Umbracians and 3rd party ISVs, Umbraco wouldn't be as rich a platform as it is today. We want to make sure that it's easy, straight forward and as backwards-compatible as possible to create packages for Umbraco
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@
|
||||
*.suo
|
||||
*.vs10x
|
||||
*.ndproj
|
||||
*.ignorer.*
|
||||
|
||||
# common directories
|
||||
.DS_Store
|
||||
@@ -156,4 +157,4 @@ build/temp/
|
||||
|
||||
|
||||
|
||||
# eof
|
||||
# eof
|
||||
|
||||
@@ -22,20 +22,17 @@ namespace Umbraco.Core.Deploy
|
||||
/// Gets the value to be deployed from the control value as a string.
|
||||
/// </summary>
|
||||
/// <param name="gridControl">The control containing the value.</param>
|
||||
/// <param name="property">The property where the control is located. Do not modify - only used for context</param>
|
||||
/// <param name="dependencies">The dependencies of the property.</param>
|
||||
/// <returns>The grid cell value to be deployed.</returns>
|
||||
/// <remarks>Note that </remarks>
|
||||
string GetValue(GridValue.GridControl gridControl, Property property, ICollection<ArtifactDependency> dependencies);
|
||||
string GetValue(GridValue.GridControl gridControl, ICollection<ArtifactDependency> dependencies);
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to modify the value of a control being deployed.
|
||||
/// </summary>
|
||||
/// <param name="gridControl">The control being deployed.</param>
|
||||
/// <param name="property">The property where the <paramref name="gridControl"/> is located. Do not modify - only used for context.</param>
|
||||
/// <remarks>Follows the pattern of the property value connectors (<see cref="IValueConnector"/>). The SetValue method is used to modify the value of the <paramref name="gridControl"/>.</remarks>
|
||||
/// <remarks>Note that only the <paramref name="gridControl"/> value should be modified - not the <paramref name="property"/>.</remarks>
|
||||
/// <remarks>The <paramref name="property"/> should only be used to assist with context data relevant when setting the <paramref name="gridControl"/> value.</remarks>
|
||||
void SetValue(GridValue.GridControl gridControl, Property property);
|
||||
|
||||
void SetValue(GridValue.GridControl gridControl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,18 @@ namespace Umbraco.Core.Deploy
|
||||
/// Gets the deploy property value corresponding to a content property value, and gather dependencies.
|
||||
/// </summary>
|
||||
/// <param name="value">The content property value.</param>
|
||||
/// <param name="propertyType">The value property type</param>
|
||||
/// <param name="dependencies">The content dependencies.</param>
|
||||
/// <returns>The deploy property value.</returns>
|
||||
string ToArtifact(object value, ICollection<ArtifactDependency> dependencies);
|
||||
string ToArtifact(object value, PropertyType propertyType, ICollection<ArtifactDependency> dependencies);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content property value corresponding to a deploy property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The deploy property value.</param>
|
||||
/// <param name="propertyType">The value property type<</param>
|
||||
/// <param name="currentValue">The current content property value.</param>
|
||||
/// <returns>The content property value.</returns>
|
||||
object FromArtifact(string value, object currentValue);
|
||||
object FromArtifact(string value, PropertyType propertyType, object currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
|
||||
/// <summary>
|
||||
/// Reads settings from /config/serilog.user.config
|
||||
/// That allows a seperate logging pipeline to be configured that wil not affect the main Umbraco log
|
||||
/// That allows a separate logging pipeline to be configured that wil not affect the main Umbraco log
|
||||
/// </summary>
|
||||
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
|
||||
public static LoggerConfiguration ReadFromUserConfigFile(this LoggerConfiguration logConfig)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Configuration;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade
|
||||
@@ -122,6 +123,7 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<MakeTagsVariant>("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
|
||||
To<MakeRedirectUrlVariant>("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
|
||||
To<AddContentTypeIsElementColumn>("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}");
|
||||
To<UpdateMemberGroupPickerData>("{8A027815-D5CD-4872-8B88-9A51AB5986A6}"); // from 7.14.0
|
||||
|
||||
|
||||
//FINAL
|
||||
@@ -145,12 +147,23 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
// main chain, skipping the migrations
|
||||
//
|
||||
From("{init-7.12.0}");
|
||||
// start stop target
|
||||
// clone start / clone stop / target
|
||||
ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}");
|
||||
|
||||
From("{init-7.12.1}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
From("{init-7.12.2}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
From("{init-7.12.3}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
|
||||
|
||||
// 7.14.0 has migrations, handle it...
|
||||
// clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
|
||||
// clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),
|
||||
// ending in 8A027815 (after 7.14 migrations)
|
||||
From("{init-7.14.0}")
|
||||
.ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{9109B8AF-6B34-46EE-9484-7434196D0C79}")
|
||||
.ToWithClone("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}", "{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}", "{8A027815-D5CD-4872-8B88-9A51AB5986A6}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_7_14_0
|
||||
{
|
||||
/// <summary>
|
||||
/// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
|
||||
/// </summary>
|
||||
public class UpdateMemberGroupPickerData : MigrationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
|
||||
/// </summary>
|
||||
public UpdateMemberGroupPickerData(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
Database.Execute($@"UPDATE umbracoPropertyData SET textValue = varcharValue, varcharValue = NULL
|
||||
WHERE textValue IS NULL AND id IN (
|
||||
SELECT id FROM umbracoPropertyData WHERE propertyTypeId in (
|
||||
SELECT id from cmsPropertyType where dataTypeId IN (
|
||||
SELECT nodeId FROM umbracoDataType WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'
|
||||
)
|
||||
)
|
||||
)");
|
||||
|
||||
Database.Execute($"UPDATE umbracoDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
|
||||
|
||||
if (modelInfos.TryGetValue(typeName, out var modelInfo))
|
||||
throw new InvalidOperationException($"Both types {type.FullName} and {modelInfo.ModelType.FullName} want to be a model type for content type with alias \"{typeName}\".");
|
||||
throw new InvalidOperationException($"Both types '{type.AssemblyQualifiedName}' and '{modelInfo.ModelType.AssemblyQualifiedName}' want to be a model type for content type with alias \"{typeName}\".");
|
||||
|
||||
// have to use an unsafe ctor because we don't know the types, really
|
||||
var modelCtor = ReflectionUtilities.EmitConstructorUnsafe<Func<object, object>>(constructor);
|
||||
|
||||
@@ -892,7 +892,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the folder path ends with a DirectorySeperatorChar
|
||||
/// Ensures that the folder path ends with a DirectorySeparatorChar
|
||||
/// </summary>
|
||||
/// <param name="currentFolder"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -367,6 +367,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_7_12_0\RenameTrueFalseField.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_12_0\SetDefaultTagsStorageType.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_12_0\UpdateUmbracoConsent.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_14_0\UpdateMemberGroupPickerData.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_8_0\AddIndexToPropertyTypeAliasColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_8_0\AddInstructionCountColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_8_0\AddMediaVersionTable.cs" />
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
var doc = GetContent(true, 1);
|
||||
//change a doc type alias
|
||||
var c = (TestPublishedContent) doc.Children.ElementAt(0);
|
||||
var c = (TestPublishedContent)doc.Children.ElementAt(0);
|
||||
c.ContentType = new PublishedContentType(22, "DontMatch", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
|
||||
var dt = doc.ChildrenAsTable(Current.Services, "Child");
|
||||
|
||||
@@ -4163,7 +4163,7 @@ html {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text--center .seperator {
|
||||
.text--center .separator {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@@ -4998,4 +4998,4 @@ nav > ul li.active ul li a {
|
||||
</PreValues>
|
||||
</DataType>
|
||||
</DataTypes>
|
||||
</umbPackage>
|
||||
</umbPackage>
|
||||
|
||||
@@ -8,10 +8,6 @@ namespace Umbraco.Tests.Testing.Objects.Accessors
|
||||
public class TestVariationContextAccessor : IVariationContextAccessor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public VariationContext VariationContext
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public VariationContext VariationContext { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+52
@@ -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/"
|
||||
}
|
||||
};
|
||||
Executable
+10
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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();
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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();
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
+18
@@ -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');
|
||||
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
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) {
|
||||
|
||||
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(config.root + config.targets.js));
|
||||
|
||||
console.log(out + " compiled");
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
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})
|
||||
];
|
||||
|
||||
return gulp.src(files)
|
||||
.pipe(less())
|
||||
.pipe(cleanCss())
|
||||
.pipe(postcss(processors))
|
||||
.pipe(rename(out))
|
||||
.pipe(gulp.dest(config.root + config.targets.css));
|
||||
|
||||
console.log(out + " compiled");
|
||||
}
|
||||
+9
@@ -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));
|
||||
};
|
||||
Regular → Executable
+14
-587
@@ -1,587 +1,14 @@
|
||||
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-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(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.
|
||||
*/
|
||||
|
||||
require('./gulp');
|
||||
|
||||
+21
-7
@@ -5204,12 +5204,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -5224,17 +5226,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -5351,7 +5356,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -5363,6 +5369,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -5377,6 +5384,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -5384,12 +5392,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -5408,6 +5418,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -5488,7 +5499,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -5500,6 +5512,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -5621,6 +5634,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "karma start test/config/karma.conf.js --singlerun",
|
||||
"build": "gulp"
|
||||
"build": "gulp build",
|
||||
"dev": "gulp dev",
|
||||
"docs": "gulp docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "1.4.2",
|
||||
@@ -62,6 +64,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 +73,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"
|
||||
}
|
||||
}
|
||||
|
||||
+10
-9
@@ -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;
|
||||
|
||||
+2
@@ -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) {
|
||||
|
||||
+9
-3
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -640,7 +640,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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+48
-16
@@ -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();
|
||||
@@ -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
|
||||
});
|
||||
};
|
||||
|
||||
+2
-2
@@ -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">/</span>
|
||||
<span class="umb-breadcrumbs__separator">/</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">/</span>
|
||||
<span class="umb-breadcrumbs__separator">/</span>
|
||||
</li>
|
||||
|
||||
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
|
||||
|
||||
+1
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">/</span>
|
||||
<span ng-if="!$last" class="umb-breadcrumbs__separator">/</span>
|
||||
|
||||
<span class="umb-breadcrumbs__ancestor-text" ng-if="$last" title="{{ancestor.name}}">{{ancestor.name}}</span>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
alias="$parent.alias"
|
||||
alias-from="$parent.name"
|
||||
enable-lock="true"
|
||||
validation-position="'right'"
|
||||
server-validation-field="Alias">
|
||||
</umb-generate-alias>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
locked="locked"
|
||||
ng-model="alias"
|
||||
placeholder-text="placeholderText"
|
||||
validation-position="validationPosition"
|
||||
server-validation-field="{{serverValidationField}}">
|
||||
</umb-locked-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,9 +29,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>
|
||||
|
||||
@@ -1,26 +1,91 @@
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController",
|
||||
function ($scope, relationResource, mediaResource, navigationService, appState, treeService, localizationService) {
|
||||
function ($scope, relationResource, mediaResource, entityResource, navigationService, appState, treeService, userService) {
|
||||
|
||||
$scope.source = _.clone($scope.currentNode);
|
||||
|
||||
$scope.error = null;
|
||||
$scope.success = false;
|
||||
$scope.loading = true;
|
||||
$scope.moving = false;
|
||||
$scope.success = false;
|
||||
|
||||
$scope.dialogTreeApi = {};
|
||||
$scope.searchInfo = {
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
function nodeSelectHandler(args) {
|
||||
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, { event: evt, node: result });
|
||||
};
|
||||
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
|
||||
$scope.onTreeInit = function () {
|
||||
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
|
||||
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
|
||||
}
|
||||
|
||||
// Mini list view
|
||||
$scope.selectListViewNode = function (node) {
|
||||
node.selected = node.selected === true ? false : true;
|
||||
nodeSelectHandler({}, { node: node });
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function () {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
|
||||
relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) {
|
||||
$scope.loading = false;
|
||||
|
||||
if (!data.length) {
|
||||
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_noRestoreRelation"])
|
||||
.then(function(values) {
|
||||
$scope.success = false;
|
||||
$scope.error = {
|
||||
errorMsg: values[0],
|
||||
data: {
|
||||
Message: values[1]
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.moving = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,40 +95,31 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController",
|
||||
$scope.target = { id: -1, name: "Root" };
|
||||
|
||||
} else {
|
||||
$scope.loading = true;
|
||||
mediaResource.getById($scope.relation.parentId).then(function (data) {
|
||||
$scope.loading = false;
|
||||
$scope.target = data;
|
||||
// make sure the target item isn't in the recycle bin
|
||||
if ($scope.target.path.indexOf("-21") !== -1) {
|
||||
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_restoreUnderRecycled"])
|
||||
.then(function (values) {
|
||||
$scope.success = false;
|
||||
$scope.error = {
|
||||
errorMsg: values[0],
|
||||
data: {
|
||||
Message: values[1].replace('%0%', $scope.target.name)
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.success = false;
|
||||
}
|
||||
$scope.loading = true;
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
entityResource.getById($scope.relation.parentId, "media").then(function (data) {
|
||||
$scope.loading = false;
|
||||
});
|
||||
$scope.target = data;
|
||||
|
||||
// make sure the target item isn't in the recycle bin
|
||||
if ($scope.target.path.indexOf("-21") !== -1) {
|
||||
$scope.moving = true;
|
||||
$scope.target = null;
|
||||
}
|
||||
}, function (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
}
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
|
||||
$scope.restore = function () {
|
||||
$scope.loading = true;
|
||||
$scope.loading = true;
|
||||
|
||||
// this code was copied from `content.move.controller.js`
|
||||
mediaResource.move({ parentId: $scope.target.id, id: $scope.source.id })
|
||||
.then(function (path) {
|
||||
@@ -89,9 +145,8 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController",
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,87 @@
|
||||
<div ng-controller="Umbraco.Editors.Media.RestoreController">
|
||||
<div class="umb-dialog-body">
|
||||
<umb-pane>
|
||||
<div class="umb-dialog-body">
|
||||
<umb-pane>
|
||||
<umb-load-indicator ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<umb-load-indicator
|
||||
ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="abstract" ng-hide="loading || error != null || success">
|
||||
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
|
||||
</p>
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong>
|
||||
<span ng-hide="moving"><localize key="recycleBin_wasRestored">was restored under</localize></span>
|
||||
<span ng-show="moving"><localize key="editdatatype_wasMoved">was moved underneath</localize></span>
|
||||
<strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-hide="moving || loading || success">
|
||||
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()"><localize key="general_ok">Ok</localize></button>
|
||||
</div>
|
||||
<p class="abstract" ng-hide="error || success">
|
||||
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
|
||||
</p>
|
||||
|
||||
</umb-pane>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
|
||||
</div>
|
||||
<div ng-hide="!moving || loading || success">
|
||||
<div>
|
||||
<div class="alert alert-info">
|
||||
<div><strong><localize key="recycleBin_itemCannotBeRestored">Cannot automatically restore this item</localize></strong></div>
|
||||
<div><localize key="recycleBin_itemCannotBeRestoredHelpText">There is no location where this item can be automatically restored. You can move the item manually using the tree below.</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree-search-box hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="media">
|
||||
</umb-tree-search-box>
|
||||
|
||||
<br />
|
||||
|
||||
<umb-tree-search-results ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree section="media"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
api="dialogTreeApi"
|
||||
on-init="onTreeInit()"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="Document"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || moving || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || !moving || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null" ng-disabled="!target"><localize key="actions_move">Move</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -437,7 +437,7 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
view: "views/propertyeditors/listview/overlays/listviewpublish.html",
|
||||
submitButtonLabelKey: "actions_publish",
|
||||
submit: function (model) {
|
||||
// create a comma seperated array of selected cultures
|
||||
// create a comma separated array of selected cultures
|
||||
let selectedCultures = [];
|
||||
if (model.languages && model.languages.length > 0) {
|
||||
model.languages.forEach(language => {
|
||||
@@ -492,7 +492,7 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
submitButtonLabelKey: "actions_unpublish",
|
||||
submit: function (model) {
|
||||
|
||||
// create a comma seperated array of selected cultures
|
||||
// create a comma separated array of selected cultures
|
||||
let selectedCultures = [];
|
||||
if (model.languages && model.languages.length > 0) {
|
||||
model.languages.forEach(language => {
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Umbraco.Web.Editors
|
||||
continue;
|
||||
}
|
||||
|
||||
//Find position in current comma seperate string path (so we get the correct children path)
|
||||
//Find position in current comma separate string path (so we get the correct children path)
|
||||
var positionInPath = childTemplate.Path.IndexOf(templateIdInPath) + templateIdInPath.Length;
|
||||
|
||||
//Get the substring of the child & any children (descendants it may have too)
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
/// <summary>
|
||||
/// Path represents the path used by the backoffice tree
|
||||
/// For files stored on disk, this is a urlencoded, comma seperated
|
||||
/// For files stored on disk, this is a urlencoded, comma separated
|
||||
/// path to the file, always starting with -1.
|
||||
///
|
||||
/// -1,Partials,Parials%2FFolder,Partials%2FFolder%2FFile.cshtml
|
||||
|
||||
@@ -10,18 +10,18 @@ namespace Umbraco.Web.Models.Trees
|
||||
{
|
||||
public override string AngularServiceName => "umbracoMenuActions";
|
||||
|
||||
public CreateChildEntity(string name, bool seperatorBefore = false)
|
||||
public CreateChildEntity(string name, bool separatorBefore = false)
|
||||
: base(ActionNew.ActionAlias, name)
|
||||
{
|
||||
Icon = "add"; Name = name;
|
||||
SeperatorBefore = seperatorBefore;
|
||||
SeparatorBefore = separatorBefore;
|
||||
}
|
||||
|
||||
public CreateChildEntity(ILocalizedTextService textService, bool seperatorBefore = false)
|
||||
public CreateChildEntity(ILocalizedTextService textService, bool separatorBefore = false)
|
||||
: base(ActionNew.ActionAlias, textService)
|
||||
{
|
||||
Icon = "add";
|
||||
SeperatorBefore = seperatorBefore;
|
||||
SeparatorBefore = separatorBefore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
{
|
||||
Name = name.IsNullOrWhiteSpace() ? action.Alias : name;
|
||||
Alias = action.Alias;
|
||||
SeperatorBefore = false;
|
||||
SeparatorBefore = false;
|
||||
Icon = action.Icon;
|
||||
Action = action;
|
||||
}
|
||||
@@ -80,8 +80,8 @@ namespace Umbraco.Web.Models.Trees
|
||||
/// <summary>
|
||||
/// Ensures a menu separator will exist before this menu item
|
||||
/// </summary>
|
||||
[DataMember(Name = "seperator")]
|
||||
public bool SeperatorBefore { get; set; }
|
||||
[DataMember(Name = "separator")]
|
||||
public bool SeparatorBefore { get; set; }
|
||||
|
||||
[DataMember(Name = "cssclass")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
if (item == null) return null;
|
||||
var menuItem = new MenuItem(item, name)
|
||||
{
|
||||
SeperatorBefore = hasSeparator,
|
||||
SeparatorBefore = hasSeparator,
|
||||
OpensDialog = opensDialog
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
|
||||
var menuItem = new MenuItem(item, textService.Localize($"actions/{item.Alias}"))
|
||||
{
|
||||
SeperatorBefore = hasSeparator,
|
||||
SeparatorBefore = hasSeparator,
|
||||
OpensDialog = opensDialog
|
||||
};
|
||||
|
||||
|
||||
@@ -10,18 +10,18 @@ namespace Umbraco.Web.Models.Trees
|
||||
{
|
||||
public override string AngularServiceName => "umbracoMenuActions";
|
||||
|
||||
public RefreshNode(string name, bool seperatorBefore = false)
|
||||
public RefreshNode(string name, bool separatorBefore = false)
|
||||
: base("refreshNode", name)
|
||||
{
|
||||
Icon = "refresh";
|
||||
SeperatorBefore = seperatorBefore;
|
||||
SeparatorBefore = separatorBefore;
|
||||
}
|
||||
|
||||
public RefreshNode(ILocalizedTextService textService, bool seperatorBefore = false)
|
||||
public RefreshNode(ILocalizedTextService textService, bool separatorBefore = false)
|
||||
: base("refreshNode", textService)
|
||||
{
|
||||
Icon = "refresh";
|
||||
SeperatorBefore = seperatorBefore;
|
||||
SeparatorBefore = separatorBefore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
@@ -8,6 +9,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
public bool ShowOpenButton { get; set; }
|
||||
|
||||
[ConfigurationField("startNodeId", "Start node", "treepicker")] // + config in configuration editor ctor
|
||||
public int StartNodeId { get; set; } = -1; // default value is -1
|
||||
public Udi StartNodeId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
@@ -17,6 +18,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
public bool DisableFolderSelect { get; set; }
|
||||
|
||||
[ConfigurationField("startNodeId", "Start node", "mediapicker")]
|
||||
public int StartNodeId { get; set; }
|
||||
public Udi StartNodeId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MemberGroupPicker, "Member Group Picker", "membergrouppicker", Group="People", Icon="icon-users")]
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MemberGroupPicker, "Member Group Picker", "membergrouppicker", ValueType = ValueTypes.Text, Group = "People", Icon = "icon-users")]
|
||||
public class MemberGroupPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public MemberGroupPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
@@ -15,6 +16,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
public string StartNodeQuery {get;set;}
|
||||
|
||||
[JsonProperty("id")]
|
||||
public int? StartNodeId {get;set;}
|
||||
public Udi StartNodeId {get;set;}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,9 +154,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
public override string Name => _name;
|
||||
|
||||
public override PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException();
|
||||
public override PublishedCultureInfo GetCulture(string culture = null) => null;
|
||||
|
||||
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => throw new NotSupportedException();
|
||||
private static readonly Lazy<Dictionary<string, PublishedCultureInfo>> NoCultures = new Lazy<Dictionary<string, PublishedCultureInfo>>(() => new Dictionary<string, PublishedCultureInfo>());
|
||||
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => NoCultures.Value;
|
||||
|
||||
public override string UrlSegment => _urlName;
|
||||
|
||||
|
||||
@@ -136,9 +136,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
public override PublishedCultureInfo GetCulture(string culture = null) => throw new NotSupportedException();
|
||||
public override PublishedCultureInfo GetCulture(string culture = null) => null;
|
||||
|
||||
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => throw new NotSupportedException();
|
||||
private static readonly Lazy<Dictionary<string, PublishedCultureInfo>> NoCultures = new Lazy<Dictionary<string, PublishedCultureInfo>>(() => new Dictionary<string, PublishedCultureInfo>());
|
||||
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => NoCultures.Value;
|
||||
|
||||
public override string WriterName
|
||||
{
|
||||
|
||||
@@ -4,9 +4,7 @@ using System.Data;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Examine;
|
||||
using Examine.Search;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -268,6 +266,21 @@ namespace Umbraco.Web
|
||||
public static bool HasCulture(this IPublishedContent content, string culture)
|
||||
=> content.Cultures.ContainsKey(culture);
|
||||
|
||||
/// <summary>
|
||||
/// Filters a sequence of <see cref="IPublishedContent"/> to return invariant items, and items that are published for the specified culture.
|
||||
/// </summary>
|
||||
/// <param name="contents">The content items.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null).</param>
|
||||
internal static IEnumerable<IPublishedContent> WhereIsInvariantOrHasCulture(this IEnumerable<IPublishedContent> contents, string culture = null)
|
||||
{
|
||||
if (contents == null) throw new ArgumentNullException(nameof(contents));
|
||||
|
||||
culture = culture ?? Current.VariationContextAccessor.VariationContext?.Culture ?? "";
|
||||
|
||||
// either does not vary by culture, or has the specified culture
|
||||
return contents.Where(x => !x.ContentType.VariesByCulture() || x.HasCulture(culture));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Search
|
||||
@@ -767,27 +780,29 @@ namespace Umbraco.Web
|
||||
/// </summary>
|
||||
/// <param name="parentNodes"></param>
|
||||
/// <param name="docTypeAlias"></param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
|
||||
/// </remarks>
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias)
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string culture = null)
|
||||
{
|
||||
return parentNodes.SelectMany(x => x.DescendantsOrSelf(docTypeAlias));
|
||||
return parentNodes.SelectMany(x => x.DescendantsOrSelf(docTypeAlias, culture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all DescendantsOrSelf of all content referenced
|
||||
/// </summary>
|
||||
/// <param name="parentNodes"></param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
|
||||
/// </remarks>
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IEnumerable<IPublishedContent> parentNodes)
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IEnumerable<IPublishedContent> parentNodes, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return parentNodes.SelectMany(x => x.DescendantsOrSelf<T>());
|
||||
return parentNodes.SelectMany(x => x.DescendantsOrSelf<T>(culture));
|
||||
}
|
||||
|
||||
|
||||
@@ -810,133 +825,133 @@ namespace Umbraco.Web
|
||||
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
|
||||
// - children and descendants occur before following siblings.
|
||||
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content)
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(false, null);
|
||||
return content.DescendantsOrSelf(false, null, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, int level)
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, int level, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(false, p => p.Level >= level);
|
||||
return content.DescendantsOrSelf(false, p => p.Level >= level, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string contentTypeAlias)
|
||||
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string contentTypeAlias, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(false, p => p.ContentType.Alias == contentTypeAlias);
|
||||
return content.DescendantsOrSelf(false, p => p.ContentType.Alias == contentTypeAlias, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Descendants<T>(this IPublishedContent content)
|
||||
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Descendants().OfType<T>();
|
||||
return content.Descendants(culture).OfType<T>();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, int level)
|
||||
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, int level, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Descendants(level).OfType<T>();
|
||||
return content.Descendants(level, culture).OfType<T>();
|
||||
}
|
||||
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content)
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(true, null);
|
||||
return content.DescendantsOrSelf(true, null, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, int level)
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(true, p => p.Level >= level);
|
||||
return content.DescendantsOrSelf(true, p => p.Level >= level, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias)
|
||||
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null)
|
||||
{
|
||||
return content.DescendantsOrSelf(true, p => p.ContentType.Alias == contentTypeAlias);
|
||||
return content.DescendantsOrSelf(true, p => p.ContentType.Alias == contentTypeAlias, culture);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content)
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.DescendantsOrSelf().OfType<T>();
|
||||
return content.DescendantsOrSelf(culture).OfType<T>();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, int level)
|
||||
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, int level, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.DescendantsOrSelf(level).OfType<T>();
|
||||
return content.DescendantsOrSelf(level, culture).OfType<T>();
|
||||
}
|
||||
|
||||
public static IPublishedContent Descendant(this IPublishedContent content)
|
||||
public static IPublishedContent Descendant(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
return content.Children.FirstOrDefault();
|
||||
return content.Children(culture).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IPublishedContent Descendant(this IPublishedContent content, int level)
|
||||
public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null)
|
||||
{
|
||||
return content.EnumerateDescendants(false).FirstOrDefault(x => x.Level == level);
|
||||
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level);
|
||||
}
|
||||
|
||||
public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias)
|
||||
public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture = null)
|
||||
{
|
||||
return content.EnumerateDescendants(false).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
|
||||
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
|
||||
}
|
||||
|
||||
public static T Descendant<T>(this IPublishedContent content)
|
||||
public static T Descendant<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.EnumerateDescendants(false).FirstOrDefault(x => x is T) as T;
|
||||
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x is T) as T;
|
||||
}
|
||||
|
||||
public static T Descendant<T>(this IPublishedContent content, int level)
|
||||
public static T Descendant<T>(this IPublishedContent content, int level, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Descendant(level) as T;
|
||||
return content.Descendant(level, culture) as T;
|
||||
}
|
||||
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content)
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level)
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
|
||||
{
|
||||
return content.EnumerateDescendants(true).FirstOrDefault(x => x.Level == level);
|
||||
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level);
|
||||
}
|
||||
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias)
|
||||
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null)
|
||||
{
|
||||
return content.EnumerateDescendants(true).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
|
||||
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
|
||||
}
|
||||
|
||||
public static T DescendantOrSelf<T>(this IPublishedContent content)
|
||||
public static T DescendantOrSelf<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.EnumerateDescendants(true).FirstOrDefault(x => x is T) as T;
|
||||
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x is T) as T;
|
||||
}
|
||||
|
||||
public static T DescendantOrSelf<T>(this IPublishedContent content, int level)
|
||||
public static T DescendantOrSelf<T>(this IPublishedContent content, int level, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.DescendantOrSelf(level) as T;
|
||||
return content.DescendantOrSelf(level, culture) as T;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func<IPublishedContent, bool> func)
|
||||
internal static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func<IPublishedContent, bool> func, string culture = null)
|
||||
{
|
||||
return content.EnumerateDescendants(orSelf).Where(x => func == null || func(x));
|
||||
return content.EnumerateDescendants(orSelf, culture).Where(x => func == null || func(x));
|
||||
}
|
||||
|
||||
internal static IEnumerable<IPublishedContent> EnumerateDescendants(this IPublishedContent content, bool orSelf)
|
||||
internal static IEnumerable<IPublishedContent> EnumerateDescendants(this IPublishedContent content, bool orSelf, string culture = null)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (orSelf) yield return content;
|
||||
|
||||
foreach (var desc in content.Children.SelectMany(x => x.EnumerateDescendants()))
|
||||
foreach (var desc in content.Children(culture).SelectMany(x => x.EnumerateDescendants()))
|
||||
yield return desc;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IPublishedContent> EnumerateDescendants(this IPublishedContent content)
|
||||
internal static IEnumerable<IPublishedContent> EnumerateDescendants(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
yield return content;
|
||||
|
||||
foreach (var desc in content.Children.SelectMany(x => x.EnumerateDescendants()))
|
||||
foreach (var desc in content.Children(culture).SelectMany(x => x.EnumerateDescendants()))
|
||||
yield return desc;
|
||||
}
|
||||
|
||||
@@ -1026,15 +1041,25 @@ namespace Umbraco.Web
|
||||
/// Gets the children of the content.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns>The children of the content.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Children are sorted by their sortOrder.</para>
|
||||
/// <para>This method exists for consistency, it is the same as calling content.Children as a property.</para>
|
||||
/// </remarks>
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content)
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
return content.Children;
|
||||
|
||||
//
|
||||
return content.Children.Where(x =>
|
||||
{
|
||||
if (!x.ContentType.VariesByCulture()) return true; // invariant = always ok
|
||||
return x.HasCulture(culture);
|
||||
return false;
|
||||
});
|
||||
|
||||
return content.Children.WhereIsInvariantOrHasCulture(culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1042,24 +1067,26 @@ namespace Umbraco.Web
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="predicate">The predicate.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns>The children of the content, filtered by the predicate.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Children are sorted by their sortOrder.</para>
|
||||
/// </remarks>
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, Func<IPublishedContent, bool> predicate)
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, Func<IPublishedContent, bool> predicate, string culture = null)
|
||||
{
|
||||
return content.Children().Where(predicate);
|
||||
return content.Children(culture).Where(predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content, of any of the specified types.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <param name="alias">One or more content type alias.</param>
|
||||
/// <returns>The children of the content, of any of the specified types.</returns>
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, params string[] alias)
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null, params string[] alias)
|
||||
{
|
||||
return content.Children(x => alias.InvariantContains(x.ContentType.Alias));
|
||||
return content.Children(x => alias.InvariantContains(x.ContentType.Alias), culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1067,19 +1094,20 @@ namespace Umbraco.Web
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The content type.</typeparam>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns>The children of content, of the given content type.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Children are sorted by their sortOrder.</para>
|
||||
/// </remarks>
|
||||
public static IEnumerable<T> Children<T>(this IPublishedContent content)
|
||||
public static IEnumerable<T> Children<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Children().OfType<T>();
|
||||
return content.Children(culture).OfType<T>();
|
||||
}
|
||||
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content)
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
return content.Children().FirstOrDefault();
|
||||
return content.Children(culture).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1088,26 +1116,26 @@ namespace Umbraco.Web
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="alias">The content type alias.</param>
|
||||
/// <returns>The first child of content, of the given content type.</returns>
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content, string alias)
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture = null)
|
||||
{
|
||||
return content.Children(alias).FirstOrDefault();
|
||||
return content.Children(culture,alias).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content, Func<IPublishedContent, bool> predicate)
|
||||
public static IPublishedContent FirstChild(this IPublishedContent content, Func<IPublishedContent, bool> predicate, string culture = null)
|
||||
{
|
||||
return content.Children(predicate).FirstOrDefault();
|
||||
return content.Children(predicate, culture).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static T FirstChild<T>(this IPublishedContent content)
|
||||
public static T FirstChild<T>(this IPublishedContent content, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Children<T>().FirstOrDefault();
|
||||
return content.Children<T>(culture).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static T FirstChild<T>(this IPublishedContent content, Func<T, bool> predicate)
|
||||
public static T FirstChild<T>(this IPublishedContent content, Func<T, bool> predicate, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
return content.Children<T>().FirstOrDefault(predicate);
|
||||
return content.Children<T>(culture).FirstOrDefault(predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1116,10 +1144,11 @@ namespace Umbraco.Web
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="services">A service context.</param>
|
||||
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns>The children of the content.</returns>
|
||||
public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "")
|
||||
public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null)
|
||||
{
|
||||
return GenerateDataTable(content, services, contentTypeAliasFilter);
|
||||
return GenerateDataTable(content, services, contentTypeAliasFilter, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1128,14 +1157,15 @@ namespace Umbraco.Web
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="services">A service context.</param>
|
||||
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
|
||||
/// <returns>The children of the content.</returns>
|
||||
private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "")
|
||||
private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null)
|
||||
{
|
||||
var firstNode = contentTypeAliasFilter.IsNullOrWhiteSpace()
|
||||
? content.Children.Any()
|
||||
? content.Children.ElementAt(0)
|
||||
? content.Children(culture).Any()
|
||||
? content.Children(culture).ElementAt(0)
|
||||
: null
|
||||
: content.Children.FirstOrDefault(x => x.ContentType.Alias == contentTypeAliasFilter);
|
||||
: content.Children(culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAliasFilter);
|
||||
if (firstNode == null)
|
||||
return new DataTable(); //no children found
|
||||
|
||||
|
||||
@@ -646,7 +646,30 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug<PublishedRouter>("EnsurePublishedContentAccess: Current member has access");
|
||||
// grab the current member
|
||||
var member = membershipHelper.GetCurrentMember();
|
||||
// if the member has the "approved" and/or "locked out" properties, make sure they're correctly set before allowing access
|
||||
var memberIsActive = true;
|
||||
if (member != null)
|
||||
{
|
||||
if (member.HasProperty(Constants.Conventions.Member.IsApproved) == false)
|
||||
memberIsActive = member.Value<bool>(Constants.Conventions.Member.IsApproved);
|
||||
|
||||
if (member.HasProperty(Constants.Conventions.Member.IsLockedOut) == false)
|
||||
memberIsActive = member.Value<bool>(Constants.Conventions.Member.IsLockedOut) == false;
|
||||
}
|
||||
|
||||
if (memberIsActive == false)
|
||||
{
|
||||
_logger.Debug<PublishedRouter>("Current member is either unapproved or locked out, redirect to error page");
|
||||
var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
|
||||
if (errorPageId != request.PublishedContent.Id)
|
||||
request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug<PublishedRouter>("Current member has access");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Umbraco.Web.Trees
|
||||
|
||||
if (menu.Items.Any())
|
||||
{
|
||||
menu.Items.Last().SeperatorBefore = true;
|
||||
menu.Items.Last().SeparatorBefore = true;
|
||||
}
|
||||
|
||||
// add default actions for *all* users
|
||||
@@ -237,14 +237,16 @@ namespace Umbraco.Web.Trees
|
||||
AddActionNode<ActionRights>(item, menu, opensDialog: true);
|
||||
//fixme - conver this editor to angular
|
||||
AddActionNode<ActionProtect>(item, menu, true, convert: true, opensDialog: true);
|
||||
|
||||
menu.Items.Add(new MenuItem("notify", Services.TextService)
|
||||
if (EmailSender.CanSendRequiredEmail)
|
||||
{
|
||||
Icon = "megaphone",
|
||||
SeperatorBefore = true,
|
||||
OpensDialog = true
|
||||
});
|
||||
|
||||
menu.Items.Add(new MenuItem("notify", Services.TextService)
|
||||
{
|
||||
Icon = "megaphone",
|
||||
SeparatorBefore = true,
|
||||
OpensDialog = true
|
||||
});
|
||||
}
|
||||
|
||||
menu.Items.Add(new RefreshNode(Services.TextService, true));
|
||||
|
||||
return menu;
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Umbraco.Web.Trees
|
||||
menu.Items.Add(new MenuItem("importDocumentType", Services.TextService)
|
||||
{
|
||||
Icon = "page-up",
|
||||
SeperatorBefore = true,
|
||||
SeparatorBefore = true,
|
||||
OpensDialog = true
|
||||
});
|
||||
menu.Items.Add(new RefreshNode(Services.TextService, true));
|
||||
@@ -130,7 +130,7 @@ namespace Umbraco.Web.Trees
|
||||
menu.Items.Add(new MenuItem("export", Services.TextService)
|
||||
{
|
||||
Icon = "download-alt",
|
||||
SeperatorBefore = true,
|
||||
SeparatorBefore = true,
|
||||
OpensDialog = true
|
||||
});
|
||||
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
|
||||
|
||||
@@ -832,7 +832,7 @@ namespace Umbraco.Web
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins any number of int/string/objects into one string and seperates them with the string seperator parameter.
|
||||
/// Joins any number of int/string/objects into one string and separates them with the string separator parameter.
|
||||
/// </summary>
|
||||
public string Join(string separator, params object[] args)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user