Completed
Push — master ( 4ee171...2f8415 )
by Rain
03:28
created

Utils.js ➔ plainToHtml   C

Complexity

Conditions 12
Paths 48

Size

Total Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
c 1
b 0
f 0
nc 48
nop 2
dl 0
loc 74
rs 5.3992

1 Function

Rating   Name   Duplication   Size   Complexity  
A Utils.js ➔ ... ➔ ??? 0 1 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like Utils.js ➔ plainToHtml 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 _ from '_';
5
import ko from 'ko';
6
import Autolinker from 'Autolinker';
7
8
import {$win, $div, dropdownVisibility, data as GlobalsData} from 'Common/Globals';
9
import {ComposeType, EventKeyCode, SaveSettingsStep, FolderType} from 'Common/Enums';
10
import {Mime} from 'Common/Mime';
11
import {jassl} from 'Common/Jassl';
12
13
const trim = $.trim;
14
const inArray = $.inArray;
15
const isArray = _.isArray;
16
const isObject = _.isObject;
17
const isFunc = _.isFunction;
18
const isUnd = _.isUndefined;
19
const isNull = _.isNull;
20
const has = _.has;
21
const bind = _.bind;
22
const noop = () => {}; // eslint-disable-line no-empty-function
23
const noopTrue = () => true;
24
const noopFalse = () => false;
25
26
export {trim, inArray, isArray, isObject, isFunc, isUnd, isNull, has, bind, noop, noopTrue, noopFalse, jassl};
27
28
/**
29
 * @param {Function} func
30
 */
31
export function silentTryCatch(func)
32
{
33
	try {
34
		func();
35
	}
36
	catch (e) {} // eslint-disable-line no-empty
37
}
38
39
/**
40
 * @param {*} value
41
 * @returns {boolean}
42
 */
43
export function isNormal(value)
44
{
45
	return !isUnd(value) && !isNull(value);
46
}
47
48
/**
49
 * @param {(string|number)} value
50
 * @param {boolean=} includeZero = true
51
 * @returns {boolean}
52
 */
53
export function isPosNumeric(value, includeZero = true)
54
{
55
	return !isNormal(value) ? false :
56
		(includeZero ? (/^[0-9]*$/).test(value.toString()) : (/^[1-9]+[0-9]*$/).test(value.toString()));
57
}
58
59
/**
60
 * @param {*} value
61
 * @param {number=} defaultValur = 0
62
 * @returns {number}
63
 */
64
export function pInt(value, defaultValur = 0)
65
{
66
	const result = isNormal(value) && '' !== value ? window.parseInt(value, 10) : defaultValur;
67
	return window.isNaN(result) ? defaultValur : result;
68
}
69
70
/**
71
 * @param {*} value
72
 * @returns {string}
73
 */
74
export function pString(value)
75
{
76
	return isNormal(value) ? '' + value : '';
77
}
78
79
/**
80
 * @param {*} value
81
 * @returns {boolean}
82
 */
83
export function pBool(value)
84
{
85
	return !!value;
86
}
87
88
/**
89
 * @param {*} value
90
 * @returns {string}
91
 */
92
export function boolToAjax(value)
93
{
94
	return value ? '1' : '0';
95
}
96
97
/**
98
 * @param {*} values
99
 * @returns {boolean}
100
 */
101
export function isNonEmptyArray(values)
102
{
103
	return isArray(values) && 0 < values.length;
104
}
105
106
/**
107
 * @param {string} component
108
 * @returns {string}
109
 */
110
export function encodeURIComponent(component)
111
{
112
	return window.encodeURIComponent(component);
113
}
114
115
/**
116
 * @param {string} component
117
 * @returns {string}
118
 */
119
export function decodeURIComponent(component)
120
{
121
	return window.decodeURIComponent(component);
122
}
123
124
/**
125
 * @param {string} url
126
 * @returns {string}
127
 */
128
export function decodeURI(url)
129
{
130
	return window.decodeURI(url);
131
}
132
133
/**
134
 * @param {string} url
135
 * @returns {string}
136
 */
137
export function encodeURI(url)
138
{
139
	return window.encodeURI(url);
140
}
141
142
/**
143
 * @param {string} queryString
144
 * @returns {Object}
145
 */
146
export function simpleQueryParser(queryString)
147
{
148
	let
149
		index = 0,
150
		len = 0,
151
		temp = null;
0 ignored issues
show
Unused Code introduced by
The assignment to temp seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
152
153
	const
154
		queries = queryString.split('&'),
155
		params = {};
156
157
	for (len = queries.length; index < len; index++)
158
	{
159
		temp = queries[index].split('=');
160
		params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]);
161
	}
162
163
	return params;
164
}
165
166
/**
167
 * @param {number=} len = 32
168
 * @returns {string}
169
 */
170
export function fakeMd5(len = 32)
171
{
172
	const
173
		line = '0123456789abcdefghijklmnopqrstuvwxyz',
174
		lineLen = line.length;
175
176
	len = pInt(len);
177
178
	let result = '';
179
	while (result.length < len)
180
	{
181
		result += line.substr(window.Math.round(window.Math.random() * lineLen), 1);
182
	}
183
184
	return result;
185
}
186
187
/**
188
 * @param {string} text
189
 * @returns {string}
190
 */
191
export function encodeHtml(text)
192
{
193
	return isNormal(text) ? _.escape(text.toString()) : '';
194
}
195
196
/**
197
 * @param {string} text
198
 * @param {number=} len = 100
199
 * @returns {string}
200
 */
