Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

quill

Package Overview
Dependencies
Maintainers
1
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

quill - npm Package Compare versions

Comparing version 1.0.0-beta.9 to 1.0.0-beta.10

54

blots/block.js

@@ -49,12 +49,25 @@ import extend from 'extend';

class Block extends Parchment.Block {
constructor(domNode) {
super(domNode);
this.cache = {};
}
delta() {
return this.descendants(Parchment.Leaf).reduce((delta, leaf) => {
if (leaf.length() === 0) {
return delta;
} else {
return delta.insert(leaf.value(), bubbleFormats(leaf));
}
}, new Delta()).insert('\n', bubbleFormats(this));
if (this.cache.delta == null) {
this.cache.delta = this.descendants(Parchment.Leaf).reduce((delta, leaf) => {
if (leaf.length() === 0) {
return delta;
} else {
return delta.insert(leaf.value(), bubbleFormats(leaf));
}
}, new Delta()).insert('\n', bubbleFormats(this));
}
return this.cache.delta;
}
deleteAt(index, length) {
super.deleteAt(index, length);
this.cache = {};
}
formatAt(index, length, name, value) {

@@ -69,2 +82,3 @@ if (length <= 0) return;

}
this.cache = {};
}

@@ -83,2 +97,3 @@

}
this.cache = {};
}

@@ -99,8 +114,22 @@ let block = this;

}
this.cache = {};
}
length() {
return super.length() + NEWLINE_LENGTH;
if (this.cache.length == null) {
this.cache.length = super.length() + NEWLINE_LENGTH;
}
return this.cache.length;
}
moveChildren(target, ref) {
super.moveChildren(target, ref);
this.cache = {};
}
optimize() {
super.optimize();
this.cache = {};
}
path(index) {

@@ -110,2 +139,7 @@ return super.path(index, true);

removeChild(child) {
super.removeChild(child);
this.cache = {};
}
split(index, force = false) {

@@ -122,3 +156,5 @@ if (force && (index === 0 || index >= this.length() - NEWLINE_LENGTH)) {

} else {
return super.split(index, force);
let next = super.split(index, force);
this.cache = {};
return next;
}

@@ -125,0 +161,0 @@ }

2

blots/cursor.js

@@ -28,3 +28,3 @@ import Parchment from 'parchment';

// super.detach() will also clear domNode.__blot
if (this.parent != null) this.parent.children.remove(this);
if (this.parent != null) this.parent.removeChild(this);
}

@@ -31,0 +31,0 @@

@@ -100,2 +100,3 @@ import Parchment from 'parchment';

