diff --git a/customize.dist/images/logo_white.png b/customize.dist/images/logo_white.png new file mode 100644 index 000000000..81928ffb1 Binary files /dev/null and b/customize.dist/images/logo_white.png differ diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 1d07bef96..89acf8e2f 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -263,7 +263,7 @@ define([ [ 'slide', '/slide/', Msg.main_slidePad, 'fa-file-powerpoint-o' ], [ 'poll.cp-more.cp-hidden', '/poll/', Msg.main_pollPad, 'fa-calendar' ], [ 'whiteboard.cp-more.cp-hidden', '/whiteboard/', Msg.main_whiteboardPad, 'fa-paint-brush' ], - [ 'recent.cp-more.cp-hidden', '/drive/', Msg.main_recentPads, 'fa-hdd-o' ] + [ 'recent.cp-more.cp-hidden', '/drive/', Msg.main_localPads, 'fa-hdd-o' ] ].map(function (x) { return h('a', [ { href: x[1] }, @@ -427,33 +427,43 @@ define([ display: 'block', } }, [ - h('button#clear', Msg.canvas_clear), ' ', - h('button#toggleDraw', Msg.canvas_disable), - h('button#delete', { + h('button#clear.btn.btn-danger', Msg.canvas_clear), ' ', + h('button#toggleDraw.btn.btn-secondary', Msg.canvas_disable), + h('button#delete.btn.btn-secondary', { style: { display: 'none', } - }), - h('input#width', { - type: 'range', - value: "5", - min: "1", - max: "100" - }), - h('label', { - 'for': 'width' - }, Msg.canvas_width), - h('input#opacity', { - type: 'range', - value: "1", - min: "0.1", - max: "1", - step: "0.1" - }), - h('label', { - 'for': 'width', - }), - h('span.selected') + }, Msg.canvas_delete), + h('div.range-group', [ + h('label', { + 'for': 'width' + }, Msg.canvas_width), + h('input#width', { + type: 'range', + value: "5", + min: "1", + max: "100" + }), + h('span#width-val', '5px') + ]), + h('div.range-group', [ + h('label', { + 'for': 'opacity', + }, Msg.canvas_opacity), + h('input#opacity', { + type: 'range', + value: "1", + min: "0.1", + max: "1", + step: "0.1" + }), + h('span#opacity-val', '100%') + ]), + h('span.selected', [ + h('img', { + title: Msg.canvas_currentBrush + }) + ]) ]), setHTML(h('div#colors'), ' '), loadingScreen(), @@ -480,16 +490,15 @@ define([ h('p', Msg.poll_p_encryption) ]), h('div.upper', [ - h('button#publish', { + h('button#publish.btn.btn-success', { style: { display: 'none' } }, Msg.poll_publish_button), - h('button#admin', { + h('button#admin.btn.btn-primary', { style: { display: 'none' }, title: Msg.poll_admin_button }, Msg.poll_admin_button), - h('button#help', { - title: Msg.poll_show_help_button, - style: { display: 'none' } + h('button#help.btn.btn-secondary', { + title: Msg.poll_show_help_button }, Msg.poll_show_help_button) ]), h('div.realtime', [ @@ -504,13 +513,13 @@ define([ ]), h('div#tableContainer', [ h('div#tableScroll'), - h('button#create-user', { + h('button#create-user.btn.btn-secondary', { title: Msg.poll_create_user }, h('span.fa.fa-plus')), - h('button#create-option', { + h('button#create-option.btn.btn-secondary', { title: Msg.poll_create_option }, h('span.fa.fa-plus')), - h('button#commit', { + h('button#commit.btn.btn-secondary', { title: Msg.poll_commit }, h('span.fa.fa-check')) ]) diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index e607ef7ff..138ba5817 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -3,6 +3,7 @@ @import "../less2/include/alertify.less"; @import "../less2/include/colortheme.less"; +@import "../less2/include/modal.less"; @import "./bar.less"; @import "./loading.less"; @import "./dropdown.less"; @@ -633,29 +634,29 @@ noscript { /* Upload status table */ #uploadStatusContainer { + .modal_base(); position: absolute; left: 10vw; right: 10vw; - bottom: 100px; - background-color: rgba(0,0,0,0.5); - color: white; - opacity: 0.7; + bottom: 10vh; + opacity: 0.9; box-sizing: border-box; - z-index:10000; + z-index: 10000; display: none; - font-family: @colortheme_font; #uploadStatus { width: 80vw; - border: 1px solid black; - border-collapse: collapse; tr:nth-child(1) { - background-color: #888; - border: 1px solid #999; - td { text-align: center; } + background-color: darken(@colortheme_modal-bg, 20%); + td { + text-align: center; + font-weight: bold; + padding: 0.25em; + } } + @upload_pad_h: 0.25em; + @upload_pad_v: 0.5em; + td { - border-left: 1px solid #BBB; - border-right: 1px solid #BBB; - padding: 0 10px; + padding: @upload_pad_h @upload_pad_v; } .upProgress { width: 200px; @@ -666,9 +667,10 @@ noscript { .progressContainer { position: absolute; width: 0px; - left: 5px; - top: 1px; bottom: 1px; + left: @upload_pad_v; + top: @upload_pad_h; bottom: @upload_pad_h; background-color: rgba(0,0,255,0.3); + z-index: -1; } .upCancel { text-align: center; } .fa.cancel { diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index 1a791bc04..a035f5bf0 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -39,14 +39,14 @@ box-shadow: @alertify_box-shadow; &, &.default { // FIXME - background: rgba(0, 0, 0, .8); + background: @colortheme_notification-log; } &.error { font-weight: bold; - background: @colortheme_cp-red; + background: @colortheme_notification-warn; } &.success { - background: rgba(0, 0, 0, .8); + background: @colortheme_notification-log; } } } @@ -114,8 +114,7 @@ text-align: left; padding: @alertify_padding-base; background: #fff; - // FIXME - box-shadow: 0 2px 4px -1px rgba(0,0,0,.14), 0 4px 5px 0 rgba(0,0,0,.098), 0 1px 10px 0 rgba(0,0,0,.084); + box-shadow: @alertify_box-shadow; } .msg { diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less index a1e02d9d4..a62800442 100644 --- a/customize.dist/src/less2/include/colortheme.less +++ b/customize.dist/src/less2/include/colortheme.less @@ -15,6 +15,8 @@ @colortheme_modal-bg: #222; @colortheme_modal-fg: #fff; +@colortheme_modal-link: #eee; +@colortheme_modal-link-visited: lighten(@colortheme_modal-link, 10%); @colortheme_modal-dim: rgba(0, 0, 0, 0.4); @colortheme_modal-padding: 12px; @colortheme_modal-shadow: 0 8px 32px 0 rgba(0,0,0,.4); @@ -24,6 +26,9 @@ @colortheme_alertify-red: #E55236; @colortheme_alertify-green: #77C825; +@colortheme_notification-log: rgba(0, 0, 0, 0.8); +@colortheme_notification-warn: rgba(205, 37, 50, 0.8); + // Apps @colortheme_pad-bg: #1c4fa0; diff --git a/customize.dist/src/less2/include/mediatag.less b/customize.dist/src/less2/include/mediatag.less new file mode 100644 index 000000000..704fd71bd --- /dev/null +++ b/customize.dist/src/less2/include/mediatag.less @@ -0,0 +1,18 @@ +.mediatag_base() { + media-tag { + min-height: 0; + flex: 1; + display: flex; + flex-flow: column; + text-align: center; + } + + media-tag img { + flex: 1; + max-height: 100% !important; + } + + media-tag iframe { + min-height: 100%; + } +} diff --git a/customize.dist/src/less2/include/modal.less b/customize.dist/src/less2/include/modal.less new file mode 100644 index 000000000..21cc69e97 --- /dev/null +++ b/customize.dist/src/less2/include/modal.less @@ -0,0 +1,17 @@ +@import (once) "./colortheme.less"; + +.modal_base() { + font-family: @colortheme_font; + + background-color: @colortheme_modal-bg; + color: @colortheme_modal-fg; + box-shadow: @colortheme_modal-shadow; + + a { + color: @colortheme_modal-link; + + &:visited { + color: @colortheme_modal-link-visited; + } + } +} diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index 900a4dd46..34b0b9f4a 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -291,7 +291,7 @@ define(function () { out.blog = "Blog"; out.initialState = [ - '

', + '

', 'Esto es CryptPad, el editor colaborativo en tiempo real Zero Knowledge. Todo está guardado cuando escribes.', '
', 'Comparte el enlace a este pad para editar con amigos o utiliza el botón  Compartir  para obtener un enlace sólo lectura que permite leer pero no escribir.', @@ -299,7 +299,7 @@ define(function () { '

', 'Vamos, empieza a escribir...', - '

', + '

', '

 

' ].join(''); diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 70814a2de..5278a8be8 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -566,7 +566,7 @@ define(function () { // Initial states out.initialState = [ - '

', + '

', 'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.', '
', 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton  Partager  pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.', @@ -574,7 +574,7 @@ define(function () { '

', '', 'Lancez-vous, commencez à taper...', - '

', + '

', '

 

' ].join(''); diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 5fb3a6ae1..ec7cac571 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -118,6 +118,10 @@ define(function () { out.shareButton = 'Share'; out.shareSuccess = 'Copied link to clipboard'; + out.userListButton = "User list"; + + out.userAccountButton = "Your account"; + out.newButton = 'New'; out.newButtonTitle = 'Create a new pad'; out.uploadButton = 'Upload files'; @@ -244,9 +248,11 @@ define(function () { out.canvas_enable = "Enable draw"; out.canvas_width = "Width"; out.canvas_opacity = "Opacity"; - out.canvas_opacityLabel = "opacity: {0}"; + out.canvas_opacityLabel = "Opacity: {0}"; out.canvas_widthLabel = "Width: {0}"; out.canvas_saveToDrive = "Save this image as a file in your CryptDrive"; + out.canvas_currentBrush = "Current brush"; + out.canvas_chooseColor = "Choose a color"; // Profile out.profileButton = "Profile"; // dropdown menu @@ -343,6 +349,8 @@ define(function () { out.fm_backup_title = 'Backup link'; out.fm_nameFile = 'How would you like to name that file?'; out.fm_error_cantPin = "Internal server error. Please reload the page and try again."; + out.fm_viewListButton = "List view"; + out.fm_viewGridButton = "Grid view"; // File - Context menu out.fc_newfolder = "New folder"; out.fc_rename = "Rename"; @@ -483,6 +491,10 @@ define(function () { out.todo_markAsIncompleteTitle = "Mark this task as incomplete"; out.todo_removeTaskTitle = "Remove this task from your todo list"; + // pad + out.pad_showToolbar = "Show toolbar"; + out.pad_hideToolbar = "Hide toolbar"; + // general warnings out.warn_notPinned = "This pad is not in anyone's CryptDrive. It will expire after 3 months. Learn more..."; @@ -525,7 +537,7 @@ define(function () { out.main_slidePad = 'Markdown Presentation'; out.main_pollPad = 'Poll or Schedule'; out.main_whiteboardPad = 'Whiteboard'; - out.main_recentPads = 'Recent Pads'; + out.main_localPads = 'Local Pads'; out.footer_applications = "Applications"; out.footer_contact = "Contact"; @@ -603,7 +615,7 @@ define(function () { // Initial states out.initialState = [ - '

', + '

', 'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '
', 'Share the link to this pad to edit with friends or use the  Share  button to share a read-only link which allows viewing but not editing.', @@ -611,7 +623,7 @@ define(function () { '

', 'Go ahead, just start typing...', - '

', + '

', '

 

' ].join(''); diff --git a/customize.dist/translations/messages.pt-br.js b/customize.dist/translations/messages.pt-br.js index 6ea5865d4..8764c7233 100644 --- a/customize.dist/translations/messages.pt-br.js +++ b/customize.dist/translations/messages.pt-br.js @@ -484,7 +484,7 @@ define(function () { // Initial states out.initialState = [ - '

', + '

', 'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '
', 'Share the link to this pad to edit with friends or use the  Share  button to share a read-only link which allows viewing but not editing.', @@ -492,7 +492,7 @@ define(function () { '

', 'Go ahead, just start typing...', - '

', + '

', '

 

' ].join(''); diff --git a/customize.dist/translations/messages.ro.js b/customize.dist/translations/messages.ro.js index 0eeb8f7f2..d2d497dbd 100644 --- a/customize.dist/translations/messages.ro.js +++ b/customize.dist/translations/messages.ro.js @@ -331,7 +331,7 @@ define(function () { out.header_france = "With \"love\" from \"Franța\"/ by \"XWiki"; out.header_support = " \"OpenPaaS-ng\""; out.header_logoTitle = "Mergi la pagina principală"; - out.initialState = "

Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește  Share  butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.

Îndrăznește, începe să scrii...

 

"; + out.initialState = "

Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește  Share  butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.

Îndrăznește, începe să scrii...

 

"; out.codeInitialState = "/*\n Acesta este editorul colaborativ de cod bazat pe tehnologia Zero Knowledge CryptPad.\n Ce scrii aici este criptat, așa că doar oamenii care au link-ul pot să-l acceseze.\n Poți să alegi ce limbaj de programare pus n evidență și schema de culori UI n dreapta sus.\n*/"; out.slideInitialState = "# CryptSlide\n* Acesta este un editor colaborativ bazat pe tehnologia Zero Knowledge.\n* Ce scrii aici este criptat, așa că doar oamenii care au link-ul pot să-l acceseze.\n* Nici măcar serverele nu au acces la ce scrii tu.\n* Ce vezi aici, ce auzi aici, atunci când pleci, lași aici.\n\n-\n# Cum se folosește\n1. Scrie-ți conținutul slide-urilor folosind sintaxa markdown\n - Află mai multe despre sintaxa markdown [aici](http://www.markdowntutorial.com/)\n2. Separă-ți slide-urile cu -\n3. Click pe butonul \"Play\" pentru a vedea rezultatele - Slide-urile tale sunt actualizate în timp real."; out.driveReadmeTitle = "Ce este CryptDrive?"; diff --git a/customize.dist/translations/messages.zh.js b/customize.dist/translations/messages.zh.js index ac0d9ce77..012b31018 100644 --- a/customize.dist/translations/messages.zh.js +++ b/customize.dist/translations/messages.zh.js @@ -467,7 +467,7 @@ define(function () { // Initial states out.initialState = [ - '

', + '

', '這是 CryptPad, 零知識即時協作編輯平台,當你輸入時一切已即存好。', '
', '分享這個工作檔案的網址連結給友人或是使用、  分享  按鈕分享唯讀的連結 其只能看不能編寫。', @@ -475,7 +475,7 @@ define(function () { '

', '來吧, 開始打字輸入吧...', - '

', + '

', '

 

' ].join(''); diff --git a/www/code/code.less b/www/code/code.less index 6c620fff8..ce7c7898e 100644 --- a/www/code/code.less +++ b/www/code/code.less @@ -59,19 +59,36 @@ body { box-sizing: border-box; font-family: Calibri,Ubuntu,sans-serif; word-wrap: break-word; - media-tag * { - max-width:100%; + position: relative; + media-tag { + * { + max-width:100%; + } + iframe[type="application/pdf"] { + max-height:50vh; + } } } #preview { max-width: 40vw; - margin: auto; + margin: 1em auto; .markdown_preformatted-code; .markdown_gfm-table(black); } +.cp-splitter { + position: absolute; + height: 100%; + width: 8px; + top: 0; + left: 0; + z-index: 9999; + + cursor: col-resize; +} + @media (max-width: @media-medium-screen) { .CodeMirror { flex: 1; diff --git a/www/code/inner.js b/www/code/inner.js index fa3a41f6f..d36a7acd2 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -4,6 +4,7 @@ define([ 'cm/lib/codemirror', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'less!/code/code.less', 'less!/customize/src/less/toolbar.less', 'less!/customize/src/less/cryptpad.less', diff --git a/www/code/main.js b/www/code/main.js index db358018d..7591f12a2 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -387,6 +387,26 @@ define([ } }); + // add the splitter + var splitter = $('
', { + 'class': 'cp-splitter' + }).appendTo($iframe.find('#previewContainer')); + + var $target = $iframe.find('.CodeMirror'); + splitter.on('mousedown', function (e) { + e.preventDefault(); + var x = e.pageX; + var w = $target.width(); + + $iframe.on('mouseup mousemove', function handler(evt) { + if (evt.type === 'mouseup') { + $iframe.off('mouseup mousemove', handler); + return; + } + $target.css('width', (w - x + evt.pageX) + 'px'); + }); + }); + Cryptpad.removeLoadingScreen(); setEditable(true); initializing = false; diff --git a/www/common/common-file.js b/www/common/common-file.js index 0093b9ef6..66e5eaefc 100644 --- a/www/common/common-file.js +++ b/www/common/common-file.js @@ -56,12 +56,13 @@ define([ $row.find('.upCancel').html('-'); var $pv = $row.find('.progressValue'); var $pb = $row.find('.progressContainer'); + var $pc = $row.find('.upProgress'); var $link = $row.find('.upLink'); var updateProgress = function (progressValue) { $pv.text(Math.round(progressValue*100)/100 + '%'); $pb.css({ - width: (progressValue/100)*188+'px' + width: (progressValue/100)*$pc.width()+'px' }); }; diff --git a/www/common/common-interface.js b/www/common/common-interface.js index d7d0b46d6..83389b816 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -313,6 +313,7 @@ define([ position: 'bottom', distance: 0, performance: true, + dynamicTitle: true, delay: [delay, 0] }); }; diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index 3bc6fc8aa..ffb0fe75e 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -79,7 +79,132 @@ define([ // Messaging tools var avatars = {}; - var addToFriendListUI = function (common, $block, open, remove, f) { + // TODO make this internal to the messenger + var channels = Msg.channels = window.channels = {}; + + var UI = Msg.UI = {}; + UI.init = function (common, $listContainer, $msgContainer) { + var ui = { + containers: { + friendList: $listContainer, + messages: $msgContainer, + }, + }; + + ui.setFriendList = function (display, remove) { + UI.getFriendList(common, display, remove).appendTo($listContainer); + }; + + ui.notify = function (curvePublic) { + var $friend = $listContainer.find('.friend').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + $friend.addClass('notify'); + }; + + ui.unnotify = function (curvePublic) { + var $friend = $listContainer.find('.friend').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + $friend.removeClass('notify'); + }; + + ui.update = function (curvePublic, types) { + var data = getFriend(common, curvePublic); + var chan = channels[data.channel]; + if (!chan.ready) { + chan.updateOnReady = (chan.updateOnReady || []).concat(types); + return; + } + var $friend = $listContainer.find('.friend').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + if (types.indexOf('displayName') >= 0) { + $friend.find('.name').text(data.displayName); + } + if (types.indexOf('avatar') >= 0) { + $friend.find('.default').remove(); + $friend.find('media-tag').remove(); + if (data.avatar && avatars[data.avatar]) { + $friend.prepend(avatars[data.avatar]); + } else { + common.displayAvatar($friend, data.avatar, data.displayName, function ($img) { + if (data.avatar && $img) { + avatars[data.avatar] = $img[0].outerHTML; + } + }); + } + } + }; + + ui.updateStatus = function (curvePublic) { + var data = getFriend(common, curvePublic); + var chan = channels[data.channel]; + + // FIXME mixes logic and presentation + var $friend = $listContainer.find('.friend').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + var status = chan.userList.some(function (nId) { + return chan.mapId[nId] === curvePublic; + }); + var statusText = status ? 'online' : 'offline'; + $friend.find('.status').attr('class', 'status '+statusText); + }; + + ui.getChannel = function (curvePublic) { + // TODO extract into UI method + var $chat = $msgContainer.find('.chat').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + return $chat.length? $chat: null; + }; + + ui.hideInfo = function () { + $msgContainer.find('.info').hide(); + }; + + ui.showInfo = function () { + $msgContainer.find('.info').show(); + }; + + ui.createChat = function (curvePublic) { + return $('
', {'class':'chat'}) + .data('key', curvePublic).appendTo($msgContainer); + }; + + ui.hideChat = function () { + $msgContainer.find('.chat').hide(); + }; + + ui.getFriend = function (curvePublic) { + return $listContainer.find('.friend').filter(function (idx, el) { + return $(el).data('key') === curvePublic; + }); + }; + + ui.addToFriendList = function (curvePublic, display, remove) { + var $block = $listContainer.find('> div'); + UI.addToFriendList(common, $block, display, remove, curvePublic); + }; + + ui.createMessage = function (msg, name) { + var $msg = $('
', {'class': 'message'}) + .attr('title', msg.time ? new Date(msg.time).toLocaleString(): '?'); + + if (name) { + $('
', {'class':'sender'}).text(name).appendTo($msg); + } + + $('
', {'class':'content'}).html(parseMessage(msg.text)).appendTo($msg); + return $msg; + }; + + return ui; + }; + + // internal + UI.addToFriendList = function (common, $block, open, remove, f) { var proxy = common.getProxy(); var friends = proxy.friends || {}; if (f === "me") { return; } @@ -120,12 +245,14 @@ define([ } $('', {'class': 'status'}).appendTo($friend); }; - Msg.getFriendListUI = function (common, open, remove) { - var proxy = common.getProxy(); + + // iterate over your friends list and return a dom element containing UI + UI.getFriendList = function (common, open, remove) { + var proxy = common.getProxy(); // throws var $block = $('
'); var friends = proxy.friends || {}; Object.keys(friends).forEach(function (f) { - addToFriendListUI(common, $block, open, remove, f); + UI.addToFriendList(common, $block, open, remove, f); }); return $block; }; @@ -146,7 +273,6 @@ define([ }); }; - var channels = Msg.channels = window.channels = {}; var msgAlreadyKnown = function (channel, sig) { return channel.messages.some(function (message) { @@ -162,8 +288,16 @@ define([ var parsedMsg = JSON.parse(msg); if (parsedMsg[0] === Types.message) { - parsedMsg.shift(); - channel.messages.push([sig, parsedMsg]); + // TODO validate messages here + var res = { + type: parsedMsg[0], + sig: sig, + channel: parsedMsg[1], + time: parsedMsg[2], + text: parsedMsg[3], + }; + + channel.messages.push(res); return true; } var proxy; @@ -192,6 +326,8 @@ define([ } }; + /* Broadcast a display name, profile, or avatar change to all contacts + */ var updateMyData = function (common) { var friends = getFriendList(common); var mySyncData = friends.me; @@ -218,7 +354,7 @@ define([ var onChannelReady = function (common, chanId) { if (ready.indexOf(chanId) !== -1) { return; } ready.push(chanId); - channels[chanId].updateStatus(); + channels[chanId].updateStatus(); // c'est quoi? var friends = getFriendList(common); if (ready.length === Object.keys(friends).length) { // All channels are ready @@ -240,7 +376,29 @@ define([ if (!isId) { return; } var decryptedMsg = channel.encryptor.decrypt(msg); - var parsed = JSON.parse(decryptedMsg); + + if (decryptedMsg === null) { + // console.error('unable to decrypt message'); + // console.error('potentially meant for yourself'); + + // message failed to parse, meaning somebody sent it to you but + // encrypted it with the wrong key, or you're sending a message to + // yourself in a different tab. + return; + } + + if (!decryptedMsg) { + console.error('decrypted message was falsey but not null'); + return; + } + + var parsed; + try { + parsed = JSON.parse(decryptedMsg); + } catch (e) { + console.error(decryptedMsg); + return; + } if (parsed[0] !== Types.mapId && parsed[0] !== Types.mapIdAck) { return; } if (parsed[2] !== sender || !parsed[1]) { return; } channel.mapId[sender] = parsed[1]; @@ -293,9 +451,9 @@ define([ } }; + // TODO extract into UI method var createChatBox = function (common, $container, curvePublic, messenger) { var data = getFriend(common, curvePublic); - var proxy = common.getProxy(); // Input var channel = channels[data.channel]; @@ -343,6 +501,8 @@ define([ messenger.input = $input[0]; var send = function () { + // TODO implement sending queue + // TODO separate message logic from UI var channel = channels[data.channel]; if (channel.sending) { console.error("still sending"); @@ -356,42 +516,26 @@ define([ console.error("input is disabled"); return; } + + var payload = $input.val(); // Send the message - var msg = [Types.message, proxy.curvePublic, +new Date(), $input.val()]; - var msgStr = JSON.stringify(msg); - var cryptMsg = channel.encryptor.encrypt(msgStr); channel.sending = true; - - console.log(channel.wc); - var network = common.getNetwork(); - if (!network.webChannels.some(function (wc) { - if (wc.id === channel.wc.id) { - console.error(wc.id, channel.wc.id); - return true; + channel.send(payload, function (e) { + if (e) { + channel.sending = false; + console.error(e); + return; } - console.error(wc.id, channel.wc.id); - //return wc.id === channel.wc.id; - })) { - console.error('no such channel:' + channel.wc.id); - return; - } - - channel.wc.bcast(cryptMsg).then(function () { $input.val(''); - pushMsg(common, channel, cryptMsg); channel.refresh(); channel.sending = false; - }, function (err) { - channel.sending = false; - console.error(err); }); }; - $('