diff --git a/apps/cory/ssb.json b/apps/cory/ssb.json deleted file mode 100644 index 1a8c4a1a..00000000 --- a/apps/cory/ssb.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"tildefriends-app","files":{"app.js":"&7dCNJFk5RMHTWZC2qR8/UzjS22bXn7ZsPS6L/LIgUOg=.sha256","index.html":"&c+LsaIXIVMFXYjv5PkbgwjzxQ967QYRER5yy0YgpnZo=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&cI/JLy83mOngcqYCEP8Vej8urDvAQAV1WxFsL67/K3M=.sha256","tf-message.js":"&qFKclMumLUufurbQyh2MrjwBG6E9w3L7HLfpelzmxzc=.sha256","tf.js":"&U4OySOFb2gqZJBgm+dUT44+OigJEgeNnJk3aYilnKNg=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&LXyUSm6zSakN/ghJlZ1Qg2VJfV5alhN0gl8F7txIIOU=.sha256","style.css":"&qegBNCrVUihxffRUxGFuG/6u+0Y6d18zHtfNHBZtZ04=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&zgD9eGT2WzOpHkQyraApePUZ7w5NdUFG+ip8KnSVGqw=.sha256"}} \ No newline at end of file diff --git a/apps/cory/ssb/app.js b/apps/cory/ssb/app.js deleted file mode 100644 index 34d989c1..00000000 --- a/apps/cory/ssb/app.js +++ /dev/null @@ -1,625 +0,0 @@ -import * as tfrpc from '/tfrpc.js'; - -const k_posts_max = 40; -const k_votes_max = 20; - -var g_ready = false; -var g_selected = null; -let g_whoami = null; - -var g_blocking_cache = {}; -var g_following_cache = {}; -var g_following_deep_cache = {}; -var g_sequence = {}; - -async function following(db, id) { - if (g_following_cache[id]) { - return g_following_cache[id]; - } - var o = await db.get(id + ":following"); - const k_version = 5; - var f = o ? JSON.parse(o) : o; - if (!f || f.version != k_version) { - f = {users: [], sequence: 0, version: k_version}; - } - f.users = new Set(f.users); - await ssb.sqlStream( - "SELECT "+ - " sequence, "+ - " json_extract(content, '$.contact') AS contact, "+ - " json_extract(content, '$.following') AS following "+ - "FROM messages "+ - "WHERE "+ - " author = ?1 AND "+ - " sequence > ?2 AND "+ - " json_extract(content, '$.type') = 'contact' "+ - "UNION SELECT MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ?1 "+ - "ORDER BY sequence", - [id, f.sequence], - function(row) { - if (row.following) { - f.users.add(row.contact); - } else { - f.users.delete(row.contact); - } - if (row.sequence) { - f.sequence = row.sequence; - } - }); - g_sequence[id] = f.sequence; - var as_set = f.users; - f.users = Array.from(f.users).sort(); - var j = JSON.stringify(f); - if (o != j) { - await db.set(id + ":following", j); - } - f.users = as_set; - g_following_cache[id] = f.users; - return f.users; -} - -async function followingDeep(db, seed_ids, depth, blocked) { - if (depth <= 0) { - return seed_ids; - } - var key = JSON.stringify([seed_ids, depth, blocked]); - if (g_following_deep_cache[key]) { - return g_following_deep_cache[key]; - } - var f = await Promise.all(seed_ids.map(x => following(db, x).then(x => [...x]))); - var ids = [].concat(...f); - if (blocked) { - ids = ids.filter(x => !blocked.has(x)); - } - var x = await followingDeep(db, [...new Set(ids)].sort(), depth - 1, blocked); - x = [...new Set([].concat(...x, ...seed_ids))].sort(); - g_following_deep_cache[key] = x; - return x; -} - -async function blocking(db, id) { - if (g_blocking_cache[id]) { - return g_blocking_cache[id]; - } - var o = await db.get(id + ":blocking"); - const k_version = 5; - var f = o ? JSON.parse(o) : o; - if (!f || f.version != k_version) { - f = {users: [], sequence: 0, version: k_version}; - } - f.users = new Set(f.users); - if (!g_sequence[id] || g_sequence[id] > f.sequence) { - await ssb.sqlStream( - "SELECT "+ - " sequence, "+ - " json_extract(content, '$.contact') AS contact, "+ - " json_extract(content, '$.blocking') AS blocking "+ - "FROM messages "+ - "WHERE "+ - " author = ?1 AND "+ - " sequence > ?2 AND "+ - " json_extract(content, '$.type') = 'contact' "+ - "UNION SELECT MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ?1 "+ - "ORDER BY sequence", - [id, f.sequence], - function(row) { - if (row.blocking) { - f.users.add(row.contact); - } else { - f.users.delete(row.contact); - } - if (row.sequence) { - f.sequence = row.sequence; - } - }); - g_sequence[id] = f.sequence; - } - var as_set = f.users; - f.users = Array.from(f.users).sort(); - var j = JSON.stringify(f); - if (o != j) { - await db.set(id + ":blocking", j); - } - f.users = as_set; - g_blocking_cache[id] = f.users; - return f.users; -} - -async function getAbout(db, id) { - var o = await db.get(id + ":about"); - const k_version = 5; - var f = o ? JSON.parse(o) : o; - if (!f || f.version != k_version) { - f = {about: {}, sequence: 0, version: k_version}; - } - if (g_sequence[id] === undefined || g_sequence[id] > f.sequence) { - await ssb.sqlStream( - "SELECT "+ - " sequence, "+ - " content "+ - "FROM messages "+ - "WHERE "+ - " author = ?1 AND "+ - " sequence > ?2 AND "+ - " json_extract(content, '$.type') = 'about' AND "+ - " json_extract(content, '$.about') = ?1 "+ - "UNION SELECT MAX(sequence) as sequence, NULL FROM messages WHERE author = ?1 "+ - "ORDER BY sequence", - [id, f.sequence], - function(row) { - if (row.content) { - var about = {}; - try { - about = JSON.parse(row.content); - } catch { - } - delete about.about; - delete about.type; - f.about = Object.assign(f.about, about); - } - if (row.sequence) { - f.sequence = Math.max(f.sequence, row.sequence); - } - }); - g_sequence[id] = f.sequence; - var j = JSON.stringify(f); - if (o != j) { - await db.set(id + ":about", j); - } - } - return f.about; -} - -function fnv32a(value) -{ - var result = 0x811c9dc5; - for (var i = 0; i < value.length; i++) { - result ^= value.charCodeAt(i); - result += (result << 1) + (result << 4) + (result << 7) + (result << 8) + (result << 24); - } - return result >>> 0; -} - -async function getRecentPostsSingleId(db, id, limit) { - var recent = []; - await ssb.sqlStream( - "SELECT "+ - " rowid, "+ - " id, "+ - " timestamp "+ - "FROM messages "+ - "WHERE "+ - " author = ? AND "+ - " json_extract(content, '$.type') = 'post' "+ - "ORDER BY sequence DESC LIMIT ?", - [id, limit], - function(row) { - if (row.id) { - recent.push({id: row.id, timestamp: row.timestamp}); - } - }); - recent.sort((x, y) => y.timestamp - x.timestamp); - return recent.map(x => x.id); -} - -async function getRecentPostIds(db, id, ids, limit) { - if (ids.length == 1) { - return await getRecentPostsSingleId(db, ids[0], limit); - } - const k_version = 11; - const k_batch_max = 32; - var o = await db.get(id + ':recent_posts'); - var recent = []; - var f = o ? JSON.parse(o) : o; - var ids_hash = fnv32a(JSON.stringify(ids)); - if (!f || f.version != k_version || f.ids_hash != ids_hash) { - f = {recent: [], rowid: 0, version: k_version, ids_hash: ids_hash}; - } - var row_id_max = 0; - await ssb.sqlStream( - "SELECT MAX(rowid) as rowid FROM messages", - [], - function(row) { - row_id_max = row.rowid; - }); - for (var i = 0; i < ids.length; i += k_batch_max) { - var ids_batch = ids.slice(i, Math.min(i + k_batch_max, ids.length)); - await ssb.sqlStream( - "SELECT "+ - " rowid, "+ - " id, "+ - " timestamp "+ - "FROM messages "+ - "WHERE "+ - " rowid > ? AND "+ - " rowid <= ? AND "+ - " author IN (" + ids_batch.map(x => '?').join(", ") + ") "+ - "ORDER BY timestamp DESC LIMIT ?", - [].concat([f.rowid, row_id_max], ids_batch, [limit]), - function(row) { - if (row.id) { - recent.push({id: row.id, timestamp: row.timestamp}); - } - }); - } - f.rowid = row_id_max; - f.recent = [].concat(recent, f.recent); - var have = {}; - f.recent = f.recent.filter(function(x) { - if (!have[x.id]) { - have[x.id] = true; - return true; - } - }); - f.recent.sort((x, y) => y.timestamp - x.timestamp); - f.recent = f.recent.slice(0, limit); - var j = JSON.stringify(f); - if (o != j) { - await db.set(id + ":recent_posts", j); - } - return f.recent.map(x => x.id); -} - -async function getRecentPostIds2(db, id, ids, start_time) { - if (ids.length == 1) { - return getRecentPostsSingleId(db, ids[0], 20); - } - const k_batch_max = 32; - var row_id_max = 0; - await ssb.sqlStream( - "SELECT MAX(rowid) as rowid FROM messages", - [], - function(row) { - row_id_max = row.rowid; - }); - var posts_by_author = {}; - for (var i = 0; i < ids.length; i += k_batch_max) { - var ids_batch = ids.slice(i, Math.min(i + k_batch_max, ids.length)); - await ssb.sqlStream( - "SELECT "+ - " author, "+ - " id "+ - "FROM messages "+ - "WHERE "+ - " author IN (" + ids_batch.map(x => '?').join(", ") + ") AND "+ - " timestamp > ? AND "+ - " rowid <= ? AND "+ - " json_extract(content, '$.type') = 'post' "+ - "ORDER BY timestamp DESC", - [].concat(ids_batch, [start_time, row_id_max]), - function(row) { - if (row.id) { - if (!posts_by_author[row.author]) { - posts_by_author[row.author] = []; - } - posts_by_author[row.author].push(row.id); - } - }); - } - return Object.values(posts_by_author).map(x => x[0]); -} - -async function getRelatedPostIds(db, message, ids, limit) { - const k_batch_max = 16; - var recent = []; - var row_id_max = 0; - await ssb.sqlStream( - "SELECT MAX(rowid) as rowid FROM messages", - [], - function(row) { - row_id_max = row.rowid; - }); - var id = message.id; - try { - id = JSON.parse(message.content).root || id; - } catch { - } - for (var i = 0; i < ids.length; i += k_batch_max) { - var ids_batch = ids.slice(i, Math.min(i + k_batch_max, ids.length)); - await ssb.sqlStream( - "SELECT "+ - " rowid, "+ - " id, "+ - " timestamp "+ - "FROM messages "+ - "WHERE "+ - " timestamp >= ? AND "+ - " rowid <= ? AND "+ - " author IN (" + ids_batch.map(x => '?').join(", ") + ") AND "+ - " json_extract(content, '$.type') = 'post' AND "+ - " (id = ? OR json_extract(content, '$.root') = ?) "+ - "ORDER BY timestamp DESC LIMIT ?", - [].concat([message.timestamp || 0, row_id_max], ids_batch, [message.id, id, limit]), - function(row) { - if (row.id) { - recent.push({id: row.id, timestamp: row.timestamp}); - } - }); - } - recent.sort((x, y) => y.timestamp - x.timestamp); - recent = recent.slice(0, limit); - return recent.map(x => x.id); -} - -async function getVotes(db, id) { - var o = await db.get(id + ":votes"); - const k_version = 7; - var f = o ? JSON.parse(o) : o; - if (!f || f.version != k_version) { - f = {votes: [], sequence: 0, version: k_version}; - } - if (g_sequence[id] === undefined || g_sequence[id] > f.sequence) { - var votes = []; - await ssb.sqlStream( - "SELECT "+ - " author, "+ - " id, "+ - " sequence, "+ - " timestamp, "+ - " content "+ - "FROM messages "+ - "WHERE "+ - " author = ? AND "+ - " sequence > ? AND "+ - " json_extract(content, '$.type') = 'vote' "+ - "UNION SELECT NULL, NULL, MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ? "+ - "ORDER BY sequence DESC LIMIT ?", - [id, f.sequence, id, k_votes_max], - function(row) { - if (row.id) { - votes.push(row); - } - if (row.sequence) { - f.sequence = Math.max(f.sequence, row.sequence); - } - }); - g_sequence[id] = f.sequence; - f.votes = [].concat(votes, f.votes).slice(0, k_votes_max); - var j = JSON.stringify(f); - if (o != j) { - await db.set(id + ":votes", j); - } - } - return f.votes; -} - -async function getPosts(db, ids) { - var posts = []; - if (ids.length) { - await ssb.sqlStream( - "SELECT rowid, * FROM messages WHERE id IN (" + ids.map(x => "?").join(", ") + ") ORDER BY timestamp DESC", - ids, - row => posts.push(row)); - } - return posts; -} - -tfrpc.register(async function ready() { - let identities = await ssb.getIdentities(); - let whoami = await app.localStorageGet('whoami'); - await tfrpc.rpc.set_identities(identities); - g_ready = true; - refresh_internal(whoami, g_selected, true); -}); - -tfrpc.register(async function store_blob(blob) { - if (Array.isArray(blob)) { - blob = Uint8Array.from(blob); - } - return await ssb.blobStore(blob); -}); - -ssb.addEventListener('broadcasts', async function() { - await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts()); -}); - -core.register('onConnectionsChanged', async function() { - var connections = await ssb.connections(); - await tfrpc.rpc.set('connections', connections); -}); - -async function updateSequences(db) { - var k_batch_max = 100; - var changes = {}; - var keys = Object.keys(g_sequence); - for (var i = 0; i < keys.length; i += k_batch_max) { - var ids_batch = keys.slice(i, Math.min(i + k_batch_max, keys.length)); - await ssb.sqlStream( - "SELECT "+ - " author, "+ - " MAX(sequence) AS sequence "+ - "FROM messages "+ - "WHERE "+ - " author IN (" + ids_batch.map(x => '?').join(", ") + ")", - ids_batch, - function(row) { - if (g_sequence[row.author] != row.sequence) { - g_sequence[row.author] = row.sequence; - changes[row.author] = row.sequence; - } - }); - } - return changes; -} - -async function refresh_internal(whoami, selected, force) { - if (whoami !== g_whoami || selected !== g_selected || force) { - if (g_whoami !== whoami && whoami) { - await app.localStorageSet('whoami', whoami); - } - g_whoami = whoami; - g_selected = selected; - } else { - return; - } - if (typeof(whoami) !== 'string') { - return; - } - if (!g_ready) { - return; - } - var timing = []; - timing.push({name: 'start', time: new Date()}); - g_following_cache = {}; - g_following_deep_cache = {}; - await tfrpc.rpc.clear(); - await tfrpc.rpc.set_identities(await ssb.getIdentities()); - await tfrpc.rpc.set('all_identities', await ssb.getAllIdentities()); - await tfrpc.rpc.set('selected', selected); - var db = await database("ssb"); - g_sequence = {}; - try { - g_sequence = JSON.parse(await db.get('sequence')); - } catch (e) { - } - await updateSequences(db); - timing.push({name: 'init', time: new Date()}); - var blocked = await blocking(db, whoami); - timing.push({name: 'blocked', time: new Date()}); - var all_followed = await followingDeep(db, [whoami], 2, blocked); - timing.push({name: 'all_followed', time: new Date()}); - let actual_selected = (selected ? [selected] : all_followed) ?? []; - await Promise.all([ - tfrpc.rpc.set('whoami', whoami), - tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts()), - tfrpc.rpc.set('connections', await ssb.connections()), - tfrpc.rpc.set('apps', await core.apps()), - ]); - timing.push({name: 'core', time: new Date()}); - var ids; - if (selected && selected.startsWith('%')) { - var m = await getPosts(db, [selected]); - m = m.length ? m[0] : {id: selected}; - ids = await getRelatedPostIds(db, m, all_followed, k_posts_max); - } else { - ids = await getRecentPostIds2(db, whoami, actual_selected, (new Date()).valueOf() - (24 * 60 * 60 * 1000)); - } - timing.push({name: 'get_post_ids', time: new Date()}); - var posts = await getPosts(db, ids); - timing.push({name: 'get_posts', time: new Date()}); - var roots = posts.map(function(x) { - try { - return JSON.parse(x.content).root; - } catch { - return null; - } - }); - var have = new Set(posts.map(x => x.id)); - roots = [...new Set(roots)].filter(x => x && !have.has(x)); - var all_posts = [].concat(posts, await getPosts(db, roots)); - timing.push({name: 'get_root_posts', time: new Date()}); - await tfrpc.rpc.push_posts(all_posts); - timing.push({name: 'send_posts', time: new Date()}); - let all_users = {}; - await Promise.all(all_followed.map(id => getAbout(db, id).then(function(results) { - if (Object.keys(results).length) { - all_users[id] = results; - } - }))); - await tfrpc.rpc.push_users(all_users); - timing.push({name: 'about', time: new Date()}); - var all_votes = []; - for (let id of all_followed) { - var results = await getVotes(db, id); - if (results.length) { - all_votes.push(results); - } - } - all_votes = all_votes.flat(); - await tfrpc.rpc.push_votes(all_votes); - timing.push({name: 'votes', time: new Date()}); - if (selected && selected.length == 1 && selected[0].startsWith('@')) { - let size = 0; - await ssb.sqlStream( - 'SELECT SUM(LENGTH(content)) AS length FROM messages WHERE author = ?1', - selected, - function(row) { - size = row.length; - }); - let users = {}; - users[selected[0]] = {size: size}; - await tfrpc.rpc.push_users(users); - } - await tfrpc.rpc.push_following(Object.fromEntries(all_followed.map(id => [id, [...(g_following_cache[id] || [])]]))); - timing.push({name: 'following', time: new Date()}); - await tfrpc.rpc.push_blocking(whoami, [...(g_blocking_cache[whoami] || [])]); - timing.push({name: 'send_blocking', time: new Date()}); - await db.set('sequence', JSON.stringify(g_sequence)); - - var times = {}; - var previous = null; - for (let t of timing) { - times[t.name] = (t.time - (previous || t).time) / 1000.0 + ' s'; - previous = t; - }times.total = (new Date() - timing[0].time) / 1000.0 + ' s'; - await tfrpc.rpc.ready(times); -} - -ssb.addEventListener('message', async function(id) { - var db = await database("ssb"); - var posts = await getPosts(db, [id]); - for (let post of posts) { - if (post.author == g_whoami || - JSON.parse(post.content).type != 'post') { - await tfrpc.rpc.push_posts([post]); - } else { - await tfrpc.rpc.add_unread(1); - } - } -}); - -tfrpc.register(async function refresh(whoami, selected, force) { - return refresh_internal(whoami, selected, force); -}); - -tfrpc.register(async function createIdentity() { - return ssb.createIdentity(); -}); - -tfrpc.register(async function appendMessage(message) { - await addAppSources(message); - return ssb.appendMessageWithIdentity(g_whoami, message); -}); - -async function addAppSources(message) { - if (message.mentions) { - for (let mention of message.mentions) { - if (mention.type == 'application/tildefriends') { - var blob = await ssb.blobGet(mention.link); - var json = JSON.parse(utf8Decode(blob)); - for (let file of Object.keys(json.files)) { - message.mentions.push({ - name: file, - link: json.files[file], - }); - } - } - } - } -} - -core.register('message', async function(m) { - if (m.message) { - if (m.message.connect) { - await ssb.connect(m.message.connect); - } - } else if (m.event == 'hashChange') { - let hash = m.hash.length > 1 ? m.hash.substring(1) : null; - let changed = g_selected !== hash; - await refresh_internal(g_whoami, hash, changed); - } else if (m.event == 'focus' || m.event == 'blur') { - /* Shh. */ - } else { - print(JSON.stringify(m)); - } -}); - -async function main() { - if (core.user?.credentials?.permissions?.authenticated) { - await app.setDocument(utf8Decode(await getFile("index.html"))); - } else { - await app.setDocument('
{{content_raw}}-
, or missing
. Bailing hydration and performing ' + - 'full client-side render.' - ); - } - } - // either not server-rendered, or hydration failed. - // create an empty node and replace it - oldVnode = emptyNodeAt(oldVnode); - } - - // replacing existing element - var oldElm = oldVnode.elm; - var parentElm = nodeOps.parentNode(oldElm); - - // create new node - createElm( - vnode, - insertedVnodeQueue, - // extremely rare edge case: do not insert if old element is in a - // leaving transition. Only happens when combining transition + - // keep-alive + HOCs. (#4590) - oldElm._leaveCb ? null : parentElm, - nodeOps.nextSibling(oldElm) - ); - - // update parent placeholder node element, recursively - if (isDef(vnode.parent)) { - var ancestor = vnode.parent; - var patchable = isPatchable(vnode); - while (ancestor) { - for (var i = 0; i < cbs.destroy.length; ++i) { - cbs.destroy[i](ancestor); - } - ancestor.elm = vnode.elm; - if (patchable) { - for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) { - cbs.create[i$1](emptyNode, ancestor); - } - // #6513 - // invoke insert hooks that may have been merged by create hooks. - // e.g. for directives that uses the "inserted" hook. - var insert = ancestor.data.hook.insert; - if (insert.merged) { - // start at index 1 to avoid re-invoking component mounted hook - for (var i$2 = 1; i$2 < insert.fns.length; i$2++) { - insert.fns[i$2](); - } - } - } else { - registerRef(ancestor); - } - ancestor = ancestor.parent; - } - } - - // destroy old node - if (isDef(parentElm)) { - removeVnodes([oldVnode], 0, 0); - } else if (isDef(oldVnode.tag)) { - invokeDestroyHook(oldVnode); - } - } - } - - invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch); - return vnode.elm - } - } - - /* */ - - var directives = { - create: updateDirectives, - update: updateDirectives, - destroy: function unbindDirectives (vnode) { - updateDirectives(vnode, emptyNode); - } - }; - - function updateDirectives (oldVnode, vnode) { - if (oldVnode.data.directives || vnode.data.directives) { - _update(oldVnode, vnode); - } - } - - function _update (oldVnode, vnode) { - var isCreate = oldVnode === emptyNode; - var isDestroy = vnode === emptyNode; - var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context); - var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context); - - var dirsWithInsert = []; - var dirsWithPostpatch = []; - - var key, oldDir, dir; - for (key in newDirs) { - oldDir = oldDirs[key]; - dir = newDirs[key]; - if (!oldDir) { - // new directive, bind - callHook$1(dir, 'bind', vnode, oldVnode); - if (dir.def && dir.def.inserted) { - dirsWithInsert.push(dir); - } - } else { - // existing directive, update - dir.oldValue = oldDir.value; - dir.oldArg = oldDir.arg; - callHook$1(dir, 'update', vnode, oldVnode); - if (dir.def && dir.def.componentUpdated) { - dirsWithPostpatch.push(dir); - } - } - } - - if (dirsWithInsert.length) { - var callInsert = function () { - for (var i = 0; i < dirsWithInsert.length; i++) { - callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode); - } - }; - if (isCreate) { - mergeVNodeHook(vnode, 'insert', callInsert); - } else { - callInsert(); - } - } - - if (dirsWithPostpatch.length) { - mergeVNodeHook(vnode, 'postpatch', function () { - for (var i = 0; i < dirsWithPostpatch.length; i++) { - callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode); - } - }); - } - - if (!isCreate) { - for (key in oldDirs) { - if (!newDirs[key]) { - // no longer present, unbind - callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy); - } - } - } - } - - var emptyModifiers = Object.create(null); - - function normalizeDirectives$1 ( - dirs, - vm - ) { - var res = Object.create(null); - if (!dirs) { - // $flow-disable-line - return res - } - var i, dir; - for (i = 0; i < dirs.length; i++) { - dir = dirs[i]; - if (!dir.modifiers) { - // $flow-disable-line - dir.modifiers = emptyModifiers; - } - res[getRawDirName(dir)] = dir; - dir.def = resolveAsset(vm.$options, 'directives', dir.name, true); - } - // $flow-disable-line - return res - } - - function getRawDirName (dir) { - return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('.'))) - } - - function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) { - var fn = dir.def && dir.def[hook]; - if (fn) { - try { - fn(vnode.elm, dir, vnode, oldVnode, isDestroy); - } catch (e) { - handleError(e, vnode.context, ("directive " + (dir.name) + " " + hook + " hook")); - } - } - } - - var baseModules = [ - ref, - directives - ]; - - /* */ - - function updateAttrs (oldVnode, vnode) { - var opts = vnode.componentOptions; - if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) { - return - } - if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) { - return - } - var key, cur, old; - var elm = vnode.elm; - var oldAttrs = oldVnode.data.attrs || {}; - var attrs = vnode.data.attrs || {}; - // clone observed objects, as the user probably wants to mutate it - if (isDef(attrs.__ob__)) { - attrs = vnode.data.attrs = extend({}, attrs); - } - - for (key in attrs) { - cur = attrs[key]; - old = oldAttrs[key]; - if (old !== cur) { - setAttr(elm, key, cur, vnode.data.pre); - } - } - // #4391: in IE9, setting type can reset value for input[type=radio] - // #6666: IE/Edge forces progress value down to 1 before setting a max - /* istanbul ignore if */ - if ((isIE || isEdge) && attrs.value !== oldAttrs.value) { - setAttr(elm, 'value', attrs.value); - } - for (key in oldAttrs) { - if (isUndef(attrs[key])) { - if (isXlink(key)) { - elm.removeAttributeNS(xlinkNS, getXlinkProp(key)); - } else if (!isEnumeratedAttr(key)) { - elm.removeAttribute(key); - } - } - } - } - - function setAttr (el, key, value, isInPre) { - if (isInPre || el.tagName.indexOf('-') > -1) { - baseSetAttr(el, key, value); - } else if (isBooleanAttr(key)) { - // set attribute for blank value - // e.g. - if (isFalsyAttrValue(value)) { - el.removeAttribute(key); - } else { - // technically allowfullscreen is a boolean attribute for