editor.quill.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /**
  2. * Copyright (c) UNA, Inc - https://una.io
  3. * MIT License - https://opensource.org/licenses/MIT
  4. *
  5. * @defgroup UnaCore UNA Core
  6. * @{
  7. */
  8. function bx_editor_init(oParams) {
  9. var oEditor = null;
  10. hljs.configure({
  11. languages: ['javascript', 'php', 'html', 'css']
  12. });
  13. bEmptyToolbar = oParams.toolbar == false ? true : false;
  14. if (oParams.query_params == undefined)
  15. oParams.query_params = {};
  16. oParams.toolbar = {
  17. container: bEmptyToolbar ? [] : oParams.toolbar,
  18. handlers: {
  19. 'show-html': function() {
  20. bx_alert('<textarea class="bx-def-font-inputs bx-form-input-textarea bx-form-input-html-quill-code" id="' + oParams.name + '_code">' + oEditor.container.firstChild.innerHTML + '</textarea>',function() {
  21. oEditor.container.firstChild.innerHTML = $('#'+oParams.name+'_code').val();
  22. });
  23. },
  24. 'embed': function(value) {
  25. var range = oEditor.getSelection();
  26. bx_prompt(_t('_sys_txt_quill_tooltip_embed_popup_header'), '', function(oPopup){
  27. sLink = $(oPopup).find("input[type = 'text']").val()
  28. $.getJSON(oParams.root_url + 'embed.php?', {a: 'get_link', l: sLink}, function(aData){
  29. if (range) {
  30. oEditor.clipboard.dangerouslyPasteHTML(range.index, "</p>&#8205; <p>&#8205; </p>", 'api');
  31. oEditor.insertEmbed(range.index+2, 'embed-link', {source: sLink, inlinecode : aData.code}, 'api');
  32. }
  33. else{
  34. oEditor.insertEmbed(0, 'embed-link', {source: sLink, inlinecode : aData.code}, 'api');
  35. }
  36. if ($(oParams.selector).next().next().find('.bx-embed-link a[href="' + aData.link + '"]').length > 0)
  37. bx_embed_link($(oParams.selector).next().next().find('.bx-embed-link a[href="' + aData.link + '"]')[0]);
  38. else
  39. bx_embed_link();
  40. });
  41. });
  42. },
  43. 'link': function(value) {
  44. if (value) {
  45. var range = oEditor.getSelection();
  46. bx_prompt(_t('_sys_txt_quill_tooltip_link_popup_header'), '', function(oPopup){
  47. var sLink = $(oPopup).find("input[type = 'text']").val();
  48. if (range) {
  49. if (range.length > 0){
  50. oEditor.format('link', sLink);
  51. }
  52. else{
  53. oEditor.insertText(range.index, sLink, 'link', sLink);
  54. }
  55. }
  56. else{
  57. oEditor.insertText(0, sLink, 'link', sLink);
  58. }
  59. });
  60. } else {
  61. oEditor.format('link', false);
  62. }
  63. }
  64. }
  65. }
  66. sVal = $(oParams.selector).val();
  67. if(!oParams.empty_tags){
  68. sVal = sVal.replaceAll('<p><br></p>','');
  69. }
  70. $(oParams.selector).after("<div id='" + oParams.name + "' class='bx-def-font-inputs bx-form-input-textarea bx-form-input-html bx-form-input-html-quill " + oParams.css_class + "'>" + sVal + "</div>" );
  71. $(oParams.selector).hide();
  72. $(oParams.selector).attr('object_editor', oParams.name);
  73. if (typeof bQuillRegistred === 'undefined' ) {
  74. var Embed = Quill.import('blots/embed');
  75. const BaseLink = Quill.import("formats/link");
  76. class Link extends BaseLink {
  77. format(name, value) {
  78. if (["href", "target"].indexOf(name) > -1) {
  79. if (value) {
  80. this.domNode.setAttribute(name, value);
  81. } else {
  82. this.domNode.removeAttribute(name);
  83. }
  84. } else {
  85. super.format(name, value);
  86. if (name == 'link'){
  87. if (value){
  88. if (!value.startsWith(oParams.root_url) && (value.startsWith('http://') || value.startsWith('https://'))){
  89. this.domNode.setAttribute("target", "_blank");
  90. }
  91. else{
  92. this.domNode.removeAttribute('target');
  93. }
  94. }
  95. }
  96. }
  97. }
  98. static create(value) {
  99. const node = super.create(value);
  100. node.setAttribute("href", this.sanitize(value));
  101. if (!value.startsWith(oParams.root_url) && (value.startsWith('http://') || value.startsWith('https://'))){
  102. node.setAttribute("target", "_blank");
  103. }
  104. else{
  105. node.removeAttribute('target');
  106. }
  107. return node;
  108. }
  109. }
  110. Quill.register(Link, true);
  111. class MenthionLink extends Embed {
  112. static create(value) {
  113. let node = super.create(value);
  114. if (value.id && value.value){
  115. node.setAttribute('href', value.id);
  116. node.innerHTML = value.denotationChar + value.value;
  117. node.setAttribute('title', value.value);
  118. node.setAttribute('dchar', value.denotationChar);
  119. node.setAttribute('data-profile-id', value.dataProfileId);
  120. }
  121. if (value.url && value.title && value.dataProfileId){
  122. node.setAttribute('href', value.url);
  123. node.innerHTML = value.text;
  124. node.setAttribute('title', value.title);
  125. if (value.dchar)
  126. node.setAttribute('dchar', value.dchar);
  127. else
  128. node.setAttribute('dchar', '@');
  129. node.setAttribute('data-profile-id', value.dataProfileId);
  130. }
  131. const sDenotationChar = node.getAttribute('dchar');
  132. if(sDenotationChar == '@')
  133. node.setAttribute('class', 'bx-mention-link');
  134. else if(sDenotationChar == '#')
  135. node.setAttribute('class', 'bx-tag-link');
  136. return node;
  137. }
  138. format(name, value) {
  139. if (name === 'href' || name === 'title' || name === 'dchar' || name === 'data-profile-id' || name === 'dataProfileId') {
  140. if (value) {
  141. if (name === 'dchar'){
  142. this.domNode.innerHTML = value + this.domNode.getAttribute('title');
  143. }
  144. if (name === 'dataProfileId'){
  145. this.domNode.setAttribute('data-profile-id', value);
  146. }
  147. else{
  148. this.domNode.setAttribute(name, value);
  149. }
  150. } else {
  151. this.domNode.removeAttribute(name, value);
  152. }
  153. }
  154. else {
  155. super.format(name, value);
  156. }
  157. };
  158. static value(node) {
  159. return { url: node.getAttribute('href') ,title: node.getAttribute('title'), dchar: node.getAttribute('dchar'), dataProfileId: node.getAttribute('data-profile-id'), text: node.innerText }
  160. }
  161. static formats(node) {
  162. let format = {};
  163. if (node.hasAttribute('href')) {
  164. format.href = node.getAttribute('href');
  165. }
  166. if (node.hasAttribute('title')) {
  167. format.title = node.getAttribute('title');
  168. }
  169. else{
  170. format.title = node.innerText.replace(node.getAttribute('dchar'), '');
  171. }
  172. if (node.hasAttribute('dchar')) {
  173. format.dchar = node.getAttribute('dchar');
  174. }
  175. if (node.hasAttribute('data-profile-id')) {
  176. format['data-profile-id'] = node.getAttribute('data-profile-id');
  177. }
  178. if (node.hasAttribute('dataProfileId')) {
  179. format.dataProfileId = node.getAttribute('dataProfileId');
  180. }
  181. return format;
  182. }
  183. }
  184. MenthionLink.blotName = 'menthion-link';
  185. //MenthionLink.className = '1';
  186. MenthionLink.tagName = 'a';
  187. Quill.register({
  188. 'formats/menthion-link': MenthionLink
  189. });
  190. class EmbedCode extends Embed {
  191. static create(value) {
  192. let node = super.create(value);
  193. if (value.source && value.inlinecode){
  194. node.setAttribute('source', value.source);
  195. node.innerHTML = value.inlinecode + "&nbsp;";
  196. return node;
  197. }
  198. return node;
  199. };
  200. format(name, value) {
  201. if (name === 'source') {
  202. if (value) {
  203. this.domNode.setAttribute(name, value);
  204. } else {
  205. this.domNode.removeAttribute(name, value);
  206. }
  207. }
  208. else {
  209. super.format(name, value);
  210. }
  211. };
  212. static value(node) {
  213. return { source: node.getAttribute('source'), inlinecode: "emded"}
  214. }
  215. static formats(node) {
  216. let format = {};
  217. if (node.hasAttribute('source')) {
  218. format.source = node.getAttribute('source');
  219. }
  220. return format;
  221. }
  222. }
  223. EmbedCode.className = 'bx-embed-link';
  224. EmbedCode.blotName = 'embed-link';
  225. EmbedCode.tagName = 'div';
  226. Quill.register({
  227. 'formats/embed-link': EmbedCode
  228. });
  229. var AlignStyle = Quill.import('attributors/style/align');
  230. Quill.register(AlignStyle, true);
  231. var DirectionStyle = Quill.import('attributors/style/direction');
  232. Quill.register(DirectionStyle, true);
  233. const ImageFormatAttributesList = [
  234. 'alt',
  235. 'height',
  236. 'width',
  237. 'style'
  238. ];
  239. const BaseImageFormat = Quill.import('formats/image');
  240. class ImageFormat extends BaseImageFormat {
  241. static formats(domNode) {
  242. return ImageFormatAttributesList.reduce(function(formats, attribute) {
  243. if (domNode.hasAttribute(attribute)) {
  244. formats[attribute] = domNode.getAttribute(attribute);
  245. }
  246. return formats;
  247. }, {});
  248. }
  249. format(name, value) {
  250. if (ImageFormatAttributesList.indexOf(name) > -1) {
  251. if (value) {
  252. this.domNode.setAttribute(name, value);
  253. } else {
  254. this.domNode.removeAttribute(name);
  255. }
  256. } else {
  257. super.format(name, value);
  258. }
  259. }
  260. }
  261. Quill.register(ImageFormat, true);
  262. const Parchment = Quill.import("parchment");
  263. const pixelLevels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
  264. const TAB_MULTIPLIER = 30
  265. class IndentAttributor extends Parchment.Attributor.Style {
  266. add(node, value) {
  267. return super.add(node, `${+value * TAB_MULTIPLIER}px`)
  268. }
  269. value(node) {
  270. return parseFloat(super.value(node)) / TAB_MULTIPLIER || undefined // Don't return NaN
  271. }
  272. }
  273. const IndentStyle = new IndentAttributor("indent", "margin-left", {
  274. scope: Parchment.Scope.BLOCK,
  275. whitelist: pixelLevels.map(value => `${value * TAB_MULTIPLIER}px`),
  276. })
  277. Quill.register({"formats/indent": IndentStyle}, true);
  278. bQuillRegistred = true;
  279. var icons = Quill.import('ui/icons');
  280. icons['embed'] = '<svg class="fr-svg" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path class="ql-fill" d="M20.73889,15.45929a3.4768,3.4768,0,0,0-5.45965-.28662L9.5661,12.50861a3.49811,3.49811,0,0,0-.00873-1.01331l5.72174-2.66809a3.55783,3.55783,0,1,0-.84527-1.81262L8.70966,9.6839a3.50851,3.50851,0,1,0,.0111,4.63727l5.7132,2.66412a3.49763,3.49763,0,1,0,6.30493-1.526ZM18.00745,5.01056A1.49993,1.49993,0,1,1,16.39551,6.3894,1.49994,1.49994,0,0,1,18.00745,5.01056ZM5.99237,13.49536a1.49989,1.49989,0,1,1,1.61194-1.37878A1.49982,1.49982,0,0,1,5.99237,13.49536Zm11.78211,5.494a1.49993,1.49993,0,1,1,1.61193-1.37885A1.49987,1.49987,0,0,1,17.77448,18.98932Z"></path></svg>';
  281. icons['show-html'] = '<svg class="fr-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path class="ql-fill" d="M162.1 257.8c-7.812-7.812-20.47-7.812-28.28 0l-48 48c-7.812 7.812-7.812 20.5 0 28.31l48 48C137.8 386.1 142.9 388 148 388s10.23-1.938 14.14-5.844c7.812-7.812 7.812-20.5 0-28.31L128.3 320l33.86-33.84C169.1 278.3 169.1 265.7 162.1 257.8zM365.3 93.38l-74.63-74.64C278.6 6.742 262.3 0 245.4 0H64C28.65 0 0 28.65 0 64l.0065 384c0 35.34 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM336 448c0 8.836-7.164 16-16 16H64.02c-8.838 0-16-7.164-16-16L48 64.13c0-8.836 7.164-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1V448zM221.9 257.8c-7.812 7.812-7.812 20.5 0 28.31L255.7 320l-33.86 33.84c-7.812 7.812-7.812 20.5 0 28.31C225.8 386.1 230.9 388 236 388s10.23-1.938 14.14-5.844l48-48c7.812-7.812 7.812-20.5 0-28.31l-48-48C242.3 250 229.7 250 221.9 257.8z"/></svg>';
  282. }
  283. var oConfig = {
  284. theme: oParams.skin,
  285. modules: {
  286. clipboard: {
  287. matchVisual: false
  288. },
  289. syntax: true,
  290. imageResize: {},
  291. toolbar: oParams.toolbar,
  292. "emoji-toolbar": true,
  293. mention: {
  294. allowedChars: /^[\S]*$/,
  295. mentionDenotationChars: ["@", "#"],
  296. showDenotationChar: true,
  297. blotName: 'menthion-link',
  298. mentionContainerClass: 'bx-popup bx-popup-trans bx-popup-border bx-popup-color-bg',
  299. mentionListClass: 'ql-mention-list bx-menu-ver',
  300. dataAttributes: ['id', 'value', 'denotationChar', 'link', 'target','disabled', 'dataProfileId'],
  301. listItemClass: 'bx-menu-item bx-def-color-bg-hl-hover',
  302. source: function (searchTerm, renderList, mentionChar) {
  303. var aFlds = oParams.query_params['fi'].split(",");
  304. aFlds.forEach(fld => {
  305. oParams.query_params[fld] = $('#' + oParams.query_params['f'] + ' [name="' + fld + '"]').val()
  306. });
  307. $.getJSON(oParams.root_url + 'searchExtended.php?action=get_mention', $.extend({}, {symbol: mentionChar, term: searchTerm}, oParams.query_params), function(data){
  308. renderList(data, searchTerm);
  309. });
  310. },
  311. renderItem: function(item, searchTerm){
  312. item.id = item.url;
  313. item.dataProfileId = item.value;
  314. item.value = item.label;
  315. return item.symbol + item.value;
  316. },
  317. onSelect: function(item, insertItem){
  318. insertItem(item, false)
  319. }
  320. },
  321. }
  322. };
  323. if (oParams.allowed_tags){
  324. oConfig.formats = oParams.allowed_tags;
  325. }
  326. if(!Quill.imports['modules/imageUploader'])
  327. Quill.register('modules/imageUploader', ImageUploader);
  328. oConfig.modules.imageUploader = {
  329. upload: file => {
  330. return new Promise((resolve, reject) => {
  331. var bProcessed = false;
  332. if (typeof glOnInsertImageInEditor !== 'undefined' && glOnInsertImageInEditor instanceof Array && glOnInsertImageInEditor.length > 0) {
  333. for (var i = 0; i < glOnInsertImageInEditor.length; i++) {
  334. if (typeof glOnInsertImageInEditor[i] === "function") {
  335. var bTmp = glOnInsertImageInEditor[i](file,oParams.selector);
  336. if (bTmp)
  337. bProcessed = true;
  338. }
  339. }
  340. if(bProcessed)
  341. reject("External uploader");
  342. }
  343. if(!bProcessed){
  344. const formData = new FormData();
  345. formData.append("file", file);
  346. fetch(oParams.root_url + "storage.php?o=sys_images_editor&t=sys_images_editor&a=upload", {
  347. method: "POST",
  348. body: formData
  349. }
  350. )
  351. .then(response => response.json())
  352. .then(result => {
  353. if ('undefined' != typeof(result.link))
  354. resolve(result.link);
  355. else
  356. reject("Upload failed");
  357. })
  358. .catch(error => {
  359. reject("Upload failed");
  360. });
  361. }
  362. });
  363. }
  364. }
  365. oEditor = new Quill('#' + oParams.name, oConfig)
  366. $(oParams.selector).next().find('button.ql-bold').attr('title', _t('_sys_txt_quill_tooltip_bold'));
  367. $(oParams.selector).next().find('button.ql-italic').attr('title', _t('_sys_txt_quill_tooltip_italic'));
  368. $(oParams.selector).next().find('button.ql-underline').attr('title', _t('_sys_txt_quill_tooltip_underline'));
  369. $(oParams.selector).next().find('button.ql-clean').attr('title', _t('_sys_txt_quill_tooltip_clean'));
  370. $(oParams.selector).next().find('button.ql-list[value = "ordered"]').attr('title', _t('_sys_txt_quill_tooltip_list_ordered'));
  371. $(oParams.selector).next().find('button.ql-list[value = "bullet"]').attr('title', _t('_sys_txt_quill_tooltip_list_bullet'));
  372. $(oParams.selector).next().find('button.ql-indent[value = "-1"]').attr('title', _t('_sys_txt_quill_tooltip_indent_1'));
  373. $(oParams.selector).next().find('button.ql-indent[value = "+1"]').attr('title', _t('_sys_txt_quill_tooltip_indent_2'));
  374. $(oParams.selector).next().find('button.ql-blockquote').attr('title', _t('_sys_txt_quill_tooltip_blockquote'));
  375. $(oParams.selector).next().find('button.ql-direction').attr('title', _t('_sys_txt_quill_tooltip_direction'));
  376. $(oParams.selector).next().find('button.ql-script[value="sub"]').attr('title', _t('_sys_txt_quill_tooltip_script_sub'));
  377. $(oParams.selector).next().find('button.ql-script[value="super"]').attr('title', _t('_sys_txt_quill_tooltip_script_super'));
  378. $(oParams.selector).next().find('button.ql-link').attr('title', _t('_sys_txt_quill_tooltip_link'));
  379. $(oParams.selector).next().find('button.ql-image').attr('title', _t('_sys_txt_quill_tooltip_image'));
  380. $(oParams.selector).next().find('button.ql-code-block').attr('title', _t('_sys_txt_quill_tooltip_code_block'));
  381. $(oParams.selector).next().find('button.ql-embed').attr('title', _t('_sys_txt_quill_tooltip_embed'));
  382. $(oParams.selector).next().find('button.ql-emoji').attr('title', _t('_sys_txt_quill_tooltip_emoji'));
  383. $(oParams.selector).next().find('button.ql-show-html').attr('title', _t('_sys_txt_quill_tooltip_show_html'));
  384. $(oParams.selector).next().find('span.ql-color .ql-picker-label').attr({'title': _t('_sys_txt_quill_tooltip_color'), 'aria-label': _t('_sys_txt_quill_tooltip_color')});
  385. $(oParams.selector).next().find('span.ql-background .ql-picker-label').attr({'title': _t('_sys_txt_quill_tooltip_background'), 'aria-label': _t('_sys_txt_quill_tooltip_background')});
  386. $(oParams.selector).next().find('span.ql-align .ql-picker-label').attr({'title': _t('_sys_txt_quill_tooltip_align'), 'aria-label': _t('_sys_txt_quill_tooltip_align')});
  387. //--- a mini toolbar renders alignment as four separate buttons rather than one picker
  388. $(oParams.selector).next().find('button.ql-align[value=""]').attr('title', _t('_sys_txt_quill_tooltip_align_left'));
  389. $(oParams.selector).next().find('button.ql-align[value="center"]').attr('title', _t('_sys_txt_quill_tooltip_align_center'));
  390. $(oParams.selector).next().find('button.ql-align[value="right"]').attr('title', _t('_sys_txt_quill_tooltip_align_right'));
  391. $(oParams.selector).next().find('button.ql-align[value="justify"]').attr('title', _t('_sys_txt_quill_tooltip_align_justify'));
  392. $(oParams.selector).next().find('span.ql-header .ql-picker-label').attr({'title': _t('_sys_txt_quill_tooltip_header'), 'aria-label': _t('_sys_txt_quill_tooltip_header')});
  393. //--- quill-mention points aria-owns at its list, but only inserts that list into the document when
  394. //--- the list opens, so the reference dangles and every page with an editor reports an invalid
  395. //--- ARIA value. The editor is not a combobox, so the attribute has nothing to say here.
  396. $('#' + oParams.name).find('.ql-editor').addClass('bx-def-vanilla-html').removeAttr('aria-owns');
  397. if (bEmptyToolbar)
  398. $(oParams.selector).next().hide();
  399. oEditor.clipboard.addMatcher (Node.TEXT_NODE, function (node, delta) {
  400. const Delta = Quill.import('delta')
  401. bx_editor_on_space_enter(node.data, oParams.selector, false);
  402. return delta;
  403. });
  404. if (oParams.insert_as_plain_text) {
  405. oEditor.clipboard.addMatcher (Node.ELEMENT_NODE, function (node, delta) {
  406. let ops = []
  407. delta.ops.forEach(op => {
  408. if (op.insert && typeof op.insert === 'string') {
  409. ops.push({
  410. insert: op.insert
  411. })
  412. }
  413. })
  414. delta.ops = ops
  415. return delta
  416. });
  417. }
  418. else{
  419. oEditor.clipboard.addMatcher (Node.ELEMENT_NODE, function (node, delta) {
  420. delta.forEach(e => {
  421. //if(typeof e.insert == 'string' && e.attributes == null)
  422. // e.insert = e.insert.replace(/\n/g, '') + "\n";
  423. if(e.attributes){
  424. e.attributes.color = '';
  425. e.attributes.background = '';
  426. }
  427. });
  428. return delta;
  429. });
  430. }
  431. oEditor.keyboard.addBinding({
  432. key: ' ',
  433. handler: function(range, context) {
  434. bx_editor_on_space_enter (oEditor.container.firstChild.innerHTML, oParams.selector);
  435. return true;
  436. }
  437. });
  438. oEditor.container.addEventListener('keydown', function(event) {
  439. if (event.key === 'Enter' || event.keyCode === 13) {
  440. bx_editor_on_space_enter (oEditor.container.firstChild.innerHTML, oParams.selector);
  441. }
  442. });
  443. oEditor.on('editor-change', function(delta, oldDelta, source) {
  444. sVal = oEditor.container.firstChild.innerHTML;
  445. if(!oParams.empty_tags){
  446. sVal = sVal.replaceAll('<p><br></p>','');
  447. }
  448. if ((oEditor.getContents()['ops'] || []).length == 1 && oEditor.getText().trim().length === 0) {
  449. sVal = ''
  450. }
  451. $(oParams.selector).val(sVal);
  452. });
  453. return oEditor
  454. }
  455. function bx_editor_activate(oEditor)
  456. {
  457. oEditor.focus();
  458. }
  459. function bx_editor_insert_html (sEditorId, sImgId, sHtml)
  460. {
  461. if ($('#' + sEditorId) && $('#' + sEditorId).attr('object_editor')) {
  462. eval ('oEditor = ' + $('#' + sEditorId).attr('object_editor'));
  463. if (oEditor.getSelection())
  464. oEditor.clipboard.dangerouslyPasteHTML(oEditor.getSelection().index, sHtml, 'api');
  465. else
  466. oEditor.clipboard.dangerouslyPasteHTML(0, sHtml, 'api');
  467. }
  468. }
  469. function bx_editor_insert_img (sEditorId, sImgId, sImgUrl, sClasses)
  470. {
  471. if ('undefined' == typeof(sClasses))
  472. sClasses = '';
  473. bx_editor_insert_html(sEditorId, sImgId, '<img id="' + sImgId + '" class="' + sClasses + '" src="' + sImgUrl + '" />')
  474. }
  475. function bx_editor_on_space_enter (sCode, sEditorId, bSpace = true)
  476. {
  477. if (typeof glBxEditorOnSpaceEnterTimer !== 'undefined')
  478. clearTimeout(glBxEditorOnSpaceEnterTimer);
  479. if (bSpace)
  480. glBxEditorOnSpaceEnterTimer = setTimeout(bx_editor_on_space_enter_in, 500, sCode, sEditorId);
  481. else
  482. bx_editor_on_space_enter_in(sCode, sEditorId);
  483. }
  484. function bx_editor_on_space_enter_in(sCode, sEditorId) {
  485. glBxEditorOnSpaceEnterTimer = undefined;
  486. if (typeof glOnSpaceEnterInEditor !== 'undefined' && glOnSpaceEnterInEditor instanceof Array) {
  487. for (var i = 0; i < glOnSpaceEnterInEditor.length; i++) {
  488. if (typeof glOnSpaceEnterInEditor[i] === "function") {
  489. glOnSpaceEnterInEditor[i](sCode, sEditorId);
  490. }
  491. }
  492. }
  493. }
  494. function bx_editor_remove_img (aEditorIds, aMarkers)
  495. {
  496. for (var i = 0; i < aEditorIds.length; i++) {
  497. var eEditor = $('#' + $('#' + aEditorIds[i]).attr('object_editor'));
  498. // delete images in html editor
  499. for (var k = 0; k < aMarkers.length; k++) {
  500. var jFiles = eEditor.find(aMarkers[k]);
  501. jFiles.each(function () {
  502. $(this).remove();
  503. });
  504. }
  505. }
  506. }
  507. /** @} */