123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- /*!
- SlickNav Responsive Mobile Menu
- (c) 2014 Josh Cope
- licensed under MIT
- */
- ;(function ($, document, window) {
- var
- // default settings object.
- defaults = {
- label: 'MENU',
- duplicate: true,
- duration: 200,
- easingOpen: 'swing',
- easingClose: 'swing',
- closedSymbol: '►',
- openedSymbol: '▼',
- prependTo: 'body',
- parentTag: 'a',
- closeOnClick: false,
- allowParentLinks: false,
- init: function () {
- },
- open: function () {
- },
- close: function () {
- }
- },
- mobileMenu = 'slicknav',
- prefix = 'slicknav';
- function Plugin(element, options) {
- this.element = element;
- // jQuery has an extend method which merges the contents of two or
- // more objects, storing the result in the first object. The first object
- // is generally empty as we don't want to alter the default options for
- // future instances of the plugin
- this.settings = $.extend({}, defaults, options);
- this._defaults = defaults;
- this._name = mobileMenu;
- this.init();
- }
- Plugin.prototype.init = function () {
- var $this = this;
- var menu = $(this.element);
- var settings = this.settings;
- // clone menu if needed
- if (settings.duplicate) {
- $this.mobileNav = menu.clone();
- //remove ids from clone to prevent css issues
- $this.mobileNav.removeAttr('id');
- $this.mobileNav.find('*').each(function (i, e) {
- $(e).removeAttr('id');
- });
- }
- else {
- $this.mobileNav = menu;
- }
- // styling class for the button
- var iconClass = prefix + '_icon';
- if (settings.label == '') {
- iconClass += ' ' + prefix + '_no-text';
- }
- if (settings.parentTag == 'a') {
- settings.parentTag = 'a href="#"';
- }
- // create menu bar
- $this.mobileNav.attr('class', prefix + '_nav');
- var menuBar = $('<div class="' + prefix + '_menu"></div>');
- $this.btn = $('<' + settings.parentTag + ' aria-haspopup="true" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed"><span class="' + prefix + '_menutxt">' + settings.label + '</span><span class="' + iconClass + '"><span class="' + prefix + '_icon-bar"></span><span class="' + prefix + '_icon-bar"></span><span class="' + prefix + '_icon-bar"></span></span></a>');
- $(menuBar).append($this.btn);
- $(settings.prependTo).prepend(menuBar);
- menuBar.append($this.mobileNav);
- // iterate over structure adding additional structure
- var items = $this.mobileNav.find('li');
- $(items).each(function () {
- var item = $(this);
- var data = {};
- data.children = item.children('ul').attr('role', 'menu');
- item.data("menu", data);
- // if a list item has a nested menu
- if (data.children.length > 0) {
- // select all text before the child menu
- var a = item.contents();
- var nodes = [];
- $(a).each(function () {
- if (!$(this).is("ul")) {
- nodes.push(this);
- }
- else {
- return false;
- }
- });
- // wrap item text with tag and add classes
- var wrap = $(nodes).wrapAll('<' + settings.parentTag + ' role="menuitem" aria-haspopup="true" tabindex="-1" class="' + prefix + '_item"/>').parent();
- item.addClass(prefix + '_collapsed');
- item.addClass(prefix + '_parent');
- // create parent arrow
- $(nodes).last().after('<span class="' + prefix + '_arrow">' + settings.closedSymbol + '</span>');
- }
- else {
- if (item.children().length == 0) {
- item.addClass(prefix + '_txtnode');
- }
- }
- // accessibility for links
- item.children('a').attr('role', 'menuitem').click(function () {
- //Emulate menu close if set
- if (settings.closeOnClick) {
- $($this.btn).click();
- }
- });
- });
- // structure is in place, now hide appropriate items
- $(items).each(function () {
- var data = $(this).data("menu");
- $this._visibilityToggle(data.children, false, null, true);
- });
- // finally toggle entire menu
- $this._visibilityToggle($this.mobileNav, false, 'init', true);
- // accessibility for menu button
- $this.mobileNav.attr('role', 'menu');
- // outline prevention when using mouse
- $(document).mousedown(function () {
- $this._outlines(false);
- });
- $(document).keyup(function () {
- $this._outlines(true);
- });
- // menu button click
- $($this.btn).click(function (e) {
- e.preventDefault();
- $this._menuToggle();
- });
- // click on menu parent
- $this.mobileNav.on('click', '.' + prefix + '_item', function (e) {
- e.preventDefault();
- $this._itemClick($(this));
- });
- // check for enter key on menu button and menu parents
- $($this.btn).keydown(function (e) {
- var ev = e || event;
- if (ev.keyCode == 13) {
- e.preventDefault();
- $this._menuToggle();
- }
- });
- $this.mobileNav.on('keydown', '.' + prefix + '_item', function (e) {
- var ev = e || event;
- if (ev.keyCode == 13) {
- e.preventDefault();
- $this._itemClick($(e.target));
- }
- });
- // allow links clickable within parent tags if set
- if (settings.allowParentLinks) {
- $('.' + prefix + '_item a').click(function (e) {
- e.stopImmediatePropagation();
- });
- }
- };
- //toggle menu
- Plugin.prototype._menuToggle = function (el) {
- var $this = this;
- var btn = $this.btn;
- var mobileNav = $this.mobileNav;
- if (btn.hasClass(prefix + '_collapsed')) {
- btn.removeClass(prefix + '_collapsed');
- btn.addClass(prefix + '_open');
- }
- else {
- btn.removeClass(prefix + '_open');
- btn.addClass(prefix + '_collapsed');
- }
- btn.addClass(prefix + '_animating');
- $this._visibilityToggle(mobileNav, true, btn);
- };
- // toggle clicked items
- Plugin.prototype._itemClick = function (el) {
- var $this = this;
- var settings = $this.settings;
- var data = el.data("menu");
- if (!data) {
- data = {};
- data.arrow = el.children('.' + prefix + '_arrow');
- data.ul = el.next('ul');
- data.parent = el.parent();
- el.data("menu", data);
- }
- if (data.parent.hasClass(prefix + '_collapsed')) {
- data.arrow.html(settings.openedSymbol);
- data.parent.removeClass(prefix + '_collapsed');
- data.parent.addClass(prefix + '_open');
- data.parent.addClass(prefix + '_animating');
- $this._visibilityToggle(data.ul, true, el);
- }
- else {
- data.arrow.html(settings.closedSymbol);
- data.parent.addClass(prefix + '_collapsed');
- data.parent.removeClass(prefix + '_open');
- data.parent.addClass(prefix + '_animating');
- $this._visibilityToggle(data.ul, true, el);
- }
- };
- // toggle actual visibility and accessibility tags
- Plugin.prototype._visibilityToggle = function (el, animate, trigger, init) {
- var $this = this;
- var settings = $this.settings;
- var items = $this._getActionItems(el);
- var duration = 0;
- if (animate) {
- duration = settings.duration;
- }
- if (el.hasClass(prefix + '_hidden')) {
- el.removeClass(prefix + '_hidden');
- el.slideDown(duration, settings.easingOpen, function () {
- $(trigger).removeClass(prefix + '_animating');
- $(trigger).parent().removeClass(prefix + '_animating');
- //Fire open callback
- if (!init) {
- settings.open(trigger);
- }
- });
- el.attr('aria-hidden', 'false');
- items.attr('tabindex', '0');
- $this._setVisAttr(el, false);
- }
- else {
- el.addClass(prefix + '_hidden');
- el.slideUp(duration, this.settings.easingClose, function () {
- el.attr('aria-hidden', 'true');
- items.attr('tabindex', '-1');
- $this._setVisAttr(el, true);
- el.hide(); //jQuery 1.7 bug fix
- $(trigger).removeClass(prefix + '_animating');
- $(trigger).parent().removeClass(prefix + '_animating');
- //Fire init or close callback
- if (!init) {
- settings.close(trigger);
- }
- else {
- if (trigger == 'init') {
- settings.init();
- }
- }
- });
- }
- };
- // set attributes of element and children based on visibility
- Plugin.prototype._setVisAttr = function (el, hidden) {
- var $this = this;
- // select all parents that aren't hidden
- var nonHidden = el.children('li').children('ul').not('.' + prefix + '_hidden');
- // iterate over all items setting appropriate tags
- if (!hidden) {
- nonHidden.each(function () {
- var ul = $(this);
- ul.attr('aria-hidden', 'false');
- var items = $this._getActionItems(ul);
- items.attr('tabindex', '0');
- $this._setVisAttr(ul, hidden);
- });
- }
- else {
- nonHidden.each(function () {
- var ul = $(this);
- ul.attr('aria-hidden', 'true');
- var items = $this._getActionItems(ul);
- items.attr('tabindex', '-1');
- $this._setVisAttr(ul, hidden);
- });
- }
- };
- // get all 1st level items that are clickable
- Plugin.prototype._getActionItems = function (el) {
- var data = el.data("menu");
- if (!data) {
- data = {};
- var items = el.children('li');
- var anchors = items.children('a');
- data.links = anchors.add(items.children('.' + prefix + '_item'));
- el.data("menu", data);
- }
- return data.links;
- };
- Plugin.prototype._outlines = function (state) {
- if (!state) {
- $('.' + prefix + '_item, .' + prefix + '_btn').css('outline', 'none');
- }
- else {
- $('.' + prefix + '_item, .' + prefix + '_btn').css('outline', '');
- }
- };
- Plugin.prototype.toggle = function () {
- $this._menuToggle();
- };
- Plugin.prototype.open = function () {
- $this = this;
- if ($this.btn.hasClass(prefix + '_collapsed')) {
- $this._menuToggle();
- }
- };
- Plugin.prototype.close = function () {
- $this = this;
- if ($this.btn.hasClass(prefix + '_open')) {
- $this._menuToggle();
- }
- };
- $.fn[mobileMenu] = function (options) {
- var args = arguments;
- // Is the first parameter an object (options), or was omitted, instantiate
- // a new instance
- if (options === undefined || typeof options === 'object') {
- return this.each(function () {
- // Only allow the plugin to be instantiated once due to methods
- if (!$.data(this, 'plugin_' + mobileMenu)) {
- // if it has no instance, create a new one, pass options to our
- // plugin constructor, and store the plugin instance in the elements
- // jQuery data object.
- $.data(this, 'plugin_' + mobileMenu, new Plugin(this, options));
- }
- });
- // If is a string and doesn't start with an underscore or 'init'
- // function, treat this as a call to a public method.
- }
- else {
- if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
- // Cache the method call to make it possible to return a value
- var returns;
- this.each(function () {
- var instance = $.data(this, 'plugin_' + mobileMenu);
- // Tests that there's already a plugin-instance and checks that the
- // requested public method exists
- if (instance instanceof Plugin && typeof instance[options] === 'function') {
- // Call the method of our plugin instance, and pass it the supplied
- // arguments.
- returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
- }
- });
- // If the earlier cached method gives a value back return the value,
- // otherwise return this to preserve chainability.
- return returns !== undefined ? returns : this;
- }
- }
- };
- }($jQueryAdminimal, document, window));
- (function ($) {
- Drupal.admin = Drupal.admin || {};
- Drupal.admin.behaviors = Drupal.admin.behaviors || {};
- // Create the responsive menu using SlickNav.
- Drupal.admin.behaviors.responsivemenu = function (context, settings, $adminMenu) {
- $('#admin-menu-menu-responsive').slicknav({
- label: Drupal.t('Menu'),
- prependTo: 'body',
- closedSymbol: '<i class="closed"></i>',
- openedSymbol: '<i class="open"></i>',
- allowParentLinks: true
- });
- };
- // Create the responsive shortcuts dropdown.
- Drupal.admin.behaviors.responsiveshortcuts = function (context, settings, $adminMenu) {
- // Check if there are any shortucts to respondify.
- if (jQuery("div.toolbar-shortcuts ul.menu li").length) {
- // Create the dropdown base
- $('<select id="responsive-shortcuts-dropdown"/>').appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts");
- // Create default option "Select"
- $("<option />", {
- "selected": "selected",
- "class": "hide",
- "value": "",
- "text": Drupal.t('Shortcuts')
- }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
- // Populate dropdown with menu items
- $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts a").each(function () {
- var el = $(this);
- $("<option />", {
- "value": el.attr("href"),
- "text": el.text()
- }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
- });
- // Redirect the user when selecting an option.
- $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select").change(function () {
- window.location = $(this).find("option:selected").val();
- });
- // Clean the mess.
- $('#admin-menu-shortcuts-responsive div.toolbar-shortcuts ul').remove();
- // Move the select box into the responsive menu.
- $("#admin-menu-shortcuts-responsive").prependTo(".slicknav_menu");
- }
- // Remove the edit shortcuts link from the DOM to avoid duble rendering.
- $('#admin-menu-shortcuts-responsive #edit-shortcuts').remove();
- };
- })($jQueryAdminimal);
|