New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

medium-editor-tc-mention

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

medium-editor-tc-mention - npm Package Compare versions

Comparing version 2.1.1 to 2.2.0

lib/__tests__/setup.js

6

CHANGELOG.md

@@ -0,1 +1,7 @@

<a name="2.2.0"></a>
# [2.2.0](https://github.com/tomchentw/medium-editor-tc-mention/compare/v2.1.1...v2.2.0) (2016-01-25)
<a name="2.1.1"></a>

@@ -2,0 +8,0 @@ ## [2.1.1](https://github.com/tomchentw/medium-editor-tc-mention/compare/v2.1.0...v2.1.1) (2015-11-25)

18

lib/__tests__/index.spec.js
"use strict";
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _expect = require("expect");

@@ -9,15 +7,11 @@

var _mochaJsdom = require("mocha-jsdom");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _mochaJsdom2 = _interopRequireDefault(_mochaJsdom);
describe("index", function () {
(0, _mochaJsdom2["default"])();
it("should be exported", function () {
describe("index", function describeIndex() {
it("should be exported", function it() {
var Module = require("../index");
(0, _expect2["default"])(Module["default"]).toExist();
(0, _expect2["default"])(Module.TCMention).toExist();
(0, _expect2.default)(Module.default).toExist();
(0, _expect2.default)(Module.TCMention).toExist();
});
});
}); /* eslint-disable prefer-arrow-callback */
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.TCMention = exports.LEFT_ARROW_KEYCODE = undefined;
exports.unwrapForTextNode = unwrapForTextNode;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _mediumEditor = require("medium-editor");

@@ -14,358 +13,339 @@

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function last(text) {
return text[text.length - 1];
return text[text.length - 1];
}
var LEFT_ARROW_KEYCODE = 37;
var LEFT_ARROW_KEYCODE = exports.LEFT_ARROW_KEYCODE = 37;
exports.LEFT_ARROW_KEYCODE = LEFT_ARROW_KEYCODE;
function unwrapForTextNode(el, doc) {
var parentNode = el.parentNode,
prevNode,
currentNode;
_mediumEditor2["default"].util.unwrap(el, doc);
// Merge textNode
currentNode = parentNode.lastChild;
while (prevNode = currentNode.previousSibling) {
if (3 === currentNode.nodeType && 3 === prevNode.nodeType) {
prevNode.textContent += currentNode.textContent;
parentNode.removeChild(currentNode);
}
currentNode = prevNode;
var parentNode = el.parentNode;
_mediumEditor2.default.util.unwrap(el, doc);
// Merge textNode
var currentNode = parentNode.lastChild;
var prevNode = currentNode.previousSibling;
while (prevNode) {
if (currentNode.nodeType === 3 && prevNode.nodeType === 3) {
prevNode.textContent += currentNode.textContent;
parentNode.removeChild(currentNode);
}
currentNode = prevNode;
prevNode = currentNode.previousSibling;
}
}
var TCMention = _mediumEditor2["default"].Extension.extend({
name: "mention",
var TCMention = exports.TCMention = _mediumEditor2.default.Extension.extend({
name: "mention",
/* @deprecated: use extraPanelClassName. Will remove in next major (3.0.0) release
* extraClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraClassName: "",
/* @deprecated: use extraPanelClassName. Will remove in next major (3.0.0) release
* extraClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraClassName: "",
/* @deprecated: use extraActivePanelClassName. Will remove in next major (3.0.0) release
* extraActiveClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActiveClassName: "",
/* @deprecated: use extraActivePanelClassName. Will remove in next major (3.0.0) release
* extraActiveClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActiveClassName: "",
/* extraPanelClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraPanelClassName: "",
/* extraPanelClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraPanelClassName: "",
/* extraActivePanelClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActivePanelClassName: "",
/* extraActivePanelClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActivePanelClassName: "",
extraTriggerClassNameMap: {},
extraTriggerClassNameMap: {},
extraActiveTriggerClassNameMap: {},
extraActiveTriggerClassNameMap: {},
/* tagName: [string]
*
* Element tag name that would indicate that this mention. It will have
* `medium-editor-mention-at` className applied on it.
*/
tagName: "strong",
/* tagName: [string]
*
* Element tag name that would indicate that this mention. It will have
* `medium-editor-mention-at` className applied on it.
*/
tagName: "strong",
/* renderPanelContent: [function (panelEl: dom, currentMentionText: string, selectMentionCallback: function)]
*
* Render function that used to create the content of the panel when panel is show.
*
* @params panelEl: DOM element of the panel.
*
* @params currentMentionText: Often used as query criteria. e.g. @medium
*
* @params selectMentionCallback:
* callback used in customized panel content.
*
* When called with null, it tells the Mention plugin to close the panel.
* e.g. selectMentionCallback(null);
*
* When called with text, it tells the Mention plugin that the text is selected by the user.
* e.g. selectMentionCallback("@mediumrocks")
*/
renderPanelContent: function renderPanelContent() {},
/* renderPanelContent: [
* function (panelEl: dom, currentMentionText: string, selectMentionCallback: function)
* ]
*
* Render function that used to create the content of the panel when panel is show.
*
* @params panelEl: DOM element of the panel.
*
* @params currentMentionText: Often used as query criteria. e.g. @medium
*
* @params selectMentionCallback:
* callback used in customized panel content.
*
* When called with null, it tells the Mention plugin to close the panel.
* e.g. selectMentionCallback(null);
*
* When called with text, it tells the Mention plugin that the text is selected by the user.
* e.g. selectMentionCallback("@mediumrocks")
*/
renderPanelContent: function renderPanelContent() {},
/* destroyPanelContent: [function (panelEl: dom)]
*
* Destroy function to remove any contents rendered by renderPanelContent before panelEl being removed from the document.
*
* @params panelEl: DOM element of the panel.
*/
destroyPanelContent: function destroyPanelContent() {},
/* destroyPanelContent: [function (panelEl: dom)]
*
* Destroy function to remove any contents rendered by renderPanelContent
* before panelEl being removed from the document.
*
* @params panelEl: DOM element of the panel.
*/
destroyPanelContent: function destroyPanelContent() {},
activeTriggerList: ["@"],
activeTriggerList: ["@"],
triggerClassNameMap: {
"#": "medium-editor-mention-hash",
"@": "medium-editor-mention-at"
},
triggerClassNameMap: {
"#": "medium-editor-mention-hash",
"@": "medium-editor-mention-at"
},
activeTriggerClassNameMap: {
"#": "medium-editor-mention-hash-active",
"@": "medium-editor-mention-at-active"
},
activeTriggerClassNameMap: {
"#": "medium-editor-mention-hash-active",
"@": "medium-editor-mention-at-active"
},
hideOnBlurDelay: 300,
hideOnBlurDelay: 300,
init: function init() {
this.initMentionPanel();
this.attachEventHandlers();
},
init: function init() {
this.initMentionPanel();
this.attachEventHandlers();
},
destroy: function destroy() {
if (this.mentionPanel) {
if (this.mentionPanel.parentNode) {
this.destroyPanelContent(this.mentionPanel);
this.mentionPanel.parentNode.removeChild(this.mentionPanel);
}
delete this.mentionPanel;
}
},
initMentionPanel: function initMentionPanel() {
var el = this.document.createElement("div");
destroy: function destroy() {
if (this.mentionPanel) {
if (this.mentionPanel.parentNode) {
this.destroyPanelContent(this.mentionPanel);
this.mentionPanel.parentNode.removeChild(this.mentionPanel);
}
delete this.mentionPanel;
}
},
el.classList.add("medium-editor-mention-panel");
if (this.extraPanelClassName || this.extraClassName) {
el.classList.add(this.extraPanelClassName || this.extraClassName);
}
initMentionPanel: function initMentionPanel() {
var el = this.document.createElement("div");
this.getEditorOption("elementsContainer").appendChild(el);
el.classList.add("medium-editor-mention-panel");
if (this.extraPanelClassName || this.extraClassName) {
el.classList.add(this.extraPanelClassName || this.extraClassName);
}
this.mentionPanel = el;
},
attachEventHandlers: function attachEventHandlers() {
if (this.hideOnBlurDelay !== null && this.hideOnBlurDelay !== undefined) {
// for hideOnBlurDelay, the panel should hide after blur event
this.subscribe("blur", this.handleBlur.bind(this));
// and clear out hide timeout if focus again
this.subscribe("focus", this.handleFocus.bind(this));
}
// if the editor changes its content, we have to show or hide the panel
this.subscribe("editableKeyup", this.handleKeyup.bind(this));
},
handleBlur: function handleBlur() {
var _this = this;
this.getEditorOption("elementsContainer").appendChild(el);
if (this.hideOnBlurDelay !== null && this.hideOnBlurDelay !== undefined) {
this.hideOnBlurDelayId = setTimeout(function () {
_this.hidePanel(false);
}, this.hideOnBlurDelay);
}
},
handleFocus: function handleFocus() {
if (this.hideOnBlurDelayId) {
clearTimeout(this.hideOnBlurDelayId);
this.hideOnBlurDelayId = null;
}
},
handleKeyup: function handleKeyup(event) {
var keyCode = _mediumEditor2.default.util.getKeyCode(event);
var isSpace = keyCode === _mediumEditor2.default.util.keyCode.SPACE;
this.getWordFromSelection(event.target, isSpace ? -1 : 0);
this.mentionPanel = el;
},
if (!isSpace && this.activeTriggerList.indexOf(this.trigger) !== -1 && this.word.length > 1) {
this.showPanel();
} else {
this.hidePanel(keyCode === LEFT_ARROW_KEYCODE);
}
},
hidePanel: function hidePanel(isArrowTowardsLeft) {
this.mentionPanel.classList.remove("medium-editor-mention-panel-active");
var extraActivePanelClassName = this.extraActivePanelClassName || this.extraActiveClassName;
attachEventHandlers: function attachEventHandlers() {
if (null != this.hideOnBlurDelay) {
// for hideOnBlurDelay, the panel should hide after blur event
this.subscribe("blur", this.handleBlur.bind(this));
// and clear out hide timeout if focus again
this.subscribe("focus", this.handleFocus.bind(this));
}
// if the editor changes its content, we have to show or hide the panel
this.subscribe("editableKeyup", this.handleKeyup.bind(this));
},
if (extraActivePanelClassName) {
this.mentionPanel.classList.remove(extraActivePanelClassName);
}
if (this.activeMentionAt) {
this.activeMentionAt.classList.remove(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName);
}
}
if (this.activeMentionAt) {
// http://stackoverflow.com/a/27004526/1458162
var _activeMentionAt = this.activeMentionAt;
var parentNode = _activeMentionAt.parentNode;
var previousSibling = _activeMentionAt.previousSibling;
var nextSibling = _activeMentionAt.nextSibling;
var firstChild = _activeMentionAt.firstChild;
handleBlur: function handleBlur() {
var _this = this;
var siblingNode = isArrowTowardsLeft ? previousSibling : nextSibling;
var textNode = undefined;
if (!siblingNode) {
textNode = this.document.createTextNode("");
parentNode.appendChild(textNode);
} else if (siblingNode.nodeType !== 3) {
textNode = this.document.createTextNode("");
parentNode.insertBefore(textNode, siblingNode);
} else {
textNode = siblingNode;
}
var lastEmptyWord = last(firstChild.textContent);
var hasLastEmptyWord = lastEmptyWord.trim().length === 0;
if (hasLastEmptyWord) {
var textContent = firstChild.textContent;
if (null != this.hideOnBlurDelay) {
this.hideOnBlurDelayId = setTimeout(function () {
_this.hidePanel(false);
}, this.hideOnBlurDelay);
firstChild.textContent = textContent.substr(0, textContent.length - 1);
textNode.textContent = "" + lastEmptyWord + textNode.textContent;
} else {
if (textNode.textContent.length === 0 && firstChild.textContent.length > 1) {
textNode.textContent = " ";
}
},
}
if (isArrowTowardsLeft) {
_mediumEditor2.default.selection.select(this.document, textNode, textNode.length);
} else {
_mediumEditor2.default.selection.select(this.document, textNode, Math.min(textNode.length, 1));
}
if (firstChild.textContent.length <= 1) {
// LIKE core#execAction
this.base.saveSelection();
unwrapForTextNode(this.activeMentionAt, this.document);
this.base.restoreSelection();
}
//
this.activeMentionAt = null;
}
},
getWordFromSelection: function getWordFromSelection(target, initialDiff) {
var _MediumEditor$selecti = _mediumEditor2.default.selection.getSelectionRange(this.document);
handleFocus: function handleFocus() {
if (this.hideOnBlurDelayId) {
clearTimeout(this.hideOnBlurDelayId);
this.hideOnBlurDelayId = null;
}
},
var startContainer = _MediumEditor$selecti.startContainer;
var startOffset = _MediumEditor$selecti.startOffset;
var endContainer = _MediumEditor$selecti.endContainer;
handleKeyup: function handleKeyup(event) {
var keyCode = _mediumEditor2["default"].util.getKeyCode(event);
var isSpace = keyCode === _mediumEditor2["default"].util.keyCode.SPACE;
this.getWordFromSelection(event.target, isSpace ? -1 : 0);
if (startContainer !== endContainer) {
return;
}
var textContent = startContainer.textContent;
if (!isSpace && -1 !== this.activeTriggerList.indexOf(this.trigger) && 1 < this.word.length) {
this.showPanel();
} else {
this.hidePanel(keyCode === LEFT_ARROW_KEYCODE);
}
},
function getWordPosition(position, diff) {
var prevText = textContent[position - 1];
if (prevText === null || prevText === undefined) {
return position;
} else if (prevText.trim().length === 0 || position <= 0 || textContent.length < position) {
return position;
} else {
return getWordPosition(position + diff, diff);
}
}
hidePanel: function hidePanel(isArrowTowardsLeft) {
this.mentionPanel.classList.remove("medium-editor-mention-panel-active");
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.remove(this.extraActivePanelClassName || this.extraActiveClassName);
}
if (this.activeMentionAt) {
this.activeMentionAt.classList.remove(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName);
}
}
if (this.activeMentionAt) {
// http://stackoverflow.com/a/27004526/1458162
var _activeMentionAt = this.activeMentionAt;
var parentNode = _activeMentionAt.parentNode;
var previousSibling = _activeMentionAt.previousSibling;
var nextSibling = _activeMentionAt.nextSibling;
var firstChild = _activeMentionAt.firstChild;
this.wordStart = getWordPosition(startOffset + initialDiff, -1);
this.wordEnd = getWordPosition(startOffset + initialDiff, 1) - 1;
this.word = textContent.slice(this.wordStart, this.wordEnd);
this.trigger = this.word.slice(0, 1);
this.triggerClassName = this.triggerClassNameMap[this.trigger];
this.activeTriggerClassName = this.activeTriggerClassNameMap[this.trigger];
//
this.extraTriggerClassName = this.extraTriggerClassNameMap[this.trigger];
this.extraActiveTriggerClassName = this.extraActiveTriggerClassNameMap[this.trigger];
},
showPanel: function showPanel() {
if (!this.mentionPanel.classList.contains("medium-editor-mention-panel-active")) {
this.activatePanel();
this.wrapWordInMentionAt();
}
this.positionPanel();
this.updatePanelContent();
},
activatePanel: function activatePanel() {
this.mentionPanel.classList.add("medium-editor-mention-panel-active");
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.add(this.extraActivePanelClassName || this.extraActiveClassName);
}
},
wrapWordInMentionAt: function wrapWordInMentionAt() {
var selection = this.document.getSelection();
if (!selection.rangeCount) {
return;
}
// http://stackoverflow.com/a/6328906/1458162
var range = selection.getRangeAt(0).cloneRange();
if (range.startContainer.parentNode.classList.contains(this.triggerClassName)) {
this.activeMentionAt = range.startContainer.parentNode;
} else {
var nextWordEnd = Math.min(this.wordEnd, range.startContainer.textContent.length);
range.setStart(range.startContainer, this.wordStart);
range.setEnd(range.startContainer, nextWordEnd);
// Instead, insert our own version of it.
// TODO: Not sure why, but using <span> tag doens't work here
var element = this.document.createElement(this.tagName);
element.classList.add(this.triggerClassName);
if (this.extraTriggerClassName) {
element.classList.add(this.extraTriggerClassName);
}
this.activeMentionAt = element;
//
range.surroundContents(element);
selection.removeAllRanges();
selection.addRange(range);
//
_mediumEditor2.default.selection.select(this.document, this.activeMentionAt.firstChild, this.word.length);
}
this.activeMentionAt.classList.add(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.add(this.extraActiveTriggerClassName);
}
},
positionPanel: function positionPanel() {
var _activeMentionAt$getB = this.activeMentionAt.getBoundingClientRect();
var siblingNode = isArrowTowardsLeft ? previousSibling : nextSibling;
var textNode = undefined;
if (!siblingNode) {
textNode = this.document.createTextNode("");
parentNode.appendChild(textNode);
} else if (3 !== siblingNode.nodeType) {
textNode = this.document.createTextNode("");
parentNode.insertBefore(textNode, siblingNode);
} else {
textNode = siblingNode;
}
var lastEmptyWord = last(firstChild.textContent);
var hasLastEmptyWord = 0 === lastEmptyWord.trim().length;
if (hasLastEmptyWord) {
firstChild.textContent = firstChild.textContent.substr(0, firstChild.textContent.length - 1);
textNode.textContent = "" + lastEmptyWord + textNode.textContent;
} else {
if (0 === textNode.textContent.length && 1 < firstChild.textContent.length) {
textNode.textContent = " ";
}
}
if (isArrowTowardsLeft) {
_mediumEditor2["default"].selection.select(this.document, textNode, textNode.length);
} else {
_mediumEditor2["default"].selection.select(this.document, textNode, Math.min(textNode.length, 1));
}
if (1 >= firstChild.textContent.length) {
// LIKE core#execAction
this.base.saveSelection();
unwrapForTextNode(this.activeMentionAt, this.document);
this.base.restoreSelection();
}
//
this.activeMentionAt = null;
}
},
var bottom = _activeMentionAt$getB.bottom;
var left = _activeMentionAt$getB.left;
var width = _activeMentionAt$getB.width;
var _window = this.window;
var pageXOffset = _window.pageXOffset;
var pageYOffset = _window.pageYOffset;
getWordFromSelection: function getWordFromSelection(target, initialDiff) {
var _MediumEditor$selection$getSelectionRange = _mediumEditor2["default"].selection.getSelectionRange(this.document);
var startContainer = _MediumEditor$selection$getSelectionRange.startContainer;
var startOffset = _MediumEditor$selection$getSelectionRange.startOffset;
var endContainer = _MediumEditor$selection$getSelectionRange.endContainer;
var endOffset = _MediumEditor$selection$getSelectionRange.endOffset;
if (startContainer !== endContainer) {
return;
}
var textContent = startContainer.textContent;
function getWordPosition(_x, _x2) {
var _again = true;
_function: while (_again) {
var position = _x,
diff = _x2;
_again = false;
var prevText = textContent[position - 1];
if (null == prevText || 0 === prevText.trim().length || 0 >= position || textContent.length < position) {
return position;
} else {
_x = position + diff;
_x2 = diff;
_again = true;
prevText = undefined;
continue _function;
}
}
}
this.wordStart = getWordPosition(startOffset + initialDiff, -1);
this.wordEnd = getWordPosition(startOffset + initialDiff, 1) - 1;
this.word = textContent.slice(this.wordStart, this.wordEnd);
this.trigger = this.word.slice(0, 1);
this.triggerClassName = this.triggerClassNameMap[this.trigger];
this.activeTriggerClassName = this.activeTriggerClassNameMap[this.trigger];
//
this.extraTriggerClassName = this.extraTriggerClassNameMap[this.trigger];
this.extraActiveTriggerClassName = this.extraActiveTriggerClassNameMap[this.trigger];
},
showPanel: function showPanel() {
if (!this.mentionPanel.classList.contains("medium-editor-mention-panel-active")) {
this.activatePanel();
this.wrapWordInMentionAt();
}
this.positionPanel();
this.updatePanelContent();
},
activatePanel: function activatePanel() {
this.mentionPanel.classList.add("medium-editor-mention-panel-active");
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.add(this.extraActivePanelClassName || this.extraActiveClassName);
}
},
wrapWordInMentionAt: function wrapWordInMentionAt() {
var selection = this.document.getSelection();
if (!selection.rangeCount) {
return;
}
// http://stackoverflow.com/a/6328906/1458162
var range = selection.getRangeAt(0).cloneRange();
if (range.startContainer.parentNode.classList.contains(this.triggerClassName)) {
this.activeMentionAt = range.startContainer.parentNode;
} else {
range.setStart(range.startContainer, this.wordStart);
range.setEnd(range.startContainer, Math.min(this.wordEnd, range.startContainer.textContent.length));
// Instead, insert our own version of it.
// TODO: Not sure why, but using <span> tag doens't work here
var element = this.document.createElement(this.tagName);
element.classList.add(this.triggerClassName);
if (this.extraTriggerClassName) {
element.classList.add(this.extraTriggerClassName);
}
this.activeMentionAt = element;
//
range.surroundContents(element);
selection.removeAllRanges();
selection.addRange(range);
//
_mediumEditor2["default"].selection.select(this.document, this.activeMentionAt.firstChild, this.word.length);
}
this.activeMentionAt.classList.add(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.add(this.extraActiveTriggerClassName);
}
},
positionPanel: function positionPanel() {
var _activeMentionAt$getBoundingClientRect = this.activeMentionAt.getBoundingClientRect();
var bottom = _activeMentionAt$getBoundingClientRect.bottom;
var left = _activeMentionAt$getBoundingClientRect.left;
var width = _activeMentionAt$getBoundingClientRect.width;
var _window = this.window;
var pageXOffset = _window.pageXOffset;
var pageYOffset = _window.pageYOffset;
this.mentionPanel.style.top = pageYOffset + bottom + "px";
this.mentionPanel.style.left = pageXOffset + left + width + "px";
},
updatePanelContent: function updatePanelContent() {
this.renderPanelContent(this.mentionPanel, this.word, this.handleSelectMention.bind(this));
},
handleSelectMention: function handleSelectMention(seletedText) {
if (seletedText) {
var textNode = this.activeMentionAt.firstChild;
textNode.textContent = seletedText;
_mediumEditor2["default"].selection.select(this.document, textNode, seletedText.length);
//
this.hidePanel(false);
} else {
this.hidePanel(false);
}
this.mentionPanel.style.top = pageYOffset + bottom + "px";
this.mentionPanel.style.left = pageXOffset + left + width + "px";
},
updatePanelContent: function updatePanelContent() {
this.renderPanelContent(this.mentionPanel, this.word, this.handleSelectMention.bind(this));
},
handleSelectMention: function handleSelectMention(seletedText) {
if (seletedText) {
var textNode = this.activeMentionAt.firstChild;
textNode.textContent = seletedText;
_mediumEditor2.default.selection.select(this.document, textNode, seletedText.length);
//
this.hidePanel(false);
} else {
this.hidePanel(false);
}
}
});
exports.TCMention = TCMention;
exports["default"] = TCMention;
exports.default = TCMention;

@@ -1,2 +0,2 @@

!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("MediumEditor"));else if("function"==typeof define&&define.amd)define(["MediumEditor"],e);else{var i=e("object"==typeof exports?require("MediumEditor"):t.MediumEditor);for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}(this,function(t){return function(t){function e(n){if(i[n])return i[n].exports;var a=i[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function a(t){return t[t.length-1]}function s(t,e){var i,n,a=t.parentNode;for(o["default"].util.unwrap(t,e),n=a.lastChild;i=n.previousSibling;)3===n.nodeType&&3===i.nodeType&&(i.textContent+=n.textContent,a.removeChild(n)),n=i}Object.defineProperty(e,"__esModule",{value:!0}),e.unwrapForTextNode=s;var r=i(1),o=n(r),l=37;e.LEFT_ARROW_KEYCODE=l;var h=o["default"].Extension.extend({name:"mention",extraClassName:"",extraActiveClassName:"",extraPanelClassName:"",extraActivePanelClassName:"",extraTriggerClassNameMap:{},extraActiveTriggerClassNameMap:{},tagName:"strong",renderPanelContent:function(){},destroyPanelContent:function(){},activeTriggerList:["@"],triggerClassNameMap:{"#":"medium-editor-mention-hash","@":"medium-editor-mention-at"},activeTriggerClassNameMap:{"#":"medium-editor-mention-hash-active","@":"medium-editor-mention-at-active"},hideOnBlurDelay:300,init:function(){this.initMentionPanel(),this.attachEventHandlers()},destroy:function(){this.mentionPanel&&(this.mentionPanel.parentNode&&(this.destroyPanelContent(this.mentionPanel),this.mentionPanel.parentNode.removeChild(this.mentionPanel)),delete this.mentionPanel)},initMentionPanel:function(){var t=this.document.createElement("div");t.classList.add("medium-editor-mention-panel"),(this.extraPanelClassName||this.extraClassName)&&t.classList.add(this.extraPanelClassName||this.extraClassName),this.getEditorOption("elementsContainer").appendChild(t),this.mentionPanel=t},attachEventHandlers:function(){null!=this.hideOnBlurDelay&&(this.subscribe("blur",this.handleBlur.bind(this)),this.subscribe("focus",this.handleFocus.bind(this))),this.subscribe("editableKeyup",this.handleKeyup.bind(this))},handleBlur:function(){var t=this;null!=this.hideOnBlurDelay&&(this.hideOnBlurDelayId=setTimeout(function(){t.hidePanel(!1)},this.hideOnBlurDelay))},handleFocus:function(){this.hideOnBlurDelayId&&(clearTimeout(this.hideOnBlurDelayId),this.hideOnBlurDelayId=null)},handleKeyup:function(t){var e=o["default"].util.getKeyCode(t),i=e===o["default"].util.keyCode.SPACE;this.getWordFromSelection(t.target,i?-1:0),!i&&-1!==this.activeTriggerList.indexOf(this.trigger)&&1<this.word.length?this.showPanel():this.hidePanel(e===l)},hidePanel:function(t){if(this.mentionPanel.classList.remove("medium-editor-mention-panel-active"),(this.extraActivePanelClassName||this.extraActiveClassName)&&this.mentionPanel.classList.remove(this.extraActivePanelClassName||this.extraActiveClassName),this.activeMentionAt&&(this.activeMentionAt.classList.remove(this.activeTriggerClassName),this.extraActiveTriggerClassName&&this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName)),this.activeMentionAt){var e=this.activeMentionAt,i=e.parentNode,n=e.previousSibling,r=e.nextSibling,l=e.firstChild,h=t?n:r,d=void 0;h?3!==h.nodeType?(d=this.document.createTextNode(""),i.insertBefore(d,h)):d=h:(d=this.document.createTextNode(""),i.appendChild(d));var c=a(l.textContent),m=0===c.trim().length;m?(l.textContent=l.textContent.substr(0,l.textContent.length-1),d.textContent=""+c+d.textContent):0===d.textContent.length&&1<l.textContent.length&&(d.textContent=" "),t?o["default"].selection.select(this.document,d,d.length):o["default"].selection.select(this.document,d,Math.min(d.length,1)),1>=l.textContent.length&&(this.base.saveSelection(),s(this.activeMentionAt,this.document),this.base.restoreSelection()),this.activeMentionAt=null}},getWordFromSelection:function(t,e){function i(t,e){for(var i=!0;i;){var n=t,a=e;i=!1;var s=l[n-1];if(null==s||0===s.trim().length||0>=n||l.length<n)return n;t=n+a,e=a,i=!0,s=void 0}}var n=o["default"].selection.getSelectionRange(this.document),a=n.startContainer,s=n.startOffset,r=n.endContainer;n.endOffset;if(a===r){var l=a.textContent;this.wordStart=i(s+e,-1),this.wordEnd=i(s+e,1)-1,this.word=l.slice(this.wordStart,this.wordEnd),this.trigger=this.word.slice(0,1),this.triggerClassName=this.triggerClassNameMap[this.trigger],this.activeTriggerClassName=this.activeTriggerClassNameMap[this.trigger],this.extraTriggerClassName=this.extraTriggerClassNameMap[this.trigger],this.extraActiveTriggerClassName=this.extraActiveTriggerClassNameMap[this.trigger]}},showPanel:function(){this.mentionPanel.classList.contains("medium-editor-mention-panel-active")||(this.activatePanel(),this.wrapWordInMentionAt()),this.positionPanel(),this.updatePanelContent()},activatePanel:function(){this.mentionPanel.classList.add("medium-editor-mention-panel-active"),(this.extraActivePanelClassName||this.extraActiveClassName)&&this.mentionPanel.classList.add(this.extraActivePanelClassName||this.extraActiveClassName)},wrapWordInMentionAt:function(){var t=this.document.getSelection();if(t.rangeCount){var e=t.getRangeAt(0).cloneRange();if(e.startContainer.parentNode.classList.contains(this.triggerClassName))this.activeMentionAt=e.startContainer.parentNode;else{e.setStart(e.startContainer,this.wordStart),e.setEnd(e.startContainer,Math.min(this.wordEnd,e.startContainer.textContent.length));var i=this.document.createElement(this.tagName);i.classList.add(this.triggerClassName),this.extraTriggerClassName&&i.classList.add(this.extraTriggerClassName),this.activeMentionAt=i,e.surroundContents(i),t.removeAllRanges(),t.addRange(e),o["default"].selection.select(this.document,this.activeMentionAt.firstChild,this.word.length)}this.activeMentionAt.classList.add(this.activeTriggerClassName),this.extraActiveTriggerClassName&&this.activeMentionAt.classList.add(this.extraActiveTriggerClassName)}},positionPanel:function(){var t=this.activeMentionAt.getBoundingClientRect(),e=t.bottom,i=t.left,n=t.width,a=this.window,s=a.pageXOffset,r=a.pageYOffset;this.mentionPanel.style.top=r+e+"px",this.mentionPanel.style.left=s+i+n+"px"},updatePanelContent:function(){this.renderPanelContent(this.mentionPanel,this.word,this.handleSelectMention.bind(this))},handleSelectMention:function(t){if(t){var e=this.activeMentionAt.firstChild;e.textContent=t,o["default"].selection.select(this.document,e,t.length),this.hidePanel(!1)}else this.hidePanel(!1)}});e.TCMention=h,e["default"]=h},function(e,i){e.exports=t}])});
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("MediumEditor"));else if("function"==typeof define&&define.amd)define(["MediumEditor"],e);else{var i=e("object"==typeof exports?require("MediumEditor"):t.MediumEditor);for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}(this,function(t){return function(t){function e(n){if(i[n])return i[n].exports;var a=i[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function a(t){return t[t.length-1]}function s(t,e){var i=t.parentNode;o["default"].util.unwrap(t,e);for(var n=i.lastChild,a=n.previousSibling;a;)3===n.nodeType&&3===a.nodeType&&(a.textContent+=n.textContent,i.removeChild(n)),n=a,a=n.previousSibling}Object.defineProperty(e,"__esModule",{value:!0}),e.TCMention=e.LEFT_ARROW_KEYCODE=void 0,e.unwrapForTextNode=s;var r=i(1),o=n(r),l=e.LEFT_ARROW_KEYCODE=37,h=e.TCMention=o["default"].Extension.extend({name:"mention",extraClassName:"",extraActiveClassName:"",extraPanelClassName:"",extraActivePanelClassName:"",extraTriggerClassNameMap:{},extraActiveTriggerClassNameMap:{},tagName:"strong",renderPanelContent:function(){},destroyPanelContent:function(){},activeTriggerList:["@"],triggerClassNameMap:{"#":"medium-editor-mention-hash","@":"medium-editor-mention-at"},activeTriggerClassNameMap:{"#":"medium-editor-mention-hash-active","@":"medium-editor-mention-at-active"},hideOnBlurDelay:300,init:function(){this.initMentionPanel(),this.attachEventHandlers()},destroy:function(){this.mentionPanel&&(this.mentionPanel.parentNode&&(this.destroyPanelContent(this.mentionPanel),this.mentionPanel.parentNode.removeChild(this.mentionPanel)),delete this.mentionPanel)},initMentionPanel:function(){var t=this.document.createElement("div");t.classList.add("medium-editor-mention-panel"),(this.extraPanelClassName||this.extraClassName)&&t.classList.add(this.extraPanelClassName||this.extraClassName),this.getEditorOption("elementsContainer").appendChild(t),this.mentionPanel=t},attachEventHandlers:function(){null!==this.hideOnBlurDelay&&void 0!==this.hideOnBlurDelay&&(this.subscribe("blur",this.handleBlur.bind(this)),this.subscribe("focus",this.handleFocus.bind(this))),this.subscribe("editableKeyup",this.handleKeyup.bind(this))},handleBlur:function(){var t=this;null!==this.hideOnBlurDelay&&void 0!==this.hideOnBlurDelay&&(this.hideOnBlurDelayId=setTimeout(function(){t.hidePanel(!1)},this.hideOnBlurDelay))},handleFocus:function(){this.hideOnBlurDelayId&&(clearTimeout(this.hideOnBlurDelayId),this.hideOnBlurDelayId=null)},handleKeyup:function(t){var e=o["default"].util.getKeyCode(t),i=e===o["default"].util.keyCode.SPACE;this.getWordFromSelection(t.target,i?-1:0),!i&&-1!==this.activeTriggerList.indexOf(this.trigger)&&this.word.length>1?this.showPanel():this.hidePanel(e===l)},hidePanel:function(t){this.mentionPanel.classList.remove("medium-editor-mention-panel-active");var e=this.extraActivePanelClassName||this.extraActiveClassName;if(e&&this.mentionPanel.classList.remove(e),this.activeMentionAt&&(this.activeMentionAt.classList.remove(this.activeTriggerClassName),this.extraActiveTriggerClassName&&this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName)),this.activeMentionAt){var i=this.activeMentionAt,n=i.parentNode,r=i.previousSibling,l=i.nextSibling,h=i.firstChild,d=t?r:l,c=void 0;d?3!==d.nodeType?(c=this.document.createTextNode(""),n.insertBefore(c,d)):c=d:(c=this.document.createTextNode(""),n.appendChild(c));var u=a(h.textContent),m=0===u.trim().length;if(m){var g=h.textContent;h.textContent=g.substr(0,g.length-1),c.textContent=""+u+c.textContent}else 0===c.textContent.length&&h.textContent.length>1&&(c.textContent=" ");t?o["default"].selection.select(this.document,c,c.length):o["default"].selection.select(this.document,c,Math.min(c.length,1)),h.textContent.length<=1&&(this.base.saveSelection(),s(this.activeMentionAt,this.document),this.base.restoreSelection()),this.activeMentionAt=null}},getWordFromSelection:function(t,e){function i(t,e){var n=l[t-1];return null===n||void 0===n?t:0===n.trim().length||0>=t||l.length<t?t:i(t+e,e)}var n=o["default"].selection.getSelectionRange(this.document),a=n.startContainer,s=n.startOffset,r=n.endContainer;if(a===r){var l=a.textContent;this.wordStart=i(s+e,-1),this.wordEnd=i(s+e,1)-1,this.word=l.slice(this.wordStart,this.wordEnd),this.trigger=this.word.slice(0,1),this.triggerClassName=this.triggerClassNameMap[this.trigger],this.activeTriggerClassName=this.activeTriggerClassNameMap[this.trigger],this.extraTriggerClassName=this.extraTriggerClassNameMap[this.trigger],this.extraActiveTriggerClassName=this.extraActiveTriggerClassNameMap[this.trigger]}},showPanel:function(){this.mentionPanel.classList.contains("medium-editor-mention-panel-active")||(this.activatePanel(),this.wrapWordInMentionAt()),this.positionPanel(),this.updatePanelContent()},activatePanel:function(){this.mentionPanel.classList.add("medium-editor-mention-panel-active"),(this.extraActivePanelClassName||this.extraActiveClassName)&&this.mentionPanel.classList.add(this.extraActivePanelClassName||this.extraActiveClassName)},wrapWordInMentionAt:function(){var t=this.document.getSelection();if(t.rangeCount){var e=t.getRangeAt(0).cloneRange();if(e.startContainer.parentNode.classList.contains(this.triggerClassName))this.activeMentionAt=e.startContainer.parentNode;else{var i=Math.min(this.wordEnd,e.startContainer.textContent.length);e.setStart(e.startContainer,this.wordStart),e.setEnd(e.startContainer,i);var n=this.document.createElement(this.tagName);n.classList.add(this.triggerClassName),this.extraTriggerClassName&&n.classList.add(this.extraTriggerClassName),this.activeMentionAt=n,e.surroundContents(n),t.removeAllRanges(),t.addRange(e),o["default"].selection.select(this.document,this.activeMentionAt.firstChild,this.word.length)}this.activeMentionAt.classList.add(this.activeTriggerClassName),this.extraActiveTriggerClassName&&this.activeMentionAt.classList.add(this.extraActiveTriggerClassName)}},positionPanel:function(){var t=this.activeMentionAt.getBoundingClientRect(),e=t.bottom,i=t.left,n=t.width,a=this.window,s=a.pageXOffset,r=a.pageYOffset;this.mentionPanel.style.top=r+e+"px",this.mentionPanel.style.left=s+i+n+"px"},updatePanelContent:function(){this.renderPanelContent(this.mentionPanel,this.word,this.handleSelectMention.bind(this))},handleSelectMention:function(t){if(t){var e=this.activeMentionAt.firstChild;e.textContent=t,o["default"].selection.select(this.document,e,t.length),this.hidePanel(!1)}else this.hidePanel(!1)}});e["default"]=h},function(e,i){e.exports=t}])});
//# sourceMappingURL=index.min.js.map
{
"name": "medium-editor-tc-mention",
"version": "2.1.1",
"version": "2.2.0",
"description": "MediumEditor extension for mention panels like @username or #tagging",

@@ -14,14 +14,15 @@ "main": "lib/index.js",

"prebuild": "npm run lint && npm run clean",
"build:babel": "babel src --out-dir lib",
"build:webpack": "webpack -p && rimraf lib/mention-panel.min.js lib/mention-panel.min.js.map lib/mention-panel.min.css.map",
"build:babel": "cross-env NODE_ENV=production babel src --out-dir lib",
"build:webpack": "cross-env NODE_ENV=production webpack --config webpack.config.babel.js -p",
"postbuild:webpack": "rimraf lib/mention-panel.min.js lib/mention-panel.min.js.map lib/mention-panel.min.css.map",
"build": "npm run build:babel && npm run build:webpack",
"lint": "eslint src",
"lint": "cross-env NODE_ENV=test eslint src",
"pretest:cov": "npm run lint",
"pretest": "npm run lint",
"test:cov": "babel-node ./node_modules/.bin/isparta cover --report lcov _mocha -- $npm_package_config_mocha",
"test:cov": "cross-env NODE_ENV=test babel-node ./node_modules/.bin/isparta cover --report lcov _mocha -- $npm_package_config_mocha",
"test:watch": "npm test -- --watch",
"test": "mocha $npm_package_config_mocha"
"test": "cross-env NODE_ENV=test mocha $npm_package_config_mocha"
},
"config": {
"mocha": "--compilers js:babel/register ./src/**/__tests__/*.spec.js"
"mocha": "--compilers js:babel-register ./src/**/__tests__/*.spec.js --require ./src/__tests__/setup.js"
},

