From ac43f4cb1fc5acb9dddd77cba4edfe78bfb8b21a Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 14 Nov 2016 15:56:49 +0100 Subject: [PATCH 01/14] new prototype poll --- www/poll/test/index.html | 50 ++++++ www/poll/test/main.js | 187 ++++++++++++++++++++++ www/poll/test/render.js | 325 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 562 insertions(+) create mode 100644 www/poll/test/index.html create mode 100644 www/poll/test/main.js create mode 100644 www/poll/test/render.js diff --git a/www/poll/test/index.html b/www/poll/test/index.html new file mode 100644 index 000000000..a053052d4 --- /dev/null +++ b/www/poll/test/index.html @@ -0,0 +1,50 @@ + + + + + + Zero Knowledge Date Picker + + + + + + +
+ + +
diff --git a/www/poll/test/main.js b/www/poll/test/main.js new file mode 100644 index 000000000..654dd8a00 --- /dev/null +++ b/www/poll/test/main.js @@ -0,0 +1,187 @@ +define([ + '/api/config?cb=' + Math.random().toString(16).substring(2), + '/bower_components/textpatcher/TextPatcher.js', + '/bower_components/chainpad-listmap/chainpad-listmap.js', + '/bower_components/chainpad-crypto/crypto.js', + '/common/cryptpad-common.js', + '/bower_components/hyperjson/hyperjson.js', + '/poll/test/render.js', + '/common/toolbar.js', + '/common/visible.js', + '/common/notify.js', + '/bower_components/file-saver/FileSaver.min.js', + '/bower_components/jquery/dist/jquery.min.js', + //'/customize/pad.js' +], function (Config, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Render, Toolbar) { + var $ = window.jQuery; + var APP = window.APP = { + Toolbar: Toolbar, + Hyperjson: Hyperjson, + Render: Render, + //$bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), + }; + + var change = function (o, n, path) { + if (path && path.join) { + console.log("Change from [%s] to [%s] at [%s]", + o, n, path.join(', ')); + } + + var table = APP.$table[0]; + Render.updateTable(table, APP.proxy); + + /* FIXME browser autocomplete fills in new fields sometimes + calling updateTable twice removes the autofilled in values + setting autocomplete="off" is not reliable + + https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion + */ + window.setTimeout(function () { + Render.updateTable(table, APP.proxy); + }); + }; + + var getRealtimeId = function (input) { + return input.getAttribute && input.getAttribute('data-rt-id'); + }; + + var handleInput = function (input) { + var type = input.type.toLowerCase(); + var id = getRealtimeId(input); + + switch (type) { + case 'text': + console.log("text[rt-id='%s'] [%s]", id, input.value); + Render.setValue(APP.proxy, id, input.value); + break; + case 'checkbox': + console.log("checkbox[tr-id='%s'] %s", id, input.checked); + Render.setValue(APP.proxy, id, input.checked); + break; + default: + console.log("Input[type='%s']", type); + break; + } + }; + + var handleSpan = function (span) { + var id = span.getAttribute('data-rt-id'); + var type = Render.typeofId(id); + if (type === 'row') { + Render.removeRow(APP.proxy, id, function () { + change(); + }); + } else if (type === 'col') { + Render.removeColumn(APP.proxy, id, function () { + change(); + }); + } + }; + + var handleClick = function (e) { + if (!APP.ready) { return; } + var target = e && e.target; + + if (!target) { return void console.log("NO TARGET"); } + + var nodeName = target && target.nodeName; + + switch (nodeName) { + case 'INPUT': + handleInput(target); + break; + case 'SPAN': + handleSpan(target); + break; + case undefined: + //console.error(new Error("C'est pas possible!")); + break; + default: + console.log(target, nodeName); + break; + } + }; + + var prepareProxy = function (proxy, schema) { + if (proxy && proxy.version === 1) { return; } + console.log("Configuring proxy schema..."); + + proxy.info = schema.info; + proxy.table = schema.table; + proxy.version = 1; + }; + + var ready = function (info) { + console.log("READY"); + + var proxy = APP.proxy; + + prepareProxy(proxy, Render.Example); + + var $table = APP.$table = $(Render.asHTML(proxy)); + var $createRow = APP.$createRow = $('#create-option').click(function () { + Render.createRow(proxy, function () { + change(); + }); + }); + + var $createCol = APP.$createCol = $('#create-user').click(function () { + Render.createColumn(proxy, function () { + change(); + }); + }); + + $('.realtime').append($table); + + $table + .click(handleClick) + .on('keyup', handleClick); + + proxy + .on('change', [], change) + .on('remove', [], change); + + APP.ready = true; + }; + + var secret = Cryptpad.getSecrets(); + + var create = function (info) { + var realtime = APP.realtime = info.realtime; + + var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); + + APP.patchText = TextPatcher.create({ + realtime: realtime, + logging: true, + }); + + Cryptpad.replaceHash(editHash); + }; + + var disconnect = function () { + //setEditable(false); // TODO + //Cryptpad.alert(Messages.common_connectionLost); // TODO + }; + + var config = { + websocketURL: Cryptpad.getWebsocketURL(), + channel: secret.channel, + data: {}, + // our public key + validateKey: secret.keys.validateKey || undefined, + //readOnly: readOnly, + crypto: Crypto.createEncryptor(secret.keys), + }; + + // don't initialize until the store is ready. + Cryptpad.ready(function () { + var rt = window.rt = APP.rt = Listmap.create(config); + APP.proxy = rt.proxy; + rt.proxy + .on('create', create) + .on('ready', ready) + .on('disconnect', disconnect); + }); +}); + diff --git a/www/poll/test/render.js b/www/poll/test/render.js new file mode 100644 index 000000000..5f984703a --- /dev/null +++ b/www/poll/test/render.js @@ -0,0 +1,325 @@ +define([ + '/common/cryptpad-common.js', + '/bower_components/hyperjson/hyperjson.js', + '/bower_components/diff-dom/diffDOM.js', +], function (Cryptpad, Hyperjson) { + var DiffDOM = window.diffDOM; + + var Example = { + info: { + title: 'my title', + description: 'my description', + }, + table: { +/* TODO + +deprecate the practice of storing cells, cols, and rows separately. + +Instead, keep everything in one map, and iterate over columns and rows +by maintaining indexes in rowsOrder and colsOrder + +*/ + cells: {}, + cols: {}, + colsOrder: [], + rows: {}, + rowsOrder: [] + } + }; + + var Render = { + Example: Example + }; + + var Uid = Render.Uid = function (prefix, f) { + f = f || function () { + return Number(Math.random() * Number.MAX_SAFE_INTEGER) + .toString(32).replace(/\./g, ''); + }; + return function () { return prefix + '-' + f(); }; + }; + + var coluid = Render.coluid = Uid('x'); + var rowuid = Render.rowuid = Uid('y'); + + var isRow = Render.isRow = function (id) { return /^y\-[^_]*$/.test(id); }; + var isColumn = Render.isColumn = function (id) { return /^x\-[^_]*$/.test(id); }; + var isCell = Render.isCell = function (id) { return /^x\-[^_]*_y\-.*$/.test(id); }; + + var typeofId = Render.typeofId = function (id) { + if (isRow(id)) { return 'row'; } + if (isColumn(id)) { return 'col'; } + if (isCell(id)) { return 'cell'; } + return null; + }; + + var getColumnValue = Render.getColumnValue = function (obj, colId) { + return Cryptpad.find(obj, ['table', 'cols'].concat([colId])); + }; + + var getRowValue = Render.getRowValue = function (obj, rowId) { + return Cryptpad.find(obj, ['table', 'rows'].concat([rowId])); + }; + + var getCellValue = Render.getCellValue = function (obj, cellId) { + return Cryptpad.find(obj, ['table', 'cells'].concat([cellId])); + }; + + var setRowValue = Render.setRowValue = function (obj, rowId, value) { + var parent = Cryptpad.find(obj, ['table', 'rows']); + if (typeof(parent) === 'object') { return (parent[rowId] = value); } + return null; + }; + + var setColumnValue = Render.setColumnValue = function (obj, colId, value) { + var parent = Cryptpad.find(obj, ['table', 'cols']); + if (typeof(parent) === 'object') { return (parent[colId] = value); } + return null; + }; + + var setCellValue = Render.setCellValue = function (obj, cellId, value) { + var parent = Cryptpad.find(obj, ['table', 'cells']); + if (typeof(parent) === 'object') { return (parent[cellId] = value); } + return null; + }; + + var createColumn = Render.createColumn = function (obj, cb, id, value) { + var order = Cryptpad.find(obj, ['table', 'colsOrder']); + if (!order) { throw new Error("Uninitialized realtime object!"); } + id = id || coluid(); + value = value || ""; + setColumnValue(obj, id, value); + order.push(id); + if (typeof(cb) === 'function') { cb(void 0, id); } + }; + + var removeColumn = Render.removeColumn = function (obj, id, cb) { + var order = Cryptpad.find(obj, ['table', 'colsOrder']); + var parent = Cryptpad.find(obj, ['table', 'cols']); + + if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); } + + var idx = order.indexOf(id); + if (idx === -1) { + return void console + .error(new Error("Attempted to remove id which does not exist")); + } + + order.splice(idx, 1); + if (parent[id]) { delete parent[id]; } + if (typeof(cb) === 'function') { + cb(); + } + }; + + var createRow = Render.createRow = function (obj, cb, id, value) { + var order = Cryptpad.find(obj, ['table', 'rowsOrder']); + if (!order) { throw new Error("Uninitialized realtime object!"); } + id = id || rowuid(); + value = value || ""; + setRowValue(obj, id, value); + order.push(id); + if (typeof(cb) === 'function') { cb(void 0, id); } + }; + + var removeRow = Render.removeRow = function (obj, id, cb) { + var order = Cryptpad.find(obj, ['table', 'rowsOrder']); + var parent = Cryptpad.find(obj, ['table', 'rows']); + + if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); } + + var idx = order.indexOf(id); + if (idx === -1) { + return void console + .error(new Error("Attempted to remove id which does not exist")); + } + + order.splice(idx, 1); + if (parent[id]) { delete parent[id]; } + if (typeof(cb) === 'function') { cb(); } + }; + + var setValue = Render.setValue = function (obj, id, value) { + var type = typeofId(id); + switch (type) { + case 'row': return setRowValue(obj, id, value); + case 'col': return setColumnValue(obj, id, value); + case 'cell': return setCellValue(obj, id, value); + case null: break; + default: + console.log("[%s] has type [%s]", id, type); + throw new Error("Unexpected type!"); + } + }; + + var getValue = Render.getValue = function (obj, id) { + switch (typeofId(id)) { + case 'row': return getRowValue(obj, id); + case 'col': return getColumnValue(obj, id); + case 'cell': return getCellValue(obj, id); + case null: break; + default: throw new Error("Unexpected type!"); + } + }; + + var getRowIds = Render.getRowIds = function (obj) { + return Cryptpad.find(obj, ['table', 'rowsOrder']); + }; + + var getColIds = Render.getColIds = function (obj) { + return Cryptpad.find(obj, ['table', 'colsOrder']); + }; + + var getCells = Render.getCells = function (obj) { + return Cryptpad.find(obj, ['table', 'cells']); + }; + + /* cellMatrix takes a proxy object, and optionally an alternate ordering + of row/column keys (as an array). + + it returns an array of arrays containing the relevant data for each + cell in table we wish to construct. + */ + var cellMatrix = Render.cellMatrix = function (obj, rows, cols) { + if (typeof(obj) !== 'object') { + throw new Error('expected realtime-proxy object'); + } + + var cells = getCells(obj); + rows = rows || getRowIds(obj); + cols = cols || getColIds(obj); + + return [null].concat(rows).map(function (row, i) { + if (i === 0) { + return [null].concat(cols.map(function (col) { + return { + 'data-rt-id': col, + type: 'text', + value: getColumnValue(obj, col) || "", + }; + })); + } + + return [{ + 'data-rt-id': row, + value: getRowValue(obj, row), + type: 'text', + }].concat(cols.map(function (col) { + var id = [col, rows[i-1]].join('_'); + var val = cells[id] || false; + + var result = { + 'data-rt-id': id, + type: 'checkbox', + autocomplete: 'nope' + }; + + if (val) { result.checked = true; } + return result; + })); + }); + }; + + var makeRemoveElement = Render.makeRemoveElement = function (id) { + return ['SPAN', { 'data-rt-id': id, }, ['x']]; + }; + + var makeHeadingCell = Render.makeHeadingCell = function (cell) { + if (!cell) { return ['TD', {}, []]; } + if (cell.type === 'text') { + return ['TD', {}, [ + ['INPUT', cell, []], + makeRemoveElement(cell['data-rt-id']) + ]]; + } + return ['TD', cell, []]; + }; + + var makeBodyCell = Render.makeBodyCell = function (cell) { + if (cell.type === 'text') { + return ['TD', {}, [ + ['INPUT', cell, []], + makeRemoveElement(cell['data-rt-id']) + ]]; + } + + if (cell.type === 'checkbox') { + return ['TD', {}, [ ['INPUT', cell, []] ]]; + } + return ['TD', cell, []]; + }; + + var makeBodyRow = Render.makeBodyRow = function (row) { + return ['TR', {}, row.map(makeBodyCell)]; + }; + + var toHyperjson = Render.toHyperjson = function (matrix) { + if (!matrix || !matrix.length) { return; } + var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(makeHeadingCell)] ]]; + var body = ['TBODY', {}, matrix.slice(1).map(makeBodyRow)]; + return ['TABLE', {}, [head, body]]; + }; + + var asHTML = Render.asHTML = function (obj) { + return Hyperjson.toDOM(toHyperjson(cellMatrix(obj))); + }; + + var diffIsInput = Render.diffIsInput = function (info) { + var nodeName = Cryptpad.find(info, ['node', 'nodeName']); + if (nodeName !== 'INPUT') { return; } + return true; + }; + + var getInputType = Render.getInputType = function (info) { + return Cryptpad.find(info, ['node', 'type']); + }; + + var diffOptions = { + preDiffApply: function (info) { + if (!diffIsInput(info)) { return; } + switch (getInputType(info)) { + case 'checkbox': + //console.log('checkbox'); + //console.log("[preDiffApply]", info); +/* + ['modifyAttribute', + 'addAttribute', + 'removeAttribute' + ].some(function (x) { + //if (x === info.diff.action) { } + });*/ + break; + case 'text': + break; + default: break; + } + }, + postDiffApply: function (info) { + /* + if (!diffIsInput(info)) { return; } + switch (getInputType(info)) { + case 'checkbox': + console.log("[postDiffApply]", info); + break; + case 'text': break; + default: break; + }*/ + } + }; + + var updateTable = Render.updateTable = function (table, obj, conf) { + var DD = new DiffDOM(diffOptions); + + var matrix = cellMatrix(obj); + + var hj = toHyperjson(matrix); + + if (!hj) { throw new Error("Expected Hyperjson!"); } + + var table2 = Hyperjson.toDOM(hj); + var patch = DD.diff(table, table2); + DD.apply(table, patch); + }; + + return Render; +}); From eb5017720190e9845b5d0cc2eb71ad2cb6f5aeac Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 14 Nov 2016 18:03:17 +0100 Subject: [PATCH 02/14] do a bit of work to preserve cursors --- www/poll/test/render.js | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 5f984703a..cf547da50 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -1,8 +1,9 @@ define([ '/common/cryptpad-common.js', '/bower_components/hyperjson/hyperjson.js', + '/bower_components/textpatcher/TextPatcher.js', '/bower_components/diff-dom/diffDOM.js', -], function (Cryptpad, Hyperjson) { +], function (Cryptpad, Hyperjson, TextPatcher) { var DiffDOM = window.diffDOM; var Example = { @@ -274,6 +275,28 @@ by maintaining indexes in rowsOrder and colsOrder return Cryptpad.find(info, ['node', 'type']); }; + var preserveCursor = Render.preserveCursor = function (info) { + if (['modifyValue', 'modifyAttribute'].indexOf(info.diff.action) !== -1) { + var element = info.node; + var o = info.oldValue || ''; + var n = info.newValue || ''; + var op = TextPatcher.diff(o, n); + + info.selection = ['selectionStart', 'selectionEnd'].map(function (attr) { + var before = info.node[attr]; + var after = TextPatcher.transformCursor(element[attr], op); + return after; + }); + } + }; + + var recoverCursor = Render.recoverCursor = function (info) { + if (info.selection && info.node) { + info.node.selectionStart = info.selection[0]; + info.node.selectionEnd = info.selection[1]; + } + }; + var diffOptions = { preDiffApply: function (info) { if (!diffIsInput(info)) { return; } @@ -281,20 +304,15 @@ by maintaining indexes in rowsOrder and colsOrder case 'checkbox': //console.log('checkbox'); //console.log("[preDiffApply]", info); -/* - ['modifyAttribute', - 'addAttribute', - 'removeAttribute' - ].some(function (x) { - //if (x === info.diff.action) { } - });*/ break; case 'text': + preserveCursor(info); break; default: break; } }, postDiffApply: function (info) { + if (info.selection) { recoverCursor(info); } /* if (!diffIsInput(info)) { return; } switch (getInputType(info)) { From e5ff7020fbb1c363f31c1f88d076ced21497f077 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Nov 2016 12:02:37 +0100 Subject: [PATCH 03/14] move buttons out of form --- www/poll/test/index.html | 41 +++++++++++++++++----------- www/poll/test/main.js | 45 +++++++++++++++++++++++++++++-- www/poll/test/render.js | 58 +++++++++++++++++++++++++++++++++------- 3 files changed, 118 insertions(+), 26 deletions(-) diff --git a/www/poll/test/index.html b/www/poll/test/index.html index a053052d4..52149bc1c 100644 --- a/www/poll/test/index.html +++ b/www/poll/test/index.html @@ -4,6 +4,7 @@ Zero Knowledge Date Picker + -
- - -
+ + + + + + +
+
+
+
+ +
diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 654dd8a00..615d19e72 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -21,6 +21,7 @@ define([ //$bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path) { if (path && path.join) { console.log("Change from [%s] to [%s] at [%s]", @@ -45,6 +46,7 @@ define([ return input.getAttribute && input.getAttribute('data-rt-id'); }; + /* Called whenever an event is fired on an input element */ var handleInput = function (input) { var type = input.type.toLowerCase(); var id = getRealtimeId(input); @@ -64,6 +66,7 @@ define([ } }; + /* Called whenever an event is fired on a span */ var handleSpan = function (span) { var id = span.getAttribute('data-rt-id'); var type = Render.typeofId(id); @@ -75,6 +78,10 @@ define([ Render.removeColumn(APP.proxy, id, function () { change(); }); + } else if (type === 'cell') { + change(); + } else { + console.log("UNHANDLED"); } }; @@ -91,6 +98,7 @@ define([ handleInput(target); break; case 'SPAN': + case 'LABEL': handleSpan(target); break; case undefined: @@ -102,6 +110,9 @@ define([ } }; + /* + Make sure that the realtime data structure has all the required fields + */ var prepareProxy = function (proxy, schema) { if (proxy && proxy.version === 1) { return; } console.log("Configuring proxy schema..."); @@ -111,8 +122,22 @@ define([ proxy.version = 1; }; - var ready = function (info) { + /* + + */ + var publish = APP.publish = function (bool) { + if (!APP.ready || APP.proxy.published) { return; } + APP.proxy.published = true; + APP.$publish.hide(); + + ['textarea', '#title'].forEach(function (sel) { + $(sel).attr('disabled', bool); + }); + }; + + var ready = function (info, userid) { console.log("READY"); + console.log('userid: %s', userid); var proxy = APP.proxy; @@ -141,6 +166,14 @@ define([ .on('change', [], change) .on('remove', [], change); + if (!proxy.published) { + var $publish = APP.$publish = $('#publish') + .show() + .click(function () { + publish(true); + }); + } + APP.ready = true; }; @@ -180,7 +213,15 @@ define([ APP.proxy = rt.proxy; rt.proxy .on('create', create) - .on('ready', ready) + .on('ready', function (info) { + Cryptpad.getPadAttribute('userid', function (e, userid) { + if (e) { console.error(e); } + if (userid === null) { userid = Render.coluid(); } + Cryptpad.setPadAttribute('userid', userid, function (e) { + ready(info, userid); + }); + }); + }) .on('disconnect', disconnect); }); }); diff --git a/www/poll/test/render.js b/www/poll/test/render.js index cf547da50..53c2589a9 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -222,7 +222,10 @@ by maintaining indexes in rowsOrder and colsOrder }; var makeRemoveElement = Render.makeRemoveElement = function (id) { - return ['SPAN', { 'data-rt-id': id, }, ['x']]; + return ['SPAN', { + 'data-rt-id': id, + class: 'remove', + }, ['✖']]; }; var makeHeadingCell = Render.makeHeadingCell = function (cell) { @@ -236,16 +239,45 @@ by maintaining indexes in rowsOrder and colsOrder return ['TD', cell, []]; }; + var clone = function (o) { + return JSON.parse(JSON.stringify(o)); + }; + + var makeCheckbox = Render.makeCheckbox = function (cell) { + var attrs = clone(cell); + + // FIXME + attrs.id = cell['data-rt-id']; + + var labelClass = 'cover'; + if (cell.checked) { + labelClass += ' yes'; + } + + return ['TD', {class:"checkbox-cell"}, [ + ['DIV', {class: 'checkbox-contain'}, [ + ['INPUT', attrs, []], + ['SPAN', {class: labelClass}, []], + ['LABEL', { + for: attrs.id, + 'data-rt-id': attrs.id, + }, []] + ]] + ]]; + }; + var makeBodyCell = Render.makeBodyCell = function (cell) { if (cell.type === 'text') { return ['TD', {}, [ - ['INPUT', cell, []], - makeRemoveElement(cell['data-rt-id']) + ['DIV', {class: 'text-cell'}, [ + ['INPUT', cell, []], + makeRemoveElement(cell['data-rt-id']) + ]] ]]; } if (cell.type === 'checkbox') { - return ['TD', {}, [ ['INPUT', cell, []] ]]; + return makeCheckbox(cell); } return ['TD', cell, []]; }; @@ -258,7 +290,7 @@ by maintaining indexes in rowsOrder and colsOrder if (!matrix || !matrix.length) { return; } var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(makeHeadingCell)] ]]; var body = ['TBODY', {}, matrix.slice(1).map(makeBodyRow)]; - return ['TABLE', {}, [head, body]]; + return ['TABLE', {id:'table'}, [head, body]]; }; var asHTML = Render.asHTML = function (obj) { @@ -278,12 +310,15 @@ by maintaining indexes in rowsOrder and colsOrder var preserveCursor = Render.preserveCursor = function (info) { if (['modifyValue', 'modifyAttribute'].indexOf(info.diff.action) !== -1) { var element = info.node; + + if (typeof(element.selectionStart) !== 'number') { return; } + var o = info.oldValue || ''; var n = info.newValue || ''; var op = TextPatcher.diff(o, n); info.selection = ['selectionStart', 'selectionEnd'].map(function (attr) { - var before = info.node[attr]; + var before = element[attr]; var after = TextPatcher.transformCursor(element[attr], op); return after; }); @@ -291,9 +326,14 @@ by maintaining indexes in rowsOrder and colsOrder }; var recoverCursor = Render.recoverCursor = function (info) { - if (info.selection && info.node) { - info.node.selectionStart = info.selection[0]; - info.node.selectionEnd = info.selection[1]; + try { + if (info.selection && info.node) { + info.node.selectionStart = info.selection[0]; + info.node.selectionEnd = info.selection[1]; + } + } catch (err) { + //console.log(info.node); + //console.error(err); } }; From 4a4d4a047414b31dd870189d39d2efb19d6c0cbb Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Nov 2016 12:02:58 +0100 Subject: [PATCH 04/14] most recent work --- www/poll/test/main.js | 14 ++++++++++++-- www/poll/test/render.js | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 615d19e72..cf2132478 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -51,9 +51,13 @@ define([ var type = input.type.toLowerCase(); var id = getRealtimeId(input); + console.log(input); + switch (type) { case 'text': console.log("text[rt-id='%s'] [%s]", id, input.value); + + if (!input.value) { return void console.log("Hit enter?"); } Render.setValue(APP.proxy, id, input.value); break; case 'checkbox': @@ -85,10 +89,14 @@ define([ } }; - var handleClick = function (e) { + var handleClick = function (e, isKeyup) { if (!APP.ready) { return; } var target = e && e.target; + if (isKeyup) { + console.log("Keyup!"); + } + if (!target) { return void console.log("NO TARGET"); } var nodeName = target && target.nodeName; @@ -145,6 +153,8 @@ define([ var $table = APP.$table = $(Render.asHTML(proxy)); var $createRow = APP.$createRow = $('#create-option').click(function () { + // + console.error("BUTTON CLICKED! LOL"); Render.createRow(proxy, function () { change(); }); @@ -160,7 +170,7 @@ define([ $table .click(handleClick) - .on('keyup', handleClick); + .on('keyup', function (e) { handleClick(e, true); }); proxy .on('change', [], change) diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 53c2589a9..fde96c54c 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -114,6 +114,7 @@ by maintaining indexes in rowsOrder and colsOrder }; var createRow = Render.createRow = function (obj, cb, id, value) { + console.error('new row!'); var order = Cryptpad.find(obj, ['table', 'rowsOrder']); if (!order) { throw new Error("Uninitialized realtime object!"); } id = id || rowuid(); From bdb8a2ec5952fa8c93675ad12772913ce57e8ead Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Nov 2016 12:04:22 +0100 Subject: [PATCH 05/14] additional styles for newpoll --- customize.dist/src/cryptpad.less | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index 7492114e9..716fc7a85 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -384,8 +384,12 @@ form.realtime { padding: 0px; margin: 0px; height: 100%; + + width: 500px; + input { width: 80%; + width: 90%; height: 100%; border: 0px; &[disabled] { @@ -399,9 +403,10 @@ form.realtime { &.checkbox-cell { margin: 0px; padding: 0px; + height: 100%; div.checkbox-contain { - display: block; + display: inline-block; height: 100%; width: 100%; position: relative; @@ -427,6 +432,11 @@ form.realtime { background-color: @cp-red; color: @base; + + &:after { + height: 100%; + } + &:after { content: "✖"; } display: block; From ffedcb63f77bbf3a208bd1d6e46b3552bb1eb3c9 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 25 Nov 2016 18:17:03 +0100 Subject: [PATCH 06/14] Display own column at the beginning, add uncommitted column --- customize.dist/main.css | 8 +++++++- www/poll/test/main.js | 29 ++++++++++++++++++++++++++--- www/poll/test/render.js | 24 +++++++++++++++++------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index 2455aa465..ddccca51f 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -337,9 +337,11 @@ form.realtime table tr td div.text-cell { padding: 0px; margin: 0px; height: 100%; + width: 500px; } form.realtime table tr td div.text-cell input { width: 80%; + width: 90%; height: 100%; border: 0px; } @@ -351,9 +353,10 @@ form.realtime table tr td div.text-cell input[disabled] { form.realtime table tr td.checkbox-cell { margin: 0px; padding: 0px; + height: 100%; } form.realtime table tr td.checkbox-cell div.checkbox-contain { - display: block; + display: inline-block; height: 100%; width: 100%; position: relative; @@ -376,6 +379,9 @@ form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbo color: #302B28; display: block; } +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { + height: 100%; +} form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { content: "✖"; } diff --git a/www/poll/test/main.js b/www/poll/test/main.js index cf2132478..22b3d06db 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -21,6 +21,18 @@ define([ //$bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), }; + var sortColumns = function (order, firstcol) { + var colsOrder = order.slice(); + colsOrder.sort(function (a, b) { + return (a === firstcol) ? -1 : + ((b === firstcol) ? 1 : 0); + }); + if (colsOrder.indexOf(firstcol) === -1) { + colsOrder.unshift(firstcol); + } + return colsOrder; + }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path) { if (path && path.join) { @@ -29,7 +41,13 @@ define([ } var table = APP.$table[0]; - Render.updateTable(table, APP.proxy); + + var colsOrder = sortColumns(APP.proxy.table.colsOrder, APP.userid); + var conf = { + cols: colsOrder + }; + + Render.updateTable(table, APP.proxy, conf); /* FIXME browser autocomplete fills in new fields sometimes calling updateTable twice removes the autofilled in values @@ -38,7 +56,7 @@ define([ https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion */ window.setTimeout(function () { - Render.updateTable(table, APP.proxy); + Render.updateTable(table, APP.proxy, conf); }); }; @@ -53,6 +71,8 @@ define([ console.log(input); + if ($(input).hasClass("uncommitted-cell")) { console.log('do nothing'); return; } + switch (type) { case 'text': console.log("text[rt-id='%s'] [%s]", id, input.value); @@ -151,7 +171,9 @@ define([ prepareProxy(proxy, Render.Example); - var $table = APP.$table = $(Render.asHTML(proxy)); + var colsOrder = sortColumns(proxy.table.colsOrder, userid); + + var $table = APP.$table = $(Render.asHTML(proxy, null, colsOrder)); var $createRow = APP.$createRow = $('#create-option').click(function () { // console.error("BUTTON CLICKED! LOL"); @@ -227,6 +249,7 @@ define([ Cryptpad.getPadAttribute('userid', function (e, userid) { if (e) { console.error(e); } if (userid === null) { userid = Render.coluid(); } + APP.userid = userid; Cryptpad.setPadAttribute('userid', userid, function (e) { ready(info, userid); }); diff --git a/www/poll/test/render.js b/www/poll/test/render.js index fde96c54c..b27fd3db1 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -194,11 +194,16 @@ by maintaining indexes in rowsOrder and colsOrder return [null].concat(rows).map(function (row, i) { if (i === 0) { return [null].concat(cols.map(function (col) { - return { + var result = { 'data-rt-id': col, type: 'text', - value: getColumnValue(obj, col) || "", + value: getColumnValue(obj, col) || "" }; + if (getColumnValue(obj, col) === false) { + result.placeholder = 'new column here'; //TODO translate + result['class'] = 'uncommitted'; + } + return result; })); } @@ -215,7 +220,9 @@ by maintaining indexes in rowsOrder and colsOrder type: 'checkbox', autocomplete: 'nope' }; - + if (getColumnValue(obj, col) === false) { + result['class'] = 'uncommitted-cell'; + } if (val) { result.checked = true; } return result; })); @@ -232,9 +239,10 @@ by maintaining indexes in rowsOrder and colsOrder var makeHeadingCell = Render.makeHeadingCell = function (cell) { if (!cell) { return ['TD', {}, []]; } if (cell.type === 'text') { + var removeElement = cell['class'] !== "uncommitted" ? makeRemoveElement(cell['data-rt-id']) : ''; return ['TD', {}, [ ['INPUT', cell, []], - makeRemoveElement(cell['data-rt-id']) + removeElement ]]; } return ['TD', cell, []]; @@ -294,8 +302,8 @@ by maintaining indexes in rowsOrder and colsOrder return ['TABLE', {id:'table'}, [head, body]]; }; - var asHTML = Render.asHTML = function (obj) { - return Hyperjson.toDOM(toHyperjson(cellMatrix(obj))); + var asHTML = Render.asHTML = function (obj, rows, cols) { + return Hyperjson.toDOM(toHyperjson(cellMatrix(obj, rows, cols))); }; var diffIsInput = Render.diffIsInput = function (info) { @@ -369,7 +377,9 @@ by maintaining indexes in rowsOrder and colsOrder var updateTable = Render.updateTable = function (table, obj, conf) { var DD = new DiffDOM(diffOptions); - var matrix = cellMatrix(obj); + var rows = conf ? conf.rows : null; + var cols = conf ? conf.cols : null; + var matrix = cellMatrix(obj, rows, cols); var hj = toHyperjson(matrix); From bca746bbb5186f790e199f62189855da8b3eeffb Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 28 Nov 2016 18:38:06 +0100 Subject: [PATCH 07/14] Fix uncommitted column, add toolbar --- www/poll/test/index.html | 4 +- www/poll/test/main.js | 139 ++++++++++++++++++++++++++++++++++----- www/poll/test/render.js | 17 ++--- 3 files changed, 133 insertions(+), 27 deletions(-) diff --git a/www/poll/test/index.html b/www/poll/test/index.html index 52149bc1c..3aef58e04 100644 --- a/www/poll/test/index.html +++ b/www/poll/test/index.html @@ -47,15 +47,17 @@ +
+


-
+
diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 22b3d06db..bfff6fe11 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -1,5 +1,6 @@ define([ '/api/config?cb=' + Math.random().toString(16).substring(2), + '/customize/messages.js?app=poll', '/bower_components/textpatcher/TextPatcher.js', '/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-crypto/crypto.js', @@ -12,13 +13,13 @@ define([ '/bower_components/file-saver/FileSaver.min.js', '/bower_components/jquery/dist/jquery.min.js', //'/customize/pad.js' -], function (Config, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Render, Toolbar) { +], function (Config, Messages, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Render, Toolbar) { var $ = window.jQuery; var APP = window.APP = { Toolbar: Toolbar, Hyperjson: Hyperjson, Render: Render, - //$bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), + $bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), }; var sortColumns = function (order, firstcol) { @@ -27,12 +28,39 @@ define([ return (a === firstcol) ? -1 : ((b === firstcol) ? 1 : 0); }); - if (colsOrder.indexOf(firstcol) === -1) { - colsOrder.unshift(firstcol); - } return colsOrder; }; + var mergeUncommitted = function (proxy, uncommitted, commit) { + var newObj; + if (commit) { + newObj = proxy; + } else { + newObj = $.extend(true, {}, proxy); + } + // We have uncommitted data only if the user's column is not in the proxy + // If it is already is the proxy, nothing to merge + if (proxy.table.colsOrder.indexOf(APP.userid) !== -1) { + return newObj; + } + // Merge uncommitted into the proxy + uncommitted.table.colsOrder.forEach(function (x) { + if (newObj.table.colsOrder.indexOf(x) !== -1) { return; } + newObj.table.colsOrder.push(x); + }); + for (var k in uncommitted.table.cols) { + if (!newObj.table.cols[k]) { + newObj.table.cols[k] = uncommitted.table.cols[k]; + } + } + for (var k in uncommitted.table.cells) { + if (!newObj.table.cells[k]) { + newObj.table.cells[k] = uncommitted.table.cells[k]; + } + } + return newObj; + }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path) { if (path && path.join) { @@ -42,12 +70,14 @@ define([ var table = APP.$table[0]; - var colsOrder = sortColumns(APP.proxy.table.colsOrder, APP.userid); + var displayedObj = mergeUncommitted(APP.proxy, APP.uncommitted); + + var colsOrder = sortColumns(displayedObj.table.colsOrder, APP.userid); var conf = { cols: colsOrder }; - Render.updateTable(table, APP.proxy, conf); + Render.updateTable(table, displayedObj, conf); /* FIXME browser autocomplete fills in new fields sometimes calling updateTable twice removes the autofilled in values @@ -56,7 +86,8 @@ define([ https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion */ window.setTimeout(function () { - Render.updateTable(table, APP.proxy, conf); + var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted); + Render.updateTable(table, displayedObj2, conf); }); }; @@ -71,18 +102,22 @@ define([ console.log(input); - if ($(input).hasClass("uncommitted-cell")) { console.log('do nothing'); return; } + var object = APP.proxy; + + var x = Render.getCoordinates(id)[0]; + if (type !== "row" && x === APP.userid && APP.proxy.table.colsOrder.indexOf(x) === -1) { + object = APP.uncommitted; + } switch (type) { case 'text': console.log("text[rt-id='%s'] [%s]", id, input.value); - if (!input.value) { return void console.log("Hit enter?"); } - Render.setValue(APP.proxy, id, input.value); + Render.setValue(object, id, input.value); break; case 'checkbox': console.log("checkbox[tr-id='%s'] %s", id, input.checked); - Render.setValue(APP.proxy, id, input.checked); + Render.setValue(object, id, input.checked); break; default: console.log("Input[type='%s']", type); @@ -163,17 +198,36 @@ define([ }); }; + + var copyObject = function (obj) { + return JSON.parse(JSON.stringify(obj)); + }; + + // special UI elements + var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); + var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); + + var items = [$title, $description]; + 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); + } - prepareProxy(proxy, Render.Example); + var displayedObj = mergeUncommitted(proxy, uncommitted, false); - var colsOrder = sortColumns(proxy.table.colsOrder, userid); + var colsOrder = sortColumns(displayedObj.table.colsOrder, userid); - var $table = APP.$table = $(Render.asHTML(proxy, null, colsOrder)); + + var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder)); var $createRow = APP.$createRow = $('#create-option').click(function () { // console.error("BUTTON CLICKED! LOL"); @@ -188,6 +242,28 @@ define([ }); }); + //TODO + 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(); + }); + + items.forEach(function ($item) { + var id = $item.attr('id'); + + $item.on('change keyup', function () { + var val = $item.val(); + proxy.info[id] = val; + }); + + if (typeof(proxy.info[id]) !== 'undefined') { + $item.val(proxy.info[id]); + } + }); + $('.realtime').append($table); $table @@ -195,7 +271,30 @@ define([ .on('keyup', function (e) { handleClick(e, true); }); proxy - .on('change', [], change) + .on('change', ['info'], function (o, n, p) { + var $target = $('#' + p[1]); + var el = $target[0]; + var selects; + var op; + + if (el && ['textarea', 'text'].indexOf(el.type) !== -1) { + op = TextPatcher.diff(o, n); + 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) { @@ -221,6 +320,14 @@ define([ logging: true, }); + var userList = info.userList; + var config = { + userData: {}, + readOnly: false, + common: Cryptpad + }; + toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config); + Cryptpad.replaceHash(editHash); }; diff --git a/www/poll/test/render.js b/www/poll/test/render.js index b27fd3db1..91acc266b 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -8,8 +8,8 @@ define([ var Example = { info: { - title: 'my title', - description: 'my description', + title: '', + description: '', }, table: { /* TODO @@ -54,6 +54,10 @@ by maintaining indexes in rowsOrder and colsOrder return null; }; + var getCoordinates = Render.getCoordinates = function (id) { + return id.split('_'); + }; + var getColumnValue = Render.getColumnValue = function (obj, colId) { return Cryptpad.find(obj, ['table', 'cols'].concat([colId])); }; @@ -143,6 +147,7 @@ by maintaining indexes in rowsOrder and colsOrder var setValue = Render.setValue = function (obj, id, value) { var type = typeofId(id); + switch (type) { case 'row': return setRowValue(obj, id, value); case 'col': return setColumnValue(obj, id, value); @@ -199,10 +204,6 @@ by maintaining indexes in rowsOrder and colsOrder type: 'text', value: getColumnValue(obj, col) || "" }; - if (getColumnValue(obj, col) === false) { - result.placeholder = 'new column here'; //TODO translate - result['class'] = 'uncommitted'; - } return result; })); } @@ -214,15 +215,11 @@ by maintaining indexes in rowsOrder and colsOrder }].concat(cols.map(function (col) { var id = [col, rows[i-1]].join('_'); var val = cells[id] || false; - var result = { 'data-rt-id': id, type: 'checkbox', autocomplete: 'nope' }; - if (getColumnValue(obj, col) === false) { - result['class'] = 'uncommitted-cell'; - } if (val) { result.checked = true; } return result; })); From eaeaf4df402263735bdbac4dd60e54aba7eea0d5 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 29 Nov 2016 17:26:31 +0100 Subject: [PATCH 08/14] Improve UI, add title input and forget button --- customize.dist/main.css | 3 + customize.dist/src/cryptpad.less | 6 ++ www/poll/test/index.html | 49 +++++++++- www/poll/test/main.js | 157 +++++++++++++++++++++++++------ www/poll/test/render.js | 4 +- 5 files changed, 186 insertions(+), 33 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index ddccca51f..9eb23b1e2 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -391,6 +391,9 @@ form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbo form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after { content: "✔"; } +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted { + background: #ddd; +} form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine { display: none; } diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index 716fc7a85..5f95cd553 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -444,6 +444,12 @@ form.realtime { background-color: @cp-green; &:after { content: "✔"; } } + + &.uncommitted { + background: #ddd; + } + + &.mine { display: none; } diff --git a/www/poll/test/index.html b/www/poll/test/index.html index 3aef58e04..65219ca6e 100644 --- a/www/poll/test/index.html +++ b/www/poll/test/index.html @@ -4,6 +4,7 @@ Zero Knowledge Date Picker + @@ -43,21 +44,59 @@ border: .5px solid black; } + table#table { + margin: 0px; + } + #tableContainer { + position: relative; + padding: 29px; + padding-right: 82px; + } + #tableContainer button { + height: 2rem; + } + #commit { + position: absolute; + left: 532px; + bottom: 0px; + } + #create-user { + position: absolute; + left: 0px; + top: 31px; + width: 50px; + overflow: hidden; + } + #create-option { + position: absolute; + bottom: 0px; + left: 249px; + width: 50px; + } +
- - +
+

CryptPoll

+

+ +

+

+
+ -

-

- +

+ + + +

diff --git a/www/poll/test/main.js b/www/poll/test/main.js index bfff6fe11..513999a73 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -15,6 +15,10 @@ define([ //'/customize/pad.js' ], function (Config, Messages, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Render, Toolbar) { var $ = window.jQuery; + + var HIDE_INTRODUCTION_TEXT = "hide_poll_text"; + var defaultName; + var APP = window.APP = { Toolbar: Toolbar, Hyperjson: Hyperjson, @@ -31,6 +35,10 @@ define([ return colsOrder; }; + var isOwnColumnCommitted = function () { + return APP.proxy && APP.proxy.table.colsOrder.indexOf(APP.userid) !== -1; + }; + var mergeUncommitted = function (proxy, uncommitted, commit) { var newObj; if (commit) { @@ -40,7 +48,7 @@ define([ } // We have uncommitted data only if the user's column is not in the proxy // If it is already is the proxy, nothing to merge - if (proxy.table.colsOrder.indexOf(APP.userid) !== -1) { + if (isOwnColumnCommitted()) { return newObj; } // Merge uncommitted into the proxy @@ -61,6 +69,28 @@ define([ return newObj; }; + var styleUncommittedColumn = function () { + var id = APP.userid; + if (isOwnColumnCommitted()) { return; } + $('[data-rt-id^="' + id + '"]').closest('td').addClass("uncommitted"); + $('td.uncommitted .remove').remove(); + $('td.uncommitted .cover').addClass("uncommitted"); + $('.uncommitted input[type="text"]').attr("placeholder", "New column here"); //TODO + }; + + var updateTableButtons = function () { + if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { + $('#commit').show(); + $('#commit').css('width', $($('.checkbox-cell')[0]).width()); + } else { + $('#commit').hide(); + } + var width = $('#table').outerWidth(); + if (width) { + $('#create-user').css('left', width + 30 + 'px'); + } + }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path) { if (path && path.join) { @@ -88,6 +118,8 @@ define([ window.setTimeout(function () { var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted); Render.updateTable(table, displayedObj2, conf); + updateTableButtons(); + styleUncommittedColumn(); }); }; @@ -193,7 +225,7 @@ define([ APP.proxy.published = true; APP.$publish.hide(); - ['textarea', '#title'].forEach(function (sel) { + ['textarea'].forEach(function (sel) { $(sel).attr('disabled', bool); }); }; @@ -204,11 +236,9 @@ define([ }; // special UI elements - var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); + //var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); TODO var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); - var items = [$title, $description]; - var ready = function (info, userid) { console.log("READY"); console.log('userid: %s', userid); @@ -226,7 +256,6 @@ define([ var colsOrder = sortColumns(displayedObj.table.colsOrder, userid); - var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder)); var $createRow = APP.$createRow = $('#create-option').click(function () { // @@ -242,7 +271,7 @@ define([ }); }); - //TODO + // Commit button var $commit = APP.$commit = $('#commit').click(function () { var uncommittedCopy = JSON.parse(JSON.stringify(APP.uncommitted)); APP.uncommitted = {}; @@ -251,20 +280,26 @@ define([ change(); }); - items.forEach(function ($item) { - var id = $item.attr('id'); - - $item.on('change keyup', function () { - var val = $item.val(); - proxy.info[id] = val; - }); + // Title + if (APP.proxy.info.defaultTitle) { + updateDefaultTitle(APP.proxy.info.defaultTitle); + } else { + APP.proxy.info.defaultTitle = defaultName + } + updateTitle(APP.proxy.info.title || defaultName); - if (typeof(proxy.info[id]) !== 'undefined') { - $item.val(proxy.info[id]); - } + // 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); + } - $('.realtime').append($table); + $('#tableContainer').prepend($table); + updateTableButtons(); + styleUncommittedColumn(); $table .click(handleClick) @@ -272,20 +307,18 @@ define([ proxy .on('change', ['info'], function (o, n, p) { - var $target = $('#' + p[1]); - var el = $target[0]; - var selects; - var op; - - if (el && ['textarea', 'text'].indexOf(el.type) !== -1) { - op = TextPatcher.diff(o, n); - selects = ['selectionStart', 'selectionEnd'].map(function (attr) { + 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]; @@ -310,6 +343,39 @@ define([ var secret = Cryptpad.getSecrets(); + + 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; + APP.$bar.find('.' + Toolbar.constants.title).find('span.title').text(data); + APP.$bar.find('.' + Toolbar.constants.title).find('input').val(data); + }); + }; + + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + APP.$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + var renameCb = function (err, title) { + if (err) { return; } + document.title = title; + APP.proxy.info.title = title; + }; + + var suggestName = function (fallback) { + return document.title || defaultName || ""; + }; + var create = function (info) { var realtime = APP.realtime = info.realtime; @@ -324,11 +390,35 @@ define([ var config = { userData: {}, readOnly: false, + title: { + onRename: renameCb, + defaultName: defaultName, + suggestName: suggestName + }, common: Cryptpad }; toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config); + var $rightside = APP.$bar.find('.' + Toolbar.constants.rightside); + + /* add a forget button */ + var forgetCb = function (err, title) { + if (err) { return; } + document.title = title; + }; + var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); + $rightside.append($forgetPad); + Cryptpad.replaceHash(editHash); + + Cryptpad.getPadTitle(function (err, title) { + if (err) { + console.error(err); + console.log("Couldn't get pad title"); + return; + } + updateTitle(title || defaultName); + }); }; var disconnect = function () { @@ -348,6 +438,8 @@ define([ // don't initialize until the store is ready. Cryptpad.ready(function () { + var parsedHash = Cryptpad.parsePadUrl(window.location.href); + defaultName = Cryptpad.getDefaultName(parsedHash); var rt = window.rt = APP.rt = Listmap.create(config); APP.proxy = rt.proxy; rt.proxy @@ -363,6 +455,17 @@ define([ }); }) .on('disconnect', disconnect); + + Cryptpad.getPadAttribute(HIDE_INTRODUCTION_TEXT, function (e, value) { + if (e) { console.error(e); } + if (value === null) { + Cryptpad.setPadAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { + if (e) { console.error(e) } + }); + } else if (value === "1") { + $('#howItWorks').hide(); + } + }); }); }); diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 91acc266b..950da7342 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -202,7 +202,8 @@ by maintaining indexes in rowsOrder and colsOrder var result = { 'data-rt-id': col, type: 'text', - value: getColumnValue(obj, col) || "" + value: getColumnValue(obj, col) || "", + placeholder: 'User' //TODO translate }; return result; })); @@ -212,6 +213,7 @@ by maintaining indexes in rowsOrder and colsOrder 'data-rt-id': row, value: getRowValue(obj, row), type: 'text', + placeholder: 'Option' //TODO translate }].concat(cols.map(function (col) { var id = [col, rows[i-1]].join('_'); var val = cells[id] || false; From 3632834500fcc346e0873be3e936549abebf0a95 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 30 Nov 2016 18:39:19 +0100 Subject: [PATCH 09/14] Lock inputs when the user is not editing them --- customize.dist/main.css | 2 +- customize.dist/src/cryptpad.less | 2 +- www/poll/test/main.js | 87 ++++++++++++++++++++++++++++---- www/poll/test/render.js | 24 ++++++--- 4 files changed, 98 insertions(+), 17 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index 9eb23b1e2..32e538c68 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -399,7 +399,7 @@ form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbo } form.realtime table input[type="text"] { height: 100%; - width: 80%; + width: 70%; border: 3px solid #302B28; } form.realtime table .edit { diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index 5f95cd553..e123f8722 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -465,7 +465,7 @@ form.realtime { input { &[type="text"] { height: 100%; - width: 80%; + width: 70%; border: 3px solid @base; } } diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 513999a73..ce0a2f4d9 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -24,6 +24,10 @@ define([ Hyperjson: Hyperjson, Render: Render, $bar: $('#toolbar').css({ border: '1px solid white', background: 'grey', 'margin-bottom': '1vh', }), + editable: { + row: [], + col: [] + } }; var sortColumns = function (order, firstcol) { @@ -69,16 +73,42 @@ define([ return newObj; }; + var setColumnDisabled = function (id, state) { + if (!state) { + $('input[data-rt-id^="' + id + '"]').removeAttr('disabled'); + return; + } + $('input[data-rt-id^="' + id + '"]').attr('disabled', 'disabled'); + }; + var styleUncommittedColumn = function () { var id = APP.userid; + + // Enable the checkboxes for the user's column (committed or not) + $('input[disabled="disabled"][data-rt-id^="' + id + '"]').removeAttr('disabled'); + $('input[type="checkbox"][data-rt-id^="' + id + '"]').addClass('enabled'); + if (isOwnColumnCommitted()) { return; } $('[data-rt-id^="' + id + '"]').closest('td').addClass("uncommitted"); - $('td.uncommitted .remove').remove(); + $('td.uncommitted .remove, td.uncommitted .edit').css('visibility', 'hidden'); $('td.uncommitted .cover').addClass("uncommitted"); $('.uncommitted input[type="text"]').attr("placeholder", "New column here"); //TODO }; + var unlockElements = function () { + APP.editable.row.forEach(function (id) { + $('input[type="text"][disabled="disabled"][data-rt-id="' + id + '"]').removeAttr('disabled'); + $('span.edit[data-rt-id="' + id + '"]').css('visibility', 'hidden'); + }); + APP.editable.col.forEach(function (id) { + $('input[disabled="disabled"][data-rt-id^="' + id + '"]').removeAttr('disabled'); + $('input[type="checkbox"][data-rt-id^="' + id + '"]').addClass('enabled'); + $('span.edit[data-rt-id="' + id + '"]').css('visibility', 'hidden'); + }); + }; + var updateTableButtons = function () { + unlockElements(); if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { $('#commit').show(); $('#commit').css('width', $($('.checkbox-cell')[0]).width()); @@ -91,6 +121,23 @@ define([ } }; + var unlockColumn = function (id, cb) { + if (APP.editable.col.indexOf(id) === -1) { + APP.editable.col.push(id); + } + if (typeof(cb) === "function") { + cb(); + } + }; + var unlockRow = function (id, cb) { + if (APP.editable.row.indexOf(id) === -1) { + APP.editable.row.push(id); + } + if (typeof(cb) === "function") { + cb(); + } + }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path) { if (path && path.join) { @@ -146,10 +193,16 @@ define([ console.log("text[rt-id='%s'] [%s]", id, input.value); if (!input.value) { return void console.log("Hit enter?"); } Render.setValue(object, id, input.value); + change(); break; case 'checkbox': console.log("checkbox[tr-id='%s'] %s", id, input.checked); - Render.setValue(object, id, input.checked); + if ($(input).hasClass('enabled')) { + Render.setValue(object, id, input.checked); + change(); + } else { + console.log('checkbox locked'); + } break; default: console.log("Input[type='%s']", type); @@ -162,13 +215,29 @@ define([ var id = span.getAttribute('data-rt-id'); var type = Render.typeofId(id); if (type === 'row') { - Render.removeRow(APP.proxy, id, function () { - change(); - }); + var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; + var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; + if (isRemove) { + Render.removeRow(APP.proxy, id, function () { + change(); + }); + } else if (isEdit) { + unlockRow(id, function () { + change(); + }); + } } else if (type === 'col') { - Render.removeColumn(APP.proxy, id, function () { - change(); - }); + var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; + var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; + if (isRemove) { + Render.removeColumn(APP.proxy, id, function () { + change(); + }); + } else if (isEdit) { + unlockColumn(id, function () { + change(); + }); + } } else if (type === 'cell') { change(); } else { @@ -193,7 +262,7 @@ define([ handleInput(target); break; case 'SPAN': - case 'LABEL': + //case 'LABEL': handleSpan(target); break; case undefined: diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 950da7342..a817bc19f 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -203,7 +203,8 @@ by maintaining indexes in rowsOrder and colsOrder 'data-rt-id': col, type: 'text', value: getColumnValue(obj, col) || "", - placeholder: 'User' //TODO translate + placeholder: 'User', //TODO translate + disabled: 'disabled' }; return result; })); @@ -213,14 +214,15 @@ by maintaining indexes in rowsOrder and colsOrder 'data-rt-id': row, value: getRowValue(obj, row), type: 'text', - placeholder: 'Option' //TODO translate + placeholder: 'Option', //TODO translate + disabled: 'disabled' }].concat(cols.map(function (col) { var id = [col, rows[i-1]].join('_'); var val = cells[id] || false; var result = { 'data-rt-id': id, type: 'checkbox', - autocomplete: 'nope' + autocomplete: 'nope', }; if (val) { result.checked = true; } return result; @@ -235,13 +237,22 @@ by maintaining indexes in rowsOrder and colsOrder }, ['✖']]; }; + var makeEditElement = Render.makeEditElement = function (id) { + return ['SPAN', { + 'data-rt-id': id, + class: 'edit', + }, ['']]; + }; + var makeHeadingCell = Render.makeHeadingCell = function (cell) { if (!cell) { return ['TD', {}, []]; } if (cell.type === 'text') { - var removeElement = cell['class'] !== "uncommitted" ? makeRemoveElement(cell['data-rt-id']) : ''; + var removeElement = makeRemoveElement(cell['data-rt-id']); + var editElement = makeEditElement(cell['data-rt-id']); return ['TD', {}, [ ['INPUT', cell, []], - removeElement + removeElement, + editElement ]]; } return ['TD', cell, []]; @@ -279,7 +290,8 @@ by maintaining indexes in rowsOrder and colsOrder return ['TD', {}, [ ['DIV', {class: 'text-cell'}, [ ['INPUT', cell, []], - makeRemoveElement(cell['data-rt-id']) + makeRemoveElement(cell['data-rt-id']), + makeEditElement(cell['data-rt-id']) ]] ]]; } From 90804ed9e03afea8ad86aca410586c071240bc51 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 1 Dec 2016 18:40:09 +0100 Subject: [PATCH 10/14] Add usernames/userlist in the toolbar and fix publish button --- customize.dist/translations/messages.es.js | 4 +- customize.dist/translations/messages.fr.js | 4 +- customize.dist/translations/messages.js | 4 +- www/common/cryptpad-common.js | 3 - www/common/toolbar.js | 2 +- www/poll/test/index.html | 11 +- www/poll/test/main.js | 261 +++++++++++++++------ www/poll/test/render.js | 59 +++-- 8 files changed, 248 insertions(+), 100 deletions(-) diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index a7b9740b9..0b6de909f 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -27,8 +27,8 @@ define(function () { out.readOnly = 'Solo lectura'; out.anonymous = 'Anónimo'; out.yourself = "tú mismo"; - out.anonymousUsers = "usuarios anónimos"; - out.anonymousUser = "usuario anónimo"; + out.anonymousUsers = "editores anónimos"; + out.anonymousUser = "editor anónimo"; out.shareView = "URL de sólo lectura"; out.shareEdit = "Editar URL"; out.users = "Usuarios"; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 94ca6050a..493bd69c9 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -27,8 +27,8 @@ define(function () { out.readonly = 'Lecture seule'; out.anonymous = "Anonyme"; out.yourself = "Vous-même"; - out.anonymousUsers = "utilisateurs anonymes"; - out.anonymousUser = "utilisateur anonyme"; + out.anonymousUsers = "éditeurs anonymes"; + out.anonymousUser = "éditeur anonyme"; out.shareView = "URL de lecture seule"; out.shareEdit = "URL d'édition"; out.users = "Utilisateurs"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 61880205a..8bde3fb00 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -29,8 +29,8 @@ define(function () { out.readonly = 'Read only'; out.anonymous = "Anonymous"; out.yourself = "Yourself"; - out.anonymousUsers = "anonymous users"; - out.anonymousUser = "anonymous user"; + out.anonymousUsers = "anonymous editors"; + out.anonymousUser = "anonymous editor"; out.shareView = "Read-only URL"; out.shareEdit = "Edit URL"; out.users = "Users"; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 1866fb34a..2d65ff4cc 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -759,7 +759,6 @@ define([ case 'editshare': button = $(' diff --git a/www/poll/test/main.js b/www/poll/test/main.js index ce0a2f4d9..f56f8490a 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -19,6 +19,9 @@ define([ var HIDE_INTRODUCTION_TEXT = "hide_poll_text"; var defaultName; + var secret = Cryptpad.getSecrets(); + var readOnly = secret.keys && !secret.keys.editKeyStr; + var APP = window.APP = { Toolbar: Toolbar, Hyperjson: Hyperjson, @@ -108,19 +111,23 @@ define([ }; var updateTableButtons = function () { - unlockElements(); if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { $('#commit').show(); $('#commit').css('width', $($('.checkbox-cell')[0]).width()); - } else { - $('#commit').hide(); } + $('#create-user, #create-option').show(); var width = $('#table').outerWidth(); if (width) { $('#create-user').css('left', width + 30 + 'px'); } }; + var updateDisplayedTable = function () { + styleUncommittedColumn(); + unlockElements(); + updateTableButtons(); + }; + var unlockColumn = function (id, cb) { if (APP.editable.col.indexOf(id) === -1) { APP.editable.col.push(id); @@ -151,10 +158,11 @@ define([ var colsOrder = sortColumns(displayedObj.table.colsOrder, APP.userid); 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 calling updateTable twice removes the autofilled in values @@ -165,8 +173,7 @@ define([ window.setTimeout(function () { var displayedObj2 = mergeUncommitted(APP.proxy, APP.uncommitted); Render.updateTable(table, displayedObj2, conf); - updateTableButtons(); - styleUncommittedColumn(); + updateDisplayedTable(); }); }; @@ -286,19 +293,113 @@ define([ proxy.version = 1; }; + /* */ var publish = APP.publish = function (bool) { - if (!APP.ready || APP.proxy.published) { return; } - APP.proxy.published = true; - APP.$publish.hide(); + if (!APP.ready) { return; } + if (APP.proxy.published !== bool) { + APP.proxy.published = bool; + } + console.log(bool); + if (bool) { + 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) { $(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]; } + + 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); + } + + APP.proxy.info.userData = userData; + }; + + //var myData = {}; + var getLastName = function (cb) { + Cryptpad.getAttribute('username', function (err, userName) { + cb(err, userName || ''); + }); + }; + + 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) { + 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; + APP.$bar.find('.' + Toolbar.constants.title).find('span.title').text(data); + APP.$bar.find('.' + Toolbar.constants.title).find('input').val(data); + }); + }; + + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + APP.$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + var renameCb = function (err, title) { + if (err) { return; } + document.title = title; + APP.proxy.info.title = title; + }; + + var suggestName = function (fallback) { + return document.title || defaultName || ""; + }; + var copyObject = function (obj) { return JSON.parse(JSON.stringify(obj)); @@ -308,7 +409,7 @@ define([ //var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title'); TODO var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); - var ready = function (info, userid) { + var ready = function (info, userid, readOnly) { console.log("READY"); console.log('userid: %s', userid); @@ -316,8 +417,8 @@ define([ 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) { + if (!readOnly && proxy.table.colsOrder.indexOf(userid) === -1 && + uncommitted.table.colsOrder.indexOf(userid) === -1) { uncommitted.table.colsOrder.unshift(userid); } @@ -325,7 +426,7 @@ define([ var colsOrder = sortColumns(displayedObj.table.colsOrder, userid); - var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder)); + var $table = APP.$table = $(Render.asHTML(displayedObj, null, colsOrder, readOnly)); var $createRow = APP.$createRow = $('#create-option').click(function () { // console.error("BUTTON CLICKED! LOL"); @@ -359,16 +460,15 @@ define([ // Description $description.on('change keyup', function () { - var val = $item.val(); + var val = $description.val(); proxy.info.description = val; }); if (typeof(proxy.info.description) !== 'undefined') { - $description.val(proxy.info.descrption); + $description.val(proxy.info.description); } $('#tableContainer').prepend($table); - updateTableButtons(); - styleUncommittedColumn(); + updateDisplayedTable(); $table .click(handleClick) @@ -378,6 +478,8 @@ define([ .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]; @@ -387,7 +489,7 @@ define([ var after = TextPatcher.transformCursor(el[attr], op); return after; }); - $target.val(n); + $description.val(n); if (op) { el.selectionStart = selects[0]; el.selectionEnd = selects[1]; @@ -399,76 +501,84 @@ define([ .on('change', ['table'], change) .on('remove', [], change); - if (!proxy.published) { - var $publish = APP.$publish = $('#publish') - .show() - .click(function () { - publish(true); - }); - } + // #publish button is removed in readonly + var $publish = APP.$publish = $('#publish') + .click(function () { + publish(true); + }); - APP.ready = true; - }; + addToUserData(APP.proxy.info.userData); - var secret = Cryptpad.getSecrets(); + getLastName(function (err, lastName) { + APP.ready = true; - - 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; - APP.$bar.find('.' + Toolbar.constants.title).find('span.title').text(data); - APP.$bar.find('.' + Toolbar.constants.title).find('input').val(data); - }); - }; - - var updateDefaultTitle = function (defaultTitle) { - defaultName = defaultTitle; - APP.$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); - }; - var renameCb = function (err, title) { - if (err) { return; } - document.title = title; - APP.proxy.info.title = title; - }; + if (!proxy.published) { + $('#publish').show(); // Show the publish button + publish(false); + } else { + publish(true); + } - var suggestName = function (fallback) { - return document.title || defaultName || ""; - }; + // 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 realtime = APP.realtime = info.realtime; + var myID = APP.myID = info.myID; + + var editHash; + var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys); - var editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); + if (!readOnly) { + editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); + } APP.patchText = TextPatcher.create({ realtime: realtime, logging: true, }); - var userList = info.userList; + userList = APP.userList = info.userList; var config = { - userData: {}, - readOnly: false, + userData: userData, + readOnly: readOnly, title: { onRename: renameCb, defaultName: defaultName, suggestName: suggestName }, + ifrw: window, common: Cryptpad }; 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 */ var forgetCb = function (err, title) { @@ -478,7 +588,19 @@ define([ var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); $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) { if (err) { @@ -498,6 +620,7 @@ define([ var config = { websocketURL: Cryptpad.getWebsocketURL(), channel: secret.channel, + readOnly: readOnly, data: {}, // our public key validateKey: secret.keys.validateKey || undefined, @@ -507,6 +630,10 @@ define([ // don't initialize until the store is ready. Cryptpad.ready(function () { + if (readOnly) { + $('#commit, #create-user, #create-option, #publish').remove(); + } + var parsedHash = Cryptpad.parsePadUrl(window.location.href); defaultName = Cryptpad.getDefaultName(parsedHash); var rt = window.rt = APP.rt = Listmap.create(config); @@ -519,7 +646,7 @@ define([ if (userid === null) { userid = Render.coluid(); } APP.userid = userid; Cryptpad.setPadAttribute('userid', userid, function (e) { - ready(info, userid); + ready(info, userid, readOnly); }); }); }) diff --git a/www/poll/test/render.js b/www/poll/test/render.js index a817bc19f..8f8f5b7ad 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -10,6 +10,7 @@ define([ info: { title: '', description: '', + userData: {} }, table: { /* TODO @@ -187,7 +188,7 @@ by maintaining indexes in rowsOrder and colsOrder it returns an array of arrays containing the relevant data for each 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') { throw new Error('expected realtime-proxy object'); } @@ -224,6 +225,9 @@ by maintaining indexes in rowsOrder and colsOrder type: 'checkbox', autocomplete: 'nope', }; + if (readOnly) { + result.disabled = "disabled"; + } if (val) { result.checked = true; } 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.type === 'text') { var removeElement = makeRemoveElement(cell['data-rt-id']); var editElement = makeEditElement(cell['data-rt-id']); - return ['TD', {}, [ - ['INPUT', cell, []], - removeElement, - editElement - ]]; + var elements = [['INPUT', cell, []]]; + if (!readOnly) { + elements.push(removeElement); + elements.push(editElement); + } + return ['TD', {}, elements]; } 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') { + 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', {}, [ - ['DIV', {class: 'text-cell'}, [ - ['INPUT', cell, []], - makeRemoveElement(cell['data-rt-id']), - makeEditElement(cell['data-rt-id']) - ]] + ['DIV', {class: 'text-cell'}, elements] ]]; } @@ -302,19 +310,25 @@ by maintaining indexes in rowsOrder and colsOrder return ['TD', cell, []]; }; - var makeBodyRow = Render.makeBodyRow = function (row) { - return ['TR', {}, row.map(makeBodyCell)]; + var makeBodyRow = Render.makeBodyRow = function (row, readOnly) { + 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; } - var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(makeHeadingCell)] ]]; - var body = ['TBODY', {}, matrix.slice(1).map(makeBodyRow)]; + var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(function (cell) { + return makeHeadingCell(cell, readOnly); + })] ]]; + var body = ['TBODY', {}, matrix.slice(1).map(function (row) { + return makeBodyRow(row, readOnly); + })]; return ['TABLE', {id:'table'}, [head, body]]; }; - var asHTML = Render.asHTML = function (obj, rows, cols) { - return Hyperjson.toDOM(toHyperjson(cellMatrix(obj, rows, cols))); + var asHTML = Render.asHTML = function (obj, rows, cols, readOnly) { + return Hyperjson.toDOM(toHyperjson(cellMatrix(obj, rows, cols, readOnly), readOnly)); }; var diffIsInput = Render.diffIsInput = function (info) { @@ -390,9 +404,10 @@ by maintaining indexes in rowsOrder and colsOrder var rows = conf ? conf.rows : 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!"); } From 6dff82ede2cb0d0e020ac14fb5236b3222510ac2 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 5 Dec 2016 18:54:46 +0100 Subject: [PATCH 11/14] Improve UI, scrollbar in the table, publish/admin buttons --- customize.dist/main.css | 14 +++++++++- customize.dist/src/cryptpad.less | 12 ++++++++- customize.dist/src/toolbar.less | 2 +- customize.dist/toolbar.css | 2 +- www/common/toolbar.js | 4 +-- www/poll/test/index.html | 29 ++++++++++---------- www/poll/test/main.js | 46 +++++++++++++++++++++++++++----- www/poll/test/render.js | 19 ++++++++++--- 8 files changed, 98 insertions(+), 30 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index 32e538c68..f34dacb58 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -328,6 +328,13 @@ form.realtime > textarea { } form.realtime table { border-collapse: collapse; + width: calc(99%); +} +form.realtime table tr td:first-child { + position: absolute; + left: 29px; + top: auto; + width: 400px; } form.realtime table tr td { padding: 0px; @@ -337,7 +344,7 @@ form.realtime table tr td div.text-cell { padding: 0px; margin: 0px; height: 100%; - width: 500px; + width: 400px; } form.realtime table tr td div.text-cell input { width: 80%; @@ -354,6 +361,7 @@ form.realtime table tr td.checkbox-cell { margin: 0px; padding: 0px; height: 100%; + min-width: 150px; } form.realtime table tr td.checkbox-cell div.checkbox-contain { display: inline-block; @@ -423,7 +431,11 @@ form.realtime table thead tr th .remove { cursor: pointer; font-size: 20px; } +form.realtime table tfoot tr { + border: none; +} form.realtime table tfoot tr td { + border: none; text-align: center; } form.realtime table tfoot tr td .save { diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index e123f8722..a54ac78f6 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -375,7 +375,14 @@ form.realtime { table { border-collapse: collapse; + width: calc(100% - 1px); tr { + td:first-child { + position:absolute; + left: 29px; + top: auto; + width: 400px; + } td { padding: 0px; margin: 0px; @@ -385,7 +392,7 @@ form.realtime { margin: 0px; height: 100%; - width: 500px; + width: 400px; input { width: 80%; @@ -404,6 +411,7 @@ form.realtime { margin: 0px; padding: 0px; height: 100%; + min-width: 150px; div.checkbox-contain { display: inline-block; @@ -502,7 +510,9 @@ form.realtime { } tfoot { tr { + border: none; td { + border: none; text-align: center; .save { padding: 15px; diff --git a/customize.dist/src/toolbar.less b/customize.dist/src/toolbar.less index d8f7b6a6c..c420bdae1 100644 --- a/customize.dist/src/toolbar.less +++ b/customize.dist/src/toolbar.less @@ -271,7 +271,7 @@ margin: 2px 4px 2px 0px; } .cryptpad-userbuttons-container { - display: none; + /*display: none;*/ } } .cryptpad-toolbar-rightside { diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index cfde957a3..02eeff7e7 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -279,7 +279,7 @@ margin: 2px 4px 2px 0px; } .cryptpad-toolbar-leftside .cryptpad-userbuttons-container { - display: none; + /*display: none;*/ } .cryptpad-toolbar-rightside { text-align: right; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 52d849866..0a5320c10 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -202,14 +202,14 @@ define([ var updateUserList = function (myUserName, userlistElement, userList, userData, readOnly, $stateElement, $userAdminElement) { var meIdx = userList.indexOf(myUserName); if (meIdx === -1) { + console.log('nok'); $stateElement.text(Messages.synchronizing); return; } $stateElement.text(''); - // Make sure the elements are displayed var $userButtons = $(userlistElement).find("#userButtons"); - $userButtons.show(); + $userButtons.attr('display', 'inline'); var numberOfUsers = userList.length; diff --git a/www/poll/test/index.html b/www/poll/test/index.html index 67ebaa089..6fef7493d 100644 --- a/www/poll/test/index.html +++ b/www/poll/test/index.html @@ -64,25 +64,24 @@ #publish { display: none; } - #commit { - position: absolute; - left: 532px; - bottom: 0px; - } #create-user { position: absolute; - left: 0px; - top: 31px; + display: inline-block; + /*left: 0px; + top: 31px;*/ width: 50px; overflow: hidden; } #create-option { - position: absolute; - bottom: 0px; - left: 249px; width: 50px; } - + #tableScroll { + overflow-x: auto; + margin-left: 400px; + max-width: 70%; + width: auto; + display: inline-block; + } @@ -98,14 +97,16 @@ +

-

- +

+
+ -

+
diff --git a/www/poll/test/main.js b/www/poll/test/main.js index f56f8490a..6d8b468a2 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -90,6 +90,7 @@ define([ // Enable the checkboxes for the user's column (committed or not) $('input[disabled="disabled"][data-rt-id^="' + id + '"]').removeAttr('disabled'); $('input[type="checkbox"][data-rt-id^="' + id + '"]').addClass('enabled'); + $('[data-rt-id="' + id + '"] ~ .edit').css('visibility', 'hidden'); if (isOwnColumnCommitted()) { return; } $('[data-rt-id^="' + id + '"]').closest('td').addClass("uncommitted"); @@ -115,10 +116,16 @@ define([ $('#commit').show(); $('#commit').css('width', $($('.checkbox-cell')[0]).width()); } - $('#create-user, #create-option').show(); + + var $createOption = APP.$table.find('tfoot tr td:first-child'); + var $commitCell = APP.$table.find('tfoot tr td:nth-child(2)'); + $createOption.append(APP.$createRow); + $commitCell.append(APP.$commit); + $('#create-user, #create-option').css('display', 'inline-block'); + if (!APP.proxy || !APP.proxy.table.rowsOrder || APP.proxy.table.rowsOrder.length === 0) { $('#create-user').hide(); } var width = $('#table').outerWidth(); if (width) { - $('#create-user').css('left', width + 30 + 'px'); + //$('#create-user').css('left', width + 30 + 'px'); } }; @@ -252,18 +259,38 @@ define([ } }; + var hideInputs = function (e) { + if ($(e.target).is('[type="text"]')) { + return; + } + var $cells = APP.$table.find('thead td:not(.uncommitted), tbody td'); + $cells.find('[type="text"][data-rt-id!="' + APP.userid + '"]').attr('disabled', true); + $cells.find('[data-rt-id!="' + APP.userid + '"] ~ .edit').css('visibility', 'visible'); + APP.editable.col = [APP.userid]; + APP.editable.row = []; + }; + + $(window).click(hideInputs); + var handleClick = function (e, isKeyup) { + e.stopPropagation(); + if (!APP.ready) { return; } var target = e && e.target; if (isKeyup) { console.log("Keyup!"); + return; } if (!target) { return void console.log("NO TARGET"); } var nodeName = target && target.nodeName; + if (!$(target).parents('#table tbody').length) { + hideInputs(e); + } + switch (nodeName) { case 'INPUT': handleInput(target); @@ -302,13 +329,14 @@ define([ if (APP.proxy.published !== bool) { APP.proxy.published = bool; } - console.log(bool); if (bool) { APP.$publish.hide(); + APP.$admin.show(); $('#create-option').hide(); $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').hide(); } else { APP.$publish.show(); + APP.$admin.hide(); $('#create-option').show(); $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').show(); } @@ -428,7 +456,7 @@ define([ 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(); @@ -447,6 +475,7 @@ define([ APP.uncommitted = {}; prepareProxy(APP.uncommitted, copyObject(Render.Example)); mergeUncommitted(proxy, uncommittedCopy, true); + APP.$commit.hide(); change(); }); @@ -467,7 +496,7 @@ define([ $description.val(proxy.info.description); } - $('#tableContainer').prepend($table); + $('#tableScroll').prepend($table); updateDisplayedTable(); $table @@ -507,13 +536,18 @@ define([ publish(true); }); + // #publish button is removed in readonly + var $admin = APP.$admin = $('#admin') + .click(function () { + publish(false); + }); + 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); diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 8f8f5b7ad..0b9fe790e 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -195,6 +195,7 @@ by maintaining indexes in rowsOrder and colsOrder var cells = getCells(obj); rows = rows || getRowIds(obj); + rows.push(''); cols = cols || getColIds(obj); return [null].concat(rows).map(function (row, i) { @@ -210,6 +211,13 @@ by maintaining indexes in rowsOrder and colsOrder return result; })); } + if (i === rows.length) { + return [null].concat(cols.map(function (col) { + return { + 'class': 'lastRow', + }; + })); + } return [{ 'data-rt-id': row, @@ -291,7 +299,7 @@ by maintaining indexes in rowsOrder and colsOrder }; var makeBodyCell = Render.makeBodyCell = function (cell, readOnly) { - if (cell.type === 'text') { + if (cell && cell.type === 'text') { var removeElement = makeRemoveElement(cell['data-rt-id']); var editElement = makeEditElement(cell['data-rt-id']); var elements = [['INPUT', cell, []]]; @@ -304,7 +312,7 @@ by maintaining indexes in rowsOrder and colsOrder ]]; } - if (cell.type === 'checkbox') { + if (cell && cell.type === 'checkbox') { return makeCheckbox(cell); } return ['TD', cell, []]; @@ -321,10 +329,13 @@ by maintaining indexes in rowsOrder and colsOrder var head = ['THEAD', {}, [ ['TR', {}, matrix[0].map(function (cell) { return makeHeadingCell(cell, readOnly); })] ]]; - var body = ['TBODY', {}, matrix.slice(1).map(function (row) { + var foot = ['TFOOT', {}, matrix.slice(-1).map(function (row) { + return makeBodyRow(row, readOnly); + })]; + var body = ['TBODY', {}, matrix.slice(1, -1).map(function (row) { return makeBodyRow(row, readOnly); })]; - return ['TABLE', {id:'table'}, [head, body]]; + return ['TABLE', {id:'table'}, [head, foot, body]]; }; var asHTML = Render.asHTML = function (obj, rows, cols, readOnly) { From 740b6e955e6748b8ee40b62d672049758b11668e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 6 Dec 2016 18:55:10 +0100 Subject: [PATCH 12/14] Improve UI, fix issues with the table --- customize.dist/main.css | 146 +++++++++++++++------ customize.dist/src/cryptpad.less | 62 +++++++-- customize.dist/src/variables.less | 1 + customize.dist/translations/messages.fr.js | 6 + customize.dist/translations/messages.js | 6 + www/poll/test/index.html | 31 +++-- www/poll/test/main.js | 68 +++++----- www/poll/test/render.js | 10 +- 8 files changed, 231 insertions(+), 99 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index f34dacb58..99b5eea7f 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -318,58 +318,68 @@ tbody td:last-child { color: #FF0073; cursor: pointer !important; } -form.realtime { +form.realtime, +div.realtime { padding: 0px; margin: 0px; } -form.realtime > textarea { +form.realtime > textarea, +div.realtime > textarea { width: 50%; height: 15vh; } -form.realtime table { +form.realtime table, +div.realtime table { border-collapse: collapse; - width: calc(99%); + width: calc(100% - 1px); } -form.realtime table tr td:first-child { +form.realtime table tr td:first-child, +div.realtime table tr td:first-child { position: absolute; left: 29px; top: auto; - width: 400px; + width: calc(30% - 50px); } -form.realtime table tr td { +form.realtime table tr td, +div.realtime table tr td { padding: 0px; margin: 0px; } -form.realtime table tr td div.text-cell { +form.realtime table tr td div.text-cell, +div.realtime table tr td div.text-cell { padding: 0px; margin: 0px; height: 100%; - width: 400px; } -form.realtime table tr td div.text-cell input { +form.realtime table tr td div.text-cell input, +div.realtime table tr td div.text-cell input { width: 80%; width: 90%; height: 100%; border: 0px; } -form.realtime table tr td div.text-cell input[disabled] { +form.realtime table tr td div.text-cell input[disabled], +div.realtime table tr td div.text-cell input[disabled] { background-color: transparent; color: #fafafa; font-weight: bold; } -form.realtime table tr td.checkbox-cell { +form.realtime table tr td.checkbox-cell, +div.realtime table tr td.checkbox-cell { margin: 0px; padding: 0px; height: 100%; min-width: 150px; } -form.realtime table tr td.checkbox-cell div.checkbox-contain { +form.realtime table tr td.checkbox-cell div.checkbox-contain, +div.realtime table tr td.checkbox-cell div.checkbox-contain { display: inline-block; height: 100%; width: 100%; position: relative; } -form.realtime table tr td.checkbox-cell div.checkbox-contain label { +form.realtime table tr td.checkbox-cell div.checkbox-contain label, +div.realtime table tr td.checkbox-cell div.checkbox-contain label { background-color: transparent; display: block; position: absolute; @@ -378,82 +388,136 @@ form.realtime table tr td.checkbox-cell div.checkbox-contain label { height: 100%; width: 100%; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable), +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) { display: none; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover { font-weight: bold; background-color: #FF0073; color: #302B28; display: block; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { height: 100%; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover:after { content: "✖"; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes { background-color: #46E981; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.yes:after { content: "✔"; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.uncommitted { background: #ddd; } -form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine { +form.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine, +div.realtime table tr td.checkbox-cell div.checkbox-contain input[type="checkbox"]:not(.editable) ~ .cover.mine { display: none; } -form.realtime table input[type="text"] { +form.realtime table input[type="text"], +div.realtime table input[type="text"] { height: 100%; - width: 70%; - border: 3px solid #302B28; + border: 1px solid #302B28; + width: 80%; +} +form.realtime table thead td, +div.realtime table thead td { + padding: 0px 5px; + background: #4c443f; + border-radius: 20px 20px 0 0; +} +form.realtime table thead td input[type="text"], +div.realtime table thead td input[type="text"] { + width: 100%; + box-sizing: border-box; +} +form.realtime table thead td input[type="text"][disabled], +div.realtime table thead td input[type="text"][disabled] { + color: white; + padding: 1px 5px; +} +form.realtime table tbody .text-cell, +div.realtime table tbody .text-cell { + background: #4c443f; +} +form.realtime table tbody .text-cell input[type="text"], +div.realtime table tbody .text-cell input[type="text"] { + width: calc(100% - 50px); +} +form.realtime table tbody .text-cell .edit, +div.realtime table tbody .text-cell .edit { + float: right; + margin: 0 10px 0 0; +} +form.realtime table tbody .text-cell .remove, +div.realtime table tbody .text-cell .remove { + float: left; + margin: 0 0 0 10px; } -form.realtime table .edit { +form.realtime table .edit, +div.realtime table .edit { color: #46E981; cursor: pointer; - width: 10%; - font-size: 20px; -} -form.realtime table .edit:after { - content: '✐'; + float: left; + margin-left: 10px; + /*&:after { content: '✐'; }*/ + /*&.editable { display: none; }*/ } -form.realtime table .edit.editable { - display: none; +form.realtime table .remove, +div.realtime table .remove { + float: right; + margin-right: 10px; } -form.realtime table thead tr th input[type="text"][disabled] { +form.realtime table thead tr th input[type="text"][disabled], +div.realtime table thead tr th input[type="text"][disabled] { background-color: transparent; color: #fafafa; font-weight: bold; } -form.realtime table thead tr th .remove { +form.realtime table thead tr th .remove, +div.realtime table thead tr th .remove { cursor: pointer; font-size: 20px; } -form.realtime table tfoot tr { +form.realtime table tfoot tr, +div.realtime table tfoot tr { border: none; } -form.realtime table tfoot tr td { +form.realtime table tfoot tr td, +div.realtime table tfoot tr td { border: none; text-align: center; } -form.realtime table tfoot tr td .save { +form.realtime table tfoot tr td .save, +div.realtime table tfoot tr td .save { padding: 15px; border-top-left-radius: 5px; border-top-right-radius: 5px; } form.realtime #adduser, -form.realtime #addoption { +div.realtime #adduser, +form.realtime #addoption, +div.realtime #addoption { color: #46E981; border: 1px solid #46E981; padding: 15px; cursor: pointer; } -form.realtime #adduser { +form.realtime #adduser, +div.realtime #adduser { border-top-left-radius: 5px; } -form.realtime #addoption { +form.realtime #addoption, +div.realtime #addoption { border-bottom-left-radius: 5px; } div.modal, diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index a54ac78f6..d0a783f3e 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -359,7 +359,7 @@ tbody { cursor: pointer !important; } -form.realtime { +form.realtime, div.realtime { > input { &[type="text"] { @@ -375,13 +375,13 @@ form.realtime { table { border-collapse: collapse; - width: calc(100% - 1px); + width: ~"calc(100% - 1px)"; tr { td:first-child { position:absolute; left: 29px; top: auto; - width: 400px; + width: ~"calc(30% - 50px)"; } td { padding: 0px; @@ -390,9 +390,7 @@ form.realtime { div.text-cell { padding: 0px; margin: 0px; - height: 100%; - - width: 400px; + height: 100%; input { width: 80%; @@ -473,17 +471,57 @@ form.realtime { input { &[type="text"] { height: 100%; - width: 70%; - border: 3px solid @base; + border: 1px solid @base; + width: 80%; + } + } + thead { + td { + padding: 0px 5px; + background: @less-light-base; + border-radius: 20px 20px 0 0; + input { + &[type="text"] { + width: 100%; + box-sizing: border-box; + &[disabled] { + color: white; + padding: 1px 5px; + } + } + } + } + } + + tbody { + .text-cell { + background: @less-light-base; + //border-radius: 20px 0 0 20px; + input[type="text"] { + width: ~"calc(100% - 50px)"; + } + .edit { + float:right; + margin: 0 10px 0 0; + } + .remove { + float: left; + margin: 0 0 0 10px; + } } } .edit { color: @cp-green; cursor: pointer; - width: 10%; - font-size: 20px; - &:after { content: '✐'; } - &.editable { display: none; } + float: left; + margin-left: 10px; + /*&:after { content: '✐'; }*/ + /*&.editable { display: none; }*/ + } + + .remove { + float: right; + margin-right: 10px } thead { diff --git a/customize.dist/src/variables.less b/customize.dist/src/variables.less index 14e6de373..c6d555219 100644 --- a/customize.dist/src/variables.less +++ b/customize.dist/src/variables.less @@ -1,5 +1,6 @@ @base: #302B28; @light-base: lighten(@base, 20%); +@less-light-base: lighten(@base, 10%); @fore: #fafafa; @cp-green: #46E981; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 493bd69c9..e8948cafc 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -129,6 +129,12 @@ define(function () { out.wizardTitle = "Utiliser l'assistant pour créer votre sondage"; out.wizardConfirm = "Êtes-vous vraiment prêt à ajouter ces options au sondage ?"; + out.poll_publish_button = "Publier"; + out.poll_admin_button = "Administrer"; + out.poll_create_user = "Ajouter un utilisateur"; + out.poll_create_option = "Ajouter une option"; + out.poll_commit = "Valider"; + out.poll_closeWizardButton = "Fermer l'assistant"; out.poll_closeWizardButtonTitle = "Fermer l'assistant"; out.poll_wizardComputeButton = "Générer les options"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 8bde3fb00..65acfb831 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -131,6 +131,12 @@ define(function () { out.wizardTitle = "Use the wizard to create your poll"; out.wizardConfirm = "Are you really ready to add these options to your poll?"; + out.poll_publish_button = "Publish"; + out.poll_admin_button = "Admin"; + out.poll_create_user = "Add a new user"; + out.poll_create_option = "Add a new option"; + out.poll_commit = "Commit"; + out.poll_closeWizardButton = "Close wizard"; out.poll_closeWizardButtonTitle = "Close wizard"; out.poll_wizardComputeButton = "Compute Options"; diff --git a/www/poll/test/index.html b/www/poll/test/index.html index 6fef7493d..77345e52b 100644 --- a/www/poll/test/index.html +++ b/www/poll/test/index.html @@ -55,7 +55,7 @@ #tableContainer { position: relative; padding: 29px; - padding-right: 82px; + padding-right: 79px; } #tableContainer button { height: 2rem; @@ -67,8 +67,8 @@ #create-user { position: absolute; display: inline-block; - /*left: 0px; - top: 31px;*/ + /*left: 0px;*/ + top: 55px; width: 50px; overflow: hidden; } @@ -77,11 +77,20 @@ } #tableScroll { overflow-x: auto; - margin-left: 400px; + margin-left: calc(30% - 50px + 29px); max-width: 70%; width: auto; display: inline-block; } + #description[disabled] { + resize: none; + } + #description { + padding: 5px; + } + #commit { + width: 100%; + } @@ -96,17 +105,17 @@

- - + + -
+


- - - + + +
- +
diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 6d8b468a2..3e9b3d5ee 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -96,7 +96,7 @@ define([ $('[data-rt-id^="' + id + '"]').closest('td').addClass("uncommitted"); $('td.uncommitted .remove, td.uncommitted .edit').css('visibility', 'hidden'); $('td.uncommitted .cover').addClass("uncommitted"); - $('.uncommitted input[type="text"]').attr("placeholder", "New column here"); //TODO + $('.uncommitted input[type="text"]').attr("placeholder", Messages.poll_userPlaceholder); }; var unlockElements = function () { @@ -114,7 +114,6 @@ define([ var updateTableButtons = function () { if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { $('#commit').show(); - $('#commit').css('width', $($('.checkbox-cell')[0]).width()); } var $createOption = APP.$table.find('tfoot tr td:first-child'); @@ -129,10 +128,25 @@ define([ } }; + var setTablePublished = function (bool) { + if (bool) { + if (APP.$publish) { APP.$publish.hide(); } + if (APP.$admin) { APP.$admin.show(); } + $('#create-option').hide(); + $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').hide(); + } else { + if (APP.$publish) { APP.$publish.show(); } + if (APP.$admin) { APP.$admin.hide(); } + $('#create-option').show(); + $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').show(); + } + }; + var updateDisplayedTable = function () { styleUncommittedColumn(); unlockElements(); updateTableButtons(); + setTablePublished(APP.proxy.published); }; var unlockColumn = function (id, cb) { @@ -211,7 +225,7 @@ define([ break; case 'checkbox': console.log("checkbox[tr-id='%s'] %s", id, input.checked); - if ($(input).hasClass('enabled')) { + if (APP.editable.col.indexOf(x) >= 0 || x === APP.userid) { Render.setValue(object, id, input.checked); change(); } else { @@ -329,18 +343,7 @@ define([ if (APP.proxy.published !== bool) { APP.proxy.published = bool; } - if (bool) { - APP.$publish.hide(); - APP.$admin.show(); - $('#create-option').hide(); - $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').hide(); - } else { - APP.$publish.show(); - APP.$admin.hide(); - $('#create-option').show(); - $('.remove[data-rt-id^="y"], .edit[data-rt-id^="y"]').show(); - } - + setTablePublished(bool); ['textarea'].forEach(function (sel) { $(sel).attr('disabled', bool); }); @@ -456,7 +459,6 @@ define([ 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(); @@ -479,6 +481,18 @@ define([ change(); }); + // #publish button is removed in readonly + var $publish = APP.$publish = $('#publish') + .click(function () { + publish(true); + }); + + // #publish button is removed in readonly + var $admin = APP.$admin = $('#admin') + .click(function () { + publish(false); + }); + // Title if (APP.proxy.info.defaultTitle) { updateDefaultTitle(APP.proxy.info.defaultTitle); @@ -488,10 +502,16 @@ define([ updateTitle(APP.proxy.info.title || defaultName); // Description + var resize = function () { + var lineCount = $description.val().split('\n').length; + $description.css('height', lineCount + 'rem'); + }; $description.on('change keyup', function () { var val = $description.val(); proxy.info.description = val; + resize(); }); + resize(); if (typeof(proxy.info.description) !== 'undefined') { $description.val(proxy.info.description); } @@ -530,18 +550,6 @@ define([ .on('change', ['table'], change) .on('remove', [], change); - // #publish button is removed in readonly - var $publish = APP.$publish = $('#publish') - .click(function () { - publish(true); - }); - - // #publish button is removed in readonly - var $admin = APP.$admin = $('#admin') - .click(function () { - publish(false); - }); - addToUserData(APP.proxy.info.userData); getLastName(function (err, lastName) { @@ -686,10 +694,10 @@ define([ }) .on('disconnect', disconnect); - Cryptpad.getPadAttribute(HIDE_INTRODUCTION_TEXT, function (e, value) { + Cryptpad.getAttribute(HIDE_INTRODUCTION_TEXT, function (e, value) { if (e) { console.error(e); } if (value === null) { - Cryptpad.setPadAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { + Cryptpad.setAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { if (e) { console.error(e) } }); } else if (value === "1") { diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 0b9fe790e..826a867a9 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -205,7 +205,7 @@ by maintaining indexes in rowsOrder and colsOrder 'data-rt-id': col, type: 'text', value: getColumnValue(obj, col) || "", - placeholder: 'User', //TODO translate + placeholder: Cryptpad.Messages.poll_userPlaceholder, disabled: 'disabled' }; return result; @@ -223,7 +223,7 @@ by maintaining indexes in rowsOrder and colsOrder 'data-rt-id': row, value: getRowValue(obj, row), type: 'text', - placeholder: 'Option', //TODO translate + placeholder: Cryptpad.Messages.poll_optionPlaceholder, disabled: 'disabled' }].concat(cols.map(function (col) { var id = [col, rows[i-1]].join('_'); @@ -253,7 +253,7 @@ by maintaining indexes in rowsOrder and colsOrder return ['SPAN', { 'data-rt-id': id, class: 'edit', - }, ['']]; + }, ['✐']]; }; var makeHeadingCell = Render.makeHeadingCell = function (cell, readOnly) { @@ -263,8 +263,8 @@ by maintaining indexes in rowsOrder and colsOrder var editElement = makeEditElement(cell['data-rt-id']); var elements = [['INPUT', cell, []]]; if (!readOnly) { - elements.push(removeElement); - elements.push(editElement); + elements.unshift(removeElement); + elements.unshift(editElement); } return ['TD', {}, elements]; } From f26cdb1a216ff2264047f03a10831be3f1633cd8 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 7 Dec 2016 11:44:09 +0100 Subject: [PATCH 13/14] Fix UI issues, unclickable user column, add confirm dialog --- customize.dist/main.css | 1 + customize.dist/src/cryptpad.less | 1 + www/poll/test/main.js | 24 ++++++++++++++++-------- www/poll/test/render.js | 15 +++++++++++++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index 99b5eea7f..62208fa1b 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -434,6 +434,7 @@ div.realtime table thead td { padding: 0px 5px; background: #4c443f; border-radius: 20px 20px 0 0; + text-align: center; } form.realtime table thead td input[type="text"], div.realtime table thead td input[type="text"] { diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index d0a783f3e..d681e3c50 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -480,6 +480,7 @@ form.realtime, div.realtime { padding: 0px 5px; background: @less-light-base; border-radius: 20px 20px 0 0; + text-align: center; input { &[type="text"] { width: 100%; diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 3e9b3d5ee..63df28926 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -91,6 +91,7 @@ define([ $('input[disabled="disabled"][data-rt-id^="' + id + '"]').removeAttr('disabled'); $('input[type="checkbox"][data-rt-id^="' + id + '"]').addClass('enabled'); $('[data-rt-id="' + id + '"] ~ .edit').css('visibility', 'hidden'); + $('.lock[data-rt-id="' + id + '"]').html('🔓'); if (isOwnColumnCommitted()) { return; } $('[data-rt-id^="' + id + '"]').closest('td').addClass("uncommitted"); @@ -108,11 +109,12 @@ define([ $('input[disabled="disabled"][data-rt-id^="' + id + '"]').removeAttr('disabled'); $('input[type="checkbox"][data-rt-id^="' + id + '"]').addClass('enabled'); $('span.edit[data-rt-id="' + id + '"]').css('visibility', 'hidden'); + $('.lock[data-rt-id="' + id + '"]').html('🔓'); }); }; var updateTableButtons = function () { - if ($('.checkbox-cell').length && !isOwnColumnCommitted()) { + if (!isOwnColumnCommitted()) { $('#commit').show(); } @@ -246,8 +248,11 @@ define([ var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; if (isRemove) { - Render.removeRow(APP.proxy, id, function () { - change(); + Cryptpad.confirm(Messages.poll_removeOption, function (res) { + if (!res) { return; } + Render.removeRow(APP.proxy, id, function () { + change(); + }); }); } else if (isEdit) { unlockRow(id, function () { @@ -258,8 +263,11 @@ define([ var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; if (isRemove) { - Render.removeColumn(APP.proxy, id, function () { - change(); + Cryptpad.confirm(Messages.poll_removeUser, function (res) { + if (!res) { return; } + Render.removeColumn(APP.proxy, id, function () { + change(); + }); }); } else if (isEdit) { unlockColumn(id, function () { @@ -277,9 +285,10 @@ define([ if ($(e.target).is('[type="text"]')) { return; } + $('.lock[data-rt-id!="' + APP.userid + '"]').html('🔒 '); var $cells = APP.$table.find('thead td:not(.uncommitted), tbody td'); $cells.find('[type="text"][data-rt-id!="' + APP.userid + '"]').attr('disabled', true); - $cells.find('[data-rt-id!="' + APP.userid + '"] ~ .edit').css('visibility', 'visible'); + $('.edit[data-rt-id!="' + APP.userid + '"]').css('visibility', 'visible'); APP.editable.col = [APP.userid]; APP.editable.row = []; }; @@ -294,14 +303,13 @@ define([ if (isKeyup) { console.log("Keyup!"); - return; } if (!target) { return void console.log("NO TARGET"); } var nodeName = target && target.nodeName; - if (!$(target).parents('#table tbody').length) { + if (!$(target).parents('#table tbody').length || $(target).hasClass('edit')) { hideInputs(e); } diff --git a/www/poll/test/render.js b/www/poll/test/render.js index 826a867a9..b0b41369d 100644 --- a/www/poll/test/render.js +++ b/www/poll/test/render.js @@ -111,6 +111,12 @@ by maintaining indexes in rowsOrder and colsOrder .error(new Error("Attempted to remove id which does not exist")); } + Object.keys(obj.table.cells).forEach(function (key) { + if (key.indexOf(id) === 0) { + delete obj.table.cells[key]; + } + }); + order.splice(idx, 1); if (parent[id]) { delete parent[id]; } if (typeof(cb) === 'function') { @@ -256,14 +262,23 @@ by maintaining indexes in rowsOrder and colsOrder }, ['✐']]; }; + var makeLockElement = Render.makeLockElement = function (id) { + return ['SPAN', { + 'data-rt-id': id, + class: 'lock', + }, ['🔒']]; + }; + var makeHeadingCell = Render.makeHeadingCell = function (cell, readOnly) { if (!cell) { return ['TD', {}, []]; } if (cell.type === 'text') { var removeElement = makeRemoveElement(cell['data-rt-id']); var editElement = makeEditElement(cell['data-rt-id']); + var lockElement = makeLockElement(cell['data-rt-id']); var elements = [['INPUT', cell, []]]; if (!readOnly) { elements.unshift(removeElement); + elements.unshift(lockElement); elements.unshift(editElement); } return ['TD', {}, elements]; From ddc99cecb109ef39c28a82184568d97b79c6751b Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 7 Dec 2016 12:22:21 +0100 Subject: [PATCH 14/14] Fix lint errors --- customize.dist/main.css | 1 + customize.dist/src/cryptpad.less | 1 + www/poll/test/main.js | 24 +++++++++++------------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/customize.dist/main.css b/customize.dist/main.css index 62208fa1b..1d3e3c347 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -445,6 +445,7 @@ form.realtime table thead td input[type="text"][disabled], div.realtime table thead td input[type="text"][disabled] { color: white; padding: 1px 5px; + border: none; } form.realtime table tbody .text-cell, div.realtime table tbody .text-cell { diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index d681e3c50..494e7c369 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -488,6 +488,7 @@ form.realtime, div.realtime { &[disabled] { color: white; padding: 1px 5px; + border: none; } } } diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 63df28926..8dbc5c683 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -68,9 +68,9 @@ define([ newObj.table.cols[k] = uncommitted.table.cols[k]; } } - for (var k in uncommitted.table.cells) { - if (!newObj.table.cells[k]) { - newObj.table.cells[k] = uncommitted.table.cells[k]; + for (var l in uncommitted.table.cells) { + if (!newObj.table.cells[l]) { + newObj.table.cells[l] = uncommitted.table.cells[l]; } } return newObj; @@ -244,9 +244,9 @@ define([ var handleSpan = function (span) { var id = span.getAttribute('data-rt-id'); var type = Render.typeofId(id); + var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; + var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; if (type === 'row') { - var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; - var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; if (isRemove) { Cryptpad.confirm(Messages.poll_removeOption, function (res) { if (!res) { return; } @@ -260,8 +260,6 @@ define([ }); } } else if (type === 'col') { - var isRemove = span.className && span.className.split(' ').indexOf('remove') !== -1; - var isEdit = span.className && span.className.split(' ').indexOf('edit') !== -1; if (isRemove) { Cryptpad.confirm(Messages.poll_removeUser, function (res) { if (!res) { return; } @@ -390,9 +388,9 @@ define([ if(myUserNameTemp.length > 32) { myUserNameTemp = myUserNameTemp.substr(0, 32); } - myUserName = myUserNameTemp; + var myUserName = myUserNameTemp; var myID = APP.myID; - var myData = {} + var myData = {}; myData[myID] = { name: myUserName }; @@ -505,7 +503,7 @@ define([ if (APP.proxy.info.defaultTitle) { updateDefaultTitle(APP.proxy.info.defaultTitle); } else { - APP.proxy.info.defaultTitle = defaultName + APP.proxy.info.defaultTitle = defaultName; } updateTitle(APP.proxy.info.title || defaultName); @@ -613,7 +611,7 @@ define([ ifrw: window, common: Cryptpad }; - toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config); + var toolbar = info.realtime.toolbar = Toolbar.create(APP.$bar, info.myID, info.realtime, info.getLag, userList, config); var $bar = APP.$bar; var $rightside = $bar.find('.' + Toolbar.constants.rightside); @@ -681,7 +679,7 @@ define([ // don't initialize until the store is ready. Cryptpad.ready(function () { if (readOnly) { - $('#commit, #create-user, #create-option, #publish').remove(); + $('#commit, #create-user, #create-option, #publish, #admin').remove(); } var parsedHash = Cryptpad.parsePadUrl(window.location.href); @@ -706,7 +704,7 @@ define([ if (e) { console.error(e); } if (value === null) { Cryptpad.setAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { - if (e) { console.error(e) } + if (e) { console.error(e); } }); } else if (value === "1") { $('#howItWorks').hide();