mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-29 18:10:09 +00:00
sorting mostly done -- still rough corners remaining...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
b4b39b4de9
commit
23c3c3ad4f
@ -558,25 +558,16 @@ object.Constructor('BasePage', {
|
||||
|
||||
// sorting...
|
||||
//
|
||||
// XXX should this be page-level (current) store level???
|
||||
// XXX when this is async, should this return a promise????
|
||||
sort: async function(cmp){
|
||||
// not sorting single pages...
|
||||
//if(this.length <= 1){
|
||||
if(!this.isPattern){
|
||||
return this }
|
||||
// sort...
|
||||
sort: async function(...cmp){
|
||||
// normalize to path...
|
||||
this.metadata =
|
||||
{ order: (await this.each())
|
||||
.sort(...arguments)
|
||||
.map(function(p){
|
||||
return p.path }) }
|
||||
{ order: await this.store.sort(this.path, ...cmp) }
|
||||
return this },
|
||||
reverse: async function(){
|
||||
// not sorting single pages...
|
||||
if(this.length <= 1){
|
||||
return this }
|
||||
this.metadata = { order: (await this.match()).reverse() }
|
||||
this.sort('reverse')
|
||||
return this },
|
||||
|
||||
//
|
||||
|
||||
@ -643,6 +643,7 @@ module.BaseStore = {
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// .exists(<path>)
|
||||
// -> <normalized-path>
|
||||
@ -689,6 +690,83 @@ module.BaseStore = {
|
||||
return false }
|
||||
return pwpath.joinArgs(res, args) },
|
||||
//*/
|
||||
|
||||
// XXX EXPERIMENTAL...
|
||||
// XXX should we handle undefined attr values???
|
||||
// XXX BUG: chains still not working correctly...
|
||||
sort: function(paths, ...by){
|
||||
var that = this
|
||||
paths =
|
||||
(paths.includes('*')
|
||||
|| paths.includes('**')) ?
|
||||
this.match(paths).iter()
|
||||
: paths
|
||||
var _async = false
|
||||
return paths
|
||||
// pre-fetch all the needed data...
|
||||
// XXX we can try and make this lazy and only get the data
|
||||
// we need when we need it (in sort)...
|
||||
// ...not sure if this is worth it...
|
||||
.map(function(p, i){
|
||||
var d
|
||||
var res = []
|
||||
for(var cmp of by){
|
||||
res.push(
|
||||
(cmp == 'path'
|
||||
|| cmp == 'location') ?
|
||||
p
|
||||
: cmp == 'dir' ?
|
||||
pwpath.dirname(p)
|
||||
: cmp == 'name' ?
|
||||
pwpath.basename(p)
|
||||
: cmp == 'title' ?
|
||||
pwpath.decodeElem(
|
||||
pwpath.basename(p))
|
||||
: cmp == 'depth' ?
|
||||
pwpath.split(p).length
|
||||
// async attr...
|
||||
: typeof(cmp) == 'string' ?
|
||||
// NOTE: we only get page data once per page...
|
||||
(d = d ?? that.get(p))
|
||||
.then(function(data){
|
||||
return data[cmp] })
|
||||
: null) }
|
||||
_async = _async || !!d
|
||||
return d ?
|
||||
// wait for data to resolve...
|
||||
Promise.all([i, p, Promise.all(res)])
|
||||
: [i, p, res] })
|
||||
// NOTE: if one of the sort attrs is async we need to wrap the
|
||||
// whole thing in a promise...
|
||||
.run(function(){
|
||||
return _async ?
|
||||
Promise.all(this).iter()
|
||||
: this })
|
||||
.sort(function([ia, a, ca], [ib, b, cb]){
|
||||
for(var [i, cmp] of by.entries()){
|
||||
var res =
|
||||
typeof(cmp) == 'string' ?
|
||||
((ca[i] == null
|
||||
&& cb[i] == null) ?
|
||||
0
|
||||
: (cb[i] == null
|
||||
|| ca[i] < cb[i]) ?
|
||||
-1
|
||||
: (ca[i] == null
|
||||
|| ca[i] > cb[i]) ?
|
||||
1
|
||||
: 0)
|
||||
: typeof(cmp) == 'function' ?
|
||||
cmp(a, b)
|
||||
: 0
|
||||
// got a non equal...
|
||||
if(res != 0){
|
||||
return res } }
|
||||
// keep positions if all comparisons are equal...
|
||||
return ia - ib })
|
||||
.map(function([_, p]){
|
||||
return p }) },
|
||||
|
||||
// find the closest existing alternative path...
|
||||
find: async function(path, strict=false){
|
||||
var {path, args} = pwpath.splitArgs(path)
|
||||
@ -709,7 +787,6 @@ module.BaseStore = {
|
||||
: '/'+p
|
||||
if(pages.has(p)){
|
||||
return p+args } } },
|
||||
|
||||
//
|
||||
// Resolve page for path
|
||||
// .match(<path>)
|
||||
@ -802,19 +879,20 @@ module.BaseStore = {
|
||||
// pattern match * / **
|
||||
if(path.includes('*')
|
||||
|| path.includes('**')){
|
||||
var order = (this.metadata(path) ?? {}).order || []
|
||||
|
||||
var {path, args} = pwpath.splitArgs(path)
|
||||
path = pwpath.sanitize(path)
|
||||
|
||||
var all = args.all
|
||||
var sort = args.sort
|
||||
var test = await this.__match_args(args)
|
||||
args = pwpath.joinArgs('', args)
|
||||
|
||||
var order = (await this.metadata(path) ?? {}).order || []
|
||||
|
||||
// NOTE: we are matching full paths only here so leading and
|
||||
// trainling '/' are optional...
|
||||
var pattern = new RegExp(`^\\/?`
|
||||
+RegExp.quoteRegExp(
|
||||
// remove leading/trailing '/'
|
||||
path.replace(/^\/|\/$/g, ''))
|
||||
+RegExp.quoteRegExp(path)
|
||||
// pattern: **
|
||||
.replace(/\\\*\\\*/g, '(.*)')
|
||||
// pattern: *
|
||||
@ -860,7 +938,13 @@ module.BaseStore = {
|
||||
m[0].slice(1)
|
||||
: m[0])
|
||||
return res }, new Set())]
|
||||
.sortAs(order)
|
||||
// handle live sort...
|
||||
.run(function(){
|
||||
return (sort && sort !== true) ?
|
||||
that
|
||||
.sort(this, ...sort.split(/\s*[,\s]+/g))
|
||||
:this
|
||||
.sortAs(order) })
|
||||
.map(function(p){
|
||||
return p+args })}
|
||||
// direct search...
|
||||
|
||||
@ -36,8 +36,12 @@
|
||||
* -
|
||||
*
|
||||
*
|
||||
* XXX sort: define a generic sort path argument...
|
||||
* ...this will unify all interfaces (macros/patterns/etc)
|
||||
* XXX sort: define a generic sort path argument... DONE-ish
|
||||
* XXX sort chains still not totally correct...
|
||||
* This correctly shows Doc and WikiHome first
|
||||
* await pwiki.store.sort('*', 'tags')
|
||||
* This mixes them back up:
|
||||
* await pwiki.store.sort('*', 'tags', 'ctime')
|
||||
* XXX macros: else/default macro args essentially mean the same thing, should we
|
||||
* unify them to use the same name???
|
||||
* XXX parser: error handling: revise page quoting...
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user