201
export function splitPlainText(text, len = 100)
202
{
203
	let
204
		prefix = '',
205
		subText = '',
206
		result = text,
207
		spacePos = 0,
208
		newLinePos = 0;
209
210
	while (result.length > len)
211
	{
212
		subText = result.substring(0, len);
213
		spacePos = subText.lastIndexOf(' ');
214
		newLinePos = subText.lastIndexOf('\n');
215
216
		if (-1 !== newLinePos)
217
		{
218
			spacePos = newLinePos;
219
		}
220
221
		if (-1 === spacePos)
222
		{
223
			spacePos = len;
224
		}
225
226
		prefix += subText.substring(0, spacePos) + '\n';
227
		result = result.substring(spacePos + 1);
228
	}
229
230
	return prefix + result;
231
}
232
233
const timeOutAction = (function() {
234
	const timeOuts = {};
235
	return (action, fFunction, timeOut) => {
236
		timeOuts[action] = isUnd(timeOuts[action]) ? 0 : timeOuts[action];
237
		window.clearTimeout(timeOuts[action]);
238
		timeOuts[action] = window.setTimeout(fFunction, timeOut);
239
	};
240
}());
241
242
const timeOutActionSecond = (function() {
243
	const timeOuts = {};
244
	return (action, fFunction, timeOut) => {
245
		if (!timeOuts[action])
246
		{
247
			timeOuts[action] = window.setTimeout(() => {
248
				fFunction();
249
				timeOuts[action] = 0;
250
			}, timeOut);
251
		}
252
	};
253
}());
254
255
export {timeOutAction, timeOutActionSecond};
256
257
/**
258
 * @returns {boolean}
259
 */
260
export function inFocus()
261
{
262
	try {
263
		if (window.document.activeElement)
264
		{
265
			if (isUnd(window.document.activeElement.__inFocusCache))
266
			{
267
				window.document.activeElement.__inFocusCache = $(window.document.activeElement).is('input,textarea,iframe,.cke_editable');
268
			}
269
270
			return !!window.document.activeElement.__inFocusCache;
271
		}
272
	}
273
	catch (e) {} // eslint-disable-line no-empty
274
275
	return false;
276
}
277
278
/**
279
 * @param {boolean} force
280
 * @returns {void}
281
 */
282
export function removeInFocus(force)
283
{
284
	if (window.document && window.document.activeElement && window.document.activeElement.blur)
285
	{
286
		try {
287
			const activeEl = $(window.document.activeElement);
288
			if (activeEl && activeEl.is('input,textarea'))
289
			{
290
				window.document.activeElement.blur();
291
			}
292
			else if (force)
293
			{
294
				window.document.activeElement.blur();
295
			}
296
		}
297
		catch (e) {} // eslint-disable-line no-empty
298
	}
299
}
300
301
/**
302
 * @returns {void}
303
 */
304
export function removeSelection()
305
{
306
	try {
307
		if (window && window.getSelection)
308
		{
309
			const sel = window.getSelection();
310
			if (sel && sel.removeAllRanges)
311
			{
312
				sel.removeAllRanges();
313
			}
314
		}
315
		else if (window.document && window.document.selection && window.document.selection.empty)
316
		{
317
			window.document.selection.empty();
318
		}
319
	}
320
	catch (e) {} // eslint-disable-line no-empty
321
}
322
323
/**
324
 * @param {string} prefix
325
 * @param {string} subject
326
 * @returns {string}
327
 */
328
export function replySubjectAdd(prefix, subject)
329
{
330
	prefix = trim(prefix.toUpperCase());
331
	subject = trim(subject.replace(/[\s]+/g, ' '));
332
333
	let drop = false,
334
		re = 'RE' === prefix,
335
		fwd = 'FWD' === prefix;
336
337
	const
338
		parts = [],
339
		prefixIsRe = !fwd;
340
341
	if ('' !== subject)
342
	{
343
		_.each(subject.split(':'), (part) => {
344
			const trimmedPart = trim(part);
345
			if (!drop && ((/^(RE|FWD)$/i).test(trimmedPart) || (/^(RE|FWD)[\[\(][\d]+[\]\)]$/i).test(trimmedPart)))
346
			{
347
				if (!re)
348
				{
349
					re = !!(/^RE/i).test(trimmedPart);
350
				}
351
352
				if (!fwd)
353
				{
354
					fwd = !!(/^FWD/i).test(trimmedPart);
355
				}
356
			}
357
			else
358
			{
359
				parts.push(part);
360
				drop = true;
361
			}
362
		});
363
	}
364
365
	if (prefixIsRe)
366
	{
367
		re = false;
368
	}
369
	else
370
	{
371
		fwd = false;
372
	}
373
374
	return trim(
375
		(prefixIsRe ? 'Re: ' : 'Fwd: ') +
376
		(re ? 'Re: ' : '') +
377
		(fwd ? 'Fwd: ' : '') +
378
		trim(parts.join(':'))
379
	);
380
}
381
382
/**
383
 * @param {number} num
384
 * @param {number} dec
385
 * @returns {number}
386
 */
387
export function roundNumber(num, dec)
388
{
389
	return window.Math.round(num * window.Math.pow(10, dec)) / window.Math.pow(10, dec);
390
}
391
392
/**
393
 * @param {(number|string)} sizeInBytes
394
 * @returns {string}
395
 */
396
export function friendlySize(sizeInBytes)
397
{
398
	sizeInBytes = pInt(sizeInBytes);
399
400
	switch (true)
401
	{
402
		case 1073741824 <= sizeInBytes:
403
			return roundNumber(sizeInBytes / 1073741824, 1) + 'GB';
404
		case 1048576 <= sizeInBytes:
405
			return roundNumber(sizeInBytes / 1048576, 1) + 'MB';
406
		case 1024 <= sizeInBytes:
407
			return roundNumber(sizeInBytes / 1024, 0) + 'KB';
408
		// no default
409
	}
410
411
	return sizeInBytes + 'B';
412
}
413
414
/**
415
 * @param {string} desc
416
 */
417
export function log(desc)
418
{
419
	if (window.console && window.console.log)
420
	{
421
		window.console.log(desc);
422
	}
423
}
424
425
/**
426
 * @param {?} object
427
 * @param {string} methodName
428
 * @param {Array=} params
429
 * @param {number=} delay = 0
430
 */
431
export function delegateRun(object, methodName, params, delay = 0)
432
{
433
	if (object && object[methodName])
434
	{
435
		delay = pInt(delay);
436
		params = isArray(params) ? params : [];
437
438
		if (0 >= delay)
439
		{
440
			object[methodName](...params);
441
		}
442
		else
443
		{
444
			_.delay(() => {
445
				object[methodName](...params);
446
			}, delay);
447
		}
448
	}
449
}
450
451
/**
452
 * @param {?} event
453
 */
454
export function killCtrlACtrlS(event)
455
{
456
	event = event || window.event;
457
	if (event && event.ctrlKey && !event.shiftKey && !event.altKey)
458
	{
459
		const key = event.keyCode || event.which;
460
		if (key === EventKeyCode.S)
461
		{
462
			event.preventDefault();
463
			return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
464
		}
465
		else if (key === EventKeyCode.A)
466
		{
467
			const sender = event.target || event.srcElement;
468
			if (sender && ('true' === '' + sender.contentEditable ||
469
				(sender.tagName && sender.tagName.match(/INPUT|TEXTAREA/i))))
470
			{
471
				return;
472
			}
473
474
			if (window.getSelection)
475
			{
476
				window.getSelection().removeAllRanges();
477
			}
478
			else if (window.document.selection && window.document.selection.clear)
479
			{
480
				window.document.selection.clear();
481
			}
482
483
			event.preventDefault();
484
		}
485
	}
486
}
487
488
/**
489
 * @param {(Object|null|undefined)} context
490
 * @param {Function} fExecute
491
 * @param {(Function|boolean|null)=} fCanExecute = true
492
 * @returns {Function}
493
 */
494
export function createCommandLegacy(context, fExecute, fCanExecute = true)
495
{
496
	let fResult = null;
497
	const fNonEmpty = (...args) => {
498
		if (fResult && fResult.canExecute && fResult.canExecute())
499
		{
500
			fExecute.apply(context, args);
501
		}
502
		return false;
503
	};
504
505
	fResult = fExecute ? fNonEmpty : noop;
506
	fResult.enabled = ko.observable(true);
507
	fResult.isCommand = true;
508
509
	if (isFunc(fCanExecute))
510
	{
511
		fResult.canExecute = ko.computed(() => fResult.enabled() && fCanExecute.call(context));
512
	}
513
	else
514
	{
515
		fResult.canExecute = ko.computed(() => fResult.enabled() && !!fCanExecute);
516
	}
517
518
	return fResult;
519
}
520
521
/**
522
 * @param {Function} fExecute
523
 * @param {(Function|boolean|null)=} fCanExecute = true
524
 * @returns {Function}
525
 */
526
export function createCommand(fExecute, fCanExecute = true)
527
{
528
	return createCommandLegacy(null, fExecute, fCanExecute);
529
}
530
531
/**
532
 * @param {string} theme
533
 * @returns {string}
534
 */
535
export const convertThemeName = _.memoize((theme) => {
0 ignored issues
show
Unused Code introduced by
The constant convertThemeName seems to be never used. Consider removing it.
Loading history...
536
537
	if ('@custom' === theme.substr(-7))
538
	{
539
		theme = trim(theme.substring(0, theme.length - 7));
540
	}
541
542
	return trim(theme.replace(/[^a-zA-Z0-9]+/g, ' ').replace(/([A-Z])/g, ' $1').replace(/[\s]+/g, ' '));
543
});
544
545
/**
546
 * @param {string} name
547
 * @returns {string}
548
 */
