diff --git a/www/common/metadata-manager.js b/www/common/metadata-manager.js index 822880a02..24d03df2e 100644 --- a/www/common/metadata-manager.js +++ b/www/common/metadata-manager.js @@ -1,24 +1,38 @@ define([], function () { + var UNINIT = 'uninitialized'; var create = function (sframeChan) { - var personalMetadata = 'uninitialized'; - var myID = 'uninitialized'; + var meta = UNINIT; + var myID = UNINIT; var members = []; - var metadataObj = 'unintialized'; + var metadataObj = UNINIT; var dirty = true; var changeHandlers = []; var checkUpdate = function () { if (!dirty) { return; } - if (metadataObj === 'uninitialized') { throw new Error(); } - if (myID === 'uninitialized') { throw new Error(); } - if (personalMetadata === 'uninitialized') { throw new Error(); } + if (meta === UNINIT) { throw new Error(); } + if (myID === UNINIT) { myID = meta.myID; } + if (metadataObj === UNINIT) { + metadataObj = { + defaultTitle: meta.doc.defaultTitle, + title: meta.doc.defaultTitle, + users: {} + }; + } var mdo = {}; - Object.keys(metadataObj).forEach(function (x) { + // We don't want to add our user data to the object multiple times. + var containsYou = false; + console.log(metadataObj); + Object.keys(metadataObj.users).forEach(function (x) { if (members.indexOf(x) === -1) { return; } - mdo[x] = metadataObj[x]; + mdo[x] = metadataObj.users[x]; + if (metadataObj.users[x].uid === meta.user.uid) { + console.log('document already contains you'); + containsYou = true; + } }); - mdo[myID] = personalMetadata; - metadataObj = mdo; + if (!containsYou) { mdo[myID] = meta.user; } + metadataObj.users = mdo; dirty = false; changeHandlers.forEach(function (f) { f(); }); }; @@ -27,8 +41,8 @@ define([], function () { setTimeout(checkUpdate); }; - sframeChan.on('EV_USERDATA_UPDATE', function (ev) { - personalMetadata = ev; + sframeChan.on('EV_METADATA_UPDATE', function (ev) { + meta = ev; change(); }); sframeChan.on('EV_RT_CONNECT', function (ev) { @@ -52,8 +66,9 @@ define([], function () { }); return Object.freeze({ - metadataChange: function (meta) { - metadataObj = meta; + updateMetadata: function (m) { + if (JSON.stringify(metadataObj) === JSON.stringify(m)) { return; } + metadataObj = m; change(); }, getMetadata: function () { diff --git a/www/common/sframe-chainpad-netflux-inner.js b/www/common/sframe-chainpad-netflux-inner.js index d4bd31f0e..e5b921859 100644 --- a/www/common/sframe-chainpad-netflux-inner.js +++ b/www/common/sframe-chainpad-netflux-inner.js @@ -52,7 +52,7 @@ define([ onConnectionChange({ state: false }); }); sframeChan.on('EV_RT_CONNECT', function (content) { - content.members.forEach(userList.onJoin); + //content.members.forEach(userList.onJoin); myID = content.myID; isReady = false; if (chainpad) { diff --git a/www/common/sframe-chainpad-netflux-outer.js b/www/common/sframe-chainpad-netflux-outer.js index 078a920e7..01b26d494 100644 --- a/www/common/sframe-chainpad-netflux-outer.js +++ b/www/common/sframe-chainpad-netflux-outer.js @@ -228,7 +228,9 @@ define([], function () { return { start: function (config) { - config.sframeChan.whenReg('EV_RT_READY', function () { start(config); }); + config.sframeChan.whenReg('EV_RT_READY', function () { + start(config); + }); } }; }); diff --git a/www/common/sframe-channel.js b/www/common/sframe-channel.js index 3dd0a3d8d..62250704a 100644 --- a/www/common/sframe-channel.js +++ b/www/common/sframe-channel.js @@ -18,6 +18,7 @@ define([ var chan = {}; + // Send a query. channel.query('Q_SOMETHING', { args: "whatever" }, function (reply) { ... }); chan.query = function (q, content, cb) { if (!otherWindow) { throw new Error('not yet initialized'); } if (!SFrameProtocol[q]) { @@ -40,6 +41,7 @@ define([ }), '*'); }; + // Fire an event. channel.event('EV_SOMETHING', { args: "whatever" }); var event = chan.event = function (e, content) { if (!otherWindow) { throw new Error('not yet initialized'); } if (!SFrameProtocol[e]) { @@ -51,13 +53,17 @@ define([ otherWindow.postMessage(JSON.stringify({ content: content, q: e }), '*'); }; + // Be notified on query or event. channel.on('EV_SOMETHING', function (args, reply) { ... }); + // If the type is a query, your handler will be invoked with a reply function that takes + // one argument (the content to reply with). chan.on = function (queryType, handler, quiet) { - if (!otherWindow) { throw new Error('not yet initialized'); } + if (!otherWindow && !quiet) { throw new Error('not yet initialized'); } if (!SFrameProtocol[queryType]) { throw new Error('please only register handlers which are defined in sframe-protocol.js'); } (handlers[queryType] = handlers[queryType] || []).push(function (data, msg) { handler(data.content, function (replyContent) { + if (queryType.indexOf('Q_') !== 0) { throw new Error("replies to events are invalid"); } msg.source.postMessage(JSON.stringify({ txid: data.txid, content: replyContent @@ -69,25 +75,35 @@ define([ } }; - chan.whenReg = function (queryType, handler) { + // If a particular handler is registered, call the callback immediately, otherwise it will be called + // when that handler is first registered. + // channel.whenReg('Q_SOMETHING', function () { ...query Q_SOMETHING?... }); + chan.whenReg = function (queryType, cb, always) { if (!otherWindow) { throw new Error('not yet initialized'); } if (!SFrameProtocol[queryType]) { throw new Error('please only register handlers which are defined in sframe-protocol.js'); } + var reg = always; if (insideHandlers.indexOf(queryType) > -1) { - handler(); + cb(); } else { - (callWhenRegistered[queryType] = callWhenRegistered[queryType] || []).push(handler); + reg = true; + } + if (reg) { + (callWhenRegistered[queryType] = callWhenRegistered[queryType] || []).push(cb); } }; - (handlers['EV_REGISTER_HANDLER'] = handlers['EV_REGISTER_HANDLER'] || []).push(function (data) { - if (callWhenRegistered[data.content]) { - callWhenRegistered[data.content].forEach(function (f) { f(); }); - delete callWhenRegistered[data.content]; + // Same as whenReg except it will invoke every time there is another registration, not just once. + chan.onReg = function (queryType, cb) { chan.whenReg(queryType, cb, true); }; + + chan.on('EV_REGISTER_HANDLER', function (content) { + if (callWhenRegistered[content]) { + callWhenRegistered[content].forEach(function (f) { f(); }); + delete callWhenRegistered[content]; } - insideHandlers.push(data.content); - }); + insideHandlers.push(content); + }, true); var intr; var txid; diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index b6ab3f7b8..ea7557fc7 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -34,5 +34,5 @@ define({ // Called from the outside, this informs the inside whenever the user's data has been changed. // The argument is the object representing the content of the user profile minus the netfluxID // which changes per-reconnect. - 'EV_USERDATA_UPDATE': true + 'EV_METADATA_UPDATE': true }); \ No newline at end of file diff --git a/www/pad2/main.js b/www/pad2/main.js index 675b05a25..3f527e72c 100644 --- a/www/pad2/main.js +++ b/www/pad2/main.js @@ -260,6 +260,7 @@ define([ // secret.keys = secret.key; //} var readOnly = false; // TODO + var cpNfInner; var $bar = $('#cke_1_toolbox'); @@ -339,7 +340,9 @@ define([ var stringifyDOM = module.stringifyDOM = function (dom) { var hjson = Hyperjson.fromDOM(dom, isNotMagicLine, brFilter); - + hjson[3] = { + metadata: cpNfInner.metadataMgr.getMetadata() + }; /*hjson[3] = { TODO users: UserList.userData, defaultTitle: Title.defaultTitle, @@ -380,9 +383,6 @@ define([ } }; - var meta; - var metaStr; - realtimeOptions.onRemote = function () { if (initializing) { return; } if (isHistoryMode) { return; } @@ -403,6 +403,10 @@ define([ newSInner = stringify(newInner[2]); } + if (newInner[3]) { + cpNfInner.metadataMgr.updateMetadata(newInner[3].metadata); + } + // build a dom from HJSON, diff, and patch the editor applyHjson(shjson); @@ -446,14 +450,6 @@ define([ if (newSInner && newSInner !== oldSInner) { Cryptpad.notify(); } - - var newMeta = newInner[3]; - var newMetaStr = JSON.stringify(newMeta); - if (newMetaStr !== metaStr) { - metaStr = newMetaStr; - meta = newMeta; - //meta[] HERE - } }; var exportFile = function () { @@ -473,7 +469,7 @@ define([ }; realtimeOptions.onInit = function (info) { - + console.log('onInit'); // TODO return; @@ -599,6 +595,7 @@ define([ // this should only ever get called once, when the chain syncs realtimeOptions.onReady = function (info) { + console.log('onReady'); if (!module.isMaximized) { module.isMaximized = true; $('iframe.cke_wysiwyg_frame').css('width', ''); @@ -686,9 +683,7 @@ define([ } }; - var cpNfInner = CpNfInner.start(realtimeOptions); - - + cpNfInner = CpNfInner.start(realtimeOptions); Cryptpad.onLogout(function () { setEditable(false); }); diff --git a/www/pad2/outer.js b/www/pad2/outer.js index e24a9a4b8..4d835bf03 100644 --- a/www/pad2/outer.js +++ b/www/pad2/outer.js @@ -18,6 +18,34 @@ define([ })); Cryptpad.ready(waitFor()); }).nThen(function (waitFor) { + var parsed = Cryptpad.parsePadUrl(window.location.href); + if (!parsed.type) { throw new Error(); } + var defaultTitle = Cryptpad.getDefaultName(parsed); + var updateMeta = function () { + console.log('EV_METADATA_UPDATE'); + var name; + nThen(function (waitFor) { + Cryptpad.getLastName(waitFor(function (n) { name = n })); + }).nThen(function (waitFor) { + sframeChan.event('EV_METADATA_UPDATE', { + doc: { + defaultTitle: defaultTitle, + type: parsed.type + }, + myID: Cryptpad.getNetwork().webChannels[0].myID, + user: { + name: name, + uid: Cryptpad.getUid(), + avatar: Cryptpad.getAvatarUrl(), + profile: Cryptpad.getProfileUrl(), + curvePublic: Cryptpad.getProxy().curvePublic + } + }); + }); + }; + Cryptpad.onDisplayNameChanged(updateMeta); + sframeChan.onReg('EV_METADATA_UPDATE', updateMeta); + Cryptpad.onError(function (info) { console.log('error'); console.log(info);