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()