1class wpdEditorCounter { 2 constructor(quill, options) { 3 this.quill = quill; 4 this.options = options; 5 this.commentmaxcount = options.commentmaxcount; 6 this.replymaxcount = options.replymaxcount; 7 this.commentmincount = options.commentmincount; 8 this.replymincount = options.replymincount; 9 this.container = document.getElementById('wpd-editor-char-counter-' + options.uniqueID); 10 this.submit = document.getElementById('wpd-field-submit-' + options.uniqueID); 11 quill.on('editor-change', this.update.bind(this)); 12 this.update(); 13 } 14 15 calculate() { 16 let length = this.quill.getText().length, 17 editorid = this.quill.container.id, 18 images = Array.from(document.querySelectorAll(`#${editorid} .ql-editor img`)); 19 if (images.length) { 20 images.forEach(function (img) { 21 if (img.src.match(/https\:\/\/s\.w\.org\/images\/core\/emoji/gi) !== null) { 22 length += img.alt.length; 23 } else if (img.classList.contains('wpdem-sticker')) { 24 length += img.alt.length; 25 } else { 26 length += img.src.length; 27 } 28 }); 29 } 30 return length; 31 } 32 33 update() { 34 let length = this.calculate(), 35 _length = length - 1; 36 let parentId = this.quill.container.id.substring(this.quill.container.id.lastIndexOf('-') + 1); 37 let commentmaxcount = parseInt(parentId) ? this.replymaxcount : this.commentmaxcount; 38 39 if (commentmaxcount > 0 && length >= commentmaxcount) { 40 this.quill.deleteText(commentmaxcount, length); 41 } 42 if (commentmaxcount > 0) { 43 let range = commentmaxcount - _length; 44 this.container.innerText = range >= 0 ? range : 0; 45 if (length + 10 > commentmaxcount) { 46 this.container.classList.add("error"); 47 } else { 48 this.container.classList.remove("error"); 49 } 50 } else if (this.container) { 51 this.container.remove(); 52 } 53 } 54} 55 56Quill.register('modules/counter', wpdEditorCounter); 57 58let Link = Quill.import('formats/link'); 59 60class wpdEditorLink extends Link { 61 static create(value) { 62 let node = super.create(value); 63 value = this.sanitize(value); 64 node.setAttribute('href', value); 65 let siteUrl = location.protocol + '//' + location.hostname; 66 if (value.startsWith(siteUrl) || value.charAt(0) === '#' || (value.charAt(0) === '/' && value.charAt(1) !== '/')) { 67 node.removeAttribute('target'); 68 } 69 return node; 70 } 71 72 static sanitize(url) { 73 let s_url = super.sanitize(url); 74 let protocol = s_url.slice(0, s_url.indexOf(':')); 75 if (!(s_url.charAt(0) === '#' || s_url.charAt(0) === '/') && this.PROTOCOL_WHITELIST.indexOf(protocol) === -1) { 76 s_url = 'http://' + url; 77 } 78 return s_url; 79 } 80 81} 82 83Quill.register(wpdEditorLink, true); 84 85class WpdEditor { 86 constructor() { 87 this.editorWraperPrefix = 'wpd-editor-wraper'; 88 this.textEditorContainer = 'ql-texteditor'; 89 this.textEditorPrefix = 'wc-textarea'; 90 this.editorToolbarPrefix = 'wpd-editor-toolbar'; 91 this.sourceCodeButtonName = 'sourcecode'; 92 this.spoiler = 'spoiler'; 93 this.spoilerPromtTitle = wpdiscuzAjaxObj.wc_spoiler_title; 94 this._container = ''; 95 this._uniqueid = ''; 96 this.currentEditor = null; 97 this._editors = new Map(); 98 this._handlers = new Map(); 99 this._initDefaults(); 100 } 101 102 addButtonEventHandler(name, func) { 103 this._handlers.set(name, func); 104 } 105 106 set uniqueid(value) { 107 if (value !== '' && typeof value === 'string') { 108 this._uniqueid = value; 109 } else if (value === '') { 110 this._uniqueid = this._findUniqueId(); 111 } else { 112 console.error('Incorrect uniqueid.'); 113 } 114 } 115 116 get uniqueid() { 117 return this._uniqueid; 118 } 119 120 set container(value) { 121 if (value !== '' && typeof value === 'string') { 122 this._container = value; 123 this.uniqueid = this._findUniqueId(); 124 } else { 125 console.error('Incorrect uniqueid.'); 126 } 127 } 128 129 get container() { 130 return this._container; 131 } 132 133 createEditor(container) { 134 this.container = container; 135 if (!this._editors.has(this.uniqueid)) { 136 let toolbar = `#${this.editorToolbarPrefix}-${this.uniqueid}`; 137 wpdiscuzEditorOptions.modules.toolbar = toolbar; 138 wpdiscuzEditorOptions.modules.counter.uniqueID = this.uniqueid; 139 let editor = new Quill(this.container, wpdiscuzEditorOptions); 140// editor.setContents([{insert: '\n'}]); 141 editor.on('editor-change', (eventName, ...args) => { 142 if (args[0] !== null) { 143 this.currentEditor = editor; 144 this.container = editor.container.id; 145 } 146 }); 147// editor.clipboard.addMatcher('PRE', (node, delta) => { 148// var Delta = Quill.import('delta'); 149// return new Delta([{insert: this._htmlEntities(node.innerHTML), attributes: {'code-block': true}}]); 150// }); 151 editor.clipboard.addMatcher('a', (node, delta) => {
152 if (node.getAttribute("href") === node.innerHTML) { 153 var Delta = Quill.import('delta'); 154 return new Delta([{insert: node.innerHTML}]); 155 } else { 156 return delta; 157 } 158 }); 159 160 editor.clipboard.addMatcher('img', (node, delta) => { 161 let Delta = Quill.import('delta'); 162 let src = node.getAttribute("src"); 163 if (/^data:image\/.+;base64/.test(src)) { 164 return new Delta([{insert: ''}]); 165 } else { 166 return new Delta([{insert: src}]); 167 } 168 }); 169 Array.from(document.querySelectorAll(`${toolbar} button`)).forEach((button) => { 170 button.onclick = () => { 171 this.currentEditor = editor; 172 this.container = editor.container.id; 173 let buttonName = button.dataset.wpde_button_name; 174 if (buttonName !== undefined && 175 typeof buttonName === 'string' && 176 buttonName.trim() !== '' && this._handlers.has(buttonName)) { 177 this._handlers.get(buttonName)(this.currentEditor, this.uniqueid); 178 } 179 }; 180 }); 181 this._bindTextEditor(editor); 182 this._editors.set(this.uniqueid, editor); 183 document.getElementById(`${this.editorWraperPrefix}-${this.uniqueid}`).style.display = ""; 184 } else { 185 this.currentEditor = this._editors.get(this.uniqueid); 186 } 187 let commentsCount = 0; 188 if (document.getElementsByClassName('wpd-thread-info').length) { 189 commentsCount = parseInt(document.getElementsByClassName('wpd-thread-info')[0].getAttribute('data-comments-count')); 190 } 191 let phraseKey = commentsCount ? 'wc_comment_join_text' : 'wc_be_the_first_text'; 192 this.currentEditor.root.setAttribute('data-placeholder', wpdiscuzAjaxObj.applyFilterOnPhrase(wpdiscuzEditorOptions[phraseKey], phraseKey, jQuery(container))); 193 return this.currentEditor; 194 } 195 196// _htmlEntities(str) { 197// var txt = document.createElement('textarea'); 198// txt.innerHTML = str; 199// return txt.value.replace(/<\!\-\-\?php/g, '<?php').replace(/\?\-\->/g, '?>').replace(/\-\-\->/g, '->'); 200// } 201 202 removeEditor(container) { 203 this.container = container; 204 if (this._editors.has(this.uniqueid)) { 205 this._editors.delete(this.uniqueid); 206 } 207 } 208 209 _bindTextEditor(editor) { 210 let textEditorID = `${this.textEditorPrefix}-${this.uniqueid}`, 211 textEditorHtml = document.getElementById(textEditorID); 212 if (textEditorHtml) { 213 textEditorHtml.style.cssText = "display: none;"; 214 editor.addContainer(this.textEditorContainer).appendChild(textEditorHtml); 215 } 216// if (editor.container.id.indexOf('-edit_') > 0) { 217// console.log(textEditorHtml.value); 218// editor.clipboard.dangerouslyPasteHTML(0, textEditorHtml.value); 219// editor.update(); 220// } 221 /* editor.on('text-change', (delta, oldDelta, source) => { 222 if (source === Quill.sources.USER) { 223 textEditorHtml.value = editor.root.innerHTML; 224 } 225 });*/ 226 this.currentEditor = editor; 227 } 228 229 _findUniqueId() { 230 return this.container.substring(this.container.lastIndexOf('-') + 1); 231 } 232 233 _initDefaults() { 234 this.addButtonEventHandler(this.sourceCodeButtonName, (editor) => { 235 let textEditor = document.getElementById(`${this.textEditorPrefix}-${this.uniqueid}`); 236// editor.deleteText(0, editor.getLength()); 237// editor.clipboard.dangerouslyPasteHTML(0, textEditor.value); 238 let sourceCodeWrapperBg = document.getElementById('wpd-editor-source-code-wrapper-bg'); 239 let sourceCodeWrapper = document.getElementById('wpd-editor-source-code-wrapper'); 240 let sourceCode = document.getElementById('wpd-editor-source-code'); 241 let editorUid = document.getElementById('wpd-editor-uid'); 242 sourceCodeWrapperBg.style.display = 'block'; 243 sourceCodeWrapper.style.display = 'block'; 244 editorUid.value = editor.container.id; 245 sourceCode.value = editor.root.innerHTML; 246 }); 247 this.addButtonEventHandler(this.spoiler, (editor) => { 248 let spoilerTitle = prompt(this.spoilerPromtTitle); 249 if (spoilerTitle === null) { 250 return; 251 } 252 let spoilerShortCodeLeft = ` [spoiler title="${spoilerTitle}"] `, 253 spoilerShortCodeRight = ' [/spoiler] ', 254 reng = editor.getSelection(); 255 if (reng === null) { 256 reng = { 257 index: editor.getLength() - 1, 258 length: 0 259 }; 260 } 261 if (reng.length === 0) { 262 editor.insertText(reng.index, spoilerShortCodeLeft + spoilerShortCodeRight, Quill.sources.USER); 263 editor.setSelection(reng.index + spoilerShortCodeLeft.length, Quill.sources.USER); 264 } else { 265 editor.insertText(reng.index, spoilerShortCodeLeft); 266 editor.insertText(reng.index + spoilerShortCodeLeft.length + reng.length, spoilerShortCodeRight, Quill.sources.USER); 267 editor.setSelection(reng.index + spoilerShortCodeLeft.length + reng.length + spoilerShortCodeRight.length, Quill.sources.USER); 268 } 269 }); 270 } 271}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.