@@ -52,22 +53,31 @@ "repository": {

"devDependencies": {
"babel": "^5.8.23",
"babel-core": "^5.8.25",
"babel-eslint": "^4.1.3",
"babel-loader": "^5.3.2",
"codeclimate-test-reporter": "^0.1.1",
"css-loader": "^0.19.0",
"eslint": "^1.6.0",
"expect": "^1.12.2",
"extract-text-webpack-plugin": "^0.8.2",
"isparta": "^3.1.0",
"istanbul": "^0.3.22",
"jsdom": "^6.5.1",
"medium-editor": "^5.8.3",
"mocha": "^2.3.3",
"mocha-jsdom": "^1.0.0",
"node-sass": "^3.3.3",
"rimraf": "^2.4.3",
"sass-loader": "^3.0.0",
"style-loader": "^0.12.4",
"webpack": "^1.12.2"
"babel-cli": "^6.4.5",
"babel-core": "^6.4.5",
"babel-eslint": "^5.0.0-beta6",
"babel-loader": "^6.2.1",
"babel-plugin-transform-flow-comments": "^6.4.0",
"babel-plugin-typecheck": "^3.6.1",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.3.13",
"babel-register": "^6.4.3",
"codeclimate-test-reporter": "^0.3.0",
"cross-env": "^1.0.7",
"css-loader": "^0.23.1",
"eslint": "^1.10.3",
"eslint-config-airbnb": "^4.0.0",
"eslint-plugin-react": "^3.16.1",
"expect": "^1.13.4",
"extract-text-webpack-plugin": "^1.0.1",
"isparta": "^4.0.0",
"istanbul": "^0.4.2",
"jsdom": "^7.2.2",
"medium-editor": "^5.13.0",
"mocha": "^2.3.4",
"node-sass": "^3.4.2",
"rimraf": "^2.5.1",
"sass-loader": "^3.1.2",
"style-loader": "^0.13.0",
"tomchentw-npm-dev": "^3.2.0",
"webpack": "^1.12.12"
},

@@ -74,0 +84,0 @@ "dependencies": {},

@@ -0,1 +1,3 @@

/* eslint-disable prefer-arrow-callback */
import {

@@ -5,12 +7,6 @@ default as expect,

import {
default as jsdom,
} from "mocha-jsdom";
describe(`index`, function describeIndex() {
it(`should be exported`, function it() {
const Module = require(`../index`);
describe("index", () => {
jsdom();
it("should be exported", () => {
const Module = require("../index");
expect(Module.default).toExist();

@@ -17,0 +13,0 @@ expect(Module.TCMention).toExist();

@@ -1,5 +0,7 @@

import MediumEditor from "medium-editor";
import {
default as MediumEditor,
} from "medium-editor";
function last (text) {
return text[text.length - 1];
function last(text) {
return text[text.length - 1];
}

@@ -9,318 +11,335 @@

export function unwrapForTextNode (el, doc) {
var parentNode = el.parentNode,
prevNode,
currentNode;
MediumEditor.util.unwrap(el, doc);
export function unwrapForTextNode(el, doc) {
const parentNode = el.parentNode;
MediumEditor.util.unwrap(el, doc);
// Merge textNode
currentNode = parentNode.lastChild;
while (prevNode = currentNode.previousSibling) {
if (3 === currentNode.nodeType && 3 === prevNode.nodeType) {
prevNode.textContent += currentNode.textContent;
parentNode.removeChild(currentNode);
}
currentNode = prevNode;
let currentNode = parentNode.lastChild;
let prevNode = currentNode.previousSibling;
while (prevNode) {
if (currentNode.nodeType === 3 && prevNode.nodeType === 3) {
prevNode.textContent += currentNode.textContent;
parentNode.removeChild(currentNode);
}
currentNode = prevNode;
prevNode = currentNode.previousSibling;
}
}
export const TCMention = MediumEditor.Extension.extend({
name: `mention`,
name: `mention`,
/* @deprecated: use extraPanelClassName. Will remove in next major (3.0.0) release
* extraClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraClassName: ``,
/* @deprecated: use extraPanelClassName. Will remove in next major (3.0.0) release
* extraClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraClassName: ``,
/* @deprecated: use extraActivePanelClassName. Will remove in next major (3.0.0) release
* extraActiveClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActiveClassName: ``,
/* @deprecated: use extraActivePanelClassName. Will remove in next major (3.0.0) release
* extraActiveClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActiveClassName: ``,
/* extraPanelClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraPanelClassName: ``,
/* extraPanelClassName: [string]
*
* Extra className to be added with the `medium-editor-mention-panel` element.
*/
extraPanelClassName: ``,
/* extraActivePanelClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActivePanelClassName: ``,
/* extraActivePanelClassName: [string]
*
* Extra active className to be added with the `medium-editor-mention-panel-active` element.
*/
extraActivePanelClassName: ``,
extraTriggerClassNameMap: {},
extraTriggerClassNameMap: {},
extraActiveTriggerClassNameMap: {},
extraActiveTriggerClassNameMap: {},
/* tagName: [string]
*
* Element tag name that would indicate that this mention. It will have
* `medium-editor-mention-at` className applied on it.
*/
tagName: `strong`,
/* tagName: [string]
*
* Element tag name that would indicate that this mention. It will have
* `medium-editor-mention-at` className applied on it.
*/
tagName: `strong`,
/* renderPanelContent: [function (panelEl: dom, currentMentionText: string, selectMentionCallback: function)]
*
* Render function that used to create the content of the panel when panel is show.
*
* @params panelEl: DOM element of the panel.
*
* @params currentMentionText: Often used as query criteria. e.g. @medium
*
* @params selectMentionCallback:
* callback used in customized panel content.
*
* When called with null, it tells the Mention plugin to close the panel.
* e.g. selectMentionCallback(null);
*
* When called with text, it tells the Mention plugin that the text is selected by the user.
* e.g. selectMentionCallback("@mediumrocks")
*/
renderPanelContent: () => {},
/* renderPanelContent: [
* function (panelEl: dom, currentMentionText: string, selectMentionCallback: function)
* ]
*
* Render function that used to create the content of the panel when panel is show.
*
* @params panelEl: DOM element of the panel.
*
* @params currentMentionText: Often used as query criteria. e.g. @medium
*
* @params selectMentionCallback:
* callback used in customized panel content.
*
* When called with null, it tells the Mention plugin to close the panel.
* e.g. selectMentionCallback(null);
*
* When called with text, it tells the Mention plugin that the text is selected by the user.
* e.g. selectMentionCallback("@mediumrocks")
*/
renderPanelContent() {},
/* destroyPanelContent: [function (panelEl: dom)]
*
* Destroy function to remove any contents rendered by renderPanelContent before panelEl being removed from the document.
*
* @params panelEl: DOM element of the panel.
*/
destroyPanelContent: () => {},
/* destroyPanelContent: [function (panelEl: dom)]
*
* Destroy function to remove any contents rendered by renderPanelContent
* before panelEl being removed from the document.
*
* @params panelEl: DOM element of the panel.
*/
destroyPanelContent() {},
activeTriggerList: [`@`],
activeTriggerList: [`@`],
triggerClassNameMap: {
"#": `medium-editor-mention-hash`,
"@": `medium-editor-mention-at`,
},
triggerClassNameMap: {
"#": `medium-editor-mention-hash`,
"@": `medium-editor-mention-at`,
},
activeTriggerClassNameMap: {
"#": `medium-editor-mention-hash-active`,
"@": `medium-editor-mention-at-active`,
},
activeTriggerClassNameMap: {
"#": `medium-editor-mention-hash-active`,
"@": `medium-editor-mention-at-active`,
},
hideOnBlurDelay: 300,
hideOnBlurDelay: 300,
init () {
this.initMentionPanel();
this.attachEventHandlers();
},
init() {
this.initMentionPanel();
this.attachEventHandlers();
},
destroy () {
if (this.mentionPanel) {
if (this.mentionPanel.parentNode) {
this.destroyPanelContent(this.mentionPanel);
this.mentionPanel.parentNode.removeChild(this.mentionPanel);
}
delete this.mentionPanel;
}
},
destroy() {
if (this.mentionPanel) {
if (this.mentionPanel.parentNode) {
this.destroyPanelContent(this.mentionPanel);
this.mentionPanel.parentNode.removeChild(this.mentionPanel);
}
delete this.mentionPanel;
}
},
initMentionPanel () {
const el = this.document.createElement(`div`);
initMentionPanel() {
const el = this.document.createElement(`div`);
el.classList.add(`medium-editor-mention-panel`);
if (this.extraPanelClassName || this.extraClassName) {
el.classList.add(this.extraPanelClassName || this.extraClassName);
}
el.classList.add(`medium-editor-mention-panel`);
if (this.extraPanelClassName || this.extraClassName) {
el.classList.add(this.extraPanelClassName || this.extraClassName);
}
this.getEditorOption(`elementsContainer`).appendChild(el);
this.getEditorOption(`elementsContainer`).appendChild(el);
this.mentionPanel = el;
},
this.mentionPanel = el;
},
attachEventHandlers () {
if (null != this.hideOnBlurDelay) {
// for hideOnBlurDelay, the panel should hide after blur event
this.subscribe(`blur`, ::this.handleBlur);
// and clear out hide timeout if focus again
this.subscribe(`focus`, ::this.handleFocus);
}
// if the editor changes its content, we have to show or hide the panel
this.subscribe(`editableKeyup`, ::this.handleKeyup);
},
attachEventHandlers() {
if (this.hideOnBlurDelay !== null && this.hideOnBlurDelay !== undefined) {
// for hideOnBlurDelay, the panel should hide after blur event
this.subscribe(`blur`, ::this.handleBlur);
// and clear out hide timeout if focus again
this.subscribe(`focus`, ::this.handleFocus);
}
// if the editor changes its content, we have to show or hide the panel
this.subscribe(`editableKeyup`, ::this.handleKeyup);
},
handleBlur () {
if (null != this.hideOnBlurDelay) {
this.hideOnBlurDelayId = setTimeout(() => {
this.hidePanel(false);
}, this.hideOnBlurDelay);
}
},
handleBlur() {
if (this.hideOnBlurDelay !== null && this.hideOnBlurDelay !== undefined) {
this.hideOnBlurDelayId = setTimeout(() => {
this.hidePanel(false);
}, this.hideOnBlurDelay);
}
},
handleFocus () {
if (this.hideOnBlurDelayId) {
clearTimeout(this.hideOnBlurDelayId);
this.hideOnBlurDelayId = null;
}
},
handleFocus() {
if (this.hideOnBlurDelayId) {
clearTimeout(this.hideOnBlurDelayId);
this.hideOnBlurDelayId = null;
}
},
handleKeyup (event) {
const keyCode = MediumEditor.util.getKeyCode(event);
const isSpace = keyCode === MediumEditor.util.keyCode.SPACE;
this.getWordFromSelection(event.target, isSpace ? -1 : 0);
handleKeyup(event) {
const keyCode = MediumEditor.util.getKeyCode(event);
const isSpace = keyCode === MediumEditor.util.keyCode.SPACE;
this.getWordFromSelection(event.target, isSpace ? -1 : 0);
if (!isSpace && -1 !== this.activeTriggerList.indexOf(this.trigger) && 1 < this.word.length) {
this.showPanel();
} else {
this.hidePanel(keyCode === LEFT_ARROW_KEYCODE);
}
},
if (!isSpace && this.activeTriggerList.indexOf(this.trigger) !== -1 && this.word.length > 1) {
this.showPanel();
} else {
this.hidePanel(keyCode === LEFT_ARROW_KEYCODE);
}
},
hidePanel (isArrowTowardsLeft) {
this.mentionPanel.classList.remove(`medium-editor-mention-panel-active`);
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.remove(this.extraActivePanelClassName || this.extraActiveClassName);
}
if (this.activeMentionAt) {
this.activeMentionAt.classList.remove(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName);
}
}
if (this.activeMentionAt) {
// http://stackoverflow.com/a/27004526/1458162
const {parentNode, previousSibling, nextSibling, firstChild} = this.activeMentionAt;
const siblingNode = isArrowTowardsLeft ? previousSibling : nextSibling;
let textNode;
if (!siblingNode) {
textNode = this.document.createTextNode(``);
parentNode.appendChild(textNode);
} else if (3 !== siblingNode.nodeType) {
textNode = this.document.createTextNode(``);
parentNode.insertBefore(textNode, siblingNode);
} else {
textNode = siblingNode;
}
const lastEmptyWord = last(firstChild.textContent);
const hasLastEmptyWord = 0 === lastEmptyWord.trim().length;
if (hasLastEmptyWord) {
firstChild.textContent = firstChild.textContent.substr(0, firstChild.textContent.length-1);
textNode.textContent = `${ lastEmptyWord }${ textNode.textContent }`;
} else {
if (0 === textNode.textContent.length && 1 < firstChild.textContent.length) {
textNode.textContent = `\u00A0`;
}
}
if (isArrowTowardsLeft) {
MediumEditor.selection.select(this.document, textNode, textNode.length);
} else {
MediumEditor.selection.select(this.document, textNode, Math.min(textNode.length, 1));
}
if (1 >= firstChild.textContent.length) {
// LIKE core#execAction
this.base.saveSelection();
unwrapForTextNode(this.activeMentionAt, this.document);
this.base.restoreSelection();
}
//
this.activeMentionAt = null;
}
},
hidePanel(isArrowTowardsLeft) {
this.mentionPanel.classList.remove(`medium-editor-mention-panel-active`);
const extraActivePanelClassName = this.extraActivePanelClassName || this.extraActiveClassName;
getWordFromSelection (target, initialDiff) {
const {startContainer, startOffset, endContainer, endOffset} = MediumEditor.selection.getSelectionRange(this.document);
if (startContainer !== endContainer) {
return;
if (extraActivePanelClassName) {
this.mentionPanel.classList.remove(extraActivePanelClassName);
}
if (this.activeMentionAt) {
this.activeMentionAt.classList.remove(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.remove(this.extraActiveTriggerClassName);
}
}
if (this.activeMentionAt) {
// http://stackoverflow.com/a/27004526/1458162
const { parentNode, previousSibling, nextSibling, firstChild } = this.activeMentionAt;
const siblingNode = isArrowTowardsLeft ? previousSibling : nextSibling;
let textNode;
if (!siblingNode) {
textNode = this.document.createTextNode(``);
parentNode.appendChild(textNode);
} else if (siblingNode.nodeType !== 3) {
textNode = this.document.createTextNode(``);
parentNode.insertBefore(textNode, siblingNode);
} else {
textNode = siblingNode;
}
const lastEmptyWord = last(firstChild.textContent);
const hasLastEmptyWord = lastEmptyWord.trim().length === 0;
if (hasLastEmptyWord) {
const { textContent } = firstChild;
firstChild.textContent = textContent.substr(0, textContent.length - 1);
textNode.textContent = `${ lastEmptyWord }${ textNode.textContent }`;
} else {
if (textNode.textContent.length === 0 && firstChild.textContent.length > 1) {
textNode.textContent = `\u00A0`;
}
const {textContent} = startContainer;
}
if (isArrowTowardsLeft) {
MediumEditor.selection.select(this.document, textNode, textNode.length);
} else {
MediumEditor.selection.select(this.document, textNode, Math.min(textNode.length, 1));
}
if (firstChild.textContent.length <= 1) {
// LIKE core#execAction
this.base.saveSelection();
unwrapForTextNode(this.activeMentionAt, this.document);
this.base.restoreSelection();
}
//
this.activeMentionAt = null;
}
},
function getWordPosition (position, diff) {
const prevText = textContent[position - 1];
if (null == prevText || 0 === prevText.trim().length || 0 >= position || textContent.length < position) {
return position;
} else {
return getWordPosition(position + diff, diff);
}
}
getWordFromSelection(target, initialDiff) {
const {
startContainer,
startOffset,
endContainer,
} = MediumEditor.selection.getSelectionRange(this.document);
if (startContainer !== endContainer) {
return;
}
const { textContent } = startContainer;
this.wordStart = getWordPosition(startOffset + initialDiff, -1);
this.wordEnd = getWordPosition(startOffset + initialDiff, 1) - 1;
this.word = textContent.slice(this.wordStart, this.wordEnd);
this.trigger = this.word.slice(0, 1);
this.triggerClassName = this.triggerClassNameMap[this.trigger];
this.activeTriggerClassName = this.activeTriggerClassNameMap[this.trigger];
//
this.extraTriggerClassName = this.extraTriggerClassNameMap[this.trigger];
this.extraActiveTriggerClassName = this.extraActiveTriggerClassNameMap[this.trigger];
},
function getWordPosition(position, diff) {
const prevText = textContent[position - 1];
if (prevText === null || prevText === undefined) {
return position;
} else if (prevText.trim().length === 0 || position <= 0 || textContent.length < position) {
return position;
} else {
return getWordPosition(position + diff, diff);
}
}
showPanel () {
if (!this.mentionPanel.classList.contains(`medium-editor-mention-panel-active`)) {
this.activatePanel();
this.wrapWordInMentionAt();
}
this.positionPanel();
this.updatePanelContent();
},
this.wordStart = getWordPosition(startOffset + initialDiff, -1);
this.wordEnd = getWordPosition(startOffset + initialDiff, 1) - 1;
this.word = textContent.slice(this.wordStart, this.wordEnd);
this.trigger = this.word.slice(0, 1);
this.triggerClassName = this.triggerClassNameMap[this.trigger];
this.activeTriggerClassName = this.activeTriggerClassNameMap[this.trigger];
//
this.extraTriggerClassName = this.extraTriggerClassNameMap[this.trigger];
this.extraActiveTriggerClassName = this.extraActiveTriggerClassNameMap[this.trigger];
},
activatePanel () {
this.mentionPanel.classList.add(`medium-editor-mention-panel-active`);
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.add(this.extraActivePanelClassName || this.extraActiveClassName);
}
},
showPanel() {
if (!this.mentionPanel.classList.contains(`medium-editor-mention-panel-active`)) {
this.activatePanel();
this.wrapWordInMentionAt();
}
this.positionPanel();
this.updatePanelContent();
},
wrapWordInMentionAt () {
const selection = this.document.getSelection();
if (!selection.rangeCount) {
return;
}
// http://stackoverflow.com/a/6328906/1458162
const range = selection.getRangeAt(0).cloneRange();
if (range.startContainer.parentNode.classList.contains(this.triggerClassName)) {
this.activeMentionAt = range.startContainer.parentNode;
} else {
range.setStart(range.startContainer, this.wordStart);
range.setEnd(range.startContainer, Math.min(this.wordEnd, range.startContainer.textContent.length));
// Instead, insert our own version of it.
// TODO: Not sure why, but using <span> tag doens't work here
const element = this.document.createElement(this.tagName);
element.classList.add(this.triggerClassName);
if (this.extraTriggerClassName) {
element.classList.add(this.extraTriggerClassName);
}
this.activeMentionAt = element;
//
range.surroundContents(element);
selection.removeAllRanges();
selection.addRange(range);
//
MediumEditor.selection.select(this.document, this.activeMentionAt.firstChild, this.word.length);
}
this.activeMentionAt.classList.add(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.add(this.extraActiveTriggerClassName);
}
},
activatePanel() {
this.mentionPanel.classList.add(`medium-editor-mention-panel-active`);
if (this.extraActivePanelClassName || this.extraActiveClassName) {
this.mentionPanel.classList.add(this.extraActivePanelClassName || this.extraActiveClassName);
}
},
positionPanel () {
const {bottom, left, width} = this.activeMentionAt.getBoundingClientRect();
const {pageXOffset, pageYOffset} = this.window;
wrapWordInMentionAt() {
const selection = this.document.getSelection();
if (!selection.rangeCount) {
return;
}
// http://stackoverflow.com/a/6328906/1458162
const range = selection.getRangeAt(0).cloneRange();
if (range.startContainer.parentNode.classList.contains(this.triggerClassName)) {
this.activeMentionAt = range.startContainer.parentNode;
} else {
const nextWordEnd = Math.min(this.wordEnd, range.startContainer.textContent.length);
range.setStart(range.startContainer, this.wordStart);
range.setEnd(range.startContainer, nextWordEnd);
// Instead, insert our own version of it.
// TODO: Not sure why, but using <span> tag doens't work here
const element = this.document.createElement(this.tagName);
element.classList.add(this.triggerClassName);
if (this.extraTriggerClassName) {
element.classList.add(this.extraTriggerClassName);
}
this.activeMentionAt = element;
//
range.surroundContents(element);
selection.removeAllRanges();
selection.addRange(range);
//
MediumEditor.selection.select(
this.document,
this.activeMentionAt.firstChild,
this.word.length
);
}
this.activeMentionAt.classList.add(this.activeTriggerClassName);
if (this.extraActiveTriggerClassName) {
this.activeMentionAt.classList.add(this.extraActiveTriggerClassName);
}
},
this.mentionPanel.style.top = `${ pageYOffset + bottom }px`;
this.mentionPanel.style.left = `${ pageXOffset + left + width }px`;
},
positionPanel() {
const { bottom, left, width } = this.activeMentionAt.getBoundingClientRect();
const { pageXOffset, pageYOffset } = this.window;
updatePanelContent () {
this.renderPanelContent(this.mentionPanel, this.word, ::this.handleSelectMention);
},
this.mentionPanel.style.top = `${ pageYOffset + bottom }px`;
this.mentionPanel.style.left = `${ pageXOffset + left + width }px`;
},
handleSelectMention (seletedText) {
if (seletedText) {
const textNode = this.activeMentionAt.firstChild;
textNode.textContent = seletedText;
MediumEditor.selection.select(this.document, textNode, seletedText.length);
//
this.hidePanel(false);
} else {
this.hidePanel(false);
}
},
updatePanelContent() {
this.renderPanelContent(this.mentionPanel, this.word, ::this.handleSelectMention);
},
handleSelectMention(seletedText) {
if (seletedText) {
const textNode = this.activeMentionAt.firstChild;
textNode.textContent = seletedText;
MediumEditor.selection.select(this.document, textNode, seletedText.length);
//
this.hidePanel(false);
} else {
this.hidePanel(false);
}
},
});
export default TCMention;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc