From bd4b4620d4d001ac5555f9c573d0bb38dc657236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 4 Feb 2019 13:34:26 +0100 Subject: [PATCH 01/54] First part of refactoring umb-editor-navigation --- .../editor/umbeditornavigation.directive.js | 13 +++--- .../umbeditornavigationitem.directive.js | 40 +++++++++++++++++++ .../src/less/canvas-designer.less | 1 + .../components/umb-editor-navigation.less | 22 +++++----- src/Umbraco.Web.UI.Client/src/less/navs.less | 1 + .../editor/umb-editor-navigation-item.html | 12 ++++++ .../editor/umb-editor-navigation.html | 36 ++++++----------- .../src/views/components/umb-dropdown.html | 2 +- 8 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js index 943d2232c2..6b269ad17e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js @@ -17,14 +17,17 @@ name: "More" }; - scope.clickNavigationItem = function (selectedItem) { + scope.openNavigationItem = function (item) { + + console.log("openNavigationItem", item) + scope.showDropdown = false; - runItemAction(selectedItem); - setItemToActive(selectedItem); + runItemAction(item); + setItemToActive(item); if(scope.onSelect) { - scope.onSelect({"item": selectedItem}); + scope.onSelect({"item": item}); } - eventsService.emit("app.tabChange", selectedItem); + eventsService.emit("app.tabChange", item); }; scope.toggleDropdown = function () { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js new file mode 100644 index 0000000000..60a5a54d0f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js @@ -0,0 +1,40 @@ +/** +@ngdoc directive +@name umbraco.directives.directive:umbTabContent +@restrict E +@scope + +@description +Use this directive to render tab content. For an example see: {@link umbraco.directives.directive:umbTabContent umbTabContent} + +@param {string=} tab The tab. + +**/ +(function () { + 'use strict'; + + function UmbEditorNavigationItemController($scope, $element, $attrs) { + + console.log("LINKKK!") + var vm = this; + + this.callbackOpen = function(item) { + console.log("callbackOpen") + vm.open({item:vm.item}); + }; + } + + angular + .module('umbraco.directives.html') + .component('umbEditorNavigationItem', { + templateUrl: 'views/components/editor/umb-editor-navigation-item.html', + controller: UmbEditorNavigationItemController, + controllerAs: 'vm', + bindings: { + item: '=', + open: '&', + index: '@' + } + }); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less index 7f67d5c3b2..d1492a33c6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less +++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less @@ -176,6 +176,7 @@ a, a:hover{ .dropdown-menu { position: absolute; + display: block; top: auto; right: 0; z-index: 1000; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index c1f099c2a5..f4bbeadc3f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -106,29 +106,25 @@ line-height: 1em; } -.umb-sub-views-nav-item__more { +.umb-sub-views-nav-item-more__icon { margin-bottom: 10px; } -.umb-sub-views-nav-item__more i { +.umb-sub-views-nav-item-more__icon i { height: 5px; width: 5px; border-radius: 50%; - background: @gray-3; + background: @ui-active-type;// fallback if browser doesnt support currentColor + background: currentColor; display: inline-block; margin: 0 5px 0 0; } -.umb-sub-views-nav-item__more i:last-of-type { +.umb-sub-views-nav-item-more__icon i:last-of-type { margin-right: 0; } -// make dots green the an item is active -.umb-sub-views-nav-item.is-active .umb-sub-views-nav-item__more i { - background-color: @ui-active; -} - -.umb-sub-views-nav__dropdown.umb-sub-views-nav__dropdown { +.umb-sub-views-nav-item-more__dropdown { left: auto; right: 0; display: grid; @@ -136,3 +132,9 @@ min-width: auto; margin-top: 10px; } +.umb-sub-views-nav-item-more__dropdown > li { + display: flex; +} +.umb-sub-views-nav-item-more__dropdown .umb-sub-views-nav-item:first { + border-left: none; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/navs.less b/src/Umbraco.Web.UI.Client/src/less/navs.less index 0101113670..a2710fab6c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/navs.less +++ b/src/Umbraco.Web.UI.Client/src/less/navs.less @@ -220,6 +220,7 @@ // DROPDOWNS // --------- .dropdown-menu { + display: block; border-radius: @dropdownBorderRadius; box-shadow: 0 5px 20px rgba(0,0,0,.3); padding-top: 0; 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 new file mode 100644 index 0000000000..002e9adfc0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation-item.html @@ -0,0 +1,12 @@ + + + {{ vm.item.name }} +
{{vm.item.badge.count}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index e278a8c401..1bc7c5ff4a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -3,42 +3,32 @@
  • - - - {{ item.name }} -
    {{item.badge.count}}
    -
    + +
  • -
    +
    {{ moreButton.name }}
    - + - - - {{ item.name }} - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html index 141793f6b1..2f24186597 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-dropdown.html @@ -1 +1 @@ - \ No newline at end of file + From 64d2940c3b510a3c218237f6d4d791f042f5cc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 6 Feb 2019 11:26:39 +0100 Subject: [PATCH 02/54] refactoring of umb-editor-navigation --- .../umbeditorcontentheader.directive.js | 23 ++- .../editor/umbeditornavigation.directive.js | 4 +- .../umbeditornavigationitem.directive.js | 10 +- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../umb-editor-navigation-item.less | 132 +++++++++++++++++ .../components/umb-editor-navigation.less | 134 ------------------ .../content/umb-variant-content.html | 7 +- .../editor/umb-editor-content-header.html | 8 +- .../editor/umb-editor-navigation-item.html | 3 +- .../editor/umb-editor-navigation.html | 47 +++--- 10 files changed, 188 insertions(+), 181 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js index 0d78aab0eb..0f1aae940d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js @@ -11,17 +11,27 @@ if (!scope.serverValidationAliasField) { scope.serverValidationAliasField = "Alias"; } - + scope.vm = {}; scope.vm.dropdownOpen = false; scope.vm.currentVariant = ""; function onInit() { + setCurrentVariant(); + /* + angular.forEach(scope.content.apps, (app) => { + if (app.alias === "umbContent") { + console.log("content app", app) + app.type = "dropdown"; + app.groups = scope.content.tabs; + } + }); + */ } function setCurrentVariant() { - angular.forEach(scope.variants, function (variant) { + angular.forEach(scope.content.variants, function (variant) { if (variant.active) { scope.vm.currentVariant = variant; } @@ -72,10 +82,10 @@ onInit(); //watch for the active culture changing, if it changes, update the current variant - if (scope.variants) { + if (scope.content.variants) { scope.$watch(function () { - for (var i = 0; i < scope.variants.length; i++) { - var v = scope.variants[i]; + for (var i = 0; i < scope.content.variants.length; i++) { + var v = scope.content.variants[i]; if (v.active) { return v.language.culture; } @@ -100,10 +110,9 @@ nameDisabled: " li { + display: flex; +} +.umb-sub-views-nav-item-more__dropdown .umb-sub-views-nav-item:first { + border-left: none; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less index f4bbeadc3f..985765e53a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation.less @@ -4,137 +4,3 @@ margin: 0; border-left: 1px solid @gray-9; } - -.umb-sub-views-nav-item { - text-align: center; - cursor: pointer; - display: block; - padding: 4px 10px 0 10px; - //border-bottom: 4px solid transparent; - min-width: 70px; - border-right: 1px solid @gray-9; - box-sizing: border-box; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: @editorHeaderHeight; - position: relative; - - color: @ui-active-type; - - &:hover { - color: @ui-active-type-hover !important; - } - - &::after { - content: ""; - height: 0px; - left: 8px; - right: 8px; - background-color: @ui-light-active-border; - position: absolute; - bottom: 0; - border-radius: 3px 3px 0 0; - opacity: 0; - transition: all .2s linear; - } -} - -.umb-sub-views-nav-item:focus { - outline: none; -} - -.umb-sub-views-nav-item:hover, -.umb-sub-views-nav-item:focus { - text-decoration: none; -} - -.umb-sub-views-nav-item.is-active { - //color: @ui-active; - //border-bottom-color: @ui-active; - - //background-color: rgba(@ui-active, 0.25); - color: @ui-light-active-type; - //border-bottom-color: @ui-active; - &::after { - opacity: 1; - height: 4px; - } -} - -.show-validation .umb-sub-views-nav-item.-has-error { - color: @red; -} - -.umb-sub-views-nav-item .icon { - font-size: 24px; - display: block; - text-align: center; - margin-bottom: 7px; -} - -.umb-sub-views-nav-item .badge { - position: absolute; - top: 6px; - right: 6px; - min-width: 16px; - color: @white; - background-color: @ui-active-type; - 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; - } - &.-type-warning { - background-color: @yellow-d2; - } - &:empty { - height: 12px; - min-width: 12px; - } -} - -.umb-sub-views-nav-item-text { - font-size: 12px; - line-height: 1em; -} - -.umb-sub-views-nav-item-more__icon { - margin-bottom: 10px; -} - -.umb-sub-views-nav-item-more__icon i { - height: 5px; - width: 5px; - border-radius: 50%; - background: @ui-active-type;// fallback if browser doesnt support currentColor - background: currentColor; - display: inline-block; - margin: 0 5px 0 0; -} - -.umb-sub-views-nav-item-more__icon i:last-of-type { - margin-right: 0; -} - -.umb-sub-views-nav-item-more__dropdown { - left: auto; - right: 0; - display: grid; - grid-template-columns: 1fr 1fr 1fr; - min-width: auto; - margin-top: 10px; -} -.umb-sub-views-nav-item-more__dropdown > li { - display: flex; -} -.umb-sub-views-nav-item-more__dropdown .umb-sub-views-nav-item:first { - border-left: none; -} diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html index c03b017a82..84928a00bb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html @@ -1,19 +1,18 @@ 
    - -
    +
    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 002e9adfc0..329e96242b 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 @@ -1,8 +1,7 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index 1bc7c5ff4a..31388a54f8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -1,11 +1,11 @@
      -
    • -
      +
    • +
      @@ -13,24 +13,27 @@
    • - -
      - {{ moreButton.name }} -
      +
      - - - - - - + +
      + {{ moreButton.name }} +
      + + + + + + + + +
    • From fb070928f743301c01cf6ca7b744f725132c9c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 7 Feb 2019 08:57:20 +0100 Subject: [PATCH 03/54] V8: umb-editor-navigation-anchor-dropdown first version --- .../components/content/edit.controller.js | 17 +++ .../content/umbtabbedcontent.directive.js | 113 +++++++++++++----- .../content/umbvariantcontent.directive.js | 15 ++- .../umbvariantcontenteditors.directive.js | 10 +- .../umbeditorcontentheader.directive.js | 16 ++- .../editor/umbeditornavigation.directive.js | 9 +- .../umbeditornavigationitem.directive.js | 45 ++++++- .../util/getDomElement.directive.js | 17 +++ .../umb-editor-navigation-item.less | 36 ++++-- .../src/views/components/content/edit.html | 3 +- .../content/umb-tabbed-content.html | 13 +- .../content/umb-variant-content-editors.html | 3 +- .../content/umb-variant-content.html | 1 + .../editor/umb-editor-content-header.html | 3 +- .../editor/umb-editor-navigation-item.html | 10 +- .../editor/umb-editor-navigation.html | 2 + 16 files changed, 256 insertions(+), 57 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/util/getDomElement.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 16db974df9..c91683be83 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -878,6 +878,23 @@ } }; + /** + * Call back when a content app changes + * @param {any} app + */ + $scope.appAnchorChanged = function (app, anchor) { + + if ($scope.app !== app) { + console.log("Change app") + // TODO: Not working..!!!!!!!! + $scope.appChanged(app); + } + + //send an event downwards + $scope.$broadcast("editors.apps.appAnchorChanged", { app: app, anchor: anchor }); + + }; + // methods for infinite editing $scope.close = function () { if ($scope.infiniteModel.close) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index 5ebb40fac6..f288d8681d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -4,38 +4,95 @@ /** This directive is used to render out the current variant tabs and properties and exposes an API for other directives to consume */ function tabbedContentDirective() { + function link($scope, $element, $attrs) { + + var appRootNode = $element[0]; + + // Directive for cached property groups. + var propertyGroupNodesDictionary = {}; + + var scrollableNode = appRootNode.closest(".umb-scrollable"); + scrollableNode.addEventListener("scroll", onScroll); + + function onScroll(event) { + + var viewFocusY = scrollableNode.scrollTop + scrollableNode.clientHeight * .5; + + for(var i in $scope.content.tabs) { + var group = $scope.content.tabs[i]; + var node = propertyGroupNodesDictionary[group.id]; + //console.log(node.offsetTop, node.offsetTop + node.clientHeight) + if (viewFocusY >= node.offsetTop && viewFocusY <= node.offsetTop + node.clientHeight) { + setActiveAnchor(group); + return; + } + } + + } + function setActiveAnchor(tab) { + var i = $scope.content.tabs.length; + while(i--) { + $scope.content.tabs[i].active = false; + } + tab.active = true; + } + function scrollTo(id) { + console.log("scrollTo", id); + + if (propertyGroupNodesDictionary[id]) { + let y = propertyGroupNodesDictionary[id].offsetTop - 20;// currently only relative to closest relatively positioned parent + + scrollableNode.scrollTo(0, y); + } + } + + $scope.registerPropertyGroup = function(element, appAnchor) { + propertyGroupNodesDictionary[appAnchor] = element; + } + + $scope.$on("editors.apps.appAnchorChanged", function($event, $args) { + if($args.app.alias === "umbContent") { + setActiveAnchor($args.anchor); + scrollTo($args.anchor.id); + } + }); + + + } + + function controller($scope, $element, $attrs) { + + + //expose the property/methods for other directives to use + this.content = $scope.content; + this.activeVariant = _.find(this.content.variants, variant => { + return variant.active; + }); + + $scope.activeVariant = this.activeVariant; + + $scope.defaultVariant = _.find(this.content.variants, variant => { + return variant.language.isDefault; + }); + + $scope.unlockInvariantValue = function(property) { + property.unlockInvariantValue = !property.unlockInvariantValue; + }; + + $scope.$watch("tabbedContentForm.$dirty", + function (newValue, oldValue) { + if (newValue === true) { + $scope.content.isDirty = true; + } + }); + } + var directive = { restrict: 'E', replace: true, templateUrl: 'views/components/content/umb-tabbed-content.html', - controller: function ($scope) { - - //expose the property/methods for other directives to use - this.content = $scope.content; - this.activeVariant = _.find(this.content.variants, variant => { - return variant.active; - }); - - $scope.activeVariant = this.activeVariant; - - $scope.defaultVariant = _.find(this.content.variants, variant => { - return variant.language.isDefault; - }); - - $scope.unlockInvariantValue = function(property) { - property.unlockInvariantValue = !property.unlockInvariantValue; - }; - - $scope.$watch("tabbedContentForm.$dirty", - function (newValue, oldValue) { - if (newValue === true) { - $scope.content.isDirty = true; - } - }); - }, - link: function(scope) { - - }, + controller: controller, + link: link, scope: { content: "=" } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js index 8545854992..9eb4ddee15 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js @@ -16,7 +16,8 @@ onCloseSplitView: "&", onSelectVariant: "&", onOpenSplitView: "&", - onSelectApp: "&" + onSelectApp: "&", + onSelectAppAnchor: "&" }, controllerAs: 'vm', controller: umbVariantContentController @@ -35,6 +36,7 @@ vm.selectVariant = selectVariant; vm.openSplitView = openSplitView; vm.selectApp = selectApp; + vm.selectAppAnchor = selectAppAnchor; function onInit() { // disable the name field if the active content app is not "Content" @@ -89,6 +91,17 @@ } } + /** + * Used to proxy a callback + * @param {any} item + */ + function selectAppAnchor(item, anchor) { + // call the callback if any is registered + if(vm.onSelectAppAnchor) { + vm.onSelectAppAnchor({"app": item, "anchor": anchor}); + } + } + /** * Used to proxy a callback * @param {any} variant diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js index addbb3b11b..0995a13707 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js @@ -10,7 +10,8 @@ page: "<", content: "<", // TODO: Not sure if this should be = since we are changing the 'active' property of a variant culture: "<", - onSelectApp: "&?" + onSelectApp: "&?", + onSelectAppAnchor: "&?" }, controllerAs: 'vm', controller: umbVariantContentEditorsController @@ -32,6 +33,7 @@ vm.closeSplitView = closeSplitView; vm.selectVariant = selectVariant; vm.selectApp = selectApp; + vm.selectAppAnchor = selectAppAnchor; //Used to track how many content views there are (for split view there will be 2, it could support more in theory) vm.editors = []; @@ -323,6 +325,12 @@ vm.onSelectApp({"app": app}); } } + + function selectAppAnchor(app, anchor) { + if(vm.onSelectAppAnchor) { + vm.onSelectAppAnchor({"app": app, "anchor": anchor}); + } + } } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js index 0f1aae940d..ad20c6bbae 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorcontentheader.directive.js @@ -19,15 +19,14 @@ function onInit() { setCurrentVariant(); - /* + angular.forEach(scope.content.apps, (app) => { if (app.alias === "umbContent") { - console.log("content app", app) - app.type = "dropdown"; - app.groups = scope.content.tabs; + console.log("app: ", app) + app.anchors = scope.content.tabs; } }); - */ + } function setCurrentVariant() { @@ -56,6 +55,12 @@ } } + scope.selectAnchorItem = function(item, anchor) { + if(scope.onSelectAnchorItem) { + scope.onSelectAnchorItem({"item": item, "anchor": anchor}); + } + } + scope.closeSplitView = function () { if (scope.onCloseSplitView) { scope.onCloseSplitView(); @@ -114,6 +119,7 @@ openVariants: "<", hideChangeVariant: " a { text-align: center; cursor: pointer; display: block; @@ -36,16 +36,16 @@ } } -.umb-sub-views-nav-item a:focus { +.umb-sub-views-nav-item > a:focus { outline: none; } -.umb-sub-views-nav-item a:hover, -.umb-sub-views-nav-item a:focus { +.umb-sub-views-nav-item > a:hover, +.umb-sub-views-nav-item > a:focus { text-decoration: none; } -.umb-sub-views-nav-item a.is-active { +.umb-sub-views-nav-item > a.is-active { color: @ui-light-active-type; @@ -55,7 +55,7 @@ } } -.show-validation .umb-sub-views-nav-item a.-has-error { +.show-validation .umb-sub-views-nav-item > a.-has-error { color: @red; } @@ -98,6 +98,28 @@ line-height: 1em; } + +.umb-sub-views-nav-item__anchor_dropdown {// inherits from .dropdown-menu + display: none; + &.show { + display: block; + } +} +.umb-sub-views-nav-item__anchor_dropdown li a { + border-left: 4px solid transparent; +} +.umb-sub-views-nav-item__anchor_dropdown li.is-active a { + border-left-color: @ui-selected-border; +} +.umb-sub-views-nav-item__anchor_dropdown li:hover.is-active a { + border-left-color: @ui-selected-border-hover; +} + + +// -------------------------------- +// item__more, appears when there is not enough room for the visible items. +// -------------------------------- + .umb-sub-views-nav-item-more__icon { margin-bottom: 10px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html index e97eabf17f..dda9334e05 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html @@ -10,7 +10,8 @@ page="page" content="content" culture="culture" - on-select-app="appChanged(app)"> + on-select-app="appChanged(app)" + on-select-app-anchor="appAnchorChanged(app, anchor)"> diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html index cdacea7cf1..be768db497 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html @@ -1,16 +1,15 @@ 
      -
      +
      -
      +
      {{ group.label }}
      -  
      -
      - + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content-editors.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content-editors.html index 9d879fac22..76bca6fce2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content-editors.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content-editors.html @@ -13,7 +13,8 @@ on-open-split-view="vm.openSplitView(variant)" on-close-split-view="vm.closeSplitView($index)" on-select-variant="vm.selectVariant(variant, $index)" - on-select-app="vm.selectApp(app)"> + on-select-app="vm.selectApp(app)" + on-select-app-anchor="vm.selectAppAnchor(app, anchor)">
      diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html index 84928a00bb..34c7792055 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-variant-content.html @@ -13,6 +13,7 @@ name-disabled="vm.nameDisabled" content="vm.editor.content" on-select-navigation-item="vm.selectApp(item)" + on-select-anchor-item="vm.selectAppAnchor(item, anchor)" open-variants="vm.openVariants" hide-change-variant="vm.page.hideChangeVariant" show-back-button="vm.page.listViewPath !== null" diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-content-header.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-content-header.html index 8e308e89b2..98ecfd4d28 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-content-header.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-content-header.html @@ -64,7 +64,8 @@ + on-select="selectNavigationItem(item)" + on-anchor-select="selectAnchorItem(item, anchor)">
      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 329e96242b..848985239c 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 @@ -1,7 +1,7 @@ @@ -9,3 +9,11 @@ {{ vm.item.name }}
      {{vm.item.badge.count}}
      + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html index 31388a54f8..0c8f0be7a2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-navigation.html @@ -6,6 +6,7 @@
      @@ -28,6 +29,7 @@ From 42803ff006d45167ac4e259d53691dd00f4958d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 7 Feb 2019 13:26:23 +0100 Subject: [PATCH 04/54] V8: umb-editor-navigation anchor-dropdown refined, remembers last active anchor, --- .../components/content/edit.controller.js | 10 +++-- .../content/umbtabbedcontent.directive.js | 39 ++++++++++++++++--- .../content/umbvariantcontent.directive.js | 14 ++++--- .../umbvariantcontenteditors.directive.js | 11 ++++-- .../editor/umbeditornavigation.directive.js | 3 ++ .../umbeditornavigationitem.directive.js | 2 +- .../umb-editor-navigation-item.less | 15 +++++-- .../editor/umb-editor-navigation-item.html | 2 +- 8 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index c91683be83..6b7b129809 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -871,6 +871,8 @@ $scope.app = app; + $scope.$broadcast("editors.apps.appChanged", { app: app }); + if (infiniteMode) { createInfiniteModeButtons($scope.content); } else { @@ -883,13 +885,15 @@ * @param {any} app */ $scope.appAnchorChanged = function (app, anchor) { - + /* + // This is how it should be done — but because of the current architecture, i had to give the responsibilty to 'activate' the content-app to the menu, cause thats the only place you currently can change the active content-app. + // proposal. Make sure that the content-app-menu dosnt do anything. Just make it callback when menu-item are clicked, then make the controller of the view handle what to be done. Then the controller should broadcast a local event, notifying that the current content-app has been changed. + // read more on this issue: https://github.com/umbraco/Umbraco-CMS/issues/4467 if ($scope.app !== app) { - console.log("Change app") // TODO: Not working..!!!!!!!! $scope.appChanged(app); } - + */ //send an event downwards $scope.$broadcast("editors.apps.appAnchorChanged", { app: app, anchor: anchor }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index f288d8681d..c2d2ce5fa9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -2,7 +2,7 @@ 'use strict'; /** This directive is used to render out the current variant tabs and properties and exposes an API for other directives to consume */ - function tabbedContentDirective() { + function tabbedContentDirective($timeout) { function link($scope, $element, $attrs) { @@ -36,12 +36,30 @@ } tab.active = true; } + function getActiveAnchor() { + var i = $scope.content.tabs.length; + while(i--) { + if ($scope.content.tabs[i].active === true) + return $scope.content.tabs[i]; + } + return false; + } + function getScrollPositionFor(id) { + if (propertyGroupNodesDictionary[id]) { + return propertyGroupNodesDictionary[id].offsetTop - 20;// currently only relative to closest relatively positioned parent + } + return null; + } function scrollTo(id) { console.log("scrollTo", id); - - if (propertyGroupNodesDictionary[id]) { - let y = propertyGroupNodesDictionary[id].offsetTop - 20;// currently only relative to closest relatively positioned parent - + var y = getScrollPositionFor(id); + if (getScrollPositionFor !== null) { + scrollableNode.scrollTo(0, y); + } + } + function jumpTo(id) { + var y = getScrollPositionFor(id); + if (getScrollPositionFor !== null) { scrollableNode.scrollTo(0, y); } } @@ -50,6 +68,14 @@ propertyGroupNodesDictionary[appAnchor] = element; } + $scope.$on("editors.apps.appChanged", function($event, $args) { + // if app changed to this app, then we want to scroll to the current anchor + if($args.app.alias === "umbContent") { + var activeAnchor = getActiveAnchor(); + $timeout(jumpTo.bind(null, [activeAnchor.id])); + } + }); + $scope.$on("editors.apps.appAnchorChanged", function($event, $args) { if($args.app.alias === "umbContent") { setActiveAnchor($args.anchor); @@ -84,7 +110,8 @@ if (newValue === true) { $scope.content.isDirty = true; } - }); + } + ); } var directive = { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js index 9eb4ddee15..5556308e06 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontent.directive.js @@ -80,16 +80,20 @@ * @param {any} item */ function selectApp(item) { - // disable the name field if the active content app is not "Content" or "Info" - vm.nameDisabled = false; - if(item && item.alias !== "umbContent" && item.alias !== "umbInfo") { - vm.nameDisabled = true; - } // call the callback if any is registered if(vm.onSelectApp) { vm.onSelectApp({"app": item}); } } + + $scope.$on("editors.apps.appChanged", function($event, $args) { + var app = $args.app; + // disable the name field if the active content app is not "Content" or "Info" + vm.nameDisabled = false; + if(app && app.alias !== "umbContent" && app.alias !== "umbInfo") { + vm.nameDisabled = true; + } + }); /** * Used to proxy a callback diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js index 0995a13707..bd21cca541 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js @@ -318,9 +318,6 @@ * @param {any} app This is the model of the selected app */ function selectApp(app) { - if(app && app.alias) { - activeAppAlias = app.alias; - } if(vm.onSelectApp) { vm.onSelectApp({"app": app}); } @@ -331,6 +328,14 @@ vm.onSelectAppAnchor({"app": app, "anchor": anchor}); } } + + + $scope.$on("editors.apps.appChanged", function($event, $args) { + var app = $args.app; + if(app && app.alias) { + activeAppAlias = app.alias; + } + }); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js index 34810f17dd..31976118fd 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigation.directive.js @@ -32,6 +32,9 @@ if(scope.onAnchorSelect) { scope.onAnchorSelect({"item": item, "anchor": anchor}); } + if (item.active !== true) { + scope.openNavigationItem(item); + } }; scope.toggleDropdown = function () { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js index abb685807b..8ebee7d15c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js @@ -48,7 +48,7 @@ Use this directive to render tab content. For an example see: {@link umbraco.dir vm.mouseOut = function() { clearTimeout(vm.mouseOutDelay); - vm.mouseOutDelay = setTimeout(hideDropdownBind, 1000); + vm.mouseOutDelay = setTimeout(hideDropdownBind, 500); } 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 faa4ff40b0..673de62b36 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 @@ -1,5 +1,6 @@ .umb-sub-views-nav-item { position: relative; + display: block; } .umb-sub-views-nav-item > a { text-align: center; @@ -36,6 +37,9 @@ } } +.umb-sub-views-nav-item > a:active { + .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); +} .umb-sub-views-nav-item > a:focus { outline: none; } @@ -101,6 +105,12 @@ .umb-sub-views-nav-item__anchor_dropdown {// inherits from .dropdown-menu display: none; + margin: 0; + + // center align horizontal + left: 50%; + transform: translateX(-50%); + &.show { display: block; } @@ -111,9 +121,8 @@ .umb-sub-views-nav-item__anchor_dropdown li.is-active a { border-left-color: @ui-selected-border; } -.umb-sub-views-nav-item__anchor_dropdown li:hover.is-active a { - border-left-color: @ui-selected-border-hover; -} + +.umb-sub-views-nav-item // -------------------------------- 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 848985239c..90408e00cc 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 @@ -11,7 +11,7 @@ -
      \ No newline at end of file +
      diff --git a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs index 46069fec79..601728189c 100644 --- a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -8,7 +8,7 @@ namespace Umbraco.Web.PropertyEditors /// /// A property editor to allow the individual selection of pre-defined items. /// - [DataEditor(Constants.PropertyEditors.Aliases.RadioButtonList, "Radio button list", "radiobuttons", ValueType = ValueTypes.Integer, Group="lists", Icon="icon-target")] + [DataEditor(Constants.PropertyEditors.Aliases.RadioButtonList, "Radio button list", "radiobuttons", ValueType = ValueTypes.String, Group="lists", Icon="icon-target")] public class RadioButtonsPropertyEditor : DataEditor { private readonly ILocalizedTextService _textService; From 354c45e0e2971a3352b328d83624744e09ac467f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 8 Feb 2019 10:32:21 +0100 Subject: [PATCH 10/54] #4477 - also refresh cache after migration --- .../RadioButtonPropertyEditorsMigration.cs | 57 ++++++++++++++++++- .../RadioButtonListValueConverter.cs | 6 +- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs index bcea3ec3b6..4a5e2269b0 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs @@ -1,18 +1,27 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; +using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Sync; +using Umbraco.Web.Cache; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { public class RadioButtonPropertyEditorsMigration : MigrationBase { - public RadioButtonPropertyEditorsMigration(IMigrationContext context) + private readonly CacheRefresherCollection _cacheRefreshers; + private readonly IServerMessenger _serverMessenger; + + public RadioButtonPropertyEditorsMigration(IMigrationContext context, CacheRefresherCollection cacheRefreshers, IServerMessenger serverMessenger) : base(context) { + _cacheRefreshers = cacheRefreshers; + _serverMessenger = serverMessenger; } public override void Migrate() @@ -23,6 +32,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 .From() .Where(x => x.EditorAlias == "Umbraco.RadioButtonList")); + var refreshCache = false; foreach (var dataType in dataTypes) { ValueListConfiguration config; @@ -60,15 +70,42 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 // persist changes foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto); + + UpdateDataType(dataType); + refreshCache = true; } } + + if (refreshCache) + { + var dataTypeCacheRefresher = _cacheRefreshers[ContentCacheRefresher.UniqueId]; + _serverMessenger.PerformRefreshAll(dataTypeCacheRefresher); + } + + } + + private void UpdateDataType(DataTypeDto dataType) + { + dataType.DbType = ValueStorageType.Nvarchar.ToString(); + Database.Update(dataType); } private bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config) { //Get the INT ids stored for this property/drop down int[] ids = null; - if (propData.IntegerValue.HasValue) ids = new[] {propData.IntegerValue.Value}; + if (!propData.VarcharValue.IsNullOrWhiteSpace()) + { + ids = ConvertStringValues(propData.VarcharValue); + } + else if (!propData.TextValue.IsNullOrWhiteSpace()) + { + ids = ConvertStringValues(propData.TextValue); + } + else if (propData.IntegerValue.HasValue) + { + ids = new[] { propData.IntegerValue.Value }; + } //if there are INT ids, convert them to values based on the configuration if (ids == null || ids.Length <= 0) return false; @@ -101,5 +138,21 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 private class ValueListConfigurationEditor : ConfigurationEditor { } + + private int[] ConvertStringValues(string val) + { + var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + var intVals = splitVals + .Select(x => int.TryParse(x, out var i) ? i : int.MinValue) + .Where(x => x != int.MinValue) + .ToArray(); + + //only return if the number of values are the same (i.e. All INTs) + if (splitVals.Length == intVals.Length) + return intVals; + + return null; + } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs index fc7d3d42de..b99cc7e0e3 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs @@ -17,10 +17,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) { - var intAttempt = source.TryConvertTo(); + var attempt = source.TryConvertTo(); - if (intAttempt.Success) - return intAttempt.Result; + if (attempt.Success) + return attempt.Result; return null; } From 8f39cd605aa35ec95a884675c92be59efe2b957b Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 8 Feb 2019 11:47:42 +0100 Subject: [PATCH 11/54] Fix MacroMapperProfile --- src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs index de649a09d8..a507cc4c03 100644 --- a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs @@ -45,9 +45,15 @@ namespace Umbraco.Web.Models.Mapping } parameter.View = paramEditor.GetValueEditor().View; - var paramConfig = paramEditor.GetConfigurationEditor().ToValueEditor(paramEditor.DefaultConfiguration); - //set the config - parameter.Configuration = paramConfig; + + // sets the parameter configuration to be the default configuration editor's configuration, + // ie configurationEditor.DefaultConfigurationObject, prepared for the value editor, ie + // after ToValueEditor - important to use DefaultConfigurationObject here, because depending + // on editors, ToValueEditor expects the actual strongly typed configuration - not the + // dictionary thing returned by DefaultConfiguration + + var configurationEditor = paramEditor.GetConfigurationEditor(); + parameter.Configuration = configurationEditor.ToValueEditor(configurationEditor.DefaultConfigurationObject); }); } } From b5c803b5ed0fd75722af3d16e7f037ebc7f65839 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 8 Feb 2019 12:42:46 +0100 Subject: [PATCH 12/54] Cleanup TreeEntityPath --- .../Persistence/Repositories/Implement/EntityRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs index 5321e45f24..ae907051ca 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs @@ -199,7 +199,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private IEnumerable PerformGetAllPaths(Guid objectType, Action> filter = null) { // NodeId is named Id on TreeEntityPath = use an alias - var sql = Sql().Select(x => Alias(x.NodeId, "Id"), x => x.Path).From().Where(x => x.NodeObjectType == objectType); + var sql = Sql().Select(x => Alias(x.NodeId, nameof(TreeEntityPath.Id)), x => x.Path).From().Where(x => x.NodeObjectType == objectType); filter?.Invoke(sql); return Database.Fetch(sql); } From 1860a175d1e00bb39158eef1a1d465dc7d488042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 8 Feb 2019 13:06:56 +0100 Subject: [PATCH 13/54] remove eventlisteners on destroy --- .../components/content/umbtabbedcontent.directive.js | 10 ++++++++-- .../editor/umbeditornavigationitem.directive.js | 12 +++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index deb799580f..6fe0881f72 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -13,7 +13,7 @@ var scrollableNode = appRootNode.closest(".umb-scrollable"); scrollableNode.addEventListener("scroll", onScroll); - scrollableNode.addEventListener("mousehweel", cancelScrollTween); + scrollableNode.addEventListener("mousewheel", cancelScrollTween); function onScroll(event) { @@ -87,7 +87,7 @@ $scope.registerPropertyGroup = function(element, appAnchor) { propertyGroupNodesDictionary[appAnchor] = element; - } + }; $scope.$on("editors.apps.appChanged", function($event, $args) { // if app changed to this app, then we want to scroll to the current anchor @@ -104,6 +104,12 @@ } }); + //ensure to unregister from all dom-events + $scope.$on('$destroy', function () { + cancelScrollTween(); + scrollableNode.removeEventListener("scroll", onScroll); + scrollableNode.removeEventListener("mousehweel", cancelScrollTween); + }); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js index 1d5bfb552a..3a0dbb06d8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditornavigationitem.directive.js @@ -10,15 +10,25 @@ }; vm.anchorClicked = function(anchor, $event) { - vm.onOpenAnchor({item:vm.item, anchor:anchor}); $event.stopPropagation(); $event.preventDefault(); }; + // needed to make sure that we update what anchors are active. + vm.mouseOver = function() { + $scope.$digest(); + } + var componentNode = $element[0]; componentNode.classList.add('umb-sub-views-nav-item'); + componentNode.addEventListener('mouseover', vm.mouseOver); + + //ensure to unregister from all dom-events + $scope.$on('$destroy', function () { + componentNode.removeEventListener("mouseover", vm.mouseOver); + }); } From 612a63b6bb5edb7d8f77deae37914e7a01f5510b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 8 Feb 2019 13:30:20 +0100 Subject: [PATCH 14/54] fix if scrollTween not defined issue --- .../components/content/umbtabbedcontent.directive.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index 6fe0881f72..ecc8872ba1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -82,7 +82,9 @@ } } function cancelScrollTween() { - $scope.scrollTween.pause(); + if($scope.scrollTween) { + $scope.scrollTween.pause(); + } } $scope.registerPropertyGroup = function(element, appAnchor) { From 521fc227ba0f9a3de107219579b77ec80e61c333 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 8 Feb 2019 13:04:30 +0000 Subject: [PATCH 15/54] TYPO - Update src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js --- .../directives/components/content/umbtabbedcontent.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js index ecc8872ba1..06f426889f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbtabbedcontent.directive.js @@ -110,7 +110,7 @@ $scope.$on('$destroy', function () { cancelScrollTween(); scrollableNode.removeEventListener("scroll", onScroll); - scrollableNode.removeEventListener("mousehweel", cancelScrollTween); + scrollableNode.removeEventListener("mousewheel", cancelScrollTween); }); } From b177607d47d1b03e83f6cbe190522d48e3b4b56f Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 8 Feb 2019 14:13:46 +0100 Subject: [PATCH 16/54] Suspend JS tests - can we build? --- src/Umbraco.Web.UI.Client/gulp/tasks/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/build.js b/src/Umbraco.Web.UI.Client/gulp/tasks/build.js index 32bf71f5f7..8fe582e406 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/build.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/build.js @@ -6,5 +6,5 @@ var runSequence = require('run-sequence'); // Build - build the files ready for production gulp.task('build', function(cb) { - runSequence(["js", "dependencies", "less", "views"], "test:unit", cb); + runSequence(["js", "dependencies", "less", "views"], /*"test:unit",*/ cb); }); From 4f53cfc85527ad8cdf02e25f7c66b4be5c64f8b0 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 8 Feb 2019 14:18:24 +0100 Subject: [PATCH 17/54] #4477 - Added fixme for cache rebuild --- .../V_8_0_0/RadioButtonPropertyEditorsMigration.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs index 4a5e2269b0..2c4e601a9e 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs @@ -14,14 +14,9 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { public class RadioButtonPropertyEditorsMigration : MigrationBase { - private readonly CacheRefresherCollection _cacheRefreshers; - private readonly IServerMessenger _serverMessenger; - - public RadioButtonPropertyEditorsMigration(IMigrationContext context, CacheRefresherCollection cacheRefreshers, IServerMessenger serverMessenger) + public RadioButtonPropertyEditorsMigration(IMigrationContext context) : base(context) { - _cacheRefreshers = cacheRefreshers; - _serverMessenger = serverMessenger; } public override void Migrate() @@ -78,8 +73,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 if (refreshCache) { - var dataTypeCacheRefresher = _cacheRefreshers[ContentCacheRefresher.UniqueId]; - _serverMessenger.PerformRefreshAll(dataTypeCacheRefresher); + //FIXME: trigger cache rebuild. Currently the data in the database tables is wrong. } } From 99887cb362d76ebbe5e22772b21d83514182fe7e Mon Sep 17 00:00:00 2001 From: Stephan Date: Sun, 10 Feb 2019 11:25:46 +0100 Subject: [PATCH 18/54] Bugfix IdkMap --- src/Umbraco.Core/Services/IdkMap.cs | 2 +- .../PublishedCache/NuCache/PublishedSnapshotService.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Services/IdkMap.cs b/src/Umbraco.Core/Services/IdkMap.cs index 9ec62fda0f..f352def49e 100644 --- a/src/Umbraco.Core/Services/IdkMap.cs +++ b/src/Umbraco.Core/Services/IdkMap.cs @@ -158,7 +158,7 @@ namespace Umbraco.Core.Services // multiple times, but we don't lock the cache while accessing the database = better int? val = null; - + if (_dictionary.TryGetValue(umbracoObjectType, out var mappers)) if ((val = mappers.key2id(key)) == default(int)) val = null; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 9845becb45..cc1216eb68 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -192,10 +192,13 @@ namespace Umbraco.Web.PublishedCache.NuCache LoadCaches(); + Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? default; + int GetId(ContentStore store, Guid uid) => store.LiveSnapshot.Get(uid)?.Id ?? default; + if (idkMap != null) { - idkMap.SetMapper(UmbracoObjectTypes.Document, id => _contentStore.LiveSnapshot.Get(id).Uid, uid => _contentStore.LiveSnapshot.Get(uid).Id); - idkMap.SetMapper(UmbracoObjectTypes.Media, id => _mediaStore.LiveSnapshot.Get(id).Uid, uid => _mediaStore.LiveSnapshot.Get(uid).Id); + idkMap.SetMapper(UmbracoObjectTypes.Document, id => GetUid(_contentStore, id), uid => GetId(_contentStore, uid)); + idkMap.SetMapper(UmbracoObjectTypes.Media, id => GetUid(_mediaStore, id), uid => GetId(_mediaStore, uid)); } } From 6fdada69eb2d96744fb1f640c194a0c626b5ef82 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sun, 10 Feb 2019 18:55:16 +0100 Subject: [PATCH 19/54] Always show folder names in the media picker --- .../src/views/components/umb-media-grid.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html index da94729562..1f5235146d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html @@ -4,7 +4,7 @@ -
      +
      {{item.name}}
      From dd54b0324c6cb0e8fa1a4f00ace3acd71fb1badf Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 11 Feb 2019 14:13:44 +1100 Subject: [PATCH 20/54] fixes up some comments --- src/Umbraco.Core/Services/IMediaService.cs | 4 +--- src/Umbraco.Core/Services/IMemberService.cs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index 02398c3634..78da440bc6 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -100,9 +100,7 @@ namespace Umbraco.Core.Services /// Page number /// Page size /// Total records query would return without paging - /// Field to order by - /// Direction to order by - /// Flag to indicate when ordering by system field + /// /// /// An Enumerable list of objects IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index 8a9d11f766..ee0e2ef5ed 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -99,7 +99,6 @@ namespace Umbraco.Core.Services /// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method which can be /// used during Member creation. /// - /// /// This method exists so that Umbraco developers can use one entry point to create/update /// this will not work for updating members in most cases (depends on your membership provider settings) /// From e35436225f9bd3d1a9096c888eabf249d300c6ce Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 11 Feb 2019 15:47:13 +1100 Subject: [PATCH 21/54] Fixes JS with the content picker --- .../src/common/services/umbrequesthelper.service.js | 4 ++++ .../propertyeditors/contentpicker/contentpicker.controller.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index 6991c5d386..bad5f4e342 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -161,6 +161,10 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe }, function (response) { + if (!response) { + return; //sometimes oddly this happens, nothing we can do + } + if (!response.status && response.message && response.stack) { //this is a JS/angular error that we should deal with return $q.reject({ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index 15a1526b9f..16aa7efceb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -105,6 +105,10 @@ function contentPickerController($scope, entityResource, editorState, iconHelper }; if ($scope.model.config) { + //special case, if the `startNode` is falsy on the server config delete it entirely so the default value is merged in + if (!$scope.model.config.startNode) { + delete $scope.model.config.startNode; + } //merge the server config on top of the default config, then set the server config to use the result $scope.model.config = angular.extend(defaultConfig, $scope.model.config); } From e62de9561bdbf87db1a8e7a7e41b10cda770bf82 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 11 Feb 2019 07:54:39 +0100 Subject: [PATCH 22/54] #4466 - Sets the MacroType when created from Partial View Macro Files snippets --- src/Umbraco.Web/Editors/MacroRenderingController.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Editors/MacroRenderingController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs index 3cd2e86dd8..49b58416cd 100644 --- a/src/Umbraco.Web/Editors/MacroRenderingController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -124,7 +124,7 @@ namespace Umbraco.Web.Editors // When rendering the macro in the backoffice the default setting would be to use the Culture of the logged in user. // Since a Macro might contain thing thats related to the culture of the "IPublishedContent" (ie Dictionary keys) we want // to set the current culture to the culture related to the content item. This is hacky but it works. - + var culture = publishedContent.GetCulture(); _variationContextAccessor.VariationContext = new VariationContext(); //must have an active variation context! if (culture != null) @@ -156,7 +156,8 @@ namespace Umbraco.Web.Editors { Alias = macroName.ToSafeAlias(), Name = macroName, - MacroSource = model.VirtualPath.EnsureStartsWith("~") + MacroSource = model.VirtualPath.EnsureStartsWith("~"), + MacroType = MacroTypes.PartialView }; _macroService.Save(macro); // may throw From 153b665d0a9b434a2f1269371381ef0e547b5170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 11 Feb 2019 09:39:54 +0100 Subject: [PATCH 23/54] #4430 change grid-editor settings to use editorService --- .../grid/dialogs/editconfig.controller.js | 16 ++ .../grid/dialogs/editconfig.html | 53 +++++++ .../grid/dialogs/layoutconfig.controller.js | 28 +++- .../grid/dialogs/layoutconfig.html | 52 ++++++- .../grid/dialogs/rowconfig.controller.js | 26 +++- .../grid/dialogs/rowconfig.html | 51 ++++++- .../dialogs/rowdeleteconfirm.controller.js | 16 ++ .../grid/dialogs/rowdeleteconfirm.html | 38 ++++- .../grid/grid.prevalues.controller.js | 139 ++++++++---------- .../propertyeditors/grid/grid.prevalues.html | 24 --- 10 files changed, 330 insertions(+), 113 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js new file mode 100644 index 0000000000..3441b6a060 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.controller.js @@ -0,0 +1,16 @@ +function EditConfigController($scope) { + + $scope.close = function() { + if($scope.model.close) { + $scope.model.close(); + } + } + + $scope.submit = function() { + if($scope.model && $scope.model.submit) { + $scope.model.submit($scope.model); + } + } +} + +angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController", EditConfigController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html index fb541ecf84..9c42e04f75 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/editconfig.html @@ -1,3 +1,25 @@ +
      + + + + + +
      + + + + + + + + + +

      {{model.name}}

      @@ -12,3 +34,34 @@
      + + + + + + + + + + + + + + + + + + + + + +
      diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js index 566535fc98..4ad857b1e7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js @@ -1,10 +1,25 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.GridPrevalueEditor.LayoutConfigController", - function ($scope) { + function ($scope, localizationService) { + + + function init() { + setTitle(); + } + + function setTitle() { + if (!$scope.model.title) { + localizationService.localize("grid_addGridLayout") + .then(function(data){ + $scope.model.title = data; + }); + } + } $scope.currentLayout = $scope.model.currentLayout; $scope.columns = $scope.model.columns; $scope.rows = $scope.model.rows; + $scope.currentSection = undefined; $scope.scaleUp = function(section, max, overflow){ var add = 1; @@ -57,9 +72,12 @@ angular.module("umbraco") template.sections.splice(index, 1); }; - $scope.closeSection = function(){ - $scope.currentSection = undefined; - }; + + $scope.close = function() { + if($scope.model.close) { + $scope.model.close(); + } + } $scope.$watch("currentLayout", function(layout){ if(layout){ @@ -71,4 +89,6 @@ angular.module("umbraco") $scope.availableLayoutSpace = $scope.columns - total; } }, true); + + init(); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.html index 0e1a92a62c..6f70c5e7ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.html @@ -1,8 +1,31 @@
      + + + + + +
      + + + + + + + + + + + + +
      -

      @@ -32,7 +55,7 @@
      -
      +
      @@ -111,4 +134,27 @@
      -
      + + + + + + + + + + + + + + + + + + +
      diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js index 4e3dde50e4..1bb7516f30 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js @@ -1,5 +1,19 @@ -function RowConfigController($scope) { +function RowConfigController($scope, localizationService) { + function init() { + setTitle(); + } + + function setTitle() { + if (!$scope.model.title) { + localizationService.localize("grid_addRowConfiguration") + .then(function(data){ + $scope.model.title = data; + }); + } + } + + $scope.currentRow = $scope.model.currentRow; $scope.editors = $scope.model.editors; $scope.columns = $scope.model.columns; @@ -69,6 +83,12 @@ function RowConfigController($scope) { $scope.closeArea = function() { $scope.currentCell = undefined; }; + + $scope.close = function() { + if($scope.model.close) { + $scope.model.close(); + } + } $scope.nameChanged = false; var originalName = $scope.currentRow.name; @@ -93,6 +113,10 @@ function RowConfigController($scope) { } }, true); + + init(); + + } angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController", RowConfigController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html index c9a0d807ea..12d83f23fd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html @@ -1,8 +1,30 @@
      + + + + +
      + + + + + + + + + + + + +
      -

      @@ -14,7 +36,7 @@ - + @@ -54,7 +76,7 @@
      - + @@ -97,4 +119,27 @@
      + + + +
      +
      +
      + + + + + + + + +
      + +
      +
      diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.controller.js new file mode 100644 index 0000000000..10b5601304 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.controller.js @@ -0,0 +1,16 @@ +function DeleteRowConfirmController($scope) { + + $scope.close = function() { + if($scope.model.close) { + $scope.model.close(); + } + } + + $scope.submit = function() { + if($scope.model && $scope.model.submit) { + $scope.model.submit($scope.model); + } + } +} + +angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.DeleteRowConfirmController", DeleteRowConfirmController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html index c69ae2cb8f..2bf1f00b0e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html @@ -1,4 +1,13 @@ -
      +
      + + + + + + + + +

      Warning!

      @@ -15,4 +24,31 @@ Are you sure?

      + + + +
      +
      +
      + + + + + + + + + + +
      +
      diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js index 19057fa842..d38697d351 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js @@ -1,6 +1,6 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.GridPrevalueEditorController", - function ($scope, gridService) { + function ($scope, gridService, editorService) { var emptyModel = { styles:[ @@ -89,28 +89,23 @@ angular.module("umbraco") }; $scope.model.value.templates.push(template); } + + var layoutConfigOverlay = { + currentLayout: template, + rows: $scope.model.value.layouts, + columns: $scope.model.value.columns, + view: "views/propertyEditors/grid/dialogs/layoutconfig.html", + size: "small", + submit: function(model) { + editorService.close(); + }, + close: function(model) { + editorService.close(); + } + }; - $scope.layoutConfigOverlay = {}; - $scope.layoutConfigOverlay.view = "views/propertyEditors/grid/dialogs/layoutconfig.html"; - $scope.layoutConfigOverlay.currentLayout = template; - $scope.layoutConfigOverlay.rows = $scope.model.value.layouts; - $scope.layoutConfigOverlay.columns = $scope.model.value.columns; - $scope.layoutConfigOverlay.show = true; + editorService.open(layoutConfigOverlay); - $scope.layoutConfigOverlay.submit = function(model) { - $scope.layoutConfigOverlay.show = false; - $scope.layoutConfigOverlay = null; - }; - - $scope.layoutConfigOverlay.close = function(oldModel) { - - //reset templates - $scope.model.value.templates = templatesCopy; - - $scope.layoutConfigOverlay.show = false; - $scope.layoutConfigOverlay = null; - } - }; $scope.deleteTemplate = function(index){ @@ -135,50 +130,44 @@ angular.module("umbraco") }; $scope.model.value.layouts.push(layout); } - - $scope.rowConfigOverlay = {}; - $scope.rowConfigOverlay.view = "views/propertyEditors/grid/dialogs/rowconfig.html"; - $scope.rowConfigOverlay.currentRow = layout; - $scope.rowConfigOverlay.editors = $scope.editors; - $scope.rowConfigOverlay.columns = $scope.model.value.columns; - $scope.rowConfigOverlay.show = true; - - $scope.rowConfigOverlay.submit = function(model) { - $scope.rowConfigOverlay.show = false; - $scope.rowConfigOverlay = null; - }; - - $scope.rowConfigOverlay.close = function(oldModel) { - $scope.model.value.layouts = layoutsCopy; - $scope.rowConfigOverlay.show = false; - $scope.rowConfigOverlay = null; + + var rowConfigOverlay = { + currentRow: layout, + editors: $scope.editors, + columns: $scope.model.value.columns, + view: "views/propertyEditors/grid/dialogs/rowconfig.html", + size: "small", + submit: function(model) { + editorService.close(); + }, + close: function(model) { + editorService.close(); + } }; + editorService.open(rowConfigOverlay); + }; //var rowDeletesPending = false; $scope.deleteLayout = function(index) { + + var rowDeleteOverlay = { + dialogData: { + rowName: $scope.model.value.layouts[index].name + }, + view: "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html", + size: "small", + submit: function(model) { + $scope.model.value.layouts.splice(index, 1); + editorService.close(); + }, + close: function(model) { + editorService.close(); + } + }; - $scope.rowDeleteOverlay = {}; - $scope.rowDeleteOverlay.view = "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html"; - $scope.rowDeleteOverlay.dialogData = { - rowName: $scope.model.value.layouts[index].name - }; - $scope.rowDeleteOverlay.show = true; - - $scope.rowDeleteOverlay.submit = function(model) { - - $scope.model.value.layouts.splice(index, 1); - - $scope.rowDeleteOverlay.show = false; - $scope.rowDeleteOverlay = null; - }; - - $scope.rowDeleteOverlay.close = function(oldModel) { - $scope.rowDeleteOverlay.show = false; - $scope.rowDeleteOverlay = null; - }; - + editorService.open(rowDeleteOverlay); }; @@ -210,26 +199,22 @@ angular.module("umbraco") }; var editConfigCollection = function(configValues, title, callback) { + + var editConfigCollectionOverlay = { + config: configValues, + title: title, + view: "views/propertyeditors/grid/dialogs/editconfig.html", + size: "small", + submit: function(model) { + callback(model.config); + editorService.close(); + }, + close: function(model) { + editorService.close(); + } + }; - $scope.editConfigCollectionOverlay = {}; - $scope.editConfigCollectionOverlay.view = "views/propertyeditors/grid/dialogs/editconfig.html"; - $scope.editConfigCollectionOverlay.config = configValues; - $scope.editConfigCollectionOverlay.title = title; - $scope.editConfigCollectionOverlay.show = true; - - $scope.editConfigCollectionOverlay.submit = function(model) { - - callback(model.config); - - $scope.editConfigCollectionOverlay.show = false; - $scope.editConfigCollectionOverlay = null; - }; - - $scope.editConfigCollectionOverlay.close = function(oldModel) { - $scope.editConfigCollectionOverlay.show = false; - $scope.editConfigCollectionOverlay = null; - }; - + editorService.open(editConfigCollectionOverlay); }; $scope.editConfig = function() { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html index 539433821b..92d1a9ef26 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html @@ -158,28 +158,4 @@
      - - - - - - - - - - - -
    From 14f878b690d489ace56dd104e05c757119b12ed0 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 11 Feb 2019 10:36:54 +0100 Subject: [PATCH 24/54] #4477 - Align Dropdown, checkbox list and radio button list --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 + .../CheckBoxListPropertyEditorsMigration.cs | 150 ++++++++++++++++++ .../RadioButtonPropertyEditorsMigration.cs | 6 +- .../CheckboxListValueConverter.cs | 5 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../checkboxlist/checkboxlist.controller.js | 6 +- .../checkboxlist/checkboxlist.html | 2 +- .../PublishValuesMultipleValueEditor.cs | 13 +- .../FlexibleDropdownPropertyValueConverter.cs | 7 +- 9 files changed, 172 insertions(+), 19 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/CheckBoxListPropertyEditorsMigration.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index c8247aa835..d185c31a2b 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -128,6 +128,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); To("{940FD19A-00A8-4D5C-B8FF-939143585726}"); + To("{C62C9BF1-833E-4866-B959-C8AB59E43E51}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/CheckBoxListPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/CheckBoxListPropertyEditorsMigration.cs new file mode 100644 index 0000000000..87a77963a8 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/CheckBoxListPropertyEditorsMigration.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class CheckBoxListPropertyEditorsMigration : MigrationBase + { + public CheckBoxListPropertyEditorsMigration(IMigrationContext context) + : base(context) + { + } + + public override void Migrate() + { + //need to convert the old drop down data types to use the new one + var dataTypes = Database.Fetch(Sql() + .Select() + .From() + .Where(x => x.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.CheckBoxList))); + + var refreshCache = false; + foreach (var dataType in dataTypes) + { + ValueListConfiguration config; + + if (!dataType.Configuration.IsNullOrWhiteSpace()) + { + // parse configuration, and update everything accordingly + try + { + config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase( + dataType.Configuration); + } + catch (Exception ex) + { + Logger.Error( + ex, + "Invalid drop down configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared", + dataType.Configuration); + + continue; + } + + // get property data dtos + var propertyDataDtos = Database.Fetch(Sql() + .Select() + .From() + .InnerJoin() + .On((pt, pd) => pt.Id == pd.PropertyTypeId) + .InnerJoin() + .On((dt, pt) => dt.NodeId == pt.DataTypeId) + .Where(x => x.DataTypeId == dataType.NodeId)); + + // update dtos + var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config)); + + // persist changes + foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto); + + UpdateDataType(dataType); + refreshCache = true; + } + } + + if (refreshCache) + { + //FIXME: trigger cache rebuild. Currently the data in the database tables is wrong. + } + + } + + private void UpdateDataType(DataTypeDto dataType) + { + dataType.DbType = ValueStorageType.Nvarchar.ToString(); + Database.Update(dataType); + } + + private bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config) + { + //Get the INT ids stored for this property/drop down + int[] ids = null; + if (!propData.VarcharValue.IsNullOrWhiteSpace()) + { + ids = ConvertStringValues(propData.VarcharValue); + } + else if (!propData.TextValue.IsNullOrWhiteSpace()) + { + ids = ConvertStringValues(propData.TextValue); + } + else if (propData.IntegerValue.HasValue) + { + ids = new[] { propData.IntegerValue.Value }; + } + + //if there are INT ids, convert them to values based on the configuration + if (ids == null || ids.Length <= 0) return false; + + //map the ids to values + var values = new List(); + var canConvert = true; + + foreach (var id in ids) + { + var val = config.Items.FirstOrDefault(x => x.Id == id); + if (val != null) + values.Add(val.Value); + else + { + Logger.Warn( + "Could not find associated data type configuration for stored Id {DataTypeId}", id); + canConvert = false; + } + } + + if (!canConvert) return false; + + propData.VarcharValue = JsonConvert.SerializeObject(values); + propData.TextValue = null; + propData.IntegerValue = null; + return true; + } + + private class ValueListConfigurationEditor : ConfigurationEditor + { + } + + private int[] ConvertStringValues(string val) + { + var splitVals = JsonConvert.DeserializeObject(val); + + var intVals = splitVals + .Select(x => int.TryParse(x, out var i) ? i : int.MinValue) + .Where(x => x != int.MinValue) + .ToArray(); + + //only return if the number of values are the same (i.e. All INTs) + if (splitVals.Length == intVals.Length) + return intVals; + + return null; + } + } +} diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs index 2c4e601a9e..e032cdea43 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 var dataTypes = Database.Fetch(Sql() .Select() .From() - .Where(x => x.EditorAlias == "Umbraco.RadioButtonList")); + .Where(x => x.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.RadioButtonList))); var refreshCache = false; foreach (var dataType in dataTypes) @@ -123,7 +123,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 if (!canConvert) return false; - propData.VarcharValue = string.Join(",", values); + propData.VarcharValue = values.FirstOrDefault() ?? string.Empty; propData.TextValue = null; propData.IntegerValue = null; return true; @@ -135,7 +135,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 private int[] ConvertStringValues(string val) { - var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var splitVals = new []{ val.Trim() }; var intVals = splitVals .Select(x => int.TryParse(x, out var i) ? i : int.MinValue) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs index 4062ed7311..3d69c37b8b 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.PropertyEditors.ValueConverters @@ -8,8 +9,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters [DefaultPropertyValueConverter] public class CheckboxListValueConverter : PropertyValueConverterBase { - private static readonly char[] Comma = { ',' }; - public override bool IsConverter(PublishedPropertyType propertyType) => propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.CheckBoxList); @@ -26,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters if (string.IsNullOrEmpty(sourceString)) return Enumerable.Empty(); - return sourceString.Split(Comma, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()); + return JsonConvert.DeserializeObject(sourceString); } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 72dbb03a9b..da6c4a672c 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -370,6 +370,7 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js index 9ef1b69aad..0699658711 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js @@ -54,7 +54,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro $scope.selectedItems = []; for (var i = 0; i < configItems.length; i++) { - var isChecked = _.contains($scope.model.value, configItems[i].id); + var isChecked = _.contains($scope.model.value, configItems[i].value); $scope.selectedItems.push({ checked: isChecked, key: configItems[i].id, @@ -68,11 +68,11 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro function (v) { return v === item.key; }); - + if (item.checked) { //if it doesn't exist in the model, then add it if (index < 0) { - $scope.model.value.push(item.key); + $scope.model.value.push(item.val); } } else { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html index 29760e3f5b..f777dc4797 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html @@ -6,7 +6,7 @@ {{item.val}} diff --git a/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs b/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs index 8e0737dedd..13b060cf3d 100644 --- a/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs @@ -1,12 +1,11 @@ using System; using System.Linq; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Web.Composing; namespace Umbraco.Web.PropertyEditors { @@ -36,8 +35,8 @@ namespace Umbraco.Web.PropertyEditors /// public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) { - var delimited = base.ToEditor(property, dataTypeService, culture, segment).ToString(); - return delimited.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var json = base.ToEditor(property, dataTypeService, culture, segment).ToString(); + return JsonConvert.DeserializeObject(json) ?? Array.Empty(); } /// @@ -55,9 +54,9 @@ namespace Umbraco.Web.PropertyEditors return null; } - var values = json.Select(item => item.Value()).ToList(); - //change to delimited - return string.Join(",", values); + var values = json.Select(item => item.Value()).ToArray(); + + return JsonConvert.SerializeObject(values); } } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/FlexibleDropdownPropertyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/FlexibleDropdownPropertyValueConverter.cs index d470f54662..43add34327 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/FlexibleDropdownPropertyValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/FlexibleDropdownPropertyValueConverter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -17,8 +18,10 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) { - return source?.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim()).ToArray() - ?? Enumerable.Empty(); + if(source == null) return Array.Empty(); + + + return JsonConvert.DeserializeObject(source.ToString()) ?? Array.Empty(); } public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) From a892ae1567284e800e89fd87d88e49943ef85386 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 11 Feb 2019 11:35:21 +0100 Subject: [PATCH 25/54] Add missing index on UserLogin table (prevents deadlocks) --- src/Umbraco.Core/Migrations/MigrationBase_Extra.cs | 6 ++++++ src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs | 2 +- src/Umbraco.Core/Persistence/Dtos/UserLoginDto.cs | 7 +++++-- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs index 6d936e8407..bf07e4d08f 100644 --- a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs +++ b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs @@ -96,6 +96,12 @@ namespace Umbraco.Core.Migrations return tables.Any(x => x.InvariantEquals(tableName)); } + protected bool IndexExists(string indexName) + { + var indexes = SqlSyntax.GetDefinedIndexes(Context.Database); + return indexes.Any(x => x.Item2.InvariantEquals(indexName)); + } + protected bool ColumnExists(string tableName, string columnName) { var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray(); diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index a9444a0918..cfa82748d2 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -127,7 +127,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}"); To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); - + To("98339BEF-E4B2-48A8-B9D1-D173DC842BBE"); //FINAL diff --git a/src/Umbraco.Core/Persistence/Dtos/UserLoginDto.cs b/src/Umbraco.Core/Persistence/Dtos/UserLoginDto.cs index e03efa8fe9..d7d02631b7 100644 --- a/src/Umbraco.Core/Persistence/Dtos/UserLoginDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/UserLoginDto.cs @@ -30,11 +30,14 @@ namespace Umbraco.Core.Persistence.Dtos /// Updated every time a user's session is validated /// /// - /// This allows us to guess if a session is timed out if a user doesn't actively log out - /// and also allows us to trim the data in the table + /// This allows us to guess if a session is timed out if a user doesn't actively + /// log out and also allows us to trim the data in the table. + /// The index is IMPORTANT as it prevents deadlocks during deletion of + /// old sessions (DELETE ... WHERE lastValidatedUtc < date). /// [Column("lastValidatedUtc")] [NullSetting(NullSetting = NullSettings.NotNull)] + [Index(IndexTypes.NonClustered, Name = "IX_userLoginDto_lastValidatedUtc")] public DateTime LastValidatedUtc { get; set; } /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b80d607d4f..f5bdc417bd 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -367,6 +367,7 @@ + From e08a7c3ea8530ad59ea69e5893509ef7c7065cf3 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 11 Feb 2019 11:54:51 +0100 Subject: [PATCH 26/54] Need to clone the object before removing $-prefixed variables. Otherwise we are modifying the same data as the views are using --- .../donotpostdollarvariablesrequest.interceptor.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js index eabb611320..03373089d7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js +++ b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js @@ -26,7 +26,9 @@ //dealing with requests: 'request': function(config) { if(config.method === "POST"){ - transform(config.data); + var clone = angular.copy(config); + transform(clone.data); + return clone; } return config; From 0bdd1131bb4173b2df859fa88cad653b76dd4b6f Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 11 Feb 2019 11:57:13 +0100 Subject: [PATCH 27/54] Add missing file --- .../V_8_0_0/AddUserLoginDtoDateIndex.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs new file mode 100644 index 0000000000..0ccc2d93ff --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs @@ -0,0 +1,22 @@ +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class AddUserLoginDtoDateIndex : MigrationBase + { + public AddUserLoginDtoDateIndex(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + if (!IndexExists("IX_umbracoUserLogin_lastValidatedUtc")) + Create.Index("IX_umbracoUserLogin_lastValidatedUtc") + .OnTable(UserLoginDto.TableName) + .OnColumn("lastValidatedUtc") + .Ascending() + .WithOptions().NonClustered() + .Do(); + } + } +} From 5342e65f7c0597aed0c0b2933305d2a0b96d1290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 11 Feb 2019 12:46:23 +0100 Subject: [PATCH 28/54] V8: update selection colors for users section --- .../subheader/umb-editor-sub-header.less | 7 ++ .../less/components/users/umb-user-cards.less | 44 ++++++++----- .../src/less/tables.less | 9 +++ .../src/views/member/edit.html | 9 +-- .../propertyeditors/listview/listview.html | 14 ++-- .../src/views/users/user.html | 5 +- .../src/views/users/views/groups/groups.html | 29 +++++---- .../users/views/users/users.controller.js | 18 ++---- .../src/views/users/views/users/users.html | 64 +++++++++---------- 9 files changed, 112 insertions(+), 87 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less index 2b9f1e31a5..1aadb1c39b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less @@ -15,6 +15,13 @@ } } +.umb-editor-sub-header.--state-selection { + padding-left: 10px; + padding-right: 10px; + background-color: @pinkLight; + border-radius: 3px; +} + .umb-editor-sub-header.-umb-sticky-bar { box-shadow: 0 6px 3px -3px rgba(0,0,0,.16); transition: box-shadow 1s; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-cards.less b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-cards.less index de2dca5f91..e24f68078b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-cards.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-cards.less @@ -8,6 +8,8 @@ box-sizing: border-box; max-width: 100%; display: flex; + position: relative; + user-select: none; } .umb-user-card:hover, @@ -15,6 +17,22 @@ outline: none; text-decoration: none !important; } +.umb-user-card.-selected { + &::before { + content: ""; + position: absolute; + z-index:2; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: 2px solid @ui-selected-border; + border-radius: 5px; + box-shadow: 0 0 4px 0 darken(@ui-selected-border, 20), inset 0 0 2px 0 darken(@ui-selected-border, 20); + pointer-events: none; + } + +} .umb-user-card__content { position: relative; @@ -30,9 +48,12 @@ max-width: 100%; } -.umb-user-card__content:hover, -.umb-user-card:focus .umb-user-card__content { - border-color: @turquoise; +.umb-user-card__goToUser { + &:hover { + .umb-user-card__name { + text-decoration: underline; + } + } } .umb-user-card__avatar { @@ -47,24 +68,13 @@ left: 10px; } + .umb-user-card__name { font-size: 15px; font-weight: bold; text-align: center; margin-bottom: 2px; - word-wrap: break-word; -} - -.umb-user-card__checkmark { - position: absolute; - top: 10px; - right: 10px; - display: none; -} - -.umb-user-card:hover .umb-user-card__checkmark, -.umb-user-card__checkmark--visible { - display: block; + word-wrap: break-word; } .umb-user-card__group { @@ -77,4 +87,4 @@ font-size: 13px; text-align: center; margin-top: auto; -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/less/tables.less b/src/Umbraco.Web.UI.Client/src/less/tables.less index fa8a44ec47..09b6ea8a42 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tables.less +++ b/src/Umbraco.Web.UI.Client/src/less/tables.less @@ -62,6 +62,15 @@ table { } +.table tr > td:first-child { + border-left: 4px solid transparent; +} +.table tr.--selected > td:first-child { + border-left-color:@ui-selected-border; +} + + + // CONDENSED TABLE W/ HALF PADDING // ------------------------------- diff --git a/src/Umbraco.Web.UI.Client/src/views/member/edit.html b/src/Umbraco.Web.UI.Client/src/views/member/edit.html index 310559b4d4..ee6e9c625c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/member/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/member/edit.html @@ -24,13 +24,13 @@
    {{ group.label }}
     
    - +
    - + @@ -38,8 +38,8 @@ - @@ -51,6 +51,7 @@ ng-if="page.listViewPath" type="link" href="#{{page.listViewPath}}" + button-style="link" label="Return to list" label-key="buttons_returnToList"> diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 9a638d91fa..2c70ba5730 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -6,7 +6,7 @@
    - + @@ -85,7 +85,7 @@ type="button" label="Clear selection" label-key="buttons_clearSelection" - button-style="selection" + button-style="white" action="clearSelection()" disabled="actionInProgress"> @@ -140,7 +140,7 @@ ng-if="options.allowBulkPublish && (buttonPermissions == null || buttonPermissions.canPublish)" style="margin-right: 5px;" type="button" - button-style="selection" + button-style="white" label-key="actions_publish" icon="icon-globe" action="publish()" @@ -153,7 +153,7 @@ ng-if="options.allowBulkUnpublish && (buttonPermissions == null || buttonPermissions.canUnpublish)" style="margin-right: 5px;" type="button" - button-style="selection" + button-style="white" label-key="actions_unpublish" icon="icon-block" action="unpublish()" @@ -166,7 +166,7 @@ ng-if="options.allowBulkCopy && (buttonPermissions == null || buttonPermissions.canCopy)" style="margin-right: 5px;" type="button" - button-style="selection" + button-style="white" label-key="actions_copy" icon="icon-documents" action="copy()" @@ -179,7 +179,7 @@ ng-if="options.allowBulkMove && (buttonPermissions == null || buttonPermissions.canMove)" style="margin-right: 5px;" type="button" - button-style="selection" + button-style="white" label-key="actions_move" icon="icon-enter" action="move()" @@ -191,7 +191,7 @@ - + - +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html index deee402fd5..863d9658ae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/groups/groups.html @@ -2,13 +2,13 @@ - - + + @@ -40,6 +40,7 @@ @@ -54,6 +55,7 @@ type="button" label="Delete" label-key="general_delete" + button-style="white" icon="icon-trash" action="vm.deleteUserGroups()" size="xs"> @@ -64,7 +66,7 @@
    - Groups ({{vm.userGroups.length}}) + Groups ({{vm.userGroups.length}})
    @@ -76,19 +78,20 @@ - - - + + + + ng-click="vm.selectUserGroup(group, vm.selection, $event)" + style="width: 20px; height: 100px;"/> - -
    \ No newline at end of file +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index 92ed10267d..6e624bfbe3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -199,14 +199,14 @@ vm.activeLayout = selectedLayout; } - function selectUser(user, selection, event) { + function selectUser(user, event) { - // prevent the current user to be selected - if (!user.isCurrentUser) { + // prevent the current user to be selected, why? + //if (!user.isCurrentUser) { if (user.selected) { - var index = selection.indexOf(user.id); - selection.splice(index, 1); + var index = vm.selection.indexOf(user.id); + vm.selection.splice(index, 1); user.selected = false; } else { user.selected = true; @@ -219,7 +219,7 @@ event.preventDefault(); event.stopPropagation(); } - } + //} } function clearSelection() { @@ -230,11 +230,7 @@ } function clickUser(user) { - if (vm.selection.length > 0) { - selectUser(user, vm.selection); - } else { - goToUser(user.id); - } + goToUser(user.id); } function disableUsers() { diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index 4b6f77e696..c270e823e6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -5,7 +5,7 @@ - + @@ -49,7 +49,7 @@ @@ -58,16 +58,16 @@ {{ vm.selection.length }} of {{ vm.users.length }} selected - + @@ -78,19 +78,19 @@ ng-if="vm.allowEnableUser" type="button" size="xs" - button-style="outline" + button-style="white" state="vm.enableUserButtonState" label-key="actions_enable" icon="icon-check" action="vm.enableUsers()"> - +
    - Status: + Status: {{ vm.getFilterName(vm.userStatesFilter) }} @@ -168,7 +168,7 @@
    - Order by: + Order by: {{ vm.getSortLabel(vm.usersOptions.orderBy, vm.usersOptions.orderDirection) }} @@ -192,20 +192,18 @@ @@ -332,7 +330,7 @@ Required {{addUserForm.name.errorMsg}} - + @@ -342,7 +340,7 @@ Required {{addUserForm.username.errorMsg}} - + @@ -356,7 +354,7 @@ - +
    - + Back to users - +
    - +

    - +
    @@ -511,7 +509,7 @@ - +
    Date: Mon, 11 Feb 2019 13:27:50 +0100 Subject: [PATCH 29/54] v8: Fix users layout switcher (#4458) * Localize edit link, remove duplicate class attributes and only make remove link red * Revert "Localize edit link, remove duplicate class attributes and only make remove link red" This reverts commit 63cc250c0f929b1f7e6f9f05fae2fd302682d418. * Use built-in $id function for tracky by since users doesn't have name property * Set active layout to card layout * Update onLayoutSelect * Format document --- .../components/umblayoutselector.directive.js | 2 +- .../views/components/umb-layout-selector.html | 2 +- .../users/views/users/users.controller.js | 9 +++------ .../src/views/users/views/users/users.html | 19 +++++++++---------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umblayoutselector.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblayoutselector.directive.js index 87cd84ca40..58a5e1be0e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umblayoutselector.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblayoutselector.directive.js @@ -10,7 +10,7 @@ bindings: { layouts: '<', activeLayout: '<', - onLayoutSelect: "&" + onLayoutSelect: '&' } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-layout-selector.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-layout-selector.html index 21840cb1d1..c84e63a359 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-layout-selector.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-layout-selector.html @@ -8,7 +8,7 @@ class="umb-layout-selector__dropdown shadow-depth-3 animated -half-second fadeIn" on-outside-click="vm.closeLayoutDropdown()"> -
    + on-layout-select="vm.selectLayout(layout)"> @@ -229,7 +228,7 @@
    - +
    - + - - +
    From 64f41541fe399419f1650c5178d0ca2005767c78 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 11 Feb 2019 13:33:52 +0100 Subject: [PATCH 30/54] Fix the tree item state annotations (#4497) --- .../src/less/components/tree/umb-tree.less | 35 +++++++++---------- .../views/components/tree/umb-tree-item.html | 7 ++-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less index 698a4211f5..eaa26b5d1a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less @@ -232,43 +232,40 @@ body.touch .umb-tree { } } -.protected, -.has-unpublished-version, -.is-container, -.locked { +.umb-tree-item__annotation { &::before { font-family: 'icomoon'; position: absolute; - font-size: 20px; - padding-left: 7px; - padding-top: 7px; bottom: 0; } } -.protected::before { - content: "\e256"; - color: @red; -} - -.has-unpublished-version::before { +.has-unpublished-version > .umb-tree-item__inner > .umb-tree-item__annotation::before { content: "\e25a"; color: @green; + font-size: 20px; + margin-left: -25px; } -.is-container::before { +.is-container > .umb-tree-item__inner > .umb-tree-item__annotation::before { content: "\e04e"; color: @blue; - font-size: 8px; - padding-left: 13px; - padding-top: 8px; - pointer-events: none; + font-size: 9px; + margin-left: -20px; } +.protected > .umb-tree-item__inner > .umb-tree-item__annotation::before { + content: "\e256"; + color: @red; + font-size: 20px; + margin-left: -25px; +} -.locked::before { +.locked > .umb-tree-item__inner > .umb-tree-item__annotation::before { content: "\e0a7"; color: @red; + font-size: 9px; + margin-left: -20px; } .no-access { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tree/umb-tree-item.html b/src/Umbraco.Web.UI.Client/src/views/components/tree/umb-tree-item.html index 9474e98350..b11b656c8e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/tree/umb-tree-item.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/tree/umb-tree-item.html @@ -1,11 +1,12 @@
  •   + ng-class="{'icon-navigation-right': !node.expanded || node.metaData.isContainer, 'icon-navigation-down': node.expanded && !node.metaData.isContainer}" + ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}" + ng-click="load(node)">  + {{node.name}} From 154b59c84b9f365391e381405b6dcc0da3031d9d Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 11 Feb 2019 14:09:40 +0100 Subject: [PATCH 31/54] Fix redirect tracking --- .../Routing/RedirectTrackingComponent.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs index c49dffd6e4..acbd022f2e 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs @@ -38,16 +38,24 @@ namespace Umbraco.Web.Routing { get { - var oldRoutes = - (Dictionary) UmbracoContext.Current.HttpContext.Items[ - ContextKey3]; + var oldRoutes = (Dictionary) UmbracoContext.Current.HttpContext.Items[ContextKey3]; if (oldRoutes == null) - UmbracoContext.Current.HttpContext.Items[ContextKey3] = - oldRoutes = new Dictionary(); + UmbracoContext.Current.HttpContext.Items[ContextKey3] = oldRoutes = new Dictionary(); return oldRoutes; } } + private static bool HasOldRoutes + { + get + { + if (Current.UmbracoContext == null) return false; + if (Current.UmbracoContext.HttpContext == null) return false; + if (Current.UmbracoContext.HttpContext.Items[ContextKey3] == null) return false; + return true; + } + } + private static bool LockedEvents { get => Moving && UmbracoContext.Current.HttpContext.Items[ContextKey2] != null; @@ -97,8 +105,8 @@ namespace Umbraco.Web.Routing ContentService.Published += ContentService_Published; ContentService.Moving += ContentService_Moving; ContentService.Moved += ContentService_Moved; - ContentCacheRefresher.CacheUpdated += ContentCacheRefresher_CacheUpdated; + ContentCacheRefresher.CacheUpdated += ContentCacheRefresher_CacheUpdated; // kill all redirects once a content is deleted //ContentService.Deleted += ContentService_Deleted; @@ -111,21 +119,26 @@ namespace Umbraco.Web.Routing public void Terminate() { } - private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender, - CacheRefresherEventArgs args) + private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) { + // that event is a distributed even that triggers on all nodes + // BUT it should totally NOT run on nodes other that the one that handled the other events + // and besides, it cannot run on a background thread! + if (!HasOldRoutes) + return; + // sanity checks if (args.MessageType != MessageType.RefreshByPayload) { throw new InvalidOperationException("ContentCacheRefresher MessageType should be ByPayload."); } + if (args.MessageObject == null) { return; } - var payloads = args.MessageObject as ContentCacheRefresher.JsonPayload[]; - if (payloads == null) + if (!(args.MessageObject is ContentCacheRefresher.JsonPayload[])) { throw new InvalidOperationException("ContentCacheRefresher MessageObject should be JsonPayload[]."); } @@ -137,8 +150,7 @@ namespace Umbraco.Web.Routing { // assuming we cannot have 'CacheUpdated' for only part of the infos else we'd need // to set a flag in 'Published' to indicate which entities have been refreshed ok - CreateRedirect(oldRoute.Key.ContentId, oldRoute.Key.Culture, oldRoute.Value.ContentKey, - oldRoute.Value.OldRoute); + CreateRedirect(oldRoute.Key.ContentId, oldRoute.Key.Culture, oldRoute.Value.ContentKey, oldRoute.Value.OldRoute); removeKeys.Add(oldRoute.Key); } From e4a492dc572f16a41a80c4fb1702cfd9b8277168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 11 Feb 2019 14:30:01 +0100 Subject: [PATCH 32/54] Disable button dont hide them + dont select current user --- .../users/views/users/users.controller.js | 67 +++++++++---------- .../src/views/users/views/users/users.html | 21 +++--- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index 6862ffa1f6..c0e59be8e4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -196,27 +196,23 @@ vm.activeLayout = selectedLayout; } - function selectUser(user, event) { - - // prevent the current user to be selected, why? - //if (!user.isCurrentUser) { - - if (user.selected) { - var index = vm.selection.indexOf(user.id); - vm.selection.splice(index, 1); - user.selected = false; - } else { - user.selected = true; - vm.selection.push(user.id); - } - - setBulkActions(vm.users); - - if (event) { - event.preventDefault(); - event.stopPropagation(); - } - //} + function selectUser(user) { + + if (user.isCurrentUser) { + return; + } + + if (user.selected) { + var index = vm.selection.indexOf(user.id); + vm.selection.splice(index, 1); + user.selected = false; + } else { + user.selected = true; + vm.selection.push(user.id); + } + + setBulkActions(vm.users); + } function clearSelection() { @@ -621,18 +617,20 @@ var firstSelectedUserGroups; angular.forEach(users, function (user) { - + if (!user.selected) { return; } - + + console.log("CHECK") // if the current user is selected prevent any bulk actions with the user included if (user.isCurrentUser) { vm.allowDisableUser = false; vm.allowEnableUser = false; vm.allowUnlockUser = false; vm.allowSetUserGroup = false; - return; + console.log("IS CURRENT!") + return false; } if (user.userDisplayState && user.userDisplayState.key === "Disabled") { @@ -656,16 +654,17 @@ } // store the user group aliases of the first selected user - if (!firstSelectedUserGroups) { - firstSelectedUserGroups = user.userGroups.map(function (ug) { return ug.alias; }); - vm.allowSetUserGroup = true; - } else if (vm.allowSetUserGroup === true) { - // for 2nd+ selected user, compare the user group aliases to determine if we should allow bulk editing. - // we don't allow bulk editing of users not currently having the same assigned user groups, as we can't - // really support that in the user group picker. - var userGroups = user.userGroups.map(function (ug) { return ug.alias; }); - if (_.difference(firstSelectedUserGroups, userGroups).length > 0) { - vm.allowSetUserGroup = false; + if (vm.allowSetUserGroup === true) { + if (!firstSelectedUserGroups) { + firstSelectedUserGroups = user.userGroups.map(function (ug) { return ug.alias; }); + } else { + // for 2nd+ selected user, compare the user group aliases to determine if we should allow bulk editing. + // we don't allow bulk editing of users not currently having the same assigned user groups, as we can't + // really support that in the user group picker. + var userGroups = user.userGroups.map(function (ug) { return ug.alias; }); + if (_.difference(firstSelectedUserGroups, userGroups).length > 0) { + vm.allowSetUserGroup = false; + } } } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index b0a64fa6c0..cefc3c5c86 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -63,7 +63,7 @@
  • -
    +
    + {{user.name}}{{user.name}} {{ userGroup.name }}, {{ user.formattedLastLogin }} From 944c8d59d764cf99a255c7acdda57f5dab56c92e Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 11 Feb 2019 15:30:11 +0100 Subject: [PATCH 33/54] Need to clone the object before removing $-prefixed variables. Otherwise we are modifying the same data as the views are using --- src/Umbraco.Core/Constants-Applications.cs | 9 +- .../Migrations/Install/DatabaseDataCreator.cs | 4 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 + .../dashboard/dashboard.tabs.controller.js | 99 ------------------- .../dashboard/forms/formsdashboardintro.html | 8 -- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + .../Umbraco/config/lang/en_us.xml | 3 +- src/Umbraco.Web/Dashboards/FormsDashboard.cs | 3 +- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 1 + .../Trees/FormsBackOfficeSection.cs | 14 +++ src/Umbraco.Web/Trees/FormsTreeController.cs | 27 +++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + 12 files changed, 57 insertions(+), 115 deletions(-) create mode 100644 src/Umbraco.Web/Trees/FormsBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/FormsTreeController.cs diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs index 2d4042fad0..e66df3a5f9 100644 --- a/src/Umbraco.Core/Constants-Applications.cs +++ b/src/Umbraco.Core/Constants-Applications.cs @@ -45,7 +45,7 @@ /// /// Application alias for the forms section. /// - public const string Forms = "forms"; + public const string FormsInstaller = "formsInstaller"; } /// @@ -77,7 +77,7 @@ /// alias for the macro tree. /// public const string Macros = "macros"; - + /// /// alias for the datatype tree. /// @@ -92,7 +92,7 @@ /// alias for the dictionary tree. /// public const string Dictionary = "dictionary"; - + public const string Stylesheets = "stylesheets"; /// @@ -121,7 +121,7 @@ public const string Templates = "templates"; public const string RelationTypes = "relationTypes"; - + public const string Languages = "languages"; /// @@ -138,6 +138,7 @@ /// alias for the users tree. /// public const string Users = "users"; + public const string Forms = "formsInstaller"; public const string Scripts = "scripts"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 7f7229ccd6..055b899231 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -189,13 +189,13 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Members }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Settings }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Users }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Forms }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.FormsInstaller }); _database.Insert(new UserGroup2AppDto { UserGroupId = 2, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Media }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Forms }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.FormsInstaller }); _database.Insert(new UserGroup2AppDto { UserGroupId = 4, AppAlias = Constants.Applications.Translation }); } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index c404e0404d..a868245940 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -228,6 +228,7 @@ namespace Umbraco.Tests.Testing .Append() .Append() .Append() + .Append() .Append(); Composition.RegisterUnique(); diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index ed3d6ded33..e801e2cc58 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -192,7 +192,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization function Video_player (videoId) { // Get dom elements this.container = document.getElementById(videoId); - this.video = this.container.getElementsByTagName('video')[0]; //Create controls this.controls = document.createElement('div'); @@ -215,104 +214,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization this.controls.appendChild(this.loader); this.loader.appendChild(this.progress_bar); } - - - Video_player.prototype - .seeking = function() { - // get the value of the seekbar (hidden input[type="range"]) - var time = this.video.duration * (this.seek_bar.value / 100); - - // Update video to seekbar value - this.video.currentTime = time; - }; - - // Stop video when user initiates seeking - Video_player.prototype - .start_seek = function() { - this.video.pause(); - }; - - // Start video when user stops seeking - Video_player.prototype - .stop_seek = function() { - this.video.play(); - }; - - // Update the progressbar (span.loader) according to video.currentTime - Video_player.prototype - .update_progress_bar = function() { - // Get video progress in % - var value = (100 / this.video.duration) * this.video.currentTime; - - // Update progressbar - this.progress_bar.style.width = value + '%'; - }; - - // Bind progressbar to mouse when seeking - Video_player.prototype - .handle_mouse_move = function(event) { - // Get position of progressbar relative to browser window - var pos = this.progress_bar.getBoundingClientRect().left; - - // Make sure event is reckonized cross-browser - event = event || window.event; - - // Update progressbar - this.progress_bar.style.width = (event.clientX - pos) + "px"; - }; - - // Eventlisteners for seeking - Video_player.prototype - .video_event_handler = function(videoPlayer, interval) { - // Update the progress bar - var animate_progress_bar = setInterval(function () { - videoPlayer.update_progress_bar(); - }, interval); - - // Fire when input value changes (user seeking) - videoPlayer.seek_bar - .addEventListener("change", function() { - videoPlayer.seeking(); - }); - - // Fire when user clicks on seekbar - videoPlayer.seek_bar - .addEventListener("mousedown", function (clickEvent) { - // Pause video playback - videoPlayer.start_seek(); - - // Stop updating progressbar according to video progress - clearInterval(animate_progress_bar); - - // Update progressbar to where user clicks - videoPlayer.handle_mouse_move(clickEvent); - - // Bind progressbar to cursor - window.onmousemove = function(moveEvent){ - videoPlayer.handle_mouse_move(moveEvent); - }; - }); - - // Fire when user releases seekbar - videoPlayer.seek_bar - .addEventListener("mouseup", function () { - - // Unbind progressbar from cursor - window.onmousemove = null; - - // Start video playback - videoPlayer.stop_seek(); - - // Animate the progressbar - animate_progress_bar = setInterval(function () { - videoPlayer.update_progress_bar(); - }, interval); - }); - }; - - - var videoPlayer = new Video_player('video_1'); - videoPlayer.video_event_handler(videoPlayer, 17); } angular.module("umbraco").controller("Umbraco.Dashboard.FormsDashboardController", FormsController); diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html index 3b382367c4..c18e7f4ccf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html @@ -8,14 +8,6 @@
    -
    - -
    -

    Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it!

    Courier Developer Forms + Forms Help Umbraco Configuration Wizard Media 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 852abcd5d8..b9aa3b6ece 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1247,6 +1247,7 @@ To manage your website, simply open the Umbraco back office and start adding con Content Forms + Forms Media Members Packages @@ -1388,7 +1389,7 @@ To manage your website, simply open the Umbraco back office and start adding con Styles The CSS that should be applied in the rich text editor, e.g. "color:red;" Code - Rich Text Editor + Rich Text Editor Failed to delete template with ID %0% diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs index a3e1123369..bb21a04fdc 100644 --- a/src/Umbraco.Web/Dashboards/FormsDashboard.cs +++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Dashboards; @@ -9,7 +10,7 @@ namespace Umbraco.Web.Dashboards { public string Alias => "formsInstall"; - public string[] Sections => new [] { "forms" }; + public string[] Sections => new [] { Constants.Applications.FormsInstaller }; public string View => "views/dashboard/forms/formsdashboardintro.html"; diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 3afe6aa397..52373184b4 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -220,6 +220,7 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append() + .Append() .Append(); // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards diff --git a/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs new file mode 100644 index 0000000000..681fe61993 --- /dev/null +++ b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs @@ -0,0 +1,14 @@ +using Umbraco.Core; +using Umbraco.Core.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office media section + /// + public class FormsBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.FormsInstaller; + public string Name => "Forms"; + } +} diff --git a/src/Umbraco.Web/Trees/FormsTreeController.cs b/src/Umbraco.Web/Trees/FormsTreeController.cs new file mode 100644 index 0000000000..2c6885cf97 --- /dev/null +++ b/src/Umbraco.Web/Trees/FormsTreeController.cs @@ -0,0 +1,27 @@ +using System.Net.Http.Formatting; +using Umbraco.Web.Models.Trees; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Trees +{ + [UmbracoTreeAuthorize(Constants.Trees.Forms)] + [Tree(Constants.Applications.FormsInstaller, Constants.Trees.Forms, SortOrder = 0, IsSingleNodeTree = true)] + [PluginController("UmbracoTrees")] + [CoreTree] + public class FormsTreeController : TreeController + { + protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) + { + //full screen app without tree nodes + return TreeNodeCollection.Empty; + } + + protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) + { + //doesn't have a menu, this is a full screen app without tree nodes + return MenuItemCollection.Empty; + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 8699540e4b..23ae727c35 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -214,6 +214,8 @@ + + From 60ca85fe25e4874adfff3bd853990481ef6139e5 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 11 Feb 2019 15:30:11 +0100 Subject: [PATCH 34/54] Introduced the forms section in the sections menu. --- src/Umbraco.Core/Constants-Applications.cs | 9 +- .../Migrations/Install/DatabaseDataCreator.cs | 4 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 + .../dashboard/dashboard.tabs.controller.js | 99 ------------------- .../dashboard/forms/formsdashboardintro.html | 8 -- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + .../Umbraco/config/lang/en_us.xml | 3 +- src/Umbraco.Web/Dashboards/FormsDashboard.cs | 3 +- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 1 + .../Trees/FormsBackOfficeSection.cs | 14 +++ src/Umbraco.Web/Trees/FormsTreeController.cs | 27 +++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + 12 files changed, 57 insertions(+), 115 deletions(-) create mode 100644 src/Umbraco.Web/Trees/FormsBackOfficeSection.cs create mode 100644 src/Umbraco.Web/Trees/FormsTreeController.cs diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs index 2d4042fad0..e66df3a5f9 100644 --- a/src/Umbraco.Core/Constants-Applications.cs +++ b/src/Umbraco.Core/Constants-Applications.cs @@ -45,7 +45,7 @@ /// /// Application alias for the forms section. /// - public const string Forms = "forms"; + public const string FormsInstaller = "formsInstaller"; } /// @@ -77,7 +77,7 @@ /// alias for the macro tree. /// public const string Macros = "macros"; - + /// /// alias for the datatype tree. /// @@ -92,7 +92,7 @@ /// alias for the dictionary tree. ///
    public const string Dictionary = "dictionary"; - + public const string Stylesheets = "stylesheets"; /// @@ -121,7 +121,7 @@ public const string Templates = "templates"; public const string RelationTypes = "relationTypes"; - + public const string Languages = "languages"; /// @@ -138,6 +138,7 @@ /// alias for the users tree. /// public const string Users = "users"; + public const string Forms = "formsInstaller"; public const string Scripts = "scripts"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 7f7229ccd6..055b899231 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -189,13 +189,13 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Members }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Settings }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Users }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Forms }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.FormsInstaller }); _database.Insert(new UserGroup2AppDto { UserGroupId = 2, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Media }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Forms }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.FormsInstaller }); _database.Insert(new UserGroup2AppDto { UserGroupId = 4, AppAlias = Constants.Applications.Translation }); } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index c404e0404d..a868245940 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -228,6 +228,7 @@ namespace Umbraco.Tests.Testing .Append() .Append() .Append() + .Append() .Append(); Composition.RegisterUnique(); diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index ed3d6ded33..e801e2cc58 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -192,7 +192,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization function Video_player (videoId) { // Get dom elements this.container = document.getElementById(videoId); - this.video = this.container.getElementsByTagName('video')[0]; //Create controls this.controls = document.createElement('div'); @@ -215,104 +214,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization this.controls.appendChild(this.loader); this.loader.appendChild(this.progress_bar); } - - - Video_player.prototype - .seeking = function() { - // get the value of the seekbar (hidden input[type="range"]) - var time = this.video.duration * (this.seek_bar.value / 100); - - // Update video to seekbar value - this.video.currentTime = time; - }; - - // Stop video when user initiates seeking - Video_player.prototype - .start_seek = function() { - this.video.pause(); - }; - - // Start video when user stops seeking - Video_player.prototype - .stop_seek = function() { - this.video.play(); - }; - - // Update the progressbar (span.loader) according to video.currentTime - Video_player.prototype - .update_progress_bar = function() { - // Get video progress in % - var value = (100 / this.video.duration) * this.video.currentTime; - - // Update progressbar - this.progress_bar.style.width = value + '%'; - }; - - // Bind progressbar to mouse when seeking - Video_player.prototype - .handle_mouse_move = function(event) { - // Get position of progressbar relative to browser window - var pos = this.progress_bar.getBoundingClientRect().left; - - // Make sure event is reckonized cross-browser - event = event || window.event; - - // Update progressbar - this.progress_bar.style.width = (event.clientX - pos) + "px"; - }; - - // Eventlisteners for seeking - Video_player.prototype - .video_event_handler = function(videoPlayer, interval) { - // Update the progress bar - var animate_progress_bar = setInterval(function () { - videoPlayer.update_progress_bar(); - }, interval); - - // Fire when input value changes (user seeking) - videoPlayer.seek_bar - .addEventListener("change", function() { - videoPlayer.seeking(); - }); - - // Fire when user clicks on seekbar - videoPlayer.seek_bar - .addEventListener("mousedown", function (clickEvent) { - // Pause video playback - videoPlayer.start_seek(); - - // Stop updating progressbar according to video progress - clearInterval(animate_progress_bar); - - // Update progressbar to where user clicks - videoPlayer.handle_mouse_move(clickEvent); - - // Bind progressbar to cursor - window.onmousemove = function(moveEvent){ - videoPlayer.handle_mouse_move(moveEvent); - }; - }); - - // Fire when user releases seekbar - videoPlayer.seek_bar - .addEventListener("mouseup", function () { - - // Unbind progressbar from cursor - window.onmousemove = null; - - // Start video playback - videoPlayer.stop_seek(); - - // Animate the progressbar - animate_progress_bar = setInterval(function () { - videoPlayer.update_progress_bar(); - }, interval); - }); - }; - - - var videoPlayer = new Video_player('video_1'); - videoPlayer.video_event_handler(videoPlayer, 17); } angular.module("umbraco").controller("Umbraco.Dashboard.FormsDashboardController", FormsController); diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html index 3b382367c4..c18e7f4ccf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html @@ -8,14 +8,6 @@
    -
    - -
    -

    Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it!

    Courier Developer Forms + Forms Help Umbraco Configuration Wizard Media 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 852abcd5d8..b9aa3b6ece 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1247,6 +1247,7 @@ To manage your website, simply open the Umbraco back office and start adding con Content Forms + Forms Media Members Packages @@ -1388,7 +1389,7 @@ To manage your website, simply open the Umbraco back office and start adding con Styles The CSS that should be applied in the rich text editor, e.g. "color:red;" Code - Rich Text Editor + Rich Text Editor Failed to delete template with ID %0% diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs index a3e1123369..bb21a04fdc 100644 --- a/src/Umbraco.Web/Dashboards/FormsDashboard.cs +++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Dashboards; @@ -9,7 +10,7 @@ namespace Umbraco.Web.Dashboards { public string Alias => "formsInstall"; - public string[] Sections => new [] { "forms" }; + public string[] Sections => new [] { Constants.Applications.FormsInstaller }; public string View => "views/dashboard/forms/formsdashboardintro.html"; diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 3afe6aa397..52373184b4 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -220,6 +220,7 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append() + .Append() .Append(); // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards diff --git a/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs new file mode 100644 index 0000000000..681fe61993 --- /dev/null +++ b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs @@ -0,0 +1,14 @@ +using Umbraco.Core; +using Umbraco.Core.Models.Trees; + +namespace Umbraco.Web.Trees +{ + /// + /// Defines the back office media section + /// + public class FormsBackOfficeSection : IBackOfficeSection + { + public string Alias => Constants.Applications.FormsInstaller; + public string Name => "Forms"; + } +} diff --git a/src/Umbraco.Web/Trees/FormsTreeController.cs b/src/Umbraco.Web/Trees/FormsTreeController.cs new file mode 100644 index 0000000000..2c6885cf97 --- /dev/null +++ b/src/Umbraco.Web/Trees/FormsTreeController.cs @@ -0,0 +1,27 @@ +using System.Net.Http.Formatting; +using Umbraco.Web.Models.Trees; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Trees +{ + [UmbracoTreeAuthorize(Constants.Trees.Forms)] + [Tree(Constants.Applications.FormsInstaller, Constants.Trees.Forms, SortOrder = 0, IsSingleNodeTree = true)] + [PluginController("UmbracoTrees")] + [CoreTree] + public class FormsTreeController : TreeController + { + protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) + { + //full screen app without tree nodes + return TreeNodeCollection.Empty; + } + + protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) + { + //doesn't have a menu, this is a full screen app without tree nodes + return MenuItemCollection.Empty; + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 8699540e4b..23ae727c35 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -214,6 +214,8 @@ + + From 0d963d3c4d2fa68db21c1234e6dc6dbff74edaca Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 01:58:42 +1100 Subject: [PATCH 35/54] Fixing package installation for content templates --- .../Packaging/PackageDataInstallation.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index a569954629..064e6cc959 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -294,8 +294,21 @@ namespace Umbraco.Core.Packaging where property.Attribute("isDoc") == null select property; + //TODO: This will almost never work, we can't reference a template by an INT Id within a package manifest, we need to change the + // packager to package templates by UDI and resolve by the same, in 98% of cases, this isn't going to work, or it will resolve the wrong template. var template = templateId.HasValue ? _fileService.GetTemplate(templateId.Value) : null; + //now double check this is correct since its an INT it could very well be pointing to an invalid template :/ + if (template != null) + { + if (!contentType.IsAllowedTemplate(template.Alias)) + { + //well this is awkward, we'll set the template to null and it will be wired up to the default template + // when it's persisted in the document repository + template = null; + } + } + IContent content = parent == null ? new Content(nodeName, parentId, contentType) { @@ -312,6 +325,8 @@ namespace Umbraco.Core.Packaging Key = key }; + var propTypes = contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x); + foreach (var property in properties) { string propertyTypeAlias = property.Name.LocalName; @@ -319,10 +334,11 @@ namespace Umbraco.Core.Packaging { var propertyValue = property.Value; - var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias); - - //set property value - content.SetValue(propertyTypeAlias, propertyValue); + if (propTypes.TryGetValue(propertyTypeAlias, out var propertyType)) + { + //set property value + content.SetValue(propertyTypeAlias, propertyValue); + } } } From 59f437ebf8a7dd2faeaf9582d7fccb70f7a5f108 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 02:03:21 +1100 Subject: [PATCH 36/54] update to latest examine --- build/NuSpecs/UmbracoCms.Web.nuspec | 2 +- src/Umbraco.Examine/Umbraco.Examine.csproj | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index c52c8831e0..cf4958bc98 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -27,7 +27,7 @@ - + diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index 989afd8d1c..7b5a195a31 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -48,7 +48,7 @@ - + diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e88aa5ae61..e0ad304c4f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -80,7 +80,7 @@ - + 1.8.14 diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 3658ef7066..922181bb89 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -87,7 +87,7 @@ - + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 8699540e4b..11d2be5b70 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -63,7 +63,7 @@ - + 2.6.2.25 From b5bd138bf7c6209489aeaba77dd36a9621433e06 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 11 Feb 2019 22:13:04 +0100 Subject: [PATCH 37/54] Taking composite PropertyType's into consideration when creating content from xml (PackageInstallation) --- .../Packaging/PackageDataInstallation.cs | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 064e6cc959..963ab7050f 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -102,8 +102,8 @@ namespace Umbraco.Core.Packaging { // TODO: I don't think this ordering is necessary var orderedTypes = (from contentType in contentTypes - orderby contentType.ParentId descending, contentType.Id descending - select contentType).ToList(); + orderby contentType.ParentId descending, contentType.Id descending + select contentType).ToList(); removedContentTypes.AddRange(orderedTypes); contentTypeService.Delete(orderedTypes, userId); } @@ -157,7 +157,7 @@ namespace Umbraco.Core.Packaging DictionaryItemsUninstalled = removedDictionaryItems, DataTypesUninstalled = removedDataTypes, LanguagesUninstalled = removedLanguages, - + }; return summary; @@ -188,8 +188,8 @@ namespace Umbraco.Core.Packaging var element = packageDocument.XmlData; var roots = from doc in element.Elements() - where (string)doc.Attribute("isDoc") == "" - select doc; + where (string)doc.Attribute("isDoc") == "" + select doc; var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList(); if (contents.Any()) @@ -289,7 +289,7 @@ namespace Umbraco.Core.Packaging var nodeName = element.Attribute("nodeName").Value; var path = element.Attribute("path").Value; var templateId = element.AttributeValue("template"); - + var properties = from property in element.Elements() where property.Attribute("isDoc") == null select property; @@ -325,7 +325,11 @@ namespace Umbraco.Core.Packaging Key = key }; - var propTypes = contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x); + //Here we make sure that we take composition properties in account as well + //otherwise we would skip them and end up losing content + var propTypes = contentType.CompositionPropertyTypes.Any() + ? contentType.CompositionPropertyTypes.ToDictionary(x => x.Alias, x => x) + : contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x); foreach (var property in properties) { @@ -351,7 +355,7 @@ namespace Umbraco.Core.Packaging public IEnumerable ImportDocumentType(XElement docTypeElement, int userId) { - return ImportDocumentTypes(new []{ docTypeElement }, userId); + return ImportDocumentTypes(new[] { docTypeElement }, userId); } /// @@ -375,7 +379,7 @@ namespace Umbraco.Core.Packaging public IEnumerable ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId) { var importedContentTypes = new Dictionary(); - + //When you are importing a single doc type we have to assume that the dependencies are already there. //Otherwise something like uSync won't work. var graph = new TopoGraph>(x => x.Key, x => x.Dependencies); @@ -468,7 +472,7 @@ namespace Umbraco.Core.Packaging if (updatedContentTypes.Any()) _contentTypeService.Save(updatedContentTypes, userId); } - + return list; } @@ -870,7 +874,7 @@ namespace Umbraco.Core.Packaging { _dataTypeService.Save(dataTypes, userId, true); } - + return dataTypes; } @@ -953,7 +957,7 @@ namespace Umbraco.Core.Packaging var items = new List(); foreach (var dictionaryItemElement in dictionaryItemElementList) items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, parentId, userId)); - + return items; } @@ -1040,7 +1044,7 @@ namespace Umbraco.Core.Packaging _localizationService.Save(langauge, userId); list.Add(langauge); } - + return list; } @@ -1203,7 +1207,7 @@ namespace Umbraco.Core.Packaging public IEnumerable ImportTemplate(XElement templateElement, int userId) { - return ImportTemplates(new[] {templateElement}, userId); + return ImportTemplates(new[] { templateElement }, userId); } /// @@ -1250,7 +1254,7 @@ namespace Umbraco.Core.Packaging var alias = templateElement.Element("Alias").Value; var design = templateElement.Element("Design").Value; var masterElement = templateElement.Element("Master"); - + var existingTemplate = _fileService.GetTemplate(alias) as Template; var template = existingTemplate ?? new Template(templateName, alias); template.Content = design; From 978f59ffe8f7fcc710f2d07e47cf725895d6b427 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 10:53:30 +1100 Subject: [PATCH 38/54] Removes the xml cache tables - we don't use them apart from in unit tests --- .../Install/DatabaseSchemaCreator.cs | 2 - .../Upgrade/V_8_0_0/DropTaskTables.cs | 1 - .../Upgrade/V_8_0_0/DropXmlTables.cs | 17 +++++++ .../Persistence/Constants-DatabaseSchema.cs | 49 +++++++++---------- .../Implement/DocumentRepository.cs | 2 - .../Implement/MemberRepository.cs | 1 - src/Umbraco.Core/Umbraco.Core.csproj | 3 +- .../LegacyXmlPublishedCache}/ContentXmlDto.cs | 7 +-- .../LegacyXmlPublishedCache}/PreviewXmlDto.cs | 7 +-- .../LegacyXmlPublishedCache/XmlStore.cs | 1 - .../Persistence/SqlCeTableByTableTest.cs | 1 + .../SqlCeSyntaxProviderTests.cs | 1 + .../Services/ContentServiceTests.cs | 1 + .../Services/ContentTypeServiceTests.cs | 1 + .../Services/MediaServiceTests.cs | 1 + .../Services/MemberServiceTests.cs | 1 + .../Services/MemberTypeServiceTests.cs | 1 + .../Services/PerformanceTests.cs | 1 + .../TestHelpers/TestWithDatabaseBase.cs | 7 +++ src/Umbraco.Tests/Umbraco.Tests.csproj | 2 + 20 files changed, 67 insertions(+), 40 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs rename src/{Umbraco.Core/Persistence/Dtos => Umbraco.Tests/LegacyXmlPublishedCache}/ContentXmlDto.cs (81%) rename src/{Umbraco.Core/Persistence/Dtos => Umbraco.Tests/LegacyXmlPublishedCache}/PreviewXmlDto.cs (81%) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index 5cc818a6d2..b33e624576 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -50,8 +50,6 @@ namespace Umbraco.Core.Migrations.Install typeof (MemberTypeDto), typeof (MemberDto), typeof (Member2MemberGroupDto), - typeof (ContentXmlDto), - typeof (PreviewXmlDto), typeof (PropertyTypeGroupDto), typeof (PropertyTypeDto), typeof (PropertyDataDto), diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropTaskTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropTaskTables.cs index 008b3e4b5f..061b96976a 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropTaskTables.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropTaskTables.cs @@ -1,6 +1,5 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { - public class DropTaskTables : MigrationBase { public DropTaskTables(IMigrationContext context) diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs new file mode 100644 index 0000000000..be79178932 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class DropXmlTables : MigrationBase + { + public DropXmlTables(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + if (TableExists("cmsContentXml")) + Delete.Table("cmsContentXml").Do(); + if (TableExists("cmsPreviewXml")) + Delete.Table("cmsPreviewXml").Do(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs index b874c6e04a..b62a99ce83 100644 --- a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs +++ b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs @@ -5,17 +5,16 @@ namespace Umbraco.Core { public static class DatabaseSchema { + //TODO: Why aren't all table names with the same prefix? public const string TableNamePrefix = "umbraco"; public static class Tables { - public const string Lock = /*TableNamePrefix*/ "umbraco" + "Lock"; - public const string Log = /*TableNamePrefix*/ "umbraco" + "Log"; + public const string Lock = TableNamePrefix + "Lock"; + public const string Log = TableNamePrefix + "Log"; - public const string Node = /*TableNamePrefix*/ "umbraco" + "Node"; + public const string Node = TableNamePrefix + "Node"; public const string NodeData = /*TableNamePrefix*/ "cms" + "ContentNu"; - public const string NodeXml = /*TableNamePrefix*/ "cms" + "ContentXml"; // TODO: get rid of these with the xml cache - public const string NodePreviewXml = /*TableNamePrefix*/ "cms" + "PreviewXml"; // TODO: get rid of these with the xml cache public const string ContentType = /*TableNamePrefix*/ "cms" + "ContentType"; public const string ContentChildType = /*TableNamePrefix*/ "cms" + "ContentTypeAllowedContentType"; @@ -37,22 +36,22 @@ namespace Umbraco.Core public const string PropertyTypeGroup = /*TableNamePrefix*/ "cms" + "PropertyTypeGroup"; public const string PropertyData = TableNamePrefix + "PropertyData"; - public const string RelationType = /*TableNamePrefix*/ "umbraco" + "RelationType"; - public const string Relation = /*TableNamePrefix*/ "umbraco" + "Relation"; + public const string RelationType = TableNamePrefix + "RelationType"; + public const string Relation = TableNamePrefix + "Relation"; - public const string Domain = /*TableNamePrefix*/ "umbraco" + "Domain"; - public const string Language = /*TableNamePrefix*/ "umbraco" + "Language"; + public const string Domain = TableNamePrefix + "Domain"; + public const string Language = TableNamePrefix + "Language"; public const string DictionaryEntry = /*TableNamePrefix*/ "cms" + "Dictionary"; public const string DictionaryValue = /*TableNamePrefix*/ "cms" + "LanguageText"; - public const string User = /*TableNamePrefix*/ "umbraco" + "User"; - public const string UserGroup = /*TableNamePrefix*/ "umbraco" + "UserGroup"; - public const string UserStartNode = /*TableNamePrefix*/ "umbraco" + "UserStartNode"; - public const string User2UserGroup = /*TableNamePrefix*/ "umbraco" + "User2UserGroup"; - public const string User2NodeNotify = /*TableNamePrefix*/ "umbraco" + "User2NodeNotify"; - public const string UserGroup2App = /*TableNamePrefix*/ "umbraco" + "UserGroup2App"; - public const string UserGroup2NodePermission = /*TableNamePrefix*/ "umbraco" + "UserGroup2NodePermission"; - public const string ExternalLogin = /*TableNamePrefix*/ "umbraco" + "ExternalLogin"; + public const string User = TableNamePrefix + "User"; + public const string UserGroup = TableNamePrefix + "UserGroup"; + public const string UserStartNode = TableNamePrefix + "UserStartNode"; + public const string User2UserGroup = TableNamePrefix + "User2UserGroup"; + public const string User2NodeNotify = TableNamePrefix + "User2NodeNotify"; + public const string UserGroup2App = TableNamePrefix + "UserGroup2App"; + public const string UserGroup2NodePermission = TableNamePrefix + "UserGroup2NodePermission"; + public const string ExternalLogin = TableNamePrefix + "ExternalLogin"; public const string Macro = /*TableNamePrefix*/ "cms" + "Macro"; public const string MacroProperty = /*TableNamePrefix*/ "cms" + "MacroProperty"; @@ -61,21 +60,21 @@ namespace Umbraco.Core public const string MemberType = /*TableNamePrefix*/ "cms" + "MemberType"; public const string Member2MemberGroup = /*TableNamePrefix*/ "cms" + "Member2MemberGroup"; - public const string Access = /*TableNamePrefix*/ "umbraco" + "Access"; - public const string AccessRule = /*TableNamePrefix*/ "umbraco" + "AccessRule"; - public const string RedirectUrl = /*TableNamePrefix*/ "umbraco" + "RedirectUrl"; + public const string Access = TableNamePrefix + "Access"; + public const string AccessRule = TableNamePrefix + "AccessRule"; + public const string RedirectUrl = TableNamePrefix + "RedirectUrl"; - public const string CacheInstruction = /*TableNamePrefix*/ "umbraco" + "CacheInstruction"; - public const string Server = /*TableNamePrefix*/ "umbraco" + "Server"; + public const string CacheInstruction = TableNamePrefix + "CacheInstruction"; + public const string Server = TableNamePrefix + "Server"; public const string Tag = /*TableNamePrefix*/ "cms" + "Tags"; public const string TagRelationship = /*TableNamePrefix*/ "cms" + "TagRelationship"; public const string KeyValue = TableNamePrefix + "KeyValue"; - public const string AuditEntry = /*TableNamePrefix*/ "umbraco" + "Audit"; - public const string Consent = /*TableNamePrefix*/ "umbraco" + "Consent"; - public const string UserLogin = /*TableNamePrefix*/ "umbraco" + "UserLogin"; + public const string AuditEntry = TableNamePrefix + "Audit"; + public const string Consent = TableNamePrefix + "Consent"; + public const string UserLogin = TableNamePrefix + "UserLogin"; } } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index d8e6fd2c0e..24b50d294b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -202,10 +202,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement "DELETE FROM " + Constants.DatabaseSchema.Tables.DocumentCultureVariation + " WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.DocumentVersion + " WHERE id IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)", "DELETE FROM " + Constants.DatabaseSchema.Tables.PropertyData + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)", - "DELETE FROM cmsPreviewXml WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersionCultureVariation + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)", "DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id", - "DELETE FROM cmsContentXml WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.Node + " WHERE id = @id" diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs index ba3526f1f0..808f61305a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs @@ -188,7 +188,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement "DELETE FROM cmsMember2MemberGroup WHERE Member = @id", "DELETE FROM cmsMember WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id", - "DELETE FROM cmsContentXml WHERE nodeId = @id", "DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id", "DELETE FROM umbracoNode WHERE id = @id" }; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f5bdc417bd..57aee5ffbf 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -379,6 +379,7 @@ + @@ -826,7 +827,6 @@ - @@ -846,7 +846,6 @@ - diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentXmlDto.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs similarity index 81% rename from src/Umbraco.Core/Persistence/Dtos/ContentXmlDto.cs rename to src/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs index 5929f5cb81..2f2c1e787a 100644 --- a/src/Umbraco.Core/Persistence/Dtos/ContentXmlDto.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs @@ -1,9 +1,10 @@ using NPoco; using Umbraco.Core.Persistence.DatabaseAnnotations; +using Umbraco.Core.Persistence.Dtos; -namespace Umbraco.Core.Persistence.Dtos +namespace Umbraco.Tests.LegacyXmlPublishedCache { - [TableName(Constants.DatabaseSchema.Tables.NodeXml)] + [TableName("cmsContentXml")] [PrimaryKey("nodeId", AutoIncrement = false)] [ExplicitColumns] internal class ContentXmlDto @@ -20,4 +21,4 @@ namespace Umbraco.Core.Persistence.Dtos [Column("rv")] public long Rv { get; set; } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Dtos/PreviewXmlDto.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs similarity index 81% rename from src/Umbraco.Core/Persistence/Dtos/PreviewXmlDto.cs rename to src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs index 40cc50b00a..4fcbef820a 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PreviewXmlDto.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs @@ -1,9 +1,10 @@ using NPoco; using Umbraco.Core.Persistence.DatabaseAnnotations; +using Umbraco.Core.Persistence.Dtos; -namespace Umbraco.Core.Persistence.Dtos +namespace Umbraco.Tests.LegacyXmlPublishedCache { - [TableName(Constants.DatabaseSchema.Tables.NodePreviewXml)] + [TableName("cmsPreviewXml")] [PrimaryKey("nodeId", AutoIncrement = false)] [ExplicitColumns] internal class PreviewXmlDto @@ -20,4 +21,4 @@ namespace Umbraco.Core.Persistence.Dtos [Column("rv")] public long Rv { get; set; } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs index 6dec9f2448..3b675c2f07 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs @@ -12,7 +12,6 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; diff --git a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs index 38daa2c1a7..dcbf5919eb 100644 --- a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs index 557de9eb11..1d87bb35e7 100644 --- a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs +++ b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 85c195e553..bcbf01d3f0 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -18,6 +18,7 @@ using Umbraco.Core.Services.Implement; using Umbraco.Tests.Testing; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Cache; +using Umbraco.Tests.LegacyXmlPublishedCache; namespace Umbraco.Tests.Services { diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 7a7aad6905..341371ca02 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Tests.Scoping; diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests/Services/MediaServiceTests.cs index b9e1fee0db..17711fbd31 100644 --- a/src/Umbraco.Tests/Services/MediaServiceTests.cs +++ b/src/Umbraco.Tests/Services/MediaServiceTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index 0c9c543b0d..98553941cd 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Security.Providers; diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs index 5f4a87c3eb..24709469e9 100644 --- a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/Services/PerformanceTests.cs b/src/Umbraco.Tests/Services/PerformanceTests.cs index 7d73d95e74..449e933c24 100644 --- a/src/Umbraco.Tests/Services/PerformanceTests.cs +++ b/src/Umbraco.Tests/Services/PerformanceTests.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 2bfc1b6dc8..643deab304 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -307,6 +307,13 @@ namespace Umbraco.Tests.TestHelpers var schemaHelper = new DatabaseSchemaCreator(scope.Database, Logger); //Create the umbraco database and its base data schemaHelper.InitializeDatabaseSchema(); + + //Special case, we need to create the xml cache tables manually since they are not part of the default + //setup. + //TODO: Remove this when we update all tests to use nucache + schemaHelper.CreateTable(); + schemaHelper.CreateTable(); + scope.Complete(); } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e0ad304c4f..5aa1588ef2 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -126,6 +126,8 @@ + + From 3d729eb2c325b9239749719440e89d10e25b0d8b Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 10:54:18 +1100 Subject: [PATCH 39/54] updates umb plan --- src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index cfa82748d2..08d1cc8f4f 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -127,7 +127,8 @@ namespace Umbraco.Core.Migrations.Upgrade To("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}"); To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); - To("98339BEF-E4B2-48A8-B9D1-D173DC842BBE"); + To("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}"); + To("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}"); //FINAL From 77d70c7e7f2fac6e2a1e611fb8f56d5de33412ba Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 11:43:34 +1100 Subject: [PATCH 40/54] Fixes test --- .../Migrations/Install/DatabaseSchemaCreator.cs | 7 ++++++- src/Umbraco.Tests/Persistence/SchemaValidationTest.cs | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index b33e624576..d8283fd112 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -137,13 +137,18 @@ namespace Umbraco.Core.Migrations.Install /// Validates the schema of the current database. /// internal DatabaseSchemaResult ValidateSchema() + { + return ValidateSchema(OrderedTables); + } + + internal DatabaseSchemaResult ValidateSchema(IEnumerable orderedTables) { var result = new DatabaseSchemaResult(SqlSyntax); result.IndexDefinitions.AddRange(SqlSyntax.GetDefinedIndexes(_database) .Select(x => new DbIndexDefinition(x))); - result.TableDefinitions.AddRange(OrderedTables + result.TableDefinitions.AddRange(orderedTables .Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax))); ValidateDbTables(result); diff --git a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs index 2c875d6afc..c7118dac79 100644 --- a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs +++ b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs @@ -1,9 +1,11 @@ -using Moq; +using System.Linq; +using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -21,7 +23,9 @@ namespace Umbraco.Tests.Persistence using (var scope = ScopeProvider.CreateScope()) { var schema = new DatabaseSchemaCreator(scope.Database, Logger); - result = schema.ValidateSchema(); + result = schema.ValidateSchema( + //TODO: When we remove the xml cache from tests we can remove this too + DatabaseSchemaCreator.OrderedTables.Concat(new []{typeof(ContentXmlDto), typeof(PreviewXmlDto)})); } // Assert From 1a1222905b4967c25773448949b28d673399d1b3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 12:22:36 +1100 Subject: [PATCH 41/54] reverts the formsInstaller alias, fixes the ApplicationTreeController to allow full screen sections without trees, removes the forms tree controller --- src/Umbraco.Core/Constants-Applications.cs | 3 +-- .../Migrations/Install/DatabaseDataCreator.cs | 4 +-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 - .../Umbraco/config/lang/en_us.xml | 1 - src/Umbraco.Web/Dashboards/FormsDashboard.cs | 2 +- src/Umbraco.Web/Editors/SectionController.cs | 2 +- .../Trees/ApplicationTreeController.cs | 19 ++++++++++--- .../Trees/FormsBackOfficeSection.cs | 2 +- src/Umbraco.Web/Trees/FormsTreeController.cs | 27 ------------------- src/Umbraco.Web/Umbraco.Web.csproj | 1 - 10 files changed, 21 insertions(+), 41 deletions(-) delete mode 100644 src/Umbraco.Web/Trees/FormsTreeController.cs diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs index e66df3a5f9..b53a2b8eaf 100644 --- a/src/Umbraco.Core/Constants-Applications.cs +++ b/src/Umbraco.Core/Constants-Applications.cs @@ -45,7 +45,7 @@ /// /// Application alias for the forms section. /// - public const string FormsInstaller = "formsInstaller"; + public const string Forms = "forms"; } /// @@ -138,7 +138,6 @@ /// alias for the users tree. /// public const string Users = "users"; - public const string Forms = "formsInstaller"; public const string Scripts = "scripts"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 055b899231..7f7229ccd6 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -189,13 +189,13 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Members }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Settings }); _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Users }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.FormsInstaller }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Forms }); _database.Insert(new UserGroup2AppDto { UserGroupId = 2, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Content }); _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Media }); - _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.FormsInstaller }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Forms }); _database.Insert(new UserGroup2AppDto { UserGroupId = 4, AppAlias = Constants.Applications.Translation }); } diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 91a4d9378c..548d6932a6 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1244,7 +1244,6 @@ To manage your website, simply open the Umbraco back office and start adding con Courier Developer Forms - Forms Help Umbraco Configuration Wizard Media 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 b9aa3b6ece..7dcd101aff 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1247,7 +1247,6 @@ To manage your website, simply open the Umbraco back office and start adding con Content Forms - Forms Media Members Packages diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs index bb21a04fdc..867e8af3aa 100644 --- a/src/Umbraco.Web/Dashboards/FormsDashboard.cs +++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs @@ -10,7 +10,7 @@ namespace Umbraco.Web.Dashboards { public string Alias => "formsInstall"; - public string[] Sections => new [] { Constants.Applications.FormsInstaller }; + public string[] Sections => new [] { Constants.Applications.Forms }; public string View => "views/dashboard/forms/formsdashboardintro.html"; diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index 0a2f17cd15..52034b9c95 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors // this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that // since tree's by nature are controllers and require request contextual data - var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, Umbraco) + var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, _sectionService, Umbraco) { ControllerContext = ControllerContext }; diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 162d001e96..b8fe709738 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -32,13 +32,15 @@ namespace Umbraco.Web.Trees public class ApplicationTreeController : UmbracoAuthorizedApiController { private readonly ITreeService _treeService; + private readonly ISectionService _sectionService; public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, - IRuntimeState runtimeState, ITreeService treeService, UmbracoHelper umbracoHelper) + IRuntimeState runtimeState, ITreeService treeService, ISectionService sectionService, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { _treeService = treeService; + _sectionService = sectionService; } /// @@ -56,12 +58,21 @@ namespace Umbraco.Web.Trees if (string.IsNullOrEmpty(application)) throw new HttpResponseException(HttpStatusCode.NotFound); + var section = _sectionService.GetByAlias(application); + if (section == null) + throw new HttpResponseException(HttpStatusCode.NotFound); + //find all tree definitions that have the current application alias var groupedTrees = _treeService.GetBySectionGrouped(application, use); var allTrees = groupedTrees.Values.SelectMany(x => x).ToList(); if (allTrees.Count == 0) - throw new HttpResponseException(HttpStatusCode.NotFound); + { + //if there are no trees defined for this section but the section is defined then we can have a simple + //full screen section without trees + var name = Services.TextService.Localize("sections/" + application); + return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true); + } // handle request for a specific tree / or when there is only one tree if (!tree.IsNullOrWhiteSpace() || allTrees.Count == 1) @@ -101,8 +112,8 @@ namespace Umbraco.Web.Trees return treeRootNode; } - // otherwise it's a section with no tree, aka a fullscreen section - // todo is this true? what if we just failed to TryGetRootNode on all of them? + // otherwise it's a section with all empty trees, aka a fullscreen section + // todo is this true? what if we just failed to TryGetRootNode on all of them? SD: Yes it's true but we should check the result of TryGetRootNode and throw? return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true); } diff --git a/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs index 681fe61993..048ed47f11 100644 --- a/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs +++ b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs @@ -8,7 +8,7 @@ namespace Umbraco.Web.Trees /// public class FormsBackOfficeSection : IBackOfficeSection { - public string Alias => Constants.Applications.FormsInstaller; + public string Alias => Constants.Applications.Forms; public string Name => "Forms"; } } diff --git a/src/Umbraco.Web/Trees/FormsTreeController.cs b/src/Umbraco.Web/Trees/FormsTreeController.cs deleted file mode 100644 index 2c6885cf97..0000000000 --- a/src/Umbraco.Web/Trees/FormsTreeController.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Net.Http.Formatting; -using Umbraco.Web.Models.Trees; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Trees -{ - [UmbracoTreeAuthorize(Constants.Trees.Forms)] - [Tree(Constants.Applications.FormsInstaller, Constants.Trees.Forms, SortOrder = 0, IsSingleNodeTree = true)] - [PluginController("UmbracoTrees")] - [CoreTree] - public class FormsTreeController : TreeController - { - protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) - { - //full screen app without tree nodes - return TreeNodeCollection.Empty; - } - - protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) - { - //doesn't have a menu, this is a full screen app without tree nodes - return MenuItemCollection.Empty; - } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 23ae727c35..6522ac9a05 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -215,7 +215,6 @@ - From c00f805ea2fd8ce511c4ab9c19ab0f78a79e7de5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 13:36:32 +1100 Subject: [PATCH 42/54] Fixes dirty tracking on tags editor when it's csv format --- .../tags/umbtagseditor.directive.js | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index edf54ca034..5131dc3dcb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -29,6 +29,8 @@ let typeahead; let tagsHound; + let initLoad = true; + vm.$onInit = onInit; vm.$onChanges = onChanges; vm.$onDestroy = onDestroy; @@ -138,9 +140,17 @@ if (changes.value) { if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) { - configureViewModel(); - reValidate() - + if (initLoad) { + //this occurs if we have to re-format the model on the init load, so set the flag to false + //so the next time it actually changes we process it. + initLoad = false; + //we need to reset the form since it actually hasn't changed but it will be detected as changed + vm.tagEditorForm.$setPristine(); + } + else { + configureViewModel(); + reValidate(); + } } } } @@ -161,6 +171,7 @@ //json storage vm.viewModel = JSON.parse(vm.value); updateModelValue(vm.viewModel); + return; } else { //csv storage @@ -175,13 +186,15 @@ }); updateModelValue(vm.viewModel); - + return; } } else if (angular.isArray(vm.value)) { vm.viewModel = vm.value; } } + //if we've made it here we haven't had to re-format the model so we'll set this to false + initLoad = false; } function updateModelValue(val) { From 54aa1924c0cee7d39f75fdc8ec32fd6ee413ee12 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 13:55:50 +1100 Subject: [PATCH 43/54] ok, properly fixes dirty tracking on the tags editor --- .../tags/umbtagseditor.directive.js | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index 5131dc3dcb..40def728ed 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -55,7 +55,7 @@ vm.isLoading = false; //ensure that the models are formatted correctly - configureViewModel(); + configureViewModel(true); // Set the visible prompt to -1 to ensure it will not be visible vm.promptIsVisible = "-1"; @@ -140,17 +140,8 @@ if (changes.value) { if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) { - if (initLoad) { - //this occurs if we have to re-format the model on the init load, so set the flag to false - //so the next time it actually changes we process it. - initLoad = false; - //we need to reset the form since it actually hasn't changed but it will be detected as changed - vm.tagEditorForm.$setPristine(); - } - else { - configureViewModel(); - reValidate(); - } + configureViewModel(); + reValidate(); } } } @@ -164,14 +155,19 @@ $element.find('.tags-' + vm.htmlId).typeahead('destroy'); } - function configureViewModel() { + function configureViewModel(isInitLoad) { if (vm.value) { if (angular.isString(vm.value) && vm.value.length > 0) { if (vm.config.storageType === "Json") { //json storage vm.viewModel = JSON.parse(vm.value); - updateModelValue(vm.viewModel); - return; + + //if this is the first load, we are just re-formatting the underlying model to be consistent + //we don't want to notify the component parent of any changes, that will occur if the user actually + //changes a value. If we notify at this point it will signal a form dirty change which we don't want. + if (!isInitLoad) { + updateModelValue(vm.viewModel); + } } else { //csv storage @@ -185,16 +181,18 @@ return self.indexOf(v) === i; }); - updateModelValue(vm.viewModel); - return; + //if this is the first load, we are just re-formatting the underlying model to be consistent + //we don't want to notify the component parent of any changes, that will occur if the user actually + //changes a value. If we notify at this point it will signal a form dirty change which we don't want. + if (!isInitLoad) { + updateModelValue(vm.viewModel); + } } } else if (angular.isArray(vm.value)) { vm.viewModel = vm.value; } } - //if we've made it here we haven't had to re-format the model so we'll set this to false - initLoad = false; } function updateModelValue(val) { From 118e31d6478ce11bdfeb23df9094a8f7baece548 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 14:03:22 +1100 Subject: [PATCH 44/54] removes/renames list view settings that don't make sense for v8 --- .../views/propertyeditors/listview/listview.controller.js | 1 - src/Umbraco.Web/PropertyEditors/ListViewConfiguration.cs | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index a3fc33d2ea..44c0c4ae7b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -142,7 +142,6 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs } $scope.options = { - displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1, pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10, pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1, filter: '', diff --git a/src/Umbraco.Web/PropertyEditors/ListViewConfiguration.cs b/src/Umbraco.Web/PropertyEditors/ListViewConfiguration.cs index 6448a3354c..bcddc18369 100644 --- a/src/Umbraco.Web/PropertyEditors/ListViewConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/ListViewConfiguration.cs @@ -13,7 +13,6 @@ namespace Umbraco.Web.PropertyEditors // initialize defaults PageSize = 10; - DisplayAtTabNumber = 1; OrderBy = "SortOrder"; OrderDirection = "asc"; @@ -43,9 +42,6 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - [ConfigurationField("displayAtTabNumber", "Display At Tab Number", "number", Description = "Which tab position that the list of child items will be displayed")] - public int DisplayAtTabNumber { get; set; } - [ConfigurationField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", Description = "The default sort order for the list")] public string OrderBy { get; set; } @@ -64,7 +60,7 @@ namespace Umbraco.Web.PropertyEditors Description = "The bulk actions that are allowed from the list view")] public BulkActionPermissionSettings BulkActionPermissions { get; set; } = new BulkActionPermissionSettings(); // TODO: managing defaults? - [ConfigurationField("tabName", "Tab Name", "textstring", Description = "The name of the listview tab (default if empty: 'Child Items')")] + [ConfigurationField("tabName", "Content app name", "textstring", Description = "The name of the listview content app (default if empty: 'Child Items')")] public string TabName { get; set; } public class Property From c4eb76faad5b268914998b4ec1eb1863c9b89bc8 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Feb 2019 15:02:27 +1100 Subject: [PATCH 45/54] Updates the checkbox html editor to store the string values, not int ids, renames the underlying confg editor and updates comments, updates the migration and we'll need to migrate the checkbox data too. --- .../Migrations/Upgrade/UmbracoPlan.cs | 2 +- ...tonAndCheckboxPropertyEditorsMigration.cs} | 110 ++++++++++-------- src/Umbraco.Core/Umbraco.Core.csproj | 5 +- .../checkboxlist/checkboxlist.controller.js | 8 +- .../checkboxlist/checkboxlist.html | 2 +- .../CheckBoxListPropertyEditor.cs | 7 +- .../DropDownFlexiblePropertyEditor.cs | 2 +- ...eValueEditor.cs => MultipleValueEditor.cs} | 8 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 9 files changed, 78 insertions(+), 68 deletions(-) rename src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/{RadioButtonPropertyEditorsMigration.cs => RadioButtonAndCheckboxPropertyEditorsMigration.cs} (56%) rename src/Umbraco.Web/PropertyEditors/{PublishValuesMultipleValueEditor.cs => MultipleValueEditor.cs} (84%) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index ccacaa8893..ddc4289718 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -128,7 +128,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); To("98339BEF-E4B2-48A8-B9D1-D173DC842BBE"); - To("{940FD19A-00A8-4D5C-B8FF-939143585726}"); + To("{940FD19A-00A8-4D5C-B8FF-939143585726}"); //FINAL diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonAndCheckboxPropertyEditorsMigration.cs similarity index 56% rename from src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs rename to src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonAndCheckboxPropertyEditorsMigration.cs index 2c4e601a9e..ec60a22ecd 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonPropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioButtonAndCheckboxPropertyEditorsMigration.cs @@ -1,81 +1,98 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Sync; -using Umbraco.Web.Cache; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { - public class RadioButtonPropertyEditorsMigration : MigrationBase + public class RadioButtonAndCheckboxPropertyEditorsMigration : MigrationBase { - public RadioButtonPropertyEditorsMigration(IMigrationContext context) + public RadioButtonAndCheckboxPropertyEditorsMigration(IMigrationContext context) : base(context) { } public override void Migrate() { - //need to convert the old drop down data types to use the new one - var dataTypes = Database.Fetch(Sql() - .Select() - .From() - .Where(x => x.EditorAlias == "Umbraco.RadioButtonList")); + MigrateRadioButtons(); + MigrateCheckBoxes(); + } + + private void MigrateCheckBoxes() + { + //fixme: complete this + + var dataTypes = GetDataTypes(Constants.PropertyEditors.Aliases.CheckBoxList); + + + } + + private void MigrateRadioButtons() + { + var dataTypes = GetDataTypes(Constants.PropertyEditors.Aliases.RadioButtonList); var refreshCache = false; foreach (var dataType in dataTypes) { ValueListConfiguration config; - if (!dataType.Configuration.IsNullOrWhiteSpace()) + if (dataType.Configuration.IsNullOrWhiteSpace()) + continue; + + // parse configuration, and update everything accordingly + try { - // parse configuration, and update everything accordingly - try - { - config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase( - dataType.Configuration); - } - catch (Exception ex) - { - Logger.Error( - ex, - "Invalid drop down configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared", - dataType.Configuration); - - continue; - } - - // get property data dtos - var propertyDataDtos = Database.Fetch(Sql() - .Select() - .From() - .InnerJoin() - .On((pt, pd) => pt.Id == pd.PropertyTypeId) - .InnerJoin() - .On((dt, pt) => dt.NodeId == pt.DataTypeId) - .Where(x => x.DataTypeId == dataType.NodeId)); - - // update dtos - var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config)); - - // persist changes - foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto); - - UpdateDataType(dataType); - refreshCache = true; + config = (ValueListConfiguration)new ValueListConfigurationEditor().FromDatabase( + dataType.Configuration); } + catch (Exception ex) + { + Logger.Error( + ex, + "Invalid radio button configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared", + dataType.Configuration); + + continue; + } + + // get property data dtos + var propertyDataDtos = Database.Fetch(Sql() + .Select() + .From() + .InnerJoin() + .On((pt, pd) => pt.Id == pd.PropertyTypeId) + .InnerJoin() + .On((dt, pt) => dt.NodeId == pt.DataTypeId) + .Where(x => x.DataTypeId == dataType.NodeId)); + + // update dtos + var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config)); + + // persist changes + foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto); + + UpdateDataType(dataType); + refreshCache = true; } if (refreshCache) { //FIXME: trigger cache rebuild. Currently the data in the database tables is wrong. } + } + private List GetDataTypes(string editorAlias) + { + //need to convert the old drop down data types to use the new one + var dataTypes = Database.Fetch(Sql() + .Select() + .From() + .Where(x => x.EditorAlias == editorAlias)); + return dataTypes; } private void UpdateDataType(DataTypeDto dataType) @@ -123,7 +140,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 if (!canConvert) return false; - propData.VarcharValue = string.Join(",", values); + //The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first + propData.VarcharValue = values.Count > 0 ? values[0] : string.Empty; propData.TextValue = null; propData.IntegerValue = null; return true; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 4358fdbd42..d43aedc2d0 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -52,9 +52,6 @@ - - ..\Umbraco.Tests\bin\Debug\Umbraco.Web.dll - @@ -389,7 +386,7 @@ - + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js index 9ef1b69aad..8897c59cef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.controller.js @@ -42,7 +42,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro return f.checked; }), function(m) { - return m.key; + return m.value; }); //get all of the same values between the arrays var same = _.intersection($scope.model.value, selectedVals); @@ -54,7 +54,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro $scope.selectedItems = []; for (var i = 0; i < configItems.length; i++) { - var isChecked = _.contains($scope.model.value, configItems[i].id); + var isChecked = _.contains($scope.model.value, configItems[i].value); $scope.selectedItems.push({ checked: isChecked, key: configItems[i].id, @@ -66,13 +66,13 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro function changed(item) { var index = _.findIndex($scope.model.value, function (v) { - return v === item.key; + return v === item.value; }); if (item.checked) { //if it doesn't exist in the model, then add it if (index < 0) { - $scope.model.value.push(item.key); + $scope.model.value.push(item.value); } } else { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html index 29760e3f5b..6e9150d07c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/checkboxlist/checkboxlist.html @@ -4,7 +4,7 @@