From b9099435cb6535db835d25361e7b706b85744b20 Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Mon, 22 Apr 2013 16:05:45 +0200 Subject: add undo for feed and folder deletion, fix #56 --- js/app/directives/undonotification.coffee | 52 +++++++++++++ .../businesslayer/feedbusinesslayer.coffee | 21 ++++-- .../businesslayer/folderbusinesslayer.coffee | 19 +++-- js/app/services/models/feedmodel.coffee | 3 +- js/app/services/undoqueue.coffee | 86 ++++++++++++++++++++++ 5 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 js/app/directives/undonotification.coffee create mode 100644 js/app/services/undoqueue.coffee (limited to 'js/app') diff --git a/js/app/directives/undonotification.coffee b/js/app/directives/undonotification.coffee new file mode 100644 index 000000000..5e30af169 --- /dev/null +++ b/js/app/directives/undonotification.coffee @@ -0,0 +1,52 @@ +### + +ownCloud - News + +@author Bernhard Posselt +@copyright 2012 Bernhard Posselt nukeawhale@gmail.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU AFFERO GENERAL PUBLIC LICENSE for more details. + +You should have received a copy of the GNU Affero General Public +License along with this library. If not, see . + +### + +angular.module('News').directive 'undoNotification', ['$rootScope', +($rootScope) -> + + return (scope, elm, attr) -> + + elm.click -> + $(@).fadeOut() + + scope.$on 'notUndone', -> + $(elm).fadeOut() + + undo = -> + caption = '' + + link = $(elm).find('a') + link.click -> + undo() + $rootScope.$apply() + elm.fadeOut() + + scope.getCaption = -> + return caption + + scope.$on 'undoMessage', (scope, data) -> + undo = data.undoCallback + caption = data.caption + elm.fadeIn().css("display","inline") + + +] \ No newline at end of file diff --git a/js/app/services/businesslayer/feedbusinesslayer.coffee b/js/app/services/businesslayer/feedbusinesslayer.coffee index 9d2f37390..93f89ad31 100644 --- a/js/app/services/businesslayer/feedbusinesslayer.coffee +++ b/js/app/services/businesslayer/feedbusinesslayer.coffee @@ -23,14 +23,16 @@ License along with this library. If not, see . angular.module('News').factory 'FeedBusinessLayer', ['_BusinessLayer', 'ShowAll', 'Persistence', 'ActiveFeed', 'FeedType', -'ItemModel', 'FeedModel', 'NewLoading', '_ExistsError', 'Utils', +'ItemModel', 'FeedModel', 'NewLoading', '_ExistsError', 'Utils', '$rootScope', +'UndoQueue', (_BusinessLayer, ShowAll, Persistence, ActiveFeed, FeedType, ItemModel, -FeedModel, NewLoading, _ExistsError, Utils) -> +FeedModel, NewLoading, _ExistsError, Utils, $rootScope, UndoQueue) -> class FeedBusinessLayer extends _BusinessLayer constructor: (@_showAll, @_feedModel, persistence, activeFeed, feedType, - itemModel, @_newLoading, @_utils) -> + itemModel, @_newLoading, @_utils, @_$rootScope, + @_undoQueue) -> super(activeFeed, persistence, itemModel, feedType.Feed) @_feedType = feedType @@ -52,8 +54,14 @@ FeedModel, NewLoading, _ExistsError, Utils) -> delete: (feedId) -> - @_feedModel.removeById(feedId) - @_persistence.deleteFeed(feedId) + feed = @_feedModel.removeById(feedId) + callback = => + @_persistence.deleteFeed(feedId) + + undoCallback = => + @_feedModel.add(feed) + + @_undoQueue.add(feed.title, callback, 10*1000, undoCallback) markFeedRead: (feedId) -> @@ -185,6 +193,7 @@ FeedModel, NewLoading, _ExistsError, Utils) -> return new FeedBusinessLayer(ShowAll, FeedModel, Persistence, ActiveFeed, - FeedType, ItemModel, NewLoading, Utils) + FeedType, ItemModel, NewLoading, Utils, + $rootScope, UndoQueue) ] \ No newline at end of file diff --git a/js/app/services/businesslayer/folderbusinesslayer.coffee b/js/app/services/businesslayer/folderbusinesslayer.coffee index d19796d85..e35866f21 100644 --- a/js/app/services/businesslayer/folderbusinesslayer.coffee +++ b/js/app/services/businesslayer/folderbusinesslayer.coffee @@ -24,22 +24,31 @@ License along with this library. If not, see . angular.module('News').factory 'FolderBusinessLayer', ['_BusinessLayer', 'FolderModel', 'FeedBusinessLayer', 'Persistence', 'FeedType', 'ActiveFeed', 'ItemModel', 'ShowAll', '_ExistsError', 'OPMLParser', +'UndoQueue', (_BusinessLayer, FolderModel, FeedBusinessLayer, Persistence, FeedType, -ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser) -> +ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) -> class FolderBusinessLayer extends _BusinessLayer constructor: (@_folderModel, @_feedBusinessLayer, @_showAll, activeFeed, - persistence, @_feedType, itemModel, @_opmlParser) -> + persistence, @_feedType, itemModel, @_opmlParser, + @_undoQueue) -> super(activeFeed, persistence, itemModel, @_feedType.Folder) getById: (folderId) -> return @_folderModel.getById(folderId) + delete: (folderId) -> - @_folderModel.removeById(folderId) - @_persistence.deleteFolder(folderId) + folder = @_folderModel.removeById(folderId) + callback = => + @_persistence.deleteFolder(folderId) + + undoCallback = => + @_folderModel.add(folder) + + @_undoQueue.add(folder.name, callback, 10*1000, undoCallback) hasFeeds: (folderId) -> @@ -155,6 +164,6 @@ ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser) -> return new FolderBusinessLayer(FolderModel, FeedBusinessLayer, ShowAll, ActiveFeed, Persistence, FeedType, ItemModel, - OPMLParser) + OPMLParser, UndoQueue) ] \ No newline at end of file diff --git a/js/app/services/models/feedmodel.coffee b/js/app/services/models/feedmodel.coffee index 4c925b94c..bddd647d3 100644 --- a/js/app/services/models/feedmodel.coffee +++ b/js/app/services/models/feedmodel.coffee @@ -40,7 +40,8 @@ angular.module('News').factory 'FeedModel', if data.faviconLink == null data.faviconLink = 'url(' + @_utils.imagePath('news', 'rss.svg') + ')' - else if angular.isDefined(data.faviconLink) + else if angular.isDefined(data.faviconLink) and + data.faviconLink.indexOf('url(') != 0 data.faviconLink = 'url(' + data.faviconLink + ')' ### We want to add a feed on the client side before diff --git a/js/app/services/undoqueue.coffee b/js/app/services/undoqueue.coffee new file mode 100644 index 000000000..30418bacf --- /dev/null +++ b/js/app/services/undoqueue.coffee @@ -0,0 +1,86 @@ +### + +ownCloud - App Framework + +@author Bernhard Posselt +@copyright 2012 Bernhard Posselt nukeawhale@gmail.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU AFFERO GENERAL PUBLIC LICENSE for more details. + +You should have received a copy of the GNU Affero General Public +License along with this library. If not, see . + +### + +# A class which follows the command pattern +# Can be used for actions that need need to be able to undo like folder deletion +angular.module('News').factory 'UndoQueue', +['$timeout', '$rootScope', +($timeout, $rootScope) -> + + class UndoQueue + + constructor: (@_$timeout, @_$rootScope) -> + @_queue = [] + + + add: (@_caption, @_callback, @_timeout=0, @_undoCallback=null) -> + ### + @_caption the caption which indentifies the item + @_callback function the callback which should be executed when it was + not undone, this will usually be a request to the server to finally + delete something + @_timeout int the timeout after the callback should be executed + defaults to 0 + @_undoCallback function the function which should be executed when + an command has been canceled. Usually this will add back a deleted + object back to the interface, defaults to an empty function + ### + @_executeAll() + + command = + _undoCallback: @_undoCallback or= -> + _callback: @_callback + execute: => + command._callback() + undo: => + command._undoCallback() + @_$timeout.cancel(command.promise) + @_queue = [] + promise: @_$timeout => + command.execute() + @_$rootScope.$broadcast('notUndone') + , @_timeout + + data = + undoCallback: command.undo + caption: @_caption + + @_$rootScope.$broadcast 'undoMessage', data + + @_queue.push(command) + + + _executeAll: -> + ### + Executes the callback before the timeout has run out + This is useful to execute all remaining commands if a new command is + added + ### + for command in @_queue + @_$timeout.cancel(command.promise) + command.execute() + @_queue = [] + + + return new UndoQueue($timeout, $rootScope) + +] \ No newline at end of file -- cgit v1.2.3