Merge remote-tracking branch 'origin/dev-v8' into temp8-server-content-validation-fixes-4884

This commit is contained in:
Shannon
2019-03-14 00:58:02 +11:00
24 changed files with 358 additions and 202 deletions
+5 -1
View File
@@ -133,7 +133,11 @@ namespace Umbraco.Core.Composing
Configs.RegisterWith(_register);
return _register.CreateFactory();
IFactory factory = null;
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
factory = _register.CreateFactory();
return factory;
}
/// <summary>
@@ -2875,7 +2875,14 @@ namespace Umbraco.Core.Services.Implement
{
foreach (var property in blueprint.Properties)
{
content.SetValue(property.Alias, property.GetValue(culture), culture);
if (property.PropertyType.VariesByCulture())
{
content.SetValue(property.Alias, property.GetValue(culture), culture);
}
else
{
content.SetValue(property.Alias, property.GetValue());
}
}
content.Name = blueprint.Name;
@@ -0,0 +1,53 @@
using System;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Tests.Composing
{
[TestFixture]
public class CompositionTests
{
[Test]
public void FactoryIsResolvable()
{
Func<IFactory, IFactory> factoryFactory = null;
var mockedRegister = Mock.Of<IRegister>();
var mockedFactory = Mock.Of<IFactory>();
// the mocked register creates the mocked factory
Mock.Get(mockedRegister)
.Setup(x => x.CreateFactory())
.Returns(mockedFactory);
// the mocked register can register a factory factory
Mock.Get(mockedRegister)
.Setup(x => x.Register(It.IsAny<Func<IFactory, IFactory>>(), Lifetime.Singleton))
.Callback<Func<IFactory, IFactory>, Lifetime>((ff, lt) => factoryFactory = ff);
// the mocked factory can invoke the factory factory
Mock.Get(mockedFactory)
.Setup(x => x.GetInstance(typeof(IFactory)))
.Returns(() => factoryFactory?.Invoke(mockedFactory));
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
// create the factory, ensure it is the mocked factory
var factory = composition.CreateFactory();
Assert.AreSame(mockedFactory, factory);
// ensure we can get an IFactory instance,
// meaning that it has been properly registered
var resolved = factory.GetInstance<IFactory>();
Assert.IsNotNull(resolved);
Assert.AreSame(factory, resolved);
}
}
}
+1
View File
@@ -118,6 +118,7 @@
<Compile Include="Cache\SnapDictionaryTests.cs" />
<Compile Include="Clr\ReflectionUtilitiesTests.cs" />
<Compile Include="Collections\OrderedHashSetTests.cs" />
<Compile Include="Composing\CompositionTests.cs" />
<Compile Include="Composing\LightInjectValidation.cs" />
<Compile Include="Composing\ContainerConformingTests.cs" />
<Compile Include="CoreThings\CallContextTests.cs" />
@@ -331,8 +331,35 @@
// This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
function performSave(args) {
// Check that all variants for publishing have a name.
if (args.action === "publish" || args.action === "sendToPublish") {
if ($scope.content.variants) {
var iVariant;
for (var i = 0; i < $scope.content.variants.length; i++) {
iVariant = $scope.content.variants[i];
iVariant.notifications = [];// maybe not needed, need to investigate.
if(iVariant.publish === true) {
if (iVariant.name == null) {
var tokens = [iVariant.language.name];
localizationService.localize("publish_contentPublishedFailedByMissingName", tokens).then(function (value) {
iVariant.notifications.push({"message": value, "type": 1});
});
return $q.reject();
}
}
}
}
}
//Used to check validility of nested form - coming from Content Apps mostly
//Set them all to be invalid
var fieldsToRollback = checkValidility();
@@ -22,38 +22,51 @@
</pre>
@param {boolean} model Set to <code>true</code> or <code>false</code> to set the checkbox to checked or unchecked.
@param {string} input-id Set the <code>id</code> of the checkbox.
@param {string} value Set the value of the checkbox.
@param {string} name Set the name of the checkbox.
@param {string} text Set the text for the checkbox label.
@param {string} server-validation-field Set the <code>val-server-field</code> of the checkbox.
@param {boolean} disabled Set the checkbox to be disabled.
@param {boolean} required Set the checkbox to be required.
@param {string} onChange Callback when the value of the input element changes.
@param {string} on-change Callback when the value of the checkbox changed by interaction.
**/
(function () {
'use strict';
function CheckboxDirective() {
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/forms/umb-checkbox.html',
scope: {
model: "=",
value: "@",
name: "@",
text: "@",
disabled: "=",
required: "=",
onChange: "&"
}
};
return directive;
function UmbCheckboxController($timeout) {
var vm = this;
vm.callOnChange = function() {
$timeout(function() {
vm.onChange({model:vm.model, value:vm.value});
}, 0);
}
}
var component = {
templateUrl: 'views/components/forms/umb-checkbox.html',
controller: UmbCheckboxController,
controllerAs: 'vm',
bindings: {
model: "=",
inputId: "@",
value: "@",
name: "@",
text: "@",
serverValidationField: "@",
disabled: "<",
required: "<",
onChange: "&"
}
};
angular.module('umbraco.directives').directive('umbCheckbox', CheckboxDirective);
angular.module('umbraco.directives').component('umbCheckbox', component);
})();
@@ -19,9 +19,15 @@ angular.module("umbraco.directives")
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope));
}
var toolbar = ["code", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbembeddialog"];
if (scope.configuration && scope.configuration.toolbar) {
toolbar = scope.configuration.toolbar;
var editorConfig = scope.configuration ? scope.configuration : null;
if (!editorConfig || angular.isString(editorConfig)) {
editorConfig = tinyMceService.defaultPrevalues();
//for the grid by default, we don't want to include the macro toolbar
editorConfig.toolbar = _.without(editorConfig, "umbmacro");
}
//make sure there's a max image size
if (!scope.configuration.maxImageSize && scope.configuration.maxImageSize !== 0) {
editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize;
}
//stores a reference to the editor
@@ -29,9 +35,9 @@ angular.module("umbraco.directives")
promises.push(tinyMceService.getTinyMceEditorConfig({
htmlId: scope.uniqueId,
stylesheets: scope.configuration ? scope.configuration.stylesheets : null,
toolbar: toolbar,
mode: scope.configuration.mode
stylesheets: editorConfig.stylesheets,
toolbar: editorConfig.toolbar,
mode: editorConfig.mode
}));
// pin toolbar to top of screen if we have focus and it scrolls off the screen
@@ -46,9 +52,16 @@ angular.module("umbraco.directives")
$q.all(promises).then(function (result) {
var tinyMceEditorConfig = result[promises.length - 1];
var standardConfig = result[promises.length - 1];
tinyMceEditorConfig.setup = function (editor) {
//create a baseline Config to extend upon
var baseLineConfigObj = {
maxImageSize: editorConfig.maxImageSize
};
angular.extend(baseLineConfigObj, standardConfig);
baseLineConfigObj.setup = function (editor) {
//set the reference
tinyMceEditor = editor;
@@ -111,7 +124,7 @@ angular.module("umbraco.directives")
//the elements needed
$timeout(function () {
tinymce.DOM.events.domLoaded = true;
tinymce.init(tinyMceEditorConfig);
tinymce.init(baseLineConfigObj);
}, 150, false);
}
@@ -22,6 +22,10 @@ a.umb-list-item:focus {
opacity: 0.6;
}
.umb-list-item--error {
color: @red;
}
.umb-list-item:hover .umb-list-checkbox,
.umb-list-item--selected .umb-list-checkbox {
opacity: 1;
@@ -34,4 +38,4 @@ a.umb-list-item:focus {
.umb-list-checkbox--visible {
opacity: 1;
}
}
@@ -113,7 +113,12 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
$scope.exitPreview = function () {
var culture = $location.search().culture || getParameterByName("culture");
var relativeUrl = "/" + $scope.pageId +'?culture='+ culture;
var relativeUrl = "/" + $scope.pageId;
if(culture){
relativeUrl +='?culture='+ culture;
}
window.top.location.href = "../preview/end?redir=" + encodeURIComponent(relativeUrl);
};
@@ -1,16 +1,19 @@
<label class="checkbox umb-form-check umb-form-check--checkbox" ng-class="{ 'umb-form-check--disabled': disabled }">
<input type="checkbox" name="{{name}}"
value="{{value}}"
<input type="checkbox"
id="{{vm.inputId}}"
name="{{vm.name}}"
value="{{vm.value}}"
class="umb-form-check__input"
ng-model="model.checked"
ng-disabled="disabled"
ng-required="required"
ng-change="onChange(model)"/>
val-server-field="{{vm.serverValidationField}}"
ng-model="vm.model"
ng-disabled="vm.disabled"
ng-required="vm.required"
ng-change="vm.callOnChange()"/>
<span class="umb-form-check__state" aria-hidden="true">
<span class="umb-form-check__check">
<i class="umb-form-check__icon icon-check"></i>
</span>
</span>
<span class="umb-form-check__text">{{text}}</span>
<span class="umb-form-check__text">{{vm.text}}</span>
</label>
@@ -14,34 +14,51 @@
/** Returns true if publishing is possible based on if there are un-published mandatory languages */
function canPublish() {
var selected = [];
var possible = false;
for (var i = 0; i < vm.variants.length; i++) {
var variant = vm.variants[i];
//if this variant will show up in the publish-able list
var publishable = dirtyVariantFilter(variant);
var published = !(variant.state === "NotCreated" || variant.state === "Draft");
if ((variant.language.isMandatory && !published) && (!publishable || !variant.publish)) {
//if a mandatory variant isn't published
//and it's not publishable or not selected to be published
//then we cannot continue
// TODO: Show a message when this occurs
var state = canVariantPublish(variant);
if (state === true) {
possible = true;
}
if (state === false) {
return false;
}
if (variant.publish) {
selected.push(variant.publish);
}
}
return selected.length > 0;
return possible;
}
/** Returns true if publishing is possible based on if the variant is a un-published mandatory language */
function canVariantPublish(variant) {
//if this variant will show up in the publish-able list
var publishable = dirtyVariantFilter(variant);
var published = !(variant.state === "NotCreated" || variant.state === "Draft");
// is this variant mandatory:
if (variant.language.isMandatory && !published && !variant.publish) {
//if a mandatory variant isn't published or set to be published
//then we cannot continue
return false;
}
// is this variant selected for publish:
if (variant.publish === true) {
return publishable;
}
return null;
}
function changeSelection(variant) {
$scope.model.disableSubmitButton = !canPublish();
//need to set the Save state to true if publish is true
variant.save = variant.publish;
variant.willPublish = canVariantPublish(variant);
}
function dirtyVariantFilter(variant) {
@@ -102,32 +119,49 @@
_.each(vm.variants,
function (variant) {
if(variant.state !== "NotCreated"){
vm.isNew = false;
if(variant.state === "NotCreated") {
vm.isNew = true;
}
});
}
);
_.each(vm.variants,
function (variant) {
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
variant.htmlId = "_content_variant_" + variant.compositeId;
// reset to not be published
variant.publish = false;
variant.save = false;
//check for pristine variants
if (!vm.hasPristineVariants) {
vm.hasPristineVariants = pristineVariantFilter(variant);
}
if(hasAnyData(variant)){
// If the variant havent been created jet.
if(variant.state === "NotCreated") {
// If the variant is mandatory, then set the variant to be published.
if (variant.language.isMandatory === true) {
variant.publish = true;
variant.save = true;
}
}
variant.canPublish = dirtyVariantFilter(variant);
// if we have data on this variant.
if(variant.canPublish && hasAnyData(variant)) {
// and if some varaints havent been saved before, or they dont have a publishing date set, then we set it for publishing.
if(vm.isNew || variant.publishDate == null){
variant.publish = true;
variant.save = true;
}
}else{
variant.publish = false;
variant.save = false;
variant.canSave = false;
}
});
variant.willPublish = canVariantPublish(variant);
}
);
if (vm.variants.length !== 0) {
//now sort it so that the current one is at the top
@@ -156,7 +190,6 @@
localizationService.localize(labelKey).then(function (value) {
vm.headline = value;
vm.loading = false;
});
@@ -10,7 +10,7 @@
<div class="umb-list umb-list--condensed" ng-if="!vm.loading">
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId">
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId" ng-class="{'umb-list-item--error': publishVariantSelectorForm.publishVariantSelector.$invalid || (variant.notifications | filter:{type:1}).length > 0}">
<ng-form name="publishVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
@@ -18,16 +18,18 @@
type="checkbox"
ng-model="variant.publish"
ng-change="vm.changeSelection(variant)"
ng-disabled="(vm.isNew && variant.language.isMandatory) || (variant.canSave === false)"
ng-disabled="(variant.canPublish === false)"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
<span ng-if="variant.language.isMandatory"> - </span>
<span ng-if="variant.language.isMandatory" ng-class="{'text-error': (variant.language.isMandatory && variant.willPublish === false) }"><localize key="languages_mandatoryLanguage"></localize></span>
</span>
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
@@ -35,7 +37,7 @@
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description text-success">{{notification.message}}</span>
<span class="db umb-permission__description" ng-class="{'text-success': notification.type === 3, 'text-error': notification.type !== 3}">{{notification.message}}</span>
</span>
</label>
</div>
@@ -22,11 +22,13 @@
<p><localize key="content_publishDescendantsWithVariantsHelp"></localize></p>
</div>
<div style="margin-bottom: 15px;">
<label>
<input type="checkbox"
ng-model="model.includeUnpublished"
style="margin-right: 8px;" />
<div style="margin-bottom: 15px;" class="flex">
<umb-checkbox
input-id="includeUnpublishedSelector"
model="model.includeUnpublished" />
<label for="includeUnpublishedSelector">
<localize key="content_includeUnpublished"></localize>
</label>
</div>
@@ -40,13 +42,14 @@
<div class="umb-list-item umb-list--condensed" ng-repeat="variant in vm.variants">
<ng-form name="publishVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
name="publishVariantSelector"
type="checkbox"
ng-model="variant.publish"
ng-change="vm.changeSelection(variant)"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<umb-checkbox
input-id="{{variant.htmlId}}"
name="publishVariantSelector"
model="variant.publish"
on-change="vm.changeSelection(variant)"
server-validation-field="{{variant.htmlId}}"/>
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 0;">
<span>{{ variant.language.name }}</span>
@@ -6,53 +6,12 @@
<umb-load-indicator></umb-load-indicator>
</div>
<div ng-if="vm.isNew && !vm.loading">
<div ng-if="!vm.loading">
<div style="margin-bottom: 15px;">
<p><localize key="content_languagesToSaveForFirstTime"></localize></p>
</div>
<div class="umb-list umb-list--condensed">
<div class="umb-list-item" ng-repeat="variant in vm.variants">
<ng-form name="saveVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
name="saveVariantSelector"
type="checkbox"
ng-model="variant.save"
ng-disabled="vm.isNew"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</span>
<span class="db" ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description text-error" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description text-success">{{notification.message}}</span>
</span>
</label>
</div>
</div>
</ng-form>
</div>
<br/>
</div>
</div>
<div ng-if="!vm.isNew && !vm.loading">
<div style="margin-bottom: 15px;">
<p><localize key="content_languagesToSave"></localize></p>
<p>
<localize ng-if="!vm.isNew" key="content_languagesToSave"></localize>
<localize ng-if="vm.isNew" key="content_languagesToSaveForFirstTime"></localize>
</p>
</div>
<div class="umb-list umb-list--condensed">
@@ -60,13 +19,14 @@
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId">
<ng-form name="saveVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
name="saveVariantSelector"
type="checkbox"
ng-model="variant.save"
ng-change="vm.changeSelection(variant)"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<umb-checkbox
input-id="{{variant.htmlId}}"
name="saveVariantSelector"
model="variant.save"
on-change="vm.changeSelection(variant)"
server-validation-field="{{variant.htmlId}}"/>
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
@@ -94,7 +54,10 @@
<div class="umb-list umb-list--condensed" ng-if="vm.hasPristineVariants">
<div style="margin-bottom: 15px; font-weight: bold;">
<p><localize key="content_unmodifiedLanguages"></localize></p>
<p>
<localize ng-if="!vm.isNew" key="content_unmodifiedLanguages"></localize>
<localize ng-if="vm.isNew" key="content_untouchedLanguagesForFirstTime"></localize>
</p>
</div>
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.pristineVariantFilter">
@@ -87,12 +87,13 @@
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter">
<ng-form name="scheduleSelectorForm">
<div class="flex">
<input id="{{'saveVariantSelector_' + variant.language.culture}}"
name="saveVariantSelector"
type="checkbox"
ng-model="variant.save"
ng-change="vm.changeSelection(variant)"
style="margin-right: 8px;" />
<umb-checkbox
input-id="{{'saveVariantSelector_' + variant.language.culture}}"
name="saveVariantSelector"
model="variant.save"
on-change="vm.changeSelection(variant)"/>
<div>
<label for="{{'saveVariantSelector_' + variant.language.culture}}" style="margin-bottom: 2px;">
@@ -13,13 +13,14 @@
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.modifiedVariantFilter">
<ng-form name="publishVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
name="publishVariantSelector"
type="checkbox"
ng-model="variant.save"
ng-change="vm.changeSelection(variant)"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<umb-checkbox
input-id="{{variant.htmlId}}"
name="publishVariantSelector"
model="variant.save"
on-change="vm.changeSelection(variant)"
server-validation-field="{{variant.htmlId}}"/>
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
@@ -16,14 +16,15 @@
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.publishedVariantFilter">
<ng-form name="unpublishVariantSelectorForm">
<div class="flex">
<input id="{{variant.htmlId}}"
name="unpublishVariantSelector"
type="checkbox"
ng-model="variant.save"
ng-change="vm.changeSelection(variant)"
ng-disabled="variant.disabled"
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<umb-checkbox
input-id="{{variant.htmlId}}"
name="unpublishVariantSelector"
model="variant.save"
on-change="vm.changeSelection(variant)"
disabled="variant.disabled"
server-validation-field="{{variant.htmlId}}"/>
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
@@ -50,8 +50,9 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
//get all of the same values between the arrays
var same = _.intersection($scope.model.value, selectedVals);
//if the lengths are the same as the value, then we are in sync, just exit
if (same.length == $scope.model.value.length === selectedVals.length) {
return;
if (same.length === $scope.model.value.length === selectedVals.length) {
return;
}
$scope.selectedItems = [];
@@ -66,18 +67,14 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
}
}
function changed(item) {
function changed(model, value) {
var index = _.findIndex($scope.model.value,
function (v) {
return v === item.val;
}
);
var index = $scope.model.value.indexOf(value);
if (item.checked) {
if (model) {
//if it doesn't exist in the model, then add it
if (index < 0) {
$scope.model.value.push(item.val);
$scope.model.value.push(value);
}
} else {
//if it exists in the model, then remove it
@@ -1,7 +1,7 @@
<div class="umb-property-editor umb-checkboxlist" ng-controller="Umbraco.PropertyEditors.CheckboxListController">
<ul class="unstyled">
<li ng-repeat="item in selectedItems track by item.key">
<umb-checkbox name="{{model.alias}}" value="{{item.val}}" model="item" text="{{item.val}}" on-change="changed(item)" required="model.validation.mandatory && !model.value.length"></umb-checkbox>
<umb-checkbox name="{{model.alias}}" value="{{item.val}}" model="item.checked" text="{{item.val}}" on-change="changed(model, value)" required="model.validation.mandatory && !model.value.length"></umb-checkbox>
</li>
</ul>
</div>
@@ -17,12 +17,13 @@ angular.module("umbraco")
if (!editorConfig || angular.isString(editorConfig)) {
editorConfig = tinyMceService.defaultPrevalues();
}
var promises = [];
if (!editorConfig.maxImageSize && editorConfig.maxImageSize != 0) {
//make sure there's a max image size
if (!editorConfig.maxImageSize && editorConfig.maxImageSize !== 0) {
editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize;
}
var promises = [];
//queue file loading
if (typeof tinymce === "undefined") { // Don't reload tinymce if already loaded
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope));
@@ -43,7 +44,7 @@ angular.module("umbraco")
var standardConfig = result[promises.length - 1];
//create a baseline Config to exten upon
//create a baseline Config to extend upon
var baseLineConfigObj = {
maxImageSize: editorConfig.maxImageSize
};
@@ -271,13 +271,14 @@
<key alias="languagesToPublishForFirstTime">Hvilke sprog vil du gerne udgive? Alle sprog med indhold gemmes!</key>
<key alias="languagesToPublish">Hvilke sprog vil du gerne udgive?</key>
<key alias="languagesToSave">Hvilke sprog vil du gerne gemme?</key>
<key alias="languagesToSaveForFirstTime">Alle sprog med indhold gemmes ved oprettelsen!</key>
<key alias="languagesToSaveForFirstTime">Hvilke sprog vil du gerne gemme?</key>
<key alias="languagesToSendForApproval">Hvilke sprog vil du gerne sende til godkendelse?</key>
<key alias="languagesToSchedule">Hvilke sprog vil du gerne planlægge?</key>
<key alias="languagesToUnpublish">Vælg sproget du vil afpublicere. Afpublicering af et obligatorisk sprog vil afpublicere alle sprog.</key>
<key alias="publishedLanguages">Udgivne sprog</key>
<key alias="unpublishedLanguages">Ikke-udgivne sprog</key>
<key alias="unmodifiedLanguages">Uændrede sprog</key>
<key alias="unmodifiedLanguages">Uændrede sprog</key>
<key alias="untouchedLanguagesForFirstTime">Disse sprog er ikke blevet oprettet</key>
<key alias="readyToPublish">Klar til at udgive?</key>
<key alias="readyToSave">Klar til at gemme?</key>
<key alias="sendForApproval">Send til godkendelse</key>
@@ -985,7 +986,8 @@ Mange hilsner fra Umbraco robotten
<key alias="contentPublishedFailedInvalid"><![CDATA[
%0% kunne ikke publiceres da følgende egenskaber : %1% ikke overholdte valderingsreglerne.
]]></key>
<key alias="contentPublishedFailedByEvent">%0% kunne ikke udgives, fordi et 3. parts modul annullerede handlingen</key>
<key alias="contentPublishedFailedByEvent">%0% kunne ikke udgives, fordi et 3. parts modul annullerede handlingen</key>
<key alias="contentPublishedFailedByMissingName"><![CDATA[%0% kan ikke udgives, fordi det mangler et navn.]]></key>
<key alias="includeUnpublished">Medtag ikke-udgivede undersider</key>
<key alias="inProgress">Publicerer - vent venligst...</key>
<key alias="inProgressCounter">%0% ud af %1% sider er blevet udgivet...</key>
@@ -281,13 +281,14 @@
<key alias="languagesToPublishForFirstTime">What languages would you like to publish? All languages with content are saved!</key>
<key alias="languagesToPublish">What languages would you like to publish?</key>
<key alias="languagesToSave">What languages would you like to save?</key>
<key alias="languagesToSaveForFirstTime">All languages with content are saved on creation!</key>
<key alias="languagesToSaveForFirstTime">What languages would you like to save?</key>
<key alias="languagesToSendForApproval">What languages would you like to send for approval?</key>
<key alias="languagesToSchedule">What languages would you like to schedule?</key>
<key alias="languagesToUnpublish">Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages.</key>
<key alias="publishedLanguages">Published Languages</key>
<key alias="unpublishedLanguages">Unpublished Languages</key>
<key alias="unmodifiedLanguages">Unmodified Languages</key>
<key alias="unmodifiedLanguages">Unmodified Languages</key>
<key alias="untouchedLanguagesForFirstTime">These languages haven't been created</key>
<key alias="readyToPublish">Ready to Publish?</key>
<key alias="readyToSave">Ready to Save?</key>
<key alias="sendForApproval">Send for approval</key>
@@ -1235,7 +1236,8 @@ To manage your website, simply open the Umbraco back office and start adding con
]]></key>
<key alias="contentPublishedFailedByParent"><![CDATA[
%0% can not be published, because a parent page is not published.
]]></key>
]]></key>
<key alias="contentPublishedFailedByMissingName"><![CDATA[%0% can not be published, because its missing a name.]]></key>
<key alias="includeUnpublished">Include unpublished subpages</key>
<key alias="inProgress">Publishing in progress - please wait...</key>
<key alias="inProgressCounter">%0% out of %1% pages have been published...</key>
@@ -283,13 +283,14 @@
<key alias="languagesToPublishForFirstTime">What languages would you like to publish? All languages with content are saved!</key>
<key alias="languagesToPublish">What languages would you like to publish?</key>
<key alias="languagesToSave">What languages would you like to save?</key>
<key alias="languagesToSaveForFirstTime">All languages with content are saved on creation!</key>
<key alias="languagesToSaveForFirstTime">What languages would you like to save?</key>
<key alias="languagesToSendForApproval">What languages would you like to send for approval?</key>
<key alias="languagesToSchedule">What languages would you like to schedule?</key>
<key alias="languagesToUnpublish">Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages.</key>
<key alias="publishedLanguages">Published Languages</key>
<key alias="unpublishedLanguages">Unpublished Languages</key>
<key alias="unmodifiedLanguages">Unmodified Languages</key>
<key alias="untouchedLanguagesForFirstTime">These languages haven't been created</key>
<key alias="readyToPublish">Ready to Publish?</key>
<key alias="readyToSave">Ready to Save?</key>
<key alias="sendForApproval">Send for approval</key>
@@ -1239,7 +1240,8 @@ To manage your website, simply open the Umbraco back office and start adding con
]]></key>
<key alias="contentPublishedFailedByParent"><![CDATA[
%0% can not be published, because a parent page is not published.
]]></key>
]]></key>
<key alias="contentPublishedFailedByMissingName"><![CDATA[%0% can not be published, because its missing a name.]]></key>
<key alias="inProgress">Publishing in progress - please wait...</key>
<key alias="inProgressCounter">%0% out of %1% pages have been published...</key>
<key alias="nodePublish">%0% has been published</key>
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
@@ -14,11 +15,18 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
[DefaultPropertyValueConverter]
public class MediaPickerValueConverter : PropertyValueConverterBase
{
// hard-coding "image" here but that's how it works at UI level too
private const string ImageTypeAlias = "image";
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
public MediaPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor)
public MediaPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor,
IPublishedModelFactory publishedModelFactory)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
_publishedSnapshotAccessor = publishedSnapshotAccessor ??
throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
_publishedModelFactory = publishedModelFactory;
}
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -31,11 +39,13 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var isMultiple = IsMultipleDataType(propertyType.DataType);
var isOnlyImages = IsOnlyImagesDataType(propertyType.DataType);
// hard-coding "image" here but that's how it works at UI level too
return isMultiple
? (isOnlyImages ? typeof(IEnumerable<>).MakeGenericType(ModelType.For("image")) : typeof(IEnumerable<IPublishedContent>))
: (isOnlyImages ? ModelType.For("image") : typeof(IPublishedContent));
? isOnlyImages
? typeof(IEnumerable<>).MakeGenericType(ModelType.For(ImageTypeAlias))
: typeof(IEnumerable<IPublishedContent>)
: isOnlyImages
? ModelType.For(ImageTypeAlias)
: typeof(IPublishedContent);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
@@ -53,7 +63,8 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return config.OnlyImages;
}
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType,
object source, bool preview)
{
if (source == null) return null;
@@ -64,15 +75,19 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return nodeIds;
}
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType,
PropertyCacheLevel cacheLevel, object source, bool preview)
{
if (source == null)
{
return null;
}
var isMultiple = IsMultipleDataType(propertyType.DataType);
var isOnlyImages = IsOnlyImagesDataType(propertyType.DataType);
var udis = (Udi[]) source;
var mediaItems = isOnlyImages
? _publishedModelFactory.CreateModelList(ImageTypeAlias)
: new List<IPublishedContent>();
if (source == null) return isMultiple ? mediaItems : null;
var udis = (Udi[])source;
var mediaItems = new List<IPublishedContent>();
if (udis.Any())
{
foreach (var udi in udis)
@@ -84,12 +99,15 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
mediaItems.Add(item);
}
if (IsMultipleDataType(propertyType.DataType))
return mediaItems;
return mediaItems.FirstOrDefault();
return isMultiple ? mediaItems : FirstOrDefault(mediaItems);
}
return source;
}
private object FirstOrDefault(IList mediaItems)
{
return mediaItems.Count == 0 ? null : mediaItems[0];
}
}
}