1 /**
  2  * @file Window window
  3  *
  4  * @author Dominik Kocuj
  5  * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2 or later
  6  * @copyright Copyright (c) 2016-2018 kocuj.pl
  7  */
  8 
  9 (function() {})(); // empty function for correct minify with comments
 10 //'use strict'; // for jshint uncomment this and comment line above
 11 
 12 /* jshint strict: true */
 13 /* jshint -W034 */
 14 
 15 /* global document */
 16 /* global jQuery */
 17 /* global window */
 18 
 19 /* global kocujILV12aHelper */
 20 /* global kocujILV12aAllJsAjax */
 21 
 22 /* global kocujILV12aAllWindowVals */
 23 
 24 /**
 25  * Windows types
 26  *
 27  * @namespace kocujILV12aAllWindowType
 28  * @public
 29  */
 30 var kocujILV12aAllWindowType = {
 31 	/**
 32 	 * Window with standard content
 33 	 *
 34 	 * @public
 35 	 * @const {number}
 36 	 */
 37 	STANDARD : 0,
 38 
 39 	/**
 40 	 * Window with AJAX content
 41 	 *
 42 	 * @public
 43 	 * @const {number}
 44 	 */
 45 	AJAX : 1,
 46 
 47 	/**
 48 	 * Information about maximum constant value; it should not be used in executing the window script methods
 49 	 *
 50 	 * @public
 51 	 * @const {number}
 52 	 */
 53 	LAST : 1
 54 };
 55 
 56 /**
 57  * Window window prototype constructor
 58  *
 59  * @constructs
 60  * @namespace kocujILV12aCAllWindow
 61  * @public
 62  * @return {void}
 63  */
 64 function kocujILV12aCAllWindow() {
 65 	'use strict';
 66 	/* jshint validthis: true */
 67 	// get this object
 68 	var self = this;
 69 	// initialize objects
 70 	self._objHelper = kocujILV12aHelper;
 71 	self._objAllJsAjax = kocujILV12aAllJsAjax;
 72 	// get current script filename
 73 	self._thisFilename = document.scripts[document.scripts.length-1].src;
 74 	// get settings
 75 	var vals = kocujILV12aAllWindowVals;
 76 	if (vals.throwErrors === '1') {
 77 		self._valsThrowErrors = true;
 78 	} else {
 79 		self._valsThrowErrors = false;
 80 	}
 81 	self._valsPrefix = vals.prefix;
 82 	self._valsDialogCssUrl = vals.dialogCssUrl;
 83 	self._valsTextLoading = vals.textLoading;
 84 	self._valsTextLoadingError = vals.textLoadingError;
 85 }
 86 
 87 /**
 88  * Window prototype
 89  *
 90  * @namespace kocujILV12aCAllWindow
 91  * @public
 92  */
 93 kocujILV12aCAllWindow.prototype = {
 94 	/**
 95 	 * Object kocujILV12aHelper
 96 	 *
 97 	 * @private
 98 	 * @type {Object}
 99 	 */
100 	_objHelper : null,
101 
102 	/**
103 	 * Object kocujILV12aAllJsAjax
104 	 *
105 	 * @private
106 	 * @type {Object}
107 	 */
108 	_objAllJsAjax : null,
109 
110 	/**
111 	 * Current script filename
112 	 *
113 	 * @private
114 	 * @type {string}
115 	 */
116 	_thisFilename : '',
117 
118 	/**
119 	 * Projects list
120 	 *
121 	 * @private
122 	 * @type {Array}
123 	 */
124 	_prj : [],
125 
126 	/**
127 	 * Script settings - throw errors (true) or not (false)
128 	 *
129 	 * @private
130 	 * @type {string}
131 	 */
132 	_valsThrowErrors : false,
133 
134 	/**
135 	 * Script settings - prefix
136 	 *
137 	 * @private
138 	 * @type {string}
139 	 */
140 	_valsPrefix : '',
141 
142 	/**
143 	 * Script settings - dialog window CSS URL
144 	 *
145 	 * @private
146 	 * @type {string}
147 	 */
148 	_valsDialogCssUrl : '',
149 
150 	/**
151 	 * Script settings - text for loading
152 	 *
153 	 * @private
154 	 * @type {string}
155 	 */
156 	_valsTextLoading : '',
157 
158 	/**
159 	 * Script settings - text for loading error
160 	 *
161 	 * @private
162 	 * @type {string}
163 	 */
164 	_valsTextLoadingError : '',
165 
166 	/**
167 	 * Add project
168 	 *
169 	 * @public
170 	 * @param {string} projectId Project identifier
171 	 * @return {void}
172 	 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.PROJECT_ALREADY_EXISTS if project identifier entered in projectId already exists
173 	 */
174 	addProject : function(projectId) {
175 		'use strict';
176 		// parse arguments
177 		var args = this._checkAddProject(projectId);
178 		// add project
179 		if (this._prj['prj_' + args.projectId] === undefined) {
180 			this.addProjectIfNotExists(args.projectId);
181 		} else {
182 			this._throwError('PROJECT_ALREADY_EXISTS', args.projectId);
183 			return;
184 		}
185 	},
186 
187 	/**
188 	 * Add project if not exists
189 	 *
190 	 * @public
191 	 * @param {string} projectId Project identifier
192 	 * @return {void}
193 	 */
194 	addProjectIfNotExists : function(projectId) {
195 		'use strict';
196 		// get this object
197 		var self = this;
198 		(function($) {
199 			// parse arguments
200 			var args = self._checkAddProject(projectId);
201 			// add project
202 			if (self._prj['prj_' + args.projectId] === undefined) {
203 				// add project
204 				self._prj['prj_' + args.projectId] = {
205 					timer         : null,
206 					cssLoaded     : false,
207 					windowsTimers : []
208 				};
209 				// add stylesheet
210 				var stylesheet = $('<link id="' + self._getHTMLNameStylesheet(args.projectId) + '" rel="stylesheet" href="' + self._valsDialogCssUrl + '" type="text/css" media="all" />');
211 				stylesheet.load(function() {
212 					self._checkStylesheet(args.projectId);
213 				});
214 				$('head').append(stylesheet);
215 				// add dummy element for checking style loading
216 				$('body').prepend('<div id="' + self._getHTMLNameDummy(args.projectId) + '" class="ui-dialog" style="display:none;"></div>');
217 				// set timer for waiting
218 				if (!self._checkStylesheet(args.projectId)) {
219 					self._prj['prj_' + args.projectId].timer = window.setInterval(function() {
220 						// check stylesheet
221 						if (self._checkStylesheet(args.projectId)) {
222 							// clear timer
223 							window.clearInterval(self._prj['prj_' + args.projectId].timer);
224 							self._prj['prj_' + args.projectId].timer = null;
225 						}
226 					}, 100);
227 				}
228 			}
229 			self._objAllJsAjax.addProjectIfNotExists(args.projectId);
230 		}(jQuery));
231 	},
232 
233 	/**
234 	 * Get HTML selector for stylesheet
235 	 *
236 	 * @public
237 	 * @param {string} projectId Project identifier
238 	 * @return {string} HTML selector for stylesheet
239 	 */
240 	getHTMLSelectorStylesheet : function(projectId) {
241 		'use strict';
242 		// parse arguments
243 		projectId = this._parseProjectId(projectId);
244 		// exit
245 		return '#' + this._getHTMLNameStylesheet(projectId);
246 	},
247 
248 	/**
249 	 * Get HTML selector for dummy element
250 	 *
251 	 * @public
252 	 * @param {string} projectId Project identifier
253 	 * @return {string} HTML selector for dummy element
254 	 */
255 	getHTMLSelectorDummy : function(projectId) {
256 		'use strict';
257 		// parse arguments
258 		projectId = this._parseProjectId(projectId);
259 		// exit
260 		return '#' + this._getHTMLNameDummy(projectId);
261 	},
262 
263 	/**
264 	 * Get HTML selector for window
265 	 *
266 	 * @public
267 	 * @param {string} projectId Project identifier
268 	 * @param {string} windowId Window identifier
269 	 * @return {string} HTML selector for window
270 	 */
271 	getHTMLSelectorWindow : function(projectId, windowId) {
272 		'use strict';
273 		// parse arguments
274 		projectId = this._parseProjectId(projectId);
275 		windowId = this._objHelper.initString(windowId);
276 		// exit
277 		return '#' + this._getHTMLNameWindow(projectId, windowId);
278 	},
279 
280 	/**
281 	 * Get HTML selector for window content
282 	 *
283 	 * @public
284 	 * @param {string} projectId Project identifier
285 	 * @param {string} windowId Window identifier
286 	 * @return {string} HTML selector for window content
287 	 */
288 	getHTMLSelectorContent : function(projectId, windowId) {
289 		'use strict';
290 		// parse arguments
291 		projectId = this._parseProjectId(projectId);
292 		windowId = this._objHelper.initString(windowId);
293 		// exit
294 		return '#' + this._getHTMLNameContent(projectId, windowId);
295 	},
296 
297 	/**
298 	 * Get HTML selector for window content inside
299 	 *
300 	 * @public
301 	 * @param {string} projectId Project identifier
302 	 * @param {string} windowId Window identifier
303 	 * @return {string} HTML selector for window content inside
304 	 */
305 	getHTMLSelectorContentInside : function(projectId, windowId) {
306 		'use strict';
307 		// parse arguments
308 		projectId = this._parseProjectId(projectId);
309 		windowId = this._objHelper.initString(windowId);
310 		// exit
311 		return '#' + this._getHTMLNameContentInside(projectId, windowId);
312 	},
313 
314 	/**
315 	 * Show window
316 	 *
317 	 * @public
318 	 * @param {string} projectId Project identifier
319 	 * @param {string} windowId Window identifier
320 	 * @param {number} type Window type
321 	 * @param {Object} attr Window attributes
322 	 * @return {void}
323 	 */
324 	show : function(projectId, windowId, type, attr) {
325 		'use strict';
326 		// get this object
327 		var self = this;
328 		(function($) {
329 			// parse arguments
330 			projectId = self._parseProjectId(projectId);
331 			windowId = self._objHelper.initString(windowId);
332 			type = self._objHelper.initNumeric(type);
333 			if (type > kocujILV12aAllWindowType.LAST) {
334 				self._throwError('WINDOW_WRONG_TYPE');
335 				return;
336 			}
337 			attr = self._objHelper.initObject(attr);
338 			switch (type) {
339 				case kocujILV12aAllWindowType.STANDARD:
340 					if (!('content' in attr)) {
341 						self._throwError('WINDOW_WRONG_ATTRIBUTES');
342 						return;
343 					}
344 					break;
345 				case kocujILV12aAllWindowType.AJAX:
346 					if ((!('url' in attr)) || (!('ajaxData' in attr))) {
347 						self._throwError('WINDOW_WRONG_ATTRIBUTES');
348 						return;
349 					}
350 					break;
351 			}
352 			// show window
353 			if (self._checkStylesheet(projectId)) {
354 				self._showWindow(projectId, windowId, type, attr);
355 			} else {
356 				self._prj['prj_' + projectId].windowsTimers['win_' + windowId] = window.setInterval(function() {
357 					// optionally show window
358 					if (self._checkStylesheet(projectId)) {
359 						// clear timer
360 						window.clearInterval(self._prj['prj_' + projectId].windowsTimers['win_' + windowId]);
361 						self._prj['prj_' + projectId].windowsTimers['win_' + windowId] = null;
362 						// show window
363 						self._showWindow(projectId, windowId, type, attr);
364 					}
365 				}, 2000);
366 			}
367 		}(jQuery));
368 	},
369 
370 	/**
371 	 * AJAX loading success callback
372 	 *
373 	 * @public
374 	 * @param {string} projectId Project identifier
375 	 * @param {string} connectionId Connection identifier
376 	 * @param {anything} data Data
377 	 * @param {string} status Text status
378 	 * @param {Object} obj Request object
379 	 * @return {void}
380 	 */
381 	ajaxSuccessCallback : function(projectId, connectionId, data, status, obj) {
382 		'use strict';
383 		// get this object
384 		var self = kocujILV12aAllWindow;
385 		(function($) {
386 			// parse parameters
387 			data = self._objHelper.initString(data);
388 			// get window identifier
389 			var tmp = connectionId.split('__');
390 			var windowId = tmp[tmp.length-1];
391 			// set HTML data
392 			$(self.getHTMLSelectorContentInside(projectId, windowId)).html(data);
393 		}(jQuery));
394 	},
395 
396 	/**
397 	 * AJAX loading error callback
398 	 *
399 	 * @public
400 	 * @param {string} projectId Project identifier
401 	 * @param {string} connectionId Connection identifier
402 	 * @param {Object} obj Request object
403 	 * @param {string} status Text status
404 	 * @param {string} err Error
405 	 * @return {void}
406 	 */
407 	ajaxErrorCallback : function(projectId, connectionId, obj, status, err) {
408 		'use strict';
409 		// get this object
410 		var self = kocujILV12aAllWindow;
411 		(function($) {
412 			// get window identifier
413 			var tmp = connectionId.split('__');
414 			var windowId = tmp[tmp.length-1];
415 			// set HTML data
416 			$(self.getHTMLSelectorContentInside(projectId, windowId)).html(self._valsTextLoadingError);
417 		}(jQuery));
418 	},
419 
420 	/**
421 	 * Get HTML prefix
422 	 *
423 	 * @private
424 	 * @param {string} projectId Project identifier
425 	 * @return {string} HTML prefix
426 	 */
427 	_getHTMLPrefix : function(projectId) {
428 		'use strict';
429 		// exit
430 		return this._valsPrefix + '_' + projectId + '__';
431 	},
432 
433 	/**
434 	 * Get HTML prefix for stylesheet
435 	 *
436 	 * @private
437 	 * @param {string} projectId Project identifier
438 	 * @return {string} HTML prefix for stylesheet
439 	 */
440 	_getHTMLNameStylesheet : function(projectId) {
441 		'use strict';
442 		// exit
443 		return this._getHTMLPrefix(projectId) + 'window_stylesheet';
444 	},
445 
446 	/**
447 	 * Get HTML prefix for dummy element
448 	 *
449 	 * @private
450 	 * @param {string} projectId Project identifier
451 	 * @return {string} HTML prefix for dummy element
452 	 */
453 	_getHTMLNameDummy : function(projectId) {
454 		'use strict';
455 		// exit
456 		return this._getHTMLPrefix(projectId) + 'window_dummy';
457 	},
458 
459 	/**
460 	 * Get HTML prefix for window
461 	 *
462 	 * @private
463 	 * @param {string} projectId Project identifier
464 	 * @param {string} windowId Window identifier
465 	 * @return {string} HTML prefix for window
466 	 */
467 	_getHTMLNameWindow : function(projectId, windowId) {
468 		'use strict';
469 		// exit
470 		return this._getHTMLPrefix(projectId) + 'window__' + windowId;
471 	},
472 
473 	/**
474 	 * Get HTML prefix for window content
475 	 *
476 	 * @private
477 	 * @param {string} projectId Project identifier
478 	 * @param {string} windowId Window identifier
479 	 * @return {string} HTML prefix for window content
480 	 */
481 	_getHTMLNameContent : function(projectId, windowId) {
482 		'use strict';
483 		// exit
484 		return this._getHTMLPrefix(projectId) + 'window_content__' + windowId;
485 	},
486 
487 	/**
488 	 * Get HTML prefix for window content inside
489 	 *
490 	 * @private
491 	 * @param {string} projectId Project identifier
492 	 * @param {string} windowId Window identifier
493 	 * @return {string} HTML prefix for window content inside
494 	 */
495 	_getHTMLNameContentInside : function(projectId, windowId) {
496 		'use strict';
497 		// exit
498 		return this._getHTMLPrefix(projectId) + 'window_content_inside__' + windowId;
499 	},
500 
501 	/**
502 	 * Parse project identifier
503 	 *
504 	 * @private
505 	 * @param {string} projectId Project identifier
506 	 * @return {string} Parsed project identifier
507 	 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.EMPTY_PROJECT_ID if project identifier entered in projectId is empty
508 	 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.PROJECT_DOES_NOT_EXIST if project identifier entered in projectId does not exist
509 	 */
510 	_parseProjectId : function(projectId) {
511 		'use strict';
512 		// parse project identifier
513 		projectId = this._objHelper.initString(projectId);
514 		if (projectId === '') {
515 			this._throwError('EMPTY_PROJECT_ID');
516 			return;
517 		}
518 		// check if project exists
519 		if (this._prj['prj_' + projectId] === undefined) {
520 			this._throwError('PROJECT_DOES_NOT_EXIST', projectId);
521 			return;
522 		}
523 		// exit
524 		return projectId;
525 	},
526 
527 	/**
528 	 * Check arguments for adding project
529 	 *
530 	 * @private
531 	 * @param {string} projectId Project identifier
532 	 * @return {Object} Parsed arguments for adding project
533 	 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.EMPTY_PROJECT_ID if project identifier entered in projectId is empty
534 	 */
535 	_checkAddProject : function(projectId) {
536 		'use strict';
537 		// parse arguments
538 		projectId = this._objHelper.initString(projectId);
539 		if (projectId === '') {
540 			this._throwError('EMPTY_PROJECT_ID');
541 			return;
542 		}
543 		// exit
544 		return {
545 			projectId : projectId
546 		};
547 	},
548 
549 	/**
550 	 * Throw an error if debugging is enabled
551 	 *
552 	 * @private
553 	 * @param {string} codeString Error code in string format
554 	 * @param {string} [param] Parameter for error information
555 	 * @return {void}
556 	 */
557 	_throwError : function(codeString, param) {
558 		'use strict';
559 		// parse arguments
560 		codeString = this._objHelper.initString(codeString);
561 		if (codeString === '') {
562 			return;
563 		}
564 		param = this._objHelper.initString(param);
565 		// throw an error
566 		if (this._valsThrowErrors) {
567 			/* jshint evil: true */
568 			eval('throw new kocujILV12aCException(kocujILV12aExceptionCode.' + codeString + ', this._thisFilename, param);');
569 		}
570 	},
571 
572 	/**
573 	 * Check window stylesheet
574 	 *
575 	 * @private
576 	 * @param {string} projectId Project identifier
577 	 * @return {boolean} Stylesheet has been loaded (true) or not (false)
578 	 */
579 	_checkStylesheet : function(projectId) {
580 		'use strict';
581 		// check if stylesheet has not been loaded already
582 		if (this._prj['prj_' + projectId].cssLoaded) {
583 			return true;
584 		}
585 		// get this object
586 		var self = this;
587 		(function($) {
588 			// set flag for loaded CSS
589 			if ($(self.getHTMLSelectorDummy(projectId)).css('position') === 'absolute') {
590 				self._prj['prj_' + projectId].cssLoaded = true;
591 			}
592 		}(jQuery));
593 		// exit
594 		return this._prj['prj_' + projectId].cssLoaded;
595 	},
596 
597 	/**
598 	 * Show window now
599 	 *
600 	 * @private
601 	 * @param {string} projectId Project identifier
602 	 * @param {string} windowId Window identifier
603 	 * @param {number} type Window type
604 	 * @param {Object} attr Window attributes
605 	 * @return {void}
606 	 */
607 	_showWindow : function(projectId, windowId, type, attr) {
608 		'use strict';
609 		// get this object
610 		var self = this;
611 		(function($) {
612 			// remove old dialog content
613 			if ($(self.getHTMLSelectorWindow(projectId, windowId)).length !== 0) {
614 				$(self.getHTMLSelectorWindow(projectId, windowId)).remove();
615 			}
616 			// add dialog content
617 			$('body').append('<div id="' + self._getHTMLNameWindow(projectId, windowId) + '" style="padding:0;"><div id="' + self._getHTMLNameContent(projectId, windowId) + '" style="height:100%;padding:0;margin:0;overflow-x:hidden;overflow-y:scroll;"><div id="' + self._getHTMLNameContentInside(projectId, windowId) + '" style="padding:10px;"></div></div></div>');
618 			$(self.getHTMLSelectorContentInside(projectId, windowId)).html('');
619 			switch (type) {
620 				case kocujILV12aAllWindowType.STANDARD:
621 					$(self.getHTMLSelectorContentInside(projectId, windowId)).html(attr.content);
622 					break;
623 				case kocujILV12aAllWindowType.AJAX:
624 					$(self.getHTMLSelectorContentInside(projectId, windowId)).html(self._valsTextLoading);
625 					break;
626 			}
627 			// set dialog content styles
628 			if ('contentCss' in attr) {
629 				$.each(attr.contentCss, function(key, value) {
630 					$(self.getHTMLSelectorContentInside(projectId, windowId)).css(key, value.split('"').join('"'));
631 				});
632 			}
633 			// show window
634 			$(self.getHTMLSelectorWindow(projectId, windowId)).dialog({
635 				width       : attr.width,
636 				height      : attr.height,
637 				title       : attr.title,
638 				modal       : true,
639 				draggable   : false,
640 				resizable   : false,
641 				responsive  : true,
642 				show        : 'fade',
643 				hide        : 'fade',
644 				open        : function() {
645 					$('.ui-widget-overlay').hide().fadeIn();
646 				},
647 				beforeClose : function() {
648 					$('.ui-widget-overlay').remove();
649 					$('<div />', {
650 						'class' : 'ui-widget-overlay'
651 					}).css({
652 						width  : $(document).width(),
653 						height : $(document).height(),
654 						zIndex : 1001
655 					}).appendTo('body').fadeOut(function(){
656 						$(this).remove();
657 					});
658 				}
659 			});
660 			// change title bar style
661 			$(self.getHTMLSelectorWindow(projectId, windowId)).parent().find('.ui-dialog-title').css({
662 				'overflow' : 'hidden',
663 				'display'  : 'block',
664 				'height'   : '100%'
665 			});
666 			// optionally send AJAX request
667 			if (type === kocujILV12aAllWindowType.AJAX) {
668 				self._objAllJsAjax.sendPost(projectId, 'window__' + windowId, attr.url, 'text', attr.ajaxData, {
669 					success : self.ajaxSuccessCallback,
670 					error   : self.ajaxErrorCallback
671 				});
672 			}
673 		}(jQuery));
674 	}
675 };
676 
677 // initialize
678 var kocujILV12aAllWindow = new kocujILV12aCAllWindow();
679