31 changed files with 82 additions and 1447 deletions
Split View
Diff Options
-
6bower.json
-
2www/code/inner.js
-
308www/common/common-codemirror.js
-
6www/common/common-history.js
-
7www/common/cryptget.js
-
7www/common/cryptpad-common.js
-
3www/common/fsStore.js
-
20www/common/sframe-app-framework.js
-
18www/common/sframe-chainpad-listmap.js
-
3www/common/sframe-chainpad-netflux-inner.js
-
19www/common/sframe-common-codemirror.js
-
5www/common/sframe-common-history.js
-
25www/common/text-cursor.js
-
2www/contacts/inner.js
-
8www/drive/inner.js
-
242www/examples/board/board.js
-
97www/examples/board/index.html
-
93www/examples/board/main.js
-
78www/examples/form/index.html
-
222www/examples/form/main.js
-
14www/examples/form/types.md
-
25www/examples/form/ula.js
-
60www/examples/style/index.html
-
75www/examples/style/main.js
-
38www/examples/text/index.html
-
97www/examples/text/main.js
-
4www/filepicker/inner.js
-
8www/pad/inner.js
-
11www/poll/inner.js
-
11www/poll/render.js
-
15www/whiteboard/inner.js
@ -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; |
|||
}); |
|||
|
|||
@ -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); |
|||
}; |
|||
}); |
|||
@ -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); |
|||
}); |
|||
}); |
|||
Write
Preview
Loading…
Cancel
Save