summaryrefslogtreecommitdiff
path: root/lib/grappelli/media/js/grappelli.min.js
blob: e76269041df004c54e41ac9c4109c9500c87a4e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
var grappelli = {};

(function($) {
    grappelli.collapseHandlerClass = "collapse-handler";
    grappelli.collapsedBlockedClass = "collapse-blocked";
    grappelli.openAllClass = "open-handler";
    grappelli.closeAllClass = "close-handler";
    grappelli.collapseClass = "collapse";
    grappelli.closedClass = "closed";
    grappelli.openClass = "open";
    
    
    /**
     * if collapsible in menu is opened it has to close if it "looses focus"
     */
    grappelli.collapseBlurHandler = function(evt) {
        var that = $(this),
            parents = $(evt.originalEvent.explicitOriginalTarget).parents(),
            handler_parent = that.parents("ul.navigation-menu")[0] || that.parents("ul#user-tools")[0];
        for (var i = 0; i < parents.length; i++) {
            if (parents[i] == handler_parent) {
                var target = evt.originalEvent.explicitOriginalTarget;
                if (target.nodeType == 3) {
                    target = $(target).parent()
                } else {
                    target = $(target);
                }
                target.one('blur', grappelli.collapseBlurHandler);
                return;
            }
        }
        that.parents("." + grappelli.collapseClass).first()
            .toggleClass(grappelli.closedClass)
            .toggleClass(grappelli.openClass);
    };
    
    /**
     * handles assignment of classes (open/close) when collapse handler is clicked
     * NOTE: special case if collapsible is within the header menu
     */
    grappelli.collapseHandler = function() {
        if (!$("body").hasClass(grappelli.collapsedBlockedClass)) {
            var that = $(this);
            that.parents("." + grappelli.collapseClass).first()
                .toggleClass(grappelli.closedClass)
                .toggleClass(grappelli.openClass);
            
            // close again on blur if it's an menu dropdown from the header (i.e. bookmarks)
            if (that.parent(".menu-item").length || that.parent(".user-options-container").length) {
                menu = $(this).parent('li').children('ul');
                menumaxheight = $(window).height() - 80;
                menuheight = menu.height();
                if (menumaxheight < menuheight) {
                    $(menu).css({
                        "max-height": menumaxheight, 
                        "overflow-y": "scroll"
                    });
                }
                
                that.one('blur', grappelli.collapseBlurHandler);
            }
        }
        return false;
    };
    
    grappelli.addCollapseHandlerClass = function() {
        $("." + this.collapseClass).each(function() {
            var node = $(this).children().first();
            if (node.is("h2") || node.is("h3") || node.is("h4")) {
                node.addClass(grappelli.collapseHandlerClass)
            }
        });
    };
    
    /**
     * add click handler to collapsibles
     * NOTE: secial case for collapse handler in menu
     */
    grappelli.registerCollapseHandler = function() {
        $("." + this.collapseHandlerClass).click(this.collapseHandler);
        
        // if the item has children you generally open the cildren with the button next to it.
        // open the menu anyways if it has an empty link
        $('a.parent.item-collapse-handler-container').click(function(){
            var that = $(this);
            
            if (that.attr('href') == "#") {
                that.next().click();
            }
        });
        
        // do this each time a submenu is opened
        $('ul.navigation-menu a.item-collapse-handler').click(function(){
            // Collapse
            $(this).closest('li.item-collapse').toggleClass("item-closed").toggleClass("item-open");
            // Calculate Menu Height
            menu = $(this).closest('ul.navigation-menu>li>ul');
            $(menu).removeAttr("style");
            menumaxheight = $(window).height() - 80;
            menuheight = menu.height();
            menuwidth = menu.outerWidth() + 15;
            if (menumaxheight < menuheight) {
                // $(menu).addClass("");
                $(menu).css({
                    "width": menuwidth,
                    "height": menuheight,
                    "max-height": menumaxheight,
                    "overflow-y": "scroll",
                    "overflow-x": "hidden !important"
                });
            }
        });
    };
    
    grappelli.registerOpenAllHandler = function() {
        $("." + this.openAllClass).click(this.openAllHandler);
    };
    
    /*
     * Open all
     */
    grappelli.openAllHandler = function() {
        // get .group and not .collapse because it doesn't necessarily have .collapse
        $(this).parents(".group")
                    .removeClass(grappelli.closedClass)
                    .addClass(grappelli.openClass)
                    .find("." + grappelli.collapseClass)
                    .removeClass(grappelli.closedClass)
                    .addClass(grappelli.openClass);
    };
    
    grappelli.registerCloseAllHandler = function() {
        $("." + this.closeAllClass).click(this.closeAllHandler);
    };
    
    /*
     * Close all
     */
    grappelli.closeAllHandler = function() {
        // get .group and not .collapse because it doesn't necessarily have .collapse
        $(this).parents(".group")
                    .find("." + grappelli.collapseClass)
                    .removeClass(grappelli.openClass)
                    .addClass(grappelli.closedClass);
    };
    
    grappelli.initCollapsible = function() {
        grappelli.addCollapseHandlerClass();
        grappelli.registerCollapseHandler();
        
        grappelli.registerOpenAllHandler();
        grappelli.registerCloseAllHandler();
        
        $("." + grappelli.collapseClass + " ul.errorlist").each(function() {
            $(this).parents("." + grappelli.collapseClass)
                .removeClass(grappelli.closedClass)
                .addClass(grappelli.openClass);
        });
    };
    
    grappelli.getFormat = function(type) {
        if (type == "date") {
            var format = DATE_FORMAT.toLowerCase().replace(/%\w/g, function(str) {
                str = str.replace(/%/, '');
                return str + str;
            });
        }
        return format;
    }
    
    grappelli.initDateAndTimePicker = function() {
        var options = {
            //appendText: '(mm/dd/yyyy)',
            showOn: 'button',
            buttonImageOnly: false,
            buttonText: '',
            dateFormat: grappelli.getFormat('date'),
            showButtonPanel: true,
            showAnim: '',
            // HACK: sets the current instance to a global var.
            // needed to actually select today if the today-button is clicked.
            // see onClick handler for ".ui-datepicker-current"
            beforeShow: function(year, month, inst) {
                grappelli.datepicker_instance = this;
            }
        };
        var dateFields = $("input[class*='vDateField']:not([id*='__prefix__'])");
        dateFields.datepicker(options);
        
        if (typeof IS_POPUP != "undefined" && IS_POPUP) {
            dateFields.datepicker('disable');
        }
        
        // HACK: adds an event listener to the today button of datepicker
        // if clicked today gets selected and datepicker hides.
        // user live() because there is no hoock after datepicker generates it's complete dom.
        $(".ui-datepicker-current").live('click', function() {
            $.datepicker._selectDate(grappelli.datepicker_instance);
            grappelli.datepicker_instance = null;
        })
        
        // inti timepicker
        $("input[class*='vTimeField']:not([id*='__prefix__'])").timepicker();
    };
    
    grappelli.initHacks = function() {
        // to get rid of text after DateField (hardcoded in django.admin)
        $('p.datetime').each(function() {
            var text = $(this).html();
            text = text.replace(/^\w*: /, "");
            text = text.replace(/<br>.*: /, "<br>");
            $(this).html(text);
        });
    };
    
    grappelli.initSearchbar = function() {
        var searchbar = $("input#searchbar");
        // var searchbar = $("input#searchbar"),
        //     searchbar_tooltip = $('div#searchbar_tooltip');
        // if (searchbar_tooltip.length == 0) return;
        
        searchbar.focus();
        
        // searchbar.bind('keydown', function() {
        //     searchbar_tooltip.hide();
        // });
        // searchbar.bind("mouseover", function() {
        //     searchbar_tooltip.show();
        // });
        // searchbar.bind("mouseout", function() {
        //     searchbar_tooltip.hide();
        // });
    };
    
    // Using window.load instead of document ready for better performances
    // It prevents lots of glitches, like divs that moves around upon loading
    //
    // Use $(document).ready only if you have to deal with images since it will
    // wait for the document to be fully loaded/rendered before running the function
    // while window.load method will run as soon as the DOM/CSS is loaded.
    
    $(window).load(function() {
        // we do the hacks first!
        // because we manipulate dom via innerHTML => loose events
        grappelli.initHacks();
        grappelli.initCollapsible();
        grappelli.initDateAndTimePicker();
        grappelli.initSearchbar();
        
        // add something for clicking outside the navigation-menu
    });
})(django.jQuery);