Completed
Push — master ( e88c19...17669b )
by Rain
03:00
created

dev/View/User/MailBox/FolderList.js   D

Complexity

Total Complexity 61
Complexity/F 2.77

Size

Lines of Code 305
Function Count 22

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
c 1
b 0
f 0
nc 27648
dl 0
loc 305
rs 4.9583
wmc 61
mnd 3
bc 47
fnc 22
bpm 2.1363
cpm 2.7727
noi 0

How to fix   Complexity   

Complexity

Complex classes like dev/View/User/MailBox/FolderList.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
import window from 'window';
3
import $ from '$';
4
import ko from 'ko';
5
import key from 'key';
6
7
import {trim, isNormal, isArray, windowResize} from 'Common/Utils';
8
import {Capa, Focused, Layout, KeyState, EventKeyCode, Magics} from 'Common/Enums';
9
import {$html, leftPanelDisabled} from 'Common/Globals';
10
import {mailBox, settings} from 'Common/Links';
11
import {setFolderHash} from 'Common/Cache';
12
13
import AppStore from 'Stores/User/App';
14
import SettingsStore from 'Stores/User/Settings';
15
import FolderStore from 'Stores/User/Folder';
16
import MessageStore from 'Stores/User/Message';
17
18
import * as Settings from 'Storage/Settings';
19
20
import {getApp} from 'Helper/Apps/User';
21
22
import {view, ViewType, showScreenPopup, setHash} from 'Knoin/Knoin';
23
import {AbstractViewNext} from 'Knoin/AbstractViewNext';
24
25
@view({
26
	name: 'View/User/MailBox/FolderList',
27
	type: ViewType.Left,
28
	templateID: 'MailFolderList'
29
})
30
class FolderListMailBoxUserView extends AbstractViewNext
31
{
32
	constructor() {
33
		super();
34
35
		this.oContentVisible = null;
36
		this.oContentScrollable = null;
37
38
		this.composeInEdit = AppStore.composeInEdit;
39
40
		this.messageList = MessageStore.messageList;
41
		this.folderList = FolderStore.folderList;
42
		this.folderListSystem = FolderStore.folderListSystem;
43
		this.foldersChanging = FolderStore.foldersChanging;
44
45
		this.foldersListWithSingleInboxRootFolder = FolderStore.foldersListWithSingleInboxRootFolder;
46
47
		this.leftPanelDisabled = leftPanelDisabled;
48
49
		this.iDropOverTimer = 0;
50
51
		this.allowComposer = !!Settings.capa(Capa.Composer);
52
		this.allowContacts = !!AppStore.contactsIsAllowed();
53
		this.allowFolders = !!Settings.capa(Capa.Folders);
54
55
		this.folderListFocused = ko.computed(() => Focused.FolderList === AppStore.focusedState());
56
57
		this.isInboxStarred = ko.computed(
58
			() => FolderStore.currentFolder() &&
59
				FolderStore.currentFolder().isInbox() &&
60
				-1 < trim(MessageStore.messageListSearch()).indexOf('is:flagged')
61
		);
62
	}
63
64
	onBuild(dom) {
65
66
		this.oContentVisible = $('.b-content', dom);
67
		this.oContentScrollable = $('.content', this.oContentVisible);
68
69
		const
70
			self = this,
71
			isMobile = Settings.appSettingsGet('mobile'),
72
			fSelectFolder = (el, event, starred) => {
73
74
				if (isMobile)
75
				{
76
					leftPanelDisabled(true);
77
				}
78
79
				event.preventDefault();
80
81
				if (starred)
82
				{
83
					event.stopPropagation();
84
				}
85
86
				const folder = ko.dataFor(el);
87
				if (folder)
88
				{
89
					if (Layout.NoPreview === SettingsStore.layout())
90
					{
91
						MessageStore.message(null);
92
					}
93
94
					if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw())
95
					{
96
						setFolderHash(folder.fullNameRaw, '');
97
					}
98
99
					if (starred)
100
					{
101
						setHash(mailBox(folder.fullNameHash, 1, 'is:flagged'));
102
					}
103
					else
104
					{
105
						setHash(mailBox(folder.fullNameHash));
106
					}
107
				}
108
			};
109
110
		dom
111
			.on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function(event) { // eslint-disable-line prefer-arrow-callback
112
				const folder = ko.dataFor(this); // eslint-disable-line no-invalid-this
113
				if (folder && event)
114
				{
115
					const collapsed = folder.collapsed();
116
					getApp().setExpandedFolder(folder.fullNameHash, collapsed);
117
118
					folder.collapsed(!collapsed);
119
					event.preventDefault();
120
					event.stopPropagation();
121
				}
122
			})
123
			.on('click', '.b-folders .e-item .e-link.selectable .inbox-star-icon', function(event) { // eslint-disable-line prefer-arrow-callback
124
				fSelectFolder(this, event, !self.isInboxStarred()); // eslint-disable-line no-invalid-this
125
			})
126
			.on('click', '.b-folders .e-item .e-link.selectable', function(event) { // eslint-disable-line prefer-arrow-callback
127
				fSelectFolder(this, event, false); // eslint-disable-line no-invalid-this
128
			});
129
130
		key('up, down', KeyState.FolderList, (event, handler) => {
131
132
			const
133
				keyCode = handler && 'up' === handler.shortcut ? EventKeyCode.Up : EventKeyCode.Down,
134
				$items = $('.b-folders .e-item .e-link:not(.hidden):visible', dom);
135
136
			if (event && $items.length)
137
			{
138
				let index = $items.index($items.filter('.focused'));
139
				if (-1 < index)
140
				{
141
					$items.eq(index).removeClass('focused');
142
				}
143
144
				if (EventKeyCode.Up === keyCode && 0 < index)
145
				{
146
					index -= 1;
147
				}
148
				else if (EventKeyCode.Down === keyCode && index < $items.length - 1)
149
				{
150
					index += 1;
151
				}
152
153
				$items.eq(index).addClass('focused');
154
				self.scrollToFocused();
155
			}
156
157
			return false;
158
		});
159
160
		key('enter', KeyState.FolderList, () => {
161
			const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom);
162
			if ($items.length && $items[0])
163
			{
164
				AppStore.focusedState(Focused.MessageList);
165
				$items.click();
166
			}
167
168
			return false;
169
		});
170
171
		key('space', KeyState.FolderList, () => {
172
			const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom);
173
			if ($items.length && $items[0])
174
			{
175
				const folder = ko.dataFor($items[0]);
176
				if (folder)
177
				{
178
					const collapsed = folder.collapsed();
179
					getApp().setExpandedFolder(folder.fullNameHash, collapsed);
180
					folder.collapsed(!collapsed);
181
				}
182
			}
183
184
			return false;
185
		});
186
187
		key('esc, tab, shift+tab, right', KeyState.FolderList, () => {
188
			AppStore.focusedState(Focused.MessageList);
189
			return false;
190
		});
191
192
		AppStore.focusedState.subscribe((value) => {
193
			$('.b-folders .e-item .e-link.focused', dom).removeClass('focused');
194
			if (Focused.FolderList === value)
195
			{
196
				$('.b-folders .e-item .e-link.selected', dom).addClass('focused');
197
			}
198
		});
199
	}
200
201
	messagesDropOver(folder) {
202
		window.clearTimeout(this.iDropOverTimer);
203
		if (folder && folder.collapsed())
204
		{
205
			this.iDropOverTimer = window.setTimeout(() => {
206
				folder.collapsed(false);
207
				getApp().setExpandedFolder(folder.fullNameHash, true);
208
				windowResize();
209
			}, Magics.Time500ms);
210
		}
211
	}
212
213
	messagesDropOut() {
214
		window.clearTimeout(this.iDropOverTimer);
215
	}
216
217
	scrollToFocused() {
218
		if (!this.oContentVisible || !this.oContentScrollable)
219
		{
220
			return false;
221
		}
222
223
		const
224
			offset = 20,
225
			focused = $('.e-item .e-link.focused', this.oContentScrollable),
226
			pos = focused.position(),
227
			visibleHeight = this.oContentVisible.height(),
228
			focusedHeight = focused.outerHeight();
229
230
		if (pos && (0 > pos.top || pos.top + focusedHeight > visibleHeight))
231
		{
232
			if (0 > pos.top)
233
			{
234
				this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + pos.top - offset);
235
			}
236
			else
237
			{
238
				this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + pos.top - visibleHeight + focusedHeight + offset);
239
			}
240
241
			return true;
242
		}
243
244
		return false;
245
	}
246
247
	/**
248
	 * @param {FolderModel} toFolder
249
	 * @param {{helper:jQuery}} ui
250
	 * @returns {void}
251
	 */
252
	messagesDrop(toFolder, ui) {
253
		if (toFolder && ui && ui.helper)
254
		{
255
			const
256
				fromFolderFullNameRaw = ui.helper.data('rl-folder'),
257
				copy = $html.hasClass('rl-ctrl-key-pressed'),
258
				uids = ui.helper.data('rl-uids');
259
260
			if (isNormal(fromFolderFullNameRaw) && '' !== fromFolderFullNameRaw && isArray(uids))
261
			{
262
				getApp().moveMessagesToFolder(fromFolderFullNameRaw, uids, toFolder.fullNameRaw, copy);
263
			}
264
		}
265
	}
266
267
	composeClick() {
268
		if (Settings.capa(Capa.Composer))
269
		{
270
			showScreenPopup(require('View/Popup/Compose'));
271
		}
272
	}
273
274
	createFolder() {
275
		showScreenPopup(require('View/Popup/FolderCreate'));
276
	}
277
278
	configureFolders() {
279
		setHash(settings('folders'));
280
	}
281
282
	contactsClick() {
283
		if (this.allowContacts)
284
		{
285
			showScreenPopup(require('View/Popup/Contacts'));
286
		}
287
	}
288
}
289
290
export {FolderListMailBoxUserView, FolderListMailBoxUserView as default};
291