No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

540 líneas
18 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. /* global MediabrowserUtility, FORM_KEY, tinyMceEditors */
  6. /* eslint-disable strict */
  7. define([
  8. 'jquery',
  9. 'wysiwygAdapter',
  10. 'Magento_Ui/js/modal/prompt',
  11. 'Magento_Ui/js/modal/confirm',
  12. 'Magento_Ui/js/modal/alert',
  13. 'underscore',
  14. 'Magento_Ui/js/modal/modal',
  15. 'jquery/ui',
  16. 'jquery/jstree/jquery.jstree',
  17. 'mage/mage'
  18. ], function ($, wysiwyg, prompt, confirm, alert, _) {
  19. window.MediabrowserUtility = {
  20. windowId: 'modal_dialog_message',
  21. modalLoaded: false,
  22. targetElementId: false,
  23. pathId: '',
  24. /**
  25. * @return {Number}
  26. */
  27. getMaxZIndex: function () {
  28. var max = 0,
  29. cn = document.body.childNodes,
  30. i, el, zIndex;
  31. for (i = 0; i < cn.length; i++) {
  32. el = cn[i];
  33. zIndex = el.nodeType == 1 ? parseInt(el.style.zIndex, 10) || 0 : 0; //eslint-disable-line eqeqeq
  34. if (zIndex < 10000) {
  35. max = Math.max(max, zIndex);
  36. }
  37. }
  38. return max + 10;
  39. },
  40. /**
  41. * @param {*} url
  42. * @param {*} width
  43. * @param {*} height
  44. * @param {*} title
  45. * @param {Object} options
  46. */
  47. openDialog: function (url, width, height, title, options) {
  48. var windowId = this.windowId,
  49. content = '<div class="popup-window" id="' + windowId + '"></div>';
  50. if (this.modalLoaded) {
  51. if (!_.isUndefined(options)) {
  52. this.modal.modal('option', 'closed', options.closed);
  53. }
  54. this.modal.modal('openModal');
  55. this.setTargetElementId(options, url);
  56. this.setPathId(url);
  57. $(window).trigger('reload.MediaGallery');
  58. return;
  59. }
  60. this.modal = $(content).modal($.extend({
  61. title: title || 'Insert File...',
  62. modalClass: 'magento',
  63. type: 'slide',
  64. buttons: []
  65. }, options));
  66. this.modal.modal('openModal');
  67. $.ajax({
  68. url: url,
  69. type: 'get',
  70. context: $(this),
  71. showLoader: true
  72. }).done(function (data) {
  73. this.modal.html(data).trigger('contentUpdated');
  74. this.modalLoaded = true;
  75. this.setTargetElementId(options, url);
  76. this.setPathId(url);
  77. }.bind(this));
  78. },
  79. /**
  80. * Setter for endcoded path id
  81. */
  82. setPathId: function (url) {
  83. this.pathId = url.match(/(&|\/|%26)current_tree_path(=|\/)([\s\S].*?)(\/|$)/)[3];
  84. },
  85. /**
  86. * Setter for targetElementId property
  87. *
  88. * @param {Object} options
  89. * @param {String} url
  90. */
  91. setTargetElementId: function (options, url) {
  92. this.targetElementId = options && options.targetElementId ?
  93. options.targetElementId
  94. : url.match(/\/target_element_id\/([\s\S].*?)\//)[1];
  95. },
  96. /**
  97. * Close dialog.
  98. */
  99. closeDialog: function () {
  100. this.modal.modal('closeModal');
  101. }
  102. };
  103. $.widget('mage.mediabrowser', {
  104. eventPrefix: 'mediabrowser',
  105. options: {
  106. contentsUrl: null,
  107. onInsertUrl: null,
  108. newFolderUrl: null,
  109. deleteFolderUrl: null,
  110. deleteFilesUrl: null,
  111. headerText: null,
  112. tree: null,
  113. currentNode: null,
  114. storeId: null,
  115. showBreadcrumbs: null,
  116. hidden: 'no-display'
  117. },
  118. /**
  119. * Proxy creation
  120. * @protected
  121. */
  122. _create: function () {
  123. this._on({
  124. 'click [data-row=file]': 'selectFile',
  125. 'dblclick [data-row=file]': 'insert',
  126. 'click #new_folder': 'newFolder',
  127. 'click #delete_folder': 'deleteFolder',
  128. 'click #delete_files': 'deleteFiles',
  129. 'click #insert_files': 'insertSelectedFiles',
  130. 'fileuploaddone': '_uploadDone',
  131. 'click [data-row=breadcrumb]': 'selectFolder'
  132. });
  133. $(window).on('reload.MediaGallery', $.proxy(this.reload, this));
  134. this.activeNode = null;
  135. //tree dont use event bubbling
  136. this.tree = this.element.find('[data-role=tree]');
  137. this.tree.on('select_node.jstree', $.proxy(this._selectNode, this));
  138. },
  139. /**
  140. * @param {jQuery.Event} event
  141. * @param {Object} data
  142. * @private
  143. */
  144. _selectNode: function (event, data) {
  145. var node = data.node;
  146. this.activeNode = node;
  147. this.element.find('#delete_files, #insert_files').toggleClass(this.options.hidden, true);
  148. this.element.find('#contents').toggleClass(this.options.hidden, false);
  149. this.element.find('#delete_folder')
  150. .toggleClass(this.options.hidden, node.id === 'root'); //eslint-disable-line eqeqeq
  151. this.element.find('#content_header_text')
  152. .html(node.id === 'root' ? this.headerText : node.text); //eslint-disable-line eqeqeq
  153. this.drawBreadcrumbs(data);
  154. this.loadFileList(node);
  155. },
  156. /**
  157. * @return {*}
  158. */
  159. reload: function (uploaded) {
  160. return this.loadFileList(this.activeNode, uploaded);
  161. },
  162. /**
  163. * @param {Object} element
  164. * @param {*} value
  165. */
  166. insertAtCursor: function (element, value) {
  167. var sel, startPos, endPos, scrollTop;
  168. if ('selection' in document) {
  169. //For browsers like Internet Explorer
  170. element.focus();
  171. sel = document.selection.createRange();
  172. sel.text = value;
  173. element.focus();
  174. } else if (element.selectionStart || element.selectionStart == '0') { //eslint-disable-line eqeqeq
  175. //For browsers like Firefox and Webkit based
  176. startPos = element.selectionStart;
  177. endPos = element.selectionEnd;
  178. scrollTop = element.scrollTop;
  179. element.value = element.value.substring(0, startPos) + value +
  180. element.value.substring(startPos, endPos) + element.value.substring(endPos, element.value.length);
  181. element.focus();
  182. element.selectionStart = startPos + value.length;
  183. element.selectionEnd = startPos + value.length + element.value.substring(startPos, endPos).length;
  184. element.scrollTop = scrollTop;
  185. } else {
  186. element.value += value;
  187. element.focus();
  188. }
  189. },
  190. /**
  191. * @param {Object} node
  192. */
  193. loadFileList: function (node, uploaded) {
  194. var contentBlock = this.element.find('#contents');
  195. return $.ajax({
  196. url: this.options.contentsUrl,
  197. type: 'GET',
  198. dataType: 'html',
  199. data: {
  200. 'form_key': FORM_KEY,
  201. node: node ? node.id : null
  202. },
  203. context: contentBlock,
  204. showLoader: true
  205. }).done(function (data) {
  206. contentBlock.html(data).trigger('contentUpdated');
  207. if (uploaded) {
  208. contentBlock.find('.filecnt:last').trigger('click');
  209. }
  210. });
  211. },
  212. /**
  213. * @param {jQuery.Event} event
  214. */
  215. selectFolder: function (event) {
  216. this.element.find('[data-id="' + $(event.currentTarget).data('node').id + '"]>a').trigger('click');
  217. },
  218. /**
  219. * Insert selected files.
  220. */
  221. insertSelectedFiles: function () {
  222. this.element.find('[data-row=file].selected').trigger('dblclick');
  223. },
  224. /**
  225. * @param {jQuery.Event} event
  226. */
  227. selectFile: function (event) {
  228. var fileRow = $(event.currentTarget);
  229. fileRow.toggleClass('selected');
  230. this.element.find('[data-row=file]').not(fileRow).removeClass('selected');
  231. this.element.find('#delete_files, #insert_files')
  232. .toggleClass(this.options.hidden, !fileRow.is('.selected'));
  233. fileRow.trigger('selectfile');
  234. },
  235. /**
  236. * @private
  237. */
  238. _uploadDone: function () {
  239. this.element.find('.file-row').remove();
  240. this.reload(true);
  241. },
  242. /**
  243. * @param {jQuery.Event} event
  244. * @return {Boolean}
  245. */
  246. insert: function (event) {
  247. var fileRow = $(event.currentTarget),
  248. targetEl;
  249. if (!fileRow.prop('id')) {
  250. return false;
  251. }
  252. targetEl = this.getTargetElement();
  253. if (!targetEl.length) {
  254. MediabrowserUtility.closeDialog();
  255. throw 'Target element not found for content update';
  256. }
  257. return $.ajax({
  258. url: this.options.onInsertUrl,
  259. data: {
  260. filename: fileRow.attr('id'),
  261. node: this.activeNode.id,
  262. store: this.options.storeId,
  263. 'as_is': typeof targetEl !== 'function' && targetEl.is('textarea') ? 1 : 0,
  264. 'force_static_path': typeof targetEl !== 'function' && targetEl.data('force_static_path') ? 1 : 0,
  265. 'form_key': FORM_KEY
  266. },
  267. context: this,
  268. showLoader: true
  269. }).done($.proxy(function (data) {
  270. if (typeof targetEl === 'function') {
  271. targetEl(data, {text: fileRow.find('img').attr('alt')});
  272. } else if (targetEl.is('textarea')) {
  273. this.insertAtCursor(targetEl.get(0), data);
  274. } else {
  275. targetEl
  276. .val(data)
  277. .data('size', fileRow.data('size'))
  278. .data('mime-type', fileRow.data('mime-type'));
  279. }
  280. MediabrowserUtility.closeDialog();
  281. if (typeof targetEl !== 'function') {
  282. targetEl.focus();
  283. jQuery(targetEl).trigger('change');
  284. }
  285. }, this));
  286. },
  287. /**
  288. * Find document target element in next order:
  289. * in acive file browser opener:
  290. * - input field with ID: "src" in opener window
  291. * - input field with ID: "href" in opener window
  292. * in document:
  293. * - element with target ID
  294. *
  295. * return {HTMLElement|null}
  296. */
  297. getTargetElement: function () {
  298. var mediaBrowser = window.MediabrowserUtility;
  299. if (!_.isUndefined(wysiwyg) && wysiwyg.get(mediaBrowser.targetElementId)) {
  300. return this.getMediaBrowserOpener() || window;
  301. }
  302. return $('#' + mediaBrowser.targetElementId);
  303. },
  304. /**
  305. * Return opener Window object if it exists, not closed and editor is active
  306. *
  307. * return {Object|null}
  308. */
  309. getMediaBrowserOpener: function () {
  310. var targetElementId = window.MediabrowserUtility.targetElementId;
  311. if (!_.isUndefined(wysiwyg) && wysiwyg.get(targetElementId) && !_.isUndefined(tinyMceEditors)) {
  312. return tinyMceEditors.get(targetElementId).getMediaBrowserOpener();
  313. }
  314. return null;
  315. },
  316. /**
  317. * New folder.
  318. */
  319. newFolder: function () {
  320. var self = this;
  321. prompt({
  322. title: this.options.newFolderPrompt,
  323. actions: {
  324. /**
  325. * @param {*} folderName
  326. */
  327. confirm: function (folderName) {
  328. $.ajax({
  329. url: self.options.newFolderUrl,
  330. dataType: 'json',
  331. data: {
  332. name: folderName,
  333. node: self.activeNode.id,
  334. store: self.options.storeId,
  335. 'form_key': FORM_KEY
  336. },
  337. context: self.element,
  338. showLoader: true
  339. }).done($.proxy(function (data) {
  340. if (data.error) {
  341. alert({
  342. content: data.message
  343. });
  344. } else {
  345. self.tree.jstree(
  346. 'refresh_node',
  347. self.element.find('[data-id="' + self.activeNode.id + '"]')
  348. );
  349. }
  350. }, this));
  351. return true;
  352. }
  353. }
  354. });
  355. },
  356. /**
  357. * Delete folder.
  358. */
  359. deleteFolder: function () {
  360. var self = this;
  361. confirm({
  362. content: this.options.deleteFolderConfirmationMessage,
  363. actions: {
  364. /**
  365. * Confirm.
  366. */
  367. confirm: function () {
  368. return $.ajax({
  369. url: self.options.deleteFolderUrl,
  370. dataType: 'json',
  371. data: {
  372. node: self.activeNode.id,
  373. store: self.options.storeId,
  374. 'form_key': FORM_KEY
  375. },
  376. context: self.element,
  377. showLoader: true
  378. }).done($.proxy(function (data) {
  379. if (data.error) {
  380. alert({
  381. content: data.message
  382. });
  383. } else {
  384. self.tree.jstree('refresh', self.activeNode.id);
  385. self.reload();
  386. $(window).trigger('fileDeleted.mediabrowser', {
  387. ids: self.activeNode.id
  388. });
  389. }
  390. }, this));
  391. },
  392. /**
  393. * @return {Boolean}
  394. */
  395. cancel: function () {
  396. return false;
  397. }
  398. }
  399. });
  400. },
  401. /**
  402. * Delete files.
  403. */
  404. deleteFiles: function () {
  405. var self = this;
  406. confirm({
  407. content: this.options.deleteFileConfirmationMessage,
  408. actions: {
  409. /**
  410. * Confirm.
  411. */
  412. confirm: function () {
  413. var selectedFiles = self.element.find('[data-row=file].selected'),
  414. ids = selectedFiles.map(function () {
  415. return $(this).attr('id');
  416. }).toArray();
  417. return $.ajax({
  418. url: self.options.deleteFilesUrl,
  419. data: {
  420. files: ids,
  421. store: self.options.storeId,
  422. 'form_key': FORM_KEY
  423. },
  424. context: self.element,
  425. showLoader: true
  426. }).done($.proxy(function (data) {
  427. if (data.error) {
  428. alert({
  429. content: data.message
  430. });
  431. } else {
  432. self.reload();
  433. self.element.find('#delete_files, #insert_files').toggleClass(
  434. self.options.hidden, true
  435. );
  436. $(window).trigger('fileDeleted.mediabrowser', {
  437. ids: ids
  438. });
  439. }
  440. }, this));
  441. },
  442. /**
  443. * @return {Boolean}
  444. */
  445. cancel: function () {
  446. return false;
  447. }
  448. }
  449. });
  450. },
  451. /**
  452. * @param {Object} data
  453. */
  454. drawBreadcrumbs: function (data) {
  455. var node, breadcrumbs;
  456. if (this.element.find('#breadcrumbs').length) {
  457. this.element.find('#breadcrumbs').remove();
  458. }
  459. node = data.node;
  460. if (node.id === 'root') { //eslint-disable-line eqeqeq
  461. return;
  462. }
  463. breadcrumbs = $('<ul class="breadcrumbs" id="breadcrumbs"></ul>');
  464. // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
  465. data.instance.get_path(node).each(function (name, index) {
  466. if (index > 0) {
  467. breadcrumbs.append($('<li>\/</li>')); //eslint-disable-line
  468. }
  469. breadcrumbs.append($('<li />').attr('data-row', 'breadcrumb').text(name));
  470. });
  471. // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
  472. breadcrumbs.insertAfter(this.element.find('#content_header'));
  473. }
  474. });
  475. return window.MediabrowserUtility;
  476. });