/* --------------------------------------------------------------
button_dropdown.js 2016-06-10
Gambio GmbH
http://www.gambio.de
Copyright (c) 2016 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------
*/
jse.libs.button_dropdown = jse.libs.button_dropdown || {};
/**
* ## Button Dropdown Library
*
* This library contains helper functions that make the manipulation of a button dropdown
* widget easier.
*
* You will need to provide the full URL in order to load this library as a dependency to a module:
*
* ```javascript
* gx.controller.module(
* 'my_custom_page',
*
* [
* gx.source + '/libs/button_dropdown'
* ],
*
* function(data) {
* // Module code ...
* });
*```
*
* ### Example
*
* ```javascript
* var $buttonDropdown = $('#my.js-button-dropdown');
*
* // Map an action to a dropdown item.
* jse.libs.button_dropdown.mapAction($buttonDropdown, action, section, callback, $targetRecentButton);
*
* // Change recent button.
* jse.libs.button_dropdown.changeDefualtButton($buttonDropdown, text, callback, $targetRecentButton);
*
* // Add a separator in a dropdown list.
* jse.libs.button_dropdown.addDropdownSeperator($buttonDropdown);
* ```
*
* @todo Further improve the code and the comments of this library.
*
* @module Admin/Libs/button_dropdown
* @exports jse.libs.button_dropdown
*/
(function (exports) {
'use strict';
// ------------------------------------------------------------------------
// PRIVATE METHODS
// ------------------------------------------------------------------------
/**
* Triggers a specific event from an element.
*
* Some situations require a different approach than just using the "trigger" method.
*
* @param {object} $element Destination element to be triggered.
* @param {object} event Event options can be used for creating new conditions.
*
* @private
*/
var _triggerEvent = function ($element, event) {
if ($element.prop('tagName') === 'A' && event.type === 'click') {
$element.get(0).click();
} else {
$element.trigger(event.type);
}
};
/**
* Binds the event to a new dropdown action item.
*
* @param {object} options See bind documentation.
*
* @private
*/
var _bindEvent = function (options) {
var $dropdown = options.$dropdown,
action = options.action,
$target = options.$target,
eventName = options.event,
callback = options.callback || false,
title = options.title || (options.$target.length ? options.$target.text() : '<No Action Title Provided>'),
$li = $('<li></li>');
$li.html('<span data-value="' + action + '">' + title + '</span>');
$dropdown.find('ul').append($li);
$li.find('span').on(eventName, function (event) {
if (callback !== false) {
//event.preventDefault();
//event.stopPropagation();
callback.call($li.find('span'), event);
} else {
_triggerEvent($target, event);
}
});
};
/**
* Initializes the default button.
*
* @param {object} $dropdown The affected button dropdown selector.
* @param {object} configValue Configuration value that comes from the UserConfigurationService.
* @param {object} title The caption of the default action button.
* @param {object} callback (optional) Callback function for the new action.
* @param {object} $targetDefaultButton (optional) Selector for the default button.
*/
var _initDefaultAction = function ($dropdown, configValue, title, callback, $targetDefaultButton) {
var interval = setInterval(function () {
if (typeof $dropdown.attr('data-configuration_value') !== 'undefined') {
// Sets the recent action button loaded from database.
if ($dropdown.attr('data-configuration_value') === configValue) {
exports.changeDefaultAction($dropdown, title, callback, $targetDefaultButton);
}
clearInterval(interval);
}
}, 300);
};
// ------------------------------------------------------------------------
// PUBLIC METHODS
// ------------------------------------------------------------------------
/**
* Adds a new item to the dropdown.
*
* @param {string} translationPhrase Translation phrase key.
* @param {string} translationSection Translation section of the phrase.
* @param {function} customCallback Define a custom callback.
* @param {object} $targetDefaultButton (optional) A custom selector which dropdown buttons should be changed.
*/
exports.mapAction =
function ($dropdown, translationPhrase, translationSection, customCallback, $targetDefaultButton) {
var $target = $targetDefaultButton || $dropdown,
title = (translationSection !== '')
? jse.core.lang.translate(translationPhrase, translationSection)
: translationPhrase;
// Sets the first action as recent action button, if no recent action has benn set so far.
if (!$dropdown.find('ul li').length && $dropdown.find('button:first').text().trim() === '') {
exports.changeDefaultAction($dropdown, title, customCallback, $target);
}
_initDefaultAction($dropdown, translationPhrase, title, customCallback, $target);
var options = {
action: translationPhrase,
$dropdown: $dropdown,
title: title,
event: 'perform:action',
callback: function (event) {
customCallback(event);
exports.changeDefaultAction($(this), title, customCallback, $target);
}
};
_bindEvent(options);
};
/**
* Changes the default action of the button.
*
* @param {object} $button The affected button dropdown widget.
* @param {string} title Text of the new button.
* @param {string} callback The callback
* @param {object} $targetDefaultButton A custom element for which button should be changed.
*/
exports.changeDefaultAction = function ($dropdown, title, callback, $targetDefaultButton) {
var $target = $targetDefaultButton || $dropdown,
icon = $target.data('icon');
if (title.length) {
$target
.find('button:first')
.off('perform:action')
.on('perform:action', callback);
}
$target
.find('button:first')
.text(title);
$target
.find('button:first')
.prop('title', title.trim());
if (typeof icon !== 'undefined') {
$target
.find('button:first')
.prepend($('<i class="fa fa-' + icon + ' btn-icon"></i>'));
}
};
/**
* Add button-dropdown action.
*
* This method works with the Bootstrap markup button-dropdowns and enables you to add actions with callbacks
* existing button dropdown elements.
*
* The action object can have the following attributes and default values:
*
* {
* text: '{Undefined}', // The text to be displayed.
* href: '#', // URL for the <a> element.
* target: '', // Target attribute for <a> element.
* class: '', // Add custom classes to the <a> element.
* data: {}, // Add data to the <a> element.
* isDefault: false, // Whether the action is the default action.
* callback: function(e) {} // Callback for click event of the <a> element.
* }
*
* @param {object} $dropdown The jQuery selector of the button dropdown wrapper.
* @param {object} action An object containing the action information.
*/
exports.addAction = function ($dropdown, action) {
let $li = $('<li/>'),
$a = $('<a />');
$a
.text(action.text || '{Undefined}')
.attr('href', action.href || '#')
.attr('target', action.target || '')
.addClass(action.class || '')
.data(action.data)
.appendTo($li);
if (action.isDefault) {
exports.setDefaultAction($dropdown, $a);
}
if (action.callback) {
$a.on('click', action.callback);
}
$li.appendTo($dropdown.find('ul'));
};
/**
* Adds a separator to the dropdown list.
*
* The separator will be added at the end of the list.
*
* @param {object} $dropdown The jQuery selector of the button dropdown wrapper.
* @param {bool} compatibilityMarkup (optional) Whether to use the compatibility markup.
*/
exports.addSeparator = function ($dropdown, compatibilityMarkup = false) {
let html = !compatibilityMarkup ? '<li role="separator" class="divider"></li>' : '<li><hr></li>';
$dropdown.find('ul').append(html);
};
/**
* Bind button dropdown default action.
*
* This method will update the default action of the dropdown upon click. This is useful for storing the
* default actions and then using them to display the default one with every new instance of the button
* dropdown.
*
* Important: The <a> elements need to have the "configurationValue" data property that defines a unique string
* for the selected action.
*
* @param {object} $dropdowns The jQuery selector of the button dropdowns wrapper.
* @param {number} userId The ID of the current user.
* @param {string} configurationKey The configuration key to be saved.
* @param {object} userConfigurationService The user_configuration_service module (needs to be passed explicitly).
*/
exports.bindDefaultAction = function ($dropdowns, userId, configurationKey, userConfigurationService) {
$dropdowns.on('click', 'a', function () {
const params = {
data: {
userId,
configurationKey,
configurationValue: $(this).data('configurationValue')
}
};
userConfigurationService.set(params);
exports.setDefaultAction($dropdowns, $(this));
});
};
/**
* Set the default action item for button dropdowns.
*
* @param {object} $dropdowns jQuery selector for the button dropdowns.
* @param {object} $actionLink jQuery selector for the action link to be set as default.
*/
exports.setDefaultAction = function ($dropdowns, $actionLink) {
$dropdowns.each((index, dropdown) => {
const $dropdownButton = $(dropdown).children('button:first');
$dropdownButton
.text($actionLink.text())
.off('click')
.on('click', () => {
// Do nothing when the dropdown is grayed out.
if ($dropdownButton.hasClass('disabled')) {
return;
}
$(dropdown)
.find(`li:eq(${$actionLink.parent().index()}) a`)[0]
.click();
});
});
};
})(jse.libs.button_dropdown);