549
export function quoteName(name)
550
{
551
	return name.replace(/["]/g, '\\"');
552
}
553
554
/**
555
 * @returns {number}
556
 */
557
export function microtime()
558
{
559
	return (new window.Date()).getTime();
560
}
561
562
/**
563
 * @returns {number}
564
 */
565
export function timestamp()
566
{
567
	return window.Math.round(microtime() / 1000);
568
}
569
570
/**
571
 *
572
 * @param {string} language
573
 * @param {boolean=} isEng = false
574
 * @returns {string}
575
 */
576
export function convertLangName(language, isEng = false)
577
{
578
	return require('Common/Translator').i18n('LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' +
579
		language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'), null, language);
580
}
581
582
/**
583
 * @returns {object}
584
 */
585
export function draggablePlace()
586
{
587
	return $('<div class="draggablePlace">' +
588
		'<span class="text"></span>&nbsp;' +
589
		'<i class="icon-copy icon-white visible-on-ctrl"></i>' +
590
		'<i class="icon-mail icon-white hidden-on-ctrl"></i>' +
591
		'</div>'
592
	).appendTo('#rl-hidden');
593
}
594
595
/**
596
 * @param {object} domOption
0 ignored issues
show
Documentation introduced by
The parameter domOption does not exist. Did you maybe forget to remove this comment?
Loading history...
597
 * @param {object} item
598
 * @returns {void}
599
 */
600
export function defautOptionsAfterRender(domItem, item)
601
{
602
	if (item && !isUnd(item.disabled) && domItem)
603
	{
604
		$(domItem)
605
			.toggleClass('disabled', item.disabled)
606
			.prop('disabled', item.disabled);
607
	}
608
}
609
610
/**
611
 * @param {string} title
0 ignored issues
show
Documentation introduced by
The parameter title does not exist. Did you maybe forget to remove this comment?
Loading history...
612
 * @param {Object} body
613
 * @param {boolean} isHtml
0 ignored issues
show
Documentation introduced by
The parameter isHtml does not exist. Did you maybe forget to remove this comment?
Loading history...
614
 * @param {boolean} print
0 ignored issues
show
Documentation introduced by
The parameter print does not exist. Did you maybe forget to remove this comment?
Loading history...
615
 */
616
export function clearBqSwitcher(body)
617
{
618
	body.find('blockquote.rl-bq-switcher').removeClass('rl-bq-switcher hidden-bq');
619
	body.find('.rlBlockquoteSwitcher').off('.rlBlockquoteSwitcher').remove();
620
	body.find('[data-html-editor-font-wrapper]').removeAttr('data-html-editor-font-wrapper');
621
}
622
623
/**
624
 * @param {object} messageData
0 ignored issues
show
Documentation introduced by
The parameter messageData does not exist. Did you maybe forget to remove this comment?
Loading history...
625
 * @param {Object} body
626
 * @param {boolean} isHtml
627
 * @param {boolean} print
628
 * @returns {void}
629
 */
630
export function previewMessage({title, subject, date, fromCreds, toCreds, toLabel}, body, isHtml, print)
631
{
632
	const
633
		win = window.open(''),
634
		doc = win.document,
635
		bodyClone = body.clone(),
636
		bodyClass = isHtml ? 'html' : 'plain';
637
638
	clearBqSwitcher(bodyClone);
639
640
	const html = bodyClone ? bodyClone.html() : '';
641
642
	doc.write(require('Html/PreviewMessage.html')
643
		.replace('{{title}}', encodeHtml(title))
644
		.replace('{{subject}}', encodeHtml(subject))
645
		.replace('{{date}}', encodeHtml(date))
646
		.replace('{{fromCreds}}', encodeHtml(fromCreds))
647
		.replace('{{toCreds}}', encodeHtml(toCreds))
648
		.replace('{{toLabel}}', encodeHtml(toLabel))
649
		.replace('{{bodyClass}}', bodyClass)
650
		.replace('{{html}}', html)
651
	);
652
653
	doc.close();
654
655
	if (print)
656
	{
657
		window.setTimeout(() => win.print(), 100);
658
	}
659
}
660
661
/**
662
 * @param {Function} fCallback
663
 * @param {?} koTrigger
664
 * @param {?} context = null
665
 * @param {number=} timer = 1000
666
 * @returns {Function}
667
 */
668
export function settingsSaveHelperFunction(fCallback, koTrigger, context = null, timer = 1000)
669
{
670
	timer = pInt(timer);
671
	return (type, data, cached, requestAction, requestParameters) => {
672
		koTrigger.call(context, data && data.Result ? SaveSettingsStep.TrueResult : SaveSettingsStep.FalseResult);
673
		if (fCallback)
674
		{
675
			fCallback.call(context, type, data, cached, requestAction, requestParameters);
676
		}
677
		_.delay(() => {
678
			koTrigger.call(context, SaveSettingsStep.Idle);
679
		}, timer);
680
	};
681
}
682
683
/**
684
 * @param {object} koTrigger
685
 * @param {mixed} context
686
 * @returns {mixed}
687
 */
688
export function settingsSaveHelperSimpleFunction(koTrigger, context)
689
{
690
	return settingsSaveHelperFunction(null, koTrigger, context, 1000);
691
}
692
693
/**
694
 * @param {object} remote
695
 * @param {string} settingName
696
 * @param {string} type
697
 * @param {function} fTriggerFunction
698
 * @returns {function}
699
 */
700
export function settingsSaveHelperSubscribeFunction(remote, settingName, type, fTriggerFunction)
701
{
702
	return (value) => {
703
704
		if (remote)
705
		{
706
			switch (type)
707
			{
708
				case 'bool':
709
				case 'boolean':
710
					value = value ? '1' : '0';
711
					break;
712
				case 'int':
713
				case 'integer':
714
				case 'number':
715
					value = pInt(value);
716
					break;
717
				case 'trim':
718
					value = trim(value);
719
					break;
720
				default:
721
					value = pString(value);
722
					break;
723
			}
724
725
			const data = {};
726
			data[settingName] = value;
727
728
			if (remote.saveAdminConfig)
729
			{
730
				remote.saveAdminConfig(fTriggerFunction || null, data);
731
			}
732
			else if (remote.saveSettings)
733
			{
734
				remote.saveSettings(fTriggerFunction || null, data);
735
			}
736
		}
737
	};
738
}
739
740
/**
741
 * @param {string} html
742
 * @returns {string}
743
 */
744
export function findEmailAndLinks(html)
745
{
746
//	return html;
747
	return Autolinker ? Autolinker.link(html, {
748
		newWindow: true,
749
		stripPrefix: false,
750
		urls: true,
751
		email: true,
752
		mention: false,
753
		phone: false,
754
		hashtag: false,
755
		replaceFn: function(match) {
756
			return !(match && 'url' === match.getType() && match.matchedText && 0 !== match.matchedText.indexOf('http'));
757
		}
758
	}) : html;
759
}
760
761
/**
762
 * @param {string} html
763
 * @returns {string}
764
 */
765
export function htmlToPlain(html)
766
{
767
	let
768
		pos = 0,
769
		limit = 0,
770
		iP1 = 0,
771
		iP2 = 0,
772
		iP3 = 0,
773
774
		text = '';
775
776
	const
777
		convertBlockquote = (blockquoteText) => {
778
			blockquoteText = '> ' + trim(blockquoteText).replace(/\n/gm, '\n> ');
779
			return blockquoteText.replace(/(^|\n)([> ]+)/gm,
780
				(...args) => (args && 2 < args.length ? args[1] + trim(args[2].replace(/[\s]/g, '')) + ' ' : ''));
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
Bug introduced by
The variable args seems to be never initialized.
Loading history...
781
		},
782
		convertDivs = (...args) => {
783
			if (args && 1 < args.length)
784
			{
785
				let divText = trim(args[1]);
786
				if (0 < divText.length)
787
				{
788
					divText = divText.replace(/<div[^>]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs);
789
					divText = '\n' + trim(divText) + '\n';
790
				}
791
792
				return divText;
793
			}
794
795
			return '';
796
		},
797
		convertPre = (...args) => (args && 1 < args.length ? args[1].toString().replace(/[\n]/gm, '<br />').replace(/[\r]/gm, '') : ''),
0 ignored issues
show
Bug introduced by
The variable args seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
798
		fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + _.escape(args[2]) : ''),
0 ignored issues
show
Bug introduced by
The variable args seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
799
		convertLinks = (...args) => (args && 1 < args.length ? trim(args[1]) : '');
0 ignored issues
show
Bug introduced by
The variable args seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
800
801
	text = html
802
		.replace(/<p[^>]*><\/p>/gi, '')
803
		.replace(/<pre[^>]*>([\s\S\r\n\t]*)<\/pre>/gmi, convertPre)
804
		.replace(/[\s]+/gm, ' ')
805
		.replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
806
		.replace(/<br[^>]*>/gmi, '\n')
807
		.replace(/<\/h[\d]>/gi, '\n')
808
		.replace(/<\/p>/gi, '\n\n')
809
		.replace(/<ul[^>]*>/gmi, '\n')
810
		.replace(/<\/ul>/gi, '\n')
811
		.replace(/<li[^>]*>/gmi, ' * ')
812
		.replace(/<\/li>/gi, '\n')
813
		.replace(/<\/td>/gi, '\n')
814
		.replace(/<\/tr>/gi, '\n')
815
		.replace(/<hr[^>]*>/gmi, '\n_______________________________\n\n')
816
		.replace(/<div[^>]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs)
817
		.replace(/<blockquote[^>]*>/gmi, '\n__bq__start__\n')
818
		.replace(/<\/blockquote>/gmi, '\n__bq__end__\n')
819
		.replace(/<a [^>]*>([\s\S\r\n]*?)<\/a>/gmi, convertLinks)
820
		.replace(/<\/div>/gi, '\n')
821
		.replace(/&nbsp;/gi, ' ')
822
		.replace(/&quot;/gi, '"')
823
		.replace(/<[^>]*>/gm, '');
824
825
	text = $div.html(text).text();
826
827
	text = text
828
		.replace(/\n[ \t]+/gm, '\n')
829
		.replace(/[\n]{3,}/gm, '\n\n')
830
		.replace(/&gt;/gi, '>')
831
		.replace(/&lt;/gi, '<')
832
		.replace(/&amp;/gi, '&');
833
834
	text = splitPlainText(trim(text));
835
836
	pos = 0;
837
	limit = 800;
838
839
	while (0 < limit)
840
	{
841
		limit -= 1;
842
		iP1 = text.indexOf('__bq__start__', pos);
843
		if (-1 < iP1)
844
		{
845
			iP2 = text.indexOf('__bq__start__', iP1 + 5);
846
			iP3 = text.indexOf('__bq__end__', iP1 + 5);
847
848
			if ((-1 === iP2 || iP3 < iP2) && iP1 < iP3)
849
			{
850
				text = text.substring(0, iP1) +
851
					convertBlockquote(text.substring(iP1 + 13, iP3)) +
852
					text.substring(iP3 + 11);
853
854
				pos = 0;
855
			}
856
			else if (-1 < iP2 && iP2 < iP3)
857
			{
858
				pos = iP2 - 1;
859
			}
860
			else
861
			{
862
				pos = 0;
863
			}
864
		}
865
		else
866
		{
867
			break;
868
		}
869
	}
870
871
	text = text
872
		.replace(/__bq__start__/gm, '')
873
		.replace(/__bq__end__/gm, '');
874
875
	return text;
876
}
877
878
/**
879
 * @param {string} plain
880
 * @param {boolean} findEmailAndLinksInText = false
881
 * @returns {string}
882
 */
883
export function plainToHtml(plain, findEmailAndLinksInText = false)
884
{
885
	plain = plain.toString().replace(/\r/g, '');
886
	plain = plain.replace(/^>[> ]>+/gm, ([match]) => (match ? match.replace(/[ ]+/g, '') : match));
0 ignored issues
show
Bug introduced by
The variable match seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
887
888
	let
889
		bIn = false,
890
		bDo = true,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bDo seems to be never used. Consider removing it.
Loading history...
891
		bStart = true,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bStart seems to be never used. Consider removing it.
Loading history...
892
		aNextText = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable aNextText seems to be never used. Consider removing it.
Loading history...
893
		sLine = '',
894
		iIndex = 0,
895
		aText = plain.split('\n');
896
897
	do
898
	{
899
		bDo = false;
900
		aNextText = [];
901
		for (iIndex = 0; iIndex < aText.length; iIndex++)
902
		{
903
			sLine = aText[iIndex];
904
			bStart = '>' === sLine.substr(0, 1);
905
			if (bStart && !bIn)
906
			{
907
				bDo = true;
908
				bIn = true;
909
				aNextText.push('~~~blockquote~~~');
910
				aNextText.push(sLine.substr(1));
911
			}
912
			else if (!bStart && bIn)
913
			{
914
				if ('' !== sLine)
915
				{
916
					bIn = false;
917
					aNextText.push('~~~/blockquote~~~');
918
					aNextText.push(sLine);
919
				}
920
				else
921
				{
922
					aNextText.push(sLine);
923
				}
924
			}
925
			else if (bStart && bIn)
926
			{
927
				aNextText.push(sLine.substr(1));
928
			}
929
			else
930
			{
931
				aNextText.push(sLine);
932
			}
933
		}
934
935
		if (bIn)
936
		{
937
			bIn = false;
938
			aNextText.push('~~~/blockquote~~~');
939
		}
940
941
		aText = aNextText;
942
	}
943
	while (bDo);
944
945
	plain = aText.join('\n');
946
947
	plain = plain
948
//			.replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
949
		.replace(/&/g, '&amp;')
950
		.replace(/>/g, '&gt;').replace(/</g, '&lt;')
951
		.replace(/~~~blockquote~~~[\s]*/g, '<blockquote>')
952
		.replace(/[\s]*~~~\/blockquote~~~/g, '</blockquote>')
953
		.replace(/\n/g, '<br />');
954
955
	return findEmailAndLinksInText ? findEmailAndLinks(plain) : plain;
956
}
957
958
window['rainloop_Utils_htmlToPlain'] = htmlToPlain; // eslint-disable-line dot-notation
959
window['rainloop_Utils_plainToHtml'] = plainToHtml; // eslint-disable-line dot-notation
960
961
/**
962
 * @param {Array} aSystem
963
 * @param {Array} aList
964
 * @param {Array=} aDisabled
965
 * @param {Array=} aHeaderLines
966
 * @param {?number=} iUnDeep
967
 * @param {Function=} fDisableCallback
968
 * @param {Function=} fVisibleCallback
969
 * @param {Function=} fRenameCallback
970
 * @param {boolean=} bSystem
971
 * @param {boolean=} bBuildUnvisible
972
 * @returns {Array}
973
 */
974
export function folderListOptionsBuilder(aSystem, aList, aDisabled, aHeaderLines,
975
	iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible)
976
{
977
	let
978
		/**
979
		 * @type {?FolderModel}
980
		 */
981
		oItem = null,
0 ignored issues
show
Unused Code introduced by
The assignment to oItem seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
982
		bSep = false,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bSep seems to be never used. Consider removing it.
Loading history...
983
		iIndex = 0,
984
		iLen = 0,
985
		aResult = [];
986
987
	const sDeepPrefix = '\u00A0\u00A0\u00A0';
988
989
	bBuildUnvisible = isUnd(bBuildUnvisible) ? false : !!bBuildUnvisible;
990
	bSystem = !isNormal(bSystem) ? 0 < aSystem.length : bSystem;
991
	iUnDeep = !isNormal(iUnDeep) ? 0 : iUnDeep;
992
	fDisableCallback = isNormal(fDisableCallback) ? fDisableCallback : null;
993
	fVisibleCallback = isNormal(fVisibleCallback) ? fVisibleCallback : null;
994
	fRenameCallback = isNormal(fRenameCallback) ? fRenameCallback : null;
995
996
	if (!isArray(aDisabled))
997
	{
998
		aDisabled = [];
999
	}
1000
1001
	if (!isArray(aHeaderLines))
1002
	{
1003
		aHeaderLines = [];
1004
	}
1005
1006
	for (iIndex = 0, iLen = aHeaderLines.length; iIndex < iLen; iIndex++)
1007
	{
1008
		aResult.push({
1009
			id: aHeaderLines[iIndex][0],
1010
			name: aHeaderLines[iIndex][1],
1011
			system: false,
1012
			seporator: false,
1013
			disabled: false
1014
		});
1015
	}
1016
1017
	bSep = true;
1018
	for (iIndex = 0, iLen = aSystem.length; iIndex < iLen; iIndex++)
1019
	{
1020
		oItem = aSystem[iIndex];
1021
		if (fVisibleCallback ? fVisibleCallback(oItem) : true)
1022
		{
1023
			if (bSep && 0 < aResult.length)
1024
			{
1025
				aResult.push({
1026
					id: '---',
1027
					name: '---',
1028
					system: false,
1029
					seporator: true,
1030
					disabled: true
1031
				});
1032
			}
1033
1034
			bSep = false;
1035
			aResult.push({
1036
				id: oItem.fullNameRaw,
1037
				name: fRenameCallback ? fRenameCallback(oItem) : oItem.name(),
1038
				system: true,
1039
				seporator: false,
1040
				disabled: !oItem.selectable || -1 < inArray(oItem.fullNameRaw, aDisabled) ||
1041
					(fDisableCallback ? fDisableCallback(oItem) : false)
1042
			});
1043
		}
1044
	}
1045
1046
	bSep = true;
1047
	for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++)
1048
	{
1049
		oItem = aList[iIndex];
1050
//			if (oItem.subScribed() || !oItem.existen || bBuildUnvisible)
1051
		if ((oItem.subScribed() || !oItem.existen || bBuildUnvisible) && (oItem.selectable || oItem.hasSubScribedSubfolders()))
1052
		{
1053
			if (fVisibleCallback ? fVisibleCallback(oItem) : true)
1054
			{
1055
				if (FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders())
1056
				{
1057
					if (bSep && 0 < aResult.length)
1058
					{
1059
						aResult.push({
1060
							id: '---',
1061
							name: '---',
1062
							system: false,
1063
							seporator: true,
1064
							disabled: true
1065
						});
1066
					}
1067
1068
					bSep = false;
1069
					aResult.push({
1070
						id: oItem.fullNameRaw,
1071
						name: (new window.Array(oItem.deep + 1 - iUnDeep)).join(sDeepPrefix) +
1072
							(fRenameCallback ? fRenameCallback(oItem) : oItem.name()),
1073
						system: false,
1074
						seporator: false,
1075
						disabled: !oItem.selectable || -1 < inArray(oItem.fullNameRaw, aDisabled) ||
1076
							(fDisableCallback ? fDisableCallback(oItem) : false)
1077
					});
1078
				}
1079
			}
1080
		}
1081
1082
		if (oItem.subScribed() && 0 < oItem.subFolders().length)
1083
		{
1084
			aResult = aResult.concat(folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
1085
				iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible));
1086
		}
1087
	}
1088
1089
	return aResult;
1090
}
1091
1092
/**
1093
 * @param {object} element
1094
 * @returns {void}
1095
 */
