Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

430 строки
14 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. /* global FORM_KEY */
  6. define([
  7. 'jquery',
  8. 'jquery/ui',
  9. 'jquery/ui-modules/widgets/tabs'
  10. ], function ($) {
  11. 'use strict';
  12. var rhash, isLocal;
  13. // mage.tabs base functionality
  14. $.widget('mage.tabs', $.ui.tabs, {
  15. options: {
  16. spinner: false,
  17. groups: null,
  18. tabPanelClass: '',
  19. excludedPanel: ''
  20. },
  21. /**
  22. * Tabs creation
  23. * @protected
  24. */
  25. _create: function () {
  26. var activeIndex = this._getTabIndex(this.options.active);
  27. this.options.active = activeIndex >= 0 ? activeIndex : 0;
  28. this._super();
  29. },
  30. /**
  31. * @override
  32. * @private
  33. * @return {Array} Array of DOM-elements
  34. */
  35. _getList: function () {
  36. if (this.options.groups) {
  37. return this.element.find(this.options.groups);
  38. }
  39. return this._super();
  40. },
  41. /**
  42. * Get active anchor
  43. * @return {Element}
  44. */
  45. activeAnchor: function () {
  46. return this.anchors.eq(this.option('active'));
  47. },
  48. /**
  49. * Get tab index by tab id
  50. * @protected
  51. * @param {String} id - id of tab
  52. * @return {Number}
  53. */
  54. _getTabIndex: function (id) {
  55. var anchors = this.anchors ?
  56. this.anchors :
  57. this._getList().find('> li > a[href]');
  58. return anchors.index($('#' + id));
  59. },
  60. /**
  61. * Switch between tabs
  62. * @protected
  63. * @param {Object} event - event object
  64. * @param {undefined|Object} eventData
  65. */
  66. _toggle: function (event, eventData) {
  67. var anchor = $(eventData.newTab).find('a');
  68. if ($(eventData.newTab).find('a').data().tabType === 'link') {
  69. location.href = anchor.prop('href');
  70. } else {
  71. this._superApply(arguments);
  72. }
  73. }
  74. });
  75. rhash = /#.*$/;
  76. /**
  77. * @param {*} anchor
  78. * @return {Boolean}
  79. */
  80. isLocal = function (anchor) {
  81. return anchor.hash.length > 1 &&
  82. anchor.href.replace(rhash, '') ===
  83. location.href.replace(rhash, '')
  84. // support: Safari 5.1
  85. // Safari 5.1 doesn't encode spaces in window.location
  86. // but it does encode spaces from anchors (#8777)
  87. .replace(/\s/g, '%20');
  88. };
  89. // Extension for mage.tabs - Move panels in destination element
  90. $.widget('mage.tabs', $.mage.tabs, {
  91. /**
  92. * Move panels in destination element on creation
  93. * @protected
  94. * @override
  95. */
  96. _create: function () {
  97. this._super();
  98. this._movePanelsInDestination(this.panels);
  99. },
  100. /**
  101. * Get panel for tab. If panel no exist in tabs container, then find panel in destination element
  102. * @protected
  103. * @override
  104. * @param {Element} tab - tab "li" DOM-element
  105. * @return {Element}
  106. */
  107. _getPanelForTab: function (tab) {
  108. var panel = this._superApply(arguments),
  109. id;
  110. if (!panel.length) {
  111. id = $(tab).attr('aria-controls');
  112. panel = $(this.options.destination).find(this._sanitizeSelector('#' + id));
  113. }
  114. return panel;
  115. },
  116. /**
  117. * @private
  118. */
  119. _processTabs: function () {
  120. var that = this;
  121. this.tablist = this._getList()
  122. .addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all')
  123. .attr('role', 'tablist');
  124. this.tabs = this.tablist.find('> li:has(a[href])')
  125. .addClass('ui-state-default ui-corner-top')
  126. .attr({
  127. role: 'tab',
  128. tabIndex: -1
  129. });
  130. this.anchors = this.tabs.map(function () {
  131. return $('a', this)[ 0 ];
  132. })
  133. .addClass('ui-tabs-anchor')
  134. .attr({
  135. role: 'presentation',
  136. tabIndex: -1
  137. });
  138. this.panels = $();
  139. this.anchors.each(function (i, anchor) {
  140. var selector, panel, panelId,
  141. anchorId = $(anchor).uniqueId().attr('id'),
  142. tab = $(anchor).closest('li'),
  143. originalAriaControls = tab.attr('aria-controls');
  144. // inline tab
  145. if (isLocal(anchor)) {
  146. selector = anchor.hash;
  147. panel = that.document.find(that._sanitizeSelector(selector));
  148. // remote tab
  149. } else {
  150. panelId = tab.attr('aria-controls') || $({}).uniqueId()[ 0 ].id;
  151. selector = '#' + panelId;
  152. panel = that.element.find(selector);
  153. if (!panel.length) {
  154. panel = that._createPanel(panelId);
  155. panel.insertAfter(that.panels[ i - 1 ] || that.tablist);
  156. }
  157. panel.attr('aria-live', 'polite');
  158. }
  159. if (panel.length) {
  160. that.panels = that.panels.add(panel);
  161. }
  162. if (originalAriaControls) {
  163. tab.data('ui-tabs-aria-controls', originalAriaControls);
  164. }
  165. tab.attr({
  166. 'aria-controls': selector.substring(1),
  167. 'aria-labelledby': anchorId
  168. });
  169. panel.attr('aria-labelledby', anchorId);
  170. if (that.options.excludedPanel.indexOf(anchorId + '_content') < 0) {
  171. panel.addClass(that.options.tabPanelClass);
  172. }
  173. });
  174. this.panels
  175. .addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
  176. .attr('role', 'tabpanel');
  177. },
  178. /**
  179. * Move panels in destination element
  180. * @protected
  181. * @override
  182. */
  183. _movePanelsInDestination: function (panels) {
  184. if (this.options.destination && !panels.parents(this.options.destination).length) {
  185. this.element.trigger('beforePanelsMove', panels);
  186. panels.find('script:not([type]), script[type="text/javascript"]').remove();
  187. panels.appendTo(this.options.destination)
  188. .each($.proxy(function (i, panel) {
  189. $(panel).trigger('move.tabs', this.anchors.eq(i));
  190. }, this));
  191. }
  192. },
  193. /**
  194. * Move panels in destination element on tabs switching
  195. * @protected
  196. * @override
  197. * @param {Object} event - event object
  198. * @param {Object} eventData
  199. */
  200. _toggle: function (event, eventData) {
  201. this._movePanelsInDestination(eventData.newPanel);
  202. this._superApply(arguments);
  203. }
  204. });
  205. // Extension for mage.tabs - Ajax functionality for tabs
  206. $.widget('mage.tabs', $.mage.tabs, {
  207. options: {
  208. /**
  209. * Add form key to ajax call
  210. * @param {Object} event - event object
  211. * @param {Object} ui
  212. */
  213. beforeLoad: function (event, ui) {
  214. ui.ajaxSettings.type = 'POST';
  215. ui.ajaxSettings.hasContent = true;
  216. ui.jqXHR.setRequestHeader('Content-Type', ui.ajaxSettings.contentType);
  217. ui.ajaxSettings.data = jQuery.param(
  218. {
  219. isAjax: true,
  220. 'form_key': typeof FORM_KEY !== 'undefined' ? FORM_KEY : null
  221. },
  222. ui.ajaxSettings.traditional
  223. );
  224. },
  225. /**
  226. * Replacing href attribute with loaded panel id
  227. * @param {Object} event - event object
  228. * @param {Object} ui
  229. */
  230. load: function (event, ui) {
  231. var panel = $(ui.panel);
  232. $(ui.tab).prop('href', '#' + panel.prop('id'));
  233. panel.trigger('contentUpdated');
  234. }
  235. }
  236. });
  237. // Extension for mage.tabs - Attach event handlers to tabs
  238. $.widget('mage.tabs', $.mage.tabs, {
  239. options: {
  240. tabIdArgument: 'tab',
  241. tabsBlockPrefix: null
  242. },
  243. /**
  244. * Attach event handlers to tabs, on creation
  245. * @protected
  246. * @override
  247. */
  248. _refresh: function () {
  249. this._super();
  250. $.each(this.tabs, $.proxy(function (i, tab) {
  251. $(this._getPanelForTab(tab))
  252. .off('changed' + this.eventNamespace)
  253. .off('highlight.validate' + this.eventNamespace)
  254. .off('focusin' + this.eventNamespace)
  255. .on('changed' + this.eventNamespace, {
  256. index: i
  257. }, $.proxy(this._onContentChange, this))
  258. .on('highlight.validate' + this.eventNamespace, {
  259. index: i
  260. }, $.proxy(this._onInvalid, this))
  261. .on('focusin' + this.eventNamespace, {
  262. index: i
  263. }, $.proxy(this._onFocus, this));
  264. }, this));
  265. ($(this.options.destination).is('form') ?
  266. $(this.options.destination) :
  267. $(this.options.destination).closest('form'))
  268. .off('beforeSubmit' + this.eventNamespace)
  269. .on('beforeSubmit' + this.eventNamespace, $.proxy(this._onBeforeSubmit, this));
  270. },
  271. /**
  272. * Mark tab as changed if some field inside tab panel is changed
  273. * @protected
  274. * @param {Object} e - event object
  275. */
  276. _onContentChange: function (e) {
  277. var cssChanged = '_changed';
  278. this.anchors.eq(e.data.index).addClass(cssChanged);
  279. this._updateNavTitleMessages(e, cssChanged);
  280. },
  281. /**
  282. * Clone messages (tooltips) from anchor to parent element
  283. * @protected
  284. * @param {Object} e - event object
  285. * @param {String} messageType - changed or error
  286. */
  287. _updateNavTitleMessages: function (e, messageType) {
  288. var curAnchor = this.anchors.eq(e.data.index),
  289. curItem = curAnchor.parents('[data-role="container"]').find('[data-role="title"]'),
  290. curItemMessages = curItem.find('[data-role="title-messages"]'),
  291. activeClass = '_active';
  292. if (curItemMessages.is(':empty')) {
  293. curAnchor
  294. .find('[data-role="item-messages"]')
  295. .clone()
  296. .appendTo(curItemMessages);
  297. }
  298. curItemMessages.find('.' + messageType).addClass(activeClass);
  299. },
  300. /**
  301. * Mark tab as error if some field inside tab panel is not passed validation
  302. * @param {Object} e - event object
  303. * @protected
  304. */
  305. _onInvalid: function (e) {
  306. var cssError = '_error',
  307. fakeEvent = e;
  308. fakeEvent.currentTarget = $(this.anchors).eq(e.data.index);
  309. this._eventHandler(fakeEvent);
  310. this.anchors.eq(e.data.index).addClass(cssError).find('.' + cssError).show();
  311. this._updateNavTitleMessages(e, cssError);
  312. },
  313. /**
  314. * Show tab panel if focus event triggered of some field inside tab panel
  315. * @param {Object} e - event object
  316. * @protected
  317. */
  318. _onFocus: function (e) {
  319. this.option('_active', e.data.index);
  320. },
  321. /**
  322. * Add active tab id in data object when "beforeSubmit" event is triggered
  323. * @param {Object} e - event object
  324. * @param {Object} data - event data object
  325. * @protected
  326. */
  327. _onBeforeSubmit: function (e, data) { //eslint-disable-line no-unused-vars
  328. var activeAnchor = this.activeAnchor(),
  329. activeTabId = activeAnchor.prop('id'),
  330. options;
  331. if (this.options.tabsBlockPrefix) {
  332. if (activeAnchor.is('[id*="' + this.options.tabsBlockPrefix + '"]')) {
  333. activeTabId = activeAnchor.prop('id').substr(this.options.tabsBlockPrefix.length);
  334. }
  335. }
  336. $(this.anchors).removeClass('error');
  337. options = {
  338. action: {
  339. args: {}
  340. }
  341. };
  342. options.action.args[this.options.tabIdArgument] = activeTabId;
  343. }
  344. });
  345. // Extension for mage.tabs - Shadow tabs functionality
  346. $.widget('mage.tabs', $.mage.tabs, {
  347. /**
  348. * Add shadow tabs functionality on creation
  349. * @protected
  350. * @override
  351. */
  352. _refresh: function () {
  353. var anchors, shadowTabs, tabs;
  354. this._super();
  355. anchors = this.anchors;
  356. shadowTabs = this.options.shadowTabs;
  357. tabs = this.tabs;
  358. if (shadowTabs) {
  359. anchors.each($.proxy(function (i, anchor) {
  360. var anchorId = $(anchor).prop('id');
  361. if (shadowTabs[anchorId]) {
  362. $(anchor).parents('li').on('click', $.proxy(function () {
  363. $.each(shadowTabs[anchorId], $.proxy(function (key, id) {
  364. this.load($(tabs).index($('#' + id).parents('li')), {});
  365. }, this));
  366. }, this));
  367. }
  368. }, this));
  369. }
  370. }
  371. });
  372. return $.mage.tabs;
  373. });