Giter VIP home page Giter VIP logo

diffdom's Introduction

Fidus Writer

Fidus Writer is an online collaborative editor especially made for academics who need to use citations and/or formulas. The editor focuses on the content rather than the layout, so that with the same text, you can later on publish it in multiple ways: On a website, as a printed book, or as an ebook. In each case, you can choose from a number of layouts that are adequate for the medium of choice.

Fidus Writer

Coverage Status

Bountysource

Installation

The installation procedures can be found in our WIKI.

Contributing

For details on contributing, please check http://fiduswriter.org/help-us/ .

License

All of Fidus Writer's original code is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE, for details see LICENSE. Some third party libraries are licensed under other, compatible open source libraries. Licensing information is included in those files.

diffdom's People

Contributors

304notmodified avatar acusti avatar aquadk avatar ast-etsybin avatar cfsnyder avatar f95johansson avatar gaohuazuo avatar johanneswilm avatar kapouer avatar kranges avatar maronin avatar michaelbenin avatar noxharmonium avatar pomax avatar rahularora12 avatar sanarena avatar sqrtt avatar ssorallen avatar wbond avatar wildhoney avatar yguarata avatar z1ad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diffdom's Issues

Detecting events bound to DOM?

I was thinking about using diffDom to apply DOM changes when my models change, but then I realized that it probably doesn't check for bound events and transfer the events over to the new elements (or if they were removed - then unbind them).

How would you handle something like this?

INPUT modifyAttribute does not affect value

When you apply this type of diff on an INPUT element, the value is not changed in the DOM.

{"action":"modifyAttribute","route":[1],"name":"value","oldValue":"hello","newValue":""}

Funny thing you diff again and apply again and you get this diff instead:

{"action":"modifyValue","oldValue":"hello","newValue":"","route":[1]}

Then the INPUT value changes in the DOM.

Load up this file in your browser and see for yourself.
https://gist.github.com/martindrapeau/097e21bea76362a0976386ad9c0c7326

Removing first child results in overly complicated diff

Removing the last child node:
<h1>Foo</h1><h2>Bar</h2><h3>Baz</h3> to <h1>Foo</h1><h2>Bar</h2>

gives a nice clean diff:

{"action":"removeElement","route":[2],"element":{"nodeName":"H3","childNodes":[...]}}

Removing the first child node:
<h1>Foo</h1><h2>Bar</h2><h3>Baz</h3> to <h2>Bar</h2><h3>Baz</h3>

gives a massive diff:

{"action":"replaceElement","oldValue":{"nodeName":"H1","childNodes":[...]},"newValue":{"nodeName":"H2","childNodes":[...]},"route":[0]},
{"action":"replaceElement","oldValue":{"nodeName":"H2","childNodes":[...]},"newValue":{"nodeName":"H3","childNodes":[...]},"route":[1]},
{"action":"removeElement","route":[2],"element":{"nodeName":"H3","childNodes":[...]}}

Route Incorrect For Removals (Multiple Distinct Elements Have Same Route)

My understanding of the route attribute of a diff object is that it can be used to retrieve the original element that was modified. For removals, this element lives in the first dom, and for additions/modifications, it lives in the second. So given:

const { DOMParser, XMLSerializer } = require('xmldom')
        , p = new DOMParser()
        , domBefore = p.parseFromString(xmlBefore)
        , domAfter = p.parseFromString(xmlAfter)
        , diff = dd.diff(domBefore, domAfter);

We should have the invariant that for every element d of diff, dd.getFromRoute(d.action.includes('remove') ? domBefore : domAfter, d.route) is the same element as d.element.

However sometimes the last element of route is incorrect, breaking this invariant. Given xmlBefore of:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE assessment>
<assessment>
  <title>Test</title>
  <short_title>Test</short_title>
  <page>
    <title>Page 1</title>
    <question>
      <multiple_choice shuffle="true" select="multiple" labels="false">
        <choice value="A">Placeholder</choice>
        <choice value="B">Placeholder</choice>
      </multiple_choice>
      <part id="be03031c79464d08a5bce122fee68ffc">
        <response match="A" score="1">
          <feedback>
            <p id="aa3ab72153c834c8395a0099dff39d434"/>
          </feedback>
        </response>
        <response match="A,B" score="0" name="AUTOGEN_{A,B}">
          <feedback>
            <p id="ab8e552e886ee486baf47d45c778deac4"/>
          </feedback>
        </response>
        <response match="B" score="0" name="AUTOGEN_{B}">
          <feedback>
            <p id="aed5ccfa249794825a9fd6e05233ca5c1"/>
          </feedback>
        </response>
      </part>
    </question>
  </page>
</assessment>

and xmlAfter of:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE assessment>
<assessment>
  <title>Test</title>
  <short_title>Test</short_title>
  <page>
    <title>Page 1</title>
    <question>
      <multiple_choice shuffle="true" select="multiple" labels="false">
        <choice value="A">Placeholder</choice>
        <choice value="B">Placeholder</choice>
      </multiple_choice>
      <part id="be03031c79464d08a5bce122fee68ffc">
        <response match="A" score="1">
          <feedback>
            <p id="aa3ab72153c834c8395a0099dff39d434"/>
          </feedback>
        </response>
      </part>
    </question>
  </page>
</assessment>

diff is:

