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(/
.*: /, "
"); $(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);