quilljs / delta Goto Github PK
View Code? Open in Web Editor NEWSimple and expressive JSON format for describing rich-text content and their changes
Home Page: https://quilljs.com/docs/delta
License: BSD 3-Clause "New" or "Revised" License
Simple and expressive JSON format for describing rich-text content and their changes
Home Page: https://quilljs.com/docs/delta
License: BSD 3-Clause "New" or "Revised" License
Does Delta have its own MIME type? Something like application/quill-delta+json
?
https://github.com/quilljs/delta#eachline
The example for eachLine() uses all lowercase instead of camelcase.
delta.eachline instead of delta.eachLine
Hi,
I was using Quill 2.0.0 pre 4 in Angular 12, very well, but now after Angular
update to 13, I've got a Webpack error :
ncaught SyntaxError: Unexpected token ':' at Object../node_modules/quill-delta/dist/Op.js (quill.js:1861) at __nested_webpack_require_732__ (quill.js:36) at eval (Delta.js:9) at Object../node_modules/quill-delta/dist/Delta.js (quill.js:1837) at __nested_webpack_require_732__ (quill.js:36) at eval (quill.js:6) at Module../core/quill.js (quill.js:611) at __nested_webpack_require_732__ (quill.js:36) at eval (core.js:2) at Module../core.js (quill.js:539)
I'm testing with older versions : it's ok with quill 1.3.7...
I don't know what has changed between the two Angular versions that causes this problem...
Thanks,
Reproduction Steps:
IMO, if the range returns 1 then delta.slice() should also behave accordingly. Now I'm not sure how to correctly split the delta when this type of unicode characters are used as delta
Sometimes fast-diff
function works not very well.
This library https://github.com/liddiard/text-diff
with cleanupSemantic
works much better.
So it would be cool to add ability to use own diff
function.
for example add optional param here
Delta.prototype.diff = function (other, index, diffFunction?)
Hi there,
I'm using quill-delta
(version 4.2.2
) in a react native app (version 0.62.2
), as a format for rich text editing.
During bundle time I'm getting the following warning:
Require cycle: node_modules/quill-delta/dist/Op.js -> node_modules/quill-delta/dist/Iterator.js -> node_modules/quill-delta/dist/Op.js
And looking at the code it's clear to see that the two files are importing from each other.
Would it be possible to get rid of Op.iterator
and calling new Iterator(ops)
directly from delta.ts
?
While we would like to provide a base configuration of Succulent that includes a set of common formats by default, we want the library to be fully extensible. Consumers should be able to eschew our common formats for their own. We should create a Renderer
component that is completely abstracted away from our common formats.
I don't understand this extract from the official Quilljs website:
use the chainable
insert()
,delete()
, andretain()
methods to create new Deltas.
source: quilljs.com/docs/delta
Returns
this
for chainability.
source: github.com/quilljs/delta#insert
If this
is returned, it's not a new instance. Hence, why the doc refers to new Deltas ?
If I have a delta which consists of some inserts and now I want to replace a certain insert (no text but an object with some properties) with another insert (no text but an object). What is the best practice for this? I read that it is not done to create your own set of operations manually, but how is it done then? I see some functions, but I can't find a proper one.
Hello quill team:
I am developing an editor with the delta library. It seems that the version on NPM is a common.js version. (The code are under dist/
folder)
I need a ESModule version. So I forked the repo.
I want es version published with the common.js version:
/dist
for common.js version
/es
for es version
If you agree with this, I can submit a PR.
Hi, I am working on an app that uses delta as the rich text format.
I need to save the rich text in my SQLite database. I want to know what is the best method to save it. For example, save the whole JSON file in the database or save each command as a row?
I saw that the documentation calls out the lack of validity checks on operations/deltas provided to the constructor of a Delta
, but is there any interest in providing basic checks on insert
/delete
/retain
operations?
For example, if you call .insert(undefined)
on any well-formed Delta
and use diff
to compare that Delta
to another, it will raise an exception. Likewise, you can call .retain
or .delete
with a non-number value and it can produce an ill-formed Delta
. I've been using this library in a few projects (and it's fantastic) but was bitten after not guarding the type of a network call, inserting undefined
.
If that's of interest, I'd be happy to make a PR. I already opened up a fork with a simple undefined
check.
Old Text : I am Naveen
New Text : I am visakh
I am soumya
I tried find difference between above two versions ...
Old Delta : "{"ops":[{"insert":"I am Naveen\n"}]}"
New Delta : "{"ops":[{"insert":"I am visakh\nI am soumya\n"}]}"
Diff it is giving as : "{"ops":[{"retain":5},{"insert":"vis"},{"delete":1},{"retain":1},{"insert":"kh\nI am soumya"},{"delete":4}]}"
Here after "vis" insertion it is giving as deleted 1 which is wrong.
It should give as visakh inserted then delete right ??
Do am wrong??
Quill notes that "Deltas are implemented as a separate standalone library"; however, the README.md
here doesn't mention how to build or install the Deltas library. Is there a pre-compiled version I can grab? If not, how should I build it?
Not sure if this is intentional, but after updating to the latest quill
and quill-delta
, stuff like quill.setContents(new Delta())
no longer compiles unless I add an <any>
cast to the Delta
object.
Argument of type 'Delta' is not assignable to parameter of type 'DeltaStatic'.
Types of property 'reduce' are incompatible.
Type '<T>(predicate: (accum: T, curr: Op, index: number) => T, initialValue: T) => T' is not assignable to type '<T>(predicate: (acc: T, curr: DeltaOperation, idx: number, arr: DeltaOperation[]) => T, initial: T) => T'.
Types of parameters 'predicate' and 'predicate' are incompatible.
Hi,
Am I correct in understanding that a "document" delta is one which contains only "insert" operations? Are there additional constraints? i.e. it must end with a newline?
A "non-document" is the inverse?
I can't find this documented anywhere. Do you think it would be worth adding a sentence or two explaining this distinction at the start of the Readme somewhere, since the API docs refer to "document" and "non-document" deltas?
Thanks
This oddity was immediately noticed by my team as I'm trying to introduce Quill. All other properties seem to be spelled out. Why abbreviate "operations" to "ops"?
"delta": {
"ops": [
{
"attributes": {
"bold": true
},
"insert": "foo"
},
{
"insert": " "
},
{
"attributes": {
"italic": true
},
"insert": "b"
},
{
"attributes": {
"italic": true,
"bold": true
},
"insert": "ar"
},
{
"attributes": {
"bold": true
},
"insert": " "
},
{
"attributes": {
"underline": true,
"bold": true
},
"insert": "ba"
},
{
"attributes": {
"underline": true
},
"insert": "z"
},
{
"insert": "\n"
}
]
}
It would seem that the Delta structure does not provide for nested quotes and lists. Is this correct, and if so is there any chance for this support in the future?
The delta that's generated looks like:
{"ops":[{"retain":710},{"insert":" yesterday, and she says—”\n“The clinic?","attributes":{"prediction":"prediction"}},{"delete":28}]}
My code is:
const delta = new Delta()
.retain(documentData?.prediction?.currentPosition)
.delete(previousPredictionText?.length || 0)
.insert(predictionText, { prediction: 'prediction' })
console.log('delta', JSON.stringify(delta))
quillEditor.updateContents(delta)
It looks like I should first retain
, then delete
, then insert
, but the generated delta
seems to do it in a different order. What am I doing wrong?
Cross linked at https://stackoverflow.com/questions/63430548/why-does-a-qulljs-delta-appear-out-of-order if anyone wants magic internet points
Hello, I'm using the QuillJS library through unpkg. I have a script tag and am simply referencing the quill.js file. In my editor's text-change event I need to compose a new Delta object, but I am getting an undefined error.
I don't know how this works. I am working on an old vanilla js site with no transpilers or anything like that. I found the Delta library on unpkg too but it's made up of multiple files (it's not self-containing like Quill.js). I tried using another script tag and pointing it to the Delta.js file and I'm getting an error about a ts file. The documentation talks about Deltas and demonstrates creating them, as if they'll just work but it doesn't for me.
Do libraries have to do something special to make their code available through a single js file? And what can you do to get around it if you don't use newer js (module imports/exports/require) . Here's a simplified example of what I am trying to do:
myQuillObj.on('text-change', function(delta, old, source) {
if (delta[0].ops.insert == 'z') {
var d = new Delta().delete(1) // <= Delta is undefined
}
myQuillObj.updateContents(d, 'api)
}
I also tried doing a copy of the delta passed to me but the resulting object doesn't contain what it needs to. I'd have to use another library like lodash to do a deep copy, which requires newer js too.
Since the update to Quill 1.1.2 (and specifically this commit)
I'm getting the following error:
TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
at Delta.insert (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:2243:54)
at eval (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:3612:26)
at Array.reduce (native)
at Delta.reduce (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:2317:25)
at normalizeDelta (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:3595:22)
at Editor.applyDelta (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:3345:21)
at eval (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:1959:44)
at Quill.modify (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:2089:22)
at Quill.setContents (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/dist/quill.js:1955:27)
at RichEditable.setValue (https://au.fdy.io:5100/dist/components/editable/rich-editable.js:34:33)
at RichEditable.attached (https://au.fdy.io:5100/dist/components/editable/editable-base.js:47:26)
at Controller.attached (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/aurelia-templating.js:3472:24)
at View.attached (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/aurelia-templating.js:1563:24)
at ViewSlot.add (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/aurelia-templating.js:1726:14)
at eval (https://au.fdy.io:5100/jspm_packages/npm/[email protected]/aurelia-templating.js:4417:28)
It is because sometimes from our server the attributes on an insert object exists but is null or undefined.
It looks like a null/undefined check needs to be added here:
https://github.com/quilljs/delta/blob/master/lib/delta.js#L26
and here:
https://github.com/quilljs/delta/blob/master/lib/delta.js#L38
Moving issue to proper project (QuillJS) as it is a rendering issue, not a delta issue.
Please close this.
Delta seems to cover a lot of the same ground as Mobiledoc (https://github.com/bustle/mobiledoc-kit/blob/master/MOBILEDOC.md). Is there any specific reason that Quill choose to create Delta over using something like Mobiledoc?
Many thanks for this library.
I am facing this error diff() called with non-document
.
After some digging, I realized that the error is thrown from this line from quill-delta
https://github.com/quilljs/delta/blob/06ca777f67905ea6533272b2f88189ee06bb4197/src/Delta.ts#L278
If I understand correctly, for diff
to work, a document has to contain ONLY insert
Op.
But the result of .compose()
contains delete
Op.
You may run this simple Node code to reproduce the problem.
const Delta = require("quill-delta");
const oldContent = new Delta([
{
insert:
"Well, you see... I'm buying this hotel and setting some new rules about the pool area. Well, you see... I'm buying this hotel and setting some new rules about the pool area. Bruce Wayne, eccentric billionaire. ",
},
{
insert: {
citation: {
citationId: "2066",
label: "1",
},
},
},
{
insert: "\n",
},
]);
// This was generated from delta.diff(anotherDelta)
const diff = new Delta([
{
delete: 13,
},
{
retain: 2,
attributes: {
color: null,
},
},
{
delete: 27,
},
{
retain: 1,
attributes: {
color: null,
},
},
{
delete: 1,
},
{
retain: 1,
attributes: {
color: null,
},
},
{
delete: 4,
},
{
retain: 1,
attributes: {
color: null,
},
},
{
delete: 25,
},
{
retain: 1,
attributes: {
color: null,
},
},
{
insert: {
citation: {
citationId: "2063",
label: "1",
},
},
},
{
delete: 484,
},
]);
const newContent = oldContent.compose(diff);
console.log(newContent);
// result:
// [ { insert: '.. eg ' }, { insert: [Object] }, { delete: 347 } ] }
newContent.diff(new Delta());
// getting error `diff() called with non-document`
// because the `compose` result contains `delete`
.compose()
returns delete
Op?diff()
without getting the error diff() called with non-document
?it seem after last update, it can render delta properly
delta = {
ops: [{
insert: 'Hello',
attributes: {
italic: true
}
}, {
insert: ' world!!'
}]
}
on previous version it render
<p><em>Hello</em><span> world!!</span></p>
but on last version it render
<p>Hello world!!</p>
I render it using 'render-quill' library.
right now to fix this I lock quill version to 1.1.1
i think it happen because last fix for null and undefined object
I have an Angular app which started to give "fast-diff/diff has no default export"
error upon build after I've updated my dependencies.
I post it here because Error message begins with:
ERROR in node_modules/@types/quill/node_modules/quill-delta/dist/Delta.d.ts(1,8):
Please check.
UPDATE
I removed @types/quill from dependencies, now I don't get error and build does not fail.
Deleted issue -- posted to wrong repository.
It seems various configurations of Rollup cause this code to be generated:
Iterator.prototype.peekLength = function () {
if (this.ops[this.index]) {
// Should never return 0 if our index is being managed correctly
return Op_1$1.default.length(this.ops[this.index]) - this.offset;
}
else {
return Infinity;
}
};
Which at runtime throws:
TypeError: Cannot read property 'length' of undefined
This seems to be because there is a cyclic import which Rollup is barfing at:
Circular dependency: node_modules/quill-delta/dist/Op.js -> node_modules/quill-delta/dist/Iterator.js -> node_modules/quill-delta/dist/Op.js
🚀 PR incoming
Quill Delta is pretty compact representation for Rich Text. I really like it.
One issue I recently found was that delete operation are no invertible. So it can make undo/redo hard to implement.
But due to rich text can make up of multiple operations, I believe that if delete op is to be invertible, it have to store an array of insert ops.
var delta = new Delta([
{ insert: 'Gandalf', attributes: { bold: true } },
{ insert: ' the ' },
{ insert: 'Grey', attributes: { color: '#ccc' } }
]);
// If we were to delete 'dalf the Grey'…
var oldDeleteOp = [{ retain: 3 }, { delete: 13 }];
var proposedDeleteOp = [{ retain: 3 }, { delete: [
{ insert: 'dalf', attributes: { bold: true } },
{ insert: ' the ' },
{ insert: 'Grey', attributes: { color: '#ccc' } }
] }];
Which also meaning, the delete op cannot store non-document delta op. This definitely complicate Quill Delta format though.
Since quill-delta
has moved to [email protected]
, who now is unicode-safe (jhchen/fast-diff#4), using .diff()
on document that has a retain
leading to a unicode surrogate pair being broke, there is a Maximum call stack size exceeded
error.
Here is in 4.0.1 without error: https://repl.it/repls/PungentColorfulScandisk
And in 4.1.0 with the error: https://repl.it/repls/FrailLimitedCoolingfan
My guess is that as quill-delta
is not unicode-safe, any used dependency shouldn't be neither
I have seen examples of conversion of delta to html format, but no where its explained to convert html to delta format. Is there anyway to do that?
I want to allow the user to paste the contents of one quill editor to another, and the pasted contents is block-quoted with a reference header. The code (typescript in angular) looks like this:
const header = new Delta().insert('The following is a quote from xxxx\n', 'blockquote');
const cursor = this.editor.getSelection();
const start = cursor ? cursor.index : 0;
const paste = wbe.editor.getContents(wbe.selection.index, wbe.selection.length);
const delta = new Delta().retain(cursor.index).concat(header).concat(paste);
this.editor.updateContents(delta, 'api');
const length = delta.length(); // this is not the right value
this.editor.setSelection(start, length);
this.editor.format('blockquote', 'true');
The length() function doesn't return what I want, which is the number of inserted characters. Is there a function that does this or do I have to iterate through the delta to count them?
I'm wondering why https://github.com/quilljs/delta/blob/master/lib/delta.js#L49 line (and the deep clone dependency) is needed and if it ought to be removed for better performance. I've not seen performance issues but saw this and thought it was unnecessary. Thoughts?
It would be nice to have a Delta interface in addition to the class. That way, we could describe existing serialized data accurately, without having to create class instances.
As far as I understand this; such an interface could be as simple as:
interface QuillDelta {
ops: Op[];
}
Does this exist somewhere already?
The README file says that it should be possible to convert Delta to string using JSON.stringify()
. However, when I try to serialize a simple delta, I get the following error:
TypeError: Converting circular structure to JSON
Is this a bug or am I doing something wrong? I use Quill 1.3.4 integrated to my Angular application through ngx-quill
library.
Good evening guys.
I have opened a PR to add quill-delta
to flow-typed
.
In case you would like to take a look at it: flow-typed/flow-typed#1177
Please consider the following JSON/Delta provided.
{ "ops": [ { "insert": "List 1 - Item 1" }, { "attributes": { "list": "ordered" }, "insert": "\n" }, { "insert": "List 1 - Item 2" }, { "attributes": { "list": "ordered" }, "insert": "\n" }, { "insert": "\nSome text between lists ...\n\nList 2 - Item 1" }, { "attributes": { "list": "ordered" }, "insert": "\n" }, { "insert": "List 2 - Item 2" }, { "attributes": { "list": "ordered" }, "insert": "\n" }, { "insert": "\nSome final text ...\n" } ] }
I am writing conversion code that turns this delta into an identical WPF FlowDocument. I have no way to discern where 1 list ends and the other begins. Perhaps I am just not considering something, but from an interpretative stand-point (WPF FlowDocument specifically, and it's use of Nested Lists) - This is one thing I am struggling to get past.
Any thoughts on this?
I'm hoping to only use this project in the browser. How do I generate the file?
new Delta().retain(1).insert({b:2}).transform(new Delta().retain(1).retain(1,{a:1}),**false**)
// result is new Delta().retain(2).retain(1,{a:1})
new Delta().retain(1).insert({b:2}).transform(new Delta().retain(1).retain(1,{a:1}),**true**)
// result is new Delta().retain(2).retain(1,{a:1})
too.
but when delta contain "insert"
new Delta().retain(1).insert({b:2}).transform(new Delta().retain(1).insert({a:1}),**false**)
//result is new Delta().retain(1).insert({a:1})
new Delta().retain(1).insert({b:2}).transform(new Delta().retain(1).insert({a:1}),**true**)
//result is new Delta().retain(2).insert({a:1})
why the result of new Delta().retain(1).insert({b:2}).transform(new Delta().retain(1).retain(1,{a:1}),**false**)
is not new Delta().retain(1).retain(1,{a:1})
too.
Hi,
Very nice work on this one.
I'm working on a diff, that can show when deltas are changed/removed.
The tricky bit is- for delta's which are "deleted", I want to delete the text, but first get the contents of the delta that is deleted.
I've tried the "getText()" (quill) but it does not get the right text at all- I will pass it something like quill.getText(10,11) and it will return a much longer string that just what was deleted.
How can this be achieved?
export const getDiff = (ops, oldOps, quill) => {
return ops.map((op,inx)=>{
if(op.insert){
return {...op, attributes:{attributes:{
background: "green",
}}
}
else if(op.delete){
const startKeep = ops[inx-1].retain
const deletedText = quill.getText(startKeep, startKeep + op.delete)
return op
}
else{
return op
}
})
}
Using new Delta()
etc. and manipulating that, how can I convert it to DeltaStatic
?
In Quill
, updateContents
accepts only DeltaStatic
.
var temp = new Delta([
{ insert: 'Gandalf', attributes: { bold: true } },
]).retain(1).delete(2).insert('text').delete(1).retain(2).insert('more').delete(2);
Log
Questions
Why deletes after each retain is moved behind insert if insert is existed? It seems that the document about Delta does't state about this feature. Please help, thank you! 👍
after I read following code in delta.js
// Since it does not matter if we insert before or after deleting at the same index,
// always prefer to insert first
if (typeof lastOp['delete'] === 'number' && newOp.insert != null) {
index -= 1;
lastOp = this.ops[index - 1];
if (typeof lastOp !== 'object') {
this.ops.unshift(newOp);
return this;
}
}
Does it means that
"example"
"example"
In Designing the Delta Format, it says that:
we add the constraint that Deltas must be compact. With this constraint, the above representation is not a valid Delta, since it can be represented more compactly
However, when transforming a Delta using the map
or filter
methods, the result is not guaranteed to be compact since there can be adjacent ops that should be merged. A simple example case:
const input = new Delta()
.insert('hello ')
.insert('bold ', {bold: true})
.insert('world');
const output = new Delta(input.filter(op => !op.attributes?.bold));
Expected:
{"ops":[{"insert":"hello world"}]}
Actual:
{"ops":[{"insert":"hello "},{"insert":"world"}]}
It appears that compose
does enforce compactness, so you can use it to write a compactify function (this particular implementation assumes an insert-only/"document" delta, but could be easily extended to support the other op types):
function compactify(delta) {
return delta.reduce((composed, op) =>
composed.compose(
new Delta()
.retain(composed.length())
.insert(op.insert, op.attributes)
),
new Delta()
);
}
However, it would be nice if one could assume the result of any method on Delta is also a valid Delta/list of ops. Perhaps since these op lists have to be put back through the Delta constructor to get a Delta object again, that would be an ideal place to put such validation/normalization
Currently theres no elegant way to convert delta to html.
to do that even the delta is independent from quill. I found found people are using solutions like
function quillGetHTML(inputDelta) {
var tempCont = document.createElement("div");
(new Quill(tempCont)).setContents(inputDelta);
return tempCont.getElementsByClassName("ql-editor")[0].innerHTML;
}
I like the the concept of deltas but the. I don't want to render editor for blog site in frontend.
Here is the repro.
I haven't found a good way to solve this problem yet.
Hello,
Given two documents in delta format, is there a provided way to tell whether they represent the same content? I simply need to enable / disable a "dirty" flag.
I see a naive way, by generating the diff
and checking whether it is empty, however it is a costly operation. So:
Thanks for your time. I love quilljs' approach to editing. At last I can represent semantic elements in my documents and not formatting. CityBlot, …
I'm using the package in my Angular application and I get this warning during build time:
Warning: C:\Projects\...\my-file.ts depends on 'quill-delta'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Tools like webpack reasonably prefer es6 module format for packages that are to be used in the browser. It would be nice if quill-delta
adhered to that as well.
Is there a description anywhere of the delta format that will be introduced by the tables support coming in the next version of quilljs? I'm writing a parser for this format, and it would be good to be future-proof for the next version!
Based on a reading of the code, it looks like the text
of an "embed" isn't actually a number. Could you update the docs to reflect the current intended use? Thanks.
E.g. this would make undo simpler / faster.
The quilljs history module has a guessUndoDelta, which can only guess the undo of an insert, understandably -- you need the base delta to be able to calculate the undo of a delete, for example.
So I'm envisioning a delta.undoCompose(baseDelta)
such that the following holds true for any delta:
const undo = delta.undoCompose(baseDelta);
deepEqual(baseDelta.compose(delta).compose(undo), baseDelta)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.