Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 1
/**
2
Core script to handle the entire theme and core functions
3
**/
4
var Layout = function () {
5
 
6
    var layoutImgPath = 'layouts/layout/img/';
7
 
8
    var layoutCssPath = 'layouts/layout/css/';
9
 
10
    var resBreakpointMd = App.getResponsiveBreakpoint('md');
11
 
12
    var ajaxContentSuccessCallbacks = [];
13
    var ajaxContentErrorCallbacks = [];
14
 
15
    //* BEGIN:CORE HANDLERS *//
16
    // this function handles responsive layout on screen size resize or mobile device rotate.
17
 
18
    // Set proper height for sidebar and content. The content and sidebar height must be synced always.
19
    var handleSidebarAndContentHeight = function () {
20
        var content = $('.page-content');
21
        var sidebar = $('.page-sidebar');
22
        var body = $('body');
23
        var height;
24
 
25
        if (body.hasClass("page-footer-fixed") === true && body.hasClass("page-sidebar-fixed") === false) {
26
            var available_height = App.getViewPort().height - $('.page-footer').outerHeight() - $('.page-header').outerHeight();
27
            var sidebar_height = sidebar.outerHeight();
28
            if (sidebar_height > available_height) {
29
                available_height = sidebar_height + $('.page-footer').outerHeight();
30
            }
31
            if (content.height() < available_height) {
32
                content.attr('style', 'min-height:' + available_height + 'px');
33
            }
34
        } else {
35
            if (body.hasClass('page-sidebar-fixed')) {
36
                height = _calculateFixedSidebarViewportHeight();
37
                if (body.hasClass('page-footer-fixed') === false) {
38
                    height = height - $('.page-footer').outerHeight();
39
                }
40
            } else {
41
                var headerHeight = $('.page-header').outerHeight();
42
                var footerHeight = $('.page-footer').outerHeight();
43
 
44
                if (App.getViewPort().width < resBreakpointMd) {
45
                    height = App.getViewPort().height - headerHeight - footerHeight;
46
                } else {
47
                    height = sidebar.height() + 20;
48
                }
49
 
50
                if ((height + headerHeight + footerHeight) <= App.getViewPort().height) {
51
                    height = App.getViewPort().height - headerHeight - footerHeight;
52
                }
53
            }
54
            content.attr('style', 'min-height:' + height + 'px');
55
        }
56
    };
57
 
58
    // Handle sidebar menu links
59
    var handleSidebarMenuActiveLink = function(mode, el) {
60
        var url = location.hash.toLowerCase();
61
 
62
        var menu = $('.page-sidebar-menu');
63
 
64
        if (mode === 'click' || mode === 'set') {
65
            el = $(el);
66
        } else if (mode === 'match') {
67
            menu.find("li > a").each(function() {
68
                var path = $(this).attr("href").toLowerCase();
69
                // url match condition
70
                if (path.length > 1 && url.substr(1, path.length - 1) == path.substr(1)) {
71
                    el = $(this);
72
                    return;
73
                }
74
            });
75
        }
76
 
77
        if (!el || el.size() == 0) {
78
            return;
79
        }
80
 
81
        if (el.attr('href').toLowerCase() === 'javascript:;' || el.attr('href').toLowerCase() === '#') {
82
            return;
83
        }
84
 
85
        var slideSpeed = parseInt(menu.data("slide-speed"));
86
        var keepExpand = menu.data("keep-expanded");
87
 
88
        // begin: handle active state
89
        if (menu.hasClass('page-sidebar-menu-hover-submenu') === false) {
90
            menu.find('li.nav-item.open').each(function() {
91
                var match = false;
92
                $(this).find('li').each(function(){
93
                    if ($(this).find(' > a').attr('href') === el.attr('href')) {
94
                        match = true;
95
                        return;
96
                    }
97
                });
98
 
99
                if (match === true) {
100
                    return;
101
                }
102
 
103
                $(this).removeClass('open');
104
                $(this).find('> a > .arrow.open').removeClass('open');
105
                $(this).find('> .sub-menu').slideUp();
106
            });
107
        } else {
108
             menu.find('li.open').removeClass('open');
109
        }
110
 
111
        menu.find('li.active').removeClass('active');
112
        menu.find('li > a > .selected').remove();
113
        // end: handle active state
114
 
115
        el.parents('li').each(function () {
116
            $(this).addClass('active');
117
            $(this).find('> a > span.arrow').addClass('open');
118
 
119
            if ($(this).parent('ul.page-sidebar-menu').size() === 1) {
120
                $(this).find('> a').append('<span class="selected"></span>');
121
            }
122
 
123
            if ($(this).children('ul.sub-menu').size() === 1) {
124
                $(this).addClass('open');
125
            }
126
        });
127
 
128
        if (mode === 'click') {
129
            if (App.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page
130
                $('.page-header .responsive-toggler').click();
131
            }
132
        }
133
    };
134
 
135
    // Handle sidebar menu
136
    var handleSidebarMenu = function () {
137
        // offcanvas mobile menu
138
        $('.page-sidebar-mobile-offcanvas .responsive-toggler').click(function() {
139
            $('body').toggleClass('page-sidebar-mobile-offcanvas-open');
140
            e.preventDefault();
141
            e.stopPropagation();
142
        });
143
 
144
        if ($('body').hasClass('page-sidebar-mobile-offcanvas')) {
145
            $(document).on('click', function(e) {
146
                if ($('body').hasClass('page-sidebar-mobile-offcanvas-open')) {
147
                    if ($(e.target).closest('.page-sidebar-mobile-offcanvas .responsive-toggler').length === 0 &&
148
                        $(e.target).closest('.page-sidebar-wrapper').length === 0) {
149
                        $('body').removeClass('page-sidebar-mobile-offcanvas-open');
150
                        e.preventDefault();
151
                        e.stopPropagation();
152
                    }
153
                }
154
            });
155
        }
156
 
157
        // handle sidebar link click
158
        $('.page-sidebar-menu').on('click', 'li > a.nav-toggle, li > a > span.nav-toggle', function (e) {
159
            var that = $(this).closest('.nav-item').children('.nav-link');
160
 
161
            if (App.getViewPort().width >= resBreakpointMd && !$('.page-sidebar-menu').attr("data-initialized") && $('body').hasClass('page-sidebar-closed') &&  that.parent('li').parent('.page-sidebar-menu').size() === 1) {
162
                return;
163
            }
164
 
165
            var hasSubMenu = that.next().hasClass('sub-menu');
166
 
167
            if (App.getViewPort().width >= resBreakpointMd && that.parents('.page-sidebar-menu-hover-submenu').size() === 1) { // exit of hover sidebar menu
168
                return;
169
            }
170
 
171
            if (hasSubMenu === false) {
172
                if (App.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page
173
                    $('.page-header .responsive-toggler').click();
174
                }
175
                return;
176
            }
177
 
178
            var parent =that.parent().parent();
179
            var the = that;
180
            var menu = $('.page-sidebar-menu');
181
            var sub = that.next();
182
 
183
            var autoScroll = menu.data("auto-scroll");
184
            var slideSpeed = parseInt(menu.data("slide-speed"));
185
            var keepExpand = menu.data("keep-expanded");
186
 
187
            if (!keepExpand) {
188
                parent.children('li.open').children('a').children('.arrow').removeClass('open');
189
                parent.children('li.open').children('.sub-menu:not(.always-open)').slideUp(slideSpeed);
190
                parent.children('li.open').removeClass('open');
191
            }
192
 
193
            var slideOffeset = -200;
194
 
195
            if (sub.is(":visible")) {
196
                $('.arrow', the).removeClass("open");
197
                the.parent().removeClass("open");
198
                sub.slideUp(slideSpeed, function () {
199
                    if (autoScroll === true && $('body').hasClass('page-sidebar-closed') === false) {
200
                        if ($('body').hasClass('page-sidebar-fixed')) {
201
                            menu.slimScroll({
202
                                'scrollTo': (the.position()).top
203
                            });
204
                        } else {
205
                            App.scrollTo(the, slideOffeset);
206
                        }
207
                    }
208
                    handleSidebarAndContentHeight();
209
                });
210
            } else if (hasSubMenu) {
211
                $('.arrow', the).addClass("open");
212
                the.parent().addClass("open");
213
                sub.slideDown(slideSpeed, function () {
214
                    if (autoScroll === true && $('body').hasClass('page-sidebar-closed') === false) {
215
                        if ($('body').hasClass('page-sidebar-fixed')) {
216
                            menu.slimScroll({
217
                                'scrollTo': (the.position()).top
218
                            });
219
                        } else {
220
                            App.scrollTo(the, slideOffeset);
221
                        }
222
                    }
223
                    handleSidebarAndContentHeight();
224
                });
225
            }
226
 
227
            e.preventDefault();
228
        });
229
 
230
        // handle menu close for angularjs version
231
        if (App.isAngularJsApp()) {
232
            $(".page-sidebar-menu li > a").on("click", function(e) {
233
                if (App.getViewPort().width < resBreakpointMd && $(this).next().hasClass('sub-menu') === false) {
234
                    $('.page-header .responsive-toggler').click();
235
                }
236
            });
237
        }
238
 
239
        // handle ajax links within sidebar menu
240
        $('.page-sidebar').on('click', ' li > a.ajaxify', function (e) {
241
            e.preventDefault();
242
            App.scrollTop();
243
            var url = $(this).attr("href");
244
            var menuContainer = $('.page-sidebar ul');
245
 
246
            menuContainer.children('li.active').removeClass('active');
247
            menuContainer.children('arrow.open').removeClass('open');
248
 
249
            $(this).parents('li').each(function () {
250
                $(this).addClass('active');
251
                $(this).children('a > span.arrow').addClass('open');
252
            });
253
            $(this).parents('li').addClass('active');
254
 
255
            if (App.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page
256
                $('.page-header .responsive-toggler').click();
257
            }
258
 
259
            Layout.loadAjaxContent(url, $(this));
260
        });
261
 
262
        // handle ajax link within main content
263
        $('.page-content').on('click', '.ajaxify', function (e) {
264
            e.preventDefault();
265
            App.scrollTop();
266
 
267
            var url = $(this).attr("href");
268
 
269
            if (App.getViewPort().width < resBreakpointMd && $('.page-sidebar').hasClass("in")) { // close the menu on mobile view while laoding a page
270
                $('.page-header .responsive-toggler').click();
271
            }
272
 
273
            Layout.loadAjaxContent(url);
274
        });
275
 
276
        // handle scrolling to top on responsive menu toggler click when header is fixed for mobile view
277
        $(document).on('click', '.page-header-fixed-mobile .page-header .responsive-toggler', function(){
278
            App.scrollTop();
279
        });
280
 
281
        // handle sidebar hover effect
282
        handleFixedSidebarHoverEffect();
283
 
284
        // handle the search bar close
285
        $('.page-sidebar').on('click', '.sidebar-search .remove', function (e) {
286
            e.preventDefault();
287
            $('.sidebar-search').removeClass("open");
288
        });
289
 
290
        // handle the search query submit on enter press
291
        $('.page-sidebar .sidebar-search').on('keypress', 'input.form-control', function (e) {
292
            if (e.which == 13) {
293
                $('.sidebar-search').submit();
294
                return false; //<---- Add this line
295
            }
296
        });
297
 
298
        // handle the search submit(for sidebar search and responsive mode of the header search)
299
        $('.sidebar-search .submit').on('click', function (e) {
300
            e.preventDefault();
301
            if ($('body').hasClass("page-sidebar-closed")) {
302
                if ($('.sidebar-search').hasClass('open') === false) {
303
                    if ($('.page-sidebar-fixed').size() === 1) {
304
                        $('.page-sidebar .sidebar-toggler').click(); //trigger sidebar toggle button
305
                    }
306
                    $('.sidebar-search').addClass("open");
307
                } else {
308
                    $('.sidebar-search').submit();
309
                }
310
            } else {
311
                $('.sidebar-search').submit();
312
            }
313
        });
314
 
315
        // handle close on body click
316
        if ($('.sidebar-search').size() !== 0) {
317
            $('.sidebar-search .input-group').on('click', function(e){
318
                e.stopPropagation();
319
            });
320
 
321
            $('body').on('click', function() {
322
                if ($('.sidebar-search').hasClass('open')) {
323
                    $('.sidebar-search').removeClass("open");
324
                }
325
            });
326
        }
327
    };
328
 
329
    // Helper function to calculate sidebar height for fixed sidebar layout.
330
    var _calculateFixedSidebarViewportHeight = function () {
331
        var sidebarHeight = App.getViewPort().height - $('.page-header').outerHeight(true);
332
        if ($('body').hasClass("page-footer-fixed")) {
333
            sidebarHeight = sidebarHeight - $('.page-footer').outerHeight();
334
        }
335
 
336
        return sidebarHeight;
337
    };
338
 
339
    // Handles fixed sidebar
340
    var handleFixedSidebar = function () {
341
        var menu = $('.page-sidebar-menu');
342
 
343
        handleSidebarAndContentHeight();
344
 
345
        if ($('.page-sidebar-fixed').size() === 0) {
346
            return;
347
        }
348
 
349
        if (App.getViewPort().width >= resBreakpointMd && !$('body').hasClass('page-sidebar-menu-not-fixed')) {
350
             menu.attr("data-height", _calculateFixedSidebarViewportHeight());
351
            App.destroySlimScroll(menu);
352
            App.initSlimScroll(menu);
353
            handleSidebarAndContentHeight();
354
        }
355
    };
356
 
357
    // Handles sidebar toggler to close/hide the sidebar.
358
    var handleFixedSidebarHoverEffect = function () {
359
        var body = $('body');
360
        if (body.hasClass('page-sidebar-fixed')) {
361
            $('.page-sidebar').on('mouseenter', function () {
362
                if (body.hasClass('page-sidebar-closed')) {
363
                    $(this).find('.page-sidebar-menu').removeClass('page-sidebar-menu-closed');
364
                }
365
            }).on('mouseleave', function () {
366
                if (body.hasClass('page-sidebar-closed')) {
367
                    $(this).find('.page-sidebar-menu').addClass('page-sidebar-menu-closed');
368
                }
369
            });
370
        }
371
    };
372
 
373
    // Hanles sidebar toggler
374
    var handleSidebarToggler = function () {
375
        var body = $('body');
376
        if ($.cookie && $.cookie('sidebar_closed') === '1' && App.getViewPort().width >= resBreakpointMd) {
377
            $('body').addClass('page-sidebar-closed');
378
            $('.page-sidebar-menu').addClass('page-sidebar-menu-closed');
379
        }
380
 
381
        // handle sidebar show/hide
382
        $('body').on('click', '.sidebar-toggler', function (e) {
383
            var sidebar = $('.page-sidebar');
384
            var sidebarMenu = $('.page-sidebar-menu');
385
            $(".sidebar-search", sidebar).removeClass("open");
386
 
387
            if (body.hasClass("page-sidebar-closed")) {
388
                body.removeClass("page-sidebar-closed");
389
                sidebarMenu.removeClass("page-sidebar-menu-closed");
390
                if ($.cookie) {
391
                    $.cookie('sidebar_closed', '0');
392
                }
393
            } else {
394
                body.addClass("page-sidebar-closed");
395
                sidebarMenu.addClass("page-sidebar-menu-closed");
396
                if (body.hasClass("page-sidebar-fixed")) {
397
                    sidebarMenu.trigger("mouseleave");
398
                }
399
                if ($.cookie) {
400
                    $.cookie('sidebar_closed', '1');
401
                }
402
            }
403
 
404
            $(window).trigger('resize');
405
        });
406
    };
407
 
408
    // Handles the horizontal menu
409
    var handleHorizontalMenu = function () {
410
        //handle tab click
411
        $('.page-header').on('click', '.hor-menu a[data-toggle="tab"]', function (e) {
412
            e.preventDefault();
413
            var nav = $(".hor-menu .nav");
414
            var active_link = nav.find('li.current');
415
            $('li.active', active_link).removeClass("active");
416
            $('.selected', active_link).remove();
417
            var new_link = $(this).parents('li').last();
418
            new_link.addClass("current");
419
            new_link.find("a:first").append('<span class="selected"></span>');
420
        });
421
 
422
        // handle search box expand/collapse
423
        $('.page-header').on('click', '.search-form', function (e) {
424
            $(this).addClass("open");
425
            $(this).find('.form-control').focus();
426
 
427
            $('.page-header .search-form .form-control').on('blur', function (e) {
428
                $(this).closest('.search-form').removeClass("open");
429
                $(this).unbind("blur");
430
            });
431
        });
432
 
433
        // handle hor menu search form on enter press
434
        $('.page-header').on('keypress', '.hor-menu .search-form .form-control', function (e) {
435
            if (e.which == 13) {
436
                $(this).closest('.search-form').submit();
437
                return false;
438
            }
439
        });
440
 
441
        // handle header search button click
442
        $('.page-header').on('mousedown', '.search-form.open .submit', function (e) {
443
            e.preventDefault();
444
            e.stopPropagation();
445
            $(this).closest('.search-form').submit();
446
        });
447
 
448
 
449
        $(document).on('click', '.mega-menu-dropdown .dropdown-menu', function (e) {
450
            e.stopPropagation();
451
        });
452
    };
453
 
454
    // Handles Bootstrap Tabs.
455
    var handleTabs = function () {
456
        // fix content height on tab click
457
        $('body').on('shown.bs.tab', 'a[data-toggle="tab"]', function () {
458
            handleSidebarAndContentHeight();
459
        });
460
    };
461
 
462
    // Handles the go to top button at the footer
463
    var handleGoTop = function () {
464
        var offset = 300;
465
        var duration = 500;
466
 
467
        if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {  // ios supported
468
            $(window).bind("touchend touchcancel touchleave", function(e){
469
               if ($(this).scrollTop() > offset) {
470
                    $('.scroll-to-top').fadeIn(duration);
471
                } else {
472
                    $('.scroll-to-top').fadeOut(duration);
473
                }
474
            });
475
        } else {  // general
476
            $(window).scroll(function() {
477
                if ($(this).scrollTop() > offset) {
478
                    $('.scroll-to-top').fadeIn(duration);
479
                } else {
480
                    $('.scroll-to-top').fadeOut(duration);
481
                }
482
            });
483
        }
484
 
485
        $('.scroll-to-top').click(function(e) {
486
            e.preventDefault();
487
            $('html, body').animate({scrollTop: 0}, duration);
488
            return false;
489
        });
490
    };
491
 
492
    // Hanlde 100% height elements(block, portlet, etc)
493
    var handle100HeightContent = function () {
494
 
495
        $('.full-height-content').each(function(){
496
            var target = $(this);
497
            var height;
498
 
499
            height = App.getViewPort().height -
500
                $('.page-header').outerHeight(true) -
501
                $('.page-footer').outerHeight(true) -
502
                $('.page-title').outerHeight(true) -
503
                $('.page-bar').outerHeight(true);
504
 
505
            if (target.hasClass('portlet')) {
506
                var portletBody = target.find('.portlet-body');
507
 
508
                App.destroySlimScroll(portletBody.find('.full-height-content-body')); // destroy slimscroll
509
 
510
                height = height -
511
                    target.find('.portlet-title').outerHeight(true) -
512
                    parseInt(target.find('.portlet-body').css('padding-top')) -
513
                    parseInt(target.find('.portlet-body').css('padding-bottom')) - 5;
514
 
515
                if (App.getViewPort().width >= resBreakpointMd && target.hasClass("full-height-content-scrollable")) {
516
                    height = height - 35;
517
                    portletBody.find('.full-height-content-body').css('height', height);
518
                    App.initSlimScroll(portletBody.find('.full-height-content-body'));
519
                } else {
520
                    portletBody.css('min-height', height);
521
                }
522
            } else {
523
               App.destroySlimScroll(target.find('.full-height-content-body')); // destroy slimscroll
524
 
525
                if (App.getViewPort().width >= resBreakpointMd && target.hasClass("full-height-content-scrollable")) {
526
                    height = height - 35;
527
                    target.find('.full-height-content-body').css('height', height);
528
                    App.initSlimScroll(target.find('.full-height-content-body'));
529
                } else {
530
                    target.css('min-height', height);
531
                }
532
            }
533
        });
534
    };
535
    //* END:CORE HANDLERS *//
536
 
537
    return {
538
        // Main init methods to initialize the layout
539
        //IMPORTANT!!!: Do not modify the core handlers call order.
540
 
541
        initHeader: function() {
542
            handleHorizontalMenu(); // handles horizontal menu
543
        },
544
 
545
        setSidebarMenuActiveLink: function(mode, el) {
546
            handleSidebarMenuActiveLink(mode, el);
547
        },
548
 
549
        initSidebar: function() {
550
            //layout handlers
551
            handleFixedSidebar(); // handles fixed sidebar menu
552
            handleSidebarMenu(); // handles main menu
553
            handleSidebarToggler(); // handles sidebar hide/show
554
 
555
            if (App.isAngularJsApp()) {
556
                handleSidebarMenuActiveLink('match'); // init sidebar active links
557
            }
558
 
559
            App.addResizeHandler(handleFixedSidebar); // reinitialize fixed sidebar on window resize
560
        },
561
 
562
        initContent: function() {
563
            handle100HeightContent(); // handles 100% height elements(block, portlet, etc)
564
            handleTabs(); // handle bootstrah tabs
565
 
566
            App.addResizeHandler(handleSidebarAndContentHeight); // recalculate sidebar & content height on window resize
567
            App.addResizeHandler(handle100HeightContent); // reinitialize content height on window resize
568
        },
569
 
570
        initFooter: function() {
571
            handleGoTop(); //handles scroll to top functionality in the footer
572
        },
573
 
574
        init: function () {
575
            this.initHeader();
576
            this.initSidebar();
577
            this.initContent();
578
            this.initFooter();
579
        },
580
 
581
        loadAjaxContent: function(url, sidebarMenuLink) {
582
            var pageContent = $('.page-content .page-content-body');
583
 
584
            App.startPageLoading({animate: true});
585
 
586
            $.ajax({
587
                type: "GET",
588
                cache: false,
589
                url: url,
590
                dataType: "html",
591
                success: function (res) {
592
                    App.stopPageLoading();
593
 
594
                    for (var i = 0; i < ajaxContentSuccessCallbacks.length; i++) {
595
                        ajaxContentSuccessCallbacks[i].call(res);
596
                    }
597
 
598
                    if (sidebarMenuLink.size() > 0 && sidebarMenuLink.parents('li.open').size() === 0) {
599
                        $('.page-sidebar-menu > li.open > a').click();
600
                    }
601
 
602
                    pageContent.html(res);
603
                    Layout.fixContentHeight(); // fix content height
604
                    App.initAjax(); // initialize core stuff
605
                },
606
                error: function (res, ajaxOptions, thrownError) {
607
                    App.stopPageLoading();
608
                    pageContent.html('<h4>Could not load the requested content.</h4>');
609
 
610
                    for (var i = 0; i < ajaxContentErrorCallbacks.length; i++) {
611
                        ajaxContentSuccessCallbacks[i].call(res);
612
                    }
613
                }
614
            });
615
        },
616
 
617
        addAjaxContentSuccessCallback: function(callback) {
618
            ajaxContentSuccessCallbacks.push(callback);
619
        },
620
 
621
        addAjaxContentErrorCallback: function(callback) {
622
            ajaxContentErrorCallbacks.push(callback);
623
        },
624
 
625
        //public function to fix the sidebar and content height accordingly
626
        fixContentHeight: function () {
627
            handleSidebarAndContentHeight();
628
        },
629
 
630
        initFixedSidebarHoverEffect: function() {
631
            handleFixedSidebarHoverEffect();
632
        },
633
 
634
        initFixedSidebar: function() {
635
            handleFixedSidebar();
636
        },
637
 
638
        getLayoutImgPath: function () {
639
            return App.getAssetsPath() + layoutImgPath;
640
        },
641
 
642
        getLayoutCssPath: function () {
643
            return App.getAssetsPath() + layoutCssPath;
644
        }
645
    };
646
 
647
}();
648
 
649
if (App.isAngularJsApp() === false) {
650
    jQuery(document).ready(function() {
651
       Layout.init(); // init metronic core componets
652
    });
653
}