From bb5dad8c1d24d04949da17ea03152e52bdfb30bb Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 30 Oct 2013 18:57:43 +1100 Subject: [PATCH 1/9] Removes user timeout timer to do digests, now just has it's own internal clock and the countdown timer will count for itself and only digest it's own scope, this is heaps better for performance. --- .../src/common/services/user.service.js | 19 ++++++++++++------- .../views/common/dialogs/user.controller.js | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js index 1808d30660..06cc7289b3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js @@ -1,5 +1,5 @@ angular.module('umbraco.services') -.factory('userService', function ($rootScope, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout) { +.factory('userService', function ($rootScope, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper) { var currentUser = null; var lastUserId = null; @@ -60,8 +60,8 @@ angular.module('umbraco.services') this will continually count down their current remaining seconds every 2 seconds until there are no more seconds remaining. */ - function countdownUserTimeout() { - $timeout(function () { + function countdownUserTimeout() { + $timeout(function() { if (currentUser) { //countdown by 2 seconds since that is how long our timer is for. currentUser.remainingAuthSeconds -= 2; @@ -90,12 +90,17 @@ angular.module('umbraco.services') countdownUserTimeout(); } else { - + //we are either timed out or very close to timing out so we need to show the login dialog. - userAuthExpired(); + //NOTE: the safeApply because our timeout is set to not run digests (performance reasons) + angularHelper.safeApply($rootScope, function() { + userAuthExpired(); + }); + } - } - }, 2000);//every 2 seconds + } + }, 2000, //every 2 seconds + false); //false = do NOT execute a digest for every iteration } /** Called to update the current user's timeout */ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.controller.js index ceac0f36f4..877ad7d351 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco") - .controller("Umbraco.Dialogs.UserController", function ($scope, $location, userService, historyService) { + .controller("Umbraco.Dialogs.UserController", function ($scope, $location, $timeout, userService, historyService) { $scope.user = userService.getCurrentUser(); $scope.history = historyService.current; @@ -13,5 +13,17 @@ angular.module("umbraco") $scope.gotoHistory = function (link) { $location.path(link); $scope.hide(); - }; -}); \ No newline at end of file + }; + + //Manually update the remaining timeout seconds + function updateTimeout() { + $timeout(function () { + $scope.user = userService.getCurrentUser(); + //manually execute the digest against this scope only + $scope.$digest(); + updateTimeout(); //keep going (recurse) + }, 1000, false); // 1 second, do NOT execute a global digest + } + updateTimeout(); + + }); \ No newline at end of file From 4f79b8bf45b06dd9caa7557b47bcc63f7805fe57 Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Wed, 30 Oct 2013 13:03:52 +0100 Subject: [PATCH 2/9] Updates video dashboards to show chapters --- .../src/views/dashboard/default/StartupDashboardVideos.html | 2 +- .../src/views/dashboard/developer/developerdashboardvideos.html | 2 +- .../src/views/dashboard/media/mediadashboardvideos.html | 2 +- .../src/views/dashboard/settings/settingsdashboardvideos.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardVideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardVideos.html index 9e72ea5f01..2135c37859 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardVideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardVideos.html @@ -3,7 +3,7 @@

To get you started:

    diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/developerdashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/developerdashboardvideos.html index b75c4e8384..0e3c107cdc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/developerdashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/developerdashboardvideos.html @@ -3,7 +3,7 @@

    To get you started:

      diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html index 9e72ea5f01..2135c37859 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html @@ -3,7 +3,7 @@

      To get you started:

        diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html index b75c4e8384..2135c37859 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html @@ -3,7 +3,7 @@

        To get you started:

          From 5ce6ec124a01f042c59c55d0960148d87eeb9241 Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Wed, 30 Oct 2013 13:11:59 +0100 Subject: [PATCH 3/9] Adds member group picker prop editor to Umbraco.Web --- src/Umbraco.Core/Constants-PropertyEditors.cs | 5 +++++ .../MemberGroupPickerPropertyEditor.cs | 15 +++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 3 files changed, 21 insertions(+) create mode 100644 src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index a6dc544a70..96ee42cfcb 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -192,6 +192,11 @@ namespace Umbraco.Core /// public const string MemberPickerAlias = "Umbraco.MemberPicker"; + /// + /// Alias for the Member Group Picker datatype. + /// + public const string MemberGroupPickerAlias = "Umbraco.MemberGroupPicker"; + /// /// Guid for the Multi-Node Tree Picker datatype /// diff --git a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs new file mode 100644 index 0000000000..e30df16e23 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Group Picker", "membergrouppicker")] + public class MemberGroupPickerPropertyEditor : PropertyEditor + { + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 6b756d6139..4fe5ecd297 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -344,6 +344,7 @@ + From 54e48663251f433050268b2058747583fe45ae8b Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Wed, 30 Oct 2013 13:19:10 +0100 Subject: [PATCH 4/9] More work on member group picker --- .../membergrouppicker.controller.js | 98 +++++++++++++++++++ .../membergrouppicker/membergrouppicker.html | 26 +++++ .../MemberGroupPickerPropertyEditor.cs | 2 +- 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js new file mode 100644 index 0000000000..a44e5c3385 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js @@ -0,0 +1,98 @@ +//this controller simply tells the dialogs service to open a memberPicker window +//with a specified callback, this callback will receive an object with a selection on it +angular.module('umbraco') +.controller("Umbraco.PropertyEditors.MemberPickerController", + + function($scope, dialogService, entityResource, $log, iconHelper){ + $scope.renderModel = []; + $scope.ids = $scope.model.value.split(','); + + $scope.cfg = {multiPicker: false, entityType: "Document", type: "content", treeAlias: "content", filter: ""}; + if($scope.model.config){ + $scope.cfg = angular.extend($scope.cfg, $scope.model.config); + } + + if($scope.cfg.type === "member"){ + $scope.cfg.entityType = "Member"; + }else if($scope.cfg.type === "media"){ + $scope.cfg.entityType = "Media"; + } + + entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function(data){ + $(data).each(function(i, item){ + item.icon = iconHelper.convertFromLegacyIcon(item.icon); + $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); + }); + }); + + $scope.openMemberPicker =function(){ + var d = dialogService.memberPicker( + { + scope: $scope, + multiPicker: $scope.cfg.multiPicker, + filter: $scope.cfg.filter, + filterCssClass: "not-allowed", + callback: populate} + ); + }; + + + $scope.remove =function(index){ + $scope.renderModel.splice(index, 1); + $scope.ids.splice(index, 1); + $scope.model.value = trim($scope.ids.join(), ","); + }; + + $scope.add =function(item){ + if($scope.ids.indexOf(item.id) < 0){ + item.icon = iconHelper.convertFromLegacyIcon(item.icon); + + $scope.ids.push(item.id); + $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); + $scope.model.value = trim($scope.ids.join(), ","); + } + }; + + $scope.clear = function() { + $scope.model.value = ""; + $scope.renderModel = []; + $scope.ids = []; + }; + + + $scope.sortableOptions = { + update: function(e, ui) { + var r = []; + angular.forEach($scope.renderModel, function(value, key){ + r.push(value.id); + }); + + $scope.ids = r; + $scope.model.value = trim($scope.ids.join(), ","); + } + }; + + + $scope.$on("formSubmitting", function (ev, args) { + $scope.model.value = trim($scope.ids.join(), ","); + }); + + + + function trim(str, chr) { + var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g'); + return str.replace(rgxtrim, ''); + } + + + function populate(data){ + if(angular.isArray(data)){ + $(data).each(function(i, item){ + $scope.add(item); + }); + }else{ + $scope.clear(); + $scope.add(data); + } + } +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html new file mode 100644 index 0000000000..b943145776 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html @@ -0,0 +1,26 @@ +
          + + + + + +
          \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs index e30df16e23..b1cde50a48 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Group Picker", "membergrouppicker")] + [PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", "membergrouppicker")] public class MemberGroupPickerPropertyEditor : PropertyEditor { } From 8b5eefafdba6b13bb0c310e62e890745ce828d7d Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Wed, 30 Oct 2013 13:33:55 +0100 Subject: [PATCH 5/9] Some more member group picker WIP --- .../src/common/services/dialog.service.js | 19 ++++ .../dialogs/membergrouppicker.controller.js | 88 +++++++++++++++++++ .../common/dialogs/membergrouppicker.html | 69 +++++++++++++++ .../membergrouppicker.controller.js | 6 +- .../membergrouppicker/membergrouppicker.html | 4 +- 5 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html diff --git a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js index 842f6ff7c3..c937d30ae7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js @@ -373,6 +373,25 @@ angular.module('umbraco.services') options.show = true; return openDialog(options); }, + + /** + * @ngdoc method + * @name umbraco.services.dialogService#memberGroupPicker + * @methodOf umbraco.services.dialogService + * + * @description + * Opens a member group picker in a modal, the callback returns a object representing the selected member + * @param {Object} options member group picker dialog options object + * @param {$scope} options.scope dialog scope + * @param {$scope} options.multiPicker should the tree pick one or multiple members before returning + * @param {Function} options.callback callback function + * @returns {Object} modal object + */ + memberGroupPicker: function (options) { + options.template = 'views/common/dialogs/memberGroupPicker.html'; + options.show = true; + return openDialog(options); + }, /** * @ngdoc method diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js new file mode 100644 index 0000000000..40d5e1d7bb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js @@ -0,0 +1,88 @@ +//used for the member picker dialog +angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerController", + function($scope, eventsService, entityResource, searchService, $log) { + var dialogOptions = $scope.$parent.dialogOptions; + $scope.dialogTreeEventHandler = $({}); + $scope.results = []; + + /** Method used for selecting a node */ + function select(text, id, entity) { + + $scope.showSearch = false; + $scope.results = []; + $scope.term = ""; + $scope.oldTerm = undefined; + + if (dialogOptions.multiPicker) { + $scope.select(id); + } + else { + //if an entity has been passed in, use it + if (entity) { + $scope.submit(entity); + } + else { + //otherwise we have to get it from the server + entityResource.getById(id, "Member").then(function (ent) { + $scope.submit(ent); + }); + } + } + } + + $scope.performSearch = function() { + if ($scope.term) { + if ($scope.oldTerm !== $scope.term) { + $scope.results = []; + searchService.searchMembers({ term: $scope.term }).then(function(data) { + $scope.results = data; + }); + $scope.showSearch = true; + $scope.oldTerm = $scope.term; + } + } + else { + $scope.oldTerm = ""; + $scope.showSearch = false; + $scope.results = []; + } + }; + + /** method to select a search result */ + $scope.selectResult = function(result) { + //since result = an entity, we'll pass it in so we don't have to go back to the server + select(result.name, result.id, result); + }; + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args) { + args.event.preventDefault(); + args.event.stopPropagation(); + + if (args.node.nodeType === "member-folder") { + return; + } + + eventsService.publish("Umbraco.Dialogs.MemberPickerController.Select", args).then(function(a) { + + //This is a tree node, so we don't have an entity to pass in, it will need to be looked up + //from the server in this method. + select(a.node.name, a.node.id); + + if (dialogOptions && dialogOptions.multipicker) { + + var c = $(a.event.target.parentElement); + if (!a.node.selected) { + a.node.selected = true; + c.find("i.umb-tree-icon").hide() + .after(""); + } + else { + a.node.selected = false; + c.find(".temporary").remove(); + c.find("i.umb-tree-icon").show(); + } + } + }); + + }); + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html new file mode 100644 index 0000000000..315a1a2673 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html @@ -0,0 +1,69 @@ +
          +
          +
          + +
          +
          + + + +
          \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js index a44e5c3385..a9cb3154f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js @@ -1,7 +1,7 @@ //this controller simply tells the dialogs service to open a memberPicker window //with a specified callback, this callback will receive an object with a selection on it angular.module('umbraco') -.controller("Umbraco.PropertyEditors.MemberPickerController", +.controller("Umbraco.PropertyEditors.MemberGroupPickerController", function($scope, dialogService, entityResource, $log, iconHelper){ $scope.renderModel = []; @@ -25,8 +25,8 @@ angular.module('umbraco') }); }); - $scope.openMemberPicker =function(){ - var d = dialogService.memberPicker( + $scope.openMemberGroupPicker =function(){ + var d = dialogService.memberGroupPicker( { scope: $scope, multiPicker: $scope.cfg.multiPicker, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html index b943145776..60b90c9c62 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.html @@ -1,4 +1,4 @@ -
          +
          • - + Add
          • From 21f0e60061e9f0420b23ee8ddc4093f1e94f366d Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Wed, 30 Oct 2013 13:41:29 +0100 Subject: [PATCH 6/9] More member group picker WIP --- .../dialogs/membergrouppicker.controller.js | 23 +---------- .../common/dialogs/membergrouppicker.html | 38 ++----------------- 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js index 40d5e1d7bb..e3c8f4fb85 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js @@ -30,23 +30,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle } } - $scope.performSearch = function() { - if ($scope.term) { - if ($scope.oldTerm !== $scope.term) { - $scope.results = []; - searchService.searchMembers({ term: $scope.term }).then(function(data) { - $scope.results = data; - }); - $scope.showSearch = true; - $scope.oldTerm = $scope.term; - } - } - else { - $scope.oldTerm = ""; - $scope.showSearch = false; - $scope.results = []; - } - }; + /** method to select a search result */ $scope.selectResult = function(result) { @@ -58,11 +42,8 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle args.event.preventDefault(); args.event.stopPropagation(); - if (args.node.nodeType === "member-folder") { - return; - } - eventsService.publish("Umbraco.Dialogs.MemberPickerController.Select", args).then(function(a) { + eventsService.publish("Umbraco.Dialogs.MemberGroupPickerController.Select", args).then(function(a) { //This is a tree node, so we don't have an entity to pass in, it will need to be looked up //from the server in this method. diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html index 315a1a2673..6a8a0e3551 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html @@ -1,45 +1,13 @@
            -
            -
            - -
            -
            +