[ { action: 'removeTextElement',
    route: [ 4, 5, 3, 3, 0 ],
    value: '\r\n        ' },
  { action: 'removeElement',
    route: [ 4, 5, 3, 3, 0 ],
    element:
     { nodeName: 'response',
       attributes: [Object],
       childNodes: [Array] } },
  { action: 'removeTextElement',
    route: [ 4, 5, 3, 3, 0 ],
    value: '\r\n        ' },
  { action: 'removeElement',
    route: [ 4, 5, 3, 3, 0 ],
    element:
     { nodeName: 'response',
       attributes: [Object],
       childNodes: [Array] } },
  { action: 'modifyAttribute',
    route: [ 4, 5, 3, 3, 1 ],
    name: 'match',
    oldValue: 'B',
    newValue: 'A' },
  { action: 'removeAttribute',
    route: [ 4, 5, 3, 3, 1 ],
    name: 'name',
    value: 'AUTOGEN_{B}' },
  { action: 'modifyAttribute',
    route: [ 4, 5, 3, 3, 1 ],
    name: 'score',
    oldValue: '0',
    newValue: '1' },
  { action: 'removeElement',
    route: [ 4, 5, 3, 3, 1, 1, 1 ],
    element: { nodeName: 'p', attributes: [Object] } },
  { action: 'addElement',
    route: [ 4, 5, 3, 3, 1, 1, 1 ],
    element: { nodeName: 'p', attributes: [Object] } } ]

All of the removed elements have the same route [ 4, 5, 3, 3, 0 ]. I think this bug is caused by lines 936 and 945 of diffDOM.js, where

diffs.push(new Diff()
    .setValue(t._const.action, t._const.removeTextElement)
    .setValue(t._const.route, route.concat(index2))
    .setValue(t._const.value, node.data)
);

should actually be doing route.concat(index1). However I feel like this issue may exist elsewhere in the code where remove diff routes are handled. Can this be fixed so that the removal routes can be used to get dom elements from the first dom (domBefore)?

Diff spec

I would greatly appreciate documentation describing the structure and content of the calculated diffs, so I can process and manipulate them.

Thanks

Not playing well with inputs?

If I have an HTML input, type into it, and then some JavaScript runs that updates the dom using diffDOM, even if the input field itself has not changed, my typing disappears and the field loses focus.

Exception thrown in IE10

Iโ€™m seeing this error in IE 9 and 10:

image

This is the line (from diffDOM) where the exception is happening:

image

Which seems to be this line in the source:

node.insertBefore(this.objToNode(diff[this._const.element], node.namespaceURI === 'http://www.w3.org/2000/svg'), node.childNodes[c] || null);

Any ideas whatโ€™s happening here?

What license?

Hey,

I just noticed that you transferred the repo. Here's my two cents :)

  1. In countries where public domain doesn't exist, declaring something to be public domain leaves people in those countries with the raw untouched copyright laws (which aren't too permissive, as you may know). So, I suggest to use a license like MIT or BSD, which are both small and permissive.
  2. @Pomax it might make sense to recreate a repo called "DOM-diff" on your account and point users to this repo, since all stargazers and stuff were lost, when you deleted the old one...

adding post-.apply hook

I want to get hold of the affected nodes after applying the patch for some post processing. Right now this can reuse some of the exiting methods.

Would you consider this as something that should be part of the library?

New hook: actual text node diff

Hey there,

currently the text diff hook, is invoked when applying the diff if I read the docs correctly.

I would like to be able to extract a diff at diff time, though, in order to implement transformations / merging for text nodes. (My goal is to have the dom diff contain an actual text diff for all changed text nodes, instead of the new string)

Is this possible?

Simple text change results in overly complex diff

Change
<p><b>Foo</b> Bar <b>Baz</b></p>
to
<p><b>Foo</b> Car <b>Baz</b></p>

Expected diff:

{"action":"modifyTextElement","route":[0,1],"oldValue":" Bar ","newValue":" Car "}

Actual diff:

{"action":"modifyTextElement","route":[0,1],"oldValue":" Bar ","newValue":" Car "},
{"action":"removeTextElement","route":[0,1],"value":" Bar "},
{"action":"addTextElement","route":[0,1],"value":" Car "}

The second two actions are redundant

release ?

are there plans before next release ?

i'm just eager to remove the github url from my package.json :)

Simple diff gives 100s of redundant addElement/removeElement diffs

Exellent library. Using it to develop math editor that re-renders only changed nodes.

The following gives 3 diffs for the first diff and 203 for the second diff. Using diffDOM from repository two days ago.

<head>
  <meta charset="utf-8">
  <title>diffDOM</title>
  <script src="diffDOM/diffDOM.js"></script>
 </head>
<body>
  <div id="diffDOM"><span>a</span><span>b</span></div>
  <div id="diffDOM"><span>a</span>b</div>
</body>
<script>
  var el1  = document.querySelectorAll('#diffDOM')[0];
  var el2  = document.querySelectorAll('#diffDOM')[1];
  var dd = new diffDOM();
  var d = dd.diff(el1, el2);
  console.log(d)
  var d = dd.diff(el2, el1);
  console.log(d)
 </script>

vdom issues

Using a "virtual" dom nodes (in the form of JS Objects) instead of "real" DOM nodes (even though they off-screen and disconnected) has speed advantages. In the vdom branch diffDOM has been converted to do that for the building of the diff list. However, it is currently still buggier than the original version. When running random.html, at least two different types of errors show up every now and then. One of these bugs has been added to the top of the basic.html file.The other one was less easily reproducible but results in an error due to a missing parentNode around lines 1192/1210.

These issues are the main thing that prevent the vdom branch from being merged into the main branch.

@unbug is currently looking at the bug in basic.html.

Elements with matching IDs or classes are not matched more strongly

Although there is special code for creating identifiers based on ID or class, they don't change the behaviour of findCommonSubsets, as roughlyEqual gives the same result (true) for comparing <p id="foo"> with <p id="foo"> as it does <p id="foo"> with <p id="bar">.

The result is changing a document from

<p id="A"></p><p id="B"></p><p id="C"></p> to <p id="A"></p><p id="C"></p>

results in an overly complicated diff of

{"action":"removeElement","route":[0],"element":{"nodeName":"P","attributes":{"id":"A"}}},
{"action":"modifyAttribute","route":[0],"name":"id","oldValue":"B","newValue":"A"}

HTML Comments cause an exception

The error triggers on line 552 because t1.attributes is undefined.

The fix might be as simple as adding a check like

t1.attributes ? slice.call(...) : []

(and same for t2 on next line), but I haven't tested it yet.

