var cledit = require('./cleditCore') var styleElts = [] function createStyleSheet(document) { var styleElt = document.createElement('style') styleElt.type = 'text/css' styleElt.innerHTML = '.cledit-section * { display: inline; }' document.head.appendChild(styleElt) styleElts.push(styleElt) } function Highlighter(editor) { var self = this cledit.Utils.createEventHooks(this) styleElts.cl_some(function (styleElt) { return editor.$document.head.contains(styleElt) }) || createStyleSheet(editor.$document) var contentElt = editor.$contentElt this.isComposing = 0 var sectionList = [] var insertBeforeSection var useBr = cledit.Utils.isWebkit var trailingNodeTag = 'div' var hiddenLfInnerHtml = '
' var lfHtml = '' + (useBr ? hiddenLfInnerHtml : '\n') + '' this.fixContent = function (modifiedSections, removedSections, noContentFix) { modifiedSections.cl_each(function (section) { section.forceHighlighting = true if (!noContentFix) { if (useBr) { section.elt.getElementsByClassName('hd-lf').cl_each(function (lfElt) { lfElt.parentNode.removeChild(lfElt) }) section.elt.getElementsByTagName('br').cl_each(function (brElt) { brElt.parentNode.replaceChild(editor.$document.createTextNode('\n'), brElt) }) } if (section.elt.textContent.slice(-1) !== '\n') { section.elt.appendChild(editor.$document.createTextNode('\n')) } } }) } this.addTrailingNode = function () { this.trailingNode = editor.$document.createElement(trailingNodeTag) contentElt.appendChild(this.trailingNode) } function Section(text) { this.text = text.text === undefined ? text : text.text this.data = text.data } Section.prototype.setElement = function (elt) { this.elt = elt elt.section = this } this.parseSections = function (content, isInit) { if (this.isComposing) { return sectionList } var newSectionList = editor.options.sectionParser ? editor.options.sectionParser(content) : [content] newSectionList = newSectionList.cl_map(function (sectionText) { return new Section(sectionText) }) var modifiedSections = [] var sectionsToRemove = [] insertBeforeSection = undefined if (isInit) { // Render everything if isInit sectionsToRemove = sectionList sectionList = newSectionList modifiedSections = newSectionList } else { // Find modified section starting from top var leftIndex = sectionList.length sectionList.cl_some(function (section, index) { var newSection = newSectionList[index] if (index >= newSectionList.length || section.forceHighlighting || // Check text modification section.text !== newSection.text || // Check that section has not been detached or moved section.elt.parentNode !== contentElt || // Check also the content since nodes can be injected in sections via copy/paste section.elt.textContent !== newSection.text) { leftIndex = index return true } }) // Find modified section starting from bottom var rightIndex = -sectionList.length sectionList.slice().reverse().cl_some(function (section, index) { var newSection = newSectionList[newSectionList.length - index - 1] if (index >= newSectionList.length || section.forceHighlighting || // Check modified section.text !== newSection.text || // Check that section has not been detached or moved section.elt.parentNode !== contentElt || // Check also the content since nodes can be injected in sections via copy/paste section.elt.textContent !== newSection.text) { rightIndex = -index return true } }) if (leftIndex - rightIndex > sectionList.length) { // Prevent overlap rightIndex = leftIndex - sectionList.length } var leftSections = sectionList.slice(0, leftIndex) modifiedSections = newSectionList.slice(leftIndex, newSectionList.length + rightIndex) var rightSections = sectionList.slice(sectionList.length + rightIndex, sectionList.length) insertBeforeSection = rightSections[0] sectionsToRemove = sectionList.slice(leftIndex, sectionList.length + rightIndex) sectionList = leftSections.concat(modifiedSections).concat(rightSections) } var newSectionEltList = editor.$document.createDocumentFragment() modifiedSections.cl_each(function (section) { section.forceHighlighting = false highlight(section) newSectionEltList.appendChild(section.elt) }) editor.watcher.noWatch(function () { if (isInit) { contentElt.innerHTML = '' contentElt.appendChild(newSectionEltList) return this.addTrailingNode() } // Remove outdated sections sectionsToRemove.cl_each(function (section) { // section may be already removed section.elt.parentNode === contentElt && contentElt.removeChild(section.elt) // To detect sections that come back with built-in undo section.elt.section = undefined }) if (insertBeforeSection !== undefined) { contentElt.insertBefore(newSectionEltList, insertBeforeSection.elt) } else { contentElt.appendChild(newSectionEltList) } // Remove unauthorized nodes (text nodes outside of sections or duplicated sections via copy/paste) var childNode = contentElt.firstChild while (childNode) { var nextNode = childNode.nextSibling if (!childNode.section) { contentElt.removeChild(childNode) } childNode = nextNode } this.addTrailingNode() self.$trigger('highlighted') editor.selectionMgr.restoreSelection() editor.selectionMgr.updateCursorCoordinates() }.cl_bind(this)) return sectionList } function highlight(section) { var html = editor.options.sectionHighlighter(section).replace(/\n/g, lfHtml) var sectionElt = editor.$document.createElement('div') sectionElt.className = 'cledit-section' sectionElt.innerHTML = html section.setElement(sectionElt) self.$trigger('sectionHighlighted', section) } } cledit.Highlighter = Highlighter