Refactored out TextPatcher and JsonOT and replaced with new ChainPad

pull/1/head
Caleb James DeLisle 7 years ago
parent 7f8147b18b
commit 75130150d5

@ -29,10 +29,10 @@
"json.sortify": "~2.1.0", "json.sortify": "~2.1.0",
"secure-fabric.js": "secure-v1.7.9", "secure-fabric.js": "secure-v1.7.9",
"hyperjson": "~1.4.0", "hyperjson": "~1.4.0",
"textpatcher": "^1.3.0",
"chainpad-json-validator": "^0.2.0",
"chainpad-crypto": "^0.1.3", "chainpad-crypto": "^0.1.3",
"chainpad-listmap": "^0.3.0", "chainpad-listmap": "git+https://git@github.com/xwiki-labs/chainpad-listmap.git#new-chainpad",
"chainpad": "git+https://git@github.com/xwiki-contrib/chainpad.git#transform-issues",
"chainpad-netflux": "^0.6.0",
"file-saver": "1.3.1", "file-saver": "1.3.1",
"alertifyjs": "1.0.11", "alertifyjs": "1.0.11",
"scrypt-async": "1.2.0", "scrypt-async": "1.2.0",

@ -1,6 +1,5 @@
define([ define([
'jquery', 'jquery',
'/bower_components/textpatcher/TextPatcher.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/diffMarked.js', '/common/diffMarked.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
@ -38,7 +37,6 @@ define([
], function ( ], function (
$, $,
TextPatcher,
Cryptpad, Cryptpad,
DiffMd, DiffMd,
nThen, nThen,

@ -1,308 +0,0 @@
define([
'jquery',
'/common/modes.js',
'/common/themes.js',
'/bower_components/file-saver/FileSaver.min.js'
], function ($, Modes, Themes) {
var saveAs = window.saveAs;
var module = {};
module.create = function (ifrw, Cryptpad, defaultMode, CMeditor) {
var exp = {};
var Messages = Cryptpad.Messages;
var CodeMirror = exp.CodeMirror = CMeditor;
CodeMirror.modeURL = "cm/mode/%N/%N";
var $pad = $('#pad-iframe');
var $textarea = exp.$textarea = $('#editor1');
if (!$textarea.length) { $textarea = exp.$textarea = $pad.contents().find('#editor1'); }
var Title;
var onLocal = function () {};
var $rightside;
var $drawer;
exp.init = function (local, title, toolbar) {
if (typeof local === "function") {
onLocal = local;
}
Title = title;
$rightside = toolbar.$rightside;
$drawer = toolbar.$drawer;
};
var editor = exp.editor = CMeditor.fromTextArea($textarea[0], {
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets : true,
showTrailingSpace : true,
styleActiveLine : true,
search: true,
highlightSelectionMatches: {showToken: /\w+/},
extraKeys: {"Shift-Ctrl-R": undefined},
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
mode: defaultMode || "javascript",
readOnly: true
});
editor.setValue(Messages.codeInitialState);
var setMode = exp.setMode = function (mode, cb) {
exp.highlightMode = mode;
if (mode !== "text") {
CMeditor.autoLoadMode(editor, mode);
}
editor.setOption('mode', mode);
if (exp.$language) {
var name = exp.$language.find('a[data-value="' + mode + '"]').text() || undefined;
name = name ? Messages.languageButton + ' ('+name+')' : Messages.languageButton;
exp.$language.setValue(mode, name);
}
if(cb) { cb(mode); }
};
var setTheme = exp.setTheme = (function () {
var path = '/common/theme/';
var $head = $(ifrw.document.head);
var themeLoaded = exp.themeLoaded = function (theme) {
return $head.find('link[href*="'+theme+'"]').length;
};
var loadTheme = exp.loadTheme = function (theme) {
$head.append($('<link />', {
rel: 'stylesheet',
href: path + theme + '.css',
}));
};
return function (theme, $select) {
if (!theme) {
editor.setOption('theme', 'default');
} else {
if (!themeLoaded(theme)) {
loadTheme(theme);
}
editor.setOption('theme', theme);
}
if ($select) {
var name = theme || undefined;
name = name ? Messages.themeButton + ' ('+theme+')' : Messages.themeButton;
$select.setValue(theme, name);
}
};
}());
exp.getHeadingText = function () {
var lines = editor.getValue().split(/\n/);
var text = '';
lines.some(function (line) {
// lines including a c-style comment are also valuable
var clike = /^\s*(\/\*|\/\/)(.*)?(\*\/)*$/;
if (clike.test(line)) {
line.replace(clike, function (a, one, two) {
if (!(two && two.replace)) { return; }
text = two.replace(/\*\/\s*$/, '').trim();
});
return true;
}
// lisps?
var lispy = /^\s*(;|#\|)+(.*?)$/;
if (lispy.test(line)) {
line.replace(lispy, function (a, one, two) {
text = two;
});
return true;
}
// lines beginning with a hash are potentially valuable
// works for markdown, python, bash, etc.
var hash = /^#+(.*?)$/;
if (hash.test(line)) {
line.replace(hash, function (a, one) {
text = one;
});
return true;
}
// TODO make one more pass for multiline comments
});
return text.trim();
};
exp.configureLanguage = function (cb, onModeChanged) {
var options = [];
Modes.list.forEach(function (l) {
options.push({
tag: 'a',
attributes: {
'data-value': l.mode,
'href': '#',
},
content: l.language // Pretty name of the language value
});
});
var dropdownConfig = {
text: 'Mode', // Button initial text
options: options, // Entries displayed in the menu
left: true, // Open to the left of the button
isSelect: true,
feedback: 'CODE_LANGUAGE',
};
var $block = exp.$language = Cryptpad.createDropdown(dropdownConfig);
$block.find('button').attr('title', Messages.languageButtonTitle);
$block.find('a').click(function () {
setMode($(this).attr('data-value'), onModeChanged);
onLocal();
});
if ($drawer) { $drawer.append($block); }
if (cb) { cb(); }
};
exp.configureTheme = function (cb) {
/* Remember the user's last choice of theme using localStorage */
var themeKey = 'CRYPTPAD_CODE_THEME';
var lastTheme = localStorage.getItem(themeKey) || 'default';
var options = [];
Themes.forEach(function (l) {
options.push({
tag: 'a',
attributes: {
'data-value': l.name,
'href': '#',
},
content: l.name // Pretty name of the language value
});
});
var dropdownConfig = {
text: 'Theme', // Button initial text
options: options, // Entries displayed in the menu
left: true, // Open to the left of the button
isSelect: true,
initialValue: lastTheme,
feedback: 'CODE_THEME',
};
var $block = exp.$theme = Cryptpad.createDropdown(dropdownConfig);
$block.find('button').attr('title', Messages.themeButtonTitle);
setTheme(lastTheme, $block);
$block.find('a').click(function () {
var theme = $(this).attr('data-value');
setTheme(theme, $block);
localStorage.setItem(themeKey, theme);
});
if ($drawer) { $drawer.append($block); }
if (cb) { cb(); }
};
exp.exportText = function () {
var text = editor.getValue();
var ext = Modes.extensionOf(exp.highlightMode);
var title = Cryptpad.fixFileName(Title ? Title.suggestTitle('cryptpad') : "?") + (ext || '.txt');
Cryptpad.prompt(Messages.exportPrompt, title, function (filename) {
if (filename === null) { return; }
var blob = new Blob([text], {
type: 'text/plain;charset=utf-8'
});
saveAs(blob, filename);
});
};
exp.importText = function (content, file) {
var $bar = ifrw.$('#cme_toolbox');
var mode;
var mime = CodeMirror.findModeByMIME(file.type);
if (!mime) {
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CMeditor.findModeByExtension(ext[1]);
mode = mode && mode.mode || null;
}
} else {
mode = mime && mime.mode || null;
}
if (mode && Modes.list.some(function (o) { return o.mode === mode; })) {
setMode(mode);
$bar.find('#language-mode').val(mode);
} else {
console.log("Couldn't find a suitable highlighting mode: %s", mode);
setMode('text');
$bar.find('#language-mode').val('text');
}
editor.setValue(content);
onLocal();
};
var cursorToPos = function(cursor, oldText) {
var cLine = cursor.line;
var cCh = cursor.ch;
var pos = 0;
var textLines = oldText.split("\n");
for (var line = 0; line <= cLine; line++) {
if(line < cLine) {
pos += textLines[line].length+1;
}
else if(line === cLine) {
pos += cCh;
}
}
return pos;
};
var posToCursor = function(position, newText) {
var cursor = {
line: 0,
ch: 0
};
var textLines = newText.substr(0, position).split("\n");
cursor.line = textLines.length - 1;
cursor.ch = textLines[cursor.line].length;
return cursor;
};
exp.setValueAndCursor = function (oldDoc, remoteDoc, TextPatcher) {
var scroll = editor.getScrollInfo();
//get old cursor here
var oldCursor = {};
oldCursor.selectionStart = cursorToPos(editor.getCursor('from'), oldDoc);
oldCursor.selectionEnd = cursorToPos(editor.getCursor('to'), oldDoc);
editor.setValue(remoteDoc);
editor.save();
var op = TextPatcher.diff(oldDoc, remoteDoc);
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextPatcher.transformCursor(oldCursor[attr], op);
});
if(selects[0] === selects[1]) {
editor.setCursor(posToCursor(selects[0], remoteDoc));
}
else {
editor.setSelection(posToCursor(selects[0], remoteDoc), posToCursor(selects[1], remoteDoc));
}
editor.scrollTo(scroll.left, scroll.top);
};
return exp;
};
return module;
});

@ -1,9 +1,9 @@
define([ define([
'jquery', 'jquery',
'/bower_components/chainpad-json-validator/json-ot.js',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad/chainpad.dist.js', '/bower_components/chainpad/chainpad.dist.js',
], function ($, JsonOT, Crypto) { ], function ($, Crypto) {
var ChainPad = window.ChainPad; var ChainPad = window.ChainPad;
var History = {}; var History = {};
@ -28,7 +28,7 @@ define([
return ChainPad.create({ return ChainPad.create({
userName: 'history', userName: 'history',
initialState: '', initialState: '',
transformFunction: JsonOT.validate, patchTransformer: ChainPad.NaiveJSONStransformer,
logLevel: 0, logLevel: 0,
noPrune: true noPrune: true
}); });

@ -3,8 +3,7 @@ define([
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-netflux/chainpad-netflux.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/bower_components/textpatcher/TextPatcher.js' ], function ($, Crypto, Realtime, Cryptpad) {
], function ($, Crypto, Realtime, Cryptpad, TextPatcher) {
//var Messages = Cryptpad.Messages; //var Messages = Cryptpad.Messages;
//var noop = function () {}; //var noop = function () {};
var finish = function (S, err, doc) { var finish = function (S, err, doc) {
@ -72,9 +71,7 @@ define([
var realtime = Session.session = info.realtime; var realtime = Session.session = info.realtime;
Session.network = info.network; Session.network = info.network;
TextPatcher.create({ realtime.contentUpdate(doc);
realtime: realtime,
})(doc);
var to = window.setTimeout(function () { var to = window.setTimeout(function () {
cb(new Error("Timeout")); cb(new Error("Timeout"));

@ -11,11 +11,9 @@ define([
'/common/common-title.js', '/common/common-title.js',
'/common/common-metadata.js', '/common/common-metadata.js',
'/common/common-messaging.js', '/common/common-messaging.js',
'/common/common-codemirror.js',
'/common/common-file.js', '/common/common-file.js',
'/file/file-crypto.js', '/file/file-crypto.js',
'/common/common-realtime.js', '/common/common-realtime.js',
'/common/clipboard.js', '/common/clipboard.js',
'/common/pinpad.js', '/common/pinpad.js',
'/customize/application_config.js', '/customize/application_config.js',
@ -23,7 +21,7 @@ define([
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/bower_components/localforage/dist/localforage.min.js', '/bower_components/localforage/dist/localforage.min.js',
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, ], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata,
Messaging, CodeMirror, Files, FileCrypto, Realtime, Clipboard, Messaging, Files, FileCrypto, Realtime, Clipboard,
Pinpad, AppConfig, MediaTag, Nthen, localForage) { Pinpad, AppConfig, MediaTag, Nthen, localForage) {
// Configure MediaTags to use our local viewer // Configure MediaTags to use our local viewer
@ -154,9 +152,6 @@ define([
// Metadata // Metadata
common.createMetadata = Metadata.create; common.createMetadata = Metadata.create;
// CodeMirror
common.createCodemirror = CodeMirror.create;
// Files // Files
common.createFileManager = function (config) { return Files.create(common, config); }; common.createFileManager = function (config) { return Files.create(common, config); };

@ -2,10 +2,9 @@ define([
'jquery', 'jquery',
'/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5', '/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
'/bower_components/textpatcher/TextPatcher.amd.js',
'/common/userObject.js', '/common/userObject.js',
'/common/migrate-user-object.js', '/common/migrate-user-object.js',
], function ($, Listmap, Crypto, TextPatcher, FO, Migrate) { ], function ($, Listmap, Crypto, FO, Migrate) {
/* /*
This module uses localStorage, which is synchronous, but exposes an This module uses localStorage, which is synchronous, but exposes an
asyncronous API. This is so that we can substitute other storage asyncronous API. This is so that we can substitute other storage

@ -2,9 +2,7 @@ define([
'jquery', 'jquery',
'/bower_components/hyperjson/hyperjson.js', '/bower_components/hyperjson/hyperjson.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'json.sortify', 'json.sortify',
'/bower_components/textpatcher/TextPatcher.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
@ -12,6 +10,7 @@ define([
'/common/common-util.js', '/common/common-util.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'/customize/application_config.js', '/customize/application_config.js',
'/bower_components/chainpad/chainpad.dist.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -20,9 +19,7 @@ define([
$, $,
Hyperjson, Hyperjson,
Toolbar, Toolbar,
JsonOT,
JSONSortify, JSONSortify,
TextPatcher,
Cryptpad, Cryptpad,
nThen, nThen,
SFCommon, SFCommon,
@ -31,6 +28,7 @@ define([
Thumb, Thumb,
AppConfig) AppConfig)
{ {
var ChainPad = window.ChainPad;
var SaveAs = window.saveAs; var SaveAs = window.saveAs;
var UNINITIALIZED = 'UNINITIALIZED'; var UNINITIALIZED = 'UNINITIALIZED';
@ -64,7 +62,6 @@ define([
var common; var common;
var cpNfInner; var cpNfInner;
var textPatcher;
var readOnly; var readOnly;
var title; var title;
var toolbar; var toolbar;
@ -182,10 +179,11 @@ define([
result in a feedback loop, which we call a browser result in a feedback loop, which we call a browser
fight */ fight */
// what changed? // what changed?
var op = TextPatcher.diff(newContentStrNoMeta, newContent2StrNoMeta); var ops = ChainPad.Diff.diff(newContentStrNoMeta, newContent2StrNoMeta);
// log the changes // log the changes
TextPatcher.log(newContentStrNoMeta, op); console.log(newContentStrNoMeta);
var sop = JSON.stringify(TextPatcher.format(newContentStrNoMeta, op)); console.log(ops);
var sop = JSON.stringify([ newContentStrNoMeta, ops ]);
var fights = window.CryptPad_fights = window.CryptPad_fights || []; var fights = window.CryptPad_fights = window.CryptPad_fights || [];
var index = fights.indexOf(sop); var index = fights.indexOf(sop);
@ -232,7 +230,7 @@ define([
} }
var contentStr = JSONSortify(content); var contentStr = JSONSortify(content);
textPatcher(contentStr); cpNfInner.chainpad.contentUpdate(contentStr);
if (cpNfInner.chainpad.getUserDoc() !== contentStr) { if (cpNfInner.chainpad.getUserDoc() !== contentStr) {
console.error("realtime.getUserDoc() !== shjson"); console.error("realtime.getUserDoc() !== shjson");
} }
@ -378,7 +376,7 @@ define([
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
cpNfInner = common.startRealtime({ cpNfInner = common.startRealtime({
// really basic operational transform // really basic operational transform
transformFunction: options.transformFunction || JsonOT.transform, patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer,
// cryptpad debug logging (default is 1) // cryptpad debug logging (default is 1)
// logLevel: 0, // logLevel: 0,
@ -410,8 +408,6 @@ define([
cpNfInner.metadataMgr.onChange(checkReady); cpNfInner.metadataMgr.onChange(checkReady);
checkReady(); checkReady();
textPatcher = TextPatcher.create({ realtime: cpNfInner.chainpad });
var infiniteSpinnerModal = false; var infiniteSpinnerModal = false;
window.setInterval(function () { window.setInterval(function () {
if (state === STATE.DISCONNECTED) { return; } if (state === STATE.DISCONNECTED) { return; }

@ -1,10 +1,10 @@
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } }); require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
define([ define([
'/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'json.sortify', 'json.sortify',
'/bower_components/textpatcher/TextPatcher.js', '/bower_components/chainpad/chainpad.dist.js'
], function (Realtime, JsonOT, Sortify, TextPatcher) { ], function (Realtime, Sortify) {
var ChainPad = window.ChainPad;
var api = {}; var api = {};
// "Proxy" is undefined in Safari : we need to use an normal object and check if there are local // "Proxy" is undefined in Safari : we need to use an normal object and check if there are local
// changes regurlarly. // changes regurlarly.
@ -627,7 +627,7 @@ define([
userName: cfg.userName, userName: cfg.userName,
initialState: Sortify(cfg.data), initialState: Sortify(cfg.data),
readOnly: cfg.readOnly, readOnly: cfg.readOnly,
transformFunction: JsonOT.transform || JsonOT.validate, patchTransformer: ChainPad.SmartJSONTransformer,
logLevel: typeof(cfg.logLevel) === 'undefined'? 0: cfg.logLevel, logLevel: typeof(cfg.logLevel) === 'undefined'? 0: cfg.logLevel,
validateContent: function (content) { validateContent: function (content) {
try { try {
@ -650,7 +650,6 @@ define([
var realtime; var realtime;
var proxy; var proxy;
var patchText;
realtimeOptions.onRemote = function () { realtimeOptions.onRemote = function () {
if (initializing) { return; } if (initializing) { return; }
@ -667,10 +666,10 @@ define([
var onLocal = realtimeOptions.onLocal = function () { var onLocal = realtimeOptions.onLocal = function () {
if (initializing) { return; } if (initializing) { return; }
var strung = isFakeProxy? DeepProxy.stringifyFakeProxy(proxy): Sortify(proxy); var strung = isFakeProxy? DeepProxy.stringifyFakeProxy(proxy): Sortify(proxy);
patchText(strung); realtime.contentUpdate(strung);
// try harder // try harder
if (realtime.getUserDoc() !== strung) { patchText(strung); } if (realtime.getUserDoc() !== strung) { realtime.contentUpdate(strung); }
// onLocal // onLocal
if (cfg.onLocal) { cfg.onLocal(); } if (cfg.onLocal) { cfg.onLocal(); }
@ -688,13 +687,8 @@ define([
var ready = false; var ready = false;
realtimeOptions.onReady = function (info) { realtimeOptions.onReady = function (info) {
if (ready) { return; } if (ready) { return; }
// create your patcher
if (realtime !== info.realtime) { if (realtime !== info.realtime) {
realtime = rt.realtime = info.realtime; realtime = rt.realtime = info.realtime;
patchText = TextPatcher.create({
realtime: realtime,
logging: cfg.logging || false,
});
} else { } else {
console.error(realtime); console.error(realtime);
} }

@ -37,7 +37,7 @@ define([
var onReady = config.onReady || function () { }; var onReady = config.onReady || function () { };
var userName = config.userName; var userName = config.userName;
var initialState = config.initialState; var initialState = config.initialState;
var transformFunction = config.transformFunction; if (config.transformFunction) { throw new Error("transformFunction is nolonger allowed"); }
var patchTransformer = config.patchTransformer; var patchTransformer = config.patchTransformer;
var validateContent = config.validateContent; var validateContent = config.validateContent;
var avgSyncMilliseconds = config.avgSyncMilliseconds; var avgSyncMilliseconds = config.avgSyncMilliseconds;
@ -50,7 +50,6 @@ define([
var chainpad = ChainPad.create({ var chainpad = ChainPad.create({
userName: userName, userName: userName,
initialState: initialState, initialState: initialState,
transformFunction: transformFunction,
patchTransformer: patchTransformer, patchTransformer: patchTransformer,
validateContent: validateContent, validateContent: validateContent,
avgSyncMilliseconds: avgSyncMilliseconds, avgSyncMilliseconds: avgSyncMilliseconds,

@ -3,9 +3,12 @@ define([
'/common/modes.js', '/common/modes.js',
'/common/themes.js', '/common/themes.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/bower_components/textpatcher/TextPatcher.js', '/common/text-cursor.js',
], function ($, Modes, Themes, Cryptpad, TextPatcher) {
'/bower_components/chainpad/chainpad.dist.js'
], function ($, Modes, Themes, Cryptpad, TextCursor) {
var module = {}; var module = {};
var ChainPad = window.ChainPad;
var cursorToPos = function(cursor, oldText) { var cursorToPos = function(cursor, oldText) {
var cLine = cursor.line; var cLine = cursor.line;
@ -34,7 +37,7 @@ define([
return cursor; return cursor;
}; };
module.setValueAndCursor = function (editor, oldDoc, remoteDoc, TextPatcher) { module.setValueAndCursor = function (editor, oldDoc, remoteDoc) {
var scroll = editor.getScrollInfo(); var scroll = editor.getScrollInfo();
//get old cursor here //get old cursor here
var oldCursor = {}; var oldCursor = {};
@ -44,9 +47,9 @@ define([
editor.setValue(remoteDoc); editor.setValue(remoteDoc);
editor.save(); editor.save();
var op = TextPatcher.diff(oldDoc, remoteDoc); var ops = ChainPad.Diff.diff(oldDoc, remoteDoc);
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) { var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextPatcher.transformCursor(oldCursor[attr], op); return TextCursor.transformCursor(oldCursor[attr], ops);
}); });
if(selects[0] === selects[1]) { if(selects[0] === selects[1]) {
@ -295,8 +298,8 @@ define([
return { content: content }; return { content: content };
}; };
exp.setValueAndCursor = function (oldDoc, remoteDoc, TextPatcher) { exp.setValueAndCursor = function (oldDoc, remoteDoc) {
return module.setValueAndCursor(editor, oldDoc, remoteDoc, TextPatcher); return module.setValueAndCursor(editor, oldDoc, remoteDoc);
}; };
///// /////
@ -308,7 +311,7 @@ define([
exp.contentUpdate = function (newContent) { exp.contentUpdate = function (newContent) {
var oldDoc = canonicalize($textarea.val()); var oldDoc = canonicalize($textarea.val());
var remoteDoc = newContent.content; var remoteDoc = newContent.content;
exp.setValueAndCursor(oldDoc, remoteDoc, TextPatcher); exp.setValueAndCursor(oldDoc, remoteDoc);
}; };
exp.getContent = function () { exp.getContent = function () {

@ -1,8 +1,7 @@
define([ define([
'jquery', 'jquery',
'/bower_components/chainpad-json-validator/json-ot.js',
'/bower_components/chainpad/chainpad.dist.js', '/bower_components/chainpad/chainpad.dist.js',
], function ($, JsonOT) { ], function ($) {
var ChainPad = window.ChainPad; var ChainPad = window.ChainPad;
var History = {}; var History = {};
@ -31,7 +30,7 @@ define([
} }
}, },
initialState: '', initialState: '',
transformFunction: JsonOT.validate, patchTransformer: ChainPad.NaiveJSONTransformer,
logLevel: 0, logLevel: 0,
noPrune: true noPrune: true
}); });

@ -0,0 +1,25 @@
define([
], function () {
var module = { exports: {} };
var transformCursor = function (cursor, op) {
if (!op) { return cursor; }
var pos = op.offset;
var remove = op.toRemove;
var insert = op.toInsert.length;
if (typeof cursor === 'undefined') { return; }
if (typeof remove === 'number' && pos < cursor) {
cursor -= Math.min(remove, cursor - pos);
}
if (typeof insert === 'number' && pos < cursor) {
cursor += insert;
}
return cursor;
};
module.exports.transformCursor = function (cursor, ops) {
if (Array.isArray(ops)) {
for (var i = ops.length - 1; i >= 0; i--) { transformCursor(cursor, ops[i]); }
return;
}
transformCursor(ops);
};
});

@ -2,7 +2,6 @@ define([
'jquery', 'jquery',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
@ -17,7 +16,6 @@ define([
$, $,
Crypto, Crypto,
Toolbar, Toolbar,
JsonOT,
Cryptpad, Cryptpad,
nThen, nThen,
SFCommon, SFCommon,

@ -1,6 +1,5 @@
define([ define([
'jquery', 'jquery',
'/bower_components/textpatcher/TextPatcher.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'json.sortify', 'json.sortify',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
@ -2940,12 +2939,7 @@ define([
var rt = APP.rt = Listmap.create(listmapConfig); var rt = APP.rt = Listmap.create(listmapConfig);
proxy = rt.proxy; proxy = rt.proxy;
var onCreate = function (info) { var onCreate = function (info) {
var realtime = APP.realtime = info.realtime; APP.realtime = info.realtime;
APP.patchText = TextPatcher.create({
realtime: realtime,
logging: true,
});
metadataMgr = common.getMetadataMgr(); metadataMgr = common.getMetadataMgr();

@ -1,242 +0,0 @@
define([
'jquery'
],function ($) {
var Board = {};
var proxy;
var Uid = function (prefix) {
return function () {
return prefix + Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
.toString(32).replace(/\./g, '');
};
};
var removeUid = function (A, e) {
var i = A.indexOf(e);
if (i === -1) { return -1; }
A.splice(i, 1);
return i;
};
var luid = Board.luid = Uid('l-'); // list-uid
var cuid = Board.cuid = Uid('c-'); // card uid
var Input = Board.Input = function (opt) {
return $('<input>', opt);
};
/*
populate the proxy with all the relevant fields
return boolean whether you are the first user
*/
Board.initialize = function (_proxy) {
proxy = _proxy;
var first = false;
['listOrder'].forEach(function (k) {
if (typeof(proxy[k]) === 'undefined') {
first = true;
proxy[k] = [];
}
});
['lists', 'cards'].forEach(function (k) {
if (typeof(proxy[k]) === 'undefined') {
proxy[k] = {};
}
});
return first;
};
/*
* a list is appended to the extant order
*/
var List = Board.List = function (id) {
if (!id) {
id = List.create();
}
var $input = Input({
type: 'text',
placeholder: 'list title',
})
.addClass('list-title')
.on('keyup change', function () {
var val = $input.val();
proxy.lists[id].title = val;
});
var $cards = $('<div>', {
})
.addClass('card-holder');
var $new = $('<a>', {
})
.addClass('add-card')
.text('add new card')
.click(function () {
// is this correct?
$cards.append(Board.Card(id));
});
var $list = $('<div>', {
id: id,
})
.addClass('list-column')
.append($input)
.append($cards)
.append($new);
return $list;
};
/*
*/
List.create = function () {
var id = luid();
proxy.listOrder.push(id);
proxy.lists[id] = {
title: "",
cards: [],
};
return id;
};
/*
*/
List.remove = function (id) {
var i = removeUid(proxy.listOrder, id);
if (i === -1) {
}
};
/*
*/
List.move = function () {
};
/*
*/
List.insert = function () {
};
List.draw = function ($lists, lid) {
if (!lid) {
console.log("List Id not supplied");
}
var $parent = $lists.find('#' + lid);
if (!$parent.length) {
console.log("Creating new list");
// doesn't exist. draw it fresh
var $list = Board.List(lid);
$lists.append($list);
//console.log("Updating list");
//var $list = Board.List(lid);
var title = proxy.lists[lid].title;
console.log(title);
$list.find('input.list-title').val(title);
return;
}
// else update
};
/*
* UI element
*/
var Card = Board.Card = function (pid) {
// pid => parent id
var id = Card.create(pid);
var $input = Input({
placeholder: 'card description',
id: id,
})
.addClass('card-title');
var $card = $('<div>', {
})
.addClass('card-container')
.append($input);
return $card;
};
/*
* a card is instantiated within a parent list
* .create(parent) adds the relevant attributes to the data structure
* and returns the created id
*/
Card.create = function (pid) {
var id = cuid();
if (typeof(proxy.lists[pid]) === 'undefined') {
console.error("Trying to create card for list which does not exist");
return id;
}
proxy.lists[pid].cards.push(id);
proxy.cards[id] = {
// TODO what goes in a card
parent: pid,
title: "",
};
return id;
};
/*
*/
Card.move = function (/*uid, A, B*/) {
};
/*
*/
Card.insert = function () {
};
Card.draw = function ($lists, cid) {
if (!cid) {
console.error("card id not supplied");
return;
}
if (!proxy.cards[cid]) {
console.error("no such card: ", cid);
return;
}
var card = proxy.cards[cid];
card = card; // TODO actually draw
};
Board.Draw = function ($lists) {
proxy.listOrder.forEach(function (luid) {
List.draw($lists, luid);
});
};
return Board;
});

@ -1,97 +0,0 @@
<!DOCTYPE html>
<html class="cp board">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Zero Knowledge Date Picker</title>
<link rel="icon" type="image/png"
href="/customize/main-favicon.png"
data-main-favicon="/customize/main-favicon.png"
data-alt-favicon="/customize/alt-favicon.png"
id="favicon" />
<link rel="stylesheet" href="/customize/main.css" />
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
<style>
html, body {
width: 100;
}
.clickable {
cursor: pointer;
}
#adduser, #addoption {
font-weight: bold;
}
#lists {
display: inline-block;
border: 1px solid white;
height: 80vh;
}
#create-list {
display: inline-block;
vertical-align: top;
background-color: green;
}
.list-column {
vertical-align: top;
box-sizing: border-box;
display: inline-block;
width: 400px;
height: 100%;
border: 1px solid white;
}
/* input */
input.list-title {
margin: 15px;
width: 80%;
display: block;
}
.card-holder {
border: 1px solid #ddd;
width: 90%;
margin: auto;
}
.add-card {
background-color: green;
display: block;
height: 20px;
width: 80%;
cursor: pointer;
margin: auto;
}
.card-title {
border: 5px solid blue;
}
.card-container {
display: block;
height: 50px;
width: 95%;
margin: auto;
padding: 5px;
border: 1px solid #ccc;
}
#board {
margin-left: 10vw;
overflow-x: visible;
}
</style>
</head>
<body>
<!--<div id="main"> -->
<div id="toolbar" class="buttons">
<sub><a href="/"></a></sub>
</div>
<div id="board">
<div id="lists"></div>
<span id="create-list">Add List</span>
</div>

@ -1,93 +0,0 @@
define([
'jquery',
'/api/config',
'/customize/messages.js',
'board.js',
'/bower_components/textpatcher/TextPatcher.js',
'/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad-crypto/crypto.js',
'/common/cryptpad-common.js',
//'/common/visible.js',
//'/common/notify.js',
'/bower_components/file-saver/FileSaver.min.js'
], function ($, Config, Messages, Board, TextPatcher, Listmap, Crypto, Cryptpad /*, Visible, Notify*/) {
// var saveAs = window.saveAs;
Cryptpad.styleAlerts();
console.log("Initializing your realtime session...");
var secret = Cryptpad.getSecrets();
var module = window.APP = {
Board: Board,
};
/*
var unnotify = function () {
if (!(module.tabNotification &&
typeof(module.tabNotification.cancel) === 'function')) { return; }
module.tabNotification.cancel();
};
var notify = function () {
if (!(Visible.isSupported() && !Visible.currently())) { return; }
unnotify();
module.tabNotification = Notify.tab(1000, 10);
};
*/
var setEditable = function (bool) {
bool = bool;
};
setEditable(false);
var $lists = $('#lists');
$('#create-list').click(function () {
Board.List.draw($lists);
});
var firstUser = function () {
Cryptpad.log("You are the first user to visit this board");
};
var whenReady = function () {
var rt = module.rt;
var proxy = rt.proxy;
var first = Board.initialize(proxy);
//var board = module.board = Board.create(proxy);
Board.Draw($lists);
if (first) { firstUser(); }
};
var config = {
websocketURL: Config.websocketURL,
channel: secret.channel,
data: {},
crypto: Crypto.createEncryptor(secret.key),
};
Cryptpad.ready(function () {
var rt = module.rt = Listmap.create(config);
var proxy = rt.proxy;
proxy
.on('create', function (info) {
module.realtime = info.realtime;
window.location.hash = info.channel + secret.key;
})
.on('ready', function () {
Cryptpad.log("Ready!");
whenReady({
});
})
.on('disconnect', function () {
Cryptpad.warn("Disconnected!");
});
});
});

@ -1,78 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
<style>
html, body{
padding: 0px;
margin: 0px;
overflow: hidden;
box-sizing: border-box;
}
form {
border: 3px solid black;
border-radius: 5px;
padding: 15px;
font-weight: bold !important;
font-size: 18px !important;
}
input[type="text"],
input[type="password"],
input[type="number"],
input[type="range"],
select
{
margin-top: 5px;
margin-bottom: 5px;
width: 80%;
}
textarea {
width: 80%;
height: 40vh;
font-weight: bold;
font-size: 18px;
}
</style>
</head>
<body>
<form>
<input type="radio" name="radio" value="one" checked>One
<input type="radio" name="radio" value="two">Two
<input type="radio" name="radio" value="three">Three<br>
<input type="checkbox" name="checkbox1" value="1">Checkbox One
<input type="checkbox" name="checkbox2" value="2">Checkbox Two<br>
<input type="text" name="text" placeholder="Text Input"><br>
<input type="password" name="password" placeholder="Passwords"><br>
<input type="number" name="number" min="1" max="5" placeholder="Numbers">Number<br>
<input type="range" name="range" min="0" max="100">Ranges<br>
<select name="select">
<option value="one">One</option>
<option value="two">Two</option>
<option value="three">Three</option>
<option value="four">Four</option>
</select> Dropdowns<br>
<select name="select-multiple" multiple>
<option value="pew">Pew</option>
<option value="bang">Bang</option>
<option value="kapow">Kapow</option>
<option value="zing">Zing</option>
</select>
<textarea name="textarea"></textarea><br>
</form>
</body>
</html>

@ -1,222 +0,0 @@
define([
'jquery',
'/api/config',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/textpatcher/TextPatcher.amd.js',
'json.sortify',
'ula.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'/common/cryptpad-common.js'
], function ($, Config, Realtime, Crypto, TextPatcher, Sortify, Formula, JsonOT, Cryptpad) {
var secret = Cryptpad.getSecrets();
var module = window.APP = {
TextPatcher: TextPatcher,
Sortify: Sortify,
Formula: Formula,
};
var initializing = true;
var uid = module.uid = Formula.uid;
var getInputType = Formula.getInputType;
var $elements = module.elements = $('input, select, textarea');
var eventsByType = Formula.eventsByType;
var Map = module.Map = {};
var UI = module.UI = {
ids: [],
each: function (f) {
UI.ids.forEach(function (id, i, list) {
if (!UI[id]) { return; }
f(UI[id], i, list);
});
},
add: function (id, ui) {
if (UI.ids.indexOf(id) === -1) {
UI.ids.push(id);
UI[id] = ui;
return true;
} else {
// it already exists
return false;
}
},
remove: function (id) {
delete UI[id];
var idx = UI.ids.indexOf(id);
if (idx > -1) {
UI.ids.splice(idx, 1);
return true;
}
}
};
var cursorTypes = ['textarea', 'password', 'text'];
var canonicalize = function (text) { return text.replace(/\r\n/g, '\n'); };
$elements.each(function (index, element) {
var $this = $(this);
var id = uid();
var type = getInputType($this);
// ignore hidden inputs, submit inputs, and buttons
if (['button', 'submit', 'hidden'].indexOf(type) !== -1) {
return;
}
$this // give each element a uid
.data('rtform-uid', id)
// get its type
.data('rt-ui-type', type);
var component = {
id: id,
$: $this,
element: element,
type: type,
preserveCursor: cursorTypes.indexOf(type) !== -1,
name: $this.prop('name'),
};
UI.add(id, component);
component.value = (function () {
var checker = ['radio', 'checkbox'].indexOf(type) !== -1;
if (checker) {
return function (content) {
return typeof content !== 'undefined'?
$this.prop('checked', !!content):
$this.prop('checked');
};
} else {
return function (content) {
return typeof content !== 'undefined' ?
$this.val(content):
typeof($this.val()) === 'string'? canonicalize($this.val()): $this.val();
};
}
}());
var update = component.update = function () { Map[id] = component.value(); };
update();
});
var config = module.config = {
initialState: Sortify(Map) || '{}',
websocketURL: Config.websocketURL,
userName: Crypto.rand64(8),
channel: secret.channel,
crypto: Crypto.createEncryptor(secret.key),
transformFunction: JsonOT.validate
};
var setEditable = module.setEditable = function (bool) {
/* (dis)allow editing */
$elements.each(function () {
$(this).attr('disabled', !bool);
});
};
setEditable(false);
config.onInit = function (info) {
var realtime = module.realtime = info.realtime;
window.location.hash = info.channel + secret.key;
// create your patcher
module.patchText = TextPatcher.create({
realtime: realtime,
logging: true,
});
};
var readValues = function () {
UI.each(function (ui) {
Map[ui.id] = ui.value();
});
};
var onLocal = config.onLocal = function () {
if (initializing) { return; }
/* serialize local changes */
readValues();
module.patchText(Sortify(Map));
};
var updateValues = function () {
var userDoc = module.realtime.getUserDoc();
var parsed = JSON.parse(userDoc);
console.log(userDoc);
// flush received values to the map
// but only if you don't have them locally
// this *shouldn't* break cursors
Object.keys(parsed).forEach(function (key) {
if (UI.ids.indexOf(key) === -1) { Map[key] = parsed[key]; }
});
UI.each(function (ui) {
var newval = parsed[ui.id];
var oldval = ui.value();
if (typeof(newval) === 'undefined') { return; }
if (newval === oldval) { return; }
var op;
var selects;
var element = ui.element;
if (ui.preserveCursor) {
op = TextPatcher.diff(oldval, newval);
selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextPatcher.transformCursor(element[attr], op);
});
}
ui.value(newval);
ui.update();
if (op && ui.preserveCursor) {
//console.log(selects);
element.selectionStart = selects[0];
element.selectionEnd = selects[1];
}
});
};
config.onRemote = function () {
if (initializing) { return; }
/* integrate remote changes */
updateValues();
};
config.onReady = function () {
updateValues();
console.log("READY");
setEditable(true);
initializing = false;
};
config.onAbort = function () {
window.alert("Network Connection Lost");
};
Realtime.start(config);
UI.each(function (ui) {
var type = ui.type;
var events = eventsByType[type];
ui.$.on(events, onLocal);
});
});

@ -1,14 +0,0 @@
```Javascript
/* elements that we need to listen to */
/*
* text => $(text).val()
* password => $(password).val()
* radio => $(radio).prop('checked')
* checkbox => $(checkbox).prop('checked')
* number => $(number).val() // returns string, no default
* range => $(range).val()
* select => $(select).val()
* textarea => $(textarea).val()
*/
```

@ -1,25 +0,0 @@
define([], function () {
var ula = {};
ula.uid = (function () {
var i = 0;
var prefix = 'rt_';
return function () { return prefix + i++; };
}());
ula.getInputType = function ($el) { return $el[0].type; };
ula.eventsByType = {
text: 'change keyup',
password: 'change keyup',
radio: 'change click',
checkbox: 'change click',
number: 'change',
range: 'keyup change',
'select-one': 'change',
'select-multiple': 'change',
textarea: 'change keyup',
};
return ula;
});

@ -1,60 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
<style></style>
</head>
<body>
<a id="edit" href="#" target="_blank">Edit this document's style</a>
<h1>HTML Ipsum Presents</h1>
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p></blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>
<pre><code>
#header h1 a {
display: block;
width: 300px;
height: 80px;
}
</code></pre>
<table>
<thead>
<tr>
<th>th 1</th>
<th>th 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>one</td>
<td>two</td>
</tr>
<tr>
<td>three</td>
<td>four</td>
</tr>
</tbody>
</table>
</body>
</html>

@ -1,75 +0,0 @@
define([
'jquery',
'/api/config',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/textpatcher/TextPatcher.amd.js',
'/common/cryptpad-common.js'
], function ($, Config, Realtime, Crypto, TextPatcher, Cryptpad) {
// TODO consider adding support for less.js
var $style = $('style').first(),
$edit = $('#edit');
var module = window.APP = {};
var secret = Cryptpad.getSecrets();
var config = {
websocketURL: Config.websocketURL,
channel: secret.channel,
crypto: Crypto.createEncryptor(secret.key),
};
var lazyDraw = (function () {
var to,
delay = 500;
return function (content) {
if (to) { clearTimeout(to); }
to = setTimeout(function () {
$style.text(content);
},delay);
};
}());
var draw = function (content) { lazyDraw(content); };
var initializing = true;
config.onInit = function (info) {
window.location.hash = info.channel + secret.key;
var realtime = module.realtime = info.realtime;
module.patchText = TextPatcher.create({
realtime: realtime,
logging: true,
});
$(window).on('hashchange', function() {
window.location.reload();
});
};
config.onReady = function () {
var userDoc = module.realtime.getUserDoc();
draw(userDoc);
console.log("Ready");
initializing = false;
};
config.onRemote = function () {
draw(module.realtime.getUserDoc());
};
config.onAbort = function () {
// notify the user of the abort
window.alert("Network Connection Lost");
};
config.onLocal = function () {
// nope
};
$edit.attr('href', '/examples/text/'+ window.location.hash);
Realtime.start(config);
});

@ -1,38 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
<style>
html, body{
padding: 0px;
margin: 0px;
overflow: hidden;
box-sizing: border-box;
}
textarea{
width: 100%;
height: 100vh;
max-width: 100%;
max-height: 100vh;
font-size: 18px;
background-color: #073642;
color: #839496;
overflow-x: hidden;
/* disallow textarea resizes */
resize: none;
}
textarea[disabled] {
background-color: #275662;
color: #637476;
}
</style>
</head>
<body>
<textarea></textarea>
</body>
</html>

@ -1,97 +0,0 @@
define([
'jquery',
'/api/config',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/textpatcher/TextPatcher.amd.js',
'/common/cryptpad-common.js'
], function ($, Config, Realtime, Crypto, TextPatcher, Cryptpad) {
var secret = Cryptpad.getSecrets();
if (!secret.keys) {
secret.keys = secret.key;
}
var module = window.APP = {
TextPatcher: TextPatcher
};
var initializing = true;
var $textarea = $('textarea');
var config = module.config = {
initialState: '',
websocketURL: Config.websocketURL,
validateKey: secret.keys.validateKey || undefined,
channel: secret.channel,
crypto: Crypto.createEncryptor(secret.keys),
};
var setEditable = function (bool) { $textarea.attr('disabled', !bool); };
var canonicalize = function (text) { return text.replace(/\r\n/g, '\n'); };
setEditable(false);
config.onInit = function (info) {
var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
Cryptpad.replaceHash(editHash);
$(window).on('hashchange', function() {
window.location.reload();
});
};
config.onRemote = function () {
if (initializing) { return; }
var userDoc = module.realtime.getUserDoc();
var content = canonicalize($textarea.val());
var op = TextPatcher.diff(content, userDoc);
var elem = $textarea[0];
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextPatcher.transformCursor(elem[attr], op);
});
$textarea.val(userDoc);
elem.selectionStart = selects[0];
elem.selectionEnd = selects[1];
};
var onLocal = config.onLocal = function () {
if (initializing) { return; }
module.patchText(canonicalize($textarea.val()));
};
config.onReady = function (info) {
var realtime = module.realtime = info.realtime;
module.patchText = TextPatcher.create({
realtime: realtime
});
$textarea.val(realtime.getUserDoc());
setEditable(true);
initializing = false;
};
config.onAbort = function () {
setEditable(false);
window.alert("Server Connection Lost");
};
config.onConnectionChange = function (info) {
if (info.state) {
initializing = true;
} else {
setEditable(false);
window.alert("Server Connection Lost. Trying to reconnect...");
}
};
Realtime.start(config);
['cut', 'paste', 'change', 'keyup', 'keydown', 'select', 'textInput']
.forEach(function (evt) {
$textarea.on(evt, onLocal);
});
});

@ -1,8 +1,6 @@
define([ define([
'jquery', 'jquery',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/bower_components/textpatcher/TextPatcher.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
@ -14,8 +12,6 @@ define([
], function ( ], function (
$, $,
Crypto, Crypto,
TextPatcher,
JsonOT,
Cryptpad, Cryptpad,
nThen, nThen,
SFCommon, SFCommon,

@ -30,9 +30,9 @@ define([
'/api/config', '/api/config',
'/common/common-hash.js', '/common/common-hash.js',
'/common/common-util.js', '/common/common-util.js',
'/bower_components/chainpad-json-validator/json-ot.js',
'/bower_components/diff-dom/diffDOM.js', '/bower_components/diff-dom/diffDOM.js',
'/bower_components/chainpad/chainpad.dist.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -49,10 +49,10 @@ define([
MediaTag, MediaTag,
ApiConfig, ApiConfig,
Hash, Hash,
Util, Util)
JsonOT)
{ {
var DiffDom = window.diffDOM; var DiffDom = window.diffDOM;
var ChainPad = window.ChainPad;
var slice = function (coll) { var slice = function (coll) {
return Array.prototype.slice.call(coll); return Array.prototype.slice.call(coll);
@ -555,7 +555,7 @@ define([
Framework.create({ Framework.create({
toolbarContainer: '#cke_1_toolbox', toolbarContainer: '#cke_1_toolbox',
contentContainer: '#cke_1_contents', contentContainer: '#cke_1_contents',
transformFunction: JsonOT.validate, patchTransformer: ChainPad.NaiveJSONTransformer,
thumbnail: { thumbnail: {
getContainer: function () { return $('iframe').contents().find('html')[0]; }, getContainer: function () { return $('iframe').contents().find('html')[0]; },
filter: function (el, before) { filter: function (el, before) {

@ -1,6 +1,5 @@
define([ define([
'jquery', 'jquery',
'/bower_components/textpatcher/TextPatcher.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js', '/common/common-util.js',
@ -16,21 +15,20 @@ define([
'/common/sframe-common-codemirror.js', '/common/sframe-common-codemirror.js',
'/common/sframe-common-interface.js', '/common/sframe-common-interface.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'cm/lib/codemirror', 'cm/lib/codemirror',
'cm/addon/display/placeholder', 'cm/addon/display/placeholder',
'cm/mode/markdown/markdown', 'cm/mode/markdown/markdown',
'css!cm/lib/codemirror.css', 'css!cm/lib/codemirror.css',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
'/bower_components/chainpad/chainpad.dist.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/customize/src/less2/main.less', 'less!/customize/src/less2/main.less',
], function ( ], function (
$, $,
TextPatcher,
Toolbar, Toolbar,
Cryptpad, Cryptpad,
Util, Util,
@ -50,6 +48,7 @@ define([
{ {
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
var saveAs = window.saveAs; var saveAs = window.saveAs;
var ChainPad = window.ChainPad;
var APP = window.APP = { var APP = window.APP = {
unlocked: { unlocked: {
@ -1069,10 +1068,6 @@ define([
if (APP.realtime !== info.realtime) { if (APP.realtime !== info.realtime) {
APP.realtime = info.realtime; APP.realtime = info.realtime;
APP.patchText = TextPatcher.create({
realtime: info.realtime,
logging: true,
});
} }
metadataMgr = common.getMetadataMgr(); metadataMgr = common.getMetadataMgr();

@ -2,10 +2,13 @@ define([
//'/common/cryptpad-common.js', //'/common/cryptpad-common.js',
'jquery', 'jquery',
'/bower_components/hyperjson/hyperjson.js', '/bower_components/hyperjson/hyperjson.js',
'/bower_components/textpatcher/TextPatcher.js', '/common/text-cursor.js',
'/bower_components/diff-dom/diffDOM.js', '/bower_components/diff-dom/diffDOM.js',
], function ($, Hyperjson, TextPatcher) { '/bower_components/chainpad/chainpad.dist.js'
], function ($, Hyperjson, TextCursor) {
var DiffDOM = window.diffDOM; var DiffDOM = window.diffDOM;
var ChainPad = window.ChainPad;
var Example = { var Example = {
metadata: { metadata: {
@ -400,10 +403,10 @@ var Renderer = function (Cryptpad, APP) {
var o = info.oldValue || ''; var o = info.oldValue || '';
var n = info.newValue || ''; var n = info.newValue || '';
var op = TextPatcher.diff(o, n); var ops = ChainPad.Diff.diff(o, n);
info.selection = ['selectionStart', 'selectionEnd'].map(function (attr) { info.selection = ['selectionStart', 'selectionEnd'].map(function (attr) {
return TextPatcher.transformCursor(element[attr], op); return TextCursor.transformCursor(element[attr], ops);
}); });
} }
}; };

@ -1,10 +1,8 @@
define([ define([
'jquery', 'jquery',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/bower_components/textpatcher/TextPatcher.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'json.sortify', 'json.sortify',
'/bower_components/chainpad-json-validator/json-ot.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js', '/common/common-util.js',
'/common/cryptget.js', '/common/cryptget.js',
@ -14,13 +12,13 @@ define([
'/api/config', '/api/config',
'/common/common-realtime.js', '/common/common-realtime.js',
'/customize/pages.js', '/customize/pages.js',
'/customize/application_config.js', '/customize/application_config.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'/whiteboard/colors.js', '/whiteboard/colors.js',
'/bower_components/secure-fabric.js/dist/fabric.min.js', '/bower_components/secure-fabric.js/dist/fabric.min.js',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
'/bower_components/chainpad/chainpad.dist.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -28,10 +26,8 @@ define([
], function ( ], function (
$, $,
Crypto, Crypto,
TextPatcher,
Toolbar, Toolbar,
JSONSortify, JSONSortify,
JsonOT,
Cryptpad, Cryptpad,
Util, Util,
Cryptget, Cryptget,
@ -47,6 +43,7 @@ define([
{ {
var saveAs = window.saveAs; var saveAs = window.saveAs;
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
var ChainPad = window.ChainPad;
var APP = window.APP = { var APP = window.APP = {
Cryptpad: Cryptpad, Cryptpad: Cryptpad,
@ -254,7 +251,7 @@ define([
config = { config = {
readOnly: readOnly, readOnly: readOnly,
transformFunction: JsonOT.validate, patchTransformer: ChainPad.NaiveJSONTransformer,
// cryptpad debug logging (default is 1) // cryptpad debug logging (default is 1)
// logLevel: 0, // logLevel: 0,
validateContent: function (content) { validateContent: function (content) {
@ -356,7 +353,7 @@ define([
var content = stringifyInner(canvas.toDatalessJSON()); var content = stringifyInner(canvas.toDatalessJSON());
APP.patchText(content); APP.realtime.contentUpdate(content);
}; };
var addImageToCanvas = function (img) { var addImageToCanvas = function (img) {
@ -516,10 +513,6 @@ define([
config.onReady = function (info) { config.onReady = function (info) {
if (APP.realtime !== info.realtime) { if (APP.realtime !== info.realtime) {
var realtime = APP.realtime = info.realtime; var realtime = APP.realtime = info.realtime;
APP.patchText = TextPatcher.create({
realtime: realtime,
//logging: true
});
} }
var userDoc = APP.realtime.getUserDoc(); var userDoc = APP.realtime.getUserDoc();

Loading…
Cancel
Save