1096
export function selectElement(element)
1097
{
1098
	let
1099
		sel = null,
0 ignored issues
show
Unused Code introduced by
The assignment to sel seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1100
		range = null;
0 ignored issues
show
Unused Code introduced by
The assignment to range seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1101
1102
	if (window.getSelection)
1103
	{
1104
		sel = window.getSelection();
1105
		sel.removeAllRanges();
1106
		range = window.document.createRange();
1107
		range.selectNodeContents(element);
1108
		sel.addRange(range);
1109
	}
1110
	else if (window.document.selection)
1111
	{
1112
		range = window.document.body.createTextRange();
1113
		range.moveToElementText(element);
1114
		range.select();
1115
	}
1116
}
1117
1118
export const detectDropdownVisibility = _.debounce(() => {
0 ignored issues
show
Unused Code introduced by
The constant detectDropdownVisibility seems to be never used. Consider removing it.
Loading history...
1119
	dropdownVisibility(!!_.find(GlobalsData.aBootstrapDropdowns, (item) => item.hasClass('open')));
1120
}, 50);
1121
1122
/**
1123
 * @param {boolean=} delay = false
1124
 */
1125
export function triggerAutocompleteInputChange(delay = false) {
1126
1127
	const fFunc = () => {
1128
		$('.checkAutocomplete').trigger('change');
1129
	};
1130
1131
	if (delay)
1132
	{
1133
		_.delay(fFunc, 100);
1134
	}
1135
	else
1136
	{
1137
		fFunc();
1138
	}
1139
}
1140
1141
const configurationScriptTagCache = {};
1142
1143
/**
1144
 * @param {string} configuration
1145
 * @returns {object}
1146
 */
