From 9196ffe7d0d658236772f76e7bbe6f67cb59e006 Mon Sep 17 00:00:00 2001 From: Alfonso Piscitelli Date: Mon, 11 Mar 2019 14:45:20 +0100 Subject: [PATCH 1/4] highlighting mentions of the users --- src/At.vue | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/At.vue b/src/At.vue index 011ff28..cd21899 100644 --- a/src/At.vue +++ b/src/At.vue @@ -71,6 +71,14 @@ export default { scrollRef: { type: String, default: '' + }, + maxLoadUsers: { + type: Number, + default: 10 + }, + enableHighlight: { + type: Boolean, + default: true } }, @@ -327,6 +335,9 @@ export default { } }, openPanel (list, range, offset, at) { + if(this.maxLoadUsers != -1) { + list = list.slice(0,this.maxLoadUsers); + } const fn = () => { const r = range.cloneRange() r.setStart(r.endContainer, offset + at.length) // 从@后第一位开始 @@ -392,6 +403,33 @@ export default { r.collapse(false) // 参数在IE下必传 applyRange(r) }, + insertMentions(text, r){ + r.deleteContents(); + var e = r.endContainer; + var chars = e.data.split(""); + var last = r.startOffset - 1; + while(chars[last] != '@' && last > -1) { + last--; + } + var after = e.data.substr(r.startOffset); + e.data = e.data.substr(0, last); + var parent = e.parentNode; + var highlightElement = document.createElement("span"); + highlightElement.innerText = text.trim(); + highlightElement.className += "mentioned"; + parent.appendChild(highlightElement); + + var space = document.createElement("span"); + space.innerHTML = "  "; + parent.appendChild(space); + r.setEndAfter(space); + + var textAfter = document.createTextNode(after); + parent.appendChild(textAfter); + this.handleInput(); + applyRange(r); + r.collapse(false); + } , insertHtml (html, r) { r.deleteContents() @@ -440,13 +478,19 @@ export default { const curItem = list[cur] if (customsEmbedded) { + console.log("ok fin qui"); // `suffix` is ignored as `customsEmbedded=true` has to be // wrapped around by spaces const html = this.$refs.embeddedItem.firstChild.innerHTML this.insertHtml(html, r); } else { - const t = itemName(curItem) + suffix - this.insertText(t, r); + const t = itemName(curItem) + suffix; + if(this.enableHighlight) { + this.insertMentions(t, r); + } else { + this.insertText(t,r); + } + } this.$emit('insert', curItem) From 20ea7f3c34aeeab7d7803068b6dd8f455aa49784 Mon Sep 17 00:00:00 2001 From: Alfonso Piscitelli Date: Wed, 13 Mar 2019 17:54:27 +0100 Subject: [PATCH 2/4] remove members property because we use another type of object (every char has its series) --- src/At.vue | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/At.vue b/src/At.vue index cd21899..e636a30 100644 --- a/src/At.vue +++ b/src/At.vue @@ -46,10 +46,6 @@ export default { type: Boolean, default: true }, - members: { - type: Array, - default: () => [] - }, nameKey: { type: String, default: '' @@ -89,12 +85,13 @@ export default { bindsValue: this.value != null, customsEmbedded: false, hasComposition: false, - atwho: null + atwho: null, + type: "" } }, computed: { atItems () { - return this.at ? [this.at] : this.ats + return this.ats.map(at => at.symbol) }, currentItem () { @@ -290,7 +287,9 @@ export default { const text = range.toString() const { at, index } = getAtAndIndex(text, atItems) - + var startedCharIndex = this.atItems.indexOf(at); + this.members = this.ats[startedCharIndex].data; + this.type = at; if (index < 0) show = false const prev = text[index - 1] @@ -478,7 +477,6 @@ export default { const curItem = list[cur] if (customsEmbedded) { - console.log("ok fin qui"); // `suffix` is ignored as `customsEmbedded=true` has to be // wrapped around by spaces const html = this.$refs.embeddedItem.firstChild.innerHTML From c4b6448247647ebde4c0e60c98fdfe4874b9bd80 Mon Sep 17 00:00:00 2001 From: Alfonso Piscitelli Date: Wed, 13 Mar 2019 17:55:26 +0100 Subject: [PATCH 3/4] remove all element mentioned --- src/At.vue | 70 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/At.vue b/src/At.vue index e636a30..6496781 100644 --- a/src/At.vue +++ b/src/At.vue @@ -170,6 +170,17 @@ export default { handleDelete (e) { const range = getPrecedingRange() if (range) { + var node = range.commonAncestorContainer.parentNode; + /** + * When you remove a char of a computed element, it is necessary remove + * all the html element. + */ + if(node.tagName == "SPAN" && node.classList.contains("at-computed")) { + node.remove(); + e.preventDefault() + e.stopPropagation() + return; + } // fixme: Very bad code from me if (this.customsEmbedded && range.endOffset >= 1) { let a = range.endContainer.childNodes[range.endOffset] @@ -402,33 +413,38 @@ export default { r.collapse(false) // 参数在IE下必传 applyRange(r) }, - insertMentions(text, r){ - r.deleteContents(); - var e = r.endContainer; - var chars = e.data.split(""); - var last = r.startOffset - 1; - while(chars[last] != '@' && last > -1) { - last--; - } - var after = e.data.substr(r.startOffset); - e.data = e.data.substr(0, last); - var parent = e.parentNode; - var highlightElement = document.createElement("span"); - highlightElement.innerText = text.trim(); - highlightElement.className += "mentioned"; - parent.appendChild(highlightElement); - - var space = document.createElement("span"); - space.innerHTML = "  "; - parent.appendChild(space); - r.setEndAfter(space); - - var textAfter = document.createTextNode(after); - parent.appendChild(textAfter); - this.handleInput(); - applyRange(r); - r.collapse(false); - } , + insertMentions(text, r) { + r.deleteContents(); + + var e = r.endContainer; + var chars = e.data.split(""); + var last = r.startOffset - 1; + + var classes = this.ats[this.atItems.indexOf(this.type)].cssClass; + while (chars[last] != this.type && last > -1) { + last--; + } + var after = e.data.substr(r.startOffset); + e.data = e.data.substr(0, last); + var parent = r.startContainer.parentElement; + while(parent.tagName!="DIV" && parent.hasAttribute("contenteditable")){ + parent = parent.parentElement; + } + var highlightElement = document.createElement("span"); + highlightElement.innerText = text.trim(); + highlightElement.className += classes; + highlightElement.classList.add("at-computed") + parent.appendChild(highlightElement); + + var space = document.createElement("span"); + space.innerHTML = "  " + after; + parent.appendChild(space); + r.setEndAfter(space); + + this.handleInput(); + applyRange(r); + r.collapse(false); + }, insertHtml (html, r) { r.deleteContents() From d36cf8210da30eb61b4fa0055eeb75c6eb389d03 Mon Sep 17 00:00:00 2001 From: Alfonso Piscitelli Date: Wed, 13 Mar 2019 17:55:44 +0100 Subject: [PATCH 4/4] implementing onlyInSet function --- src/At.vue | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/At.vue b/src/At.vue index 6496781..d8020bc 100644 --- a/src/At.vue +++ b/src/At.vue @@ -251,7 +251,8 @@ export default { } return } - if (e.keyCode === 13 || (this.tabSelect && e.keyCode === 9)) { // enter or tab + var onlyInSet = this.ats[this.atItems.indexOf(this.type)].onlyInSet + if (e.keyCode === 13 || (this.tabSelect && e.keyCode === 9) || (e.keyCode === 32 && !onlyInSet)) { // enter or tab or space if i can accept words not in the set. this.insertItem() e.preventDefault() e.stopPropagation() @@ -330,10 +331,20 @@ export default { const name = itemName(v) return filterMatch(name, chunk, at) }) + /** + * If the following property is true, the component not accept other + * different values. + */ + var onlyInSet = this.ats[this.atItems.indexOf(this.type)].onlyInSet + if(matched.length == 0 && !onlyInSet) { + matched.push({ + name: "#" + chunk + }); + } if (matched.length) { - this.openPanel(matched, range, index, at) + this.openPanel(matched, range, index, at) } else { - this.closePanel() + this.closePanel() } } }