Add usernames/userlist in the toolbar and fix publish button

This commit is contained in:
yflory
2016-12-01 18:40:09 +01:00
parent 3632834500
commit 90804ed9e0
8 changed files with 250 additions and 102 deletions

View File

@@ -27,8 +27,8 @@ define(function () {
out.readOnly = 'Solo lectura'; out.readOnly = 'Solo lectura';
out.anonymous = 'Anónimo'; out.anonymous = 'Anónimo';
out.yourself = "tú mismo"; out.yourself = "tú mismo";
out.anonymousUsers = "usuarios anónimos"; out.anonymousUsers = "editores anónimos";
out.anonymousUser = "usuario anónimo"; out.anonymousUser = "editor anónimo";
out.shareView = "URL de sólo lectura"; out.shareView = "URL de sólo lectura";
out.shareEdit = "Editar URL"; out.shareEdit = "Editar URL";
out.users = "Usuarios"; out.users = "Usuarios";

View File

@@ -27,8 +27,8 @@ define(function () {
out.readonly = 'Lecture seule'; out.readonly = 'Lecture seule';
out.anonymous = "Anonyme"; out.anonymous = "Anonyme";
out.yourself = "Vous-même"; out.yourself = "Vous-même";
out.anonymousUsers = "utilisateurs anonymes"; out.anonymousUsers = "éditeurs anonymes";
out.anonymousUser = "utilisateur anonyme"; out.anonymousUser = "éditeur anonyme";
out.shareView = "URL de lecture seule"; out.shareView = "URL de lecture seule";
out.shareEdit = "URL d'édition"; out.shareEdit = "URL d'édition";
out.users = "Utilisateurs"; out.users = "Utilisateurs";

View File

@@ -29,8 +29,8 @@ define(function () {
out.readonly = 'Read only'; out.readonly = 'Read only';
out.anonymous = "Anonymous"; out.anonymous = "Anonymous";
out.yourself = "Yourself"; out.yourself = "Yourself";
out.anonymousUsers = "anonymous users"; out.anonymousUsers = "anonymous editors";
out.anonymousUser = "anonymous user"; out.anonymousUser = "anonymous editor";
out.shareView = "Read-only URL"; out.shareView = "Read-only URL";
out.shareEdit = "Edit URL"; out.shareEdit = "Edit URL";
out.users = "Users"; out.users = "Users";

View File

@@ -759,7 +759,6 @@ define([
case 'editshare': case 'editshare':
button = $('<button>', { button = $('<button>', {
title: Messages.editShareTitle, title: Messages.editShareTitle,
'class': "button action"
}).text(Messages.editShare); }).text(Messages.editShare);
if (data && data.editHash) { if (data && data.editHash) {
var editHash = data.editHash; var editHash = data.editHash;
@@ -778,7 +777,6 @@ define([
case 'viewshare': case 'viewshare':
button = $('<button>', { button = $('<button>', {
title: Messages.viewShareTitle, title: Messages.viewShareTitle,
'class': "button action"
}).text(Messages.viewShare); }).text(Messages.viewShare);
if (data && data.viewHash) { if (data && data.viewHash) {
button.click(function () { button.click(function () {
@@ -796,7 +794,6 @@ define([
case 'viewopen': case 'viewopen':
button = $('<button>', { button = $('<button>', {
title: Messages.viewOpenTitle, title: Messages.viewOpenTitle,
'class': "button action"
}).text(Messages.viewOpen); }).text(Messages.viewOpen);
if (data && data.viewHash) { if (data && data.viewHash) {
button.click(function () { button.click(function () {

View File

@@ -16,6 +16,11 @@
padding: 0px; padding: 0px;
border: 0px; border: 0px;
} }
.cryptpad-toolbar h2 {
font: normal normal normal 12px Arial, Helvetica, Tahoma, Verdana, Sans-Serif;
color: #000;
line-height: auto;
}
.realtime { .realtime {
display: block; display: block;
overflow: auto; overflow: auto;
@@ -54,6 +59,10 @@
} }
#tableContainer button { #tableContainer button {
height: 2rem; height: 2rem;
display: none;
}
#publish {
display: none;
} }
#commit { #commit {
position: absolute; position: absolute;
@@ -93,7 +102,7 @@
<form class="realtime"> <form class="realtime">
<br /> <br />
<textarea rows=5 cols=50 id="description"></textarea><br /> <textarea rows=5 cols=50 disabled="disabled" id="description"></textarea><br />
<p id="tableContainer"> <p id="tableContainer">
<button id="create-option"><span class="fa fa-plus"></span></button> <button id="create-option"><span class="fa fa-plus"></span></button>
<button id="create-user"><span class="fa fa-plus"></span></button> <button id="create-user"><span class="fa fa-plus"></span></button>

View File

@@ -19,6 +19,9 @@ define([
var HIDE_INTRODUCTION_TEXT = "hide_poll_text"; var HIDE_INTRODUCTION_TEXT = "hide_poll_text";
var defaultName; var defaultName;
var secret = Cryptpad.getSecrets();
var readOnly = secret.keys && !secret.keys.editKeyStr;
var APP = window.APP = { var APP = window.APP = {
Toolbar: Toolbar, Toolbar: Toolbar,
Hyperjson: Hyperjson, Hyperjson: Hyperjson,
@@ -108,19 +111,23 @@ define([
}; };
var updateTableButtons = function () { var updateTableButtons = function () {
unlockElements();
if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { if ($('.checkbox-cell').length && !isOwnColumnCommitted()) {
$('#commit').show(); $('#commit').show();
$('#commit').css('width', $($('.checkbox-cell')[0]).width()); $('#commit').css('width', $($('.checkbox-cell')[0]).width());
} else {
$('#commit').hide();
} }
$('#create-user, #create-option').show();
var width = $('#table').outerWidth(); var width = $('#table').outerWidth();
if (width) { if (width) {
$('#create-user').css('left', width + 30 + 'px'); $('#create-user').css('left', width + 30 + 'px');
} }
}; };
var updateDisplayedTable = function () {
styleUncommittedColumn();
unlockElements();
updateTableButtons();
};
var unlockColumn = function (id, cb) { var unlockColumn = function (id, cb) {
if (APP.editable.col.indexOf(id) === -1) { if (APP.editable.col.indexOf(id) === -1) {
APP.editable.col.push(id); APP.editable.col.push(id);
@@ -151,10 +158,11 @@ define([
var colsOrder = sortColumns(displayedObj.table.colsOrder, APP.userid); var colsOrder = sortColumns(displayedObj.table.colsOrder, APP.userid);
var conf = { var conf = {
cols: colsOrder cols: colsOrder,
readOnly: readOnly
}; };
Render.updateTable(table, displayedObj, conf); //Render.updateTable(table, displayedObj, conf);
/* FIXME browser autocomplete fills in new fields sometimes /* FIXME browser autocomplete fills in new fields sometimes
calling updateTable twice removes the autofilled in values calling updateTable twice removes the autofilled in values
@@ -165,8 +173,7 @@ define([
window.setTimeout(function () { window.setTimeout(function () {
var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted); var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted);
Render.updateTable(table, displayedObj2, conf); Render.updateTable(table, displayedObj2, conf);
updateTableButtons(); updateDisplayedTable();
styleUncommittedColumn();
}); });
}; };
@@ -286,132 +293,80 @@ define([
proxy.version = 1; proxy.version = 1;
}; };
/* /*
*/ */
var publish = APP.publish = function (bool) { var publish = APP.publish = function (bool) {
if (!APP.ready || APP.proxy.published) { return; } if (!APP.ready) { return; }
APP.proxy.published = true; if (APP.proxy.published !== bool) {
APP.proxy.published = bool;
}
console.log(bool);
if (bool) {
APP.$publish.hide(); APP.$publish.hide();
$('#create-option').hide();
$('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').hide();
} else {
APP.$publish.show();
$('#create-option').show();
$('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').show();
}
['textarea'].forEach(function (sel) { ['textarea'].forEach(function (sel) {
$(sel).attr('disabled', bool); $(sel).attr('disabled', bool);
}); });
}; };
var userData = APP.userData = {}; // List of pretty names for all users (mapped with their ID)
var userList; // List of users still connected to the channel (server IDs)
var addToUserData = function(data) {
var users = userList ? userList.users : undefined;
//var userData = APP.proxy.info.userData;
for (var attrname in data) { userData[attrname] = data[attrname]; }
var copyObject = function (obj) { if (users && users.length) {
return JSON.parse(JSON.stringify(obj)); for (var userKey in userData) {
if (users.indexOf(userKey) === -1) { delete userData[userKey]; }
}
}
if(userList && typeof userList.onChange === "function") {
userList.onChange(userData);
}
APP.proxy.info.userData = userData;
}; };
// special UI elements //var myData = {};
//var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); TODO var getLastName = function (cb) {
var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); Cryptpad.getAttribute('username', function (err, userName) {
cb(err, userName || '');
var ready = function (info, userid) {
console.log("READY");
console.log('userid: %s', userid);
var proxy = APP.proxy;
var uncommitted = APP.uncommitted = {};
prepareProxy(proxy, copyObject(Render.Example));
prepareProxy(uncommitted, copyObject(Render.Example));
if (proxy.table.colsOrder.indexOf(userid) === -1 &&
uncommitted.table.colsOrder.indexOf(userid) === -1) {
uncommitted.table.colsOrder.unshift(userid);
}
var displayedObj = mergeUncommitted(proxy, uncommitted, false);
var colsOrder = sortColumns(displayedObj.table.colsOrder, userid);
var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder));
var $createRow = APP.$createRow = $('#create-option').click(function () {
//
console.error("BUTTON CLICKED! LOL");
Render.createRow(proxy, function () {
change();
}); });
});
var $createCol = APP.$createCol = $('#create-user').click(function () {
Render.createColumn(proxy, function () {
change();
});
});
// Commit button
var $commit = APP.$commit = $('#commit').click(function () {
var uncommittedCopy = JSON.parse(JSON.stringify(APP.uncommitted));
APP.uncommitted = {};
prepareProxy(APP.uncommitted, copyObject(Render.Example));
mergeUncommitted(proxy, uncommittedCopy, true);
change();
});
// Title
if (APP.proxy.info.defaultTitle) {
updateDefaultTitle(APP.proxy.info.defaultTitle);
} else {
APP.proxy.info.defaultTitle = defaultName
}
updateTitle(APP.proxy.info.title || defaultName);
// Description
$description.on('change keyup', function () {
var val = $item.val();
proxy.info.description = val;
});
if (typeof(proxy.info.description) !== 'undefined') {
$description.val(proxy.info.descrption);
}
$('#tableContainer').prepend($table);
updateTableButtons();
styleUncommittedColumn();
$table
.click(handleClick)
.on('keyup', function (e) { handleClick(e, true); });
proxy
.on('change', ['info'], function (o, n, p) {
if (p[1] === 'title') {
updateTitle(n);
} else if (p[1] === 'description') {
var op = TextPatcher.diff(o, n);
var el = $description[0];
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
var before = el[attr];
var after = TextPatcher.transformCursor(el[attr], op);
return after;
});
$target.val(n);
if (op) {
el.selectionStart = selects[0];
el.selectionEnd = selects[1];
}
}
console.log("change: (%s, %s, [%s])", o, n, p.join(', '));
})
.on('change', ['table'], change)
.on('remove', [], change);
if (!proxy.published) {
var $publish = APP.$publish = $('#publish')
.show()
.click(function () {
publish(true);
});
}
APP.ready = true;
}; };
var secret = Cryptpad.getSecrets(); var setName = APP.setName = function (newName) {
if (typeof(newName) !== 'string') { return; }
var myUserNameTemp = Cryptpad.fixHTML(newName.trim());
if(myUserNameTemp.length > 32) {
myUserNameTemp = myUserNameTemp.substr(0, 32);
}
myUserName = myUserNameTemp;
var myID = APP.myID;
var myData = {}
myData[myID] = {
name: myUserName
};
addToUserData(myData);
Cryptpad.setAttribute('username', newName, function (err, data) {
if (err) {
console.error("Couldn't set username");
return;
}
APP.userName.lastName = myUserName;
//change();
});
};
var updateTitle = function (newTitle) { var updateTitle = function (newTitle) {
if (newTitle === document.title) { return; } if (newTitle === document.title) { return; }
@@ -445,30 +400,185 @@ define([
return document.title || defaultName || ""; return document.title || defaultName || "";
}; };
var copyObject = function (obj) {
return JSON.parse(JSON.stringify(obj));
};
// special UI elements
//var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); TODO
var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description');
var ready = function (info, userid, readOnly) {
console.log("READY");
console.log('userid: %s', userid);
var proxy = APP.proxy;
var uncommitted = APP.uncommitted = {};
prepareProxy(proxy, copyObject(Render.Example));
prepareProxy(uncommitted, copyObject(Render.Example));
if (!readOnly && proxy.table.colsOrder.indexOf(userid) === -1 &&
uncommitted.table.colsOrder.indexOf(userid) === -1) {
uncommitted.table.colsOrder.unshift(userid);
}
var displayedObj = mergeUncommitted(proxy, uncommitted, false);
var colsOrder = sortColumns(displayedObj.table.colsOrder, userid);
var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder, readOnly));
var $createRow = APP.$createRow = $('#create-option').click(function () {
//
console.error("BUTTON CLICKED! LOL");
Render.createRow(proxy, function () {
change();
});
});
var $createCol = APP.$createCol = $('#create-user').click(function () {
Render.createColumn(proxy, function () {
change();
});
});
// Commit button
var $commit = APP.$commit = $('#commit').click(function () {
var uncommittedCopy = JSON.parse(JSON.stringify(APP.uncommitted));
APP.uncommitted = {};
prepareProxy(APP.uncommitted, copyObject(Render.Example));
mergeUncommitted(proxy, uncommittedCopy, true);
change();
});
// Title
if (APP.proxy.info.defaultTitle) {
updateDefaultTitle(APP.proxy.info.defaultTitle);
} else {
APP.proxy.info.defaultTitle = defaultName
}
updateTitle(APP.proxy.info.title || defaultName);
// Description
$description.on('change keyup', function () {
var val = $description.val();
proxy.info.description = val;
});
if (typeof(proxy.info.description) !== 'undefined') {
$description.val(proxy.info.description);
}
$('#tableContainer').prepend($table);
updateDisplayedTable();
$table
.click(handleClick)
.on('keyup', function (e) { handleClick(e, true); });
proxy
.on('change', ['info'], function (o, n, p) {
if (p[1] === 'title') {
updateTitle(n);
} else if (p[1] === "userData") {
addToUserData(APP.proxy.info.userData);
} else if (p[1] === 'description') {
var op = TextPatcher.diff(o, n);
var el = $description[0];
var selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
var before = el[attr];
var after = TextPatcher.transformCursor(el[attr], op);
return after;
});
$description.val(n);
if (op) {
el.selectionStart = selects[0];
el.selectionEnd = selects[1];
}
}
console.log("change: (%s, %s, [%s])", o, n, p.join(', '));
})
.on('change', ['table'], change)
.on('remove', [], change);
// #publish button is removed in readonly
var $publish = APP.$publish = $('#publish')
.click(function () {
publish(true);
});
addToUserData(APP.proxy.info.userData);
getLastName(function (err, lastName) {
APP.ready = true;
if (!proxy.published) {
$('#publish').show(); // Show the publish button
publish(false);
} else {
publish(true);
}
// Update the toolbar list:
// Add the current user in the metadata if he has edit rights
if (readOnly) { return; }
if (typeof(lastName) === 'string' && lastName.length) {
setName(lastName);
} else {
var myData = {};
myData[info.myId] = {
name: ""
};
addToUserData(myData);
APP.$userNameButton.click();
}
});
};
var create = function (info) { var create = function (info) {
var realtime = APP.realtime = info.realtime; var realtime = APP.realtime = info.realtime;
var myID = APP.myID = info.myID;
var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); var editHash;
var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
if (!readOnly) {
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
APP.patchText = TextPatcher.create({ APP.patchText = TextPatcher.create({
realtime: realtime, realtime: realtime,
logging: true, logging: true,
}); });
var userList = info.userList; userList = APP.userList = info.userList;
var config = { var config = {
userData: {}, userData: userData,
readOnly: false, readOnly: readOnly,
title: { title: {
onRename: renameCb, onRename: renameCb,
defaultName: defaultName, defaultName: defaultName,
suggestName: suggestName suggestName: suggestName
}, },
ifrw: window,
common: Cryptpad common: Cryptpad
}; };
toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config); toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config);
var $rightside = APP.$bar.find('.' + Toolbar.constants.rightside); var $bar = APP.$bar;
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username);
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
// Store the object sent for the "change username" button so that we can update the field value correctly
var userNameButtonObject = APP.userName = {};
/* add a "change username" button */
getLastName(function (err, lastName) {
userNameButtonObject.lastName = lastName;
var $username = APP.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName).hide();
$userBlock.append($username);
});
/* add a forget button */ /* add a forget button */
var forgetCb = function (err, title) { var forgetCb = function (err, title) {
@@ -478,7 +588,19 @@ define([
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad); $rightside.append($forgetPad);
Cryptpad.replaceHash(editHash); if (!readOnly) {
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
}
if (viewHash) {
/* add a 'links' button */
$viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
if (!readOnly) {
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
}
}
// set the hash
if (!readOnly) { Cryptpad.replaceHash(editHash); }
Cryptpad.getPadTitle(function (err, title) { Cryptpad.getPadTitle(function (err, title) {
if (err) { if (err) {
@@ -498,6 +620,7 @@ define([
var config = { var config = {
websocketURL: Cryptpad.getWebsocketURL(), websocketURL: Cryptpad.getWebsocketURL(),
channel: secret.channel, channel: secret.channel,
readOnly: readOnly,
data: {}, data: {},
// our public key // our public key
validateKey: secret.keys.validateKey || undefined, validateKey: secret.keys.validateKey || undefined,
@@ -507,6 +630,10 @@ define([
// don't initialize until the store is ready. // don't initialize until the store is ready.
Cryptpad.ready(function () { Cryptpad.ready(function () {
if (readOnly) {
$('#commit, #create-user, #create-option, #publish').remove();
}
var parsedHash = Cryptpad.parsePadUrl(window.location.href); var parsedHash = Cryptpad.parsePadUrl(window.location.href);
defaultName = Cryptpad.getDefaultName(parsedHash); defaultName = Cryptpad.getDefaultName(parsedHash);
var rt = window.rt = APP.rt = Listmap.create(config); var rt = window.rt = APP.rt = Listmap.create(config);
@@ -519,7 +646,7 @@ define([
if (userid === null) { userid = Render.coluid(); } if (userid === null) { userid = Render.coluid(); }
APP.userid = userid; APP.userid = userid;
Cryptpad.setPadAttribute('userid', userid, function (e) { Cryptpad.setPadAttribute('userid', userid, function (e) {
ready(info, userid); ready(info, userid, readOnly);
}); });
}); });
}) })

View File

@@ -10,6 +10,7 @@ define([
info: { info: {
title: '', title: '',
description: '', description: '',
userData: {}
}, },
table: { table: {
/* TODO /* TODO
@@ -187,7 +188,7 @@ by maintaining indexes in rowsOrder and colsOrder
it returns an array of arrays containing the relevant data for each it returns an array of arrays containing the relevant data for each
cell in table we wish to construct. cell in table we wish to construct.
*/ */
var cellMatrix = Render.cellMatrix = function (obj, rows, cols) { var cellMatrix = Render.cellMatrix = function (obj, rows, cols, readOnly) {
if (typeof(obj) !== 'object') { if (typeof(obj) !== 'object') {
throw new Error('expected realtime-proxy object'); throw new Error('expected realtime-proxy object');
} }
@@ -224,6 +225,9 @@ by maintaining indexes in rowsOrder and colsOrder
type: 'checkbox', type: 'checkbox',
autocomplete: 'nope', autocomplete: 'nope',
}; };
if (readOnly) {
result.disabled = "disabled";
}
if (val) { result.checked = true; } if (val) { result.checked = true; }
return result; return result;
})); }));
@@ -244,16 +248,17 @@ by maintaining indexes in rowsOrder and colsOrder
}, ['']]; }, ['']];
}; };
var makeHeadingCell = Render.makeHeadingCell = function (cell) { var makeHeadingCell = Render.makeHeadingCell = function (cell, readOnly) {
if (!cell) { return ['TD', {}, []]; } if (!cell) { return ['TD', {}, []]; }
if (cell.type === 'text') { if (cell.type === 'text') {
var removeElement = makeRemoveElement(cell['data-rt-id']); var removeElement = makeRemoveElement(cell['data-rt-id']);
var editElement = makeEditElement(cell['data-rt-id']); var editElement = makeEditElement(cell['data-rt-id']);
return ['TD', {}, [ var elements = [['INPUT', cell, []]];
['INPUT', cell, []], if (!readOnly) {
removeElement, elements.push(removeElement);
editElement elements.push(editElement);
]]; }
return ['TD', {}, elements];
} }
return ['TD', cell, []]; return ['TD', cell, []];
}; };
@@ -285,14 +290,17 @@ by maintaining indexes in rowsOrder and colsOrder
]]; ]];
}; };
var makeBodyCell = Render.makeBodyCell = function (cell) { var makeBodyCell = Render.makeBodyCell = function (cell, readOnly) {
if (cell.type === 'text') { if (cell.type === 'text') {
var removeElement = makeRemoveElement(cell['data-rt-id']);
var editElement = makeEditElement(cell['data-rt-id']);
var elements = [['INPUT', cell, []]];
if (!readOnly) {
elements.push(removeElement);
elements.push(editElement);
}
return ['TD', {}, [ return ['TD', {}, [
['DIV', {class: 'text-cell'}, [ ['DIV', {class: 'text-cell'}, elements]
['INPUT', cell, []],
makeRemoveElement(cell['data-rt-id']),
makeEditElement(cell['data-rt-id'])
]]
]]; ]];
} }
@@ -302,19 +310,25 @@ by maintaining indexes in rowsOrder and colsOrder
return ['TD', cell, []]; return ['TD', cell, []];
}; };
var makeBodyRow = Render.makeBodyRow = function (row) { var makeBodyRow = Render.makeBodyRow = function (row, readOnly) {
return ['TR', {}, row.map(makeBodyCell)]; return ['TR', {}, row.map(function (cell) {
return makeBodyCell(cell, readOnly);
})];
}; };
var toHyperjson = Render.toHyperjson = function (matrix) { var toHyperjson = Render.toHyperjson = function (matrix, readOnly) {
if (!matrix || !matrix.length) { return; } if (!matrix || !matrix.length) { return; }
var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(makeHeadingCell)] ]]; var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(function (cell) {
var body = ['TBODY', {}, matrix.slice(1).map(makeBodyRow)]; return makeHeadingCell(cell, readOnly);
})] ]];
var body = ['TBODY', {}, matrix.slice(1).map(function (row) {
return makeBodyRow(row, readOnly);
})];
return ['TABLE', {id:'table'}, [head, body]]; return ['TABLE', {id:'table'}, [head, body]];
}; };
var asHTML = Render.asHTML = function (obj, rows, cols) { var asHTML = Render.asHTML = function (obj, rows, cols, readOnly) {
return Hyperjson.toDOM(toHyperjson(cellMatrix(obj, rows, cols))); return Hyperjson.toDOM(toHyperjson(cellMatrix(obj, rows, cols, readOnly), readOnly));
}; };
var diffIsInput = Render.diffIsInput = function (info) { var diffIsInput = Render.diffIsInput = function (info) {
@@ -390,9 +404,10 @@ by maintaining indexes in rowsOrder and colsOrder
var rows = conf ? conf.rows : null; var rows = conf ? conf.rows : null;
var cols = conf ? conf.cols : null; var cols = conf ? conf.cols : null;
var matrix = cellMatrix(obj, rows, cols); var readOnly = conf ? conf.readOnly : false;
var matrix = cellMatrix(obj, rows, cols, readOnly);
var hj = toHyperjson(matrix); var hj = toHyperjson(matrix, readOnly);
if (!hj) { throw new Error("Expected Hyperjson!"); } if (!hj) { throw new Error("Expected Hyperjson!"); }