Commit a60f90b1 authored by Michael Murtaugh's avatar Michael Murtaugh

initial commit

parents
Pipeline #453 failed with stages
node_modules/
package-lock.json
all: dist/app.js
dist/app.js: src/*.js
node_modules/.bin/rollup -c
Revision 0 is the setting of the initial contents of pad are set with a single "multi-line" operation:
The source_length is 1 (the implicit newline?).
{
source_length: 1,
final_op: ">",
final_diff: 414
ops_raw: "|7+bi",
bank: "Welcome to Etherpad \n\nThis pad is synchronized as you type ... settings.json\n",
bank_length: 414,
ops: [{
lines: 7,
chars: 414,
op: "lines",
code: "+"
}
]
}
As a line operation, the bank ends with a newline.
Could call this insert_lines?!
Next, I selected all text and blanked it, this is represented by:
{
source_length: 415,
final_op: "<",
final_diff: 414,
ops_raw: "|7-bi",
bank: ""
op: [{
op: "lines",
code: "-",
lines: 7,
chars: 414
}]
}
delete_lines
? simple rep op: (insert, delete, hold) with: [lines], chars
Each change set completely describes the changes to the text starting from the top. It however ends at the last change. The =N operation "holds" content that is static.
As the line based operations must end in a newline, the initial hold is often a combination of (hold N lines / x chars) folowed by (hold N chars).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>changesets</title>
<style type="text/css">
.insert {
background: yellow;
color: black;
}
</style>
</head>
<body>
<script src="dist/app.js"></script>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
(function () {
'use strict';
// Z:9kj>1|8=al=o4*1a|1+1$
function changeset_parse (c) {
let changeset_pat = /^Z:([0-9a-z]+)([><])([0-9a-z]+)(.+?)\$/,
op_pat = /(\|([0-9a-z]+)([\+\-\=])([0-9a-z]+))|([\*\+\-\=])([0-9a-z]+)/g,
parse_op = m => {
if (m[1]) {
return {
raw: m[0],
op: ((m[3] == "+") ? "insert" : ((m[3] == "-") ? "delete" : "hold")),
lines: parseInt(m[2], 36),
chars: parseInt(m[4], 36)
}
} else if (m[5] == "*") {
return {
raw: m[0],
op: "attr",
index: parseInt(m[6], 36)
}
} else {
return {
raw: m[0],
op: ((m[5] == "+") ? "insert" : ((m[5] == "-") ? "delete" : "hold")),
chars: parseInt(m[6], 36)
}
}
};
var m = changeset_pat.exec(c),
bank = c.substring(m[0].length),
ops_raw = m[4],
op = null,
ret = {
source_length: parseInt(m[1], 36),
final_op: m[2],
final_diff: parseInt(m[3], 36),
ops_raw: ops_raw,
ops: [],
bank: bank,
bank_length: bank.length
};
while (op = op_pat.exec(ops_raw)) {
ret.ops.push(parse_op(op));
}
return ret;
}
class Pad {
constructor (padname) {
this.padname = padname;
this.text = "\n";
this.changesets = null;
}
parse_json (data) {
let pad_data = data[`pad:${this.padname}`],
last_rev = pad_data.head;
this.changesets = [];
this.last_rev = last_rev;
// console.log("loaded");
// last_rev = 10;
for (let r = 0; r<=last_rev; r++) {
let d = data[`pad:${this.padname}:revs:${r}`];
this.changesets.push(changeset_parse(d.changeset));
}
// console.log("SAME", (this.text == pad_data.atext.text));
// console.log("done", last_rev)
return last_rev;
}
perform_changeset (input_text, c) {
let textpos = 0,
bank = c.bank,
bankpos = 0,
newtext = '';
// loop through the operations
// rebuilding the final text
for (let i=0, ops=c.ops.length; i<ops; i++) {
let op = c.ops[i];
if (op.op != "attr") ;
if (op.op == "insert") {
newtext += bank.substring(bankpos, bankpos+op.chars);
// advance positions
bankpos += op.chars;
// importantly, on an insert, the (original/old/previous) textpos
// does *not* increment...
} else if (op.op == "delete") {
textpos += op.chars;
} else if (op.op == "hold") {
newtext += input_text.substring(textpos, textpos+op.chars);
textpos += op.chars;
}
}
// append rest of old text...
newtext += input_text.substring(textpos);
return newtext;
}
perform_changeset_curline (input_text, c) {
let textpos = 0,
bank = c.bank,
bankpos = 0,
newtext = '',
curline = '';
// loop through the operations
// rebuilding the final text
for (let i=0, ops=c.ops.length; i<ops; i++) {
let op = c.ops[i];
if (op.op != "attr") ;
if (op.op == "insert") {
newtext += bank.substring(bankpos, bankpos+op.chars);
// advance positions
//if (!op.lines) {
curline += "<span class=\"insert\">"+bank.substring(bankpos, bankpos+op.chars)+"</span>";
//}
bankpos += op.chars;
// importantly, on an insert, the (original/old/previous) textpos
// does *not* increment...
} else if (op.op == "delete") {
textpos += op.chars;
} else if (op.op == "hold") {
newtext += input_text.substring(textpos, textpos+op.chars);
if (!op.lines) {
curline += "<span class=\"hold\">"+input_text.substring(textpos, textpos+op.chars)+"</span>";
}
textpos += op.chars;
}
}
// append rest of old text...
newtext += input_text.substring(textpos);
var rest_of_line = input_text.substring(textpos);
if (rest_of_line.indexOf("\n")) {
rest_of_line = rest_of_line.substring(0, rest_of_line.indexOf("\n"));
}
curline += "<span class=\"rest\">"+rest_of_line+"</span>";
return {text: newtext, curline: curline};
}
}
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
}
async function init (filename, padname) {
console.log("loading json...");
let resp = await fetch(filename),
data = await resp.json(),
pad_data = data[`pad:${padname}`];
var pad = new Pad(padname);
pad.parse_json(data);
var curtext = "\n";
var div = document.createElement("div");
document.body.appendChild(div);
for (var i=0; i<=pad.last_rev; i++) {
let change = pad.perform_changeset_curline(curtext, pad.changesets[i]);
// console.log(curtext);
curtext = change.text;
div.innerHTML = change.curline;
await wait(100);
}
console.log("CHECK", (curtext == pad_data.atext.text));
}
document.addEventListener("DOMContentLoaded", e => {
init("constantcodeofconduct2.etherpad.json", "constantcodeofconduct2");
// init("test.etherpad.json", "test");
});
}());
{
"name": "collectiveconditions",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"rollup": "^1.20.1",
"rollup-plugin-commonjs": "^10.0.2",
"rollup-plugin-node-resolve": "^5.2.0"
}
}
// rollup.config.js
// https://github.com/rollup/rollup-plugin-commonjs
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
export default [{
input: 'src/app.js',
output: {
file: 'dist/app.js',
format: 'iife',
name: 'app'
},
plugins: [
resolve(),
commonjs()
]
}];
// Z:9kj>1|8=al=o4*1a|1+1$
function changeset_parse (c) {
let changeset_pat = /^Z:([0-9a-z]+)([><])([0-9a-z]+)(.+?)\$/,
op_pat = /(\|([0-9a-z]+)([\+\-\=])([0-9a-z]+))|([\*\+\-\=])([0-9a-z]+)/g,
parse_op = m => {
if (m[1]) {
return {
raw: m[0],
op: ((m[3] == "+") ? "insert" : ((m[3] == "-") ? "delete" : "hold")),
lines: parseInt(m[2], 36),
chars: parseInt(m[4], 36)
}
} else if (m[5] == "*") {
return {
raw: m[0],
op: "attr",
index: parseInt(m[6], 36)
}
} else {
return {
raw: m[0],
op: ((m[5] == "+") ? "insert" : ((m[5] == "-") ? "delete" : "hold")),
chars: parseInt(m[6], 36)
}
}
};
var m = changeset_pat.exec(c),
bank = c.substring(m[0].length),
ops_raw = m[4],
op = null,
ret = {
source_length: parseInt(m[1], 36),
final_op: m[2],
final_diff: parseInt(m[3], 36),
ops_raw: ops_raw,
ops: [],
bank: bank,
bank_length: bank.length
};
while (op = op_pat.exec(ops_raw)) {
ret.ops.push(parse_op(op));
}
return ret;
}
class Pad {
constructor (padname) {
this.padname = padname;
this.text = "\n";
this.changesets = null;
}
parse_json (data) {
let pad_data = data[`pad:${this.padname}`],
last_rev = pad_data.head;
this.changesets = [];
this.last_rev = last_rev;
// console.log("loaded");
// last_rev = 10;
for (let r = 0; r<=last_rev; r++) {
let d = data[`pad:${this.padname}:revs:${r}`];
this.changesets.push(changeset_parse(d.changeset))
}
// console.log("SAME", (this.text == pad_data.atext.text));
// console.log("done", last_rev)
return last_rev;
}
perform_changeset (input_text, c) {
let textpos = 0,
textline = 0,
bank = c.bank,
bankpos = 0,
newtext = '';
// loop through the operations
// rebuilding the final text
for (let i=0, ops=c.ops.length; i<ops; i++) {
let op = c.ops[i];
if (op.op != "attr") {
// console.log(op);
}
if (op.op == "insert") {
newtext += bank.substring(bankpos, bankpos+op.chars);
// advance positions
bankpos += op.chars;
// importantly, on an insert, the (original/old/previous) textpos
// does *not* increment...
} else if (op.op == "delete") {
textpos += op.chars;
} else if (op.op == "hold") {
newtext += input_text.substring(textpos, textpos+op.chars);
textpos += op.chars;
}
}
// append rest of old text...
newtext += input_text.substring(textpos);
return newtext;
}
perform_changeset_curline (input_text, c) {
let textpos = 0,
textline = 0,
bank = c.bank,
bankpos = 0,
newtext = '',
curline = '';
// loop through the operations
// rebuilding the final text
for (let i=0, ops=c.ops.length; i<ops; i++) {
let op = c.ops[i];
if (op.op != "attr") {
// console.log(op);
}
if (op.op == "insert") {
newtext += bank.substring(bankpos, bankpos+op.chars);
// advance positions
//if (!op.lines) {
curline += "<span class=\"insert\">"+bank.substring(bankpos, bankpos+op.chars)+"</span>";
//}
bankpos += op.chars;
// importantly, on an insert, the (original/old/previous) textpos
// does *not* increment...
} else if (op.op == "delete") {
textpos += op.chars;
} else if (op.op == "hold") {
newtext += input_text.substring(textpos, textpos+op.chars);
if (!op.lines) {
curline += "<span class=\"hold\">"+input_text.substring(textpos, textpos+op.chars)+"</span>";
}
textpos += op.chars;
}
}
// append rest of old text...
newtext += input_text.substring(textpos);
var rest_of_line = input_text.substring(textpos);
if (rest_of_line.indexOf("\n")) {
rest_of_line = rest_of_line.substring(0, rest_of_line.indexOf("\n"));
}
curline += "<span class=\"rest\">"+rest_of_line+"</span>";
return {text: newtext, curline: curline};
}
}
async function wait (time) {
return new Promise(resolve => {
setTimeout(resolve, time);
})
}
async function init (filename, padname) {
console.log("loading json...");
let resp = await fetch(filename),
data = await resp.json(),
pad_data = data[`pad:${padname}`];
var pad = new Pad(padname);
pad.parse_json(data);
var curtext = "\n";
var div = document.createElement("div");
document.body.appendChild(div);
for (var i=0; i<=pad.last_rev; i++) {
let change = pad.perform_changeset_curline(curtext, pad.changesets[i]);
// console.log(curtext);
curtext = change.text;
div.innerHTML = change.curline;
await wait(100);
}
console.log("CHECK", (curtext == pad_data.atext.text))
}
document.addEventListener("DOMContentLoaded", e => {
init("constantcodeofconduct2.etherpad.json", "constantcodeofconduct2");
// init("test.etherpad.json", "test");
});
{
"pad:test": {
"atext": {
"text": "this\nis\na\ntest\n",
"attribs": "*0|3+a*0+4|1+1"
},
"pool": {
"numToAttrib": {
"0": [
"author",
"a.zGv0AuEvfEsLZu8Y"
]
},
"nextNum": 1
},
"head": 10,
"chatHead": -1,
"publicStatus": false,
"passwordHash": null,
"savedRevisions": []
},
"globalAuthor:a.zGv0AuEvfEsLZu8Y": {
"colorId": 51,
"name": null,
"timestamp": 1566571450963,
"padIDs": "test"
},
"pad:test:revs:0": {
"changeset": "Z:1>bi|7+bi$Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nGet involved with Etherpad at http://etherpad.org\n\nWarning: DirtyDB is used. This is fine for testing but not recommended for production. -- To suppress these warning messages change suppressErrorsInPadText to true in your settings.json\n",
"meta": {
"author": "",
"timestamp": 1566571430173,
"atext": {
"text": "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nGet involved with Etherpad at http://etherpad.org\n\nWarning: DirtyDB is used. This is fine for testing but not recommended for production. -- To suppress these warning messages change suppressErrorsInPadText to true in your settings.json\n\n",
"attribs": "|8+bj"
}
}
},
"pad:test:revs:1": {
"changeset": "Z:bj<bi|7-bi$",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571434844
}
},
"pad:test:revs:2": {
"changeset": "Z:1>3*0+3$thi",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571435888
}
},
"pad:test:revs:3": {
"changeset": "Z:4>2=3*0|1+2$s\n",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571436385
}
},
"pad:test:revs:4": {
"changeset": "Z:6>2|1=5*0+2$is",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571437111
}
},
"pad:test:revs:5": {
"changeset": "Z:8>1|1=5=2*0|1+1$\n",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571437613
}
},
"pad:test:revs:6": {
"changeset": "Z:9>2|2=8*0|1+2$a\n",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571438115
}
},
"pad:test:revs:7": {
"changeset": "Z:b>2|3=a*0+2$te",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571438714
}
},
"pad:test:revs:8": {
"changeset": "Z:d>2|3=a=2*0+2$xt",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571439217
}
},
"pad:test:revs:9": {
"changeset": "Z:f<1|3=a=2-1$",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571444601
}
},
"pad:test:revs:10": {
"changeset": "Z:e>1|3=a=2*0+1$s",
"meta": {
"author": "a.zGv0AuEvfEsLZu8Y",
"timestamp": 1566571445100
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment