Updates eventsService to actually be able to handle async callbacks with promises - though i'm really not sure when this will effectively be used. It no longer returns a promise - since that was a 'false promise' anyways . lol.

This commit is contained in:
Shannon
2013-11-14 13:27:53 +11:00
parent 0b1eb4b42c
commit 6474b2b045
11 changed files with 283 additions and 248 deletions

View File

@@ -1,45 +1,54 @@
/* pubsub - based on https://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js*/
function eventsService($q) {
var cache = {};
/** Used to broadcast and listen for global events and allow the ability to add async listeners to the callbacks */
function eventsService($q, $rootScope) {
return {
/** raise an event with a given name, returns an array of promises for each listener */
publish: function (name, args) {
return {
publish: function(){
var args = [].splice.call(arguments,0);
var topic = args[0];
var deferred = $q.defer();
args.splice(0,1);
//there are no listeners
if (!$rootScope.$$listeners[name]) {
return [];
}
if(cache[topic]){
$.each(cache[topic], function() {
this.apply(null, args || []);
});
deferred.resolve.apply(null, args);
}else{
deferred.resolve.apply(null, args);
}
//setup a deferred promise for each listener
var deferred = [];
for (var i = 0; i < $rootScope.$$listeners[name].length; i++) {
deferred.push($q.defer());
}
//create a new event args object to pass to the
// $broadcast containing methods that will allow listeners
// to return data in an async if required
var eventArgs = {
args: args,
reject: function (a) {
deferred.pop().reject(a);
},
resolve: function (a) {
deferred.pop().resolve(a);
}
};
//send the event
$rootScope.$broadcast(name, eventArgs);
//return an array of promises
var promises = _.map(deferred, function(p) {
return p.promise;
});
return promises;
},
return deferred.promise;
},
subscribe: function(topic, callback) {
if(!cache[topic]) {
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback];
/** subscribe to a method, or use scope.$on = same thing */
subscribe: function(name, callback) {
return $rootScope.$on(name, callback);
},
/** pass in the result of subscribe to this method, or just call the method returned from subscribe to unsubscribe */
unsubscribe: function(handle) {
var t = handle[0];
if(cache[t]){
$.each(cache[t], function(idx){
if(this === handle[1]){
cache[t].splice(idx, 1);
}
});
}
if (angular.isFunction(handle)) {
handle();
}
}
};

View File

@@ -43,34 +43,33 @@ angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController",
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.ContentPickerController.Select", args).then(function(args){
if(dialogOptions && dialogOptions.multiPicker){
var c = $(args.event.target.parentElement);
if(!args.node.selected){
args.node.selected = true;
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if(icon.length > 0){
icon.hide().after(temp);
}else{
c.prepend(temp);
}
}else{
args.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
eventsService.publish("Umbraco.Dialogs.ContentPickerController.Select", args);
if (dialogOptions && dialogOptions.multiPicker) {
$scope.select(args.node);
var c = $(args.event.target.parentElement);
if (!args.node.selected) {
args.node.selected = true;
}else{
$scope.submit(args.node);
}
});
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if (icon.length > 0) {
icon.hide().after(temp);
} else {
c.prepend(temp);
}
} else {
args.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
$scope.select(args.node);
} else {
$scope.submit(args.node);
}
});
});

View File

@@ -30,40 +30,40 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.LinkPickerController.Select", args).then(function(args){
var c = $(args.event.target.parentElement);
eventsService.publish("Umbraco.Dialogs.LinkPickerController.Select", args);
var c = $(args.event.target.parentElement);
//renewing
if(args.node !== $scope.target){
if($scope.selectedEl){
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
//renewing
if (args.node !== $scope.target) {
if ($scope.selectedEl) {
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
$scope.selectedEl = c;
$scope.target = args.node;
$scope.target.name = args.node.name;
$scope.selectedEl = c;
$scope.target = args.node;
$scope.target.name = args.node.name;
$scope.selectedEl.find("i.umb-tree-icon")
.hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
if(args.node.id < 0){
$scope.target.url = "/";
}else{
contentResource.getNiceUrl(args.node.id).then(function(url){
$scope.target.url = angular.fromJson(url);
});
}
}else{
$scope.target = undefined;
//resetting
if($scope.selectedEl){
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
}
});
$scope.selectedEl.find("i.umb-tree-icon")
.hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
if (args.node.id < 0) {
$scope.target.url = "/";
} else {
contentResource.getNiceUrl(args.node.id).then(function (url) {
$scope.target.url = angular.fromJson(url);
});
}
} else {
$scope.target = undefined;
//resetting
if ($scope.selectedEl) {
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
}
});
});

View File

@@ -77,15 +77,16 @@ angular.module("umbraco")
$scope.gotoFolder(image.id);
}
else if (image.contentTypeAlias.toLowerCase() == 'image') {
eventsService.publish("Umbraco.Dialogs.MediaPickerController.Select", image).then(function (img) {
if (dialogOptions && dialogOptions.multiPicker) {
$scope.select(img);
img.cssclass = ($scope.dialogData.selection.indexOf(img) > -1) ? "selected" : "";
}
else {
$scope.submit(img);
}
});
eventsService.publish("Umbraco.Dialogs.MediaPickerController.Select", image);
if (dialogOptions && dialogOptions.multiPicker) {
$scope.select(image);
image.cssclass = ($scope.dialogData.selection.indexOf(image) > -1) ? "selected" : "";
}
else {
$scope.submit(image);
}
}
ev.preventDefault();
@@ -98,14 +99,14 @@ angular.module("umbraco")
}
else if (image.contentTypeAlias.toLowerCase() == 'image') {
eventsService.publish("Umbraco.Dialogs.MediaPickerController.Select", image).then(function(img) {
if (dialogOptions && dialogOptions.multiPicker) {
$scope.select(img);
}
else {
$scope.submit(img);
}
});
eventsService.publish("Umbraco.Dialogs.MediaPickerController.Select", image);
if (dialogOptions && dialogOptions.multiPicker) {
$scope.select(image);
}
else {
$scope.submit(image);
}
}
};

View File

@@ -40,29 +40,28 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.MemberGroupPickerController.Select", args).then(function(a) {
eventsService.publish("Umbraco.Dialogs.MemberGroupPickerController.Select", args);
//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(args.node.name, args.node.id);
//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.multiPicker) {
var c = $(a.event.target.parentElement);
if (!a.node.selected) {
a.node.selected = true;
c.find("i.umb-tree-icon").hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
}
else {
remove(a.node.name, a.node.id);
a.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
if (dialogOptions.multiPicker) {
var c = $(args.event.target.parentElement);
if (!args.node.selected) {
args.node.selected = true;
c.find("i.umb-tree-icon").hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
}
});
else {
remove(args.node.name, args.node.id);
args.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
}
});
});

View File

@@ -62,27 +62,26 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberPickerController",
return;
}
eventsService.publish("Umbraco.Dialogs.MemberPickerController.Select", args).then(function(a) {
eventsService.publish("Umbraco.Dialogs.MemberPickerController.Select", args);
//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(args.node.name, args.node.id);
//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) {
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("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
}
else {
a.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
var c = $(args.event.target.parentElement);
if (!args.node.selected) {
args.node.selected = true;
c.find("i.umb-tree-icon").hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
}
});
else {
args.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
}
});
});

View File

@@ -167,35 +167,35 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.TreePickerController.Select", args).then(function (a) {
if (a.node.filtered) {
return;
}
eventsService.publish("Umbraco.Dialogs.TreePickerController.Select", args);
if (args.node.filtered) {
return;
}
//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);
//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(args.node.name, args.node.id);
//ui...
if ($scope.multiPicker) {
var c = $(a.event.target.parentElement);
if (!a.node.selected) {
a.node.selected = true;
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if (icon.length > 0) {
icon.hide().after(temp);
}
else {
c.prepend(temp);
}
}
else {
a.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
}
});
//ui...
if ($scope.multiPicker) {
var c = $(args.event.target.parentElement);
if (!args.node.selected) {
args.node.selected = true;
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if (icon.length > 0) {
icon.hide().after(temp);
}
else {
c.prepend(temp);
}
}
else {
args.node.selected = false;
c.find(".temporary").remove();
c.find("i.umb-tree-icon").show();
}
}
});
});

View File

@@ -10,24 +10,25 @@ angular.module("umbraco")
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Editors.Content.CopyController.Select", args).then(function(args){
var c = $(args.event.target.parentElement);
if($scope.selectedEl){
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
eventsService.publish("Umbraco.Editors.Content.CopyController.Select", args);
var c = $(args.event.target.parentElement);
if ($scope.selectedEl) {
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if (icon.length > 0) {
icon.hide().after(temp);
} else {
c.prepend(temp);
}
$scope.target = args.node;
$scope.selectedEl = c;
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if(icon.length > 0){
icon.hide().after(temp);
}else{
c.prepend(temp);
}
$scope.target = args.node;
$scope.selectedEl = c;
});
});
$scope.copy = function(){

View File

@@ -10,26 +10,26 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Editors.Content.MoveController.Select", args).then(function(args){
var c = $(args.event.target.parentElement);
if($scope.selectedEl){
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
eventsService.publish("Umbraco.Editors.Content.MoveController.Select", args);
var c = $(args.event.target.parentElement);
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if(icon.length > 0){
icon.hide().after(temp);
}else{
c.prepend(temp);
}
if ($scope.selectedEl) {
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
$scope.target = args.node;
$scope.selectedEl = c;
});
var temp = "<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>";
var icon = c.find("i.umb-tree-icon");
if (icon.length > 0) {
icon.hide().after(temp);
} else {
c.prepend(temp);
}
$scope.target = args.node;
$scope.selectedEl = c;
});
$scope.move = function(){

View File

@@ -10,19 +10,20 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Editors.Media.MoveController.Select", args).then(function(args){
var c = $(args.event.target.parentElement);
if($scope.selectedEl){
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
eventsService.publish("Umbraco.Editors.Media.MoveController.Select", args);
var c = $(args.event.target.parentElement);
if ($scope.selectedEl) {
$scope.selectedEl.find(".temporary").remove();
$scope.selectedEl.find("i.umb-tree-icon").show();
}
c.find("i.umb-tree-icon").hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
$scope.target = args.node;
$scope.selectedEl = c;
});
c.find("i.umb-tree-icon").hide()
.after("<i class='icon umb-tree-icon sprTree icon-check blue temporary'></i>");
$scope.target = args.node;
$scope.selectedEl = c;
});
$scope.move = function(){

View File

@@ -17,41 +17,67 @@ describe('angular event tests', function () {
val: ""
};
eventsService.subscribe("testEvent", function (args) {
args.val = "changed";
eventsService.subscribe("testEvent", function (e, args) {
args.args.val = "changed";
});
eventsService.publish("testEvent", eventArgs).then(function (args) {
expect(eventArgs.val).toBe("changed");
expect(args.val).toBe("changed");
});
eventsService.publish("testEvent", eventArgs);
expect(eventArgs.val).toBe("changed");
$rootScope.$digest();
});
//NOTE: This will fail because our eventsService doesn't actually wait for async events to finish.
it('will handle 2 non async process', function () {
var eventArgs = {
val: ""
};
//it('will handle one async process', function () {
// var eventArgs = {
// val: ""
// };
eventsService.subscribe("testEvent", function (e, args) {
args.args.val = "changed";
});
eventsService.subscribe("testEvent", function (e, args) {
args.args.val = "changed1";
});
// eventsService.subscribe("testEvent", function (args) {
// $timeout(function() {
// args.val = "changed";
// }, 1000);
// });
eventsService.publish("testEvent", eventArgs);
// eventsService.publish("testEvent", eventArgs).then(function (args) {
// expect(eventArgs.val).toBe("changed");
// expect(args.val).toBe("changed");
// });
expect(eventArgs.val).toBe("changed1");
// $rootScope.$digest();
// $timeout.flush();
//});
$rootScope.$digest();
});
it('will handle one async process', function () {
var eventArgs = {
val: ""
};
eventsService.subscribe("testEvent", function (e, msg) {
$timeout(function () {
msg.args.val = "changed";
//NOTE: We could resolve anything here
msg.resolve(msg.args);
}, 1000);
});
var promises = eventsService.publish("testEvent", eventArgs);
//this won't be changed yet
expect(eventArgs.val).toBe("");
promises[0].then(function (args) {
console.log("WOOT");
expect(args.val).toBe("changed");
expect(eventArgs.val).toBe("changed");
});
$rootScope.$digest();
$timeout.flush();
});
it('will wait to execute after all handlers', function () {
//NOTE: This logic has been merged into the eventsService
it('POC will wait to execute after all handlers', function () {
//assign multiple listeners