PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/client/dist/js/HtmlEditorField.js

http://github.com/silverstripe/sapphire
JavaScript | 1219 lines | 1110 code | 109 blank | 0 comment | 37 complexity | 2e4e77c91b872acb6cd4dd4a62520787 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
  1. (function (global, factory) {
  2. if (typeof define === "function" && define.amd) {
  3. define('ss.HtmlEditorField', ['jQuery', 'i18n'], factory);
  4. } else if (typeof exports !== "undefined") {
  5. factory(require('jQuery'), require('i18n'));
  6. } else {
  7. var mod = {
  8. exports: {}
  9. };
  10. factory(global.jQuery, global.i18n);
  11. global.ssHtmlEditorField = mod.exports;
  12. }
  13. })(this, function (_jQuery, _i18n) {
  14. 'use strict';
  15. var _jQuery2 = _interopRequireDefault(_jQuery);
  16. var _i18n2 = _interopRequireDefault(_i18n);
  17. function _interopRequireDefault(obj) {
  18. return obj && obj.__esModule ? obj : {
  19. default: obj
  20. };
  21. }
  22. var ss = typeof window.ss !== 'undefined' ? window.ss : {};
  23. ss.editorWrappers = {};
  24. ss.editorWrappers.tinyMCE = function () {
  25. var editorID;
  26. return {
  27. init: function init(ID) {
  28. editorID = ID;
  29. this.create();
  30. },
  31. destroy: function destroy() {
  32. tinymce.EditorManager.execCommand('mceRemoveEditor', false, editorID);
  33. },
  34. getInstance: function getInstance() {
  35. return tinymce.EditorManager.get(editorID);
  36. },
  37. onopen: function onopen() {},
  38. onclose: function onclose() {},
  39. getConfig: function getConfig() {
  40. var selector = "#" + editorID,
  41. config = (0, _jQuery2.default)(selector).data('config'),
  42. self = this;
  43. config.selector = selector;
  44. config.setup = function (ed) {
  45. ed.on('change', function () {
  46. self.save();
  47. });
  48. };
  49. return config;
  50. },
  51. save: function save() {
  52. var instance = this.getInstance();
  53. instance.save();
  54. (0, _jQuery2.default)(instance.getElement()).trigger("change");
  55. },
  56. create: function create() {
  57. var config = this.getConfig();
  58. if (typeof config.baseURL !== 'undefined') {
  59. tinymce.EditorManager.baseURL = config.baseURL;
  60. }
  61. tinymce.init(config);
  62. },
  63. repaint: function repaint() {},
  64. isDirty: function isDirty() {
  65. return this.getInstance().isDirty();
  66. },
  67. getContent: function getContent() {
  68. return this.getInstance().getContent();
  69. },
  70. getDOM: function getDOM() {
  71. return this.getInstance().getElement();
  72. },
  73. getContainer: function getContainer() {
  74. return this.getInstance().getContainer();
  75. },
  76. getSelectedNode: function getSelectedNode() {
  77. return this.getInstance().selection.getNode();
  78. },
  79. selectNode: function selectNode(node) {
  80. this.getInstance().selection.select(node);
  81. },
  82. setContent: function setContent(html, opts) {
  83. this.getInstance().setContent(html, opts);
  84. },
  85. insertContent: function insertContent(html, opts) {
  86. this.getInstance().insertContent(html, opts);
  87. },
  88. replaceContent: function replaceContent(html, opts) {
  89. this.getInstance().execCommand('mceReplaceContent', false, html, opts);
  90. },
  91. insertLink: function insertLink(attrs, opts) {
  92. this.getInstance().execCommand("mceInsertLink", false, attrs, opts);
  93. },
  94. removeLink: function removeLink() {
  95. this.getInstance().execCommand('unlink', false);
  96. },
  97. cleanLink: function cleanLink(href, node) {
  98. var settings = this.getConfig,
  99. cb = settings['urlconverter_callback'];
  100. if (cb) href = eval(cb + "(href, node, true);");
  101. if (href.match(new RegExp('^' + tinyMCE.settings['document_base_url'] + '(.*)$'))) {
  102. href = RegExp.$1;
  103. }
  104. if (href.match(/^javascript:\s*mctmp/)) href = '';
  105. return href;
  106. },
  107. createBookmark: function createBookmark() {
  108. return this.getInstance().selection.getBookmark();
  109. },
  110. moveToBookmark: function moveToBookmark(bookmark) {
  111. this.getInstance().selection.moveToBookmark(bookmark);
  112. this.getInstance().focus();
  113. },
  114. blur: function blur() {
  115. this.getInstance().selection.collapse();
  116. },
  117. addUndo: function addUndo() {
  118. this.getInstance().undoManager.add();
  119. }
  120. };
  121. };
  122. ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
  123. _jQuery2.default.entwine('ss', function ($) {
  124. $('textarea.htmleditor').entwine({
  125. Editor: null,
  126. onadd: function onadd() {
  127. var edClass = this.data('editor') || 'default',
  128. ed = ss.editorWrappers[edClass]();
  129. this.setEditor(ed);
  130. ed.init(this.attr('id'));
  131. this._super();
  132. },
  133. onremove: function onremove() {
  134. this.getEditor().destroy();
  135. this._super();
  136. },
  137. 'from .cms-edit-form': {
  138. onbeforesubmitform: function onbeforesubmitform() {
  139. this.getEditor().save();
  140. this._super();
  141. }
  142. },
  143. openLinkDialog: function openLinkDialog() {
  144. this.openDialog('link');
  145. },
  146. openMediaDialog: function openMediaDialog() {
  147. this.openDialog('media');
  148. },
  149. openDialog: function openDialog(type) {
  150. var capitalize = function capitalize(text) {
  151. return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
  152. };
  153. var self = this,
  154. url = $('#cms-editor-dialogs').data('url' + capitalize(type) + 'form'),
  155. dialog = $('.htmleditorfield-' + type + 'dialog');
  156. if (dialog.length) {
  157. dialog.getForm().setElement(this);
  158. dialog.html('');
  159. dialog.addClass('loading');
  160. dialog.open();
  161. } else {
  162. dialog = $('<div class="htmleditorfield-dialog htmleditorfield-' + type + 'dialog loading">');
  163. $('body').append(dialog);
  164. }
  165. $.ajax({
  166. url: url,
  167. complete: function complete() {
  168. dialog.removeClass('loading');
  169. },
  170. success: function success(html) {
  171. dialog.html(html);
  172. dialog.getForm().setElement(self);
  173. dialog.trigger('ssdialogopen');
  174. }
  175. });
  176. }
  177. });
  178. $('.htmleditorfield-dialog').entwine({
  179. onadd: function onadd() {
  180. if (!this.is('.ui-dialog-content')) {
  181. this.ssdialog({
  182. autoOpen: true,
  183. buttons: {
  184. 'insert': {
  185. text: _i18n2.default._t('HtmlEditorField.INSERT', 'Insert'),
  186. 'data-icon': 'accept',
  187. class: 'ss-ui-action-constructive media-insert',
  188. click: function click() {
  189. $(this).find('form').submit();
  190. }
  191. }
  192. }
  193. });
  194. }
  195. this._super();
  196. },
  197. getForm: function getForm() {
  198. return this.find('form');
  199. },
  200. open: function open() {
  201. this.ssdialog('open');
  202. },
  203. close: function close() {
  204. this.ssdialog('close');
  205. },
  206. toggle: function toggle(bool) {
  207. if (this.is(':visible')) this.close();else this.open();
  208. },
  209. onscroll: function onscroll() {
  210. this.animate({
  211. scrollTop: this.find('form').height()
  212. }, 500);
  213. }
  214. });
  215. $('form.htmleditorfield-form').entwine({
  216. Selection: null,
  217. Bookmark: null,
  218. Element: null,
  219. setSelection: function setSelection(node) {
  220. return this._super($(node));
  221. },
  222. onadd: function onadd() {
  223. var titleEl = this.find(':header:first');
  224. this.getDialog().attr('title', titleEl.text());
  225. this._super();
  226. },
  227. onremove: function onremove() {
  228. this.setSelection(null);
  229. this.setBookmark(null);
  230. this.setElement(null);
  231. this._super();
  232. },
  233. getDialog: function getDialog() {
  234. return this.closest('.htmleditorfield-dialog');
  235. },
  236. fromDialog: {
  237. onssdialogopen: function onssdialogopen() {
  238. var ed = this.getEditor();
  239. this.setSelection(ed.getSelectedNode());
  240. this.setBookmark(ed.createBookmark());
  241. ed.blur();
  242. this.find(':input:not(:submit)[data-skip-autofocus!="true"]').filter(':visible:enabled').eq(0).focus();
  243. this.redraw();
  244. this.updateFromEditor();
  245. },
  246. onssdialogclose: function onssdialogclose() {
  247. var ed = this.getEditor();
  248. ed.moveToBookmark(this.getBookmark());
  249. this.setSelection(null);
  250. this.setBookmark(null);
  251. this.resetFields();
  252. }
  253. },
  254. getEditor: function getEditor() {
  255. return this.getElement().getEditor();
  256. },
  257. modifySelection: function modifySelection(callback) {
  258. var ed = this.getEditor();
  259. ed.moveToBookmark(this.getBookmark());
  260. callback.call(this, ed);
  261. this.setSelection(ed.getSelectedNode());
  262. this.setBookmark(ed.createBookmark());
  263. ed.blur();
  264. },
  265. updateFromEditor: function updateFromEditor() {},
  266. redraw: function redraw() {},
  267. resetFields: function resetFields() {
  268. this.find('.tree-holder').empty();
  269. }
  270. });
  271. $('form.htmleditorfield-linkform').entwine({
  272. onsubmit: function onsubmit(e) {
  273. this.insertLink();
  274. this.getDialog().close();
  275. return false;
  276. },
  277. resetFields: function resetFields() {
  278. this._super();
  279. this[0].reset();
  280. },
  281. redraw: function redraw() {
  282. this._super();
  283. var linkType = this.find(':input[name=LinkType]:checked').val();
  284. this.addAnchorSelector();
  285. this.resetFileField();
  286. this.find('.step2').nextAll('.field').not('.field[id$="' + linkType + '_Holder"]').hide();
  287. this.find('.field[id$="LinkType_Holder"]').show();
  288. this.find('.field[id$="' + linkType + '_Holder"]').show();
  289. if (linkType == 'internal' || linkType == 'anchor') {
  290. this.find('.field[id$="Anchor_Holder"]').show();
  291. }
  292. if (linkType == 'email') {
  293. this.find('.field[id$="Subject_Holder"]').show();
  294. } else {
  295. this.find('.field[id$="TargetBlank_Holder"]').show();
  296. }
  297. if (linkType == 'anchor') {
  298. this.find('.field[id$="AnchorSelector_Holder"]').show();
  299. }
  300. this.find('.field[id$="Description_Holder"]').show();
  301. },
  302. getLinkAttributes: function getLinkAttributes() {
  303. var href,
  304. target = null,
  305. subject = this.find(':input[name=Subject]').val(),
  306. anchor = this.find(':input[name=Anchor]').val();
  307. if (this.find(':input[name=TargetBlank]').is(':checked')) {
  308. target = '_blank';
  309. }
  310. switch (this.find(':input[name=LinkType]:checked').val()) {
  311. case 'internal':
  312. href = '[sitetree_link,id=' + this.find(':input[name=internal]').val() + ']';
  313. if (anchor) {
  314. href += '#' + anchor;
  315. }
  316. break;
  317. case 'anchor':
  318. href = '#' + anchor;
  319. break;
  320. case 'file':
  321. var fileid = this.find('.ss-uploadfield .ss-uploadfield-item').attr('data-fileid');
  322. href = fileid ? '[file_link,id=' + fileid + ']' : '';
  323. break;
  324. case 'email':
  325. href = 'mailto:' + this.find(':input[name=email]').val();
  326. if (subject) {
  327. href += '?subject=' + encodeURIComponent(subject);
  328. }
  329. target = null;
  330. break;
  331. default:
  332. href = this.find(':input[name=external]').val();
  333. if (href.indexOf('://') == -1) href = 'http://' + href;
  334. break;
  335. }
  336. return {
  337. href: href,
  338. target: target,
  339. title: this.find(':input[name=Description]').val()
  340. };
  341. },
  342. insertLink: function insertLink() {
  343. this.modifySelection(function (ed) {
  344. ed.insertLink(this.getLinkAttributes());
  345. });
  346. },
  347. removeLink: function removeLink() {
  348. this.modifySelection(function (ed) {
  349. ed.removeLink();
  350. });
  351. this.resetFileField();
  352. this.close();
  353. },
  354. resetFileField: function resetFileField() {
  355. var fileField = this.find('.ss-uploadfield[id$="file_Holder"]'),
  356. fileUpload = fileField.data('fileupload'),
  357. currentItem = fileField.find('.ss-uploadfield-item[data-fileid]');
  358. if (currentItem.length) {
  359. fileUpload._trigger('destroy', null, { context: currentItem });
  360. fileField.find('.ss-uploadfield-addfile').removeClass('borderTop');
  361. }
  362. },
  363. addAnchorSelector: function addAnchorSelector() {
  364. if (this.find(':input[name=AnchorSelector]').length) return;
  365. var self = this;
  366. var anchorSelector = $('<select id="Form_EditorToolbarLinkForm_AnchorSelector" name="AnchorSelector"></select>');
  367. this.find(':input[name=Anchor]').parent().append(anchorSelector);
  368. this.updateAnchorSelector();
  369. anchorSelector.change(function (e) {
  370. self.find(':input[name="Anchor"]').val($(this).val());
  371. });
  372. },
  373. getAnchors: function getAnchors() {
  374. var linkType = this.find(':input[name=LinkType]:checked').val();
  375. var dfdAnchors = $.Deferred();
  376. switch (linkType) {
  377. case 'anchor':
  378. var collectedAnchors = [];
  379. var ed = this.getEditor();
  380. if (ed) {
  381. var raw = ed.getContent().match(/\s+(name|id)\s*=\s*(["'])([^\2\s>]*?)\2|\s+(name|id)\s*=\s*([^"']+)[\s +>]/gim);
  382. if (raw && raw.length) {
  383. for (var i = 0; i < raw.length; i++) {
  384. var indexStart = raw[i].indexOf('id=') == -1 ? 7 : 5;
  385. collectedAnchors.push(raw[i].substr(indexStart).replace(/"$/, ''));
  386. }
  387. }
  388. }
  389. dfdAnchors.resolve(collectedAnchors);
  390. break;
  391. case 'internal':
  392. var pageId = this.find(':input[name=internal]').val();
  393. if (pageId) {
  394. $.ajax({
  395. url: $.path.addSearchParams(this.attr('action').replace('LinkForm', 'getanchors'), { 'PageID': parseInt(pageId) }),
  396. success: function success(body, status, xhr) {
  397. dfdAnchors.resolve($.parseJSON(body));
  398. },
  399. error: function error(xhr, status) {
  400. dfdAnchors.reject(xhr.responseText);
  401. }
  402. });
  403. } else {
  404. dfdAnchors.resolve([]);
  405. }
  406. break;
  407. default:
  408. dfdAnchors.reject(_i18n2.default._t('HtmlEditorField.ANCHORSNOTSUPPORTED', 'Anchors are not supported for this link type.'));
  409. break;
  410. }
  411. return dfdAnchors.promise();
  412. },
  413. updateAnchorSelector: function updateAnchorSelector() {
  414. var self = this;
  415. var selector = this.find(':input[name=AnchorSelector]');
  416. var dfdAnchors = this.getAnchors();
  417. selector.empty();
  418. selector.append($('<option value="" selected="1">' + _i18n2.default._t('HtmlEditorField.LOOKINGFORANCHORS', 'Looking for anchors...') + '</option>'));
  419. dfdAnchors.done(function (anchors) {
  420. selector.empty();
  421. selector.append($('<option value="" selected="1">' + _i18n2.default._t('HtmlEditorField.SelectAnchor') + '</option>'));
  422. if (anchors) {
  423. for (var j = 0; j < anchors.length; j++) {
  424. selector.append($('<option value="' + anchors[j] + '">' + anchors[j] + '</option>'));
  425. }
  426. }
  427. }).fail(function (message) {
  428. selector.empty();
  429. selector.append($('<option value="" selected="1">' + message + '</option>'));
  430. });
  431. if ($.browser.msie) selector.hide().show();
  432. },
  433. updateFromEditor: function updateFromEditor() {
  434. var htmlTagPattern = /<\S[^><]*>/g,
  435. fieldName,
  436. data = this.getCurrentLink();
  437. if (data) {
  438. for (fieldName in data) {
  439. var el = this.find(':input[name=' + fieldName + ']'),
  440. selected = data[fieldName];
  441. if (typeof selected == 'string') selected = selected.replace(htmlTagPattern, '');
  442. if (el.is(':checkbox')) {
  443. el.prop('checked', selected).change();
  444. } else if (el.is(':radio')) {
  445. el.val([selected]).change();
  446. } else if (fieldName == 'file') {
  447. el = this.find(':input[name="' + fieldName + '[Uploads][]"]');
  448. el = el.parents('.ss-uploadfield');
  449. (function attach(el, selected) {
  450. if (!el.getConfig()) {
  451. setTimeout(function () {
  452. attach(el, selected);
  453. }, 50);
  454. } else {
  455. el.attachFiles([selected]);
  456. }
  457. })(el, selected);
  458. } else {
  459. el.val(selected).change();
  460. }
  461. }
  462. }
  463. },
  464. getCurrentLink: function getCurrentLink() {
  465. var selectedEl = this.getSelection(),
  466. href = "",
  467. target = "",
  468. title = "",
  469. action = "insert",
  470. style_class = "";
  471. var linkDataSource = null;
  472. if (selectedEl.length) {
  473. if (selectedEl.is('a')) {
  474. linkDataSource = selectedEl;
  475. } else {
  476. linkDataSource = selectedEl = selectedEl.parents('a:first');
  477. }
  478. }
  479. if (linkDataSource && linkDataSource.length) this.modifySelection(function (ed) {
  480. ed.selectNode(linkDataSource[0]);
  481. });
  482. if (!linkDataSource.attr('href')) linkDataSource = null;
  483. if (linkDataSource) {
  484. href = linkDataSource.attr('href');
  485. target = linkDataSource.attr('target');
  486. title = linkDataSource.attr('title');
  487. style_class = linkDataSource.attr('class');
  488. href = this.getEditor().cleanLink(href, linkDataSource);
  489. action = "update";
  490. }
  491. if (href.match(/^mailto:(.*)$/)) {
  492. return {
  493. LinkType: 'email',
  494. email: RegExp.$1,
  495. Description: title
  496. };
  497. } else if (href.match(/^(assets\/.*)$/) || href.match(/^\[file_link\s*(?:\s*|%20|,)?id=([0-9]+)\]?(#.*)?$/)) {
  498. return {
  499. LinkType: 'file',
  500. file: RegExp.$1,
  501. Description: title,
  502. TargetBlank: target ? true : false
  503. };
  504. } else if (href.match(/^#(.*)$/)) {
  505. return {
  506. LinkType: 'anchor',
  507. Anchor: RegExp.$1,
  508. Description: title,
  509. TargetBlank: target ? true : false
  510. };
  511. } else if (href.match(/^\[sitetree_link(?:\s*|%20|,)?id=([0-9]+)\]?(#.*)?$/i)) {
  512. return {
  513. LinkType: 'internal',
  514. internal: RegExp.$1,
  515. Anchor: RegExp.$2 ? RegExp.$2.substr(1) : '',
  516. Description: title,
  517. TargetBlank: target ? true : false
  518. };
  519. } else if (href) {
  520. return {
  521. LinkType: 'external',
  522. external: href,
  523. Description: title,
  524. TargetBlank: target ? true : false
  525. };
  526. } else {
  527. return null;
  528. }
  529. }
  530. });
  531. $('form.htmleditorfield-linkform input[name=LinkType]').entwine({
  532. onclick: function onclick(e) {
  533. this.parents('form:first').redraw();
  534. this._super();
  535. },
  536. onchange: function onchange() {
  537. this.parents('form:first').redraw();
  538. var linkType = this.parent().find(':checked').val();
  539. if (linkType === 'anchor' || linkType === 'internal') {
  540. this.parents('form.htmleditorfield-linkform').updateAnchorSelector();
  541. }
  542. this._super();
  543. }
  544. });
  545. $('form.htmleditorfield-linkform input[name=internal]').entwine({
  546. onvalueupdated: function onvalueupdated() {
  547. this.parents('form.htmleditorfield-linkform').updateAnchorSelector();
  548. this._super();
  549. }
  550. });
  551. $('form.htmleditorfield-linkform :submit[name=action_remove]').entwine({
  552. onclick: function onclick(e) {
  553. this.parents('form:first').removeLink();
  554. this._super();
  555. return false;
  556. }
  557. });
  558. $('form.htmleditorfield-mediaform').entwine({
  559. toggleCloseButton: function toggleCloseButton() {
  560. var updateExisting = Boolean(this.find('.ss-htmleditorfield-file').length);
  561. this.find('.overview .action-delete')[updateExisting ? 'hide' : 'show']();
  562. },
  563. onsubmit: function onsubmit() {
  564. this.modifySelection(function (ed) {
  565. this.find('.ss-htmleditorfield-file').each(function () {
  566. $(this).insertHTML(ed);
  567. });
  568. });
  569. this.getDialog().close();
  570. return false;
  571. },
  572. updateFromEditor: function updateFromEditor() {
  573. var self = this,
  574. node = this.getSelection();
  575. if (node.is('img')) {
  576. var idOrUrl = node.data('id') || node.data('url') || node.attr('src');
  577. this.showFileView(idOrUrl).done(function (filefield) {
  578. filefield.updateFromNode(node);
  579. self.toggleCloseButton();
  580. self.redraw();
  581. });
  582. }
  583. this.redraw();
  584. },
  585. redraw: function redraw(updateExisting) {
  586. this._super();
  587. var node = this.getSelection(),
  588. hasItems = Boolean(this.find('.ss-htmleditorfield-file').length),
  589. editingSelected = node.is('img'),
  590. insertingURL = this.hasClass('insertingURL'),
  591. header = this.find('.header-edit');
  592. header[hasItems ? 'show' : 'hide']();
  593. this.closest('ui-dialog').find('ui-dialog-buttonpane .media-insert').button(hasItems ? 'enable' : 'disable').toggleClass('ui-state-disabled', !hasItems);
  594. this.find('.htmleditorfield-default-panel')[editingSelected || insertingURL ? 'hide' : 'show']();
  595. this.find('.htmleditorfield-web-panel')[editingSelected || !insertingURL ? 'hide' : 'show']();
  596. var mediaFormHeading = this.find('.htmleditorfield-mediaform-heading.insert');
  597. if (editingSelected) {
  598. mediaFormHeading.hide();
  599. } else if (insertingURL) {
  600. mediaFormHeading.show().text(_i18n2.default._t("HtmlEditorField.INSERTURL")).prepend('<button class="back-button font-icon-left-open no-text" title="' + _i18n2.default._t("HtmlEditorField.BACK") + '"></button>');
  601. this.find('.htmleditorfield-web-panel input.remoteurl').focus();
  602. } else {
  603. mediaFormHeading.show().text(_i18n2.default._t("HtmlEditorField.INSERTFROM")).find('.back-button').remove();
  604. }
  605. this.find('.htmleditorfield-mediaform-heading.update')[editingSelected ? 'show' : 'hide']();
  606. this.find('.ss-uploadfield-item-actions')[editingSelected ? 'hide' : 'show']();
  607. this.find('.ss-uploadfield-item-name')[editingSelected ? 'hide' : 'show']();
  608. this.find('.ss-uploadfield-item-preview')[editingSelected ? 'hide' : 'show']();
  609. this.find('.btn-toolbar .media-update')[editingSelected ? 'show' : 'hide']();
  610. this.find('.ss-uploadfield-item-editform').toggleEditForm(editingSelected);
  611. this.find('.htmleditorfield-from-cms .field.treedropdown').css('left', $('.htmleditorfield-mediaform-heading:visible').outerWidth());
  612. this.closest('.ui-dialog').addClass('ss-uploadfield-dropzone');
  613. this.closest('.ui-dialog').find('.ui-dialog-buttonpane .media-insert .ui-button-text').text([editingSelected ? _i18n2.default._t('HtmlEditorField.UPDATE', 'Update') : _i18n2.default._t('HtmlEditorField.INSERT', 'Insert')]);
  614. },
  615. resetFields: function resetFields() {
  616. this.find('.ss-htmleditorfield-file').remove();
  617. this.find('.ss-gridfield-items .ui-selected').removeClass('ui-selected');
  618. this.find('li.ss-uploadfield-item').remove();
  619. this.redraw();
  620. this._super();
  621. },
  622. getFileView: function getFileView(idOrUrl) {
  623. return this.find('.ss-htmleditorfield-file[data-id=' + idOrUrl + ']');
  624. },
  625. showFileView: function showFileView(idOrUrl) {
  626. var self = this,
  627. params = Number(idOrUrl) == idOrUrl ? { ID: idOrUrl } : { FileURL: idOrUrl };
  628. var item = $('<div class="ss-htmleditorfield-file loading" />');
  629. this.find('.content-edit').prepend(item);
  630. var dfr = $.Deferred();
  631. $.ajax({
  632. url: $.path.addSearchParams(this.attr('action').replace(/MediaForm/, 'viewfile'), params),
  633. success: function success(html, status, xhr) {
  634. var newItem = $(html).filter('.ss-htmleditorfield-file');
  635. item.replaceWith(newItem);
  636. self.redraw();
  637. dfr.resolve(newItem);
  638. },
  639. error: function error() {
  640. item.remove();
  641. dfr.reject();
  642. }
  643. });
  644. return dfr.promise();
  645. }
  646. });
  647. $('form.htmleditorfield-mediaform div.ss-upload .upload-url').entwine({
  648. onclick: function onclick() {
  649. var form = this.closest('form');
  650. form.addClass('insertingURL');
  651. form.redraw();
  652. }
  653. });
  654. $('form.htmleditorfield-mediaform .htmleditorfield-mediaform-heading .back-button').entwine({
  655. onclick: function onclick() {
  656. var form = this.closest('form');
  657. form.removeClass('insertingURL');
  658. form.redraw();
  659. }
  660. });
  661. $('form.htmleditorfield-mediaform .ss-gridfield-items').entwine({
  662. onselectableselected: function onselectableselected(e, ui) {
  663. var form = this.closest('form'),
  664. item = $(ui.selected);
  665. if (!item.is('.ss-gridfield-item')) return;
  666. form.closest('form').showFileView(item.data('id'));
  667. form.redraw();
  668. form.parent().trigger('scroll');
  669. },
  670. onselectableunselected: function onselectableunselected(e, ui) {
  671. var form = this.closest('form'),
  672. item = $(ui.unselected);
  673. if (!item.is('.ss-gridfield-item')) return;
  674. form.getFileView(item.data('id')).remove();
  675. form.redraw();
  676. }
  677. });
  678. $('form.htmleditorfield-form.htmleditorfield-mediaform div.ss-assetuploadfield').entwine({
  679. onfileuploadstop: function onfileuploadstop(e) {
  680. var form = this.closest('form');
  681. var editFieldIDs = [];
  682. form.find('div.content-edit').find('div.ss-htmleditorfield-file').each(function () {
  683. editFieldIDs.push($(this).data('id'));
  684. });
  685. var uploadedFiles = $('.ss-uploadfield-files', this).children('.ss-uploadfield-item');
  686. uploadedFiles.each(function () {
  687. var uploadedID = $(this).data('fileid');
  688. if (uploadedID && $.inArray(uploadedID, editFieldIDs) == -1) {
  689. $(this).remove();
  690. form.showFileView(uploadedID);
  691. }
  692. });
  693. form.parent().trigger('scroll');
  694. form.redraw();
  695. }
  696. });
  697. $('form.htmleditorfield-form.htmleditorfield-mediaform input.remoteurl').entwine({
  698. onadd: function onadd() {
  699. this._super();
  700. this.validate();
  701. },
  702. onkeyup: function onkeyup() {
  703. this.validate();
  704. },
  705. onchange: function onchange() {
  706. this.validate();
  707. },
  708. getAddButton: function getAddButton() {
  709. return this.closest('.CompositeField').find('button.add-url');
  710. },
  711. validate: function validate() {
  712. var val = this.val(),
  713. orig = val;
  714. val = $.trim(val);
  715. val = val.replace(/^https?:\/\//i, '');
  716. if (orig !== val) this.val(val);
  717. this.getAddButton().button(!!val ? 'enable' : 'disable');
  718. return !!val;
  719. }
  720. });
  721. $('form.htmleditorfield-form.htmleditorfield-mediaform .add-url').entwine({
  722. getURLField: function getURLField() {
  723. return this.closest('.CompositeField').find('input.remoteurl');
  724. },
  725. onclick: function onclick(e) {
  726. var urlField = this.getURLField(),
  727. container = this.closest('.CompositeField'),
  728. form = this.closest('form');
  729. if (urlField.validate()) {
  730. container.addClass('loading');
  731. form.showFileView('http://' + urlField.val()).done(function () {
  732. container.removeClass('loading');
  733. form.parent().trigger('scroll');
  734. });
  735. form.redraw();
  736. }
  737. return false;
  738. }
  739. });
  740. $('form.htmleditorfield-mediaform .ss-htmleditorfield-file').entwine({
  741. getAttributes: function getAttributes() {},
  742. getExtraData: function getExtraData() {},
  743. getHTML: function getHTML() {
  744. return $('<div>').append($('<a/>').attr({ href: this.data('url') }).text(this.find('.name').text())).html();
  745. },
  746. insertHTML: function insertHTML(ed) {
  747. ed.replaceContent(this.getHTML());
  748. },
  749. updateFromNode: function updateFromNode(node) {},
  750. updateDimensions: function updateDimensions(constrainBy, maxW, maxH) {
  751. var widthEl = this.find(':input[name=Width]'),
  752. heightEl = this.find(':input[name=Height]'),
  753. w = widthEl.val(),
  754. h = heightEl.val(),
  755. aspect;
  756. if (w && h) {
  757. if (constrainBy) {
  758. aspect = heightEl.getOrigVal() / widthEl.getOrigVal();
  759. if (constrainBy == 'Width') {
  760. if (maxW && w > maxW) w = maxW;
  761. h = Math.floor(w * aspect);
  762. } else if (constrainBy == 'Height') {
  763. if (maxH && h > maxH) h = maxH;
  764. w = Math.ceil(h / aspect);
  765. }
  766. } else {
  767. if (maxW && w > maxW) w = maxW;
  768. if (maxH && h > maxH) h = maxH;
  769. }
  770. widthEl.val(w);
  771. heightEl.val(h);
  772. }
  773. }
  774. });
  775. $('form.htmleditorfield-mediaform .ss-htmleditorfield-file.image').entwine({
  776. getAttributes: function getAttributes() {
  777. var width = this.find(':input[name=Width]').val(),
  778. height = this.find(':input[name=Height]').val();
  779. return {
  780. 'src': this.find(':input[name=URL]').val(),
  781. 'alt': this.find(':input[name=AltText]').val(),
  782. 'width': width ? parseInt(width, 10) : null,
  783. 'height': height ? parseInt(height, 10) : null,
  784. 'title': this.find(':input[name=Title]').val(),
  785. 'class': this.find(':input[name=CSSClass]').val(),
  786. 'data-id': this.find(':input[name=FileID]').val()
  787. };
  788. },
  789. getExtraData: function getExtraData() {
  790. return {
  791. 'CaptionText': this.find(':input[name=CaptionText]').val()
  792. };
  793. },
  794. getHTML: function getHTML() {},
  795. insertHTML: function insertHTML(ed) {
  796. var form = this.closest('form');
  797. var node = form.getSelection();
  798. if (!ed) ed = form.getEditor();
  799. var attrs = this.getAttributes(),
  800. extraData = this.getExtraData();
  801. var replacee = node && node.is('img') ? node : null;
  802. if (replacee && replacee.parent().is('.captionImage')) replacee = replacee.parent();
  803. var img = node && node.is('img') ? node : $('<img />');
  804. img.attr(attrs);
  805. var container = img.parent('.captionImage'),
  806. caption = container.find('.caption');
  807. if (extraData.CaptionText) {
  808. if (!container.length) {
  809. container = $('<div></div>');
  810. }
  811. container.attr('class', 'captionImage ' + attrs['class']).css('width', attrs.width);
  812. if (!caption.length) {
  813. caption = $('<p class="caption"></p>').appendTo(container);
  814. }
  815. caption.attr('class', 'caption ' + attrs['class']).text(extraData.CaptionText);
  816. } else {
  817. container = caption = null;
  818. }
  819. var replacer = container ? container : img;
  820. if (replacee && replacee.not(replacer).length) {
  821. replacee.replaceWith(replacer);
  822. }
  823. if (container) {
  824. container.prepend(img);
  825. }
  826. if (!replacee) {
  827. ed.repaint();
  828. ed.insertContent($('<div />').append(replacer).html(), { skip_undo: 1 });
  829. }
  830. ed.addUndo();
  831. ed.repaint();
  832. },
  833. updateFromNode: function updateFromNode(node) {
  834. this.find(':input[name=AltText]').val(node.attr('alt'));
  835. this.find(':input[name=Title]').val(node.attr('title'));
  836. this.find(':input[name=CSSClass]').val(node.attr('class'));
  837. this.find(':input[name=Width]').val(node.width());
  838. this.find(':input[name=Height]').val(node.height());
  839. this.find(':input[name=CaptionText]').val(node.siblings('.caption:first').text());
  840. this.find(':input[name=FileID]').val(node.data('id'));
  841. }
  842. });
  843. $('form.htmleditorfield-mediaform .ss-htmleditorfield-file.flash').entwine({
  844. getAttributes: function getAttributes() {
  845. var width = this.find(':input[name=Width]').val(),
  846. height = this.find(':input[name=Height]').val();
  847. return {
  848. 'src': this.find(':input[name=URL]').val(),
  849. 'width': width ? parseInt(width, 10) : null,
  850. 'height': height ? parseInt(height, 10) : null,
  851. 'data-fileid': this.find(':input[name=FileID]').val()
  852. };
  853. },
  854. getHTML: function getHTML() {
  855. var attrs = this.getAttributes();
  856. var el = tinyMCE.activeEditor.plugins.media.dataToImg({
  857. 'type': 'flash',
  858. 'width': attrs.width,
  859. 'height': attrs.height,
  860. 'params': { 'src': attrs.src },
  861. 'video': { 'sources': [] }
  862. });
  863. return $('<div />').append(el).html();
  864. },
  865. updateFromNode: function updateFromNode(node) {}
  866. });
  867. $('form.htmleditorfield-mediaform .ss-htmleditorfield-file.embed').entwine({
  868. getAttributes: function getAttributes() {
  869. var width = this.find(':input[name=Width]').val(),
  870. height = this.find(':input[name=Height]').val();
  871. return {
  872. 'src': this.find('.thumbnail-preview').attr('src'),
  873. 'width': width ? parseInt(width, 10) : null,
  874. 'height': height ? parseInt(height, 10) : null,
  875. 'class': this.find(':input[name=CSSClass]').val(),
  876. 'alt': this.find(':input[name=AltText]').val(),
  877. 'title': this.find(':input[name=Title]').val(),
  878. 'data-fileid': this.find(':input[name=FileID]').val()
  879. };
  880. },
  881. getExtraData: function getExtraData() {
  882. var width = this.find(':input[name=Width]').val(),
  883. height = this.find(':input[name=Height]').val();
  884. return {
  885. 'CaptionText': this.find(':input[name=CaptionText]').val(),
  886. 'Url': this.find(':input[name=URL]').val(),
  887. 'thumbnail': this.find('.thumbnail-preview').attr('src'),
  888. 'width': width ? parseInt(width, 10) : null,
  889. 'height': height ? parseInt(height, 10) : null,
  890. 'cssclass': this.find(':input[name=CSSClass]').val()
  891. };
  892. },
  893. getHTML: function getHTML() {
  894. var el,
  895. attrs = this.getAttributes(),
  896. extraData = this.getExtraData(),
  897. imgEl = $('<img />').attr(attrs).addClass('ss-htmleditorfield-file embed');
  898. $.each(extraData, function (key, value) {
  899. imgEl.attr('data-' + key, value);
  900. });
  901. if (extraData.CaptionText) {
  902. el = $('<div style="width: ' + attrs['width'] + 'px;" class="captionImage ' + attrs['class'] + '"><p class="caption">' + extraData.CaptionText + '</p></div>').prepend(imgEl);
  903. } else {
  904. el = imgEl;
  905. }
  906. return $('<div />').append(el).html();
  907. },
  908. updateFromNode: function updateFromNode(node) {
  909. this.find(':input[name=AltText]').val(node.attr('alt'));
  910. this.find(':input[name=Title]').val(node.attr('title'));
  911. this.find(':input[name=Width]').val(node.width());
  912. this.find(':input[name=Height]').val(node.height());
  913. this.find(':input[name=Title]').val(node.attr('title'));
  914. this.find(':input[name=CSSClass]').val(node.data('cssclass'));
  915. this.find(':input[name=FileID]').val(node.data('fileid'));
  916. }
  917. });
  918. $('form.htmleditorfield-mediaform .ss-htmleditorfield-file .dimensions :input').entwine({
  919. OrigVal: null,
  920. onmatch: function onmatch() {
  921. this._super();
  922. this.setOrigVal(parseInt(this.val(), 10));
  923. },
  924. onunmatch: function onunmatch() {
  925. this._super();
  926. },
  927. onfocusout: function onfocusout(e) {
  928. this.closest('.ss-htmleditorfield-file').updateDimensions(this.attr('name'));
  929. }
  930. });
  931. $('form.htmleditorfield-mediaform .ss-uploadfield-item .ss-uploadfield-item-cancel').entwine({
  932. onclick: function onclick(e) {
  933. var form = this.closest('form'),
  934. file = this.closest('ss-uploadfield-item');
  935. form.find('.ss-gridfield-item[data-id=' + file.data('id') + ']').removeClass('ui-selected');
  936. this.closest('.ss-uploadfield-item').remove();
  937. form.redraw();
  938. e.preventDefault();
  939. }
  940. });
  941. $('div.ss-assetuploadfield .ss-uploadfield-item-edit, div.ss-assetuploadfield .ss-uploadfield-item-name').entwine({
  942. getEditForm: function getEditForm() {
  943. return this.closest('.ss-uploadfield-item').find('.ss-uploadfield-item-editform');
  944. },
  945. fromEditForm: {
  946. onchange: function onchange(e) {
  947. var form = $(e.target);
  948. form.removeClass('edited');
  949. form.addClass('edited');
  950. }
  951. },
  952. onclick: function onclick(e) {
  953. var editForm = this.getEditForm();
  954. if (this.closest('.ss-uploadfield-item').hasClass('ss-htmleditorfield-file')) {
  955. editForm.parent('ss-uploadfield-item').removeClass('ui-state-warning');
  956. editForm.toggleEditForm();
  957. e.preventDefault();
  958. return false;
  959. }
  960. this._super(e);
  961. }
  962. });
  963. $('div.ss-assetuploadfield .ss-uploadfield-item-editform').entwine({
  964. toggleEditForm: function toggleEditForm(bool) {
  965. var itemInfo = this.prev('.ss-uploadfield-item-info'),
  966. status = itemInfo.find('.ss-uploadfield-item-status');
  967. var text = "";
  968. if (bool === true || bool !== false && this.height() === 0) {
  969. text = _i18n2.default._t('UploadField.Editing', "Editing ...");
  970. this.height('auto');
  971. itemInfo.find('.toggle-details-icon').addClass('opened');
  972. status.removeClass('ui-state-success-text').removeClass('ui-state-warning-text');
  973. } else {
  974. this.height(0);
  975. itemInfo.find('.toggle-details-icon').removeClass('opened');
  976. if (!this.hasClass('edited')) {
  977. text = _i18n2.default._t('UploadField.NOCHANGES', 'No Changes');
  978. status.addClass('ui-state-success-text');
  979. } else {
  980. text = _i18n2.default._t('UploadField.CHANGESSAVED', 'Changes Made');
  981. this.removeClass('edited');
  982. status.addClass('ui-state-success-text');
  983. }
  984. }
  985. status.attr('title', text).text(text);
  986. }
  987. });
  988. $('form.htmleditorfield-mediaform .field[id$="ParentID_Holder"] .TreeDropdownField').entwine({
  989. onadd: function onadd() {
  990. this._super();
  991. var self = this;
  992. this.bind('change', function () {
  993. var fileList = self.closest('form').find('.grid-field');
  994. fileList.setState('ParentID', self.getValue());
  995. fileList.reload();
  996. });
  997. }
  998. });
  999. });
  1000. });