430 lines
14 KiB
JavaScript
Executable File
430 lines
14 KiB
JavaScript
Executable File
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
|
|
/* global FORM_KEY */
|
|
define([
|
|
'jquery',
|
|
'jquery/ui',
|
|
'jquery/ui-modules/widgets/tabs'
|
|
], function ($) {
|
|
'use strict';
|
|
|
|
var rhash, isLocal;
|
|
|
|
// mage.tabs base functionality
|
|
$.widget('mage.tabs', $.ui.tabs, {
|
|
options: {
|
|
spinner: false,
|
|
groups: null,
|
|
tabPanelClass: '',
|
|
excludedPanel: ''
|
|
},
|
|
|
|
/**
|
|
* Tabs creation
|
|
* @protected
|
|
*/
|
|
_create: function () {
|
|
var activeIndex = this._getTabIndex(this.options.active);
|
|
|
|
this.options.active = activeIndex >= 0 ? activeIndex : 0;
|
|
this._super();
|
|
},
|
|
|
|
/**
|
|
* @override
|
|
* @private
|
|
* @return {Array} Array of DOM-elements
|
|
*/
|
|
_getList: function () {
|
|
if (this.options.groups) {
|
|
return this.element.find(this.options.groups);
|
|
}
|
|
|
|
return this._super();
|
|
},
|
|
|
|
/**
|
|
* Get active anchor
|
|
* @return {Element}
|
|
*/
|
|
activeAnchor: function () {
|
|
return this.anchors.eq(this.option('active'));
|
|
},
|
|
|
|
/**
|
|
* Get tab index by tab id
|
|
* @protected
|
|
* @param {String} id - id of tab
|
|
* @return {Number}
|
|
*/
|
|
_getTabIndex: function (id) {
|
|
var anchors = this.anchors ?
|
|
this.anchors :
|
|
this._getList().find('> li > a[href]');
|
|
|
|
return anchors.index($('#' + id));
|
|
},
|
|
|
|
/**
|
|
* Switch between tabs
|
|
* @protected
|
|
* @param {Object} event - event object
|
|
* @param {undefined|Object} eventData
|
|
*/
|
|
_toggle: function (event, eventData) {
|
|
var anchor = $(eventData.newTab).find('a');
|
|
|
|
if ($(eventData.newTab).find('a').data().tabType === 'link') {
|
|
location.href = anchor.prop('href');
|
|
} else {
|
|
this._superApply(arguments);
|
|
}
|
|
}
|
|
});
|
|
|
|
rhash = /#.*$/;
|
|
|
|
/**
|
|
* @param {*} anchor
|
|
* @return {Boolean}
|
|
*/
|
|
isLocal = function (anchor) {
|
|
return anchor.hash.length > 1 &&
|
|
anchor.href.replace(rhash, '') ===
|
|
location.href.replace(rhash, '')
|
|
// support: Safari 5.1
|
|
// Safari 5.1 doesn't encode spaces in window.location
|
|
// but it does encode spaces from anchors (#8777)
|
|
.replace(/\s/g, '%20');
|
|
};
|
|
|
|
// Extension for mage.tabs - Move panels in destination element
|
|
$.widget('mage.tabs', $.mage.tabs, {
|
|
/**
|
|
* Move panels in destination element on creation
|
|
* @protected
|
|
* @override
|
|
*/
|
|
_create: function () {
|
|
this._super();
|
|
this._movePanelsInDestination(this.panels);
|
|
},
|
|
|
|
/**
|
|
* Get panel for tab. If panel no exist in tabs container, then find panel in destination element
|
|
* @protected
|
|
* @override
|
|
* @param {Element} tab - tab "li" DOM-element
|
|
* @return {Element}
|
|
*/
|
|
_getPanelForTab: function (tab) {
|
|
var panel = this._superApply(arguments),
|
|
id;
|
|
|
|
if (!panel.length) {
|
|
id = $(tab).attr('aria-controls');
|
|
panel = $(this.options.destination).find(this._sanitizeSelector('#' + id));
|
|
}
|
|
|
|
return panel;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
_processTabs: function () {
|
|
var that = this;
|
|
|
|
this.tablist = this._getList()
|
|
.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all')
|
|
.attr('role', 'tablist');
|
|
|
|
this.tabs = this.tablist.find('> li:has(a[href])')
|
|
.addClass('ui-state-default ui-corner-top')
|
|
.attr({
|
|
role: 'tab',
|
|
tabIndex: -1
|
|
});
|
|
|
|
this.anchors = this.tabs.map(function () {
|
|
return $('a', this)[ 0 ];
|
|
})
|
|
.addClass('ui-tabs-anchor')
|
|
.attr({
|
|
role: 'presentation',
|
|
tabIndex: -1
|
|
});
|
|
|
|
this.panels = $();
|
|
|
|
this.anchors.each(function (i, anchor) {
|
|
var selector, panel, panelId,
|
|
anchorId = $(anchor).uniqueId().attr('id'),
|
|
tab = $(anchor).closest('li'),
|
|
originalAriaControls = tab.attr('aria-controls');
|
|
|
|
// inline tab
|
|
if (isLocal(anchor)) {
|
|
selector = anchor.hash;
|
|
panel = that.document.find(that._sanitizeSelector(selector));
|
|
// remote tab
|
|
} else {
|
|
panelId = tab.attr('aria-controls') || $({}).uniqueId()[ 0 ].id;
|
|
selector = '#' + panelId;
|
|
panel = that.element.find(selector);
|
|
|
|
if (!panel.length) {
|
|
panel = that._createPanel(panelId);
|
|
panel.insertAfter(that.panels[ i - 1 ] || that.tablist);
|
|
}
|
|
panel.attr('aria-live', 'polite');
|
|
}
|
|
|
|
if (panel.length) {
|
|
that.panels = that.panels.add(panel);
|
|
}
|
|
|
|
if (originalAriaControls) {
|
|
tab.data('ui-tabs-aria-controls', originalAriaControls);
|
|
}
|
|
tab.attr({
|
|
'aria-controls': selector.substring(1),
|
|
'aria-labelledby': anchorId
|
|
});
|
|
panel.attr('aria-labelledby', anchorId);
|
|
|
|
if (that.options.excludedPanel.indexOf(anchorId + '_content') < 0) {
|
|
panel.addClass(that.options.tabPanelClass);
|
|
}
|
|
});
|
|
|
|
this.panels
|
|
.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
|
|
.attr('role', 'tabpanel');
|
|
},
|
|
|
|
/**
|
|
* Move panels in destination element
|
|
* @protected
|
|
* @override
|
|
*/
|
|
_movePanelsInDestination: function (panels) {
|
|
if (this.options.destination && !panels.parents(this.options.destination).length) {
|
|
this.element.trigger('beforePanelsMove', panels);
|
|
|
|
panels.find('script:not([type]), script[type="text/javascript"]').remove();
|
|
|
|
panels.appendTo(this.options.destination)
|
|
.each($.proxy(function (i, panel) {
|
|
$(panel).trigger('move.tabs', this.anchors.eq(i));
|
|
}, this));
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Move panels in destination element on tabs switching
|
|
* @protected
|
|
* @override
|
|
* @param {Object} event - event object
|
|
* @param {Object} eventData
|
|
*/
|
|
_toggle: function (event, eventData) {
|
|
this._movePanelsInDestination(eventData.newPanel);
|
|
this._superApply(arguments);
|
|
}
|
|
});
|
|
|
|
// Extension for mage.tabs - Ajax functionality for tabs
|
|
$.widget('mage.tabs', $.mage.tabs, {
|
|
options: {
|
|
/**
|
|
* Add form key to ajax call
|
|
* @param {Object} event - event object
|
|
* @param {Object} ui
|
|
*/
|
|
beforeLoad: function (event, ui) {
|
|
ui.ajaxSettings.type = 'POST';
|
|
ui.ajaxSettings.hasContent = true;
|
|
ui.jqXHR.setRequestHeader('Content-Type', ui.ajaxSettings.contentType);
|
|
ui.ajaxSettings.data = jQuery.param(
|
|
{
|
|
isAjax: true,
|
|
'form_key': typeof FORM_KEY !== 'undefined' ? FORM_KEY : null
|
|
},
|
|
ui.ajaxSettings.traditional
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Replacing href attribute with loaded panel id
|
|
* @param {Object} event - event object
|
|
* @param {Object} ui
|
|
*/
|
|
load: function (event, ui) {
|
|
var panel = $(ui.panel);
|
|
|
|
$(ui.tab).prop('href', '#' + panel.prop('id'));
|
|
panel.trigger('contentUpdated');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Extension for mage.tabs - Attach event handlers to tabs
|
|
$.widget('mage.tabs', $.mage.tabs, {
|
|
options: {
|
|
tabIdArgument: 'tab',
|
|
tabsBlockPrefix: null
|
|
},
|
|
|
|
/**
|
|
* Attach event handlers to tabs, on creation
|
|
* @protected
|
|
* @override
|
|
*/
|
|
_refresh: function () {
|
|
this._super();
|
|
$.each(this.tabs, $.proxy(function (i, tab) {
|
|
$(this._getPanelForTab(tab))
|
|
.off('changed' + this.eventNamespace)
|
|
.off('highlight.validate' + this.eventNamespace)
|
|
.off('focusin' + this.eventNamespace)
|
|
|
|
.on('changed' + this.eventNamespace, {
|
|
index: i
|
|
}, $.proxy(this._onContentChange, this))
|
|
.on('highlight.validate' + this.eventNamespace, {
|
|
index: i
|
|
}, $.proxy(this._onInvalid, this))
|
|
.on('focusin' + this.eventNamespace, {
|
|
index: i
|
|
}, $.proxy(this._onFocus, this));
|
|
}, this));
|
|
|
|
($(this.options.destination).is('form') ?
|
|
$(this.options.destination) :
|
|
$(this.options.destination).closest('form'))
|
|
.off('beforeSubmit' + this.eventNamespace)
|
|
.on('beforeSubmit' + this.eventNamespace, $.proxy(this._onBeforeSubmit, this));
|
|
},
|
|
|
|
/**
|
|
* Mark tab as changed if some field inside tab panel is changed
|
|
* @protected
|
|
* @param {Object} e - event object
|
|
*/
|
|
_onContentChange: function (e) {
|
|
var cssChanged = '_changed';
|
|
|
|
this.anchors.eq(e.data.index).addClass(cssChanged);
|
|
this._updateNavTitleMessages(e, cssChanged);
|
|
},
|
|
|
|
/**
|
|
* Clone messages (tooltips) from anchor to parent element
|
|
* @protected
|
|
* @param {Object} e - event object
|
|
* @param {String} messageType - changed or error
|
|
*/
|
|
_updateNavTitleMessages: function (e, messageType) {
|
|
var curAnchor = this.anchors.eq(e.data.index),
|
|
curItem = curAnchor.parents('[data-role="container"]').find('[data-role="title"]'),
|
|
curItemMessages = curItem.find('[data-role="title-messages"]'),
|
|
activeClass = '_active';
|
|
|
|
if (curItemMessages.is(':empty')) {
|
|
curAnchor
|
|
.find('[data-role="item-messages"]')
|
|
.clone()
|
|
.appendTo(curItemMessages);
|
|
}
|
|
|
|
curItemMessages.find('.' + messageType).addClass(activeClass);
|
|
},
|
|
|
|
/**
|
|
* Mark tab as error if some field inside tab panel is not passed validation
|
|
* @param {Object} e - event object
|
|
* @protected
|
|
*/
|
|
_onInvalid: function (e) {
|
|
var cssError = '_error',
|
|
fakeEvent = e;
|
|
|
|
fakeEvent.currentTarget = $(this.anchors).eq(e.data.index);
|
|
this._eventHandler(fakeEvent);
|
|
this.anchors.eq(e.data.index).addClass(cssError).find('.' + cssError).show();
|
|
this._updateNavTitleMessages(e, cssError);
|
|
},
|
|
|
|
/**
|
|
* Show tab panel if focus event triggered of some field inside tab panel
|
|
* @param {Object} e - event object
|
|
* @protected
|
|
*/
|
|
_onFocus: function (e) {
|
|
this.option('_active', e.data.index);
|
|
},
|
|
|
|
/**
|
|
* Add active tab id in data object when "beforeSubmit" event is triggered
|
|
* @param {Object} e - event object
|
|
* @param {Object} data - event data object
|
|
* @protected
|
|
*/
|
|
_onBeforeSubmit: function (e, data) { //eslint-disable-line no-unused-vars
|
|
var activeAnchor = this.activeAnchor(),
|
|
activeTabId = activeAnchor.prop('id'),
|
|
options;
|
|
|
|
if (this.options.tabsBlockPrefix) {
|
|
if (activeAnchor.is('[id*="' + this.options.tabsBlockPrefix + '"]')) {
|
|
activeTabId = activeAnchor.prop('id').substr(this.options.tabsBlockPrefix.length);
|
|
}
|
|
}
|
|
$(this.anchors).removeClass('error');
|
|
options = {
|
|
action: {
|
|
args: {}
|
|
}
|
|
};
|
|
options.action.args[this.options.tabIdArgument] = activeTabId;
|
|
}
|
|
});
|
|
|
|
// Extension for mage.tabs - Shadow tabs functionality
|
|
$.widget('mage.tabs', $.mage.tabs, {
|
|
/**
|
|
* Add shadow tabs functionality on creation
|
|
* @protected
|
|
* @override
|
|
*/
|
|
_refresh: function () {
|
|
var anchors, shadowTabs, tabs;
|
|
|
|
this._super();
|
|
anchors = this.anchors;
|
|
shadowTabs = this.options.shadowTabs;
|
|
tabs = this.tabs;
|
|
|
|
if (shadowTabs) {
|
|
anchors.each($.proxy(function (i, anchor) {
|
|
var anchorId = $(anchor).prop('id');
|
|
|
|
if (shadowTabs[anchorId]) {
|
|
$(anchor).parents('li').on('click', $.proxy(function () {
|
|
$.each(shadowTabs[anchorId], $.proxy(function (key, id) {
|
|
this.load($(tabs).index($('#' + id).parents('li')), {});
|
|
}, this));
|
|
}, this));
|
|
}
|
|
}, this));
|
|
}
|
|
}
|
|
});
|
|
|
|
return $.mage.tabs;
|
|
});
|