- Unity is Strength - Collaboration is Key
+Unity is Strength - Collaboration is Key
from
by
';
- out.header_xwiki = '
';
+
+
+ // TODO Hardcode cause YOLO
+ //out.header_xwiki = '
';
out.header_support = '
';
out.header_logoTitle = 'Go to the main page';
diff --git a/www/code/index.html b/www/code/index.html
index bdef6b6f4..9b7c92d88 100644
--- a/www/code/index.html
+++ b/www/code/index.html
@@ -21,7 +21,7 @@
}
#iframe-container {
position: fixed;
- top: 2.6em;
+ top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
diff --git a/www/code/main.js b/www/code/main.js
index 1e4a11758..ee4fd2f0f 100644
--- a/www/code/main.js
+++ b/www/code/main.js
@@ -45,10 +45,13 @@ define([
var andThen = function (CMeditor) {
var CodeMirror = module.CodeMirror = CMeditor;
CodeMirror.modeURL = "/bower_components/codemirror/mode/%N/%N.js";
-
var $pad = $('#pad-iframe');
var $textarea = $pad.contents().find('#editor1');
+ var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
+ var parsedHash = Cryptpad.parsePadUrl(window.location.href);
+ var defaultName = Cryptpad.getDefaultName(parsedHash);
+
var editor = module.editor = CMeditor.fromTextArea($textarea[0], {
lineNumbers: true,
lineWrapping: true,
@@ -112,12 +115,22 @@ define([
editor.setOption('readOnly', !bool);
};
- var userList = {}; // List of pretty name of all users (mapped with their server ID)
- var toolbarList; // List of users still connected to the channel (server IDs)
- var addToUserList = function(data) {
- for (var attrname in data) { userList[attrname] = data[attrname]; }
- if(toolbarList && typeof toolbarList.onChange === "function") {
- toolbarList.onChange(userList);
+ var userData = module.userData = {}; // List of pretty name of all users (mapped with their server ID)
+ var userList; // List of users still connected to the channel (server IDs)
+ var addToUserData = function(data) {
+ var users = module.users;
+ for (var attrname in data) { userData[attrname] = data[attrname]; }
+
+ if (users && users.length) {
+ for (var userKey in userData) {
+ if (users.indexOf(userKey) === -1) {
+ delete userData[userKey];
+ }
+ }
+ }
+
+ if(userList && typeof userList.onChange === "function") {
+ userList.onChange(userData);
}
};
@@ -152,27 +165,30 @@ define([
var initializing = true;
+ var stringifyInner = function (textValue) {
+ var obj = {
+ content: textValue,
+ metadata: {
+ users: userData,
+ defaultTitle: defaultName
+ }
+ };
+ obj.metadata.title = document.title;
+ // set mode too...
+ obj.highlightMode = module.highlightMode;
+
+ // stringify the json and send it into chainpad
+ return stringify(obj);
+ };
+
var onLocal = config.onLocal = function () {
if (initializing) { return; }
if (readOnly) { return; }
editor.save();
+
var textValue = canonicalize($textarea.val());
- var obj = {content: textValue};
-
- // append the userlist to the hyperjson structure
- obj.metadata = {
- users: userList
- };
- if (!isDefaultTitle()) {
- obj.metadata.title = document.title;
- }
-
- // set mode too...
- obj.highlightMode = module.highlightMode;
-
- // stringify the json and send it into chainpad
- var shjson = stringify(obj);
+ var shjson = stringifyInner(textValue);
module.patchText(shjson);
@@ -191,13 +207,14 @@ define([
myData[myID] = {
name: myUserName
};
- addToUserList(myData);
+ addToUserData(myData);
Cryptpad.setAttribute('username', myUserName, function (err, data) {
if (err) {
console.log("Couldn't set username");
console.error(err);
return;
}
+ module.userName.lastName = myUserName;
onLocal();
});
};
@@ -233,10 +250,10 @@ define([
}
// lines including a c-style comment are also valuable
- var clike = /^\s*(\/\*|\/\/)(.*?)(\*\/)$/;
+ var clike = /^\s*(\/\*|\/\/)(.*)?(\*\/)*$/;
if (clike.test(line)) {
line.replace(clike, function (a, one, two) {
- text = two;
+ text = two.replace(/\*\/\s*$/, '').trim();
});
return true;
}
@@ -246,13 +263,10 @@ define([
};
var suggestName = function () {
- var parsed = Cryptpad.parsePadUrl(window.location.href);
- var name = Cryptpad.getDefaultName(parsed, []);
-
- if (Cryptpad.isDefaultName(parsed, document.title)) {
- return getHeadingText() || document.title;
+ if (document.title === defaultName) {
+ return getHeadingText() || "";
} else {
- return document.title || getHeadingText() || name;
+ return document.title || getHeadingText() || defaultName;
}
};
@@ -298,16 +312,68 @@ define([
onLocal();
};
- var onInit = config.onInit = function (info) {
- var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
- toolbarList = info.userList;
+ var renameCb = function (err, title) {
+ if (err) { return; }
+ document.title = title;
+ onLocal();
+ };
+
+ var updateTitle = function (newTitle) {
+ if (newTitle === document.title) { return; }
+ // Change the title now, and set it back to the old value if there is an error
+ var oldTitle = document.title;
+ document.title = newTitle;
+ Cryptpad.renamePad(newTitle, function (err, data) {
+ if (err) {
+ console.log("Couldn't set pad title");
+ console.error(err);
+ document.title = oldTitle;
+ return;
+ }
+ document.title = data;
+ $bar.find('.' + Toolbar.constants.title).find('span.title').text(data);
+ $bar.find('.' + Toolbar.constants.title).find('input').val(data);
+ });
+ };
+
+ var updateDefaultTitle = function (defaultTitle) {
+ defaultName = defaultTitle;
+ $bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName);
+ };
+
+ var updateMetadata = function(shjson) {
+ // Extract the user list (metadata) from the hyperjson
+ var json = (shjson === "") ? "" : JSON.parse(shjson);
+ if (json && json.metadata) {
+ if (json.metadata.users) {
+ var userData = json.metadata.users;
+ // Update the local user data
+ addToUserData(userData);
+ }
+ if (json.metadata.defaultTitle) {
+ updateDefaultTitle(json.metadata.defaultTitle);
+ }
+ if (typeof json.metadata.title !== "undefined") {
+ updateTitle(json.metadata.title);
+ }
+ }
+ };
+
+ var onInit = config.onInit = function (info) {
+ userList = info.userList;
var config = {
- userData: userList,
+ userData: userData,
readOnly: readOnly,
- ifrw: ifrw
+ ifrw: ifrw,
+ title: {
+ onRename: renameCb,
+ defaultName: defaultName,
+ suggestName: suggestName
+ },
+ common: Cryptpad
};
if (readOnly) {delete config.changeNameID; }
- toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config);
+ toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username);
@@ -321,13 +387,13 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
+ // Store the object sent for the "change username" button so that we can update the field value correctly
+ var userNameButtonObject = module.userName = {};
/* add a "change username" button */
getLastName(function (err, lastName) {
- var usernameCb = function (newName) {
- setName (newName);
- };
- var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb);
- $userBlock.append($username).hide();
+ userNameButtonObject.lastName = lastName;
+ var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName).hide();
+ $userBlock.append($username);
});
/* add an export button */
@@ -340,13 +406,8 @@ define([
$rightside.append($import);
/* add a rename button */
- var renameCb = function (err, title) {
- if (err) { return; }
- document.title = title;
- onLocal();
- };
- var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb);
- $rightside.append($setTitle);
+ //var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb);
+ //$rightside.append($setTitle);
}
/* add a forget button */
@@ -444,47 +505,10 @@ define([
console.error(err);
return;
}
- document.title = title || info.channel.slice(0, 8);
- Cryptpad.setPadTitle(title, function (err, data) {
- if (err) {
- console.log("Unable to set pad title");
- console.error(err);
- return;
- }
- });
+ updateTitle(title || defaultName);
});
};
- var updateTitle = function (newTitle) {
- if (newTitle === document.title) { return; }
- // Change the title now, and set it back to the old value if there is an error
- var oldTitle = document.title;
- document.title = newTitle;
- Cryptpad.setPadTitle(newTitle, function (err, data) {
- if (err) {
- console.log("Couldn't set pad title");
- console.error(err);
- document.title = oldTitle;
- return;
- }
- });
- };
-
- var updateMetadata = function(shjson) {
- // Extract the user list (metadata) from the hyperjson
- var json = (shjson === "") ? "" : JSON.parse(shjson);
- if (json && json.metadata) {
- if (json.metadata.users) {
- var userData = json.metadata.users;
- // Update the local user data
- addToUserList(userData);
- }
- if (json.metadata.title) {
- updateTitle(json.metadata.title);
- }
- }
- };
-
var unnotify = module.unnotify = function () {
if (module.tabNotification &&
typeof(module.tabNotification.cancel) === 'function') {
@@ -501,6 +525,7 @@ define([
var onReady = config.onReady = function (info) {
var realtime = module.realtime = info.realtime;
+ module.users = info.userList.users;
module.patchText = TextPatcher.create({
realtime: realtime,
//logging: true
@@ -549,14 +574,16 @@ define([
// Update the toolbar list:
// Add the current user in the metadata if he has edit rights
if (readOnly) { return; }
- myData[myID] = {
- name: ""
- };
- addToUserList(myData);
if (typeof(lastName) === 'string' && lastName.length) {
setName(lastName);
+ } else {
+ myData[myID] = {
+ name: ""
+ };
+ addToUserData(myData);
+ onLocal();
+ module.$userNameButton.click();
}
- onLocal();
});
};
@@ -628,18 +655,8 @@ define([
editor.scrollTo(scroll.left, scroll.top);
if (!readOnly) {
- var localDoc = canonicalize($textarea.val());
- var hjson2 = {
- content: localDoc,
- metadata: {
- users: userList
- },
- highlightMode: highlightMode,
- };
- if (!isDefaultTitle()) {
- hjson2.metadata.title = document.title;
- }
- var shjson2 = stringify(hjson2);
+ var textValue = canonicalize($textarea.val());
+ var shjson2 = stringifyInner(textValue);
if (shjson2 !== shjson) {
console.error("shjson2 !== shjson");
TextPatcher.log(shjson, TextPatcher.diff(shjson, shjson2));
diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js
index 4fdde73e6..d28b1e5e5 100644
--- a/www/common/cryptpad-common.js
+++ b/www/common/cryptpad-common.js
@@ -277,15 +277,15 @@ define([
};
var parsePadUrl = common.parsePadUrl = function (href) {
- var patt = /^https*:\/\/([^\/]*)\/(.*?)\/#(.*)$/i;
+ var patt = /^https*:\/\/([^\/]*)\/(.*?)\//i;
var ret = {};
- href.replace(patt, function (a, domain, type, hash) {
+ var hash = href.replace(patt, function (a, domain, type, hash) {
ret.domain = domain;
ret.type = type;
- ret.hash = hash;
return '';
});
+ ret.hash = hash.replace(/#/g, '');
return ret;
};
@@ -303,13 +303,17 @@ define([
var type = parsed.type;
var untitledIndex = 1;
var name = (Messages.type)[type] + ' - ' + new Date().toString().split(' ').slice(0,4).join(' ');
- if (isNameAvailable(name, parsed, recentPads)) { return name; }
- while (!isNameAvailable(name + ' - ' + untitledIndex, parsed, recentPads)) { untitledIndex++; }
- return name + ' - ' + untitledIndex;
+ return name;
+ /*
+ * Pad titles are shared in the document so it does not make sense anymore to avoid duplicates
+ if (isNameAvailable(name, parsed, recentPads)) { return name; }
+ while (!isNameAvailable(name + ' - ' + untitledIndex, parsed, recentPads)) { untitledIndex++; }
+ return name + ' - ' + untitledIndex;
+ */
};
var isDefaultName = common.isDefaultName = function (parsed, title) {
var name = getDefaultName(parsed, []);
- return title.slice(0, name.length) === name;
+ return title === name;
};
var makePad = function (href, title) {
@@ -620,6 +624,47 @@ define([
/*
* Buttons
*/
+ var renamePad = common.renamePad = function (title, callback) {
+ if (title === null) { return; }
+
+ if (title.trim() === "") {
+ var parsed = parsePadUrl(window.location.href);
+ title = getDefaultName(parsed);
+ }
+
+ common.setPadTitle(title, function (err, data) {
+ if (err) {
+ console.log("unable to set pad title");
+ console.log(err);
+ return;
+ }
+ callback(null, title);
+ });
+ /* Pad titles are shared in the document. We don't check for duplicates anymore.
+ common.causesNamingConflict(title, function (err, conflicts) {
+ if (err) {
+ console.log("Unable to determine if name caused a conflict");
+ console.error(err);
+ callback(err, title);
+ return;
+ }
+
+ if (conflicts) {
+ common.alert(Messages.renameConflict);
+ return;
+ }
+
+ common.setPadTitle(title, function (err, data) {
+ if (err) {
+ console.log("unable to set pad title");
+ console.log(err);
+ return;
+ }
+ callback(null, title);
+ });
+ });
+ */
+ };
var createButton = common.createButton = function (type, rightside, data, callback) {
var button;
var size = "17px";
@@ -658,33 +703,9 @@ define([
button.click(function() {
var suggestion = suggestName();
- common.prompt(Messages.renamePrompt,
- suggestion, function (title, ev) {
- if (title === null) { return; }
-
- common.causesNamingConflict(title, function (err, conflicts) {
- if (err) {
- console.log("Unable to determine if name caused a conflict");
- console.error(err);
- callback(err, title);
- return;
- }
-
- if (conflicts) {
- common.alert(Messages.renameConflict);
- return;
- }
-
- common.setPadTitle(title, function (err, data) {
- if (err) {
- console.log("unable to set pad title");
- console.log(err);
- return;
- }
- callback(null, title);
- });
- });
- });
+ common.prompt(Messages.renamePrompt, suggestion, function (title, ev) {
+ renamePad(title, callback);
+ });
});
}
break;
@@ -720,9 +741,8 @@ define([
title: Messages.userButton + '\n' + Messages.userButtonTitle
}).html('');
if (data && typeof data.lastName !== "undefined" && callback) {
- var lastName = data.lastName;
button.click(function() {
- common.prompt(Messages.changeNamePrompt, lastName, function (newName) {
+ common.prompt(Messages.changeNamePrompt, data.lastName, function (newName) {
callback(newName);
});
});
diff --git a/www/common/toolbar.js b/www/common/toolbar.js
index 943e27df5..2fc0c112d 100644
--- a/www/common/toolbar.js
+++ b/www/common/toolbar.js
@@ -17,6 +17,7 @@ define([
/** The toolbar class which contains the user list, debug link and lag. */
var TOOLBAR_CLS = Bar.constants.toolbar = 'cryptpad-toolbar';
+ var TOP_CLS = Bar.constants.top = 'cryptpad-toolbar-top';
var LEFTSIDE_CLS = Bar.constants.leftside = 'cryptpad-toolbar-leftside';
var RIGHTSIDE_CLS = Bar.constants.rightside = 'cryptpad-toolbar-rightside';
@@ -34,6 +35,8 @@ define([
var VIEWSHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-viewShare";
var DROPDOWN_CONTAINER_CLS = Bar.constants.dropdownContainer = "cryptpad-dropdown-container";
var DROPDOWN_CLS = Bar.constants.dropdown = "cryptpad-dropdown";
+ var TITLE_CLS = Bar.constants.title = "cryptpad-title";
+ var USER_CLS = Bar.constants.userAdmin = "cryptpad-user";
/** Key in the localStore which indicates realtime activity should be disallowed. */
// TODO remove? will never be used in cryptpad
@@ -49,6 +52,7 @@ define([
var $style;
var firstConnection = true;
+ var lagErrors = 0;
var styleToolbar = function ($container, href) {
href = href || '/customize/toolbar.css';
@@ -67,6 +71,7 @@ define([
'class': TOOLBAR_CLS,
id: uid(),
})
+ .append($('', {'class': TOP_CLS}))
.append($('
', {'class': LEFTSIDE_CLS}))
.append($('
', {'class': RIGHTSIDE_CLS}));
@@ -100,34 +105,6 @@ define([
'class': USERBUTTONS_CONTAINER_CLS
}).appendTo($userlistElement);
- var $editIcon = $('