From a06d29863dd1b07d20348b66064266ddbe492ee7 Mon Sep 17 00:00:00 2001 From: or-else Date: Sat, 23 Sep 2017 13:26:58 -0700 Subject: [PATCH] add UI elements for attaching images and other docs --- README.md | 6 +++--- css/base.css | 14 +++++++++++++- drafty.js | 52 ++++++++++++++++++++++++++++++++++++++++++---------- index.html | 38 ++++++++++++++++++++++++++++++++------ 4 files changed, 90 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 145913f7..64f8e2ff 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ Background pattern from http://subtlepatterns.com/, commercial and non-commercia ## Missing functionality -* Cannot send images or other media. +* Previews not generated for videos, audio or other docs. * Cannot delete messages. -* No indication of chat status (muted, blocked, etc.). -* Browser push notifications are missing. +* No indication of some chat statuses (muted, blocked, etc.). +* Browser push notifications are not implemented. * No end-to-end encryption. * Editing chat permissions is incomplete. diff --git a/css/base.css b/css/base.css index 74203da2..3e36d88d 100644 --- a/css/base.css +++ b/css/base.css @@ -900,7 +900,7 @@ table.permission-editor td.checkbox { display: flex; align-items: center; flex: none; - padding: 0.4rem; + padding: 0.4rem 0.4rem 0.4rem 0.6rem; background-color: #eceff1; box-shadow: 0 -1px rgba(0,0,0,0.1); /* Faint shadow above panel */ z-index: 2; @@ -911,6 +911,18 @@ table.permission-editor td.checkbox { overflow: hidden; } +#send-message-panel .material-icons { + min-width: 1.5rem; +} + +#send-message-panel .material-icons.secondary, .material-icons.disabled { + color: #999!important; +} + +#send-message-panel .material-icons.secondary:hover { + color: #2196f3!important; +} + /* A static panel shown when no topic is selected */ #dummy-view { width: 100%; diff --git a/drafty.js b/drafty.js index a1112754..fb70ec4c 100644 --- a/drafty.js +++ b/drafty.js @@ -89,7 +89,7 @@ Sample JSON representation of the text above: LN: { name: 'a', isVoid: false }, MN: { name: 'a', isVoid: false }, HT: { name: 'a', isVoid: false }, - XT: { name: '', isVoid: true } + IM: { name: 'img', isVoid: true } }; // Convert base64-encoded string into Blob. @@ -127,10 +127,27 @@ Sample JSON representation of the text above: close: function(data) { return ''; }, props: function(data) { return { name: data.val }; }, }, - XT: { - open: function() { return ''; }, - close: function(data) { return ''}, - props: function(data) { return { src: base64toObjectUrl(data.val, data.mime) }; }, + IM: { + open: function(data) { + var blobUrl = base64toObjectUrl(data.val, data.mime); + var res = (data.name ? '' : '') + + ''; + console.log("open: " + res); + return res; + }, + close: function(data) { + return (data.name ? '' : ''); + }, + props: function(data) { + return { + src: base64toObjectUrl(data.val, data.mime), + width: data.width, + height: data.height, + download: data.name + }; + }, } }; @@ -462,17 +479,30 @@ Sample JSON representation of the text above: return result; }, - addZeroLengthMedia: function(content, at, tag, mime, previewBits, external) { + /** + * Add inline image to drafty content + * + * @param {Drafty} content object to add image to + * @param {integer} at index where the object is inserted + * @param {string} mime mime-type of the image, e.g. "image/png" + * @param {string} bits base64-encoded image content + * @param {integer} width width of the image + * @param {integer} height height of the image + * @param {string} fname file name suggestion for downloading the image. + */ + insertImage: function(content, at, mime, base64bits, width, height, fname) { content = content || {txt: ""}; content.ent = content.ent || []; content.fmt = content.fmt || []; var entity = { - tp: tag ? tag : "XT", + tp: "IM", data: { mime: mime, - val: previewBits, - ext: external + val: base64bits, + width: width, + height: height, + name: fname } }; var range = { @@ -514,8 +544,10 @@ Sample JSON representation of the text above: } if (DECORATORS[tp]) { - markup.push({idx: range.at, what: DECORATORS[tp].open(data)}); + // Because we later sort in descending order, closing markup must come first. + // Otherwise zero-length objects will not be represented correctly. markup.push({idx: range.at + range.len, what: DECORATORS[tp].close(data)}); + markup.push({idx: range.at, what: DECORATORS[tp].open(data)}); } } } diff --git a/index.html b/index.html index 1c9d37dc..08bf7a19 100644 --- a/index.html +++ b/index.html @@ -2691,7 +2691,10 @@ {this.state.writeOnly ?
no access to messages
: null} - + ); } else { @@ -2713,6 +2716,12 @@ // Make initial keypress time as if it happened 5001 milliseconds in the past. keypressTimestamp: new Date().getTime() - KEYPRESS_DELAY - 1 }; + }, + handleAttachImage: function() { + + }, + handleAttachFile: function() { + }, handleSend: function() { var message = this.state.message.trim(); @@ -2747,13 +2756,30 @@ this.setState(newState); }, render: function() { + var prompt = this.props.disabled ? "Publishing disabled" : "New message"; + var instance = this; return (
-