1147
export function getConfigurationFromScriptTag(configuration)
1148
{
1149
	if (!configurationScriptTagCache[configuration])
1150
	{
1151
		configurationScriptTagCache[configuration] = $('script[type="application/json"][data-configuration="' + configuration + '"]');
1152
	}
1153
1154
	try
1155
	{
1156
		return JSON.parse(configurationScriptTagCache[configuration].text());
1157
	}
1158
	catch (e) {} // eslint-disable-line no-empty
1159
1160
	return {};
1161
}
1162
1163
/**
1164
 * @param {mixed} mPropOrValue
0 ignored issues
show
Documentation introduced by
The parameter mPropOrValue does not exist. Did you maybe forget to remove this comment?
Loading history...
1165
 * @param {mixed} value
1166
 */
1167
export function disposeOne(propOrValue, value)
1168
{
1169
	const disposable = value || propOrValue;
1170
	if (disposable && 'function' === typeof disposable.dispose)
1171
	{
1172
		disposable.dispose();
1173
	}
1174
}
1175
1176
/**
1177
 * @param {Object} object
1178
 */
1179
export function disposeObject(object)
1180
{
1181
	if (object)
1182
	{
1183
		if (isArray(object.disposables))
1184
		{
1185
			_.each(object.disposables, disposeOne);
1186
		}
1187
1188
		ko.utils.objectForEach(object, disposeOne);
1189
	}
1190
}
1191
1192
/**
1193
 * @param {Object|Array} objectOrObjects
1194
 * @returns {void}
1195
 */
