Merge remote-tracking branch 'origin/temp8' into temp8-packages-ui

This commit is contained in:
Shannon
2019-01-11 10:37:22 +11:00
78 changed files with 503 additions and 890 deletions

View File

@@ -109,7 +109,7 @@
});
}
}));
}
/**
@@ -308,6 +308,18 @@
}
}
function ensureDirtyIsSetIfAnyVariantIsDirty() {
$scope.contentForm.$dirty = false;
for (var i = 0; i < $scope.content.variants.length; i++) {
if($scope.content.variants[i].isDirty){
$scope.contentForm.$dirty = true;
return;
}
}
}
// This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
function performSave(args) {
@@ -331,6 +343,7 @@
eventsService.emit("content.saved", { content: $scope.content, action: args.action });
resetNestedFieldValiation(fieldsToRollback);
ensureDirtyIsSetIfAnyVariantIsDirty();
return $q.when(data);
},

View File

@@ -3,7 +3,7 @@
function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService) {
function link(scope, element, attrs, umbVariantContentCtrl) {
function link(scope, umbVariantContentCtrl) {
var evts = [];
var isInfoTab = false;
@@ -22,19 +22,12 @@
// set currentVariant
scope.currentVariant = _.find(scope.node.variants, (v) => v.active);
// find the urls for the currently selected language
if(scope.node.variants.length > 1) {
// nodes with variants
scope.currentUrls = _.filter(scope.node.urls, (url) => scope.currentVariant.language.culture === url.culture);
} else {
// invariant nodes
scope.currentUrls = scope.node.urls;
}
updateCurrentUrls();
// if there are any infinite editors open we are in infinite editing
scope.isInfiniteMode = editorService.getNumberOfEditors() > 0 ? true : false;
userService.getCurrentUser().then(function(user){
userService.getCurrentUser().then(function (user) {
// only allow change of media type if user has access to the settings sections
const hasAccessToSettings = user.allowedSections.indexOf("settings") !== -1 ? true : false;
scope.allowChangeDocumentType = hasAccessToSettings;
@@ -42,8 +35,8 @@
});
var keys = [
"general_deleted",
"content_unpublished",
"general_deleted",
"content_unpublished",
"content_published",
"content_publishedPendingChanges",
"content_notCreated",
@@ -55,7 +48,7 @@
];
localizationService.localizeMany(keys)
.then(function(data){
.then(function (data) {
labels.deleted = data[0];
labels.unpublished = data[1]; //aka draft
labels.published = data[2];
@@ -64,9 +57,9 @@
labels.unsavedChanges = data[5];
labels.doctypeChangeWarning = data[6];
labels.notPublished = data[9];
scope.historyLabel = scope.node.variants && scope.node.variants.length === 1 ? data[7] : data[8];
setNodePublishStatus();
if (scope.currentUrls.length === 0) {
@@ -123,23 +116,23 @@
scope.openDocumentType = function (documentType) {
const variantIsDirty = _.some(scope.node.variants, function(variant) {
const variantIsDirty = _.some(scope.node.variants, function (variant) {
return variant.isDirty;
});
// add confirmation dialog before opening the doc type editor
if(variantIsDirty) {
if (variantIsDirty) {
const confirm = {
title: labels.unsavedChanges,
view: "default",
content: labels.doctypeChangeWarning,
submitButtonLabelKey: "general_continue",
closeButtonLabelKey: "general_cancel",
submit: function() {
submit: function () {
openDocTypeEditor(documentType);
overlayService.close();
},
close: function() {
close: function () {
overlayService.close();
}
};
@@ -153,12 +146,12 @@
function openDocTypeEditor(documentType) {
const editor = {
id: documentType.id,
submit: function(model) {
submit: function (model) {
const args = { node: scope.node };
eventsService.emit('editors.content.reload', args);
editorService.close();
},
close: function() {
close: function () {
editorService.close();
}
};
@@ -168,10 +161,10 @@
scope.openTemplate = function () {
var templateEditor = {
id: scope.node.templateId,
submit: function(model) {
submit: function (model) {
editorService.close();
},
close: function() {
close: function () {
editorService.close();
}
};
@@ -183,16 +176,16 @@
scope.node.template = templateAlias;
};
scope.openRollback = function() {
scope.openRollback = function () {
var rollback = {
node: scope.node,
submit: function(model) {
submit: function (model) {
const args = { node: scope.node };
eventsService.emit("editors.content.reload", args);
editorService.close();
},
close: function() {
close: function () {
editorService.close();
}
};
@@ -304,6 +297,17 @@
});
}
function updateCurrentUrls() {
// find the urls for the currently selected language
if (scope.node.variants.length > 1) {
// nodes with variants
scope.currentUrls = _.filter(scope.node.urls, (url) => scope.currentVariant.language.culture === url.culture);
} else {
// invariant nodes
scope.currentUrls = scope.node.urls;
}
}
// load audit trail and redirects when on the info tab
evts.push(eventsService.on("app.tabChange", function (event, args) {
$timeout(function () {
@@ -328,6 +332,7 @@
loadAuditTrail();
loadRedirectUrls();
setNodePublishStatus();
updateCurrentUrls();
}
});

View File

@@ -55,7 +55,7 @@ angular.module("umbraco.directives")
//initialize the standard editor functionality for Umbraco
tinyMceService.initializeEditor({
editor: editor,
value: scope.value,
model: scope,
currentForm: angularHelper.getCurrentForm(scope)
});
@@ -67,7 +67,7 @@ angular.module("umbraco.directives")
$timeout(function () {
if (scope.value === null) {
editor.trigger("focus");
editor.focus();
}
}, 400);

View File

@@ -146,7 +146,6 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
var infiniteEditors = editorService.getEditors();
if (!formCtrl.$dirty && infiniteEditors.length === 0 || isSavingNewItem && infiniteEditors.length === 0) {
confirmed = true;
return;
}

View File

@@ -1194,7 +1194,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
.css("top", "auto")
.css("margin-top", "0")
.css("width", tinyMceWidth);
}
}
},
@@ -1214,15 +1214,15 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
if (!args.editor) {
throw "args.editor is required";
}
//if (!args.value) {
// throw "args.value is required";
//if (!args.model.value) {
// throw "args.model.value is required";
//}
var unwatch = null;
//Starts a watch on the model value so that we can update TinyMCE if the model changes behind the scenes or from the server
function startWatch() {
unwatch = $rootScope.$watch(() => args.value, function (newVal, oldVal) {
unwatch = $rootScope.$watch(() => args.model.value, function (newVal, oldVal) {
if (newVal !== oldVal) {
//update the display val again if it has changed from the server;
//uses an empty string in the editor when the value is null
@@ -1247,7 +1247,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//stop watching before we update the value
stopWatch();
angularHelper.safeApply($rootScope, function () {
args.value = args.editor.getContent();
args.model.value = args.editor.getContent();
});
//re-watch the value
startWatch();
@@ -1255,8 +1255,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
args.editor.on('init', function (e) {
if (args.value) {
args.editor.setContent(args.value);
if (args.model.value) {
args.editor.setContent(args.model.value);
}
//enable browser based spell checking
args.editor.getBody().setAttribute('spellcheck', true);

View File

@@ -19,6 +19,7 @@
align-items: center;
justify-content: center;
height: @editorHeaderHeight;
position: relative;
}
.umb-sub-views-nav-item:focus {
@@ -46,6 +47,33 @@
margin-bottom: 7px;
}
.umb-sub-views-nav-item .badge {
position: absolute;
top: 6px;
right: 6px;
min-width: 16px;
color: @white;
background-color: @turquoise-d1;
border: 2px solid @white;
border-radius: 50%;
font-size: 10px;
font-weight: bold;
padding: 2px;
line-height: 16px;
display: block;
&.-type-alert {
background-color: @red-l1;
}
&.-type-warning {
background-color: @yellow-d2;
}
&:empty {
height: 12px;
min-width: 12px;
}
}
.umb-sub-views-nav-item-text {
font-size: 12px;
line-height: 1em;
@@ -80,4 +108,4 @@
grid-template-columns: 1fr 1fr 1fr;
min-width: auto;
margin-top: 10px;
}
}

View File

@@ -12,6 +12,7 @@
ng-class="{'is-active': item.active, '-has-error': item.hasError}">
<i class="icon {{ item.icon }}"></i>
<span class="umb-sub-views-nav-item-text">{{ item.name }}</span>
<div ng-show="item.badge" class="badge -type-{{item.badge.type}}">{{item.badge.count}}</div>
</a>
</div>
</li>

View File

@@ -6,11 +6,12 @@
var vm = this;
vm.loading = true;
vm.hasPristineVariants = false;
vm.isNew = true;
vm.changeSelection = changeSelection;
vm.dirtyVariantFilter = dirtyVariantFilter;
vm.pristineVariantFilter = pristineVariantFilter;
/** Returns true if publishing is possible based on if there are un-published mandatory languages */
function canPublish() {
var selected = [];
@@ -22,7 +23,7 @@
var published = !(variant.state === "NotCreated" || variant.state === "Draft");
if ((variant.language.isMandatory && !published) && (!publishable || !variant.publish)) {
//if a mandatory variant isn't published
//if a mandatory variant isn't published
//and it's not publishable or not selected to be published
//then we cannot continue
@@ -53,12 +54,35 @@
return (variant.active || variant.isDirty || variant.state === "Draft" || variant.state === "PublishedPendingChanges" || variant.state === "NotCreated");
}
function hasAnyData(variant) {
var result = variant.isDirty != null || (variant.name != null && variant.name.length > 0);
if(result) return true;
for (var t=0; t < variant.tabs.length; t++){
for (var p=0; p < variant.tabs[t].properties.length; p++){
var property = variant.tabs[t].properties[p];
if(property.culture == null) continue;
result = result || (property.value != null && property.value.length > 0);
if(result) return true;
}
}
return result;
}
function pristineVariantFilter(variant) {
return !(dirtyVariantFilter(variant));
}
function onInit() {
vm.variants = $scope.model.variants;
if (!$scope.model.title) {
@@ -69,6 +93,13 @@
vm.hasPristineVariants = false;
_.each(vm.variants,
function (variant) {
if(variant.state !== "NotCreated"){
vm.isNew = false;
}
});
_.each(vm.variants,
function (variant) {
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
@@ -78,6 +109,10 @@
if (!vm.hasPristineVariants) {
vm.hasPristineVariants = pristineVariantFilter(variant);
}
if(vm.isNew && hasAnyData(variant)){
variant.save = true;
}
});
if (vm.variants.length !== 0) {
@@ -103,8 +138,16 @@
$scope.model.disableSubmitButton = true;
}
vm.loading = false;
var labelKey = vm.isNew ? "content_languagesToPublishForFirstTime" : "content_languagesToPublish";
localizationService.localize(labelKey).then(function (value) {
vm.headline = value;
vm.loading = false;
});
}
onInit();

View File

@@ -1,7 +1,7 @@
<div ng-controller="Umbraco.Overlays.PublishController as vm">
<div style="margin-bottom: 15px;">
<p><localize key="content_languagesToPublish"></localize></p>
<p>{{vm.headline}}</p>
</div>
<div ng-if="vm.loading" style="min-height: 50px; position: relative;">
@@ -65,7 +65,7 @@
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
</div>

View File

@@ -1,16 +1,17 @@
(function () {
"use strict";
function SaveContentController($scope, localizationService) {
var vm = this;
vm.loading = true;
vm.hasPristineVariants = false;
vm.isNew = true;
vm.changeSelection = changeSelection;
vm.dirtyVariantFilter = dirtyVariantFilter;
vm.pristineVariantFilter = pristineVariantFilter;
function changeSelection(variant) {
var firstSelected = _.find(vm.variants, function (v) {
return v.save;
@@ -30,8 +31,28 @@
return !(dirtyVariantFilter(variant));
}
function onInit() {
function hasAnyData(variant) {
var result = variant.isDirty != null || (variant.name != null && variant.name.length > 0);
if(result) return true;
for (var t=0; t < variant.tabs.length; t++){
for (var p=0; p < variant.tabs[t].properties.length; p++){
var property = variant.tabs[t].properties[p];
if(property.culture == null) continue;
result = result || (property.value != null && property.value.length > 0);
if(result) return true;
}
}
return result;
}
function onInit() {
vm.variants = $scope.model.variants;
if(!$scope.model.title) {
@@ -42,6 +63,13 @@
vm.hasPristineVariants = false;
_.each(vm.variants,
function (variant) {
if(variant.state !== "NotCreated"){
vm.isNew = false;
}
});
_.each(vm.variants,
function (variant) {
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
@@ -51,6 +79,10 @@
if (!vm.hasPristineVariants) {
vm.hasPristineVariants = pristineVariantFilter(variant);
}
if(vm.isNew && hasAnyData(variant)){
variant.save = true;
}
});
if (vm.variants.length !== 0) {
@@ -88,5 +120,5 @@
}
angular.module("umbraco").controller("Umbraco.Overlays.SaveContentController", SaveContentController);
})();

View File

@@ -1,72 +1,120 @@
<div ng-controller="Umbraco.Overlays.SaveContentController as vm">
<div style="margin-bottom: 15px;">
<p><localize key="content_languagesToSave"></localize></p>
</div>
<div ng-if="vm.loading" style="min-height: 50px; position: relative;">
<umb-load-indicator></umb-load-indicator>
</div>
<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">
<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}}" />
<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>
</label>
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
</ng-form>
<div ng-if="vm.isNew && !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>
</label>
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
</ng-form>
</div>
<br/>
</div>
<br/>
</div>
<div class="umb-list umb-list--condensed" ng-if="!vm.loading && vm.hasPristineVariants">
<div style="margin-bottom: 15px; font-weight: bold;">
<p><localize key="content_unmodifiedLanguages"></localize></p>
<div ng-if="!vm.isNew && !vm.loading">
<div style="margin-bottom: 15px;">
<p><localize key="content_languagesToSave"></localize></p>
</div>
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.pristineVariantFilter">
<div>
<div style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
</div>
<div class="umb-list umb-list--condensed">
<div ng-if="!(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<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}}" />
<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>
</label>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
</ng-form>
</div>
<br/>
</div>
<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>
</div>
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.pristineVariantFilter">
<div>
<div style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
</div>
<div ng-if="!(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -58,7 +58,7 @@ angular.module("umbraco")
//initialize the standard editor functionality for Umbraco
tinyMceService.initializeEditor({
editor: editor,
value: $scope.model.value,
model: $scope.model,
currentForm: angularHelper.getCurrentForm($scope)
});