Completed
Pull Request — master (#6)
by Janis
04:05
created

js/ocrview.js   B

Complexity

Total Complexity 44
Complexity/F 1.63

Size

Lines of Code 242
Function Count 27

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
wmc 44
c 1
b 0
f 0
nc 32
mnd 2
bc 46
fnc 27
dl 0
loc 242
rs 8.3396
bpm 1.7037
cpm 1.6296
noi 0

17 Functions

Rating   Name   Duplication   Size   Complexity  
A View.updateFileList 0 5 1
A View.setSelectedFiles 0 4 1
A View.destroySelectedActionButton 0 4 1
A View.loopForStatus 0 17 1
A View.renderSelectedActionButton 0 4 1
A View.initialize 0 6 1
A ocrview.js ➔ View 0 5 1
A View.destroyDropdown 0 5 2
A View.notifyError 0 4 1
A View.destroy 0 7 1
B View.togglePendingState 0 19 6
B View.registerFileActions 0 39 1
A View.getSelectedFiles 0 4 1
B View.registerEvents 0 35 1
A View.renderFileAction 0 7 1
A View.renderDropdown 0 10 3
A View.toggleSelectedActionButton 0 18 4

How to fix   Complexity   

Complexity

Complex classes like js/ocrview.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * nextCloud - ocr
3
 *
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later. See the COPYING file.
6
 *
7
 * @author Janis Koehr <[email protected]>
8
 * @copyright Janis Koehr 2016
9
 */
10
(function() {
11
	/**
12
	 * Constructor of the View object.
13
	 * This will update the different parts of the html.
14
	 * @param ocr
15
	 * @param filehandler
16
	 * @constructor
17
	 */
18
19
	// Handlebarsjs template
20
	var TEMPLATE_OCR_DROPDOWN = '<div id="ocrDropdown" class="ocrUserInterface">'+
21
		'{{#if noMatches}}'+
22
		t('ocr', 'No languages for tesseract available')+
23
		'{{else}}'+
24
		t('ocr', 'Select')+
25
		':'+
26
		'<select id="ocrLanguage">'+
27
		'{{#each languages}}'+
28
		'<option value="{{this}}">{{this}}</option>'+
29
		'{{/each}}'+
30
		'</select>'+
31
		'<input type="button" id="processOCR" value="'+
32
		t('ocr', 'Process')+
33
		'" />'+
34
		'{{/if}}'+
35
		'</div>';
36
37
	var TEMPLATE_OCR_SELECTED_FILE_ACTION = '<span class="selectedActionsOCR hidden">'+
38
		'<a id="selectedFilesOCR" href="" class="ocr">'+
39
		'<span class="icon icon-external"></span>'+
40
		'<span>'+t('ocr', 'OCR')+'</span>'+
41
		'</a>'+
42
		'</span>';
43
44
	var View = function (ocr) {
45
		this._ocr = ocr;
46
		this._selectedFiles = [];
47
		this._row = undefined;
48
	};
49
50
	/**
51
	 * Class prototype for the View. Following functions are available:
52
	 *
53
	 */
54
	View.prototype = {
55
		initialize: function () {
56
			this.renderSelectedActionButton();
57
			this.registerFileActions();
58
			this.registerEvents();
59
			this.loopForStatus();
60
		},
61
		destroy: function () {
62
			var self = this;
63
			self.destroyDropdown();
64
			self.destroySelectedActionButton();
65
			OCA.Files.fileActions.clear();
66
			OCA.Files.fileActions.registerDefaultActions();
67
		},
68
		registerFileActions: function () {
69
			var self = this;
70
			/**
71
			 * Register FileAction for mimetype pdf
72
			 */
73
			OCA.Files.fileActions.registerAction({
74
				name: 'Ocr',
75
				displayName: t('ocr', 'OCR'),
76
				order: 100,
77
				mime: 'application/pdf',
78
				permissions: OC.PERMISSION_UPDATE,
79
				altText: t('ocr', 'OCR'),
80
				iconClass: 'icon-external',
81
				actionHandler: function (filename, context) {
82
					var path = context.dir || context.fileList.getCurrentDirectory();
83
					var mimetype = context.fileActions.getCurrentMimeType();
84
					var type = context.fileActions.getCurrentType();
85
					self.renderFileAction(filename, path, type, mimetype);
86
				}
87
			});
88
			/**
89
			 * Register FileAction for mimetype image
90
			 */
91
			OCA.Files.fileActions.registerAction({
92
				name: 'Ocr',
93
				displayName: t('ocr', 'OCR'),
94
				order: 100,
95
				mime: 'image',
96
				permissions: OC.PERMISSION_UPDATE,
97
				altText: t('ocr', 'OCR'),
98
				iconClass: 'icon-external',
99
				actionHandler: function (filename, context) {
100
					var path = context.dir || context.fileList.getCurrentDirectory();
101
					var mimetype = context.fileActions.getCurrentMimeType();
102
					var type = context.fileActions.getCurrentType();
103
					self.renderFileAction(filename, path, type, mimetype);
104
				}
105
			});
106
		},
107
		setSelectedFiles: function (selectedFiles) {
108
			var self = this;
109
			self._selectedFiles = selectedFiles;
110
		},
111
		getSelectedFiles: function () {
112
			var self = this;
113
			return self._selectedFiles;
114
		},
115
		destroySelectedActionButton: function () {
116
			// remove the Template
117
			$('.selectedActionsOCR').remove();
118
		},
119
		renderSelectedActionButton: function () {
120
			// append the TEMPLATE to correct position
121
			$(TEMPLATE_OCR_SELECTED_FILE_ACTION).appendTo($('#headerName-container'));
122
		},
123
		destroyDropdown: function () {
124
			if ($('#ocrDropdown').length){
125
				$('#ocrDropdown').detach();
126
			}
127
		},
128
		renderDropdown: function(){
129
			var self = this;
130
			self.destroyDropdown();
131
			/** global: Handlebars */
132
			var template = Handlebars.compile(TEMPLATE_OCR_DROPDOWN);
133
			var noMatches = true;
134
			var languages = self._ocr.getLanguages();
135
			if(languages.length > 0 && typeof languages !== undefined){ noMatches = false; }
136
			return template({languages: languages, noMatches: noMatches});
137
		},
138
		renderFileAction: function (file, path, type, mimetype) {
139
			var self = this;
140
			var html = self.renderDropdown();
141
			$(html).appendTo($('tr').filterAttr('data-file',file).find('td.filename'));
142
			var files = [{name: file, path: path, type: type, mimetype: mimetype}];
143
			self.setSelectedFiles(files);
144
		},
145
		toggleSelectedActionButton: function () {
146
			var self = this;
147
			var selectedActionButton = $('.selectedActionsOCR');
148
			var selFiles = OCA.Files.App.fileList.getSelectedFiles();
149
			if(selFiles.length > 0 && typeof selFiles !== undefined){
150
				//show if all have correct mimetype and type = file
151
				if(self._ocr.checkMimeTypes(selFiles)){
152
					// show if not already shown
153
					selectedActionButton.removeClass('hidden');
154
				}else{
155
					selectedActionButton.addClass('hidden');
156
				}
157
			}else{
158
				// hide if not already hidden
159
				selectedActionButton.addClass('hidden');
160
				self.setSelectedFiles([]);
161
			}
162
		},
163
		togglePendingState: function (force) {
164
			var self = this;
165
			var html = '';
166
			var pendingcount = self._ocr.getStatus().pending;
167
			if(force){
168
				html = '<span class="icon icon-loading-small"></span>&nbsp;<span>' + t('ocr','OCR processing started.') + '</span>';
169
			}else{
170
				html = '<span class="icon icon-loading-small"></span>&nbsp;<span>' + pendingcount + ' ' + t('ocr','currently pending OCR requests.') + '</span>';
171
			}
172
			if(pendingcount > 0 || force){
173
				if (self._row !== undefined) { OC.Notification.hide(self._row); }
174
				self._row = OC.Notification.showHtml(html);
175
			}else{
176
				if (self._row !== undefined){
177
					OC.Notification.hide(self._row);
178
					self._row = undefined;
179
				}
180
			}
181
		},
182
		updateFileList: function () {
183
			var self = this;
184
			OCA.Files.App.fileList.reload();
185
			self.toggleSelectedActionButton('');
186
		},
187
		/**
188
		 * Loops as long as there are pending objects
189
		 */
190
		loopForStatus: function () {
191
			var self = this;
192
			$.when(self._ocr.checkStatus()).done(function(){
193
				if(self._ocr.getStatus().failed > 0) { self.notifyError('OCR processing for one or more files failed. For details please contact your administrator.'); }
194
				if(self._ocr.getStatus().pending > 0){
195
					if(self._ocr.getStatus().processed > 0) { self.updateFileList(); }
196
					self.togglePendingState(false);
197
					setTimeout($.proxy(self.loopForStatus,self), 4500);
198
				}else{
199
					if(self._ocr.getStatus().processed > 0) { self.updateFileList(); }
200
					self.togglePendingState(false);
201
				}
202
			}).fail(function(message){
203
				self.notifyError(message);
204
				setTimeout($.proxy(self.loopForStatus,self), 4500);
205
			});
206
		},
207
		notifyError: function (message) {
208
			/** global: OC */
209
			OC.Notification.showHtml('<div>'+t('ocr', message)+'</div>', {timeout: 10, type: 'error'});
210
		},
211
		registerEvents: function(){
212
			var self = this;
213
			// Close on click on other element
214
			$(document).click(function(event) {
215
				if(!$(event.target).closest('#ocrDropdown').length) {
216
					self.destroyDropdown();
217
					self.setSelectedFiles([]);
218
				}
219
			});
220
			// Register submit action
221
			$(document).on('click', '#processOCR', function(){
222
				var selectedLanguage = $('#ocrLanguage').val();
223
				$.when(self._ocr.process(self.getSelectedFiles(), selectedLanguage)).done(function(){
224
					self.destroyDropdown();
225
					self.setSelectedFiles([]);
226
					// status monitoring init
227
					self.togglePendingState(true);
228
					setTimeout($.proxy(self.loopForStatus,self), 4500);
229
				}).fail(function(message){
230
					self.notifyError('OCR processing failed: ' + message);
231
					self.destroyDropdown();
232
				});
233
			});
234
			// Register click selectedFilesAction
235
			$(document).on('click', '#selectedFilesOCR', function(){
236
				var html = self.renderDropdown();
237
				$(html).appendTo($('tr').find('th.column-name'));
238
				self.setSelectedFiles(OCA.Files.App.fileList.getSelectedFiles());
239
				return false;
240
			});
241
			// Register checkbox events
242
			/** global: _ */
243
			OCA.Files.App.fileList.$fileList.on('change', 'td.filename>.selectCheckBox', _.bind(self.toggleSelectedActionButton, this));
244
			OCA.Files.App.fileList.$el.find('.select-all').click(_.bind(self.toggleSelectedActionButton, this));
245
		}
246
	};
247
	/** global: OCA */
248
	if (OCA.Ocr) {
249
		OCA.Ocr.View = View;
250
	}
251
})();