UNPKG

jspanel3

Version:

A jQuery Plugin to create highly configurable multifunctional floating panels

1,068 lines (904 loc) 187 kB
/* global jsPanel */ 'use strict'; // Object.assign Polyfill - https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - ONLY FOR IE11 if (!Object.assign) { Object.defineProperty(Object, 'assign', { enumerable: false, configurable: true, writable: true, value: function (target) { if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object'); } var to = Object(target); for (var i = 1; i < arguments.length; i++) { var nextSource = arguments[i]; if (nextSource === undefined || nextSource === null) { continue; } nextSource = Object(nextSource); var keysArray = Object.keys(Object(nextSource)); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc !== undefined && desc.enumerable) { to[nextKey] = nextSource[nextKey]; } } } return to; } }); } var jsPanel = { version: '3.11.3', date: '2019-11-25 21:49', id: 0, // counter to add to automatically generated id attribute ziBase: 100, // the lowest z-index a jsPanel may have zi: 100, // z-index counter, has initially to be the same as ziBase modalcount: 0, // counter to set modal background and modal jsPanel z-index autopositionSpacing: 5, // sets spacing between autopositioned jsPanels pbTreshold: 0.556, // perceived brightness threshold to switch between white or black font color lastbeforeclose: false, // used in the handlers to reposition autopositioned panels template: `<div class="jsPanel"> <div class="jsPanel-hdr"> <div class="jsPanel-headerbar"> <div class="jsPanel-headerlogo"></div> <div class="jsPanel-titlebar"> <h3 class="jsPanel-title"></h3> </div> <div class="jsPanel-controlbar"> <div class="jsPanel-btn jsPanel-btn-smallify"><span class="jsglyph jsglyph-chevron-up"></span></div> <div class="jsPanel-btn jsPanel-btn-smallifyrev"><span class="jsglyph jsglyph-chevron-down"></span></div> <div class="jsPanel-btn jsPanel-btn-minimize"><span class="jsglyph jsglyph-minimize"></span></div> <div class="jsPanel-btn jsPanel-btn-normalize"><span class="jsglyph jsglyph-normalize"></span></div> <div class="jsPanel-btn jsPanel-btn-maximize"><span class="jsglyph jsglyph-maximize"></span></div> <div class="jsPanel-btn jsPanel-btn-close"><span class="jsglyph jsglyph-close"></span></div> </div> </div> <div class="jsPanel-hdr-toolbar"></div> </div> <div class="jsPanel-content jsPanel-content-nofooter"></div> <div class="jsPanel-minimized-box"></div> <div class="jsPanel-ftr"></div> </div>`, replacementTemplate: `<div class="jsPanel-replacement"> <div class="jsPanel-hdr"> <div class="jsPanel-headerbar"> <div class="jsPanel-titlebar"> <h3 class="jsPanel-title"></h3> </div> <div class="jsPanel-controlbar"> <div class="jsPanel-btn jsPanel-btn-normalize"><span class="jsglyph jsglyph-normalize"></span></div> <div class="jsPanel-btn jsPanel-btn-maximize"><span class="jsglyph jsglyph-maximize"></span></div> <div class="jsPanel-btn jsPanel-btn-close"><span class="jsglyph jsglyph-close"></span></div> </div> </div> </div> </div>`, themes: ['default', 'primary', 'info', 'success', 'warning', 'danger'], mdbthemes: ['secondary', 'elegant', 'stylish', 'unique', 'special'], // just the extra themes which are not contained in jsPanel.themes controls: ['close', 'maximize', 'normalize', 'minimize', 'smallify', 'smallifyrev'], tplHeaderOnly: `<div class="jsPanel"> <div class="jsPanel-hdr"> <div class="jsPanel-headerbar"> <div class="jsPanel-headerlogo"></div> <div class="jsPanel-titlebar"> <h3 class="jsPanel-title"></h3> </div> <div class="jsPanel-controlbar"> <div class="jsPanel-btn jsPanel-btn-close"><span class="jsglyph jsglyph-close"></span></div> </div> </div> <div class="jsPanel-hdr-toolbar"></div> </div> </div>`, tplContentOnly: `<div class="jsPanel"> <div class="jsPanel-content jsPanel-content-noheader jsPanel-content-nofooter"></div> <div class="jsPanel-minimized-box"></div> </div>`, activePanels: { list: [], getPanel(arg) { return typeof arg === 'string' ? document.getElementById(arg).jspanel.noop() : document.getElementById(this.list[arg]).jspanel.noop(); } // example: jsPanel.activePanels.getPanel(0).resize(600,250).reposition().css('background','yellow'); // or: jsPanel.activePanels.getPanel('jsPanel-1').resize(600,250).reposition().css('background','yellow'); }, closeOnEscape: false, isIE: (function () { return navigator.appVersion.indexOf('Trident') !== -1; }()), isEdge: (function () { return navigator.appVersion.indexOf('Edge') !== -1; }()), addConnector(panel) { const bgColor = panel.option.paneltype.connectorBG || null; if (panel[0].classList.contains('jsPanel-tooltip-top')) { panel.append('<div class="jsPanel-connector jsPanel-connector-top">'); jQuery('.jsPanel-connector-top', panel).css('border-top-color', bgColor || this.calcConnectorBg(panel, 'top')); panel.option.position.offsetY = panel.option.position.offsetY - 10 || -10; } else if (panel[0].classList.contains('jsPanel-tooltip-bottom')) { panel.append('<div class="jsPanel-connector jsPanel-connector-bottom">'); jQuery('.jsPanel-connector-bottom', panel).css('border-bottom-color', bgColor || this.calcConnectorBg(panel, 'bottom')); panel.option.position.offsetY = panel.option.position.offsetY + 10 || 10; } else if (panel[0].classList.contains('jsPanel-tooltip-left')) { panel.append('<div class="jsPanel-connector jsPanel-connector-left">'); jQuery('.jsPanel-connector-left', panel).css('border-left-color', bgColor || this.calcConnectorBg(panel, 'left')); panel.option.position.offsetX = panel.option.position.offsetX - 12 || -12; } else if (panel[0].classList.contains('jsPanel-tooltip-right')) { panel.append('<div class="jsPanel-connector jsPanel-connector-right">'); jQuery('.jsPanel-connector-right', panel).css('border-right-color', bgColor || this.calcConnectorBg(panel, 'right')); panel.option.position.offsetX = panel.option.position.offsetX + 12 || 12; } else if (panel[0].classList.contains('jsPanel-tooltip-lefttopcorner')) { panel.append('<div class="jsPanel-connector jsPanel-connector-lefttopcorner">'); jQuery('.jsPanel-connector-lefttopcorner', panel).css('background-color', bgColor || this.calcConnectorBg(panel, 'lefttopcorner')); } else if (panel[0].classList.contains('jsPanel-tooltip-righttopcorner')) { panel.append('<div class="jsPanel-connector jsPanel-connector-righttopcorner">'); jQuery('.jsPanel-connector-righttopcorner', panel).css('background-color', bgColor || this.calcConnectorBg(panel, 'righttopcorner')); } else if (panel[0].classList.contains('jsPanel-tooltip-rightbottomcorner')) { panel.append('<div class="jsPanel-connector jsPanel-connector-rightbottomcorner">'); jQuery('.jsPanel-connector-rightbottomcorner', panel).css('background-color', bgColor || this.calcConnectorBg(panel, 'rightbottomcorner')); } else if (panel[0].classList.contains('jsPanel-tooltip-leftbottomcorner')) { panel.append('<div class="jsPanel-connector jsPanel-connector-leftbottomcorner">'); jQuery('.jsPanel-connector-leftbottomcorner', panel).css('background-color', bgColor || this.calcConnectorBg(panel, 'leftbottomcorner')); } else if (panel[0].classList.contains('jsPanel-tooltip-lefttop')) { panel.append('<div class="jsPanel-connector jsPanel-connector-lefttop">'); jQuery('.jsPanel-connector-lefttop', panel).css('border-left-color', bgColor || this.calcConnectorBg(panel, 'lefttop')); panel.option.position.offsetX = panel.option.position.offsetX - 12 || -12; } else if (panel[0].classList.contains('jsPanel-tooltip-leftbottom')) { panel.append('<div class="jsPanel-connector jsPanel-connector-leftbottom">'); jQuery('.jsPanel-connector-leftbottom', panel).css('border-left-color', bgColor || this.calcConnectorBg(panel, 'leftbottom')); panel.option.position.offsetX = panel.option.position.offsetX - 12 || -12; } else if (panel[0].classList.contains('jsPanel-tooltip-topleft')) { panel.append('<div class="jsPanel-connector jsPanel-connector-topleft">'); jQuery('.jsPanel-connector-topleft', panel).css('border-top-color', bgColor || this.calcConnectorBg(panel, 'topleft')); panel.option.position.offsetY = panel.option.position.offsetY - 10 || -10; } else if (panel[0].classList.contains('jsPanel-tooltip-topright')) { panel.append('<div class="jsPanel-connector jsPanel-connector-topright">'); jQuery('.jsPanel-connector-topright', panel).css('border-top-color', bgColor || this.calcConnectorBg(panel, 'topright')); panel.option.position.offsetY = panel.option.position.offsetY - 10 || -10; } else if (panel[0].classList.contains('jsPanel-tooltip-righttop')) { panel.append('<div class="jsPanel-connector jsPanel-connector-righttop">'); jQuery('.jsPanel-connector-righttop', panel).css('border-right-color', bgColor || this.calcConnectorBg(panel, 'righttop')); panel.option.position.offsetX = panel.option.position.offsetX + 12 || 12; } else if (panel[0].classList.contains('jsPanel-tooltip-rightbottom')) { panel.append('<div class="jsPanel-connector jsPanel-connector-rightbottom">'); jQuery('.jsPanel-connector-rightbottom', panel).css('border-right-color', bgColor || this.calcConnectorBg(panel, 'rightbottom')); panel.option.position.offsetX = panel.option.position.offsetX + 12 || 12; } else if (panel[0].classList.contains('jsPanel-tooltip-bottomleft')) { panel.append('<div class="jsPanel-connector jsPanel-connector-bottomleft">'); jQuery('.jsPanel-connector-bottomleft', panel).css('border-bottom-color', bgColor || this.calcConnectorBg(panel, 'bottomleft')); panel.option.position.offsetY = panel.option.position.offsetY + 10 || 10; } else if (panel[0].classList.contains('jsPanel-tooltip-bottomright')) { panel.append('<div class="jsPanel-connector jsPanel-connector-bottomright">'); jQuery('.jsPanel-connector-bottomright', panel).css('border-bottom-color', bgColor || this.calcConnectorBg(panel, 'bottomright')); panel.option.position.offsetY = panel.option.position.offsetY + 10 || 10; } }, addCustomTheme(theme) { if (this.themes.indexOf(theme) === -1) { this.themes.push(theme); } }, ajax(panel) { const oAjax = panel.option.contentAjax, oSize = panel.option.contentSize; if (oAjax.then) { if (oAjax.then[0]) { oAjax.done = oAjax.then[0]; } if (oAjax.then[1]) { oAjax.fail = oAjax.then[1]; } } jQuery.ajax(oAjax) .done((data, textStatus, jqXHR) => { if (oAjax.autoload) { panel.content.append(data); } if (jQuery.isFunction(oAjax.done)) { oAjax.done.call(panel, data, textStatus, jqXHR, panel); } }) .fail((jqXHR, textStatus, errorThrown) => { if (jQuery.isFunction(oAjax.fail)) { oAjax.fail.call(panel, jqXHR, textStatus, errorThrown, panel); } }) .always((arg1, textStatus, arg3) => { if (jQuery.isFunction(oAjax.always)) { oAjax.always.call(panel, arg1, textStatus, arg3, panel); } if (panel.hasClass('jsPanel-contextmenu')) { jsPanel.checkContextmenuOverflow(panel); } // resize panel if either width or height is set to 'auto' if (typeof oSize === 'string' && oSize.match(/auto/i)) { var parts = oSize.split(' '), sizes = Object.assign({}, jQuery.jsPanel.resizedefaults, {width: parts[0], height: parts[1]}); if (oAjax.autoresize) { panel.resize(sizes); } if (!panel.hasClass('jsPanel-contextmenu')) { if (oAjax.autoreposition) { panel.reposition(); } } } else if (jQuery.isPlainObject(oSize) && (oSize.width === 'auto' || oSize.height === 'auto')) { var sizes = Object.assign({}, jQuery.jsPanel.resizedefaults, oSize); if (oAjax.autoresize) { panel.resize(sizes); } if (!panel.hasClass('jsPanel-contextmenu')) { if (oAjax.autoreposition) { panel.reposition(); } } } }); panel.data('ajaxURL', oAjax.url); // needed for exportPanels() }, applyBuiltInTheme(panel, themeDetails) { panel[0].classList.add(`jsPanel-theme-${themeDetails.color}`); // do not remove theme from jsP if (panel.header[0]) { panel.header[0].classList.add(`jsPanel-theme-${themeDetails.color}`); } // optionally set theme filling if (themeDetails.filling === 'filled') { panel.content.css('background', '')[0].classList.add('jsPanel-content-filled'); } else if (themeDetails.filling === 'filledlight') { panel.content.css('background', '')[0].classList.add('jsPanel-content-filledlight'); } if (!panel.option.headerToolbar) { panel.content.css({borderTop: `1px solid ${panel.header.title.css('color')}`}); } }, applyArbitraryTheme(panel, themeDetails) { panel.header.css('background-color', themeDetails.colors[0]); jQuery('.jsPanel-headerlogo, .jsPanel-title, .jsPanel-controlbar .jsPanel-btn .jsglyph, .jsPanel-hdr-toolbar', panel).css({color: themeDetails.colors[3]}); if (panel.option.headerToolbar) { panel.header.toolbar.css({ boxShadow: `0 0 1px ${themeDetails.colors[3]} inset`, width: 'calc(100% + 4px)', marginLeft: '-1px' }); } else { panel.content.css({borderTop: `1px solid ${themeDetails.colors[3]}`}); } if (themeDetails.filling === 'filled') { panel.content.css({backgroundColor: themeDetails.colors[0], color: themeDetails.colors[3]}); } else if (themeDetails.filling === 'filledlight') { panel.content.css({backgroundColor: themeDetails.colors[1]}); } }, applyBootstrapTheme(panel, themeDetails) { let pColor; panel.addClass(`panel panel-${themeDetails.bstheme} card card-inverse card-${themeDetails.bstheme}`); if (panel.header[0]) { panel.header[0].classList.add('panel-heading'); panel.header.title[0].classList.add('panel-title'); } // added support for material-design-for-bootstrap 4.x colors if (themeDetails.bs === 'mdb') { let mdbColor = `${themeDetails.bstheme}-color`; if (themeDetails.mdbStyle) { mdbColor = `${mdbColor}-dark`; } panel.removeClass(`panel panel-${themeDetails.bstheme}`); panel[0].classList.add(mdbColor); } // ---------------------------------------------------- panel.content[0].classList.add('panel-body'); // fix css problems for panels nested in other bootstrap panels panel.content.css('border-top-color', () => { return panel.header.css('border-top-color'); }); panel.footer.addClass('panel-footer card-footer'); if (jQuery('.panel-heading', panel).css('background-color') === 'transparent') { pColor = panel.css('background-color').replace(/\s+/g, ''); } else { pColor = jQuery('.panel-heading', panel).css('background-color').replace(/\s+/g, ''); } const bsColors = this.calcColors(pColor); jQuery('.jsPanel-headerlogo, .jsPanel-title, .jsPanel-controlbar .jsPanel-btn, .jsPanel-hdr-toolbar', panel.header).css('color', bsColors[3]); if (panel.option.headerToolbar) { panel.header.toolbar.css({ boxShadow: `0 0 1px ${bsColors[3]} inset`, width: 'calc(100% + 4px)', marginLeft: '-1px' }); } else { panel.content.css({borderTop: `1px solid ${bsColors[3]}`}); } if (themeDetails.filling === 'filled') { panel.content.css({backgroundColor: pColor, color: bsColors[3]}); } else if (themeDetails.filling === 'filledlight') { panel.content.css({backgroundColor: bsColors[1], color: '#000000'}); } }, applyThemeBorder(panel, themeDetails) { const bordervalues = panel.option.border.split(' '); panel.css({borderWidth: bordervalues[0], borderStyle: bordervalues[1], borderColor: bordervalues[2]}); //panel.header.css({'border-top-left-radius': 0, 'border-top-right-radius': 0}); if (!themeDetails.bs) { if (this.themes.indexOf(themeDetails.color) === -1) { // arbitrary themes only (for built-in themes it's taken from the css file) bordervalues[2] ? panel.css('border-color', bordervalues[2]) : panel.css('border-color', themeDetails.colors[0]); } } else { // bootstrap let pColor; if (jQuery('.panel-heading', panel).css('background-color') === 'transparent') { pColor = panel.css('background-color').replace(/\s+/g, ''); } else { pColor = jQuery('.panel-heading', panel).css('background-color').replace(/\s+/g, ''); } bordervalues[2] ? panel.css('border-color', bordervalues[2]) : panel.css('border-color', pColor); } }, calcColors(primaryColor) { const primeColor = this.color(primaryColor), secondColor = this.lighten(primaryColor, 0.81), thirdColor = this.darken(primaryColor, 0.5), fontColorForPrimary = this.perceivedBrightness(primaryColor) <= this.pbTreshold ? '#ffffff' : '#000000', fontColorForSecond = this.perceivedBrightness(secondColor) <= this.pbTreshold ? '#ffffff' : '#000000', fontColorForThird = this.perceivedBrightness(thirdColor) <= this.pbTreshold ? '#000000' : '#ffffff'; return [primeColor.hsl.css, secondColor, thirdColor, fontColorForPrimary, fontColorForSecond, fontColorForThird]; }, calcConnectorBg(panel, connector) { const bgColor_content = panel.content.css('background-color'), bgColor_ftr = panel.footer.css('background-color'), bgColor_panel = panel.header.css('background-color'); if (connector.match(/^(top|topleft|topright|lefttopcorner|righttopcorner|leftbottom|rightbottom)$/)) { if (panel.footer.css('display') !== 'none') { return bgColor_ftr; } else if (parseFloat(panel.option.contentSize.height) > 0) { return bgColor_content; } return bgColor_panel; } else if (connector.match(/^(bottom|bottomleft|bottomright|leftbottomcorner|rightbottomcorner)$/)) { if (!panel.option.headerRemove) { return bgColor_panel; } else if (parseFloat(panel.option.contentSize.height) > 0) { return bgColor_content; } else if (panel.footer.css('display') !== 'none') { return bgColor_ftr; } } else if (connector.match(/^(lefttop|righttop)$/)) { if (!panel.option.headerRemove) { return bgColor_panel; } else { return bgColor_content; } } else if (connector.match(/^(left|right)$/)) { if (parseFloat(panel.option.contentSize.height) > 0) { return bgColor_content; } else if (!panel.option.headerRemove) { return bgColor_panel; } else if (panel.footer.css('display') !== 'none') { return bgColor_ftr; } } }, clearTheme(panel) { this.themes.concat(this.mdbthemes).forEach(function (value) { panel.removeClass(`panel card card-inverse jsPanel-theme-${value} panel-${value} card-${value} ${value}-color`); panel.header.removeClass(`panel-heading jsPanel-theme-${value}`); }); panel.content.removeClass('panel-body jsPanel-content-filled jsPanel-content-filledlight'); panel.css({borderWidth: '', borderStyle: '', borderColor: ''}); jQuery('.jsPanel-hdr, .jsPanel-content', panel).css({background: ''}); jQuery('.jsPanel-headerlogo, .jsPanel-title, .jsPanel-controlbar .jsPanel-btn .jsglyph, .jsPanel-hdr-toolbar, .jsPanel-content', panel).css({color: ''}); panel.header.title.removeClass('panel-title'); panel.header.toolbar.css({boxShadow: '', width: '', marginLeft: ''}); panel.css({borderTop: '', borderTopColor: ''}); panel.footer.removeClass('panel-footer card-footer'); }, close(panel, ...params) { const id = panel.attr('id'), trigger = this.setTrigger(panel.option.position), delay = panel.option.delayClose, args = params; // params[0] has to be the callback or false // params[1] has to skipOnbeforeClose (if true callback is skipped) // params[2] has to be skipOnclosed (if true callback is skipped) function closePanel(panel, ...params) { params = args; // this code block is only relevant if panel uses autoposition ------------------------------ const jsPop = panel.option.position; if (jsPop.autoposition || ( typeof jsPop === 'string' && jsPop.match(/DOWN|RIGHT|UP|LEFT/i))) { const regex = /left-top|center-top|right-top|left-center|center|right-center|left-bottom|center-bottom|right-bottom/, parent = jQuery(panel).parent(), match = document.getElementById(id).className.match(regex); if (match) { jsPanel.lastbeforeclose = { parent: parent, class: match[0] }; } } // ------------------------------------------------------------------------------------------ // close all childpanels and then the panel itself panel.closeChildpanels().remove(); // execute the following code only when panel really was removed if (!jQuery(`#${id}`).length) { // remove id from activePanels.list let index = jsPanel.activePanels.list.indexOf(id); if (index > -1) { jsPanel.activePanels.list.splice(index, 1); } // remove replacement if present jsPanel.remMinReplacement(panel); // remove modal backdrop of corresponding modal jsPanel if (panel.option.paneltype === 'modal') { jsPanel.removeModalBackdrop(panel); } // remove class hasTooltip from tooltip trigger if panel to close is tooltip if (panel.option.paneltype.tooltip) { trigger.classList.remove('hasTooltip'); } jQuery(document).trigger('jspanelclosed', id); jQuery(document).trigger('jspanelstatuschange', id); // this code block is only relevant if panel uses autoposition ------------------------------ let container, panels, pos; if (jsPanel.lastbeforeclose) { container = jsPanel.lastbeforeclose.parent; panels = jQuery(`.${jsPanel.lastbeforeclose.class}`, container); pos = jsPanel.lastbeforeclose.class; } // than reposition all elmts if (panels) { // remove classname from all panels panels.each(function (index, elmt) { elmt.classList.remove(pos); }); // reposition remaining autopositioned panels panels.each(function (index, elmt) { jsPanel.position(elmt, panel.option.position); }); } jsPanel.lastbeforeclose = false; // ----------------------------------------------------------------------------------------------- // call onclosed callback of panel to close if (params[2] === true) { jQuery.noop(); } else { if (jQuery.isFunction(panel.option.onclosed)) { panel.option.onclosed.call(panel, panel); } } // call individual callback if (params[0] && jQuery.isFunction(params[0])) { params[0].call(panel, panel); } jsPanel.resetZis(); } } jQuery(document).trigger('jspanelbeforeclose', id); if (jQuery.isFunction(panel.option.onbeforeclose)) { // do not close panel if onbeforeclose callback returns false if (params[1] === true) { jQuery.noop(); } else { if (panel.option.onbeforeclose.call(panel, panel) === false) { return panel; } } } // delay is not implemented as function parameter because it wouldn't allow to pass in a delay used also // when hitting the close button which just calls panel.close(); if (!delay) { closePanel(panel, params[0], params[2]); } else if (typeof delay === 'number' && delay > 0) { window.setTimeout(function () { closePanel(panel, params[0], params[2]); }, delay); } else { closePanel(panel, params[0], params[2]); } }, // can be called on any container, not only jsPanels closeChildpanels(panel) { jQuery('.jsPanel', panel).each((index, elmt) => { // jspanel is not the global object jsPanel but the extension for the individual panel elmt elmt.jspanel.close(); }); return panel; }, closePanels(paneltype) { jQuery(`.jsPanel-${paneltype}`).each((index, elmt) => { if (elmt.jspanel) elmt.jspanel.close(); }); }, calcPositionFactors(panel) { if (panel.option.container === 'body') { panel.hf = parseInt(panel.css('left'), 10) / (jQuery(window).outerWidth() - panel.outerWidth()); panel.vf = parseInt(panel.css('top'), 10) / (jQuery(window).outerHeight() - panel.outerHeight()); } else { panel.hf = parseInt(panel.css('left'), 10) / (panel.parent().outerWidth() - panel.outerWidth()); panel.vf = parseInt(panel.css('top'), 10) / (panel.parent().outerHeight() - panel.outerHeight()); } }, color(val) { let color = val.toLowerCase(), r, g, b, h, s, l, match, channels, hsl, result = {}; const hexPattern = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/gi, // matches "#123" or "#f05a78" with or without "#" RGBAPattern = /^rgba?\(([0-9]{1,3}),([0-9]{1,3}),([0-9]{1,3}),?(0|1|0\.[0-9]{1,2}|\.[0-9]{1,2})?\)$/gi, // matches rgb/rgba color values, whitespace allowed HSLAPattern = /^hsla?\(([0-9]{1,3}),([0-9]{1,3}\%),([0-9]{1,3}\%),?(0|1|0\.[0-9]{1,2}|\.[0-9]{1,2})?\)$/gi, namedColors = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '0ff', aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '000', blanchedalmond: 'ffebcd', blue: '00f', blueviolet: '8a2be2', brown: 'a52a2a', burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00', chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed', cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '0ff', darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b', darkgray: 'a9a9a9', darkgrey: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b', darkmagenta: '8b008b', darkolivegreen: '556b2f', darkorange: 'ff8c00', darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a', darkseagreen: '8fbc8f', darkslateblue: '483d8b', darkslategray: '2f4f4f', darkslategrey: '2f4f4f', darkturquoise: '00ced1', darkviolet: '9400d3', deeppink: 'ff1493', deepskyblue: '00bfff', dimgray: '696969', dimgrey: '696969', dodgerblue: '1e90ff', firebrick: 'b22222', floralwhite: 'fffaf0', forestgreen: '228b22', fuchsia: 'f0f', gainsboro: 'dcdcdc', ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520', gray: '808080', grey: '808080', green: '008000', greenyellow: 'adff2f', honeydew: 'f0fff0', hotpink: 'ff69b4', indianred: 'cd5c5c', indigo: '4b0082', ivory: 'fffff0', khaki: 'f0e68c', lavender: 'e6e6fa', lavenderblush: 'fff0f5', lawngreen: '7cfc00', lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080', lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgray: 'd3d3d3', lightgrey: 'd3d3d3', lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a', lightseagreen: '20b2aa', lightskyblue: '87cefa', lightslategray: '789', lightslategrey: '789', lightsteelblue: 'b0c4de', lightyellow: 'ffffe0', lime: '0f0', limegreen: '32cd32', linen: 'faf0e6', magenta: 'f0f', maroon: '800000', mediumaquamarine: '66cdaa', mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8', mediumseagreen: '3cb371', mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a', mediumturquoise: '48d1cc', mediumvioletred: 'c71585', midnightblue: '191970', mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5', navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6', olive: '808000', olivedrab: '6b8e23', orange: 'ffa500', orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa', palegreen: '98fb98', paleturquoise: 'afeeee', palevioletred: 'd87093', papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f', pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6', purple: '800080', rebeccapurple: '639', red: 'f00', rosybrown: 'bc8f8f', royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072', sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee', sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb', slateblue: '6a5acd', slategray: '708090', slategrey: '708090', snow: 'fffafa', springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c', teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347', turquoise: '40e0d0', violet: 'ee82ee', wheat: 'f5deb3', white: 'fff', whitesmoke: 'f5f5f5', yellow: 'ff0', yellowgreen: '9acd32' }; // change named color to corresponding hex value if (namedColors[color]) { color = namedColors[color]; } // check val for hex color if (color.match(hexPattern) !== null) { // '#' entfernen wenn vorhanden color = color.replace('#', ''); // color has either 3 or 6 characters if (color.length % 2 === 1) { // color has 3 char -> convert to 6 char // r = color.substr(0,1).repeat(2); // g = color.substr(1,1).repeat(2); // String.prototype.repeat() doesn't work in IE11 // b = color.substr(2,1).repeat(2); r = String(color.substr(0, 1)) + color.substr(0, 1); g = String(color.substr(1, 1)) + color.substr(1, 1); b = String(color.substr(2, 1)) + color.substr(2, 1); result.rgb = { r: parseInt(r, 16), g: parseInt(g, 16), b: parseInt(b, 16) }; result.hex = `#${r}${g}${b}`; } else { // color has 6 char result.rgb = { r: parseInt(color.substr(0, 2), 16), g: parseInt(color.substr(2, 2), 16), b: parseInt(color.substr(4, 2), 16) }; result.hex = `#${color}`; } hsl = this.rgbToHsl(result.rgb.r, result.rgb.g, result.rgb.b); result.hsl = hsl; result.rgb.css = `rgb(${result.rgb.r},${result.rgb.g},${result.rgb.b})`; } // check val for rgb/rgba color else if (color.match(RGBAPattern)) { match = RGBAPattern.exec(color); result.rgb = {css: color, r: match[1], g: match[2], b: match[3]}; result.hex = this.rgbToHex(match[1], match[2], match[3]); hsl = this.rgbToHsl(match[1], match[2], match[3]); result.hsl = hsl; } // check val for hsl/hsla color else if (color.match(HSLAPattern)) { match = HSLAPattern.exec(color); h = match[1] / 360; s = match[2].substr(0, match[2].length - 1) / 100; l = match[3].substr(0, match[3].length - 1) / 100; channels = this.hslToRgb(h, s, l); result.rgb = { css: `rgb(${channels[0]},${channels[1]},${channels[2]})`, r: channels[0], g: channels[1], b: channels[2] }; result.hex = this.rgbToHex(result.rgb.r, result.rgb.g, result.rgb.b); result.hsl = {css: `hsl(${match[1]},${match[2]},${match[3]})`, h: match[1], s: match[2], l: match[3]}; } // or return #f5f5f5 else { result.hex = '#f5f5f5'; result.rgb = {css: 'rgb(245,245,245)', r: 245, g: 245, b: 245}; result.hsl = {css: 'hsl(0,0%,96.08%)', h: 0, s: '0%', l: '96.08%'}; } return result; }, configIconfont(panel) { const bootstrapArray = ['remove', 'fullscreen', 'resize-full', 'minus', 'chevron-up', 'chevron-down'], fontawesomeArray = ['times fa-window-close', 'arrows-alt fa-window-maximize', 'expand fa-window-restore', 'minus fa-window-minimize', 'chevron-up', 'chevron-down'], materialArray = ['close', 'fullscreen', 'fullscreen_exit', 'call_received', 'expand_less', 'expand_more'], optIconfont = panel.option.headerControls.iconfont, controls = panel.header.headerbar; // set icons if (optIconfont === 'bootstrap' || optIconfont === 'glyphicon') { this.controls.forEach((item, i) => { jQuery(`.jsPanel-btn-${item} span`, controls).removeClass().addClass(`glyphicon glyphicon-${bootstrapArray[i]}`); }); } else if (optIconfont === 'font-awesome') { this.controls.forEach((item, i) => { jQuery(`.jsPanel-btn-${item} span`, controls).removeClass().addClass(`fa fa-${fontawesomeArray[i]}`); }); } else if (optIconfont === 'material-icons') { this.controls.forEach((item, i) => { jQuery(`.jsPanel-btn-${item} span`, controls).removeClass().addClass('material-icons').text(materialArray[i]); }); } else if (Array.isArray(optIconfont)) { // ['custom-close', 'custom-maximize', 'custom-normalize', 'custom-minimize', 'custom-smallify', 'custom-unsmallify'] this.controls.forEach((item, i) => { jQuery(`.jsPanel-btn-${item} span`, controls).removeClass().addClass(`custom-control-icon ${optIconfont[i]}`); }); } }, // builds toolbar configToolbar(toolbaritems, toolbarplace, panel) { toolbaritems.forEach(item => { if (typeof item === 'object') { const el = jQuery(item.item); // add text to button if (typeof item.btntext === 'string') { el.append(item.btntext); } // add class to button if (typeof item.btnclass === 'string') { item.btnclass.split(' ').forEach(function (classname) { el[0].classList.add(classname); }); } toolbarplace.append(el); // bind handler to the item if (jQuery.isFunction(item.callback)) { const elEvent = item.event || 'click'; el.on(elEvent, panel, item.callback); // jsP is accessible in the handler as "event.data" } } }); }, contentReload(panel, callback) { if (panel.option.content) { panel.content.empty().append(panel.option.content); } else if (panel.option.contentAjax) { panel.content.empty(); this.ajax(panel); } else if (panel.option.contentIframe) { panel.content.empty(); this.iframe(panel); } // call individual callback if (callback && jQuery.isFunction(callback)) { callback.call(panel, panel); } return panel; }, contentResize(panel, callback) { const hdrftr = panel.footer[0].classList.contains('active') ? panel.header.outerHeight() + panel.footer.outerHeight() : panel.header.outerHeight(), borderWidth = parseInt(panel.css('border-top-width'), 10) + parseInt(panel.css('border-bottom-width'), 10); panel.content.css({height: panel.outerHeight() - hdrftr - borderWidth}); // call individual callback if (callback && jQuery.isFunction(callback)) { callback.call(panel, panel); } return panel; }, createMinimizedReplacement(panel) { const replacement = jQuery(this.replacementTemplate), fontColor = panel.header.title.css('color'), titletext = panel.header.title[0].textContent; let bgColor; if (panel.header.css('background-color') === 'transparent') { bgColor = panel.css('background-color'); } else { bgColor = panel.header.css('background-color'); } // move jsPanel off screen panel.css('left', '-9999px') .data('status', 'minimized'); // set replacement props replacement.css('background-color', bgColor) .prop('id', `${panel.prop('id')}-min`) .find('h3').css('color', fontColor) .prop('title', titletext) .html(titletext); // add logo if (panel.header.logo.children().length) { jQuery('.jsPanel-headerbar', replacement).prepend(panel.header.logo.clone()); } // set replacement iconfont const iconfont = panel.option.headerControls.iconfont; if (iconfont === 'font-awesome') { jQuery('.jsglyph.jsglyph-normalize', replacement).removeClass().addClass('fa fa-expand fa-window-restore'); jQuery('.jsglyph.jsglyph-maximize', replacement).removeClass().addClass('fa fa-arrows-alt fa-window-maximize'); jQuery('.jsglyph.jsglyph-close', replacement).removeClass().addClass('fa fa-times fa-window-close'); } else if (iconfont === 'bootstrap' || iconfont === 'glyphicon') { jQuery('.jsglyph.jsglyph-normalize', replacement).removeClass().addClass('glyphicon glyphicon-resize-full'); jQuery('.jsglyph.jsglyph-maximize', replacement).removeClass().addClass('glyphicon glyphicon-fullscreen'); jQuery('.jsglyph.jsglyph-close', replacement).removeClass().addClass('glyphicon glyphicon-remove'); } else if (iconfont === 'material-icons') { jQuery('.jsglyph.jsglyph-normalize', replacement).removeClass().addClass('material-icons').text('call_made'); jQuery('.jsglyph.jsglyph-maximize', replacement).removeClass().addClass('material-icons').text('fullscreen'); jQuery('.jsglyph.jsglyph-close', replacement).removeClass().addClass('material-icons').text('close'); } else if (Array.isArray(iconfont)) { jQuery('.jsglyph.jsglyph-normalize', replacement).removeClass().addClass(`custom-control-icon ${iconfont[2]}`); jQuery('.jsglyph.jsglyph-maximize', replacement).removeClass().addClass(`custom-control-icon ${iconfont[1]}`); jQuery('.jsglyph.jsglyph-close', replacement).removeClass().addClass(`custom-control-icon ${iconfont[0]}`); } jQuery('.jsPanel-btn span', replacement).css({color: fontColor}); return replacement; }, darken(val, amount) { // amount is value between 0 and 1 const hsl = this.color(val).hsl, l = parseFloat(hsl.l), lnew = l - (l * amount) + '%'; return `hsl(${hsl.h},${hsl.s},${lnew})`; }, // helper function for the doubleclick handlers (title, content, footer) dblclickhelper(odcs, panel) { if (typeof odcs === 'string') { if (odcs === 'maximize' || odcs === 'normalize') { panel.data('status') === 'normalized' ? panel.maximize() : panel.normalize(); } else if (odcs === 'minimize' || odcs === 'smallify' || odcs === 'close') { panel[odcs](); } } }, // my own implementation of a draggable functionality dragit(element, options = {}) { //let freezeVp = function(e) {e.preventDefault();}; let elmt; if (typeof element === 'string') { elmt = document.querySelector(element); } else if (element.jquery) { elmt = element[0]; } else { elmt = element; } let el = element.jquery ? element : elmt; // el is used as arg within dragstart, drag and dragstop callbacks and as return value let dragstarted, opts = Object.assign({}, jQuery.jsPanel.defaults.dragit, options), containment = opts.containment, containmentArray, dragPanel, handles, elmtParent = elmt.parentElem