Cannot read property 'childNodes' of undefined

With maxChildCount and maxChildCountDiffCount setted to small numeral, sometimes there are errors.
For example, with diffing of this two fragments and child counts = 1:

<div><ul data-gid="10"><li data-id="631"></li></ul><br><br><br></div>
<div><ul data-gid="14"><li data-id="644"></li></ul><br><br><br></div>

Eror Cannot read property 'childNodes' of undefined.
Looks like it is connected with repeated <br> tag.

Without maxChildCount it works good.

Modular compatibility

It shouldn't be hard, I'll provide a pull request if you want, but I came across a situation where I'm loading about five separate javascripts and figured it's time for AMD.js to handle it at this point.

jQuery, diffDOM, socket.io, responsive.js ,** patch.js

responsive.js is a script a wrote to handle some ui events.
patch.js listens to a node.js/socket.io server dispatching fs.watch file change events, applying html patches with diffDOM via AJAX/DOMParser.

Anyways, can you add AMD.js support or is that out of the question?

Failed to execute 'setAttribute' on 'Element': '"'

Sometimes I have get this error.
Failed to execute 'setAttribute' on 'Element': '"' is not a valid attribute at diffDOM.applyDiff
But I can't get what element can cause it.

The error appears at this line in diffDOM library:
node.setAttribute(diff.name, diff.value);

