From d3b97ae23ceda5118e64b279a81771b1290988d0 Mon Sep 17 00:00:00 2001
From: Emma Garland
Date: Fri, 10 Jul 2020 16:33:45 +0100
Subject: [PATCH 001/197] Tour Data progress is not in a cookie - it is stored
in the database (what the User has completed so far) in a column in the
umbracoUser table. Since we want to act like the tour has not been run
before, at the start and end of each test we need to clean up by resetting
the tour data so that the default user in the database hasn't already
completed the tour. I used the similar command style from the
umbraco-cypress-testhelpers project - we may want to move this out of the
test itself, but I wanted to make sure this approach was right first.
---
.../integration/Tour/backofficeTour.ts | 118 +++++++++++++-----
1 file changed, 84 insertions(+), 34 deletions(-)
diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts
index ed891a2eea..e3928e3c32 100644
--- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts
+++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts
@@ -1,49 +1,99 @@
///
+
context('Backoffice Tour', () => {
beforeEach(() => {
+ //arrange
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
+ resetTourData();
});
it('Backoffice introduction tour should run', () => {
- //arrange
- cy.umbracoGlobalHelp().should("be.visible");
-
//act
- cy.umbracoGlobalHelp().click()
+ cy.umbracoGlobalHelp().should("be.visible");
+ cy.umbracoGlobalHelp().click();
+ runBackOfficeIntroTour(0, 'Start');
+
//assert
cy.get('[data-element="help-tours"]').should("be.visible");
- //act
cy.get('[data-element="help-tours"]').click();
- //assert
- cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').should("be.visible");
+ cy.get('[data-element="help-tours"] .umb-progress-circle', { timeout: 60000 }).contains('17%');
+ });
+
+ it('Backoffice introduction tour should run then rerun', () => {
//act
- cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').click();
- //assert
- cy.get('.umb-tour-step', { timeout: 60000 }).should('be.visible');
- cy.get('.umb-tour-step__footer').should('be.visible');
- cy.get('.umb-tour-step__counter').should('be.visible');
-
- for(let i=1;i<7;i++){
- cy.get('.umb-tour-step__counter').contains(i + '/12');
- cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
- }
- cy.umbracoGlobalUser().click()
- cy.get('.umb-tour-step__counter').contains('8/12');
- cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
- cy.get('.umb-tour-step__counter').contains('9/12');
- cy.get('.umb-overlay-drawer__align-right .umb-button').should('be.visible').click();
- cy.get('.umb-tour-step__counter').contains('10/12');
- cy.umbracoGlobalHelp().click()
-
- for(let i=11;i<13;i++){
- cy.get('.umb-tour-step__counter').contains(i + '/12');
- cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
- }
- cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
-
- //assert
cy.umbracoGlobalHelp().should("be.visible");
- cy.get('[data-element="help-tours"] .umb-progress-circle').contains('17%');
- });
+ cy.umbracoGlobalHelp().click();
+ runBackOfficeIntroTour(0, 'Start');
+ runBackOfficeIntroTour(17, 'Rerun');
+
+ //assert
+ cy.get('[data-element="help-tours"]').should("be.visible");
+ cy.get('[data-element="help-tours"]').click();
+ cy.get('[data-element="help-tours"] .umb-progress-circle', { timeout: 60000 }).contains('17%');
+ cy.umbracoGlobalHelp().should("be.visible");
+ });
});
+
+afterEach(() => {
+ //cleanup
+ resetTourData();
+});
+
+function resetTourData() {
+ var tourStatus =
+ {
+ "alias": "umbIntroIntroduction",
+ "completed": false,
+ "disabled": false
+ };
+
+ cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => {
+ cy.request({
+ method: 'POST',
+ url: '/umbraco/backoffice/UmbracoApi/CurrentUser/PostSetUserTour',
+ followRedirect: false,
+ headers: {
+ ContentType: 'application/json',
+ 'X-UMB-XSRF-TOKEN': token.value,
+ },
+ body: tourStatus,
+ }).then((resp) => {
+ return;
+ });
+ })
+}
+
+function runBackOfficeIntroTour(percentageComplete, buttonText) {
+ cy.get('[data-element="help-tours"]').should("be.visible");
+ cy.get('[data-element="help-tours"]').click();
+ cy.get('[data-element="help-tours"] .umb-progress-circle', { timeout: 60000 }).contains(percentageComplete + '%');
+ cy.get('[data-element="help-tours"]').click();
+ cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').should("be.visible");
+ cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').contains(buttonText);
+ cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').click();
+ //act
+ cy.get('.umb-tour-step', { timeout: 60000 }).should('be.visible');
+ cy.get('.umb-tour-step__footer').should('be.visible');
+ cy.get('.umb-tour-step__counter').should('be.visible');
+
+ for (let i = 1; i < 7; i++) {
+ cy.get('.umb-tour-step__counter').contains(i + '/12');
+ cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
+ }
+ cy.umbracoGlobalUser().click()
+ cy.get('.umb-tour-step__counter', { timeout: 10000 }).contains('8/12');
+ cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
+ cy.get('.umb-tour-step__counter', { timeout: 10000 }).contains('9/12');
+ cy.get('.umb-overlay-drawer__align-right .umb-button').should('be.visible').click();
+ cy.get('.umb-tour-step__counter', { timeout: 10000 }).contains('10/12');
+ cy.umbracoGlobalHelp().click()
+
+ for (let i = 11; i < 13; i++) {
+ cy.get('.umb-tour-step__counter', { timeout: 10000 }).contains(i + '/12');
+ cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
+ }
+ cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click();
+
+ cy.umbracoGlobalHelp().should("be.visible");
+}
\ No newline at end of file
From 47986ec0f59a6f73544ac312739c4a79aa1fd66d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Thu, 30 Jul 2020 15:01:29 +0200
Subject: [PATCH 002/197] limit control-label effect to the first
control-label, these 3 new lines covers all cases that i could find in CMS.
---
src/Umbraco.Web.UI.Client/src/less/mixins.less | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/less/mixins.less b/src/Umbraco.Web.UI.Client/src/less/mixins.less
index a87080a326..9739a90dae 100644
--- a/src/Umbraco.Web.UI.Client/src/less/mixins.less
+++ b/src/Umbraco.Web.UI.Client/src/less/mixins.less
@@ -138,7 +138,9 @@
// additional targetting of the ng-invalid class.
.formFieldState(@textColor: @gray-4, @borderColor: @gray-7, @backgroundColor: @gray-10) {
// Set the text color
- .control-label,
+ > .control-label,
+ > .umb-el-wrap > .control-label,
+ > .umb-el-wrap > .control-header > .control-label,
.help-block,
.help-inline {
color: @textColor;
From 55805eabc3ab87571f23b9f40e60cc8fa4b7ea6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Thu, 30 Jul 2020 15:26:40 +0200
Subject: [PATCH 003/197] make the required-star as bold as possible.
---
src/Umbraco.Web.UI.Client/src/less/main.less | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less
index ce20b8dc88..2354e96d38 100644
--- a/src/Umbraco.Web.UI.Client/src/less/main.less
+++ b/src/Umbraco.Web.UI.Client/src/less/main.less
@@ -272,6 +272,7 @@ label:not([for]) {
/* CONTROL VALIDATION */
.umb-control-required {
color: @controlRequiredColor;
+ font-weight: 900;
}
.controls-row {
From 33afbb8af6c4cb9127d46a36d447adb3e99b69b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Thu, 30 Jul 2020 16:13:22 +0200
Subject: [PATCH 004/197] added validation-error badge to navigation item
---
.../src/less/components/umb-editor-navigation-item.less | 8 ++++++++
.../components/editor/umb-editor-navigation-item.html | 1 +
2 files changed, 9 insertions(+)
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
index cb673e3c6f..c2f3e0f04d 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
@@ -101,6 +101,10 @@
height: 12px;
min-width: 12px;
}
+ &.--error-badge {
+ display: none;
+ font-weight: 900;
+ }
}
&-text {
@@ -191,4 +195,8 @@
&::before {
background-color: @red;
}
+ .badge.--error-badge {
+ display: block;
+ }
+
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html
index 484e0175c5..9e5669f443 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html
@@ -9,6 +9,7 @@
{{ vm.item.name }}
{{vm.item.badge.count}}
+
!
From 0e82ec9995c3af78d6dcffd6bc1efd9854150a34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 09:45:52 +0200
Subject: [PATCH 005/197] moved and changed validation css
---
.../umb-editor-navigation-item.less | 30 ++++++++++---------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
index c2f3e0f04d..b3720feb3d 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
@@ -53,6 +53,22 @@
height: 4px;
}
}
+
+ // Validation
+ .show-validation &.-has-error {
+ color: @red;
+
+ &:hover {
+ color: @red !important;
+ }
+
+ &::before {
+ background-color: @red;
+ }
+ .badge.--error-badge {
+ display: block;
+ }
+ }
}
&__action:active,
@@ -186,17 +202,3 @@
}
}
}
-
-// Validation
-.show-validation .umb-sub-views-nav-item__action.-has-error,
-.show-validation .umb-sub-views-nav-item > a.-has-error {
- color: @red;
-
- &::before {
- background-color: @red;
- }
- .badge.--error-badge {
- display: block;
- }
-
-}
From 20779dff017610c95acfb373bbde5a3f586c8c0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 10:47:01 +0200
Subject: [PATCH 006/197] speach bubble look for property-errors
---
.../lib/bootstrap/less/alerts.less | 17 ++++++++++++
.../src/less/alerts.less | 27 +++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
index 0116b191b3..c999481032 100644
--- a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
+++ b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
@@ -77,3 +77,20 @@
.alert-block p + p {
margin-top: 5px;
}
+
+
+// Property error alerts
+// -------------------------
+.alert.property-error {
+ &::after {
+ content:'';
+ position: absolute;
+ bottom:0;
+ left: 32px;
+ width: 0;
+ height: 0;
+ border-left: 8px solid transparent;
+ border-right: 8px solid transparent;
+ border-top: 8px solid @warningBackground;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/alerts.less b/src/Umbraco.Web.UI.Client/src/less/alerts.less
index 3907b59f58..3539e21064 100644
--- a/src/Umbraco.Web.UI.Client/src/less/alerts.less
+++ b/src/Umbraco.Web.UI.Client/src/less/alerts.less
@@ -7,6 +7,7 @@
// -------------------------
.alert {
+ position: relative;
padding: 8px 35px 8px 14px;
margin-bottom: @baseLineHeight;
background-color: @warningBackground;
@@ -98,3 +99,29 @@
.alert-block p + p {
margin-top: 5px;
}
+
+
+// Property error alerts
+// -------------------------
+.alert.property-error {
+
+ display: inline-block;
+ font-size: 14px;
+ padding: 6px 16px 6px 12px;
+ margin-bottom: 6px;
+
+ &::after {
+ content:'';
+ position: absolute;
+ bottom:-6px;
+ left: 6px;
+ width: 0;
+ height: 0;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-top: 6px solid;
+ }
+ &.alert-error::after {
+ border-top-color: @errorBackground;
+ }
+}
From 8d6cafa45635f3d8bebb0d7cce64741dc1827cc5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 10:57:51 +0200
Subject: [PATCH 007/197] remove again, this is not begin used.
---
.../lib/bootstrap/less/alerts.less | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
index c999481032..0116b191b3 100644
--- a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
+++ b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/alerts.less
@@ -77,20 +77,3 @@
.alert-block p + p {
margin-top: 5px;
}
-
-
-// Property error alerts
-// -------------------------
-.alert.property-error {
- &::after {
- content:'';
- position: absolute;
- bottom:0;
- left: 32px;
- width: 0;
- height: 0;
- border-left: 8px solid transparent;
- border-right: 8px solid transparent;
- border-top: 8px solid @warningBackground;
- }
-}
From bbe2d3a9b69b586ed40455dc3c87d2b57d988bf1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 11:25:40 +0200
Subject: [PATCH 008/197] fixing create from element type, now that udi is
changed to contentUdi
---
.../src/common/services/blockeditormodelobject.service.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
index fe57534ffb..d744f8277f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
@@ -730,7 +730,7 @@
return null;
}
- var dataModel = getDataByUdi(layoutEntry.udi, this.value.contentData);
+ var dataModel = getDataByUdi(layoutEntry.contentUdi, this.value.contentData);
if (dataModel === null) {
return null;
}
From 16c66b5141bd30b6fc2c71a540372940f206f8df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 11:30:21 +0200
Subject: [PATCH 009/197] deleteAllBlocks fixed (dont know what up with
whitespace now)
---
.../umbBlockListPropertyEditor.component.js | 62 +++++++++----------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
index 327677c6b9..5d6b1dcd14 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
@@ -29,7 +29,7 @@
});
function BlockListController($scope, editorService, clipboardService, localizationService, overlayService, blockEditorService, udiService, serverValidationManager, angularHelper) {
-
+
var unsubscribe = [];
var modelObject;
@@ -84,7 +84,7 @@
vm.validationLimit = vm.model.config.validationLimit;
vm.listWrapperStyles = {};
-
+
if (vm.model.config.maxPropertyWidth) {
vm.listWrapperStyles['max-width'] = vm.model.config.maxPropertyWidth;
}
@@ -100,7 +100,7 @@
} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) {
scopeOfExistence = vm.umbElementEditorContent.getScope();
}
-
+
// Create Model Object, to manage our data for this Block Editor.
modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence, $scope);
modelObject.load().then(onLoaded);
@@ -124,7 +124,7 @@
copyAllBlocksAction,
deleteAllBlocksAction
];
-
+
if (vm.umbProperty) {
vm.umbProperty.setPropertyActions(propertyActions);
}
@@ -132,7 +132,7 @@
// Called when we save the value, the server may return an updated data and our value is re-synced
// we need to deal with that here so that our model values are all in sync so we basically re-initialize.
- function onServerValueChanged(newVal, oldVal) {
+ function onServerValueChanged(newVal, oldVal) {
// We need to ensure that the property model value is an object, this is needed for modelObject to recive a reference and keep that updated.
if (typeof newVal !== 'object' || newVal === null) {// testing if we have null or undefined value or if the value is set to another type than Object.
@@ -142,13 +142,13 @@
modelObject.update(newVal, $scope);
onLoaded();
}
-
+
function setDirty() {
if (vm.propertyForm) {
vm.propertyForm.$setDirty();
}
}
-
+
function onLoaded() {
// Store a reference to the layout model, because we need to maintain this model.
@@ -161,7 +161,7 @@
// $block must have the data property to be a valid BlockObject, if not its considered as a destroyed blockObject.
if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) {
var block = getBlockObject(entry);
-
+
// If this entry was not supported by our property-editor it would return 'null'.
if (block !== null) {
entry.$block = block;
@@ -192,7 +192,7 @@
}
function getDefaultViewForBlock(block) {
-
+
if (block.config.unsupported === true)
return "views/propertyeditors/blocklist/blocklistentryeditors/unsupportedblock/unsupportedblock.editor.html";
@@ -207,8 +207,8 @@
if (block === null) return null;
// ensure that the containing content variant language/culture is transfered along
- // to the scaffolded content object representing this block. This is required for validation
- // along with ensuring that the umb-property inheritance is constently maintained.
+ // to the scaffolded content object representing this block. This is required for validation
+ // along with ensuring that the umb-property inheritance is constently maintained.
if (vm.umbVariantContent.editor.content.language) {
block.content.language = vm.umbVariantContent.editor.content.language;
// currently we only ever deal with invariant content for blocks so there's only one
@@ -243,7 +243,7 @@
if (blockObject === null) {
return false;
}
-
+
// If we reach this line, we are good to add the layoutEntry and blockObject to our models.
// Add the Block Object to our layout entry.
@@ -251,7 +251,7 @@
// add layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
-
+
// lets move focus to this new block.
vm.setBlockFocus(blockObject);
@@ -271,7 +271,7 @@
var removed = vm.layout.splice(layoutIndex, 1);
removed.forEach(x => {
// remove any server validation errors associated
- var guid = udiService.getKey(x.contentUdi);
+ var guid = udiService.getKey(x.contentUdi);
serverValidationManager.removePropertyError(guid, vm.umbProperty.property.culture, vm.umbProperty.property.segment, "", { matchType: "contains" });
});
@@ -280,11 +280,11 @@
}
function deleteAllBlocks() {
- vm.layout.forEach(entry => {
- deleteBlock(entry.$block);
- });
+ while(vm.layout.length) {
+ deleteBlock(vm.layout[0].$block);
+ };
}
-
+
function activateBlock(blockObject) {
blockObject.active = true;
}
@@ -317,7 +317,7 @@
if (blockObject.config.settingsElementTypeKey) {
blockSettingsClone = Utilities.copy(blockObject.settings);
}
-
+
var blockEditorModel = {
$parentScope: $scope, // pass in a $parentScope, this maintains the scope inheritance in infinite editing
$parentForm: parentForm || vm.propertyForm, // pass in a $parentForm, this maintains the FormController hierarchy with the infinite editing view (if it contains a form)
@@ -366,11 +366,11 @@
vm.showCreateDialog = showCreateDialog;
function showCreateDialog(createIndex, $event) {
-
+
if (vm.blockTypePicker) {
return;
}
-
+
if (vm.availableBlockTypes.length === 0) {
return;
}
@@ -405,7 +405,7 @@
if (blockPickerModel && blockPickerModel.selectedItem) {
added = addNewBlock(createIndex, blockPickerModel.selectedItem.blockConfigModel.contentTypeKey);
}
-
+
if(!(mouseEvent.ctrlKey || mouseEvent.metaKey)) {
editorService.close();
if (added && vm.layout.length > createIndex) {
@@ -448,7 +448,7 @@
}
);
});
-
+
var arrayEntriesForPaste = clipboardService.retriveEntriesOfType("elementTypeArray", vm.availableContentTypesAliases);
arrayEntriesForPaste.forEach(function (entry) {
blockPickerModel.clipboardItems.push(
@@ -472,13 +472,13 @@
var requestCopyAllBlocks = function() {
var elementTypesToCopy = vm.layout.filter(entry => entry.$block.config.unsupported !== true).map(entry => entry.$block.content);
-
+
// list aliases
var aliases = elementTypesToCopy.map(content => content.contentTypeAlias);
// remove dublicates
aliases = aliases.filter((item, index) => aliases.indexOf(item) === index);
-
+
var contentNodeName = "";
if(vm.umbVariantContent) {
contentNodeName = vm.umbVariantContent.editor.content.name;
@@ -494,7 +494,7 @@
clipboardService.copy("elementType", block.content.contentTypeAlias, block.content, block.label);
}
function requestPasteFromClipboard(index, pasteEntry) {
-
+
if (pasteEntry === undefined) {
return false;
}
@@ -512,7 +512,7 @@
// set the BlockObject on our layout entry.
layoutEntry.$block = blockObject;
-
+
// insert layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
@@ -565,7 +565,7 @@
copyBlock: copyBlock,
requestDeleteBlock: requestDeleteBlock,
deleteBlock: deleteBlock,
- openSettingsForBlock: openSettingsForBlock
+ openSettingsForBlock: openSettingsForBlock
}
vm.sortableOptions = {
@@ -594,15 +594,15 @@
var isMinRequirementGood = vm.validationLimit.min === null || vm.layout.length >= vm.validationLimit.min;
vm.propertyForm.minCount.$setValidity("minCount", isMinRequirementGood);
-
+
var isMaxRequirementGood = vm.validationLimit.max === null || vm.layout.length <= vm.validationLimit.max;
vm.propertyForm.maxCount.$setValidity("maxCount", isMaxRequirementGood);
-
+
}
}
unsubscribe.push($scope.$watch(() => vm.layout.length, onAmountOfBlocksChanged));
-
+
$scope.$on("$destroy", function () {
for (const subscription of unsubscribe) {
subscription();
From 47203f71117f1572031d4fe97977b8684a5f0cdb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Fri, 31 Jul 2020 14:05:07 +0200
Subject: [PATCH 010/197] discard changes dialog
---
.../blockeditor/blockeditor.controller.js | 25 ++++++++++++++++++-
src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 2 ++
src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 ++
.../Umbraco/config/lang/en_us.xml | 2 ++
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
index f515cbb4ba..4d79ecb7b4 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
@@ -1,6 +1,6 @@
angular.module("umbraco")
.controller("Umbraco.Editors.BlockEditorController",
- function ($scope, localizationService, formHelper) {
+ function ($scope, localizationService, formHelper, overlayService) {
var vm = this;
vm.model = $scope.model;
@@ -67,6 +67,29 @@ angular.module("umbraco")
// * It would have a 'commit' method to commit the removed errors - which we would call in the formHelper.submitForm when it's successful
// * It would have a 'rollback' method to reset the removed errors - which we would call here
+
+ if (vm.blockForm.$dirty === true) {
+ localizationService.localizeMany(["prompt_discardChanges", "blockEditor_blockHasChanges"]).then(function (localizations) {
+ const confirm = {
+ title: localizations[0],
+ view: "default",
+ content: localizations[1],
+ submitButtonLabelKey: "general_discard",
+ submitButtonStyle: "danger",
+ closeButtonLabelKey: "general_cancel",
+ submit: function () {
+ overlayService.close();
+ vm.model.close(vm.model);
+ },
+ close: function () {
+ overlayService.close();
+ }
+ };
+ overlayService.open(confirm);
+ });
+
+ return;
+ }
// TODO: check if content/settings has changed and ask user if they are sure.
vm.model.close(vm.model);
}
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
index e3d456dea7..a7957c5afd 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
@@ -647,6 +647,7 @@
DesignOrdbogDimensioner
+ DiscardNedHentRediger
@@ -1851,6 +1852,7 @@ Mange hilsner fra Umbraco robotten
IndstillingerAvanceretSkjuld indholds editoren
+ Du har lavet ændringer til dette indhold. Er du sikker på at du vil kassere dem?
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
index 8355c36bd1..d72ee33d6c 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
@@ -675,6 +675,7 @@
DesignDictionaryDimensions
+ DiscardDownDownloadEdit
@@ -2467,6 +2468,7 @@ To manage your website, simply open the Umbraco back office and start adding con
SettingsAdvancedForce hide content editor
+ You have made changes to this content. Are you sure you want to discard them?What are Content Templates?
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
index fccd11a5aa..cb31695268 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
@@ -682,6 +682,7 @@
DesignDictionaryDimensions
+ DiscardDownDownloadEdit
@@ -2487,6 +2488,7 @@ To manage your website, simply open the Umbraco back office and start adding con
SettingsAdvancedForce hide content editor
+ You have made changes to this content. Are you sure you want to discard them?What are Content Templates?
From d06c1e01a7e36eedfdd2bb34119b90afa7ab9f9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Mon, 3 Aug 2020 11:27:32 +0200
Subject: [PATCH 011/197] Update da.xml
translate to danish
---
src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
index a7957c5afd..997fa577b7 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
@@ -647,7 +647,7 @@
DesignOrdbogDimensioner
- Discard
+ KassérNedHentRediger
From c7d42d94d0c112b0b2650c3c22a6860aebee0739 Mon Sep 17 00:00:00 2001
From: Shannon
Date: Mon, 3 Aug 2020 22:02:10 +1000
Subject: [PATCH 012/197] Changes c# model for block list editor to be much
simpler.
---
.../Models/Blocks/BlockEditorModel.cs | 36 -------------
...istLayoutReference.cs => BlockListItem.cs} | 16 ++----
.../Models/Blocks/BlockListModel.cs | 53 +++++++++++++++----
src/Umbraco.Core/Umbraco.Core.csproj | 3 +-
.../BlockListPropertyValueConverterTests.cs | 45 ++++++----------
.../BlockListTemplateExtensions.cs | 2 +-
.../BlockListPropertyValueConverter.cs | 6 +--
7 files changed, 68 insertions(+), 93 deletions(-)
delete mode 100644 src/Umbraco.Core/Models/Blocks/BlockEditorModel.cs
rename src/Umbraco.Core/Models/Blocks/{BlockListLayoutReference.cs => BlockListItem.cs} (65%)
diff --git a/src/Umbraco.Core/Models/Blocks/BlockEditorModel.cs b/src/Umbraco.Core/Models/Blocks/BlockEditorModel.cs
deleted file mode 100644
index fa5a29fece..0000000000
--- a/src/Umbraco.Core/Models/Blocks/BlockEditorModel.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.Serialization;
-using Umbraco.Core.Models.PublishedContent;
-
-namespace Umbraco.Core.Models.Blocks
-{
- ///
- /// The base class for any strongly typed model for a Block editor implementation
- ///
- public abstract class BlockEditorModel
- {
- protected BlockEditorModel(IEnumerable contentData, IEnumerable settingsData)
- {
- ContentData = contentData ?? throw new ArgumentNullException(nameof(contentData));
- SettingsData = settingsData ?? new List();
- }
-
- public BlockEditorModel()
- {
- }
-
-
- ///
- /// The content data items of the Block List editor
- ///
- [DataMember(Name = "contentData")]
- public IEnumerable ContentData { get; set; } = new List();
-
- ///
- /// The settings data items of the Block List editor
- ///
- [DataMember(Name = "settingsData")]
- public IEnumerable SettingsData { get; set; } = new List();
- }
-}
diff --git a/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs
similarity index 65%
rename from src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs
rename to src/Umbraco.Core/Models/Blocks/BlockListItem.cs
index f576bd927f..f4b5c489e7 100644
--- a/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs
+++ b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs
@@ -7,10 +7,10 @@ namespace Umbraco.Core.Models.Blocks
///
/// Represents a layout item for the Block List editor
///
- [DataContract(Name = "blockListLayout", Namespace = "")]
- public class BlockListLayoutReference : IBlockReference
+ [DataContract(Name = "block", Namespace = "")]
+ public class BlockListItem : IBlockReference
{
- public BlockListLayoutReference(Udi contentUdi, IPublishedElement content, Udi settingsUdi, IPublishedElement settings)
+ public BlockListItem(Udi contentUdi, IPublishedElement content, Udi settingsUdi, IPublishedElement settings)
{
ContentUdi = contentUdi ?? throw new ArgumentNullException(nameof(contentUdi));
Content = content ?? throw new ArgumentNullException(nameof(content));
@@ -33,19 +33,13 @@ namespace Umbraco.Core.Models.Blocks
///
/// The content data item referenced
///
- ///
- /// This is ignored from serialization since it is just a reference to the actual data element
- ///
- [IgnoreDataMember]
+ [DataMember(Name = "content")]
public IPublishedElement Content { get; }
///
/// The settings data item referenced
///
- ///
- /// This is ignored from serialization since it is just a reference to the actual data element
- ///
- [IgnoreDataMember]
+ [DataMember(Name = "settings")]
public IPublishedElement Settings { get; }
}
}
diff --git a/src/Umbraco.Core/Models/Blocks/BlockListModel.cs b/src/Umbraco.Core/Models/Blocks/BlockListModel.cs
index 0492cf0d73..9a5a3af22a 100644
--- a/src/Umbraco.Core/Models/Blocks/BlockListModel.cs
+++ b/src/Umbraco.Core/Models/Blocks/BlockListModel.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
using System.Runtime.Serialization;
using Umbraco.Core.Models.PublishedContent;
@@ -8,26 +11,54 @@ namespace Umbraco.Core.Models.Blocks
/// The strongly typed model for the Block List editor
///
[DataContract(Name = "blockList", Namespace = "")]
- public class BlockListModel : BlockEditorModel
+ public class BlockListModel : IReadOnlyList
{
+ private readonly IReadOnlyList _layout = new List();
+
public static BlockListModel Empty { get; } = new BlockListModel();
private BlockListModel()
{
}
- public BlockListModel(IEnumerable contentData, IEnumerable settingsData, IEnumerable layout)
- : base(contentData, settingsData)
+ public BlockListModel(IEnumerable layout)
{
- Layout = layout;
+ _layout = layout.ToList();
}
- ///
- /// The layout items of the Block List editor
- ///
- [DataMember(Name = "layout")]
- public IEnumerable Layout { get; } = new List();
+ public int Count => _layout.Count;
+
+ ///
+ /// Get the block by index
+ ///
+ ///
+ ///
+ public BlockListItem this[int index] => _layout[index];
+
+ ///
+ /// Get the block by content Guid
+ ///
+ ///
+ ///
+ public BlockListItem this[Guid contentKey] => _layout.FirstOrDefault(x => x.Content.Key == contentKey);
+
+ ///
+ /// Get the block by content element Udi
+ ///
+ ///
+ ///
+ public BlockListItem this[Udi contentUdi]
+ {
+ get
+ {
+ if (!(contentUdi is GuidUdi guidUdi)) return null;
+ return _layout.FirstOrDefault(x => x.Content.Key == guidUdi.Guid);
+ }
+ }
+
+ public IEnumerator GetEnumerator() => _layout.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
}
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 73af567cbc..1b1ee4fb28 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -150,8 +150,7 @@
-
-
+
diff --git a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs
index 23cc782106..959e059d59 100644
--- a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs
+++ b/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs
@@ -154,15 +154,13 @@ namespace Umbraco.Tests.PropertyEditors
var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
json = string.Empty;
converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
}
[Test]
@@ -177,8 +175,7 @@ namespace Umbraco.Tests.PropertyEditors
var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
json = @"{
layout: {},
@@ -186,8 +183,7 @@ data: []}";
converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
// Even though there is a layout, there is no data, so the conversion will result in zero elements in total
json = @"
@@ -205,8 +201,7 @@ data: []}";
converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
// Even though there is a layout and data, the data is invalid (missing required keys) so the conversion will result in zero elements in total
json = @"
@@ -228,8 +223,7 @@ data: []}";
converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(0, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
// Everthing is ok except the udi reference in the layout doesn't match the data so it will be empty
json = @"
@@ -252,8 +246,7 @@ data: []}";
converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(1, converted.ContentData.Count());
- Assert.AreEqual(0, converted.Layout.Count());
+ Assert.AreEqual(0, converted.Count);
}
[Test]
@@ -283,14 +276,12 @@ data: []}";
var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(1, converted.ContentData.Count());
- var item0 = converted.ContentData.ElementAt(0);
+ Assert.AreEqual(1, converted.Count);
+ var item0 = converted[0].Content;
Assert.AreEqual(Guid.Parse("1304E1DD-AC87-4396-84FE-8A399231CB3D"), item0.Key);
Assert.AreEqual("Test1", item0.ContentType.Alias);
- Assert.AreEqual(1, converted.Layout.Count());
- var layout0 = converted.Layout.ElementAt(0);
- Assert.IsNull(layout0.Settings);
- Assert.AreEqual(Udi.Parse("umb://element/1304E1DDAC87439684FE8A399231CB3D"), layout0.ContentUdi);
+ Assert.IsNull(converted[0].Settings);
+ Assert.AreEqual(Udi.Parse("umb://element/1304E1DDAC87439684FE8A399231CB3D"), converted[0].ContentUdi);
}
[Test]
@@ -348,17 +339,15 @@ data: []}";
var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(3, converted.ContentData.Count());
- Assert.AreEqual(3, converted.SettingsData.Count());
- Assert.AreEqual(2, converted.Layout.Count());
+ Assert.AreEqual(2, converted.Count);
- var item0 = converted.Layout.ElementAt(0);
+ var item0 = converted[0];
Assert.AreEqual(Guid.Parse("1304E1DD-AC87-4396-84FE-8A399231CB3D"), item0.Content.Key);
Assert.AreEqual("Test1", item0.Content.ContentType.Alias);
Assert.AreEqual(Guid.Parse("1F613E26CE274898908A561437AF5100"), item0.Settings.Key);
Assert.AreEqual("Setting2", item0.Settings.ContentType.Alias);
- var item1 = converted.Layout.ElementAt(1);
+ var item1 = converted[1];
Assert.AreEqual(Guid.Parse("0A4A416E-547D-464F-ABCC-6F345C17809A"), item1.Content.Key);
Assert.AreEqual("Test2", item1.Content.ContentType.Alias);
Assert.AreEqual(Guid.Parse("63027539B0DB45E7B70459762D4E83DD"), item1.Settings.Key);
@@ -434,11 +423,9 @@ data: []}";
var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel;
Assert.IsNotNull(converted);
- Assert.AreEqual(2, converted.ContentData.Count());
- Assert.AreEqual(0, converted.SettingsData.Count());
- Assert.AreEqual(1, converted.Layout.Count());
+ Assert.AreEqual(1, converted.Count);
- var item0 = converted.Layout.ElementAt(0);
+ var item0 = converted[0];
Assert.AreEqual(Guid.Parse("0A4A416E-547D-464F-ABCC-6F345C17809A"), item0.Content.Key);
Assert.AreEqual("Test2", item0.Content.ContentType.Alias);
Assert.IsNull(item0.Settings);
diff --git a/src/Umbraco.Web/BlockListTemplateExtensions.cs b/src/Umbraco.Web/BlockListTemplateExtensions.cs
index 1754eb4fc4..413584bc8e 100644
--- a/src/Umbraco.Web/BlockListTemplateExtensions.cs
+++ b/src/Umbraco.Web/BlockListTemplateExtensions.cs
@@ -14,7 +14,7 @@ namespace Umbraco.Web
public static MvcHtmlString GetBlockListHtml(this HtmlHelper html, BlockListModel model, string template = DefaultTemplate)
{
- if (model?.Layout == null || !model.Layout.Any()) return new MvcHtmlString(string.Empty);
+ if (model?.Count == 0) return new MvcHtmlString(string.Empty);
var view = DefaultFolder + template;
return html.Partial(view, model);
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
index 25b22e1a9c..0c90a41fbd 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
@@ -58,7 +58,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var contentPublishedElements = new Dictionary();
var settingsPublishedElements = new Dictionary();
- var layout = new List();
+ var layout = new List();
var value = (string)inter;
if (string.IsNullOrWhiteSpace(value)) return BlockListModel.Empty;
@@ -120,11 +120,11 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
settingsData = null;
}
- var layoutRef = new BlockListLayoutReference(contentGuidUdi, contentData, settingGuidUdi, settingsData);
+ var layoutRef = new BlockListItem(contentGuidUdi, contentData, settingGuidUdi, settingsData);
layout.Add(layoutRef);
}
- var model = new BlockListModel(contentPublishedElements.Values, settingsPublishedElements.Values, layout);
+ var model = new BlockListModel(layout);
return model;
}
}
From b0ff73fd7573fdb76e22790a5ac4589ed192ed9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Mon, 3 Aug 2020 14:12:06 +0200
Subject: [PATCH 013/197] make badge bounce
---
.../editor/umb-variant-switcher.less | 26 +++++++++++++++++++
.../umb-editor-navigation-item.less | 21 +++++++++++++--
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less
index 8dbc070856..eae25b273c 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less
@@ -50,6 +50,19 @@ button.umb-variant-switcher__toggle {
font-weight: bold;
background-color: @errorBackground;
color: @errorText;
+
+ animation-duration: 1.4s;
+ animation-iteration-count: infinite;
+ animation-name: umb-variant-switcher__toggle--badge-bounce;
+ animation-timing-function: ease;
+ @keyframes umb-variant-switcher__toggle--badge-bounce {
+ 0% { transform: translateY(0); }
+ 20% { transform: translateY(-6px); }
+ 40% { transform: translateY(0); }
+ 55% { transform: translateY(-3px); }
+ 70% { transform: translateY(0); }
+ 100% { transform: translateY(0); }
+ }
}
}
}
@@ -226,6 +239,19 @@ button.umb-variant-switcher__toggle {
font-weight: bold;
background-color: @errorBackground;
color: @errorText;
+
+ animation-duration: 1.4s;
+ animation-iteration-count: infinite;
+ animation-name: umb-variant-switcher__name--badge-bounce;
+ animation-timing-function: ease;
+ @keyframes umb-variant-switcher__name--badge-bounce {
+ 0% { transform: translateY(0); }
+ 20% { transform: translateY(-6px); }
+ 40% { transform: translateY(0); }
+ 55% { transform: translateY(-3px); }
+ 70% { transform: translateY(0); }
+ 100% { transform: translateY(0); }
+ }
}
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
index b3720feb3d..2fc705b11b 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less
@@ -65,8 +65,25 @@
&::before {
background-color: @red;
}
- .badge.--error-badge {
- display: block;
+
+ &:not(.is-active) {
+ .badge {
+ animation-duration: 1.4s;
+ animation-iteration-count: infinite;
+ animation-name: umb-sub-views-nav-item--badge-bounce;
+ animation-timing-function: ease;
+ @keyframes umb-sub-views-nav-item--badge-bounce {
+ 0% { transform: translateY(0); }
+ 20% { transform: translateY(-6px); }
+ 40% { transform: translateY(0); }
+ 55% { transform: translateY(-3px); }
+ 70% { transform: translateY(0); }
+ 100% { transform: translateY(0); }
+ }
+ }
+ .badge.--error-badge {
+ display: block;
+ }
}
}
}
From c9b0f20fa32cb067bd4d58a7ec47307d9e390803 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Mon, 3 Aug 2020 14:13:38 +0200
Subject: [PATCH 014/197] move load to the buttom of init()
---
.../umbBlockListPropertyEditor.component.js | 63 ++++++++++---------
1 file changed, 32 insertions(+), 31 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
index 327677c6b9..3b54bca48a 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
@@ -29,7 +29,7 @@
});
function BlockListController($scope, editorService, clipboardService, localizationService, overlayService, blockEditorService, udiService, serverValidationManager, angularHelper) {
-
+
var unsubscribe = [];
var modelObject;
@@ -84,7 +84,7 @@
vm.validationLimit = vm.model.config.validationLimit;
vm.listWrapperStyles = {};
-
+
if (vm.model.config.maxPropertyWidth) {
vm.listWrapperStyles['max-width'] = vm.model.config.maxPropertyWidth;
}
@@ -100,10 +100,6 @@
} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) {
scopeOfExistence = vm.umbElementEditorContent.getScope();
}
-
- // Create Model Object, to manage our data for this Block Editor.
- modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence, $scope);
- modelObject.load().then(onLoaded);
copyAllBlocksAction = {
labelKey: "clipboard_labelForCopyAllEntries",
@@ -124,15 +120,20 @@
copyAllBlocksAction,
deleteAllBlocksAction
];
-
+
if (vm.umbProperty) {
vm.umbProperty.setPropertyActions(propertyActions);
}
+
+ // Create Model Object, to manage our data for this Block Editor.
+ modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence, $scope);
+ modelObject.load().then(onLoaded);
+
};
// Called when we save the value, the server may return an updated data and our value is re-synced
// we need to deal with that here so that our model values are all in sync so we basically re-initialize.
- function onServerValueChanged(newVal, oldVal) {
+ function onServerValueChanged(newVal, oldVal) {
// We need to ensure that the property model value is an object, this is needed for modelObject to recive a reference and keep that updated.
if (typeof newVal !== 'object' || newVal === null) {// testing if we have null or undefined value or if the value is set to another type than Object.
@@ -142,13 +143,13 @@
modelObject.update(newVal, $scope);
onLoaded();
}
-
+
function setDirty() {
if (vm.propertyForm) {
vm.propertyForm.$setDirty();
}
}
-
+
function onLoaded() {
// Store a reference to the layout model, because we need to maintain this model.
@@ -161,7 +162,7 @@
// $block must have the data property to be a valid BlockObject, if not its considered as a destroyed blockObject.
if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) {
var block = getBlockObject(entry);
-
+
// If this entry was not supported by our property-editor it would return 'null'.
if (block !== null) {
entry.$block = block;
@@ -192,7 +193,7 @@
}
function getDefaultViewForBlock(block) {
-
+
if (block.config.unsupported === true)
return "views/propertyeditors/blocklist/blocklistentryeditors/unsupportedblock/unsupportedblock.editor.html";
@@ -207,8 +208,8 @@
if (block === null) return null;
// ensure that the containing content variant language/culture is transfered along
- // to the scaffolded content object representing this block. This is required for validation
- // along with ensuring that the umb-property inheritance is constently maintained.
+ // to the scaffolded content object representing this block. This is required for validation
+ // along with ensuring that the umb-property inheritance is constently maintained.
if (vm.umbVariantContent.editor.content.language) {
block.content.language = vm.umbVariantContent.editor.content.language;
// currently we only ever deal with invariant content for blocks so there's only one
@@ -243,7 +244,7 @@
if (blockObject === null) {
return false;
}
-
+
// If we reach this line, we are good to add the layoutEntry and blockObject to our models.
// Add the Block Object to our layout entry.
@@ -251,7 +252,7 @@
// add layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
-
+
// lets move focus to this new block.
vm.setBlockFocus(blockObject);
@@ -271,7 +272,7 @@
var removed = vm.layout.splice(layoutIndex, 1);
removed.forEach(x => {
// remove any server validation errors associated
- var guid = udiService.getKey(x.contentUdi);
+ var guid = udiService.getKey(x.contentUdi);
serverValidationManager.removePropertyError(guid, vm.umbProperty.property.culture, vm.umbProperty.property.segment, "", { matchType: "contains" });
});
@@ -284,7 +285,7 @@
deleteBlock(entry.$block);
});
}
-
+
function activateBlock(blockObject) {
blockObject.active = true;
}
@@ -317,7 +318,7 @@
if (blockObject.config.settingsElementTypeKey) {
blockSettingsClone = Utilities.copy(blockObject.settings);
}
-
+
var blockEditorModel = {
$parentScope: $scope, // pass in a $parentScope, this maintains the scope inheritance in infinite editing
$parentForm: parentForm || vm.propertyForm, // pass in a $parentForm, this maintains the FormController hierarchy with the infinite editing view (if it contains a form)
@@ -366,11 +367,11 @@
vm.showCreateDialog = showCreateDialog;
function showCreateDialog(createIndex, $event) {
-
+
if (vm.blockTypePicker) {
return;
}
-
+
if (vm.availableBlockTypes.length === 0) {
return;
}
@@ -405,7 +406,7 @@
if (blockPickerModel && blockPickerModel.selectedItem) {
added = addNewBlock(createIndex, blockPickerModel.selectedItem.blockConfigModel.contentTypeKey);
}
-
+
if(!(mouseEvent.ctrlKey || mouseEvent.metaKey)) {
editorService.close();
if (added && vm.layout.length > createIndex) {
@@ -448,7 +449,7 @@
}
);
});
-
+
var arrayEntriesForPaste = clipboardService.retriveEntriesOfType("elementTypeArray", vm.availableContentTypesAliases);
arrayEntriesForPaste.forEach(function (entry) {
blockPickerModel.clipboardItems.push(
@@ -472,13 +473,13 @@
var requestCopyAllBlocks = function() {
var elementTypesToCopy = vm.layout.filter(entry => entry.$block.config.unsupported !== true).map(entry => entry.$block.content);
-
+
// list aliases
var aliases = elementTypesToCopy.map(content => content.contentTypeAlias);
// remove dublicates
aliases = aliases.filter((item, index) => aliases.indexOf(item) === index);
-
+
var contentNodeName = "";
if(vm.umbVariantContent) {
contentNodeName = vm.umbVariantContent.editor.content.name;
@@ -494,7 +495,7 @@
clipboardService.copy("elementType", block.content.contentTypeAlias, block.content, block.label);
}
function requestPasteFromClipboard(index, pasteEntry) {
-
+
if (pasteEntry === undefined) {
return false;
}
@@ -512,7 +513,7 @@
// set the BlockObject on our layout entry.
layoutEntry.$block = blockObject;
-
+
// insert layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
@@ -565,7 +566,7 @@
copyBlock: copyBlock,
requestDeleteBlock: requestDeleteBlock,
deleteBlock: deleteBlock,
- openSettingsForBlock: openSettingsForBlock
+ openSettingsForBlock: openSettingsForBlock
}
vm.sortableOptions = {
@@ -594,15 +595,15 @@
var isMinRequirementGood = vm.validationLimit.min === null || vm.layout.length >= vm.validationLimit.min;
vm.propertyForm.minCount.$setValidity("minCount", isMinRequirementGood);
-
+
var isMaxRequirementGood = vm.validationLimit.max === null || vm.layout.length <= vm.validationLimit.max;
vm.propertyForm.maxCount.$setValidity("maxCount", isMaxRequirementGood);
-
+
}
}
unsubscribe.push($scope.$watch(() => vm.layout.length, onAmountOfBlocksChanged));
-
+
$scope.$on("$destroy", function () {
for (const subscription of unsubscribe) {
subscription();
From 52fa96c82474c91d111f68a55e71dfbdfb86cd7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 10:00:39 +0200
Subject: [PATCH 015/197] append the drag class if a stylesheet is present.
---
.../src/views/propertyeditors/blocklist/umb-block-list-row.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
index 55f849e4d0..bcbede231c 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
@@ -3,6 +3,7 @@
Date: Tue, 4 Aug 2020 11:09:45 +0200
Subject: [PATCH 016/197] remove unused index from blockEditorModel for
infinite editor
---
.../umbBlockListPropertyEditor.component.js | 57 +++++++++----------
1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
index 327677c6b9..c702206393 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
@@ -29,7 +29,7 @@
});
function BlockListController($scope, editorService, clipboardService, localizationService, overlayService, blockEditorService, udiService, serverValidationManager, angularHelper) {
-
+
var unsubscribe = [];
var modelObject;
@@ -84,7 +84,7 @@
vm.validationLimit = vm.model.config.validationLimit;
vm.listWrapperStyles = {};
-
+
if (vm.model.config.maxPropertyWidth) {
vm.listWrapperStyles['max-width'] = vm.model.config.maxPropertyWidth;
}
@@ -100,7 +100,7 @@
} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) {
scopeOfExistence = vm.umbElementEditorContent.getScope();
}
-
+
// Create Model Object, to manage our data for this Block Editor.
modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence, $scope);
modelObject.load().then(onLoaded);
@@ -124,7 +124,7 @@
copyAllBlocksAction,
deleteAllBlocksAction
];
-
+
if (vm.umbProperty) {
vm.umbProperty.setPropertyActions(propertyActions);
}
@@ -132,7 +132,7 @@
// Called when we save the value, the server may return an updated data and our value is re-synced
// we need to deal with that here so that our model values are all in sync so we basically re-initialize.
- function onServerValueChanged(newVal, oldVal) {
+ function onServerValueChanged(newVal, oldVal) {
// We need to ensure that the property model value is an object, this is needed for modelObject to recive a reference and keep that updated.
if (typeof newVal !== 'object' || newVal === null) {// testing if we have null or undefined value or if the value is set to another type than Object.
@@ -142,13 +142,13 @@
modelObject.update(newVal, $scope);
onLoaded();
}
-
+
function setDirty() {
if (vm.propertyForm) {
vm.propertyForm.$setDirty();
}
}
-
+
function onLoaded() {
// Store a reference to the layout model, because we need to maintain this model.
@@ -161,7 +161,7 @@
// $block must have the data property to be a valid BlockObject, if not its considered as a destroyed blockObject.
if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) {
var block = getBlockObject(entry);
-
+
// If this entry was not supported by our property-editor it would return 'null'.
if (block !== null) {
entry.$block = block;
@@ -192,7 +192,7 @@
}
function getDefaultViewForBlock(block) {
-
+
if (block.config.unsupported === true)
return "views/propertyeditors/blocklist/blocklistentryeditors/unsupportedblock/unsupportedblock.editor.html";
@@ -207,8 +207,8 @@
if (block === null) return null;
// ensure that the containing content variant language/culture is transfered along
- // to the scaffolded content object representing this block. This is required for validation
- // along with ensuring that the umb-property inheritance is constently maintained.
+ // to the scaffolded content object representing this block. This is required for validation
+ // along with ensuring that the umb-property inheritance is constently maintained.
if (vm.umbVariantContent.editor.content.language) {
block.content.language = vm.umbVariantContent.editor.content.language;
// currently we only ever deal with invariant content for blocks so there's only one
@@ -243,7 +243,7 @@
if (blockObject === null) {
return false;
}
-
+
// If we reach this line, we are good to add the layoutEntry and blockObject to our models.
// Add the Block Object to our layout entry.
@@ -251,7 +251,7 @@
// add layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
-
+
// lets move focus to this new block.
vm.setBlockFocus(blockObject);
@@ -271,7 +271,7 @@
var removed = vm.layout.splice(layoutIndex, 1);
removed.forEach(x => {
// remove any server validation errors associated
- var guid = udiService.getKey(x.contentUdi);
+ var guid = udiService.getKey(x.contentUdi);
serverValidationManager.removePropertyError(guid, vm.umbProperty.property.culture, vm.umbProperty.property.segment, "", { matchType: "contains" });
});
@@ -284,7 +284,7 @@
deleteBlock(entry.$block);
});
}
-
+
function activateBlock(blockObject) {
blockObject.active = true;
}
@@ -317,7 +317,7 @@
if (blockObject.config.settingsElementTypeKey) {
blockSettingsClone = Utilities.copy(blockObject.settings);
}
-
+
var blockEditorModel = {
$parentScope: $scope, // pass in a $parentScope, this maintains the scope inheritance in infinite editing
$parentForm: parentForm || vm.propertyForm, // pass in a $parentForm, this maintains the FormController hierarchy with the infinite editing view (if it contains a form)
@@ -325,7 +325,6 @@
openSettings: openSettings === true,
liveEditing: liveEditing,
title: blockObject.label,
- index: blockIndex,
view: "views/common/infiniteeditors/blockeditor/blockeditor.html",
size: blockObject.config.editorSize || "medium",
submit: function(blockEditorModel) {
@@ -366,11 +365,11 @@
vm.showCreateDialog = showCreateDialog;
function showCreateDialog(createIndex, $event) {
-
+
if (vm.blockTypePicker) {
return;
}
-
+
if (vm.availableBlockTypes.length === 0) {
return;
}
@@ -405,7 +404,7 @@
if (blockPickerModel && blockPickerModel.selectedItem) {
added = addNewBlock(createIndex, blockPickerModel.selectedItem.blockConfigModel.contentTypeKey);
}
-
+
if(!(mouseEvent.ctrlKey || mouseEvent.metaKey)) {
editorService.close();
if (added && vm.layout.length > createIndex) {
@@ -448,7 +447,7 @@
}
);
});
-
+
var arrayEntriesForPaste = clipboardService.retriveEntriesOfType("elementTypeArray", vm.availableContentTypesAliases);
arrayEntriesForPaste.forEach(function (entry) {
blockPickerModel.clipboardItems.push(
@@ -472,13 +471,13 @@
var requestCopyAllBlocks = function() {
var elementTypesToCopy = vm.layout.filter(entry => entry.$block.config.unsupported !== true).map(entry => entry.$block.content);
-
+
// list aliases
var aliases = elementTypesToCopy.map(content => content.contentTypeAlias);
// remove dublicates
aliases = aliases.filter((item, index) => aliases.indexOf(item) === index);
-
+
var contentNodeName = "";
if(vm.umbVariantContent) {
contentNodeName = vm.umbVariantContent.editor.content.name;
@@ -494,7 +493,7 @@
clipboardService.copy("elementType", block.content.contentTypeAlias, block.content, block.label);
}
function requestPasteFromClipboard(index, pasteEntry) {
-
+
if (pasteEntry === undefined) {
return false;
}
@@ -512,7 +511,7 @@
// set the BlockObject on our layout entry.
layoutEntry.$block = blockObject;
-
+
// insert layout entry at the decired location in layout.
vm.layout.splice(index, 0, layoutEntry);
@@ -565,7 +564,7 @@
copyBlock: copyBlock,
requestDeleteBlock: requestDeleteBlock,
deleteBlock: deleteBlock,
- openSettingsForBlock: openSettingsForBlock
+ openSettingsForBlock: openSettingsForBlock
}
vm.sortableOptions = {
@@ -594,15 +593,15 @@
var isMinRequirementGood = vm.validationLimit.min === null || vm.layout.length >= vm.validationLimit.min;
vm.propertyForm.minCount.$setValidity("minCount", isMinRequirementGood);
-
+
var isMaxRequirementGood = vm.validationLimit.max === null || vm.layout.length <= vm.validationLimit.max;
vm.propertyForm.maxCount.$setValidity("maxCount", isMaxRequirementGood);
-
+
}
}
unsubscribe.push($scope.$watch(() => vm.layout.length, onAmountOfBlocksChanged));
-
+
$scope.$on("$destroy", function () {
for (const subscription of unsubscribe) {
subscription();
From 7cbe50b2f156178d1432acc475a5f9b0e09ca261 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 11:23:13 +0200
Subject: [PATCH 017/197] need to define active always, in order for it to
become false.
---
.../blockeditor/blockeditor.controller.js | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
index f515cbb4ba..b8c6f1f27b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
@@ -23,17 +23,14 @@ angular.module("umbraco")
if (contentApp) {
if (vm.model.hideContent) {
apps.splice(apps.indexOf(contentApp), 1);
- } else if (vm.model.openSettings !== true) {
- contentApp.active = true;
}
+ contentApp.active = (vm.model.openSettings !== true);
}
if (vm.model.settings && vm.model.settings.variants) {
var settingsApp = apps.find(entry => entry.alias === "settings");
if (settingsApp) {
- if (vm.model.openSettings) {
- settingsApp.active = true;
- }
+ settingsApp.active = (vm.model.openSettings === true);
}
}
@@ -55,7 +52,7 @@ angular.module("umbraco")
vm.close = function () {
if (vm.model && vm.model.close) {
- // TODO: At this stage there could very well have been server errors that have been cleared
+ // TODO: At this stage there could very well have been server errors that have been cleared
// but if we 'close' we are basically cancelling the value changes which means we'd want to cancel
// all of the server errors just cleared. It would be possible to do that but also quite annoying.
// The rudimentary way would be to:
From 74f3b8073f3f84a6bbe884ce8fed5b094a379c43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 11:32:02 +0200
Subject: [PATCH 018/197] show state in submit button
---
.../infiniteeditors/blockeditor/blockeditor.controller.js | 6 +++++-
.../common/infiniteeditors/blockeditor/blockeditor.html | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
index f515cbb4ba..6dbf74f830 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js
@@ -42,6 +42,7 @@ angular.module("umbraco")
vm.submitAndClose = function () {
if (vm.model && vm.model.submit) {
+
// always keep server validations since this will be a nested editor and server validations are global
if (formHelper.submitForm({
scope: $scope,
@@ -49,13 +50,16 @@ angular.module("umbraco")
keepServerValidation: true
})) {
vm.model.submit(vm.model);
+ vm.saveButtonState = "success";
+ } else {
+ vm.saveButtonState = "error";
}
}
}
vm.close = function () {
if (vm.model && vm.model.close) {
- // TODO: At this stage there could very well have been server errors that have been cleared
+ // TODO: At this stage there could very well have been server errors that have been cleared
// but if we 'close' we are basically cancelling the value changes which means we'd want to cancel
// all of the server errors just cleared. It would be possible to do that but also quite annoying.
// The rudimentary way would be to:
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
index de18f13d2c..dfcfd48887 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
@@ -44,7 +44,7 @@
From 8981fd9c6fd3cf5da771a759498e56e5fba55d9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 11:34:07 +0200
Subject: [PATCH 019/197] should check for value before checking the length or
the value of first entry.
---
.../dropdownFlexible/dropdownFlexible.controller.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js
index afbb4feb20..4064df6a24 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js
@@ -15,14 +15,14 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo
//ensure this is a bool, old data could store zeros/ones or string versions
$scope.model.config.multiple = Object.toBoolean($scope.model.config.multiple);
-
+
//ensure when form is saved that we don't store [] or [null] as string values in the database when no items are selected
$scope.$on("formSubmitting", function () {
- if ($scope.model.value.length === 0 || $scope.model.value[0] === null) {
+ if ($scope.model.value && ($scope.model.value.length === 0 || $scope.model.value[0] === null)) {
$scope.model.value = null;
}
});
-
+
function convertArrayToDictionaryArray(model){
//now we need to format the items in the dictionary because we always want to have an array
var newItems = [];
@@ -41,7 +41,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo
var keys = _.keys($scope.model.config.items);
for (var i = 0; i < vals.length; i++) {
- var label = vals[i].value ? vals[i].value : vals[i];
+ var label = vals[i].value ? vals[i].value : vals[i];
newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label });
}
@@ -65,7 +65,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo
else {
throw "The items property must be either an array or a dictionary";
}
-
+
//sort the values
$scope.model.config.items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
@@ -80,7 +80,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo
$scope.model.value = "";
}
}
-
+
// if we run in single mode we'll store the value in a local variable
// so we can pass an array as the model as our PropertyValueEditor expects that
$scope.model.singleDropdownValue = "";
From 041d6a91a8824f6d35ce69a2b9b4ecbc3b521fa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 12:57:05 +0200
Subject: [PATCH 020/197] use the right red for error borders, no need for it
to be darker.
---
src/Umbraco.Web.UI.Client/src/less/variables.less | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less
index 2f627f3ab3..840c6d529f 100644
--- a/src/Umbraco.Web.UI.Client/src/less/variables.less
+++ b/src/Umbraco.Web.UI.Client/src/less/variables.less
@@ -481,7 +481,7 @@
@formErrorText: @errorBackground;
@formErrorBackground: lighten(@errorBackground, 55%);
-@formErrorBorder: darken(spin(@errorBackground, -10), 3%);
+@formErrorBorder: @red;
@formSuccessText: @successBackground;
@formSuccessBackground: lighten(@successBackground, 48%);
From ff3d0b177001b135c5452d2258a47926e1fd129c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20Lyngs=C3=B8?=
Date: Tue, 4 Aug 2020 12:57:21 +0200
Subject: [PATCH 021/197] append a badge for settings, and make sure it
visible.
---
.../umb-block-list-property-editor.less | 37 +++++++++++++++++++
.../blocklist/umb-block-list-row.html | 1 +
2 files changed, 38 insertions(+)
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less
index b6f3ace44c..0c92aef44b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less
@@ -39,6 +39,9 @@
}
}
}
+ng-form.ng-invalid-val-server-match-settings > .umb-block-list__block > .umb-block-list__block--actions {
+ opacity: 1;
+}
.umb-block-list__block--actions {
position: absolute;
z-index:999999999;// We always want to be on top of custom view, but we need to make sure we still are behind relevant Umbraco CMS UI. ToDo: Needs further testing.
@@ -58,6 +61,40 @@
&:hover {
color: @ui-action-discreet-type-hover;
}
+ > .__error-badge {
+ position: absolute;
+ top: -2px;
+ right: -2px;
+ min-width: 8px;
+ color: @white;
+ background-color: @ui-active-type;
+ border: 2px solid @white;
+ border-radius: 50%;
+ font-size: 8px;
+ font-weight: bold;
+ padding: 2px;
+ line-height: 8px;
+ background-color: @red;
+ display: none;
+ font-weight: 900;
+ }
+ &.--error > .__error-badge {
+ display: block;
+
+ animation-duration: 1.4s;
+ animation-iteration-count: infinite;
+ animation-name: umb-block-list__action--badge-bounce;
+ animation-timing-function: ease;
+ @keyframes umb-block-list__action--badge-bounce {
+ 0% { transform: translateY(0); }
+ 20% { transform: translateY(-4px); }
+ 40% { transform: translateY(0); }
+ 55% { transform: translateY(-2px); }
+ 70% { transform: translateY(0); }
+ 100% { transform: translateY(0); }
+ }
+
+ }
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
index 55f849e4d0..a2c4b5c5b4 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-row.html
@@ -19,6 +19,7 @@
Settings
+
!
-
+
+
+
-
+
+
+
-
+
+ on-confirm="vm.performDelete"
+ on-cancel="vm.cancel"
+ confirm-button-style="danger"
+ confirm-label-key="general_delete">
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html
index 5aba520b9b..1357965197 100644
--- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html
+++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html
@@ -86,7 +86,8 @@
+ text="Create template for the Parent Document Type">
+
@@ -96,7 +97,8 @@
+ text="Create template for the Item Document Type">
+