diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs
index 063bb7b27f..203c27fc2d 100644
--- a/src/Umbraco.Core/Constants-PropertyEditors.cs
+++ b/src/Umbraco.Core/Constants-PropertyEditors.cs
@@ -197,6 +197,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.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/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/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js
index ab7fa18867..78258427d2 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js
@@ -10,7 +10,7 @@
* signs the user in
*/
var d = new Date();
- var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderfull Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday");
+ var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderful Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday");
$scope.today = weekday[d.getDay()];
$scope.errorMsg = "";
@@ -56,4 +56,4 @@
}
});
};
-});
\ No newline at end of file
+});
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..d7d85a4142
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js
@@ -0,0 +1,55 @@
+//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 {
+ $scope.submit(id);
+
+ }
+ }
+
+
+ $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args) {
+ args.event.preventDefault();
+ args.event.stopPropagation();
+
+
+ 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.
+ 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..6a8a0e3551
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.html
@@ -0,0 +1,37 @@
+
\ No newline at end of file
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
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:
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..5cd12cc0cc
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/membergrouppicker/membergrouppicker.controller.js
@@ -0,0 +1,88 @@
+//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.MemberGroupPickerController",
+
+ function($scope, dialogService, entityResource, $log, iconHelper){
+ $scope.renderModel = [];
+ $scope.ids = $scope.model.value.split(',');
+
+ $scope.cfg = {multiPicker: false, entityType: "MemberGroup", type: "membergroup", treeAlias: "memberGroup", filter: ""};
+ if($scope.model.config){
+ $scope.cfg = angular.extend($scope.cfg, $scope.model.config);
+ }
+
+
+
+ $scope.openMemberGroupPicker =function(){
+ var d = dialogService.memberGroupPicker(
+ {
+ 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) < 0){
+ //item.icon = iconHelper.convertFromLegacyIcon(item.icon);
+
+ $scope.ids.push(item);
+ $scope.renderModel.push({ name: item, id: item, icon: 'icon-users' });
+ $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..60b90c9c62
--- /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
new file mode 100644
index 0000000000..b1cde50a48
--- /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.MemberGroupPickerAlias, "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 0b98ea3d80..f300c924b3 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -345,6 +345,7 @@
+