1 /** |
|
2 * MyAMS skin management |
|
3 */ |
|
4 (function($, globals) { |
|
5 |
|
6 var ams = globals.MyAMS; |
|
7 |
|
8 ams.skin = { |
|
9 |
|
10 /** |
|
11 * Compute navigation page height |
|
12 */ |
|
13 _setPageHeight: function() { |
|
14 var mainHeight = $('#main').height(); |
|
15 var windowHeight = $(window).height() - ams.navbarHeight; |
|
16 if (mainHeight > windowHeight) { |
|
17 ams.root.css('min-height', mainHeight + ams.navbarHeight); |
|
18 } else { |
|
19 ams.root.css('min-height', windowHeight); |
|
20 } |
|
21 ams.leftPanel.css('min-height', windowHeight); |
|
22 ams.leftPanel.css('max-height', windowHeight); |
|
23 }, |
|
24 |
|
25 /** |
|
26 * Check width for mobile devices |
|
27 */ |
|
28 _checkMobileWidth: function() { |
|
29 if ($(window).width() < 979) { |
|
30 ams.root.addClass('mobile-view-activated'); |
|
31 } else if (ams.root.hasClass('mobile-view-activated')) { |
|
32 ams.root.removeClass('mobile-view-activated'); |
|
33 } |
|
34 }, |
|
35 |
|
36 /** |
|
37 * Show/hide shortcut buttons |
|
38 */ |
|
39 _showShortcutButtons: function() { |
|
40 ams.shortcuts && ams.shortcuts.animate({ |
|
41 height: 'show' |
|
42 }, 200, 'easeOutCirc'); |
|
43 ams.root.addClass('shortcut-on'); |
|
44 }, |
|
45 |
|
46 _hideShortcutButtons: function() { |
|
47 ams.shortcuts && ams.shortcuts.animate({ |
|
48 height: 'hide' |
|
49 }, 300, 'easeOutCirc'); |
|
50 ams.root.removeClass('shortcut-on'); |
|
51 }, |
|
52 |
|
53 /** |
|
54 * Check notification badge |
|
55 */ |
|
56 checkNotification: function() { |
|
57 var badge = $('.badge', '#user-activity >span'); |
|
58 if (parseInt(badge.text()) > 0) { |
|
59 badge.removeClass("hidden") |
|
60 .addClass("bg-color-red bounceIn animated"); |
|
61 } else { |
|
62 badge.addClass("hidden") |
|
63 .removeClass("bg-color-red bounceIn animated"); |
|
64 } |
|
65 }, |
|
66 |
|
67 refreshNotificationsPanel: function(e) { |
|
68 var button = $(this); |
|
69 button.addClass('disabled'); |
|
70 $('i', button).addClass('fa-spin'); |
|
71 $('input[name="activity"]:checked', '#user-activity').change(); |
|
72 $('i', button).removeClass('fa-spin'); |
|
73 button.removeClass('disabled'); |
|
74 }, |
|
75 |
|
76 /** |
|
77 * Replace given form with new content |
|
78 */ |
|
79 refreshContent: function(options) { |
|
80 var target = $('[id="' + options.object_id + '"]'); |
|
81 target.replaceWith($(options.content)); |
|
82 target = $('[id="' + options.object_id + '"]'); |
|
83 ams.initContent && ams.initContent(target); |
|
84 return target; |
|
85 }, |
|
86 |
|
87 /** |
|
88 * Replace given image from updated source |
|
89 */ |
|
90 refreshImage: function(options) { |
|
91 $('img[src^="' + options.src + '"]').attr('src', options.target); |
|
92 }, |
|
93 |
|
94 /** |
|
95 * Replace given widget with given content |
|
96 */ |
|
97 refreshWidget: function(options) { |
|
98 var target = $('[id="' + options.parent_id + '"]'); |
|
99 var widget = $('[name="' + options.widget_name + '"]', target); |
|
100 if (!widget.exists()) { |
|
101 widget = $('[name="' + options.widget_name + ':list"]', target); |
|
102 } |
|
103 var label = widget.parents('.input').last(); |
|
104 label.html(options.content); |
|
105 ams.initContent && ams.initContent(label); |
|
106 return label; |
|
107 }, |
|
108 |
|
109 /** |
|
110 * Replace given table with new content |
|
111 */ |
|
112 refreshTable: function(options) { |
|
113 var widget = $('[id="' + options.object_id + '"]').parents('.ams-widget:first'); |
|
114 widget.replaceWith($(options.table)); |
|
115 widget = $('[id="' + options.object_id + '"]').parents('.ams-widget:first'); |
|
116 ams.initContent && ams.initContent(widget); |
|
117 return widget; |
|
118 }, |
|
119 |
|
120 /** |
|
121 * Replace given table with new content |
|
122 * If table is located inside a switched fieldset, fieldset is opened |
|
123 */ |
|
124 refreshSwitchedTable: function(options) { |
|
125 var widget = ams.skin.refreshTable(options); |
|
126 if (widget) { |
|
127 var legend = widget.siblings('legend'); |
|
128 if (legend.parents('fieldset:first').hasClass('switched')) { |
|
129 legend.click(); |
|
130 } |
|
131 } |
|
132 }, |
|
133 |
|
134 /** |
|
135 * Replace given row with new content |
|
136 */ |
|
137 refreshRow: function(options) { |
|
138 var tr = $('tr[id="' + options.object_id + '"]'); |
|
139 var table = tr.parents('table').first(); |
|
140 var new_tr = $(options.row); |
|
141 tr.replaceWith(new_tr); |
|
142 ams.initContent && ams.initContent(new_tr); |
|
143 if (table.hasClass('table-dnd')) { |
|
144 new_tr.addClass('no-drag-handle'); |
|
145 table.tableDnDUpdate(); |
|
146 } |
|
147 return new_tr; |
|
148 }, |
|
149 |
|
150 /** |
|
151 * Replace given row cell with new content |
|
152 */ |
|
153 refreshRowCell: function(options) { |
|
154 var tr = $('tr[id="' + options.object_id + '"]'); |
|
155 var table = tr.parents('table').first(); |
|
156 var headRow = $('tr', $('thead', table)); |
|
157 var headCell = $('th[data-ams-column-name="' + options.col_name + '"]', headRow); |
|
158 var index = $('th', headRow).index(headCell); |
|
159 if (index > -1) { |
|
160 var cell = $($('td', tr).get(index)); |
|
161 cell.html(options.cell); |
|
162 ams.initContent && ams.initContent(cell); |
|
163 } |
|
164 }, |
|
165 |
|
166 switchCellContent: function(element) { |
|
167 var source = $(this); |
|
168 var switcher = $('i.switch', source); |
|
169 var td = source.parents('td'); |
|
170 var innerdiv = $(source.data('ams-switch-target') || '.inner-table-form', td); |
|
171 var datatype = source.parents('tr'); |
|
172 if (switcher.hasClass('fa-plus-square-o')) { |
|
173 var container = datatype.parents('table'); |
|
174 innerdiv.html('<h1 class="loading"><i class="fa fa-gear fa-spin"></i></h1>'); |
|
175 ams.ajax && ams.ajax.post(container.data('ams-location') + '/' + source.data('ams-switch-handler'), |
|
176 {object_name: datatype.data('ams-element-name')}, |
|
177 function(result) { |
|
178 innerdiv.html(result); |
|
179 if (result) { |
|
180 ams.initContent && ams.initContent(innerdiv); |
|
181 switcher.removeClass('fa-plus-square-o') |
|
182 .addClass('fa-minus-square-o'); |
|
183 } |
|
184 }); |
|
185 } else { |
|
186 ams.skin.cleanContainer(innerdiv); |
|
187 innerdiv.empty(); |
|
188 switcher.removeClass('fa-minus-square-o') |
|
189 .addClass('fa-plus-square-o'); |
|
190 } |
|
191 }, |
|
192 |
|
193 /** |
|
194 * Initialize desktop and mobile widgets |
|
195 */ |
|
196 _initDesktopWidgets: function(element) { |
|
197 if (ams.enableWidgets) { |
|
198 var widgets = $('.ams-widget', element); |
|
199 if (widgets.length > 0) { |
|
200 ams.ajax && ams.ajax.check($.fn.MyAMSWidget, |
|
201 ams.baseURL + 'myams-widgets' + ams.devext + '.js', |
|
202 function() { |
|
203 widgets.each(function() { |
|
204 var widget = $(this); |
|
205 var data = widget.data(); |
|
206 var dataOptions = { |
|
207 deleteSettingsKey: '#deletesettingskey-options', |
|
208 deletePositionKey: '#deletepositionkey-options' |
|
209 }; |
|
210 var settings = $.extend({}, dataOptions, data.amsWidgetOptions); |
|
211 settings = ams.executeFunctionByName(data.amsWidgetInitcallback, widget, settings) || settings; |
|
212 widget.MyAMSWidget(settings); |
|
213 }); |
|
214 globals.MyAMSWidget.initWidgetsGrid($('.ams-widget-grid', element)); |
|
215 }); |
|
216 } |
|
217 } |
|
218 }, |
|
219 |
|
220 _initMobileWidgets: function(element) { |
|
221 if (ams.enableMobile && ams.enableWidgets) { |
|
222 ams.skin._initDesktopWidgets(element); |
|
223 } |
|
224 }, |
|
225 |
|
226 /** |
|
227 * Add an alert on top of a container |
|
228 * |
|
229 * @parent: parent container where the alert will be displayed |
|
230 * @status: info, success, warning or danger |
|
231 * @header: alert header |
|
232 * @message: main alert message |
|
233 * @subtitle: optional subtitle |
|
234 * @margin: if true, a margin will be displayed around alert |
|
235 */ |
|
236 alert: function(parent, status, header, message, subtitle, margin) { |
|
237 if (status === 'error') { |
|
238 status = 'danger'; |
|
239 } |
|
240 $('.alert-' + status, parent).not('.persistent').remove(); |
|
241 var content = '<div class="' + (margin ? 'margin-10' : '') + ' alert alert-block alert-' + status + ' padding-5 fade in">' + |
|
242 '<a class="close" data-dismiss="alert"><i class="fa fa-check"></i></a>' + |
|
243 '<h4 class="alert-heading">' + |
|
244 '<i class="fa fa-fw fa-warning"></i> ' + header + |
|
245 '</h4>' + |
|
246 (subtitle ? ('<p>' + subtitle + '</p>') : ''); |
|
247 if (typeof (message) === 'string') { |
|
248 content += '<ul><li>' + message + '</li></ul>'; |
|
249 } else if (message) { |
|
250 content += '<ul>'; |
|
251 for (var index in message) { |
|
252 if (!$.isNumeric(index)) { // IE check |
|
253 continue; |
|
254 } |
|
255 content += '<li>' + message[index] + '</li>'; |
|
256 } |
|
257 content += '</ul>'; |
|
258 } |
|
259 content += '</div>'; |
|
260 $(content).insertBefore(parent); |
|
261 if (parent.exists) { |
|
262 ams.skin.scrollTo(parent, {offset: {top: -50}}); |
|
263 } |
|
264 }, |
|
265 |
|
266 /** |
|
267 * Big message box |
|
268 */ |
|
269 bigBox: function(options, callback) { |
|
270 ams.ajax && ams.ajax.check(ams.notify, |
|
271 ams.baseURL + 'myams-notify' + ams.devext + '.js', |
|
272 function() { |
|
273 ams.notify.messageBox(options, callback); |
|
274 }); |
|
275 }, |
|
276 |
|
277 /** |
|
278 * Medium notification message box, displayed on page's bottom right |
|
279 */ |
|
280 messageBox: function(status, options, callback) { |
|
281 if (typeof (status) === 'object') { |
|
282 callback = options; |
|
283 options = status || {}; |
|
284 status = 'info'; |
|
285 } |
|
286 ams.ajax && ams.ajax.check(ams.notify, |
|
287 ams.baseURL + 'myams-notify' + ams.devext + '.js', |
|
288 function() { |
|
289 switch (status) { |
|
290 case 'error': |
|
291 case 'danger': |
|
292 options.color = '#C46A69'; |
|
293 break; |
|
294 case 'warning': |
|
295 options.color = '#C79121'; |
|
296 break; |
|
297 case 'success': |
|
298 options.color = '#739E73'; |
|
299 break; |
|
300 default: |
|
301 options.color = options.color || '#3276B1'; |
|
302 } |
|
303 options.sound = false; |
|
304 ams.notify.bigBox(options, callback); |
|
305 }); |
|
306 }, |
|
307 |
|
308 /** |
|
309 * Small notification message box, displayed on page's top right |
|
310 */ |
|
311 smallBox: function(status, options, callback) { |
|
312 if (typeof (status) === 'object') { |
|
313 callback = options; |
|
314 options = status || {}; |
|
315 status = 'info'; |
|
316 } |
|
317 ams.ajax && ams.ajax.check(ams.notify, |
|
318 ams.baseURL + 'myams-notify' + ams.devext + '.js', |
|
319 function() { |
|
320 switch (status) { |
|
321 case 'error': |
|
322 case 'danger': |
|
323 options.color = '#C46A69'; |
|
324 break; |
|
325 case 'warning': |
|
326 options.color = '#C79121'; |
|
327 break; |
|
328 case 'success': |
|
329 options.color = '#739E73'; |
|
330 break; |
|
331 default: |
|
332 options.color = options.color || '#3276B1'; |
|
333 } |
|
334 options.sound = false; |
|
335 ams.notify.smallBox(options, callback); |
|
336 }); |
|
337 }, |
|
338 |
|
339 /** |
|
340 * Scroll to given element |
|
341 * |
|
342 * @param element: the element to which to scroll |
|
343 * @param options: scroll options |
|
344 */ |
|
345 scrollTo: function(element, options) { |
|
346 ams.ajax && ams.ajax.check($.scrollTo, |
|
347 ams.baseURL + 'ext/jquery-scrollto-2.1.2' + ams.devext + '.js', |
|
348 function() { |
|
349 var body = $('body'); |
|
350 var offset = options.offset || 0; |
|
351 if (body.hasClass('fixed-header')) { |
|
352 offset -= $('#header').height(); |
|
353 } |
|
354 if (body.hasClass('fixed-ribbon')) { |
|
355 offset -= $('#ribbon').height(); |
|
356 } |
|
357 options = $.extend({}, options, {offset: offset}); |
|
358 $.scrollTo(element, options); |
|
359 }); |
|
360 }, |
|
361 |
|
362 /** |
|
363 * Initialize breadcrumbs based on active menu position |
|
364 */ |
|
365 _drawBreadCrumb: function() { |
|
366 var crumb = $('OL.breadcrumb', '#ribbon'); |
|
367 $('li', crumb).not('.parent').remove(); |
|
368 if (!$('li', crumb).exists()) { |
|
369 crumb.append($('<li></li>').append($('<a></a>').text(ams.i18n.HOME) |
|
370 .addClass('padding-right-5') |
|
371 .attr('href', $('nav a[href!="#"]:first').attr('href')))); |
|
372 } |
|
373 $('LI.active >A', 'nav').each(function() { |
|
374 var menu = $(this); |
|
375 var body = $.trim(menu.clone() |
|
376 .children(".badge") |
|
377 .remove() |
|
378 .end() |
|
379 .text()); |
|
380 var item = $("<li></li>").append(menu.attr('href').replace(/^#/, '') ? |
|
381 $("<a></a>").html(body).attr('href', menu.attr('href')) |
|
382 : body); |
|
383 crumb.append(item); |
|
384 }); |
|
385 }, |
|
386 |
|
387 /** |
|
388 * Check URL matching current location hash |
|
389 */ |
|
390 checkURL: function() { |
|
391 |
|
392 function updateActiveMenus(menu) { |
|
393 $('.active', nav).removeClass('active'); |
|
394 menu.addClass('open') |
|
395 .addClass('active'); |
|
396 menu.parents('li').addClass('open active') |
|
397 .children('ul').addClass('active') |
|
398 .show(); |
|
399 menu.parents('li:first').removeClass('open'); |
|
400 menu.parents('ul').addClass(menu.attr('href').replace(/^#/, '') ? 'active' : '') |
|
401 .show(); |
|
402 } |
|
403 |
|
404 var menu; |
|
405 var nav = $('nav'); |
|
406 var hash = location.hash; |
|
407 var url = hash.replace(/^#/, ''); |
|
408 if (url) { |
|
409 var container = $('#content'); |
|
410 if (!container.exists()) { |
|
411 container = $('body'); |
|
412 } |
|
413 menu = $('A[href="' + hash + '"]', nav); |
|
414 if (menu.exists()) { |
|
415 updateActiveMenus(menu); |
|
416 } |
|
417 ams.skin.loadURL(url, container, { |
|
418 afterLoadCallback: function() { |
|
419 var prefix = $('html head title').data('ams-title-prefix'); |
|
420 document.title = (prefix ? prefix + ' > ' : '') + |
|
421 ($('[data-ams-page-title]:first', container).data('ams-page-title') || |
|
422 menu.attr('title') || |
|
423 document.title); |
|
424 } |
|
425 }); |
|
426 } else { |
|
427 var activeUrl = $('[data-ams-active-menu]').data('ams-active-menu'); |
|
428 if (activeUrl) { |
|
429 menu = $('A[href="' + activeUrl + '"]', nav); |
|
430 } else { |
|
431 menu = $('>UL >LI >A[href!="#"]', nav).first(); |
|
432 } |
|
433 if (menu.exists()) { |
|
434 updateActiveMenus(menu); |
|
435 if (activeUrl) { |
|
436 ams.skin._drawBreadCrumb(); |
|
437 } else { |
|
438 window.location.hash = menu.attr('href'); |
|
439 } |
|
440 } |
|
441 } |
|
442 }, |
|
443 |
|
444 /** |
|
445 * List of registered 'cleaning' callbacks |
|
446 * These callbacks are called before loading a new URL into a given container |
|
447 * to clean required elements from memory before the DOM elements are removed |
|
448 */ |
|
449 _clean_callbacks: [], |
|
450 |
|
451 /** |
|
452 * Register a callback which should be called before a container is replaced |
|
453 */ |
|
454 registerCleanCallback: function(callback) { |
|
455 var callbacks = ams.skin._clean_callbacks; |
|
456 if (callbacks.indexOf(callback) < 0) { |
|
457 callbacks.push(callback); |
|
458 } |
|
459 }, |
|
460 |
|
461 /** |
|
462 * Remove given callback from registry |
|
463 */ |
|
464 unregisterCleanCallback: function(callback) { |
|
465 var callbacks = ams.skin._clean_callbacks; |
|
466 var index = callbacks.indexOf(callback); |
|
467 if (index >= 0) { |
|
468 callbacks.splice(index, 1); |
|
469 } |
|
470 }, |
|
471 |
|
472 /** |
|
473 * Call registered cleaning callbacks on given container |
|
474 */ |
|
475 cleanContainer: function(container) { |
|
476 var callbacks = ams.skin._clean_callbacks; |
|
477 for (var index = 0; index < callbacks.length; index++) { |
|
478 callbacks[index].call(container); |
|
479 } |
|
480 }, |
|
481 |
|
482 /** |
|
483 * Load given URL into container |
|
484 */ |
|
485 loadURL: function(url, container, options, callback) { |
|
486 if (url.startsWith('#')) { |
|
487 url = url.substr(1); |
|
488 } |
|
489 if (typeof (options) === 'function') { |
|
490 callback = options; |
|
491 options = {}; |
|
492 } else if (options === undefined) { |
|
493 options = {}; |
|
494 } |
|
495 container = $(container); |
|
496 var defaults = { |
|
497 type: 'GET', |
|
498 url: url, |
|
499 dataType: 'html', |
|
500 cache: false, |
|
501 beforeSend: function() { |
|
502 if (options && options.preLoadCallback) { |
|
503 ams.executeFunctionByName(options.preLoadCallback, this, options.preLoadCallbackOptions); |
|
504 } |
|
505 ams.skin.cleanContainer(container); |
|
506 container.html('<h1 class="loading"><i class="fa fa-cog fa-spin"></i> ' + ams.i18n.LOADING + ' </h1>'); |
|
507 if (container[0] === $('#content')[0]) { |
|
508 ams.skin._drawBreadCrumb(); |
|
509 var prefix = $('html head title').data('ams-title-prefix'); |
|
510 document.title = (prefix ? prefix + ' > ' : '') + $('.breadcrumb LI:last-child').text(); |
|
511 $('html, body').animate({scrollTop: 0}, 'fast'); |
|
512 } else { |
|
513 container.animate({scrollTop: 0}, 'fast'); |
|
514 } |
|
515 }, |
|
516 success: function(data, status, request) { |
|
517 if (callback) { |
|
518 ams.executeFunctionByName(callback, this, data, status, request, options); |
|
519 } else { |
|
520 var response = ams.ajax && ams.ajax.getResponse(request); |
|
521 if (response) { |
|
522 var dataType = response.contentType; |
|
523 var result = response.data; |
|
524 $('.loading', container).remove(); |
|
525 switch (dataType) { |
|
526 case 'json': |
|
527 ams.ajax.handleJSON(result, container); |
|
528 break; |
|
529 case 'script': |
|
530 break; |
|
531 case 'xml': |
|
532 break; |
|
533 case 'html': |
|
534 /* falls through */ |
|
535 case 'text': |
|
536 /* falls through */ |
|
537 default: |
|
538 // Show and init container |
|
539 container.parents('.hidden').removeClass('hidden'); |
|
540 $('.alert', container.parents('.alerts-container')).remove(); |
|
541 container.css({opacity: '0.0'}) |
|
542 .html(data) |
|
543 .removeClass('hidden') |
|
544 .delay(50) |
|
545 .animate({opacity: '1.0'}, 300); |
|
546 ams.initContent && ams.initContent(container); |
|
547 ams.form && ams.form.setFocus(container); |
|
548 } |
|
549 if (options && options.afterLoadCallback) { |
|
550 ams.executeFunctionByName(options.afterLoadCallback, this, options.afterLoadCallbackOptions); |
|
551 } |
|
552 ams.stats && ams.stats.logPageview(); |
|
553 } |
|
554 } |
|
555 }, |
|
556 error: function(request, errorOptions, error) { |
|
557 container.html('<h3 class="error"><i class="fa fa-warning txt-color-orangeDark"></i> ' + |
|
558 ams.i18n.ERROR + error + '</h3>' + |
|
559 request.responseText); |
|
560 if (options && options.afterErrorCallback) { |
|
561 ams.executeFunctionByName(options.afterErrorCallback, this); |
|
562 } |
|
563 }, |
|
564 async: options.async === undefined ? true : options.async |
|
565 }; |
|
566 var settings = $.extend({}, defaults, options); |
|
567 $.ajax(settings); |
|
568 }, |
|
569 |
|
570 /** |
|
571 * Change user language |
|
572 */ |
|
573 setLanguage: function(event, options) { |
|
574 var lang = options.lang; |
|
575 var handlerType = options.handler_type || 'json'; |
|
576 switch (handlerType) { |
|
577 case 'json': |
|
578 var method = options.method || 'setUserLanguage'; |
|
579 ams.jsonrpc && ams.jsonrpc.post(method, {lang: lang}, function() { |
|
580 window.location.reload(true); |
|
581 }); |
|
582 break; |
|
583 case 'ajax': |
|
584 var href = options.href || 'setUserLanguage'; |
|
585 ams.ajax && ams.ajax.post(href, {lang: lang}, function() { |
|
586 window.location.reload(true); |
|
587 }); |
|
588 break; |
|
589 } |
|
590 }, |
|
591 |
|
592 /** |
|
593 * Go to logout page |
|
594 */ |
|
595 logout: function() { |
|
596 window.location = ams.loginURL; |
|
597 } |
|
598 }; |
|
599 |
|
600 })(jQuery, this); |
|