1196
export function delegateRunOnDestroy(objectOrObjects)
1197
{
1198
	if (objectOrObjects)
1199
	{
1200
		if (isArray(objectOrObjects))
1201
		{
1202
			_.each(objectOrObjects, (item) => {
1203
				delegateRunOnDestroy(item);
1204
			});
1205
		}
1206
		else if (objectOrObjects && objectOrObjects.onDestroy)
1207
		{
1208
			objectOrObjects.onDestroy();
1209
		}
1210
	}
1211
}
1212
1213
/**
1214
 * @param {object} $styleTag
1215
 * @param {string} css
1216
 * @returns {boolean}
1217
 */
1218
export function appendStyles($styleTag, css)
1219
{
1220
	if ($styleTag && $styleTag[0])
1221
	{
1222
		if ($styleTag[0].styleSheet && !isUnd($styleTag[0].styleSheet.cssText))
1223
		{
1224
			$styleTag[0].styleSheet.cssText = css;
1225
		}
1226
		else
1227
		{
1228
			$styleTag.text(css);
1229
		}
1230
1231
		return true;
1232
	}
1233
1234
	return false;
1235
}
1236
1237
let
1238
	__themeTimer = 0,
1239
	__themeAjax = null;
1240
1241
/**
1242
 * @param {string} value
1243
 * @param {function=} themeTrigger = noop
1244
 * @returns {void}
1245
 */
1246
export function changeTheme(value, themeTrigger = noop)
1247
{
1248
	const
1249
		themeLink = $('#app-theme-link'),
1250
		clearTimer = () => {
1251
			__themeTimer = window.setTimeout(() => themeTrigger(SaveSettingsStep.Idle), 1000);
1252
			__themeAjax = null;
1253
		};
1254
1255
	let
1256
		themeStyle = $('#app-theme-style'),
1257
		url = themeLink.attr('href');
1258
1259
	if (!url)
1260
	{
1261
		url = themeStyle.attr('data-href');
1262
	}
1263
1264
	if (url)
1265
	{
1266
		url = url.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + value + '/-/');
1267
		url = url.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/');
1268
		url = url.toString().replace(/\/Hash\/[^\/]+\//, '/Hash/-/');
1269
1270
		if ('Json/' !== url.substring(url.length - 5, url.length))
1271
		{
1272
			url += 'Json/';
1273
		}
1274
1275
		window.clearTimeout(__themeTimer);
1276
1277
		themeTrigger(SaveSettingsStep.Animate);
1278
1279
		if (__themeAjax && __themeAjax.abort)
1280
		{
1281
			__themeAjax.abort();
1282
		}
1283
1284
		__themeAjax = $.ajax({
1285
			url: url,
1286
			dataType: 'json'
1287
		}).then((data) => {
1288
1289
			if (data && isArray(data) && 2 === data.length)
1290
			{
1291
				if (themeLink && themeLink[0] && (!themeStyle || !themeStyle[0]))
1292
				{
1293
					themeStyle = $('<style id="app-theme-style"></style>');
1294
					themeLink.after(themeStyle);
1295
					themeLink.remove();
1296
				}
1297
1298
				if (themeStyle && themeStyle[0])
1299
				{
1300
					if (appendStyles(themeStyle, data[1]))
1301
					{
1302
						themeStyle.attr('data-href', url).attr('data-theme', data[0]);
1303
					}
1304
				}
1305
1306
				themeTrigger(SaveSettingsStep.TrueResult);
1307
			}
1308
1309
		}).then(clearTimer, clearTimer);
1310
	}
1311
}
1312
1313
/**
1314
 * @returns {function}
1315
 */
1316
export function computedPagenatorHelper(koCurrentPage, koPageCount)
1317
{
1318
	return () => {
1319
1320
		const
1321
			currentPage = koCurrentPage(),
1322
			pageCount = koPageCount(),
1323
			result = [],
1324
			fAdd = (index, push = true, customName = '') => {
1325
1326
				const data = {
1327
					current: index === currentPage,
1328
					name: '' === customName ? index.toString() : customName.toString(),
1329
					custom: '' !== customName,
1330
					title: '' === customName ? '' : index.toString(),
1331
					value: index.toString()
1332
				};
1333
1334
				if (push)
1335
				{
1336
					result.push(data);
1337
				}
1338
				else
1339
				{
1340
					result.unshift(data);
1341
				}
1342
			};
1343
1344
		let
1345
			prev = 0,
1346
			next = 0,
1347
			limit = 2;
1348
1349
		if (1 < pageCount || (0 < pageCount && pageCount < currentPage))
1350
		{
1351
			if (pageCount < currentPage)
1352
			{
1353
				fAdd(pageCount);
1354
				prev = pageCount;
1355
				next = pageCount;
1356
			}
1357
			else
1358
			{
1359
				if (3 >= currentPage || pageCount - 2 <= currentPage)
1360
				{
1361
					limit += 2;
1362
				}
1363
1364
				fAdd(currentPage);
1365
				prev = currentPage;
1366
				next = currentPage;
1367
			}
1368
1369
			while (0 < limit) {
1370
1371
				prev -= 1;
1372
				next += 1;
1373
1374
				if (0 < prev)
1375
				{
1376
					fAdd(prev, false);
1377
					limit -= 1;
1378
				}
1379
1380
				if (pageCount >= next)
1381
				{
1382
					fAdd(next, true);
1383
					limit -= 1;
1384
				}
1385
				else if (0 >= prev)
1386
				{
1387
					break;
1388
				}
1389
			}
1390
1391
			if (3 === prev)
1392
			{
1393
				fAdd(2, false);
1394
			}
1395
			else if (3 < prev)
1396
			{
1397
				fAdd(Math.round((prev - 1) / 2), false, '...');
1398
			}
1399
1400
			if (pageCount - 2 === next)
1401
			{
1402
				fAdd(pageCount - 1, true);
1403
			}
1404
			else if (pageCount - 2 > next)
1405
			{
1406
				fAdd(Math.round((pageCount + next) / 2), true, '...');
1407
			}
1408
1409
			// first and last
1410
			if (1 < prev)
1411
			{
1412
				fAdd(1, false);
1413
			}
1414
1415
			if (pageCount > next)
1416
			{
1417
				fAdd(pageCount, true);
1418
			}
1419
		}
1420
1421
		return result;
1422
	};
1423
}
1424
1425
/**
1426
 * @param {string} fileName
1427
 * @returns {string}
1428
 */