Call stack is:

    at http://dev.lc/min/?g=js_main&debug&v=13:8264:27
    at Array.forEach (<anonymous>)
    at diffDOM.apply (http://dev.lc/min/?g=js_main&debug&v=13:8263:19)
    at http://dev.lc/min/?g=js_main&debug&v=13:10675:24
    at Object.success (http://dev.lc/min/?g=js_main&debug&v=13:10565:25)
    at i (http://dev.lc/min/?g=js_main&debug&v=13:2:28017)
    at Object.fireWith [as resolveWith] (http://dev.lc/min/?g=js_main&debug&v=13:2:28783)
    at A (http://dev.lc/min/?g=js_main&debug&v=13:4:14035)
    at XMLHttpRequest.<anonymous> (http://dev.lc/min/?g=js_main&debug&v=13:4:16323)

What kind of situation can cause such error? What I have to check in my html?

Do not package the `venv` dir (reduce the installed size 200x)

Your current npm package size is 33 MiB, and unpacked size is 168 MiB (as of [email protected]).

167 MiB of that is inside the venv directory.

It looks like stuff from that directory is not used by the package, so most probably it was packaged by an accident.

You could add it to .npmignore (if you have an .npmignore already) or to .gitignore (if you don't have an .npmignore), or use the files field in your package.json file.

Directory listing with sizes:

4,0K    diff-dom-2.0.0.tgz/bower.json
8,0K    diff-dom-2.0.0.tgz/demo
48K     diff-dom-2.0.0.tgz/diffDOM1.js
48K     diff-dom-2.0.0.tgz/diffDOM2.js
48K     diff-dom-2.0.0.tgz/diffDOM.js
4,0K    diff-dom-2.0.0.tgz/index.html
8,0K    diff-dom-2.0.0.tgz/LICENSE.txt
40K     diff-dom-2.0.0.tgz/newDiffDOM.js
28K     diff-dom-2.0.0.tgz/oldDiffDOM.js
4,0K    diff-dom-2.0.0.tgz/package.json
4,0K    diff-dom-2.0.0.tgz/README.md
40K     diff-dom-2.0.0.tgz/RecentDiffDOM.js
4,0K    diff-dom-2.0.0.tgz/test3.html
156K    diff-dom-2.0.0.tgz/test.html
296K    diff-dom-2.0.0.tgz/tests
167M    diff-dom-2.0.0.tgz/venv

Sub diffs

It'd be nice to be able to stop diffing at a node. Would allow for nested diffDOMs / views.

Was thinking of something like sync="false" although perhaps definable?

Below works:

nodeToObj: function(node) {
            var objNode = {}, dobj = this;
            objNode.nodeName = node.nodeName;
            if (objNode.nodeName === '#text' || objNode.nodeName === '#comment') {
                objNode.data = node.data;
            } else {
                if (node.attributes && node.attributes.length > 0) {
                    objNode.attributes = {};
                    Array.prototype.slice.call(node.attributes).forEach(
                        function(attribute) {
                            objNode.attributes[attribute.name] = attribute.value;
                        }
                    );
                    if (objNode.attributes['sync'] === "false") objNode.sync = false;
                }
                if (node.childNodes && node.childNodes.length > 0 && objNode.sync !== false) {
                    objNode.childNodes = [];
                    Array.prototype.slice.call(node.childNodes).forEach(
                        function(childNode) {
                            objNode.childNodes.push(dobj.nodeToObj(childNode));
                        }
                    );
                }
                if (this.valueDiffing) {
                    if (node.value) {
                        objNode.value = node.value;
                    }
                    if (node.checked) {
                        objNode.checked = node.checked;
                    }
                    if (node.selected) {
                        objNode.selected = node.selected;
                    }
                }
            }

            return objNode;
        },

What do you think?

Are dom changes batched?

Say there are two divs, the second one has two more childnodes.

<div></div>

<div><h1>diffDOM demo</h1><h1>diffDOM2 demo</h1></div>

In this case, there are two diffs, one for each node addition. But, when I apply diff.apply(), are the node additions added by a single operation, (say, for eg, using documentfragment) or done each time for each diff ?

My guess is it doesnt batch operations, is it so?
If it doesnt, do you plan to add this in future releases?

Is it possible to know if a specific diff is an innerHTML diff?

Whenever the diff is innerHTML (or not an attribute diff) I would like to ignore that diff.
Is it possible to determine when a diff is innerHTML? As of now, I have noticed that innerHTML diffs typically show up at the end, after attribute diffs. Would that always be the case?

[Diff, Diff, Diff, Diff]
0: Diff
1: Diff
2: Diff
3: Diff // <= this one is innerHTML diff, I would like to remove it from the diff list

Improve diff to favor Move operations

First up, the library works quite well, already, which is awesome.

I've tested various different versions of this library so far, so I don't know whether this area has already seen improvements, but e.g. with the current interactive demo it's rather easy to trigger a removal and re-insertion of the iframe without touching the corresponding html tag.

Ideally the diff would move the element without destroying it.

diff excessively replace entire div rather than changing the innerText and then appendChild

Here I have two html strings:

original

<h2>this is a paragraph <code>ha</code>&nbsp;</h2><h2>this is another`h`&nbsp;</h2><ul><li>some stuff</li></ul> 

New

<h2>this is a paragraph <code>ha</code>&nbsp;</h2><h2>this is another<code>h</code>&nbsp;</h2><ul><li>some stuff</li></ul> 

diff generated

[{"14":5,"15":[1],"18":{"26":"H2","28":[{"24":"this is another`h`ย "}]}},{"14":9,"15":[1],"16":{"26":"UL","28":[{"26":"LI","28":[{"24":"some stuff"}]}]},"17":{"26":"H2","28":[{"24":"this is another"},{"26":"CODE","28":[{"24":"h"}]},{"24":"ย "}]}},{"14":6,"15":[2],"18":{"26":"UL","28":[{"26":"LI","28":[{"24":"some stuff"}]}]}}] 

I am thinking about ways to fix this. Any input?

adjacent text node agnostic merging

Starting this issue here to begin a conversation about text nodes. For the CryptPad use case we are pushing DiffDOM to it's limit by using it to patch changes to the DOM across the wire when people have typed in a contentEditable.
We have discovered an interesting issue that browsers like to split text nodes on occasions which don't always make sense. If we make a text node longer than a given length, the browser will decide to split it into two, if we hit backspace in the middle of a text node, the browser will decide to split it and then shorten the node before, rather than shifting the entire text node.

My gut feeling is that DiffDOM probably ought to be agnostic to adjacent text nodes when it merges. That is to say, it should see ["hel","lo ","world!"] the same as ["hello"," world!"]. Furthermore there is perhaps some performance to be gained by reusing the browser's trick when a few characters are removed from the middle of a text node to call Text.splitText() and then simply shorten the prior text node.

In any case, it would be nice if the adjacent text nodes in one DOM were not shoved into the other DOM which kills our cursor location and makes any sane Operational Transform quite impossible.

What do you think about this? Is considering adjacent text nodes as separate things a valued feature or is this something which you'd be open to a patch for?

Diff a detached node to an attached node.

This is similar to #11.

My use case is I want to template a custom element. When state changes, I want to take the rendered HTML and diff it to what is currently there. The custom element may or may not be in the document at this point in time. The diff() function is causing errors when DOM mutations happen because it seems to be invoking apply(). From reading the documentation, it seems that it shouldn't be invoking apply() automatically, but instead leaving that up to the user. Heres a JSBin for it.

In #11, you said:

I would suggest you just filter out any changes on the top node.

I'm not sure what you mean by that, but I assume that I'd have to have a diff object in order to do that. Probably easy enough, but you also said:

I don't see this being relevant enough as a feature.

You may be right in that it may not add that much convenience. I can't have much an opinion on the level of difficulty required to filter out any changes on the top node because I can't get there. However, I would think that making the API consumer mutate the diff object would be exposing an implementation detail that they shouldn't be concerned with. If this was a feature, it would probably allow the diffing between an actual DocumentFragment and a node in the DOM, which would potentially add a lot of convenience for some (me for sure).

Thanks for writing this. I'm excited to experiment with it given I can get past this hurdle.

just saying hi

Johannes,

Just letting you know I landed here now. I'm gonna give your lib a try.

Alex

Diff can unintentionally cause newValue to be undefined

JSFiddle that highlights the issue:
https://jsfiddle.net/ka2tvyq7/

JSFiddle with solution:
https://jsfiddle.net/nnzwdswh/

To observe the issue, type/remove some of the text from the input. Then hit the submit button. The first time the submit button is pressed, nothing happens, but the second time, the input value is set to undefined.

Relevant code used to test this:

var dd = new diffDOM();

// create two sets of identical html
var element1 = document.createElement('form');

var input = document.createElement('input');
    input.setAttribute('type', 'text');
    input.setAttribute('value', 'testing');

var submit = document.createElement('input');
    submit.setAttribute('type', 'submit');

element1.appendChild(input);
element1.appendChild(submit);

document.body.appendChild(element1);

// element2 will remain virtual, and we will diff element1 with element2
// to determine if we actually need to update the DOM or not.
var element2 = element1.cloneNode(true);

// event listener for when the input value changes
element1.addEventListener('input', function(e){
    // update the virtual element, then diff and see if there needs to be updates
    element2.firstChild.setAttribute('value', e.target.value);

    var diff = dd.diff(element1, element2);
    dd.apply(element1, diff);

    console.log(diff);
});

// event listener for pressing the submit button
element1.addEventListener('submit', function(e){
    e.preventDefault();

     // update the virtual element, then diff and see if there needs to be updates
    element2.firstChild.setAttribute('value', '');

    var diff = dd.diff(element1, element2);
    dd.apply(element1, diff);

    console.log(diff);
});

It appears that this issue revolves around any calls to node.setAttribute(...) within the library.
Instead of:

node.setAttribute(attribute, objNode.attributes[attribute]);

I changed it to:

node.setAttribute(attribute, objNode.attributes[attribute]);
node[attribute] = objNode.attributes[attribute];

This seems redundant, but it was the only way that seemed to get it to work as intended. Have a look and let me know what you think. I can put up a PR with the changes if you feel it is necessary.

Never ending loop when diffing specific DOM.

When I compare these two DOM elements:

<div class="columns small-9">
<select class="scoring-input scoring-select" onclick="fixSelection()"><option value="a9F6FCB4D-1E9B-493C-A8AA-E30B8B14B4AF">A - <p>Caprica</p>
</option><option value="m2" selected="true">B - <p>Iowa</p>
</option><option value="aA35C82E7-3690-4B8E-9CCB-7F669E98D0E4">C - <p>Mars Colony</p>
</option><option value="aFED1F76D-C161-48E5-91A8-4F633A567BE7">D - <p>Tatooine</p>
</option></select>
</div>

and

<div class="columns small-9">
<select class="scoring-input scoring-select" onclick="fixSelection()"><option value="a9F6FCB4D-1E9B-493C-A8AA-E30B8B14B4AF">A - <p>Caprica</p>
</option><option value="a4900B142-050F-4875-B386-1D61FB1A3A05">B - <p>Mars Colony</p>
</option><option value="m2" selected="true">C - <p>Iowa</p>
</option><option value="aFED1F76D-C161-48E5-91A8-4F633A567BE7">D - <p>Tatooine</p>
</option></select>
</div>

The diff code enters a never ending loop. It somehow has to do something with the changed attributes on the option elements.

When I add the following code:

if (difflist && difflist.length > 0) {
                    for(var looper = 0; looper < difflist.length; looper++) {
                        if (difflist[looper][14] === 10) {
                            difflist.splice(looper, 1);
                            looper--;
                        }
                    }
                }

                if (difflist && difflist.length === 0) {
                    difflist = undefined;
                }

To the bottom of the main loop (do {} while (difflist);), it fixes the issue, apparently even without side effects.... I figured that the diffing / applying of the attribute changes somewhere goes wrong.. and since Im not interested in the diff of attributes, this is a safe solution for me for now.

I know this is not THE solution, but I have neither the expertise nor the time to debug this any further. For now I will use a patched version of this lib. Please include a proper fix for this issue in the next release..

Preventing a `removeElement` action in `preDiffApply` is messing up diffs of an adjacent element.

Given the following markup:

<div id="a">
    <div class="before"></div>
    <a href="#before">Before</a>
</div>

<div id="b">
    <span class="after"></span>
    <a href="#after">After</a>
</div>

I set up a simple scenario where I want to diff #a against #b and apply the diff to #a, but I have used the preDiffApply function to try to prevent removal of the div element:

const a = document.querySelector('#a');
const b = document.querySelector('#b');

const differ = new diffDOM({
    preDiffApply: function(info){
        if(info.diff.action === 'removeElement' && info.node.nodeName === 'DIV' && info.node.classList.contains('before')){
            return true;
        }
    }
});

const diff = differ.diff(a, b);
differ.apply(a, diff);

I would expect that because I have only prevented the removeElement action, that the addElement action for the span would still take place, as would the modifyAttribute and modifyTextElement actions which would update the a element, and the following output would be the result of what #a would become:

<div id="b">
    <span class="after"></span>
    <div class="before"></div>
    <a href="#after">After</a>
</div>

However, the modifyAttribute and modifyTextElement actions are no longer performing correctly and the following output is the result instead:

<div id="b">
    <span class="after"></span>
    <div class="before"></div>
    <a href="#before">Before</a> <!-- this node has not changed as expected -->
</div>

If I log the info variable in the function, It looks like the modifyAttribute action is still present, but is not referencing the correct node, and the modifyTextElement action is missing altogether.

screen shot 2018-11-11 at 9 27 03 pm

Here is a full example file containing the code referenced in this issue:

diff-test.html.zip

pre-diff hooks

I'm using diffDOM for applying patches to a contentEditable section of a page, and it's working really well. Unfortunately, patching a DOM while you're editing has unwanted side effects that often displace the cursor selection.

I'm currently modifying parts of the diff algorithm to execute optional hooks that would expose information about the nodes which are being patched, which would make it much easier to gracefully handle cursor functionality. In general, I'd like to extend the library to address issues which are pertinent to diff/patching a contentEditable node.

I'd prefer to get these changes pushed upstream so I don't have to maintain a fork. Is there an IRC channel I can join to discuss changes more directly, or should I just submit a PR and go from there?

PS: Thanks for the excellent library, I tried a number of alternatives before settling on diffDOM.

Element filtering example

Can somebody explain how to exclude some elements from source from changing, please? For example, by class name?

In my situation there are new elements on the page (created with js) and there is no such elements in update coming from server via ajax. I need to remain this elements, and update everything else.

span inside paragraph diff with the entire paragraph

Hey @johanneswilm,

Here is the element being diff'ed

<p> some text <span alt='meta text'> some text</span> </p>

The patch that gets generated is pointed to the entire paragraph, which is the unexpected behavior. I have some tricky things going on inside of the span that I prefer the update patch is applied only to the span itself.

Any ideas of how to change this behavior? I would love to submit a PR if your time is constrained.

Deep freeze on generating diff from specific data

Looks like it's connected with amount of mixed (moved) ids. And looks like there is a nonlinear dependence somewhere in the algorithm.
This is two fragments (it is different sorting of the same rows):

Element 1
<ul><li id="ob987"></li><li id="ob986"></li><li id="ob988"></li><li id="ob991"></li><li id="ob989"></li><li id="ob992"></li><li id="ob993"></li><li id="ob990"></li><li id="ob742"></li><li id="ob741"></li><li id="ob743"></li><li id="ob744"></li><li id="ob749"></li><li id="ob745"></li><li id="ob751"></li><li id="ob752"></li><li id="ob753"></li><li id="ob755"></li><li id="ob754"></li><li id="ob756"></li><li id="ob757"></li><li id="ob758"></li><li id="ob760"></li><li id="ob759"></li><li id="ob761"></li><li id="ob762"></li><li id="ob763"></li><li id="ob764"></li><li id="ob765"></li><li id="ob766"></li><li id="ob767"></li><li id="ob768"></li><li id="ob770"></li><li id="ob769"></li><li id="ob771"></li><li id="ob773"></li><li id="ob772"></li><li id="ob775"></li><li id="ob774"></li><li id="ob776"></li><li id="ob777"></li><li id="ob779"></li><li id="ob778"></li><li id="ob780"></li><li id="ob781"></li><li id="ob782"></li><li id="ob784"></li><li id="ob783"></li><li id="ob785"></li><li id="ob786"></li><li id="ob787"></li><li id="ob789"></li><li id="ob788"></li><li id="ob790"></li><li id="ob791"></li><li id="ob792"></li><li id="ob793"></li><li id="ob794"></li><li id="ob795"></li><li id="ob802"></li><li id="ob801"></li><li id="ob803"></li><li id="ob804"></li><li id="ob797"></li><li id="ob796"></li><li id="ob798"></li><li id="ob799"></li><li id="ob800"></li><li id="ob805"></li><li id="ob806"></li><li id="ob807"></li><li id="ob809"></li><li id="ob808"></li><li id="ob810"></li><li id="ob811"></li><li id="ob812"></li><li id="ob814"></li><li id="ob813"></li><li id="ob815"></li><li id="ob816"></li><li id="ob817"></li><li id="ob819"></li><li id="ob818"></li><li id="ob820"></li><li id="ob821"></li><li id="ob822"></li><li id="ob823"></li><li id="ob824"></li><li id="ob825"></li><li id="ob827"></li><li id="ob826"></li><li id="ob828"></li><li id="ob829"></li><li id="ob830"></li><li id="ob832"></li><li id="ob831"></li><li id="ob833"></li><li id="ob834"></li><li id="ob836"></li><li id="ob835"></li><li id="ob837"></li><li id="ob838"></li><li id="ob839"></li><li id="ob841"></li><li id="ob840"></li><li id="ob842"></li><li id="ob843"></li><li id="ob844"></li><li id="ob846"></li><li id="ob845"></li><li id="ob847"></li><li id="ob849"></li><li id="ob848"></li><li id="ob850"></li><li id="ob851"></li><li id="ob852"></li><li id="ob854"></li><li id="ob853"></li><li id="ob856"></li><li id="ob857"></li><li id="ob855"></li><li id="ob858"></li><li id="ob860"></li><li id="ob859"></li><li id="ob862"></li><li id="ob861"></li><li id="ob864"></li><li id="ob865"></li><li id="ob866"></li><li id="ob863"></li><li id="ob868"></li><li id="ob867"></li><li id="ob870"></li><li id="ob871"></li><li id="ob872"></li><li id="ob869"></li><li id="ob874"></li><li id="ob873"></li><li id="ob875"></li><li id="ob877"></li><li id="ob876"></li><li id="ob879"></li><li id="ob880"></li><li id="ob881"></li><li id="ob878"></li><li id="ob883"></li><li id="ob882"></li><li id="ob885"></li><li id="ob886"></li><li id="ob887"></li><li id="ob884"></li><li id="ob888"></li><li id="ob889"></li><li id="ob890"></li><li id="ob891"></li><li id="ob892"></li><li id="ob894"></li><li id="ob895"></li><li id="ob893"></li><li id="ob897"></li><li id="ob896"></li><li id="ob900"></li><li id="ob898"></li><li id="ob899"></li><li id="ob901"></li><li id="ob903"></li><li id="ob902"></li><li id="ob905"></li><li id="ob906"></li><li id="ob904"></li><li id="ob907"></li><li id="ob909"></li><li id="ob910"></li><li id="ob908"></li><li id="ob912"></li><li id="ob911"></li><li id="ob914"></li><li id="ob915"></li><li id="ob916"></li><li id="ob913"></li><li id="ob918"></li><li id="ob917"></li><li id="ob920"></li><li id="ob921"></li><li id="ob922"></li><li id="ob919"></li><li id="ob924"></li><li id="ob923"></li><li id="ob926"></li><li id="ob927"></li><li id="ob928"></li><li id="ob925"></li><li id="ob930"></li><li id="ob929"></li><li id="ob932"></li><li id="ob933"></li><li id="ob934"></li><li id="ob931"></li><li id="ob936"></li><li id="ob935"></li><li id="ob937"></li><li id="ob938"></li><li id="ob940"></li><li id="ob939"></li><li id="ob941"></li><li id="ob942"></li><li id="ob944"></li><li id="ob943"></li><li id="ob946"></li><li id="ob947"></li><li id="ob948"></li><li id="ob945"></li><li id="ob950"></li><li id="ob949"></li><li id="ob952"></li><li id="ob953"></li><li id="ob954"></li><li id="ob951"></li><li id="ob956"></li><li id="ob955"></li><li id="ob958"></li><li id="ob959"></li><li id="ob960"></li><li id="ob957"></li><li id="ob961"></li><li id="ob962"></li><li id="ob964"></li><li id="ob963"></li><li id="ob965"></li><li id="ob966"></li><li id="ob967"></li><li id="ob968"></li><li id="ob970"></li><li id="ob969"></li><li id="ob971"></li><li id="ob974"></li><li id="ob972"></li><li id="ob975"></li><li id="ob976"></li><li id="ob973"></li><li id="ob977"></li><li id="ob978"></li><li id="ob979"></li><li id="ob981"></li><li id="ob980"></li><li id="ob982"></li><li id="ob983"></li><li id="ob984"></li><li id="ob985"></li><li id="ob995"></li><li id="ob994"></li><li id="ob996"></li><li id="ob997"></li><li id="ob998"></li><li id="ob999"></li><li id="ob1001"></li><li id="ob1000"></li><li id="ob1002"></li><li id="ob1003"></li><li id="ob1004"></li><li id="ob1005"></li><li id="ob1007"></li><li id="ob1006"></li><li id="ob1008"></li><li id="ob1009"></li><li id="ob1011"></li><li id="ob1010"></li><li id="ob1013"></li><li id="ob1012"></li><li id="ob1015"></li><li id="ob1014"></li><li id="ob1016"></li><li id="ob1017"></li><li id="ob1019"></li><li id="ob1018"></li><li id="ob1021"></li><li id="ob1020"></li><li id="ob1023"></li><li id="ob1022"></li><li id="ob1024"></li><li id="ob1025"></li><li id="ob1026"></li><li id="ob1027"></li><li id="ob1029"></li><li id="ob1028"></li><li id="ob1030"></li><li id="ob1031"></li><li id="ob1032"></li><li id="ob1033"></li><li id="ob1034"></li><li id="ob1035"></li><li id="ob1036"></li><li id="ob1038"></li><li id="ob1037"></li><li id="ob1040"></li><li id="ob1039"></li><li id="ob1041"></li><li id="ob1042"></li><li id="ob1043"></li><li id="ob1045"></li><li id="ob1046"></li><li id="ob1044"></li><li id="ob1048"></li><li id="ob1047"></li><li id="ob1053"></li><li id="ob1049"></li><li id="ob1050"></li><li id="ob1052"></li><li id="ob1051"></li><li id="ob1054"></li><li id="ob1059"></li><li id="ob1055"></li><li id="ob1056"></li><li id="ob1057"></li><li id="ob1058"></li><li id="ob1061"></li><li id="ob1060"></li><li id="ob1068"></li><li id="ob1062"></li><li id="ob1063"></li><li id="ob1064"></li><li id="ob1066"></li><li id="ob1067"></li><li id="ob1065"></li><li id="ob1070"></li><li id="ob1069"></li><li id="ob1076"></li><li id="ob1071"></li><li id="ob1072"></li><li id="ob1073"></li><li id="ob1075"></li><li id="ob1077"></li><li id="ob1074"></li><li id="ob1078"></li><li id="ob1079"></li><li id="ob1080"></li><li id="ob1081"></li><li id="ob1083"></li><li id="ob1084"></li><li id="ob1082"></li><li id="ob1086"></li><li id="ob1085"></li><li id="ob1087"></li><li id="ob1088"></li><li id="ob1089"></li><li id="ob1091"></li><li id="ob1092"></li><li id="ob1090"></li><li id="ob1093"></li><li id="ob1094"></li><li id="ob1095"></li><li id="ob1096"></li><li id="ob1097"></li><li id="ob1099"></li><li id="ob1098"></li><li id="ob1100"></li><li id="ob1101"></li><li id="ob1102"></li><li id="ob1104"></li><li id="ob1105"></li><li id="ob1103"></li><li id="ob1106"></li><li id="ob1107"></li><li id="ob1108"></li><li id="ob1109"></li><li id="ob1111"></li><li id="ob1110"></li></ul>

Element 2
<ul><li id="ob745"></li><li id="ob744"></li><li id="ob758"></li><li id="ob741"></li><li id="ob754"></li><li id="ob756"></li><li id="ob757"></li><li id="ob761"></li><li id="ob755"></li><li id="ob759"></li><li id="ob763"></li><li id="ob767"></li><li id="ob768"></li><li id="ob766"></li><li id="ob774"></li><li id="ob769"></li><li id="ob743"></li><li id="ob762"></li><li id="ob742"></li><li id="ob760"></li><li id="ob778"></li><li id="ob783"></li><li id="ob788"></li><li id="ob764"></li><li id="ob780"></li><li id="ob785"></li><li id="ob753"></li><li id="ob765"></li><li id="ob792"></li><li id="ob796"></li><li id="ob776"></li><li id="ob777"></li><li id="ob775"></li><li id="ob801"></li><li id="ob805"></li><li id="ob771"></li><li id="ob781"></li><li id="ob808"></li><li id="ob790"></li><li id="ob803"></li><li id="ob798"></li><li id="ob810"></li><li id="ob791"></li><li id="ob795"></li><li id="ob751"></li><li id="ob752"></li><li id="ob749"></li><li id="ob773"></li><li id="ob772"></li><li id="ob770"></li><li id="ob813"></li><li id="ob818"></li><li id="ob834"></li><li id="ob831"></li><li id="ob833"></li><li id="ob832"></li><li id="ob823"></li><li id="ob800"></li><li id="ob807"></li><li id="ob789"></li><li id="ob797"></li><li id="ob793"></li><li id="ob804"></li><li id="ob782"></li><li id="ob825"></li><li id="ob779"></li><li id="ob802"></li><li id="ob835"></li><li id="ob784"></li><li id="ob786"></li><li id="ob840"></li><li id="ob787"></li><li id="ob817"></li><li id="ob814"></li><li id="ob845"></li><li id="ob848"></li><li id="ob847"></li><li id="ob846"></li><li id="ob853"></li><li id="ob815"></li><li id="ob820"></li><li id="ob824"></li><li id="ob858"></li><li id="ob816"></li><li id="ob859"></li><li id="ob794"></li><li id="ob799"></li><li id="ob806"></li><li id="ob811"></li><li id="ob828"></li><li id="ob837"></li><li id="ob812"></li><li id="ob809"></li><li id="ob826"></li><li id="ob861"></li><li id="ob842"></li><li id="ob850"></li><li id="ob856"></li><li id="ob860"></li><li id="ob857"></li><li id="ob855"></li><li id="ob854"></li><li id="ob867"></li><li id="ob870"></li><li id="ob882"></li><li id="ob865"></li><li id="ob871"></li><li id="ob886"></li><li id="ob887"></li><li id="ob864"></li><li id="ob885"></li><li id="ob873"></li><li id="ob838"></li><li id="ob839"></li><li id="ob836"></li><li id="ob876"></li><li id="ob829"></li><li id="ob880"></li><li id="ob830"></li><li id="ob827"></li><li id="ob879"></li><li id="ob851"></li><li id="ob852"></li><li id="ob849"></li><li id="ob895"></li><li id="ob893"></li><li id="ob892"></li><li id="ob898"></li><li id="ob896"></li><li id="ob843"></li><li id="ob844"></li><li id="ob894"></li><li id="ob841"></li><li id="ob900"></li><li id="ob875"></li><li id="ob874"></li><li id="ob902"></li><li id="ob907"></li><li id="ob821"></li><li id="ob822"></li><li id="ob904"></li><li id="ob908"></li><li id="ob909"></li><li id="ob819"></li><li id="ob872"></li><li id="ob869"></li><li id="ob868"></li><li id="ob888"></li><li id="ob890"></li><li id="ob891"></li><li id="ob866"></li><li id="ob863"></li><li id="ob862"></li><li id="ob889"></li><li id="ob911"></li><li id="ob917"></li><li id="ob905"></li><li id="ob914"></li><li id="ob920"></li><li id="ob906"></li><li id="ob910"></li><li id="ob915"></li><li id="ob921"></li><li id="ob923"></li><li id="ob926"></li><li id="ob929"></li><li id="ob932"></li><li id="ob901"></li><li id="ob935"></li><li id="ob899"></li><li id="ob927"></li><li id="ob933"></li><li id="ob897"></li><li id="ob883"></li><li id="ob912"></li><li id="ob916"></li><li id="ob884"></li><li id="ob913"></li><li id="ob940"></li><li id="ob939"></li><li id="ob941"></li><li id="ob938"></li><li id="ob946"></li><li id="ob947"></li><li id="ob943"></li><li id="ob953"></li><li id="ob959"></li><li id="ob952"></li><li id="ob958"></li><li id="ob965"></li><li id="ob949"></li><li id="ob955"></li><li id="ob963"></li><li id="ob928"></li><li id="ob925"></li><li id="ob903"></li><li id="ob924"></li><li id="ob881"></li><li id="ob878"></li><li id="ob877"></li><li id="ob961"></li><li id="ob934"></li><li id="ob931"></li><li id="ob930"></li><li id="ob991"></li><li id="ob974"></li><li id="ob972"></li><li id="ob988"></li><li id="ob971"></li><li id="ob969"></li><li id="ob986"></li><li id="ob978"></li><li id="ob979"></li><li id="ob977"></li><li id="ob980"></li><li id="ob997"></li><li id="ob996"></li><li id="ob994"></li><li id="ob983"></li><li id="ob982"></li><li id="ob962"></li><li id="ob1002"></li><li id="ob1000"></li><li id="ob948"></li><li id="ob989"></li><li id="ob945"></li><li id="ob944"></li><li id="ob1006"></li><li id="ob1003"></li><li id="ob1009"></li><li id="ob1017"></li><li id="ob1014"></li><li id="ob1024"></li><li id="ob1022"></li><li id="ob918"></li><li id="ob942"></li><li id="ob1025"></li><li id="ob922"></li><li id="ob919"></li><li id="ob1008"></li><li id="ob1016"></li><li id="ob1028"></li><li id="ob1011"></li><li id="ob957"></li><li id="ob960"></li><li id="ob1031"></li><li id="ob956"></li><li id="ob1034"></li><li id="ob1019"></li><li id="ob1039"></li><li id="ob990"></li><li id="ob973"></li><li id="ob999"></li><li id="ob995"></li><li id="ob1030"></li><li id="ob1035"></li><li id="ob1047"></li><li id="ob1036"></li><li id="ob1041"></li><li id="ob1049"></li><li id="ob1055"></li><li id="ob1054"></li><li id="ob1042"></li><li id="ob1050"></li><li id="ob1056"></li><li id="ob966"></li><li id="ob1057"></li><li id="ob1043"></li><li id="ob1106"></li><li id="ob992"></li><li id="ob998"></li><li id="ob993"></li><li id="ob987"></li><li id="ob1060"></li><li id="ob1069"></li><li id="ob1062"></li><li id="ob1071"></li><li id="ob1063"></li><li id="ob1072"></li><li id="ob1078"></li><li id="ob1085"></li><li id="ob1064"></li><li id="ob1073"></li><li id="ob1079"></li><li id="ob1093"></li><li id="ob1098"></li><li id="ob967"></li><li id="ob968"></li><li id="ob964"></li><li id="ob1087"></li><li id="ob1094"></li><li id="ob1080"></li><li id="ob975"></li><li id="ob976"></li><li id="ob970"></li><li id="ob1095"></li><li id="ob1032"></li><li id="ob1033"></li><li id="ob1029"></li><li id="ob1044"></li><li id="ob937"></li><li id="ob1088"></li><li id="ob1081"></li><li id="ob936"></li><li id="ob1089"></li><li id="ob1096"></li><li id="ob1048"></li><li id="ob1038"></li><li id="ob1107"></li><li id="ob1053"></li><li id="ob1020"></li><li id="ob1051"></li><li id="ob1108"></li><li id="ob954"></li><li id="ob1045"></li><li id="ob951"></li><li id="ob1046"></li><li id="ob950"></li><li id="ob1040"></li><li id="ob1102"></li><li id="ob1100"></li><li id="ob1023"></li><li id="ob1026"></li><li id="ob1090"></li><li id="ob1018"></li><li id="ob1021"></li><li id="ob1027"></li><li id="ob1015"></li><li id="ob1101"></li><li id="ob1037"></li><li id="ob1103"></li><li id="ob1104"></li><li id="ob1105"></li><li id="ob1099"></li><li id="ob1012"></li><li id="ob1091"></li><li id="ob1092"></li><li id="ob1086"></li><li id="ob1067"></li><li id="ob1061"></li><li id="ob1109"></li><li id="ob1007"></li><li id="ob1065"></li><li id="ob1010"></li><li id="ob1013"></li><li id="ob1074"></li><li id="ob1059"></li><li id="ob1068"></li><li id="ob1005"></li><li id="ob1001"></li><li id="ob1004"></li><li id="ob1077"></li><li id="ob1084"></li><li id="ob1070"></li><li id="ob1052"></li><li id="ob1066"></li><li id="ob1075"></li><li id="ob1083"></li><li id="ob1076"></li><li id="ob1058"></li><li id="ob1110"></li><li id="ob1097"></li><li id="ob1082"></li><li id="ob985"></li><li id="ob984"></li><li id="ob981"></li><li id="ob1111"></li></ul>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.