/** * ProcessWire Panels * * Alternative to modal windows. Creates iframe panels that load URLs. * Clicking outside the panel closes it. By default, panels load the requested * URL on mouseover of the a.pw-panel toggle link, unless the pw-panel-reload * class is specified (in which case it loads on click). * * Copyright 2016 by Ryan Cramer * License: MPL 2.0 * * REQUIREMENTS * ============ * Include the panel.js and panel.css files in the request. * jQuery is required. jQuery UI is strongly recommended but not required. * So far tested only in PW admin themes, but should work outside them too. * * BASIC USAGE * =========== * Give any link a "pw-panel" class and it will open in a left-side panel: * * Click to open panel * * If clickable element is not an tag, give "data-href" attr containing the URL the panel should open: * * Click to open panel * * To make a panel open on the right rather than the left, append "pw-panel-right" to the class attribute. * * . * * * */ var pwPanels = { /** * Quantity of panels initialized * */ qty: 0, /** * Initialize pwPanels, to be called at document.ready * */ init: function() { var url = window.location.href; if(url.indexOf('pw_panel=1') > -1) { // initialize inside of a panel $(document).on('mouseover', 'a', function() { // make links target the parent window var $a = $(this); var target = $a.attr('target'); if(typeof target == "undefined" || target.length == 0) { $a.attr('target', '_parent'); } }); } else if(url.indexOf('pw_panel=2') > -1) { // don't initialize anything (.pw-panel-links class option) } else { // initialize a page with panels in it $('.pw-panel').each(function() { var $toggler = $(this); pwPanels.addPanel($toggler); }); } }, /** * Add a new panel * * @param toggler Element that toggles the panel * */ addPanel: function($toggler) { var panelURL = $toggler.attr('data-href'); var panelID = $toggler.attr('data-panel-id'); var panelContainerID = 'pw-panel-container-' + (++pwPanels.qty); // allow for use of data-href or href attribute that references URL to load in panel if(typeof panelURL == 'undefined' || !panelURL.length) panelURL = $toggler.attr('href'); if(typeof panelURL != 'undefined' && panelURL.length) { var hash = ''; if(panelURL.indexOf('#') > -1) { var parts = panelURL.split('#'); panelURL = parts[0]; hash = '#' + parts[1]; } panelURL += (panelURL.indexOf('?') > -1 ? '&' : '?') + 'modal=panel&pw_panel='; if($toggler !== null && $toggler.hasClass('pw-panel-links')) { panelURL += '2'; // don't update target of links in panel } else { panelURL += '1'; // update target of links in panel } panelURL += hash; } var $icon = $('') .attr('class', 'pw-panel-icon fa fa-angle-double-left'); var $span = $('').attr('class', 'ui-button-text') .append($icon); var $btn = $('') .attr('class', 'pw-panel-button pw-panel-button-closed ui-button ui-state-default') .attr('href', panelURL) .on('click', pwPanels.buttonClickEvent) .on('mouseover', pwPanels.buttonMouseoverEvent) .on('mouseout', pwPanels.buttonMouseoutEvent) .append($span); var $panel = $('
') .attr('id', panelContainerID) .attr('class', 'pw-panel-container pw-panel-container-closed') .append($btn); $('body').append($panel); if(typeof panelID != 'undefined' && panelID.length) { // loading an in-page element rather than a URL $('#' + panelID).hide().addClass('pw-panel-element'); // class assigned to in-page element $panel.addClass('pw-panel-container-element').attr('data-panel-id', panelID); } // panel toggler if($toggler !== null) { pwPanels.initToggler($toggler, $btn, $panel); } else { $panel.addClass('pw-panel-left'); } }, /** * Initialize the toggler element, plus $btn and $panel with options from toggler element * * @param $toggler * @param $btn * @param $panel * */ initToggler: function($toggler, $btn, $panel) { var panelSide = $toggler.hasClass('pw-panel-right') ? 'right' : 'left'; var text = $toggler.attr('data-tab-text'); var icon = $toggler.attr('data-tab-icon'); var offset = $toggler.attr('data-tab-offset'); var panelWidth = $toggler.attr('data-panel-width'); var btnPos = panelSide == 'right' ? 'left' : 'right'; var btnExtraPx = 1; $panel.addClass('pw-panel-tab pw-panel-' + panelSide); $panel.attr('data-href', $btn.attr('href')); if($toggler.hasClass('pw-panel-reload')) $panel.addClass('pw-panel-reload'); if(typeof offset != "undefined") { offset = parseInt(offset); if(offset > -1) { // positive number indicates offset from top $btn.css('top', offset + 'px'); } else { // negative number indicates offset from bottom $btn.css('top', 'auto'); $btn.css('bottom', Math.abs(offset) + 'px'); } } if(typeof text != "undefined" && text.length) { var $btnText = $btn.children('.ui-button-text'); var $text = $("").text(text); $btnText.html('' + $text.text() + ''); $btn.addClass('pw-panel-button-text'); btnExtraPx = 7; //$btn.css(btnPos, (-1 * ($btn.height() + 7)) + 'px'); //$btn.css('top', parseInt($btn.css('top')) + ($btn.width()) + 'px'); } if(typeof icon != "undefined" && icon.length) { var $icon = $('').addClass('fa fa-fw fa-' + icon); var $text = $btn.children('.ui-button-text'); if($btn.hasClass('pw-panel-button-text')) { $text.prepend($icon); } else { $text.empty().append($icon); $btn.css(btnPos, (-1 * ($btn.outerWidth())) + 'px'); } } if(typeof panelWidth != 'undefined' && panelWidth.length) { $panel.css('width', panelWidth) $panel.css(panelSide, '-' + panelWidth); } if(panelSide == 'right') { // align button to right edge //$btn.css('left', (-1 * (btnExtraPx + $btn.height())) + 'px'); } else { // align button to left edge $btn.css('right', (-1 * (btnExtraPx + $btn.height())) + 'px'); } if(!$toggler.hasClass('pw-panel-tab')) { // if toggler doesn't specify that a tab/button should show, hide our $btn element $btn.addClass('pw-panel-button-hidden'); } // delegate events from toggler to pw-panel-button $toggler.on('click', function() { $btn.trigger('click'); return false; }).on('mouseover', function() { $btn.trigger('mouseover'); }).on('mouseout', function() { $btn.trigger('mouseout'); }); }, /** * Populate the panel content (iframe if using URL) and return it * */ initPanelContent: function($panel) { var $content = $panel.find('.pw-panel-content'); var panelID = $panel.attr('data-panel-id'); if($content.length) { return $content; } else if(typeof panelID != "undefined") { var $panelTarget = $('#' + panelID); // var $btn = $panel.find('.pw-panel-button').addClass(panelID + '-pw-panel-button'); // if needed for external trigger if($panelTarget.length) { $content = $('').addClass('pw-panel-content').css('overflow', 'auto'); $panel.append($content); $content.append($panelTarget); $panelTarget.show(); $panelTarget.trigger('pw-panel-init'); } } else { $content = $('') .addClass('pw-panel-content') .attr('src', $panel.attr('data-href')); $panel.append($content); } return $content; }, /** * Event called on window resize * */ windowResizeEvent: function() { $(".pw-panel-container-init").each(function() { var $panel = $(this); if($panel.hasClass('pw-panel-container-open')) return; var panelWidth = $panel.width(); var px = (-1 * panelWidth) + 'px'; if($panel.hasClass('pw-panel-right')) { $panel.css('right', px); } else { $panel.css('left', px); } }); }, /** * Event called on panel button click * * @returns {boolean} * */ buttonClickEvent: function() { var $btn = $(this); var $panel = $btn.closest('.pw-panel-container'); var $panelContent = $panel.find('.pw-panel-content'); var isOpen = $panel.hasClass('pw-panel-container-open'); var isLoaded = $panel.hasClass('pw-panel-container-loaded'); var panelWidth = $panel.width(); var panelSide = $panel.hasClass('pw-panel-right') ? 'right' : 'left'; var hasJQUI = typeof jQuery.ui != "undefined"; function animateFinished() { $panel.toggleClass('pw-panel-container-open pw-panel-container-closed'); $btn.toggleClass('pw-panel-button-open pw-panel-button-closed'); } if($('.pw-panel-container-init').length == 0) { // attach window resize event only if no panels have been opened before // so that we attach it only if needed, and not more than once $(window).on('resize', pwPanels.windowResizeEvent); } if(isOpen) { // close the panel var px = (-1 * panelWidth) + 'px'; if(hasJQUI) { if(panelSide == 'left') { $panel.animate({left: px}, 150, animateFinished); } else { $panel.animate({right: px}, 150, animateFinished); } } else { $panel.css(panelSide, px); animateFinished(); } $('body').css('overflow', ''); $("#pw-panel-shade").fadeOut('fast', function() { $(this).remove(); }); $btn.fadeOut('fast', function() { $btn.removeClass('ui-state-active'); $btn.fadeIn('fast'); }); if(hasJQUI && panelSide == 'left') $panel.resizable('destroy'); if($panel.hasClass('pw-panel-reload')) { // force it to create new iframe on every load $panel.find('iframe.pw-panel-content').remove(); } // trigger panel-closed event $(document).trigger('pw-panel-closed', $panel); } else { // open the panel if($panel.hasClass('pw-panel-reload') || !isLoaded) { // tell the panel to load or reload, since mouseover even didn't pwPanels.initPanelContent($panel); } if(hasJQUI) { if(panelSide == 'left') { $panel.animate({left: 0}, 150, animateFinished); } else { $panel.animate({right: 0}, 150, animateFinished); } } else { $panel.css(panelSide, 0); animateFinished(); } // shade the parent window var $shade = $("