1429
export function getFileExtension(fileName)
1430
{
1431
	fileName = trim(fileName).toLowerCase();
1432
1433
	const result = fileName.split('.').pop();
1434
	return result === fileName ? '' : result;
1435
}
1436
1437
/**
1438
 * @param {string} fileName
1439
 * @returns {string}
1440
 */
1441
export function mimeContentType(fileName)
1442
{
1443
	let
1444
		ext = '',
1445
		result = 'application/octet-stream';
1446
1447
	fileName = trim(fileName).toLowerCase();
1448
1449
	if ('winmail.dat' === fileName)
1450
	{
1451
		return 'application/ms-tnef';
1452
	}
1453
1454
	ext = getFileExtension(fileName);
1455
	if (ext && 0 < ext.length && !isUnd(Mime[ext]))
1456
	{
1457
		result = Mime[ext];
1458
	}
1459
1460
	return result;
1461
}
1462
1463
/**
1464
 * @param {string} url
1465
 * @param {number} value
1466
 * @param {Function} fCallback
1467
 */
1468
export function resizeAndCrop(url, value, fCallback)
1469
{
1470
	const img = new window.Image();
1471
	img.onload = function() {
1472
1473
		let
1474
			diff = [0, 0];
0 ignored issues
show
Unused Code introduced by
The assignment to variable diff seems to be never used. Consider removing it.
Loading history...
1475
1476
		const
1477
			canvas = window.document.createElement('canvas'),
1478
			ctx = canvas.getContext('2d');
1479
1480
		canvas.width = value;
1481
		canvas.height = value;
1482
1483
		if (this.width > this.height)
1484
		{
1485
			diff = [this.width - this.height, 0];
1486
		}
1487
		else
1488
		{
1489
			diff = [0, this.height - this.width];
1490
		}
1491
1492
		ctx.fillStyle = '#fff';
1493
		ctx.fillRect(0, 0, value, value);
1494
		ctx.drawImage(this, diff[0] / 2, diff[1] / 2, this.width - diff[0], this.height - diff[1], 0, 0, value, value);
1495
1496
		fCallback(canvas.toDataURL('image/jpeg'));
1497
	};
1498
1499
	img.src = url;
1500
}
1501
1502
/**
1503
 * @param {string} mailToUrl
1504
 * @param {Function} PopupComposeVoreModel
1505
 * @returns {boolean}
1506
 */
1507
export function mailToHelper(mailToUrl, PopupComposeVoreModel)
1508
{
1509
	if (mailToUrl && 'mailto:' === mailToUrl.toString().substr(0, 7).toLowerCase())
1510
	{
1511
		if (!PopupComposeVoreModel)
1512
		{
1513
			return true;
1514
		}
1515
1516
		mailToUrl = mailToUrl.toString().substr(7);
1517
1518
		let
1519
			to = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable to seems to be never used. Consider removing it.
Loading history...
1520
			cc = null,
1521
			bcc = null,
1522
			params = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable params seems to be never used. Consider removing it.
Loading history...
1523
1524
		const
1525
			email = mailToUrl.replace(/\?.+$/, ''),
1526
			query = mailToUrl.replace(/^[^\?]*\?/, ''),
1527
			EmailModel = require('Model/Email').default,
1528
			emailObj = new EmailModel(),
1529
			fParseEmailLine = (line) => (line ? _.compact(_.map(decodeURIComponent(line).split(/[,]/), (item) => {
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
Bug introduced by
The variable line seems to be never initialized.
Loading history...
1530
				emailObj.clear();
1531
				emailObj.mailsoParse(item);
1532
				return '' !== emailObj.email ? emailObj : null;
1533
			})) : null);
1534
1535
		to = fParseEmailLine(email);
1536
		params = simpleQueryParser(query);
1537
1538
		if (!isUnd(params.cc))
1539
		{
1540
			cc = fParseEmailLine(decodeURIComponent(params.cc));
1541
		}
1542
1543
		if (!isUnd(params.bcc))
1544
		{
1545
			bcc = fParseEmailLine(decodeURIComponent(params.bcc));
1546
		}
1547
1548
		require('Knoin/Knoin').showScreenPopup(PopupComposeVoreModel, [
1549
			ComposeType.Empty, null, to, cc, bcc,
1550
			isUnd(params.subject) ? null : pString(decodeURIComponent(params.subject)),
1551
			isUnd(params.body) ? null : plainToHtml(pString(decodeURIComponent(params.body)))
1552
		]);
1553
1554
		return true;
1555
	}
1556
1557
	return false;
1558
}
1559
1560
/**
1561
 * @param {Function} fn
1562
 * @returns {void}
1563
 */
1564
export function domReady(fn)
1565
{
1566
	$(() => fn());
1567
//
1568
//	if ('loading' !== window.document.readyState)
1569
//	{
1570
//		fn();
1571
//	}
1572
//	else
1573
//	{
1574
//		window.document.addEventListener('DOMContentLoaded', fn);
1575
//	}
1576
}
1577
1578
export const windowResize = _.debounce((timeout) => {
1579
	if (isUnd(timeout) || isNull(timeout))
1580
	{
1581
		$win.resize();
1582
	}
1583
	else
1584
	{
1585
		window.setTimeout(() => {
1586
			$win.resize();
1587
		}, timeout);
1588
	}
1589
}, 50);
1590
1591
/**
1592
 * @returns {void}
1593
 */
1594
export function windowResizeCallback()
1595
{
1596
	windowResize();
1597
}
1598
1599
let substr = window.String.substr;
1600
if ('b' !== 'ab'.substr(-1))
1601
{
1602
	substr = (str, start, length) => {
1603
		start = 0 > start ? str.length + start : start;
1604
		return str.substr(start, length);
1605
	};
1606
1607
	window.String.substr = substr;
1608
}
1609