diff options
Diffstat (limited to 'lib/grappelli/media/js/grappelli.min.js')
-rw-r--r-- | lib/grappelli/media/js/grappelli.min.js | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/lib/grappelli/media/js/grappelli.min.js b/lib/grappelli/media/js/grappelli.min.js new file mode 100644 index 0000000..e762690 --- /dev/null +++ b/lib/grappelli/media/js/grappelli.min.js @@ -0,0 +1,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); |