Login
Artifact [cf22d89d63]
Login

Artifact cf22d89d63575ab5b402d9bc9f5c068ec6527a62:


const CGI = api.cgi

const app = object{
    f: CGI.getFossilInstance(),
    out: CGI.out,
    version: CGI.getVar('version', 'trunk'),
    linkRoot: CGI.cgiRoot+'dir/', // fixme: isn't there a CGI var for this path?
    subDir: undefined /* set down below... */
}

app.subDirs = CGI.request.ENV.PATH_INFO.split('/')
assert app.subDirs.length() >= 2 /* From: "/dir" split ==> [null,'dir', ...] */
app.subDirs.shift() // 'null' split by leading slash
app.subDirs.shift() // assumes 'dir' is the first entry!
    
if(((var len = app.subDirs.length()), len)){
    app.subDirs.(len-1) || app.subDirs.pop() // trailing null from trailing slash
    app.subDir = app.subDirs.join('/')
    app.subDirDepth = app.subDirs.length()
}
//print('<br/>app.subDir=',app.subDir, app.subDirDepth)


//app.downloadPath = proc(fn){
//    return CGI.cgiRoot+'download/'+fn
//}

app.dirMatches = proc(dir){
    this.subDir || return true
    assert 'string' === typename dir
    const sd = (argv.callee.dir || (argv.callee.dir=this.subDir+'/'))
    return 0===dir.indexOf(sd)
}

app.isDir = proc(str){
    str || return false
    return 0x2f === str.byteAt(str.length()-1)
}

app.calcFileList = proc(deck, depth){
    const FC = deck.F
    FC || return
    const olist = object{}
    const flist = array[]
    const fcards = array[]
    //print("<br/>fc count =", FC.length())
    const self = this
    $FC.eachIndex proc(fc,i){
        self.dirMatches(fc.name) || return
        
        const li = fc.name.split('/'), len = li.length()
        //print('<br/>fc.name =',fc.name, 'len=',len)
        const part = li.(depth) // li.slice(depth,depth+1).join('/')
        if(len===(depth+1)){
            flist.push(part)
            fcards.push(fc)
        }
        (len>=(depth+2)) || return
        //const dest = array[]
        //print('<br/>part =',part)
        olist.(part) = true
    }
    //print("<br/>olist =",olist)
    //print("<br/>flist =",flist)
    const rc = olist.propertyKeys()
    rc.sort()
    //print("<br/>rc =",rc)
    return object{ dirs: rc, files: flist, fcards: fcards }
}

app.showBreadcrumb = proc(){
    const len = (this.subDirs.length() || return)
    const out = this.out
    const dirs = this.subDirs
    const ca = CGI.html.createAnchor
    const sep = ' / '
    const parts = array[]
    const self = this
    const link = proc(dir, label, sep = sep){
        //const ueDir = CGI.urlencode(dir)
        $out sep {<a class='dir-entry dir-entry-dir'}
        $out ' ' {style='display: inline'}
        // $out " title='" dir "'"
        $out " href='" dir  {?version=} CGI.urlencode(self.version) "'"
        $out {>} CGI.htmlEscape(label || dir) {</a>}
    }
    var i = 0
    $out {<div class='dir-breadcrumb-container'>}
    link( this.linkRoot, 'top', '' )
    var part
    for {}{i < len}{i+=1}{
        part = dirs.(i)
        if(i===len-1){
            $out sep {<span  class='dir-entry dir-entry-dir' style='display: inline'>} part {</span>}
        }else{
            parts.push(part)
            link( this.linkRoot + parts.join('/'), part )
        }
    }
    $out {</div>}
}

app.listFiles = proc(deck){
    const FC = deck.F
    if(!FC){
        this.out("Manifest contains no files.")
        return
    }
    assert 'array' === typename FC
    const fCount = FC.length(), i = 0
    //this.out("File count: ",fCount)
    const out = this.out

    const info = this.calcFileList(deck, this.subDirs ? this.subDirs.length() : 0)
    this.showBreadcrumb(info.dirs)

    const subDir = this.subDir
    const subDepth = app.subDirs.length()
    var linkRoot
    if(subDepth){
        linkRoot = this.linkRoot + app.subDirs.slice(0,subDepth).join('/') + '/'
    }else{
        linkRoot = this.linkRoot
    }
    //print('app.subDirs =',app.subDirs, subDepth, linkRoot, app.subDirs.slice(0,subDepth))
    this.out({<div class='dir-list-container'>})
    
    const self = this
    $info.dirs.eachIndex proc(v){
        $out ' ' {<div class='dir-entry'><span class='dir-entry-dir'><a}
        //$out " title='" CGI.urlencode(v) "'"
        $out " href='" linkRoot CGI.urlencode(v) {?version=} CGI.urlencode(self.version) "'"
        $out {>} CGI.htmlEscape(v) {/</a></span></div>}
    }

    const subDirLen = (subDir ? subDir.length() : 0)
    $info.fcards.eachIndex proc(fc){
        $out ' ' {<div class='dir-entry'><span class='dir-entry-file'>}
        //$out " href='" linkRoot CGI.urlencode(fc.name) "'"

        const fname = (subDirLen ? fc.name.substr(subDirLen+1/*slash*/) : fc.name);
        var url = CGI.cgiRoot.concat(
                'download/uuid/', fc.uuid,
                '?name=', CGI.urlencode(fname))
        $out {<span class='uuid'}
        $out " title='view/download " fc.uuid "'"
        $out {>} CGI.html.createAnchor(url, fc.uuid.substr(0,12)) {</span>}
        
        $out ' ' {<span class='filename dir-filename'>} fname {</span>}

        $out {</span><!-- .dir-entry-file --></div><!-- .dir-entry -->}
    }
    this.out({</div><!-- .dir-list-container -->})
    //out({<pre>} CGI.toJSONString(info) {</pre>})
}

app.ls = proc(){
    const deck = app.f.loadManifest(this.version, true, false)
    assert deck
    if(Fossil.artifactTypes.CHECKIN !== deck.type){
        throw api.Exception(this.f.rc.TYPE, "Version ".concat(this.version,' is not a checkin.'))
    }
    
    this.listFiles(deck)
    
}.importSymbols('Fossil')


app.run = proc(){
    assert this.isDir('/')
    assert !this.isDir('/a')
    this.ls()
}

CGI.html.injectCssLink(CGI.cgiRoot+'download/css/dir.css')
//$out {<style type='text/css'>}
//Fossil.file.passthrough(Fossil.file.dirPart(__FILE)+'dir.css')
//$out {</style>}

//$app.out R.routeAfterApp {<br/>}
var mlink = CGI.html.createAnchor( CGI.cgiRoot + 'manifest/'+CGI.urlencode(app.version), app.version)
$app.out {<h2>File listing for repo version [} mlink {]}
app.subDir && $app.out ' for subdir [' app.subDir ']'
$app.out {:</h2>}

app.run()