optimize(mutations = []) {
if (this.batch === true) return;
super.optimize(mutations);

@@ -112,2 +113,3 @@ if (mutations.length > 0) {

update(mutations) {
if (this.batch === true) return;
let source = Emitter.sources.USER;

@@ -114,0 +116,0 @@ if (typeof mutations === 'string') {

@@ -0,1 +1,31 @@

# 1.0.0-beta.10
Lots of bug fixes and performance improvements.
### Breaking Changes
- Keyboard handler format in initial [configuration](beta.quilljs.com/docs/modules/keyboard/) has changed. `addBinding` is overloaded to be backwards compatible.
### Bug Fixes
- Preserve last bullet on paste [#696](https://github.com/quilljs/quill/issues/696)
- Fix getBounds calculation for lists [#765](https://github.com/quilljs/quill/issues/765)
- Escape quotes in font value [#769](https://github.com/quilljs/quill/issues/769)
- Fix spacing calculation on paste [#797](https://github.com/quilljs/quill/issues/797)
- Fix Snow tooltip label [#798](https://github.com/quilljs/quill/issues/798)
- Fix link tooltip showing up on long click [#799](https://github.com/quilljs/quill/issues/799)
- Fix entering code block in IE and Firefox [#803](https://github.com/quilljs/quill/issues/803)
- Fix opening image dialog on Firefox [#805](https://github.com/quilljs/quill/issues/805)
- Fix focus loss on updateContents [#809](https://github.com/quilljs/quill/issues/809)
- Reset toolbar of blur [#810](https://github.com/quilljs/quill/issues/810)
- Fix cursor position calculation on delete [#811](https://github.com/quilljs/quill/issues/811)
- Fix highlighting across different alignment values [#815](https://github.com/quilljs/quill/issues/815)
- Allow default active button [#816](https://github.com/quilljs/quill/issues/816)
- Fix deleting last character of formatted text on Firefox [#824](https://github.com/quilljs/quill/issues/824)
- Fix Youtube regex [#826](https://github.com/quilljs/quill/pull/826)
- Fix missing imports when Quill not global [#836](https://github.com/quilljs/quill/pull/836)
Thanks to [benbro](https://github.com/benbro), [clemmy](https://github.com/clemmy), [crisbeto](https://github.com/crisbeto), [cutteroid](https://github.com/cutteroid), [jackmu95](https://github.com/jackmu95), [kylebragger](https://github.com/kylebragger), [sachinrekhi](https://github.com/sachinrekhi), [stalniy](https://github.com/stalniy), and [tOgg1](https://github.com/tOgg1) for their contributions to this release.
# 1.0.0-beta.9

@@ -2,0 +32,0 @@

@@ -22,16 +22,13 @@ import Delta from 'rich-text/lib/delta';

applyDelta(delta, source = Emitter.sources.API) {
this.updating = true;
let consumeNextNewline = false;
this.scroll.update();
let scrollLength = this.scroll.length();
this.scroll.batch = true;
delta = normalizeDelta(delta);
delta.ops.reduce((index, op) => {
if (typeof op.delete === 'number') {
this.scroll.deleteAt(index, op.delete);
return index;
}
let length = op.retain || op.insert.length || 1;
let attributes = handleOldList(op.attributes || {});
let length = op.retain || op.delete || op.insert.length || 1;
let attributes = op.attributes || {};
if (op.insert != null) {
[op, attributes] = handleOldEmbed(op, attributes);
if (typeof op.insert === 'string') {
let text = op.insert.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
length = text.length;
let text = op.insert;
if (text.endsWith('\n') && consumeNextNewline) {

@@ -41,3 +38,3 @@ consumeNextNewline = false;

}
if (index >= this.scroll.length() && !text.endsWith('\n')) {
if (index >= scrollLength && !text.endsWith('\n')) {
consumeNextNewline = true;

@@ -55,8 +52,6 @@ }

let key = Object.keys(op.insert)[0]; // There should only be one key
if (key != null) {
this.scroll.insertAt(index, key, op.insert[key]);
} else {
return index;
}
if (key == null) return index;
this.scroll.insertAt(index, key, op.insert[key]);
}
scrollLength += length;
}

@@ -68,3 +63,11 @@ Object.keys(attributes).forEach((name) => {

}, 0);
this.updating = false;
delta.ops.reduce((index, op) => {
if (typeof op.delete === 'number') {
this.scroll.deleteAt(index, op.delete);
return index;
}
return index + (op.retain || op.insert.length || 1);
}, 0);
this.scroll.batch = false;
this.scroll.optimize();
return this.update(delta, source);

@@ -86,3 +89,5 @@ }

let lines = this.scroll.lines(index, Math.max(length, 1));
let lengthRemaining = length;
lines.forEach((line, i) => {
let lineLength = line.length();
if (!(line instanceof CodeBlock)) {

@@ -92,5 +97,6 @@ line.format(format, formats[format]);

let codeIndex = index - line.offset(this.scroll);
let codeLength = line.newlineIndex(codeIndex) - index + 1;
let codeLength = line.newlineIndex(codeIndex + lengthRemaining) - codeIndex + 1;
line.formatAt(codeIndex, codeLength, format, formats[format]);
}
lengthRemaining -= lineLength;
});

@@ -179,3 +185,7 @@ });

if (line != null) {
suffixLength = line.length() - offset;
if (!(line instanceof CodeBlock)) {
suffixLength = line.length() - offset;
} else {
suffixLength = line.newlineIndex(offset) - offset + 1;
}
suffix = line.delta().slice(offset, offset + suffixLength - 1).insert('\n');

@@ -190,3 +200,2 @@ }

update(change, source = Emitter.sources.USER) {
if (this.updating) return;
let oldDelta = this.delta;

@@ -225,26 +234,27 @@ this.delta = this.getDelta();

function handleOldEmbed(op, attributes) {
if (op.insert === 1) {
attributes = clone(attributes);
op = {
insert: { image: attributes.image },
attributes: attributes
};
delete attributes['image'];
}
return [op, attributes];
function normalizeDelta(delta) {
return delta.ops.reduce(function(delta, op) {
if (op.insert === 1) {
let attributes = clone(op.attributes);
delete attributes['image'];
return delta.insert({ image: op.attributes.image }, attributes);
}
if (op.attributes != null && (op.attributes.list || op.attributes.bullet)) {
op = clone(op);
if (op.attributes.list) {
op.attributes.list = 'ordered';
} else {
op.attributes.list = 'bullet';
delete op.attributes.bullet;
}
}
if (typeof op.insert === 'string') {
let text = op.insert.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
return delta.insert(text, op.attributes);
}
return delta.push(op);
}, new Delta());
}
function handleOldList(attributes) {
if (attributes['list'] === true) {
attributes = clone(attributes);
attributes['list'] = 'ordered';
} else if (attributes['bullet'] === true) {
attributes = clone(attributes);
attributes['list'] = 'bullet';
}
return attributes;
}
export default Editor;

@@ -51,11 +51,10 @@ import './polyfill';

constructor(container, options = {}) {
this.container = typeof container === 'string' ? document.querySelector(container) : container;
options = expandConfig(container, options);
this.container = options.container;
if (this.container == null) {
return debug.error('Invalid Quill container', container);
}
let themeClass = Theme;
if (options.theme != null && options.theme !== Quill.DEFAULTS.theme) {
themeClass = Quill.import(`themes/${options.theme}`);
if (options.debug) {
Quill.debug(options.debug);
}
options = extend(true, {}, Quill.DEFAULTS, themeClass.DEFAULTS, options);
options.bounds = typeof options.bounds === 'string' ? document.querySelector(options.bounds) : options.bounds;

@@ -73,3 +72,3 @@ let html = this.container.innerHTML.trim();

this.selection = new Selection(this.scroll, this.emitter);
this.theme = new themeClass(this, options);
this.theme = new options.theme(this, options);
this.keyboard = this.theme.addModule('keyboard');

@@ -87,5 +86,2 @@ this.clipboard = this.theme.addModule('clipboard');

}
if (options.debug) {
Quill.debug(options.debug);
}
this.root.classList.toggle('ql-blank', this.editor.isBlank());

@@ -154,3 +150,4 @@ this.emitter.on(Emitter.events.TEXT_CHANGE, (delta) => {

let change = this.editor.formatLine(index, length, formats, source);
this.setSelection(range, Emitter.sources.SILENT);
this.selection.setRange(range, true, Emitter.sources.SILENT);
this.selection.scrollIntoView();
return change;

@@ -164,3 +161,4 @@ }

let change = this.editor.formatText(index, length, formats, source);
this.setSelection(range, Emitter.sources.SILENT);
this.selection.setRange(range, true, Emitter.sources.SILENT);
this.selection.scrollIntoView();
return change;

@@ -298,4 +296,6 @@ }

let change = this.editor.applyDelta(delta, source);
range = shiftRange(range, change, source);
this.setSelection(range, Emitter.sources.SILENT);
if (range != null) {
range = shiftRange(range, change, source);
this.setSelection(range, Emitter.sources.SILENT);
}
return change;

@@ -324,2 +324,54 @@ }

function expandConfig(container, userConfig) {
userConfig = extend(true, {
container: container,
modules: {
clipboard: true,
keyboard: true,
history: true
}
}, userConfig);
if (userConfig.theme == null || userConfig.theme === Quill.DEFAULTS.theme) {
userConfig.theme = Theme;
} else {
userConfig.theme = Quill.import(`themes/${userConfig.theme}`);
if (userConfig.theme == null) {
throw new Error(`Invalid theme ${userConfig.theme}. Did you register it?`);
}
}
let themeConfig = extend(true, {}, Theme.DEFAULTS);
[themeConfig, userConfig].forEach(function(config) {
config.modules = config.modules || {};
Object.keys(config.modules).forEach(function(module) {
if (config.modules[module] === true) {
config.modules[module] = {};
}
});
});
let moduleNames = Object.keys(themeConfig.modules).concat(Object.keys(userConfig.modules));
let moduleConfig = moduleNames.reduce(function(config, name) {
let moduleClass = Quill.import(`modules/${name}`);
if (moduleClass == null) {
debug.error(`Cannot load ${name} module. Are you sure you registered it?`);
} else {
config[name] = moduleClass.DEFAULTS || {};
}
return config;
}, {});
// Special case toolbar shorthand
if (userConfig.modules != null && userConfig.modules.toolbar != null &&
userConfig.modules.toolbar.constructor !== Object) {
userConfig.modules.toolbar = {
container: userConfig.modules.toolbar
};
}
userConfig = extend(true, {}, Quill.DEFAULTS, { modules: moduleConfig }, themeConfig, userConfig);
['bounds', 'container'].forEach(function(key) {
if (typeof userConfig[key] === 'string') {
userConfig[key] = document.querySelector(userConfig[key]);
}
});
return userConfig;
}
function overload(index, length, name, value, source) {

@@ -361,5 +413,4 @@ let formats = {};

} else {
if (source === Emitter.sources.USER) index -= 1;
[start, end] = [range.index, range.index + range.length].map(function(pos) {
if (index > pos) return pos;
if (pos < index || (pos === index && source !== Emitter.sources.USER)) return pos;
if (length >= 0) {

@@ -376,2 +427,2 @@ return pos + length;

export { overload, Quill as default };
export { expandConfig, overload, Quill as default };

@@ -34,8 +34,11 @@ import Parchment from 'parchment';

});
let scrollTop = this.root.scrollTop;
let scrollTop, bodyTop;
this.root.addEventListener('blur', () => {
scrollTop = this.root.scrollTop;
bodyTop = document.body.scrollTop;
});
this.root.addEventListener('focus', () => {
this.root.addEventListener('focus', (event) => {
if (scrollTop == null) return;
this.root.scrollTop = scrollTop;
document.body.scrollTop = bodyTop;
});

@@ -63,3 +66,5 @@ this.emitter.on(Emitter.events.EDITOR_CHANGE, (type, delta) => {

if (this.hasFocus()) return;
let bodyTop = document.body.scrollTop;
this.root.focus();
document.body.scrollTop = bodyTop;
this.setRange(this.savedRange);

@@ -118,7 +123,3 @@ }

} else {
if (leaf instanceof BreakBlot) {
var rect = leaf.parent.domNode.getBoundingClientRect();
} else {
var rect = leaf.domNode.getBoundingClientRect();
}
var rect = leaf.domNode.getBoundingClientRect();
if (offset > 0) side = 'right';

@@ -218,3 +219,3 @@ }

setNativeRange(startNode, startOffset, endNode = startNode, endOffset = startOffset) {
setNativeRange(startNode, startOffset, endNode = startNode, endOffset = startOffset, force = false) {
debug.info('setNativeRange', startNode, startOffset, endNode, endOffset);

@@ -229,3 +230,3 @@ if (startNode != null && (this.root.parentNode == null || startNode.parentNode == null || endNode.parentNode == null)) {

let nativeRange = this.getNativeRange();
if (nativeRange == null ||
if (nativeRange == null || force ||
startNode !== nativeRange.start.node || startOffset !== nativeRange.start.offset ||

@@ -246,3 +247,7 @@ endNode !== nativeRange.end.node || endOffset !== nativeRange.end.offset) {

setRange(range, source = Emitter.sources.API) {
setRange(range, force = false, source = Emitter.sources.API) {
if (typeof force === 'string') {
source = force;
force = false;
}
debug.info('setRange', range);

@@ -259,3 +264,6 @@ if (range != null) {

});
this.setNativeRange(...args);
if (args.length < 2) {
args = args.concat(args);
}
this.setNativeRange(...args, force);
} else {

@@ -262,0 +270,0 @@ this.setNativeRange(null);

@@ -11,9 +11,3 @@ import extend from 'extend';

this.quill = quill;
this.options = extend({}, this.constructor.DEFAULTS, options);
this.options.modules = Object.keys(this.options.modules).reduce((modules, name) => {
let value = this.options.modules[name];
// allow new Quill('#editor', { modules: { myModule: true }});
modules[name] = value === true ? {} : value;
return modules;
}, {});
this.options = options;
this.modules = {};

@@ -32,11 +26,3 @@ }

let moduleClass = this.quill.constructor.import(`modules/${name}`);
if (moduleClass == null) {
return debug.error(`Cannot load ${name} module. Are you sure you registered it?`);
}
let userOptions = this.options.modules[name] || {};
if (typeof userOptions === 'object' && userOptions.constructor === Object) {
let themeOptions = (this.constructor.DEFAULTS.modules || {})[name];
userOptions = extend({}, moduleClass.DEFAULTS || {}, themeOptions, userOptions);
}
this.modules[name] = new moduleClass(this.quill, userOptions);
this.modules[name] = new moduleClass(this.quill, this.options.modules[name] || {});
return this.modules[name];

@@ -43,0 +29,0 @@ }

@@ -68,3 +68,7 @@ import Delta from 'rich-text/lib/delta';

length() {
return this.domNode.textContent.length;
let length = this.domNode.textContent.length;
if (!this.domNode.textContent.endsWith('\n')) {
return length + 1;
}
return length;
}

@@ -71,0 +75,0 @@

@@ -14,4 +14,11 @@ import Embed from '../blots/embed';

static formats(domNode) {
let formats = {};
if (domNode.hasAttribute('height')) formats['height'] = domNode.getAttribute('height');
if (domNode.hasAttribute('width')) formats['width'] = domNode.getAttribute('width');
return formats;
}
static match(url) {
return /\.(jpe?g|gif|png)$/.test(url);
return /\.(jpe?g|gif|png)$/.test(url) || /^data:image\/.+;base64/.test(url);
}

@@ -26,2 +33,14 @@

}
format(name, value) {
if (name === 'height' || name === 'width') {
if (value) {
this.domNode.setAttribute(name, value);
} else {
this.domNode.removeAttribute(name);
}
} else {
super.format(name, value);
}
}
}

@@ -28,0 +47,0 @@ Image.blotName = 'image';

@@ -10,3 +10,3 @@ import extend from 'extend';

static formats(domNode) {
return domNode.tagName === ListItem.tagName ? undefined : super.formats(domNode);
return domNode.tagName === this.tagName ? undefined : super.formats(domNode);
}

@@ -32,3 +32,3 @@

this.parent.isolate(this.offset(this.parent), this.length());
if (name === List.blotName) {
if (name === this.parent.statics.blotName) {
this.parent.replaceWith(name, value);

@@ -35,0 +35,0 @@ return this;

@@ -33,5 +33,2 @@ import Delta from 'rich-text/lib/delta';

constructor(quill, options) {
if (options.matchers !== Clipboard.DEFAULTS.matchers) {
options.matchers = Clipboard.DEFAULTS.matchers.concat(options.matchers);
}
super(quill, options);

@@ -52,21 +49,2 @@ this.quill.root.addEventListener('paste', this.onPaste.bind(this));

clean() {
let treeWalker = document.createTreeWalker(
this.container,
NodeFilter.SHOW_COMMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
);
let comments = [];
while(treeWalker.nextNode()) {
comments.push(treeWalker.currentNode);
}
comments.forEach(function(node) {
if (node != null && node.parentNode != null) {
node.parentNode.removeChild(node);
}
});
this.container.normalize();
}
convert(html) {

@@ -77,31 +55,42 @@ const DOM_KEY = '__ql-matcher';

}
this.clean();
let textMatchers = [], elementMatchers = [];
this.matchers.forEach((pair) => {
let [selector, matcher] = pair;
if (typeof selector === 'string') {
[].forEach.call(this.container.querySelectorAll(selector), (node) => {
// TODO use weakmap
node[DOM_KEY] = node[DOM_KEY] || [];
node[DOM_KEY].push(matcher);
});
switch (selector) {
case Node.TEXT_NODE:
textMatchers.push(matcher);
break;
case Node.ELEMENT_NODE:
elementMatchers.push(matcher);
break;
default:
[].forEach.call(this.container.querySelectorAll(selector), (node) => {
// TODO use weakmap
node[DOM_KEY] = node[DOM_KEY] || [];
node[DOM_KEY].push(matcher);
});
break;
}
});
let traverse = (node) => { // Post-order
return [].reduce.call(node.childNodes || [], (delta, childNode) => {
if (childNode.nodeType !== Node.ELEMENT_NODE && childNode.nodeType !== Node.TEXT_NODE) {
return delta;
}
let childrenDelta = traverse(childNode);
childrenDelta = this.matchers.reduce(function(childrenDelta, pair) {
let [type, matcher] = pair;
if (type === true || childNode.nodeType === type) {
childrenDelta = matcher(childNode, childrenDelta);
if (node.nodeType === node.TEXT_NODE) {
return textMatchers.reduce(function(delta, matcher) {
return matcher(node, delta);
}, new Delta());
} else if (node.nodeType === node.ELEMENT_NODE) {
return [].reduce.call(node.childNodes || [], (delta, childNode) => {
let childrenDelta = traverse(childNode);
if (childNode.nodeType === node.ELEMENT_NODE) {
childrenDelta = elementMatchers.reduce(function(childrenDelta, matcher) {
return matcher(childNode, childrenDelta);
}, childrenDelta);
childrenDelta = (childNode[DOM_KEY] || []).reduce(function(childrenDelta, matcher) {
return matcher(childNode, childrenDelta);
}, childrenDelta);
}
return childrenDelta;
}, childrenDelta);
childrenDelta = (childNode[DOM_KEY] || []).reduce(function(childrenDelta, matcher) {
return matcher(childNode, childrenDelta);
}, childrenDelta);
return delta.concat(childrenDelta);
}, new Delta());
return delta.concat(childrenDelta);
}, new Delta());
} else {
return new Delta();
}
};

@@ -113,3 +102,3 @@ let delta = traverse(this.container);

}
debug.info('convert', this.container.innerHTML, delta);
debug.log('convert', this.container.innerHTML, delta);
this.container.innerHTML = '';

@@ -218,4 +207,3 @@ return delta;

function matchNewline(node, delta) {
if (!isLine(node)) return delta;
if (computeStyle(node).whiteSpace.startsWith('pre') || !deltaEndsWith(delta, '\n')) {
if (isLine(node) && !deltaEndsWith(delta, '\n')) {
delta.insert('\n');

@@ -227,7 +215,7 @@ }

function matchSpacing(node, delta) {
if (isLine(node) &&
node.nextElementSibling != null &&
node.nextElementSibling.offsetTop > node.offsetTop + node.offsetHeight*1.5 &&
!deltaEndsWith(delta, '\n\n')) {
delta.insert('\n');
if (isLine(node) && node.nextElementSibling != null && !deltaEndsWith(delta, '\n\n')) {
let nodeHeight = node.offsetHeight + parseFloat(computeStyle(node).marginTop) + parseFloat(computeStyle(node).marginBottom);
if (node.nextElementSibling.offsetTop > node.offsetTop + nodeHeight*1.5) {
delta.insert('\n');
}
}

@@ -234,0 +222,0 @@ return delta;

import Embed from '../blots/embed';
import Quill from '../core/quill';

@@ -3,0 +4,0 @@

@@ -35,4 +35,3 @@ import clone from 'clone';

if (this.options.bindings[name]) {
let [key, context, handler] = this.options.bindings[name];
this.addBinding(key, context, handler);
this.addBinding(this.options.bindings[name]);
}

@@ -42,3 +41,3 @@ });

this.addBinding({ key: Keyboard.keys.ENTER, metaKey: null, ctrlKey: null, altKey: null }, function() {});
this.addBinding({ key: Keyboard.keys.BACKSPACE }, { collapsed: true, prefix: /^$/ }, function(range) {
this.addBinding({ key: Keyboard.keys.BACKSPACE }, { collapsed: true, prefix: /^.?$/ }, function(range) {
if (range.index === 0) return;

@@ -57,13 +56,16 @@ this.quill.deleteText(range.index - 1, 1, Quill.sources.USER);

addBinding(binding, context, handler) {
binding = normalize(binding);
if (binding == null) {
addBinding(key, context = {}, handler = {}) {
let binding = normalize(key);
if (binding == null || binding.key == null) {
return debug.warn('Attempted to add invalid keyboard binding', binding);
}
if (typeof context === 'function') {
handler = context;
context = {};
context = { handler: context };
}
if (typeof handler === 'function') {
handler = { handler: handler };
}
binding = extend(binding, context, handler);
this.bindings[binding.key] = this.bindings[binding.key] || [];
this.bindings[binding.key].push([binding, context, handler]);
this.bindings[binding.key].push(binding);
}

@@ -75,4 +77,4 @@

let which = evt.which || evt.keyCode;
let bindings = (this.bindings[which] || []).filter(function(tuple) {
return Keyboard.match(evt, tuple[0]);
let bindings = (this.bindings[which] || []).filter(function(binding) {
return Keyboard.match(evt, binding);
});

@@ -95,10 +97,9 @@ if (bindings.length === 0) return;

};
let prevented = bindings.some((tuple) => {
let [key, context, handler] = tuple;
if (context.collapsed != null && context.collapsed !== curContext.collapsed) return false;
if (context.empty != null && context.empty !== curContext.empty) return false;
if (context.offset != null && context.offset !== curContext.offset) return false;
if (Array.isArray(context.format)) {
let prevented = bindings.some((binding) => {
if (binding.collapsed != null && binding.collapsed !== curContext.collapsed) return false;
if (binding.empty != null && binding.empty !== curContext.empty) return false;
if (binding.offset != null && binding.offset !== curContext.offset) return false;
if (Array.isArray(binding.format)) {
// any format is present
if (context.format.every(function(name) {
if (binding.format.every(function(name) {
return curContext.format[name] == null;

@@ -108,8 +109,8 @@ })) {

}
} else if (typeof context.format === 'object') {
} else if (typeof binding.format === 'object') {
// all formats must match
if (!Object.keys(context.format).every(function(name) {
if (context.format[name] === true) return curContext.format[name] != null;
if (context.format[name] === false) return curContext.format[name] == null;
return equal(context.format[name], curContext.format[name]);
if (!Object.keys(binding.format).every(function(name) {
if (binding.format[name] === true) return curContext.format[name] != null;
if (binding.format[name] === false) return curContext.format[name] == null;
return equal(binding.format[name], curContext.format[name]);
})) {

@@ -119,5 +120,5 @@ return false;

}
if (context.prefix != null && !context.prefix.test(curContext.prefix)) return false;
if (context.suffix != null && !context.suffix.test(curContext.suffix)) return false;
return handler.call(this, range, curContext) !== true;
if (binding.prefix != null && !binding.prefix.test(curContext.prefix)) return false;
if (binding.suffix != null && !binding.suffix.test(curContext.suffix)) return false;
return binding.handler.call(this, range, curContext) !== true;
});

@@ -148,24 +149,27 @@ if (prevented) {

'underline' : makeFormatHandler('underline'),
'indent': [
'indent': {
// highlight tab or tab at beginning of list, indent or blockquote
{ key: Keyboard.keys.TAB },
{ format: ['blockquote', 'indent', 'list'] },
function(range, context) {
key: Keyboard.keys.TAB,
format: ['blockquote', 'indent', 'list'],
handler: function(range, context) {
if (context.collapsed && context.offset !== 0) return true;
this.quill.format('indent', '+1', Quill.sources.USER);
}
],
'outdent': [
{ key: Keyboard.keys.TAB, shiftKey: true },
{ format: ['blockquote', 'indent', 'list'] },
},
'outdent': {
key: Keyboard.keys.TAB,
shiftKey: true,
format: ['blockquote', 'indent', 'list'],
// highlight tab or tab at beginning of list, indent or blockquote
function(range, context) {
handler: function(range, context) {
if (context.collapsed && context.offset !== 0) return true;
this.quill.format('indent', '-1', Quill.sources.USER);
}
],
'outdent backspace': [
{ key: Keyboard.keys.BACKSPACE },
{ collapsed: true, format: ['blockquote', 'indent', 'list'], offset: 0 },
function(range, context) {
},
'outdent backspace': {
key: Keyboard.keys.BACKSPACE,
collapsed: true,
format: ['blockquote', 'indent', 'list'],
offset: 0,
handler: function(range, context) {
if (context.format.indent != null) {

@@ -179,9 +183,9 @@ this.quill.format('indent', '-1', Quill.sources.USER);

}
],
},
'indent code-block': makeCodeBlockHandler(true),
'outdent code-block': makeCodeBlockHandler(false),
'tab': [
{ key: Keyboard.keys.TAB, shiftKey: null },
{},
function(range, context) {
'tab': {
key: Keyboard.keys.TAB,
shiftKey: null,
handler: function(range, context) {
if (!context.collapsed) {

@@ -192,7 +196,9 @@ this.quill.scroll.deleteAt(range.index, range.length);

}
],
'list empty enter': [
{ key: Keyboard.keys.ENTER },
{ collapsed: true, format: ['list'], empty: true },
function(range, context) {
},
'list empty enter': {
key: Keyboard.keys.ENTER,
collapsed: true,
format: ['list'],
empty: true,
handler: function(range, context) {
this.quill.format('list', false, Quill.sources.USER);

@@ -203,7 +209,9 @@ if (context.format.indent) {

}
],
'header enter': [
{ key: Keyboard.keys.ENTER },
{ collapsed: true, format: ['header'], suffix: /^$/ },
function(range) {
},
'header enter': {
key: Keyboard.keys.ENTER,
collapsed: true,
format: ['header'],
suffix: /^$/,
handler: function(range) {
this.quill.scroll.insertAt(range.index, '\n');

@@ -214,7 +222,9 @@ this.quill.formatText(range.index + 1, 1, 'header', false, Quill.sources.USER);

}
],
'list autofill': [
{ key: ' ' },
{ collapsed: true, format: { list: false }, prefix: /^(1\.|-)$/ },
function(range, context) {
},
'list autofill': {
key: ' ',
collapsed: true,
format: { list: false },
prefix: /^(1\.|-)$/,
handler: function(range, context) {
let length = context.prefix.length;

@@ -225,3 +235,3 @@ this.quill.scroll.deleteAt(range.index - length, length);

}
]
}
}

@@ -258,44 +268,50 @@ };

function makeCodeBlockHandler(indent) {
let handler = function(range) {
let CodeBlock = Parchment.query('code-block');
let index = range.index, length = range.length;
let [block, offset] = this.quill.scroll.descendant(CodeBlock, index);
if (block == null) return;
let scrollOffset = this.quill.scroll.offset(block);
let start = block.newlineIndex(offset, true) + 1;
let end = block.newlineIndex(scrollOffset + offset + length);
let lines = block.domNode.textContent.slice(start, end).split('\n');
offset = 0;
lines.forEach((line, i) => {
if (indent) {
block.insertAt(start + offset, CodeBlock.TAB);
offset += CodeBlock.TAB.length;
if (i === 0) {
index += CodeBlock.TAB.length;
} else {
length += CodeBlock.TAB.length;
return {
key: Keyboard.keys.TAB,
shiftKey: !indent,
format: {'code-block': true },
handler: function(range) {
let CodeBlock = Parchment.query('code-block');
let index = range.index, length = range.length;
let [block, offset] = this.quill.scroll.descendant(CodeBlock, index);
if (block == null) return;
let scrollOffset = this.quill.scroll.offset(block);
let start = block.newlineIndex(offset, true) + 1;
let end = block.newlineIndex(scrollOffset + offset + length);
let lines = block.domNode.textContent.slice(start, end).split('\n');
offset = 0;
lines.forEach((line, i) => {
if (indent) {
block.insertAt(start + offset, CodeBlock.TAB);
offset += CodeBlock.TAB.length;
if (i === 0) {
index += CodeBlock.TAB.length;
} else {
length += CodeBlock.TAB.length;
}
} else if (line.startsWith(CodeBlock.TAB)) {
block.deleteAt(start + offset, CodeBlock.TAB.length);
offset -= CodeBlock.TAB.length;
if (i === 0) {
index -= CodeBlock.TAB.length;
} else {
length -= CodeBlock.TAB.length;
}
}
} else if (line.startsWith(CodeBlock.TAB)) {
block.deleteAt(start + offset, CodeBlock.TAB.length);
offset -= CodeBlock.TAB.length;
if (i === 0) {
index -= CodeBlock.TAB.length;
} else {
length -= CodeBlock.TAB.length;
}
}
offset += line.length + 1;
});
this.quill.update(Quill.sources.USER);
this.quill.setSelection(index, length, Quill.sources.SILENT);
}
return [{ key: Keyboard.keys.TAB, shiftKey: !indent }, { format: {'code-block': true } }, handler];
offset += line.length + 1;
});
this.quill.update(Quill.sources.USER);
this.quill.setSelection(index, length, Quill.sources.SILENT);
}
};
}
function makeFormatHandler(format) {
let key = { key: format[0].toUpperCase(), shortKey: true };
let handler = function(range, context) {
this.quill.format(format, !context.format[format], Quill.sources.USER);
return {
key: format[0].toUpperCase(),
shortKey: true,
handler: function(range, context) {
this.quill.format(format, !context.format[format], Quill.sources.USER);
}
};
return [key, {}, handler];
}

@@ -302,0 +318,0 @@

@@ -69,3 +69,3 @@ import Parchment from 'parchment';

return result.value;
}
};
})()

@@ -72,0 +72,0 @@ };

@@ -14,7 +14,4 @@ import extend from 'extend';

constructor(quill, options) {
options.handlers = extend({}, Toolbar.DEFAULTS.handlers, options.handlers);
super(quill, options);
if (typeof this.options.container === 'string') {
this.container = document.querySelector(this.options.container);
} else if (Array.isArray(this.options.container)) {
if (Array.isArray(this.options.container)) {
let container = document.createElement('div');

@@ -24,2 +21,4 @@ addControls(container, this.options.container);

this.container = container;
} else if (typeof this.options.container === 'string') {
this.container = document.querySelector(this.options.container);
} else {

@@ -37,2 +36,5 @@ this.container = this.options.container;

});
this.container.addEventListener('mousedown', function(e) {
e.preventDefault(); // Prevent blur
});
[].forEach.call(this.container.querySelectorAll('button, select'), (input) => {

@@ -75,33 +77,37 @@ this.attach(input);

}
let eventNames = input.tagName === 'SELECT' ? ['change'] : ['mousedown', 'touchstart'];
eventNames.forEach((eventName) => {
input.addEventListener(eventName, (e) => {
let value;
if (input.tagName === 'SELECT') {
if (input.selectedIndex < 0) return;
let selected = input.options[input.selectedIndex];
if (selected.hasAttribute('selected')) {
value = false;
} else {
value = selected.value || false;
}
let eventName = input.tagName === 'SELECT' ? 'change' : 'click';
input.addEventListener(eventName, (e) => {
let value;
if (input.tagName === 'SELECT') {
if (input.selectedIndex < 0) return;
let selected = input.options[input.selectedIndex];
if (selected.hasAttribute('selected')) {
value = false;
} else {
value = input.classList.contains('ql-active') ? false : input.value || true;
e.preventDefault();
value = selected.value || false;
}
this.quill.focus();
let [range, ] = this.quill.selection.getRange();
if (this.handlers[format] != null) {
this.handlers[format].call(this, value);
} else if (Parchment.query(format).prototype instanceof Parchment.Embed) {
this.quill.updateContents(new Delta()
.retain(range.index)
.delete(range.length)
.insert({ [format]: true })
, Quill.sources.USER);
} else {
if (input.classList.contains('ql-active')) {
value = false;
} else {
this.quill.format(format, value, Quill.sources.USER);
value = input.value || !input.hasAttribute('value');
}
this.update(range);
});
e.preventDefault();
}
this.quill.focus();
let [range, ] = this.quill.selection.getRange();
if (this.handlers[format] != null) {
this.handlers[format].call(this, value);
} else if (Parchment.query(format).prototype instanceof Parchment.Embed) {
value = prompt(`Enter ${format}`);
if (!value) return;
this.quill.updateContents(new Delta()
.retain(range.index)
.delete(range.length)
.insert({ [format]: value })
, Quill.sources.USER);
} else {
this.quill.format(format, value, Quill.sources.USER);
}
this.update(range);
});

@@ -113,4 +119,3 @@ // TODO use weakmap

update(range) {
if (range == null) return;
let formats = this.quill.getFormat(range);
let formats = range == null ? {} : this.quill.getFormat(range);
this.controls.forEach(function(pair) {

@@ -120,6 +125,12 @@ let [format, input] = pair;

let option;
if (formats[format] == null) {
if (range == null) {
option = null;
} else if (formats[format] == null) {
option = input.querySelector('option[selected]');
} else if (!Array.isArray(formats[format])) {
option = input.querySelector(`option[value="${formats[format]}"]`);
let value = formats[format];
if (typeof value === 'string') {
value = value.replace(/\"/g, '&quot;');
}
option = input.querySelector(`option[value="${value}"]`);
}

@@ -132,8 +143,12 @@ if (option == null) {

}
} if (input.value) {
let active = input.value === formats[format] ||
(formats[format] != null && input.value === formats[format].toString());
input.classList.toggle('ql-active', active);
} else {
input.classList.toggle('ql-active', formats[format] === true || (format === 'link' && formats[format] != null));
if (range == null) {
input.classList.remove('ql-active');
} else if (input.hasAttribute('value')) {
// both being null should match (default values)
// '1' should match with 1 (headers)
input.classList.toggle('ql-active', formats[format] == input.value || (formats[format] == null && !input.value));
} else {
input.classList.toggle('ql-active', formats[format] != null);
}
}

@@ -222,2 +237,8 @@ });

},
link: function(value) {
if (value === true) {
value = prompt('Enter link URL:');
}
this.quill.format('link', value, Quill.sources.USER);
},
indent: function(value) {

@@ -224,0 +245,0 @@ let range = this.quill.getSelection();

{
"name": "quill",
"version": "1.0.0-beta.9",
"version": "1.0.0-beta.10",
"description": "Cross browser rich text editor",

@@ -38,7 +38,6 @@ "author": "Jason Chen <jhchen7@gmail.com>",

"extend": "~3.0.0",
"parchment": "1.0.0-beta.9",
"rich-text": "~3.0.1"
"parchment": "1.0.0-beta.11",
"rich-text": "~3.0.2"
},
"devDependencies": {
"async": "^1.5.2",
"babel-core": "^6.10.4",

@@ -45,0 +44,0 @@ "babel-loader": "^6.2.4",

import Quill from './core';
import { AlignClass as Align } from './formats/align';
import { DirectionClass as Direction } from './formats/direction';
import { AlignClass, AlignStyle } from './formats/align';
import { DirectionClass, DirectionStyle } from './formats/direction';
import { IndentClass as Indent } from './formats/indent';

@@ -43,8 +43,13 @@

Quill.register({
'attributors/class/align': AlignClass,
'attributors/class/background': BackgroundClass,
'attributors/class/color': ColorClass,
'attributors/class/direction': DirectionClass,
'attributors/class/font': FontClass,
'attributors/class/size': SizeClass,
'attributors/style/align': AlignStyle,
'attributors/style/background': BackgroundStyle,
'attributors/style/color': ColorStyle,
'attributors/style/direction': DirectionStyle,
'attributors/style/font': FontStyle,

@@ -56,4 +61,4 @@ 'attributors/style/size': SizeStyle

Quill.register({
'formats/align': Align,
'formats/direction': Direction,
'formats/align': AlignClass,
'formats/direction': DirectionClass,
'formats/indent': Indent,

@@ -60,0 +65,0 @@

import extend from 'extend';
import Delta from 'rich-text/lib/delta';
import Emitter from '../core/emitter';
import Keyboard from '../modules/keyboard';
import Theme from '../core/theme';

@@ -8,2 +9,3 @@ import ColorPicker from '../ui/color-picker';

import Picker from '../ui/picker';
import Tooltip from '../ui/tooltip';
import icons from '../ui/icons';

@@ -32,14 +34,2 @@

super(quill, options);
this.options.modules.toolbar = this.options.modules.toolbar || {};
if (this.options.modules.toolbar.constructor !== Object) {
this.options.modules.toolbar = {
container: this.options.modules.toolbar,
handlers: {}
};
}
this.options.modules.toolbar.handlers = extend({},
BaseTheme.DEFAULTS.modules.toolbar.handlers,
this.constructor.DEFAULTS.modules.toolbar.handlers || {},
this.options.modules.toolbar.handlers || {}
);
let listener = (e) => {

@@ -50,3 +40,3 @@ if (!document.body.contains(quill.root)) {

if (this.tooltip != null && !this.tooltip.root.contains(e.target) &&
document.activeElement !== this.tooltip.textbox) {
document.activeElement !== this.tooltip.textbox && !this.quill.hasFocus()) {
this.tooltip.hide();

@@ -129,6 +119,9 @@ }

}
BaseTheme.DEFAULTS = {
BaseTheme.DEFAULTS = extend(true, {}, Theme.DEFAULTS, {
modules: {
toolbar: {
handlers: {
formula: function(value) {
this.quill.theme.tooltip.edit('formula');
},
image: function(value) {

@@ -159,2 +152,5 @@ let fileInput = this.container.querySelector('input.ql-image[type=file]');

fileInput.click();
},
video: function(value) {
this.quill.theme.tooltip.edit('video');
}

@@ -164,5 +160,84 @@ }

}
};
});
class BaseTooltip extends Tooltip {
constructor(quill, boundsContainer) {
super(quill, boundsContainer);
this.textbox = this.root.querySelector('input[type="text"]');
this.listen();
}
listen() {
this.textbox.addEventListener('keydown', (event) => {
if (Keyboard.match(event, 'enter')) {
this.save();
event.preventDefault();
} else if (Keyboard.match(event, 'escape')) {
this.cancel();
event.preventDefault();
}
});
}
cancel() {
this.hide();
}
edit(mode = 'link', preview = null) {
this.root.classList.remove('ql-hidden');
this.root.classList.add('ql-editing');
if (preview != null) {
this.textbox.value = preview;
} else if (mode !== this.root.dataset.mode) {
this.textbox.value = '';
}
this.textbox.select();
this.textbox.setAttribute('placeholder', this.textbox.dataset[mode] || '');
this.root.dataset.mode = mode;
this.position(this.quill.getBounds(this.quill.selection.savedRange));
}
save() {
let value = this.textbox.value;
switch(this.root.dataset.mode) {
case 'link':
let scrollTop = this.quill.root.scrollTop;
if (this.linkRange) {
this.quill.formatText(this.linkRange, 'link', value, Emitter.sources.USER);
delete this.linkRange;
} else {
this.quill.focus();
this.quill.format('link', value, Emitter.sources.USER);
}
this.quill.root.scrollTop = scrollTop;
break;
case 'video':
let match = value.match(/^(https?):\/\/(www\.)?youtube\.com\/watch.*v=([a-zA-Z0-9_-]+)/) ||
value.match(/^(https?):\/\/(www\.)?youtu\.be\/([a-zA-Z0-9_-]+)/);
if (match) {
value = match[1] + '://www.youtube.com/embed/' + match[3] + '?showinfo=0';
} else if (match = value.match(/^(https?):\/\/(www\.)?vimeo\.com\/(\d+)/)) {
value = match[1] + '://player.vimeo.com/video/' + match[3] + '/';
}
// fallthrough
case 'formula':
let range = this.quill.getSelection(true);
let index = range.index + range.length;
if (range != null) {
this.quill.insertEmbed(index, this.root.dataset.mode, value, Emitter.sources.USER);
if (this.root.dataset.mode === 'formula') {
this.quill.insertText(index + 1, ' ', Emitter.sources.USER);
}
this.quill.setSelection(index + 2, Emitter.sources.USER);
}
break;
default:
}
this.textbox.value = '';
this.hide();
}
}
function fillSelect(select, values, defaultValue = false) {

@@ -181,2 +256,2 @@ values.forEach(function(value) {

export default BaseTheme;
export { BaseTooltip, BaseTheme as default };

@@ -0,11 +1,19 @@

import extend from 'extend';
import Emitter from '../core/emitter';
import Keyboard from '../modules/keyboard';
import BaseTheme from './base';
import BaseTheme, { BaseTooltip } from './base';
import icons from '../ui/icons';
import { Range } from '../core/selection';
import Tooltip from '../ui/tooltip';
const TOOLBAR_CONFIG = [
['bold', 'italic', 'link'],
[{ header: 1 }, { header: 2 }, 'blockquote']
];
class BubbleTheme extends BaseTheme {
constructor(quill, options) {
if (options.modules.toolbar != null && options.modules.toolbar.container == null) {
options.modules.toolbar.container = TOOLBAR_CONFIG;
}
super(quill, options);

@@ -22,13 +30,6 @@ this.quill.container.classList.add('ql-bubble');

}
BubbleTheme.DEFAULTS = {
BubbleTheme.DEFAULTS = extend(true, {}, BaseTooltip.DEFAULTS, {
modules: {
toolbar: {
container: [
['bold', 'italic', 'link'],
[{ header: 1 }, { header: 2 }, 'blockquote']
],
handlers: {
formula: function(value) {
this.quill.theme.tooltip.edit('formula');
},
link: function(value) {

@@ -40,5 +41,2 @@ if (!value) {

}
},
video: function(value) {
this.quill.theme.tooltip.edit('video');
}

@@ -48,6 +46,6 @@ }

}
}
});
class BubbleTooltip extends Tooltip {
class BubbleTooltip extends BaseTooltip {
constructor(quill, bounds) {

@@ -80,7 +78,4 @@ super(quill, bounds);

super.listen();
['mousedown', 'touchstart'].forEach((name) => {
this.root.querySelector('.ql-close').addEventListener(name, (event) => {
this.root.classList.remove('ql-editing');
event.preventDefault();
});
this.root.querySelector('.ql-close').addEventListener('click', (event) => {
this.root.classList.remove('ql-editing');
});

@@ -87,0 +82,0 @@ this.quill.on(Emitter.events.SCROLL_OPTIMIZE, () => {

@@ -0,11 +1,21 @@

import extend from 'extend';
import Emitter from '../core/emitter';
import BaseTheme from './base';
import BaseTheme, { BaseTooltip } from './base';
import LinkBlot from '../formats/link';
import Picker from '../ui/picker';
import { Range } from '../core/selection';
import Tooltip from '../ui/tooltip';
const TOOLBAR_CONFIG = [
[{ header: ['1', '2', '3', false] }],
['bold', 'italic', 'underline', 'link'],
[{ list: 'ordered' }, { list: 'bullet' }],
['clean']
];
class SnowTheme extends BaseTheme {
constructor(quill, options) {
if (options.modules.toolbar != null && options.modules.toolbar.container == null) {
options.modules.toolbar.container = TOOLBAR_CONFIG;
}
super(quill, options);

@@ -27,15 +37,6 @@ this.quill.container.classList.add('ql-snow');

}
SnowTheme.DEFAULTS = {
SnowTheme.DEFAULTS = extend(true, {}, BaseTheme.DEFAULTS, {
modules: {
toolbar: {
container: [
[{ header: ['1', '2', '3', false] }],
['bold', 'italic', 'underline', 'link'],
[{ list: 'ordered' }, { list: 'bullet' }],
['clean']
],
handlers: {
formula: function(value) {
this.quill.theme.tooltip.edit('formula');
},
link: function(value) {

@@ -54,5 +55,2 @@ if (value) {

}
},
video: function(value) {
this.quill.theme.tooltip.edit('video');
}

@@ -62,6 +60,6 @@ }

}
}
});
class SnowTooltip extends Tooltip {
class SnowTooltip extends BaseTooltip {
constructor(quill, bounds) {

@@ -106,2 +104,9 @@ super(quill, bounds);

}
show() {
super.show();
if (this.root.dataset.mode) {
delete this.root.dataset.mode;
}
}
}

@@ -108,0 +113,0 @@ SnowTooltip.TEMPLATE = [

@@ -11,3 +11,4 @@ import Picker from './picker';

});
this.selectItem(this.container.querySelector('.ql-selected'));
this.defaultItem = this.container.querySelector('.ql-selected');
this.selectItem(this.defaultItem);
}

@@ -17,2 +18,3 @@

super.selectItem(item, trigger);
item = item || this.defaultItem;
this.label.innerHTML = item.innerHTML;

@@ -19,0 +21,0 @@ }

@@ -11,7 +11,4 @@ import DropdownIcon from '../assets/icons/dropdown.svg';

this.select.parentNode.insertBefore(this.container, this.select);
['mousedown', 'touchstart'].forEach((name) => {
this.label.addEventListener(name, (event) => {
this.container.classList.toggle('ql-expanded');
event.preventDefault(); // prevent focus loss
});
this.label.addEventListener('click', (event) => {
this.container.classList.toggle('ql-expanded');
});

@@ -30,7 +27,4 @@ this.select.addEventListener('change', this.update.bind(this));

}
['mousedown', 'touchstart'].forEach((name) => {
item.addEventListener(name, (event) => {
this.selectItem(item, true);
event.preventDefault();
});
item.addEventListener('click', (event) => {
this.selectItem(item, true);
});

@@ -37,0 +31,0 @@ return item;

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

import Keyboard from '../modules/keyboard';
import Emitter from '../core/emitter';
class Tooltip {

@@ -16,4 +12,2 @@ constructor(quill, boundsContainer) {

});
this.textbox = this.root.querySelector('input[type="text"]');
this.listen();
this.hide();

@@ -28,32 +22,2 @@ }

listen() {
this.textbox.addEventListener('keydown', (event) => {
if (Keyboard.match(event, 'enter')) {
this.save();
event.preventDefault();
} else if (Keyboard.match(event, 'escape')) {
this.cancel();
event.preventDefault();
}
});
}
cancel() {
this.hide();
}
edit(mode = 'link', preview = null) {
this.root.classList.remove('ql-hidden');
this.root.classList.add('ql-editing');
if (preview != null) {
this.textbox.value = preview;
} else if (mode !== this.root.dataset.mode) {
this.textbox.value = '';
}
this.textbox.select();
this.textbox.setAttribute('placeholder', this.textbox.dataset[mode] || '');
this.root.dataset.mode = mode;
this.position(this.quill.getBounds(this.quill.selection.savedRange));
}
hide() {

@@ -83,34 +47,2 @@ this.root.classList.add('ql-hidden');

save() {
switch(this.root.dataset.mode) {
case 'link':
let url = this.textbox.value;
let scrollTop = this.quill.root.scrollTop;
if (this.linkRange) {
this.quill.formatText(this.linkRange, 'link', url, Emitter.sources.USER);
delete this.linkRange;
} else {
this.quill.focus();
this.quill.format('link', url, Emitter.sources.USER);
}
this.quill.root.scrollTop = scrollTop;
break;
case 'formula': // fallthrough
case 'video':
let range = this.quill.getSelection(true);
let index = range.index + range.length;
if (range != null) {
this.quill.insertEmbed(index, this.root.dataset.mode, this.textbox.value, Emitter.sources.USER);
if (this.root.dataset.mode === 'formula') {
this.quill.insertText(index + 1, ' ', Emitter.sources.USER);
}
this.quill.setSelection(index + 2, Emitter.sources.USER);
}
break;
default:
}
this.textbox.value = '';
this.hide();
}
show() {

@@ -117,0 +49,0 @@ this.root.classList.remove('ql-editing');

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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