var fb_debug={};(function($){$.fn.filebrowser=function(opts)
{opts=$.extend({dir_open_time:0,dir_close_time:0,hide_iframe:true,show_upload:true,show_info:true,show_preview:true,show_actions:true,show_action_delete:true,show_action_rename:true,show_action_move:true,show_action_mkdir:true,show_action_download:true,enable_drag:true,use:null,use_valid:null,select:null,dblclick:null,root:''},opts);var selection=null;var root_node=null;var upload=null;var upload_que=[];function Node(parent,data,injecting)
{if(!data&&!injecting)
{var from=parent;if(typeof(from)=='object')
{if(from.jquery)
{return $.data(from.closest('li')[0],'filebrowser-node');}
return from;}
else if(typeof(from)=='string')
{if(opts.root&&from.indexOf(opts.root)!=0)
{return null;}
from=from.slice(opts.root.length);if(from.length>1&&from[0]!='/')
{return null;}
from=from.slice(1);if(!from)
{return root_node;}
var node=root_node;var names=from.replace(/^\/|\/$/,'').split('/');for(var i in names)
{var name=names[i];var found=false;for(var j in node.children)
{if(node.children[j].name==name)
{node=node.children[j];found=true;break;}}
if(!found)
{return null;}}
return node;}
return null;}
var _update_keys=['name','type','size','mtime'];this._update=function(data)
{for(var i in _update_keys)
{if(typeof(data[_update_keys[i]])!='undefined')
{this[_update_keys[i]]=data[_update_keys[i]];}}}
this.update=function(callback)
{var node=this;api({method:'files.get_tree',path:this.get_path()},function(res)
{node.name=res.name;node.size=res.size;node.mtime=res.mtime;node.a.text(node.name);if(node.type=='dir')
{node.remove_children();for(var i in res.children)
{new Node(node,res.children[i]);}}
if(callback)
{callback.call(node,res);}});}
this.remove=function()
{if(this.parent)
{for(var i in this.parent.children)
{if(this===this.parent.children[i])
{this.parent.children.splice(i,1);break;}}}
this.li.remove();this.parent=null;}
this.remove_children=function()
{this.children=[];if(this.list)
{this.list.empty();}}
this.get_path=function()
{var path='';var node=this;while(node.parent)
{path=node.name+(path?'/'+path:'');node=node.parent;}
path='/'+opts.root+'/'+(path?'/'+path:'');return path.replace(/\/+/g,'/');}
this.get_dir_node=function()
{return this.type=='dir'?this:this.parent;}
this.sort=function()
{this.children.sort(function(a,b)
{return a.name.toLowerCase()>b.name.toLowerCase()?1:-1;});for(var i in this.children)
{this.children[i].li.appendTo(this.list);}}
this._build_markup=function()
{var node=this;node.li=$('<li class="node" />');$.data(node.li[0],'filebrowser-node',node);if(node.parent&&node.parent.list)
{node.li.appendTo(node.parent.list);}
node.a=$('<a href="#" />').text(node.name).attr('rel',node.get_path()).appendTo(node.li).click(function(e)
{e.preventDefault();node.select();});if(opts.dblclick)
{node.a.dblclick(opts.dblclick);}
if(node.type=='file')
{node.a.addClass('ext_'+os.path.ext(node.name));}
if(opts.enable_drag&&node.parent)
{node.a.draggable({distance:20,revert:'invalid',helper:'clone',containment:tree});}
if(node.type=='dir')
{node._build_dir_markup();}}
this._build_dir_markup=function()
{var node=this;node.li.addClass('directory closed');node.toggle=$('<div class="toggle">&nbsp;</div>').prependTo(node.li);if(opts.enable_drag)
{node.li.droppable({greedy:true,hoverClass:'drop-hover',accept:function(draggable)
{var droppable=$(this);var drop_path=droppable.find('a:first').attr('rel');var drag_path=draggable.attr('rel');return drop_path.indexOf(drag_path)<0;},drop:function(e,ui)
{var draggable=ui.draggable;var drag_path=draggable.attr('rel');var drag_node=Node(draggable);var drop_path=node.get_path()
var new_path=drop_path+'/'+drag_node.name;function move(exists)
{if(exists&&!confirm('There is already a file by that name. Would you like to replace it?'))
{return;}
drag_node.move(new_path,true);}
if(node.state!='open')
{api({method:'files.get_node',path:new_path},function(res){move(true)},function(res){move(false);});}
else
{move(Node(new_path));}
$('.drop-hover').removeClass('drop-hover');}});}
node.state='closed'
node._change_state=function(new_state)
{node.li.removeClass(node.state).addClass(new_state)
node.state=new_state;}
node.open_directory=function(callback)
{node.list=$('<ol class="list" />').hide().appendTo(node.li);node._change_state('loading');node.update(function(res)
{node._change_state('opening');node.list.slideDown(opts.dir_open_time,function()
{node._change_state('open');if(callback)
{callback();}});});}
node.close_directory=function(callback)
{if(node.li.find('.selected').length)
{node.select();}
node._change_state('closing');node.list.slideUp(opts.dir_close_time,function()
{node.remove_children();node.list.remove();node._change_state('closed');if(callback)
{callback();}});}
function toggle()
{if(node.state=='closed')
{node.open_directory();}
if(node.state=='open')
{node.close_directory();}}
node.a.dblclick(toggle);node.toggle.click(toggle);}
this.refresh=function()
{var node=this;if(node.state=='open')
{node.close_directory(function()
{node.open_directory(function()
{node.select();});});}
else if(node.state=='closed')
{node.open_directory(function()
{node.select();});}}
this.delete_=function()
{if(this===root_node)
{throw"You cannot delete the root.";}
var node=this;api({method:'files.delete',path:node.get_path()},function(res)
{node.parent.select();node.remove();});}
this.move=function(new_path,force)
{if(this===root_node)
{throw"You cannot move the root.";}
var node=this;if(!force&&Node(new_path))
{return false}
api({method:'files.move',from:node.get_path(),to:new_path},function(res)
{var existing=Node(new_path);if(existing)
{existing.remove();}
(new Node(Node(os.path.dirname(new_path)),res,true)).select();node.remove();});return true}
this.mkdir=function(name)
{var node=this;var path=this.get_path()+'/'+name;if(Node(path))
{return false;}
api({method:'files.mkdir',path:path},function(res)
{new Node(node,res,true);});return true;}
this.select=function()
{var node=this;if(selection)
{selection.a.removeClass('selected');}
this.a.addClass('selected');selection=this;if(opts.show_info)
{update_info(this);}
if(opts.select)
{opts.select(this);}}
this.children=[]
this.parent=parent;if(parent)
{parent.children.push(this);}
this.name='';this.size=0;this.type=null;this._update(data);this._build_markup();if(injecting)
{this.parent.sort();}}
Node.insert_upload=function(path)
{var parent=Node(os.path.dirname(path));if(parent)
{api({method:'files.get_node',path:path},function(res)
{new Node(parent,res,true);});}}
function Upload(opts)
{var upload=this;console.log('new Upload',opts);this._build_markup=function()
{this.li=$('<li />').appendTo(upload_que_list);this.name=$('<div class="name" />').text(this.name).appendTo(this.li);this.cancel=$('<a href="#" class="cancel">(cancel)</a>').appendTo(this.li).click(function(e)
{e.preventDefault();e.stopPropagation();if(upload.running)
{if(!confirm('Are you sure you want to cancel an upload in progress?'))
{return;}
else
{uploader.cancel(upload.id);upload.remove();Upload.prod_que();}}
else
{upload.remove();}
upload.li.addClass('error');upload.cancel.remove();upload.status.text('Cancelled. Click to close.');});this.status=$('<div class="status" />').text('Waiting to start.').appendTo(this.li);this.progress=$('<div>&nbsp</div>').appendTo($('<div class="progress" />').appendTo(this.li));this.message=$('<div class="message">Waiting to start.</div>').appendTo(this.li);this.eta=$('<div class="eta">&nbsp;</div>').appendTo(this.li);}
this.set_progress=function(amount)
{this.progress.width(Math.round(amount*1000)/10+'%');}
this.get_speed=function()
{while(this.speeds.length>30)
{this.speeds.shift();}
var speed=0;for(var i in this.speeds)
{speed+=this.speeds[i];}
return speed/this.speeds.length;}
this.calc_eta=function()
{var speed=this.get_speed();var mode_string=this.eta_mode?'Eta: ':'Elapsed: ';var eta=this.eta_mode?(this.size-this.last_bytes)/speed:(new Date()-this.start_time)/1000;if(speed||!this.eta_mode)
{eta=formatTime(eta);this.eta.text(mode_string+eta);}
else
{this.eta.text(mode_string+'Unknown.');}
return speed}
this.remove=function()
{this.li.click(function()
{$(this).fadeOut(function()
{$(this).remove();});});setTimeout(function()
{upload.li.fadeOut(function()
{upload.li.remove();});},2500);this.cancel.fadeOut();for(var i in Upload.que)
{if(this==Upload.que[i])
{Upload.que.splice(i,1);break;}}
delete Upload.id_map[this.id];uploader.removeFile(this.id);}
if(opts=='debug')
{this.name='Debugging file.ext'
this.size=1024
this.path='/testing.ext'
this._build_markup();this.set_progress(.45);return}
this.id=opts.id;this.name=opts.name;this.size=opts.size;this.dir=selection.get_dir_node().get_path();this.path=(this.dir+'/'+this.name).replace(/\/+/g,'/');existing=Node(this.path)
if(existing&&!confirm('There is already a file by that name. Would you like to upload anyways, and have a number automatically added to the name?'))
{uploader.removeFile(opts.id);return this;}
this._build_markup();this.warned_about_collision=existing?true:false;Upload.que.push(this);Upload.id_map[opts.id]=this;Upload.prod_que();}
Upload.que=[];Upload.id_map={};Upload.onSelect=function(e)
{for(var id in e.fileList)
{if(!Upload.id_map[id])
{new Upload(e.fileList[id]);}}};Upload.onStart=function(e)
{console.log('onStart',e);Upload.id_map[e.id].status.text('Starting...');};Upload.onProgress=function(e)
{var upload=Upload.id_map[e.id];var delta_time=(new Date())-upload.last_time;var delta_bytes=e.bytesLoaded-upload.last_bytes;upload.last_time=new Date();upload.last_bytes=e.bytesLoaded;var speed=1000*delta_bytes/delta_time;upload.speeds.push(speed);speed=upload.calc_eta();upload.status.text(speed?formatSize(speed)+'/s.':"Stalled.");upload.message.text('Uploaded '+formatSize(e.bytesLoaded)+' of '+formatSize(e.bytesTotal)+'.');upload.set_progress(e.bytesLoaded/e.bytesTotal);};Upload.onCancel=function(e)
{};Upload.onComplete=function(e)
{var upload=Upload.id_map[e.id];console.log('onComplete',upload);upload.status.text('DONE - Click to remove.')
upload.set_progress(1);upload.li.addClass('success');Node.insert_upload(upload.path);upload.eta.unbind('click');upload.eta_mode=false;upload.calc_eta();upload.message.text('Your file is now availible at '+upload.path+'.'+(upload.warned_about_collision?' It needed to be renamed slightly because another file by the same name already existed.':''));upload.remove()
Upload.prod_que();};Upload.onResult=function(e)
{};Upload.onError=function(e)
{var upload=Upload.id_map[e.id];console.log('onError',upload);upload.status.text('Failed.');upload.set_progress(1);upload.li.addClass('error')
upload.eta.remove();upload.message.text('The upload failed, and the server told us "'+res.message+'". Please try again later.');upload.remove();Upload.prod_que();};Upload.prod_que=function()
{if(!Upload.que.length||Upload.que[0].running)
{return null}
var upload=Upload.que[0];upload.running=true;upload.status.text('Negotiating with server.');upload.start_time=new Date();upload.li.addClass('uploading');upload.last_time=new Date();upload.last_bytes=0;upload.speeds=[];upload.eta_mode=true;upload.eta.click(function()
{upload.eta_mode=!upload.eta_mode;upload.calc_eta();});uploader.upload(upload.id,'/files.cgi','GET',{token:$.cookie('user_token'),path:upload.dir,size:upload.size},'file');}
function update_info(node)
{if(opts.show_upload)
{if(upload_path)
{upload_path.text((opts.root?'':root_node.name)+(node.type=='dir'?node:node.parent).get_path());}}
function add_field(name,contents)
{return $('<li />').addClass('field-'+name.toLowerCase().replace(/\W+/g,'_')).appendTo(info).text(contents).prepend($('<span />').text(name+':'))}
info.empty();if(opts.show_preview)
{switch(os.path.ext(node.get_path()))
{case'jpeg':case'jpg':case'gif':case'png':var preview_field=add_field('Preview','');var pw=preview_field.width();var new_img=$('<img class="preview" />').attr('src','/thumb/'+node.get_path()).appendTo(preview_field);break;}}
add_field('Name',node.name);add_field('Modification time',node.mtime?(new Date(node.mtime*1000)).toLocaleString():'Unknown');if(node.type=='file')
{add_field('Size',formatSize(node.size));}
if(!opts.show_actions)
{return;}
var actions=add_field('Actions','');if(false&&node.parent)
{button({message:'Select parent directory',silk:'folder',click:function()
{select(node.parent);}}).appendTo(actions);}
if(node.type=='dir')
{button({message:'Refresh contents',silk:'arrow_refresh',click:function(){node.refresh();}}).appendTo(actions);}
if(opts.show_action_delete&&node.parent)
{button({silk:'delete',message:'Delete',click:function()
{if(confirm('Are you sure you want to delete "'+node.name+'"?'))
{node.delete_()}}}).appendTo(actions);}
if(opts.show_action_rename&&node.parent)
{button({silk:'textfield_rename',message:'Rename',click:function()
{var name=prompt('Enter a new name.');if(!name)
{return;}
var old_ext=os.path.ext(node.name);var new_ext=os.path.ext(name);if(new_ext!=old_ext)
{if(old_ext&&new_ext&&!confirm('Are you sure you want to change the file extension from "'+old_ext+'" to "'+new_ext+'"?'))
{return;}
else if(!old_ext&&!confirm('Are you sure you want to add the file extension "'+new_ext+'"?'))
{return;}
else if(!new_ext&&!confirm('Are you sure you want to remove the file extension "'+old_ext+'"?'))
{return;}}
var new_path=node.parent.get_path();new_path+=(new_path?'/':'')+name;if(!node.move(new_path))
{alert('A file by that name already exists');}}}).appendTo(actions);}
if(opts.show_action_mkdir)
{button({silk:'folder_add',message:'Make a new directory'+(node.type=='file'?' beside this file':''),click:function()
{var name=prompt('Enter a name for the new directory.');if(!name)
{return;}
var parent=node.type=='file'?node.parent:node;if(!parent.mkdir(name))
{alert('A file by that name already exists.');}}}).appendTo(actions);}
if(opts.show_action_download&&node.type=='file')
{button({silk:'page_white_put',message:'Download',href:'/files/'+node.get_path()}).appendTo(actions);}
if(opts.use&&(!opts.use_valid||opts.use_valid(node)))
{button({silk:'accept',message:'Use this '+(node.type=='file'?'file':'directory')+'.',click:function()
{opts.use(node);}}).appendTo(actions);}}
this.addClass('filebrowser');var tree=$('<div class="tree" />').appendTo(this);var tree_list=$('<ol class="list" />').appendTo(tree);if(opts.show_info)
{var info=$('<ul class="info" />').appendTo(this);}
var root_node=new Node(null,{name:'Loading...',type:'dir'});if(opts.show_upload)
{$('<h2>File Uploads</h2>').appendTo(this);var version=getFlashVersion().split(',').shift();if(version<9)
{$('#flash-warning').show();}
else
{var upload_div=$('<div class="que" />').appendTo(this);var upload_que_list=$('<ol/>').appendTo(upload_div)
$('<h4>Add a file to the upload que:</h4>').appendTo(upload_div);$('<h5>It will be uploaded into:</h5>').appendTo(upload_div);var upload_path=$('<h6 />').appendTo(upload_div);var upload_container=$('<div id="upload-button" />').appendTo(upload_div).css({position:'relative'});var upload_button=button({message:"Add File to Que",silk:'add',click:function()
{}}).appendTo(upload_container).css({margin:0});$('<div id="upload-button-flash"/>').appendTo(upload_container).css({width:upload_button.outerWidth(false),height:upload_button.outerHeight(false),position:'absolute',top:0,left:0,zIndex:1});YAHOO.widget.Uploader.SWFURL='/uploader.swf';var uploader=new YAHOO.widget.Uploader('upload-button-flash');uploader.addListener('contentReady',function()
{uploader.setSimUploadLimit(1);uploader.setAllowMultipleFiles(true);});uploader.addListener('fileSelect',Upload.onSelect);uploader.addListener('uploadStart',Upload.onStart);uploader.addListener('uploadProgress',Upload.onProgress);uploader.addListener('uploadCancel',Upload.onCancel);uploader.addListener('uploadComplete',Upload.onComplete);uploader.addListener('uploadCompleteData',Upload.onResult);uploader.addListener('uploadError',Upload.onError);}}
root_node.li.appendTo(tree_list);root_node.open_directory(function()
{root_node.select();root_node.a.text(root_node.name);});root_node.select();if(false)
{var dbg_upload=new Upload('debug');dbg_upload.eta.text('ETA 12:34');dbg_upload=new Upload('debug');dbg_upload.message.text('Your file is now avilaible at /path');dbg_upload.li.addClass('success');dbg_upload=new Upload('debug');dbg_upload.message.text('Your file is now availible at /path. It needed to be moved.');dbg_upload.li.addClass('notice');dbg_upload=new Upload('debug');dbg_upload.message.text('Nothing scary happened.');dbg_upload.li.addClass('error');}
fb_debug.Node=Node;return this;}})(jQuery);