From a25322c3976854674986731682a7d74335b9476e Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Fri, 2 Sep 2022 14:58:45 +0300 Subject: [PATCH] added direct page actions + some tweaking and fixes... Signed-off-by: Alex A. Naanou --- pwiki/page.js | 92 +++++++++++++++++++++++++++++++-------------- pwiki/store/base.js | 83 +++++++++++++++++++++++++--------------- 2 files changed, 116 insertions(+), 59 deletions(-) diff --git a/pwiki/page.js b/pwiki/page.js index 6836ac9..6677330 100755 --- a/pwiki/page.js +++ b/pwiki/page.js @@ -151,9 +151,16 @@ object.Constructor('BasePage', { set args(args){ this.location = this.path +':'+ pwpath.obj2args(args) }, - // XXX do we need this... - get resolvedPath(){ - return this.match() }, + // NOTE: these are mostly here as helpers to be accessed via page + // actions... + // XXX should these be here or in Page??? + // XXX should this call .match(..) or .resolve(..)??? + get resolved(){ + return this.resolve() }, + get rootpath(){ + return this.root ? + this.root.path + : this.path }, // XXX should these be writable??? get name(){ @@ -575,6 +582,9 @@ object.Constructor('Page', BasePage, { // setup manually. render_root: undefined, + get renderer(){ + return (this.render_root || {}).path }, + // // () // -> @@ -1135,6 +1145,29 @@ object.Constructor('Page', BasePage, { 'join': ['macro'], }, + // direct actions... + // + // These are evaluated directly without the need to go through the + // whole page acquisition process... + // + // NOTE: these can not be overloaded. + // (XXX should this be so?) + actions: new Set([ + 'location', + 'referrer', + 'path', + 'name', + 'dir', + 'resolved', + 'rootpath', + 'renderer', + 'length', + 'type', + + //'ctime', + //'mtime', + ]), + // events... // // NOTE: textUpdate event will not get triggered if text is updated @@ -1182,6 +1215,25 @@ object.Constructor('Page', BasePage, { // // XXX revise how we handle .strict mode... get raw(){ return (async function(){ + // direct actions... + if(this.actions + && this.actions.has(this.name)){ + var name = this.name + var page = this.get('..') + var res = (this.isPattern + && !this.energetic) ? + page + .each() + .map(function(page){ + var res = page[name] + return typeof(res) == 'function' ? + res.call(page) + : res }) + : page[this.name] + return typeof(res) == 'function' ? + res.call(page) + : res } + var data = await this.data // no data... // NOTE: if we hit this it means that nothing was resolved, @@ -1471,6 +1523,13 @@ object.Constructor('pWikiPageElement', Page, { set __clone_proto__(value){ this.__clone_proto = value }, + actions: new Set([ + ...CachedPage.prototype.actions, + + 'title', + 'hash' + ]), + // NOTE: setting location will reset .hash set it directly via either // one of: // .location = [path, hash] @@ -1496,6 +1555,7 @@ object.Constructor('pWikiPageElement', Page, { .set.call(this, value) }, // XXX this is not persistent, is this what we want??? + // XXX should this default to .path or to .name??? get title(){ return this.dom.getAttribute('title') || (this.dom.querySelector('h1') || {}).innerText @@ -1670,7 +1730,7 @@ module.System = { - (@include(./*/count/!)) + (@include(./*/length/!))   × ` }, @@ -1749,28 +1809,6 @@ module.System = { // metadata... // - renderer: function(){ - return (this.render_root || {}).path }, - referrer: function(){ - return this.referrer || this.path }, - location: function(){ - return this.get('..').location }, - path: function(){ - return this.get('..').path }, - rootpath: function(){ - return this.root.path }, - resolved: async function(){ - return this.get('..').resolve() }, - dir: function(){ - return this.get('..').dir }, - name: function(){ - return this.get('..').name }, - title: function(){ - var p = this.get('..') - return p.title - ?? p.name }, - count: async function(){ - return this.get('..').length }, ctime: async function(){ var date = (await this.get('..').data).ctime return date ? @@ -1790,8 +1828,6 @@ module.System = { {energetic: true}), // XXX EXPERIMENTAL -- page types... - type: async function(){ - return await this.get('..').type }, isAction: async function(){ return await this.get('..').type == 'action' ? 'action' diff --git a/pwiki/store/base.js b/pwiki/store/base.js index 5bec6da..147c215 100755 --- a/pwiki/store/base.js +++ b/pwiki/store/base.js @@ -368,13 +368,16 @@ module.BaseStore = { if(path.includes('*') || path.includes('**')){ path = pwpath.split(path) + // normalize trailing '/'... + path.at(-1) == '' + && path.pop() // match basedir and addon basename to the result... - var name = path[path.length-1] + var name = path.at(-1) if(name && name != '' && !name.includes('*')){ path.pop() - path.push('') + //path.push('') return (await this.match(path.join('/'), strict)) .map(function(p){ return pwpath.join(p, name) }) } } @@ -751,6 +754,16 @@ module.MetaStore = { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// XXX not used... +var cacheProxy = function(name){ + var func = function(path, ...args){ + var cache = (this.root ?? this).cache + return cache[path] + ?? (cache[path] = + object.parentCall(CachedStore[name], this, ...arguments)) } + Object.defineProperty(func, 'name', {value: name}) + return func } + // XXX should this be a level-1 or level-2??? // XXX might be a fun idea to actually use this as a backend for BaseStore... // XXX make this a mixin... @@ -758,38 +771,45 @@ module.MetaStore = { // - timeout // - count // XXX TEST... -var CachedStoreMixin = -module.CachedStoreMixin = { - //__proto__: MetaStore, - - // format: - // { - // : , - // } - __cache_data: undefined, - get __cache(){ - return (this.__cache_data = this.__cache_data ?? {}) }, - set __cache(value){ +var CachedStore = +module.CachedStore = { + __proto__: MetaStore, + + __cache: undefined, + get cache(){ + return (this.__cache = this.__cache ?? {}) }, + set cache(value){ this.__cache_data = value }, - resetCache: function(){ - delete this.__cache_data + clearCache: function(){ + this.cache = {} return this }, - __exists__: async function(path){ - return path in this.__cache - || object.parentCall(CachedStoreMixin.__exists__, this, ...arguments) }, - __get__: async function(path){ - return this.__cache[path] - ?? (this.__cache[path] = - await object.parentCall(CachedStoreMixin.__get__, this, ...arguments)) }, - __update__: async function(path, data){ - // XXX this is wrong??? - this.__cache[path] = data - return object.parentCall(CachedStoreMixin.__update__, this, ...arguments) }, - __delete__: async function(path){ - delete this.__cache[path] - return object.parentCall(CachedStoreMixin.__delete__, this, ...arguments) }, + exists: async function(path){ + return path in this.cache + || object.parentCall(CachedStore.exists, this, ...arguments) }, + // XXX this sometimes caches promises... + get: async function(path){ + return this.cache[path] + ?? (this.cache[path] = + await object.parentCall(CachedStore.get, this, ...arguments)) }, + update: async function(path, data){ + this.cache[path] = data + return object.parentCall(CachedStore.update, this, ...arguments) }, + /* XXX + metadata: async function(path, data){ + if(data){ + // XXX this is wrong -- get merged data... + this.cache[path] = data + return object.parentCall(CachedStore.metadata, this, ...arguments) + } else { + return this.cache[path] + ?? (this.cache[path] = + await object.parentCall(CachedStore.metadata, this, ...arguments)) } }, + //*/ + delete: async function(path){ + delete this.cache[path] + return object.parentCall(CachedStore.delete, this, ...arguments) }, } @@ -798,7 +818,8 @@ module.CachedStoreMixin = { var Store = module.Store = - MetaStore + //MetaStore + CachedStore