From 6bcace4609a27fc864b873bf66c66a8c2468ce87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= <danxuliu@gmail.com>
Date: Fri, 9 Jun 2017 09:09:41 +0200
Subject: [PATCH] Extract toggle visibility of a SystemTagsInfoView to its own
 view
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The SystemTagsInfoViewToggleView is a basic view that renders a label
that, when clicked, toggles the visibility of an associated
SystemTagsInfoView.

In order to keep the view parent agnostic its attachment and detachment
to/from the MainfFileInfoView is done in the FilesPlugin.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
---
 apps/systemtags/js/filesplugin.js             |  16 ++-
 apps/systemtags/js/merged.json                |   3 +-
 apps/systemtags/js/systemtagsinfoview.js      |  24 ----
 .../js/systemtagsinfoviewtoggleview.js        | 103 ++++++++++++++++++
 .../js/systemtagsinfoviewtoggleviewSpec.js    |  93 ++++++++++++++++
 tests/karma.config.js                         |   1 +
 6 files changed, 214 insertions(+), 26 deletions(-)
 create mode 100644 apps/systemtags/js/systemtagsinfoviewtoggleview.js
 create mode 100644 apps/systemtags/tests/js/systemtagsinfoviewtoggleviewSpec.js

diff --git a/apps/systemtags/js/filesplugin.js b/apps/systemtags/js/filesplugin.js
index 229d64da9d5..fc2a227b5be 100644
--- a/apps/systemtags/js/filesplugin.js
+++ b/apps/systemtags/js/filesplugin.js
@@ -36,7 +36,21 @@
 
 			_.each(fileList.getRegisteredDetailViews(), function(detailView) {
 				if (detailView instanceof OCA.Files.MainFileInfoDetailView) {
-					systemTagsInfoView.setMainFileInfoView(detailView);
+					var systemTagsInfoViewToggleView =
+						new OCA.SystemTags.SystemTagsInfoViewToggleView({
+							systemTagsInfoView: systemTagsInfoView
+						});
+					systemTagsInfoViewToggleView.render();
+
+					// The toggle view element is detached before the
+					// MainFileInfoDetailView is rendered to prevent its event
+					// handlers from being removed.
+					systemTagsInfoViewToggleView.listenTo(detailView, 'pre-render', function() {
+						systemTagsInfoViewToggleView.$el.detach();
+					});
+					systemTagsInfoViewToggleView.listenTo(detailView, 'post-render', function() {
+						detailView.$el.find('.file-details').append(systemTagsInfoViewToggleView.$el);
+					});
 
 					return;
 				}
diff --git a/apps/systemtags/js/merged.json b/apps/systemtags/js/merged.json
index 0262077498a..632abf6777e 100644
--- a/apps/systemtags/js/merged.json
+++ b/apps/systemtags/js/merged.json
@@ -2,5 +2,6 @@
   "app.js",
   "systemtagsfilelist.js",
   "filesplugin.js",
-  "systemtagsinfoview.js"
+  "systemtagsinfoview.js",
+  "systemtagsinfoviewtoggleview.js"
 ]
diff --git a/apps/systemtags/js/systemtagsinfoview.js b/apps/systemtags/js/systemtagsinfoview.js
index d42bf18761b..1bf7287342f 100644
--- a/apps/systemtags/js/systemtagsinfoview.js
+++ b/apps/systemtags/js/systemtagsinfoview.js
@@ -37,8 +37,6 @@
 		 */
 		_inputView: null,
 
-		_toggleHandle: null,
-
 		initialize: function(options) {
 			var self = this;
 			options = options || {};
@@ -60,18 +58,6 @@
 
 			this._inputView.on('select', this._onSelectTag, this);
 			this._inputView.on('deselect', this._onDeselectTag, this);
-
-			this._toggleHandle = $('<span>').addClass('tag-label').text(t('systemtags', 'Tags'));
-			this._toggleHandle.prepend($('<span>').addClass('icon icon-tag'));
-
-			this._toggleHandle.on('click', function () {
-				if (self.isVisible()) {
-					self.hide();
-				} else {
-					self.show();
-					self.openDropdown();
-				}
-			});
 		},
 
 		/**
@@ -121,15 +107,6 @@
 			this.selectedTagsCollection.remove(tagId);
 		},
 
-		setMainFileInfoView: function(mainFileInfoView) {
-			this.listenTo(mainFileInfoView, 'pre-render', function() {
-				this._toggleHandle.detach();
-			});
-			this.listenTo(mainFileInfoView, 'post-render', function() {
-				mainFileInfoView.$el.find('.file-details').append(this._toggleHandle);
-			});
-		},
-
 		setFileInfo: function(fileInfo) {
 			var self = this;
 			if (!this._rendered) {
@@ -185,7 +162,6 @@
 
 		remove: function() {
 			this._inputView.remove();
-			this._toggleHandle.remove();
 		}
 	});
 
diff --git a/apps/systemtags/js/systemtagsinfoviewtoggleview.js b/apps/systemtags/js/systemtagsinfoviewtoggleview.js
new file mode 100644
index 00000000000..13a48e49cfb
--- /dev/null
+++ b/apps/systemtags/js/systemtagsinfoviewtoggleview.js
@@ -0,0 +1,103 @@
+/**
+ *
+ * @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+(function(OCA) {
+
+	var TEMPLATE =
+		'<span class="icon icon-tag"/>' + t('systemtags', 'Tags');
+
+	/**
+	 * @class OCA.SystemTags.SystemTagsInfoViewToggleView
+	 * @classdesc
+	 *
+	 * View to toggle the visibility of a SystemTagsInfoView.
+	 *
+	 * This toggle view must be explicitly rendered before it is used.
+	 */
+	var SystemTagsInfoViewToggleView = OC.Backbone.View.extend(
+		/** @lends OC.Backbone.View.prototype */ {
+
+		tagName: 'span',
+
+		className: 'tag-label',
+
+		events: {
+			'click': 'click'
+		},
+
+		/**
+		 * @type OCA.SystemTags.SystemTagsInfoView
+		 */
+		_systemTagsInfoView: null,
+
+		template: function(data) {
+			if (!this._template) {
+				this._template = Handlebars.compile(TEMPLATE);
+			}
+			return this._template(data);
+		},
+
+		/**
+		 * Initialize this toggle view.
+		 *
+		 * The options must provide a systemTagsInfoView parameter that
+		 * references the SystemTagsInfoView to associate to this toggle view.
+		 */
+		initialize: function(options) {
+			var self = this;
+			options = options || {};
+
+			this._systemTagsInfoView = options.systemTagsInfoView;
+			if (!this._systemTagsInfoView) {
+				throw 'Missing required parameter "systemTagsInfoView"';
+			}
+		},
+
+		/**
+		 * Toggles the visibility of the associated SystemTagsInfoView.
+		 *
+		 * When the systemTagsInfoView is shown its dropdown is also opened.
+		 */
+		click: function() {
+			if (this._systemTagsInfoView.isVisible()) {
+				this._systemTagsInfoView.hide();
+			} else {
+				this._systemTagsInfoView.show();
+				this._systemTagsInfoView.openDropdown();
+			}
+		},
+
+		/**
+		 * Renders this toggle view.
+		 *
+		 * @return OCA.SystemTags.SystemTagsInfoViewToggleView this object.
+		 */
+		render: function() {
+			this.$el.html(this.template());
+
+			return this;
+		},
+
+	});
+
+	OCA.SystemTags.SystemTagsInfoViewToggleView = SystemTagsInfoViewToggleView;
+
+})(OCA);
diff --git a/apps/systemtags/tests/js/systemtagsinfoviewtoggleviewSpec.js b/apps/systemtags/tests/js/systemtagsinfoviewtoggleviewSpec.js
new file mode 100644
index 00000000000..5e6c2c820e9
--- /dev/null
+++ b/apps/systemtags/tests/js/systemtagsinfoviewtoggleviewSpec.js
@@ -0,0 +1,93 @@
+/**
+ *
+ * @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+describe('OCA.SystemTags.SystemTagsInfoViewToggleView', function () {
+
+	var systemTagsInfoView;
+	var view;
+
+	beforeEach(function() {
+		systemTagsInfoView = new OCA.SystemTags.SystemTagsInfoView();
+		view = new OCA.SystemTags.SystemTagsInfoViewToggleView({ systemTagsInfoView: systemTagsInfoView });
+	});
+
+	afterEach(function() {
+		view.remove();
+		systemTagsInfoView.remove();
+	});
+
+	describe('initialize', function() {
+		it('fails if a "systemTagsInfoView" parameter is not provided', function() {
+			var constructor = function() {
+				return new OCA.SystemTags.SystemTagsInfoViewToggleView({});
+			}
+
+			expect(constructor).toThrow();
+		});
+	});
+
+	describe('click on element', function() {
+
+		var isVisibleStub;
+		var showStub;
+		var hideStub;
+		var openDropdownStub;
+
+		beforeEach(function() {
+			isVisibleStub = sinon.stub(systemTagsInfoView, 'isVisible');
+			showStub = sinon.stub(systemTagsInfoView, 'show');
+			hideStub = sinon.stub(systemTagsInfoView, 'hide');
+			openDropdownStub = sinon.stub(systemTagsInfoView, 'openDropdown');
+		});
+
+		afterEach(function() {
+			isVisibleStub.restore();
+			showStub.restore();
+			hideStub.restore();
+			openDropdownStub.restore();
+		});
+
+		it('shows a not visible SystemTagsInfoView', function() {
+			isVisibleStub.returns(false);
+
+			view.$el.click();
+
+			expect(isVisibleStub.calledOnce).toBeTruthy();
+			expect(showStub.calledOnce).toBeTruthy();
+			expect(openDropdownStub.calledOnce).toBeTruthy();
+			expect(openDropdownStub.calledAfter(showStub)).toBeTruthy();
+			expect(hideStub.notCalled).toBeTruthy();
+		});
+
+		it('hides a visible SystemTagsInfoView', function() {
+			isVisibleStub.returns(true);
+
+			view.$el.click();
+
+			expect(isVisibleStub.calledOnce).toBeTruthy();
+			expect(hideStub.calledOnce).toBeTruthy();
+			expect(showStub.notCalled).toBeTruthy();
+			expect(openDropdownStub.notCalled).toBeTruthy();
+		});
+
+	});
+
+});
diff --git a/tests/karma.config.js b/tests/karma.config.js
index 62b5171dcd1..07dc2965346 100644
--- a/tests/karma.config.js
+++ b/tests/karma.config.js
@@ -102,6 +102,7 @@ module.exports = function(config) {
 					// need to enforce loading order...
 					'apps/systemtags/js/app.js',
 					'apps/systemtags/js/systemtagsinfoview.js',
+					'apps/systemtags/js/systemtagsinfoviewtoggleview.js',
 					'apps/systemtags/js/systemtagsfilelist.js',
 					'apps/systemtags/js/filesplugin.js'
 				],
-- 
GitLab