Instantly share code, notes, and snippets.

Embed
What would you like to do?
Quill "soft" linebreaks (<br> inside <p>) ... requires https://github.com/ilkkah/quillty
import Delta from 'quill-delta';
function create(Quill) {
const Break = Quill.import('blots/break');
const Embed = Quill.import('blots/embed');
const Parchment = Quill.import('parchment');
const Inline = Quill.import('blots/inline');
const TextBlot = Quill.import('blots/text');
const Block = Quill.import('blots/block');
const LINEBREAK_CHAR = '\u000b'
function lineBreakMatcher() {
var newDelta = new Delta();
newDelta.insert({'linebreak': ''});
return newDelta;
}
class SmartBreak extends Parchment.EmbedBlot {
static create(value) {
let node = super.create();
return node;
}
length () {
return 1;
}
value () {
return LINEBREAK_CHAR
}
static value(node) {
return LINEBREAK_CHAR;
}
insertInto(parent, ref) {
Embed.prototype.insertInto.call(this, parent, ref)
}
}
SmartBreak.blotName = 'linebreak';
SmartBreak.className = 'linebreak';
SmartBreak.tagName = 'BR'
Quill.register(SmartBreak, true)
var optionsModules = {
clipboard: {
matchers: [
['BR', lineBreakMatcher]
]
}
}
// var quill = new Quill('.editor', options);
// var length = quill.getLength()
// var text = quill.getText(length - 2, 2)
// // Remove extraneous new lines
// if (text === '\n\n') {
// quill.deleteText(quill.getLength() - 2, 2)
// }
class MyBlock extends Block {
insertAt(index, value, def) {
if (def != null) return super.insertAt(index, value, def);
if (value.length === 0) return;
let lines = value.split('\n');
let text = lines.shift();
let textparts = text.split(LINEBREAK_CHAR);
// We'll keep track the position of text parts
var pos = index;
textparts.forEach((textpart, i) => {
if (textpart.length > 0) {
if (pos < this.length() - 1 || this.children.tail == null) {
super.insertAt(Math.min(pos, this.length() - 1), textpart);
} else {
this.children.tail.insertAt(this.children.tail.length(), textpart);
}
this.cache = {};
}
pos += textpart.length;
// don't insert after the last part ...
if (i !== textparts.length - 1) {
if (pos < this.length() - 1 || this.children.tail == null) {
super.insertAt(Math.min(pos, this.length() - 1), 'linebreak', true);
} else {
this.children.tail.insertAt(this.children.tail.length(), 'linebreak', true);
}
pos += 1;
}
});
let block = this;
lines.reduce(function(index, line) {
block = block.split(index, true);
block.insertAt(0, line);
return line.length;
}, index + text.length);
}
// Why position():
// A position() function is normally used for leafs only and in the old implementation a block
// couldn't be a leaf, but in this implementation it can be. (At least that's my take on this.)
position(index, inclusive) {
const path = this.path(index)
return [path[0][0].domNode, path[0][1]];
}
// So, this is a bit of a hack, but seems to work.
// Improvements welcome.
path(index) {
let x = super.path(index, null, false);
let y = super.path(index, null, true);
if ((x[0] && x[0][0] instanceof TextBlot) || (x[1] && x[1][0] instanceof TextBlot)) {
return x;
}
else if ((y[0] && y[0][0] instanceof TextBlot) || (y[1] && y[1][0] instanceof TextBlot)) {
return y;
}
else {
let posX = -1, posY = -1;
if (x[0] && x[0][0] instanceof SmartBreak) {
posX = x[0][1];
}
else if (x[1] && x[1][0] instanceof SmartBreak) {
posX = x[1][1];
}
if (y[0] && y[0][0] instanceof SmartBreak) {
posY = y[0][1];
}
else if (y[1] && y[1][0] instanceof SmartBreak) {
posY = y[1][1];
}
if (posX > -1 && posY > -1) {
if (posX < posY) {
return x;
}
else {
return y;
}
}
if (posX > -1) {
return x;
}
if (posY > -1) {
return y;
}
}
return x;
}
}
Quill.register('formats/block', MyBlock, true)
return optionsModules;
}
export default create;
@ile

This comment has been minimized.

Copy link
Owner Author

ile commented Feb 2, 2019

this.quill.keyboard.addBinding({
  key: 'Enter',
  shiftKey: true,
  ctrlKey: true
}, function(range, context) {
  var currentLeaf, lineFormats, nextLeaf;
  if (range.length > 0) {
    this.quill.scroll.deleteAt(range.index, range.length);
  }
  lineFormats = Object.keys(context.format).reduce(function(formats, format) {
    if (this.quill.scroll.query(format, Scope.BLOCK) && !Array.isArray(context.format[format])) {
      formats[format] = context.format[format];
    }
    return formats;
  }, {});
  currentLeaf = this.quill.getLeaf(range.index)[0];
  nextLeaf = this.quill.getLeaf(range.index + 1)[0];
  this.quill.insertText(range.index, '\u000b', lineFormats, Quill.sources.USER);
  if (nextLeaf === null || (currentLeaf.parent !== nextLeaf.parent)) {
    this.quill.insertText(range.index, '\u000b', Quill.sources.USER);
  }
  this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
  this.quill.focus();
  Object.keys(context.format).forEach(function(name) {
    if (lineFormats[name] !== null) {
      return;
    }
    if (Array.isArray(context.format[name])) {
      return;
    }
    if (name === 'link') {
      return;
    }
    return this.quill.format(name, context.format[name], Quill.sources.USER);
  });
  return true;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment