jspanel3
Version:
A jQuery Plugin to create highly configurable multifunctional floating panels
1,068 lines (904 loc) • 187 kB
JavaScript
/* 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