').attr('id', overlayIdAttr).html(overlayTemplate);
$overlay.off('click.labelManager', '#label-manager-close-icon');
$overlay.on('click.labelManager', '#label-manager-close-icon', function (event) {
event.preventDefault();
$overlay.hide();
});
$overlay.hide();
$overlay.appendTo('body');
$overlay.draggable({
handle: 'header'
});
return $overlay;
},
/**
* Position für Label-Manager-Overlay berechnen
*
* @param {jQuery} $trigger
* @param {jQuery} $overlay
*
* @return {{top: number, left: number}}
*/
calculateOverlayPosition: function ($trigger, $overlay) {
var triggerOffset = $trigger.offset();
var overlayWidth = $overlay.width();
var overlayHeight = $overlay.height();
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var windowScrollLeft = window.pageXOffset || 0;
var windowScrollTop = window.pageYOffset || 0;
var triggerTop = triggerOffset.top - windowScrollTop;
var triggerLeft = triggerOffset.left - windowScrollLeft;
// Overlay relativ zum "Öffner"-Link platzieren
var overlayLeft = triggerLeft + 20;
var overlayTop = triggerTop;
// Korrektur, falls Overlay rechts abgeschnitten werden würde
var overlayRightBoundary = overlayLeft + overlayWidth + 20;
if (overlayRightBoundary > windowWidth) {
overlayLeft = windowWidth - (overlayWidth + 20);
overlayTop += 20;
}
// Korrektur, falls Overlay unten abgeschnitten werden würde
var overlayBottomBoundary = overlayTop + overlayHeight;
if (overlayBottomBoundary > windowHeight) {
overlayTop = windowHeight - (overlayHeight + 20);
}
return {top: overlayTop, left: overlayLeft};
},
/**
* Liste mit Label-Typen abrufen
*
* @param {string} referenceTable
* @param {number} referenceId
*
* @return {jqXHR}
*/
fetchLabelTypesList: function (referenceTable, referenceId) {
if (typeof referenceTable !== 'string' || referenceTable === '') {
throw 'LabelManager: InvalidArgument "referenceTable".';
}
if (typeof referenceId !== 'number' || referenceId === '' || referenceId === 0) {
throw 'LabelManager: InvalidArgument "referenceId".';
}
return $.ajax({
url: 'index.php?module=ajax&action=labels&cmd=list',
method: 'post',
dataType: 'json',
data: {
reference_id: referenceId,
reference_table: referenceTable
}
});
},
/**
* @param {Array|object[]} labelList
*/
renderLabelTypesList: function (labelList) {
var $overlay = me.getOverlay();
var $contentList = $overlay.find('section.content-list').html('').show();
if (labelList.length === 0) {
$contentList.html('Keine Label gefunden');
return;
}
var itemHtml = '';
var itemTemplate =
'
' +
' ' +
'' +
'
';
labelList.forEach(function (labelItem) {
var checkedAttr = labelItem.selected === true ? 'checked="checked"' : '';
itemHtml = itemTemplate;
itemHtml = itemHtml.replace('{{checkedAttr}}', checkedAttr);
itemHtml = itemHtml.replace('{{type}}', labelItem.type);
itemHtml = itemHtml.replace('{{type}}', labelItem.type);
itemHtml = itemHtml.replace('{{title}}', labelItem.title);
var $line = $(itemHtml);
var labelColors = LabelRendererModule.calculateLabelColors(labelItem.bgcolor);
$line.find('.label-title').css(labelColors);
var $checkbox = $line.find('.label-manager-type-checkbox');
$checkbox.data('labelType', labelItem.type);
$checkbox.data('labelTitle', labelItem.title);
$checkbox.data('labelColor', labelItem.bgcolor);
$checkbox.data('labelReferenceTable', labelItem.referenceTable);
$checkbox.data('labelReferenceId', labelItem.referenceId);
$contentList.append($line);
});
// Höhe zurücksetzen (wird durch Draggable gesetzt)
$overlay.css('height', 'auto');
}
};
return {
init: me.init,
destroy: me.destroy,
showOverlay: me.showOverlay,
hideOverlay: me.hideOverlay
};
})(jQuery, LabelRenderer);
/**
* Modul zum Laden von Labels
*
* @type {{loadElement: *, loadAll: *}}
*/
var LabelLoader = (function ($, LabelRendererModule) {
'use strict';
var me = {
/**
* Lädt alle (noch) nicht geladenenen Labels
*/
loadAll: function () {
// Referenzen für benötigte Labels sammeln
var collection = me.collectLabels();
var collectionKeys = Object.keys(collection);
if (collectionKeys.length === 0) {
return; // Keine Daten vorhanden
}
// Label-Daten für gesammelte Labels abrufen und rendern
me.fetchCollection(collection).then(me.renderCollection, function (jqXhr) {
alert('LabelLoader-Fehler: ' + jqXhr.responseJSON.error);
});
},
/**
* Lädt die Labels für ein einzelnes Element
*
* autoload-Einstellung wird ignoriert
*
* @param {jQuery} $element
*/
loadElement: function ($element) {
if (!$element instanceof jQuery) {
return;
}
if ($element.length !== 1) {
return;
}
var referenceTable = $element.data('labelReferenceTable');
var referenceId = $element.data('labelReferenceId');
var compactData = $element.data('labelCompact');
var compact = typeof compactData !== 'undefined' && typeof compactData === 'boolean' ? compactData : false;
// Pflicht-Optionen vorhanden
if (typeof referenceTable === 'undefined' || typeof referenceId === 'undefined') {
return;
}
referenceId = parseInt(referenceId);
if (isNaN(referenceId)) {
return;
}
$element.addClass('labels-' + referenceTable + '-' + referenceId);
$element.addClass('label-container');
$element.removeClass('label-loader');
if (compact) {
$element.addClass('label-compact');
}
me.fetchLabels(referenceTable, referenceId);
},
/**
* @param {string} referenceTable
* @param {number} referenceId
*/
fetchLabels: function (referenceTable, referenceId) {
if (typeof referenceTable !== 'string' || referenceTable === '') {
throw 'LabelManager: InvalidArgument "referenceTable".';
}
if (typeof referenceId !== 'number' || referenceId === '' || referenceId === 0) {
throw 'LabelManager: InvalidArgument "referenceId".';
}
var collection = {};
collection[referenceTable] = [referenceId];
$.ajax({
url: 'index.php?module=ajax&action=labels&cmd=collect',
method: 'post',
dataType: 'json',
data: {
collection: collection
},
success: function (result) {
LabelRendererModule.render(result.data);
},
error: function (jqXhr) {
alert('Fehler: ' + jqXhr.responseJSON.error);
}
});
},
/**
* Sammelt alle Labels die noch nicht geladen wurden
*
* @return {Object} Collection von Labels die geladen werden müssen
*/
collectLabels: function () {
var result = {};
var $loaders = $('.label-loader');
$loaders.each(function () {
var $elem = $(this);
var referenceTable = $elem.data('labelReferenceTable');
var referenceId = $elem.data('labelReferenceId');
if (typeof referenceTable === 'undefined' || typeof referenceId === 'undefined') {
return;
}
var autoloadData = $elem.data('labelAutoload');
var autoload = typeof autoloadData !== 'undefined' && typeof autoloadData === 'boolean' ? autoloadData : true;
if (!autoload) {
return;
}
// Label-Container erstellen mit eindeutiger CSS-Klasse (aber nicht Unique)
// CSS-Klasse kann mehrmals vorkommen, in unterschiedlichen DataTables
// mit identischen Referenz-ID und -Tabelle.
$elem.addClass('labels-' + referenceTable + '-' + referenceId);
$elem.addClass('label-container');
$elem.removeClass('label-loader');
var compactData = $elem.data('labelCompact');
var compactStyle = typeof compactData !== 'undefined' && typeof compactData === 'boolean' ? compactData : false;
if (compactStyle) {
$elem.addClass('label-compact');
}
// References sammeln
if (!result.hasOwnProperty(referenceTable)) {
result[referenceTable] = [];
}
if (!me.inArray(referenceId, result[referenceTable])) {
result[referenceTable].push(referenceId);
}
});
return result;
},
/**
* @param {object} collection
*
* @return {jqXHR|null}
*/
fetchCollection: function (collection) {
return $.ajax({
url: 'index.php?module=ajax&action=labels&cmd=collect',
method: 'post',
dataType: 'json',
data: {collection: collection}
});
},
/**
* @param {object} collectionResult Das Ergebnis von me.fetchCollection()
*/
renderCollection: function (collectionResult) {
if (!collectionResult.hasOwnProperty('data')) {
return;
}
LabelRendererModule.render(collectionResult.data);
},
/**
* Prüfen ob Wert in einem Array vorkommt
*
* @param {number|string} value
* @param {Array} array
*
* @return {boolean}
*/
inArray: function (value, array) {
return array.indexOf(value) > -1;
}
};
return {
loadAll: me.loadAll,
loadElement: me.loadElement
};
})(jQuery, LabelRenderer);
/**
* Labels jQuery-Plugin + LabelsApi
*
* Dokumentation: Siehe Dateianfang
*/
(function ($, LabelLoaderModule, LabelManagerModule) {
'use strict';
var LabelsApi = function ($element, options) {
var me = {
/** @property {Object} me.defaults Default configuration */
defaults: {
referenceTable: null, // Pflicht-Option
referenceId: null, // Pflicht-Option
autoload: true,
compact: false,
trigger: null
},
storage: {
$trigger: null,
$element: null,
options: {}
},
/**
* @param {jQuery} $element
* @param {Object} options
*/
init: function ($element, options) {
if (typeof $element === 'undefined') {
throw 'LabelsApi konnte nicht initialisiert werden. Element wurde nicht übergeben.';
}
if ($element.length !== 1) {
throw 'LabelsApi konnte nicht initialisiert werden. Trigger-Element wurde nicht gefunden.';
}
// Optionen mit Defaults mergen
// Reihenfolge: Javascript-Optionen überschreiben Data-Attribute
var dataAttributesAll = $element.data();
var dataAttributesLabel = me.filterDataAttributesByPrefix(dataAttributesAll, 'label');
var mergedOptions = $.extend({}, me.defaults, dataAttributesLabel, options);
// Benötigte Optionen prüfen
if (mergedOptions.referenceTable === null) {
throw 'LabelsApi konnte nicht initialisiert werden. Benötigte Option \'referenceTable\' fehlt.';
}
if (mergedOptions.referenceId === null) {
throw 'LabelsApi konnte nicht initialisiert werden. Benötigte Option \'referenceId\' fehlt.';
}
mergedOptions.referenceId = parseInt(mergedOptions.referenceId);
if (isNaN(mergedOptions.referenceId)) {
throw 'LabelsApi konnte nicht initialisiert werden. Benötigte Option \'referenceId\' ist ungültig.';
}
// Sicherstellen dass alle Data-Attribute gesetzt sind;
// bei Initialisierung über jQuery-Plugin mit Options-Array.
if (mergedOptions.hasOwnProperty('referenceTable')) {
$element.data('labelReferenceTable', mergedOptions.referenceTable);
}
if (mergedOptions.hasOwnProperty('referenceId')) {
$element.data('labelReferenceId', mergedOptions.referenceId);
}
if (mergedOptions.hasOwnProperty('autoload')) {
$element.data('labelAutoload', mergedOptions.autoload);
}
if (mergedOptions.hasOwnProperty('compact')) {
$element.data('labelCompact', mergedOptions.compact);
}
if (mergedOptions.hasOwnProperty('trigger')) {
$element.data('labelTrigger', mergedOptions.trigger);
}
LabelLoaderModule.loadElement($element);
if (typeof mergedOptions.trigger !== 'undefined' && mergedOptions.trigger !== null) {
me.initTriggerElement(mergedOptions.trigger, mergedOptions.referenceTable, mergedOptions.referenceId);
}
},
/**
* @param {string} triggerSelector
* @param {string} referenceTable
* @param {number} referenceId
*/
initTriggerElement: function (triggerSelector, referenceTable, referenceId) {
var $trigger = $(triggerSelector);
if ($trigger.length !== 1) {
console.warn('LabelsApi: Trigger-Element "' + triggerSelector + '" wurde nicht gefunden');
return;
}
$trigger
.addClass('label-manager')
.data('labelReferenceTable', referenceTable)
.data('labelReferenceId', referenceId);
me.storage.$trigger = $trigger;
},
/**
* Label-Manager-Overlay einblenden
*/
showOverlay: function () {
if (me.storage.$trigger === null) {
console.warn('LabelsApi: Kein Trigger definiert');
}
me.storage.$trigger.trigger('click.labelManager');
},
/**
* Label-Manager-Overlay ausblenden
*/
hideOverlay: function () {
LabelManagerModule.hideOverlay();
},
/**
* @param {object} attributes
* @param {string} prefix
*
* @return {object}
*/
filterDataAttributesByPrefix: function (attributes, prefix) {
if (typeof attributes !== 'object') {
throw 'LabelManagerApi: InvalidArgument "attributes".';
}
if (typeof prefix !== 'string' || prefix === '') {
throw 'LabelManagerApi: InvalidArgument "prefix".';
}
var filteredAttributes = {};
Object.keys(attributes).forEach(function (key) {
if (key.indexOf(prefix) === 0) {
var value = attributes[key];
var keyWithoutPrefix = key.substr(prefix.length);
var keyFirstCharLowered = keyWithoutPrefix.charAt(0).toLowerCase() + keyWithoutPrefix.slice(1);
filteredAttributes[keyFirstCharLowered] = value;
}
});
return filteredAttributes;
}
};
me.init($element, options);
return {
showOverlay: me.showOverlay,
hideOverlay: me.hideOverlay
}
};
// jQuery-Plugin registrieren
$.fn.labels = function (options) {
return this.each(function () {
var $elem = $(this);
// Neue API-Instanz erzeugen
// Dokumentation: Siehe Dateianfang
var api = new LabelsApi($elem, options);
/**@return {{showOverlay: *, hideOverlay: *}} */
$elem.init.prototype.labelsApi = function () {
return api;
};
$elem.data('labelsApi', api);
});
};
}(jQuery, LabelLoader, LabelManager));
$(function () {
LabelManager.init();
LabelLoader.loadAll();
// LabelManager-Overlay ausblenden beim Wechseln von Tabs
$('#tabs').on('tabsactivate', function() {
LabelManager.hideOverlay();
});
});