@ -4,8 +4,9 @@ define([
'/common/common-hash.js' ,
'/common/common-realtime.js' ,
'/common/common-constants.js' ,
'/common/outer/userObject.js' ,
'/customize/messages.js'
] , function ( AppConfig , Util , Hash , Realtime , Constants , Messages) {
] , function ( AppConfig , Util , Hash , Realtime , Constants , OuterFO, Messages) {
var module = { } ;
var ROOT = module . ROOT = "root" ;
@ -13,15 +14,10 @@ define([
var TRASH = module . TRASH = "trash" ;
var TEMPLATE = module . TEMPLATE = "template" ;
var clone = function ( o ) {
try { return JSON . parse ( JSON . stringify ( o ) ) ; }
catch ( e ) { return undefined ; }
} ;
module . init = function ( files , config ) {
var exp = { } ;
var pinPads = config . pinPads ;
var loggedIn = config . loggedI n;
var sframeChan = config . sframeChan ;
var FILES _DATA = module . FILES _DATA = exp . FILES _DATA = Constants . storageKey ;
var OLD _FILES _DATA = module . OLD _FILES _DATA = exp . OLD _FILES _DATA = Constants . oldStorageKey ;
@ -39,7 +35,7 @@ define([
} ;
var log = config . log || logging ;
var logError = config . logError || logging ;
var debug = config. debug || logging ;
var debug = exp. debug = config. debug || logging ;
var error = exp . error = function ( ) {
exp . fixFiles ( ) ;
console . error . apply ( console , arguments ) ;
@ -48,6 +44,11 @@ define([
// TODO: workgroup
var workgroup = config . workgroup ;
if ( pinPads ) {
// Extend "exp" with methods used only outside of the iframe (requires access to store)
OuterFO . init ( config , exp , files ) ;
}
/ *
* UTILS
@ -146,22 +147,6 @@ define([
if ( type === 'name' ) { return data . filename ; }
return data . filename || data . title || NEW _FILE _NAME ;
} ;
exp . getPadAttribute = function ( href , attr , cb ) {
cb = cb || function ( ) { } ;
var id = exp . getIdFromHref ( href ) ;
if ( ! id ) { return void cb ( null , undefined ) ; }
var data = getFileData ( id ) ;
cb ( null , clone ( data [ attr ] ) ) ;
} ;
exp . setPadAttribute = function ( href , attr , value , cb ) {
cb = cb || function ( ) { } ;
var id = exp . getIdFromHref ( href ) ;
if ( ! id ) { return void cb ( "E_INVAL_HREF" ) ; }
if ( ! attr || ! attr . trim ( ) ) { return void cb ( "E_INVAL_ATTR" ) ; }
var data = getFileData ( id ) ;
data [ attr ] = clone ( value ) ;
cb ( null ) ;
} ;
// PATHS
@ -473,7 +458,7 @@ define([
* OPERATIONS
* /
var getAvailableName = function ( parentEl , name ) {
var getAvailableName = exp . getAvailableName = function ( parentEl , name ) {
if ( typeof ( parentEl [ name ] ) === "undefined" ) { return name ; }
var newName = name ;
var i = 1 ;
@ -484,84 +469,17 @@ define([
return newName ;
} ;
// FILES DATA
exp . pushData = function ( data , cb ) {
if ( typeof cb !== "function" ) { cb = function ( ) { } ; }
var todo = function ( ) {
var id = Util . createRandomInteger ( ) ;
files [ FILES _DATA ] [ id ] = data ;
cb ( null , id ) ;
} ;
if ( ! loggedIn || ! AppConfig . enablePinning || config . testMode ) {
return void todo ( ) ;
}
if ( ! pinPads ) { return ; }
pinPads ( [ Hash . hrefToHexChannelId ( data . href ) ] , function ( obj ) {
if ( obj && obj . error ) { return void cb ( obj . error ) ; }
todo ( ) ;
} ) ;
} ;
var spliceFileData = exp . removeData = function ( id ) {
delete files [ FILES _DATA ] [ id ] ;
} ;
// MOVE
var pushToTrash = function ( name , element , path ) {
var trash = files [ TRASH ] ;
if ( typeof ( trash [ name ] ) === "undefined" ) { trash [ name ] = [ ] ; }
var trashArray = trash [ name ] ;
var trashElement = {
element : element ,
path : path
} ;
trashArray . push ( trashElement ) ;
} ;
var copyElement = function ( elementPath , newParentPath ) {
if ( comparePath ( elementPath , newParentPath ) ) { return ; } // Nothing to do...
var element = find ( elementPath ) ;
var newParent = find ( newParentPath ) ;
// Move to Trash
if ( isPathIn ( newParentPath , [ TRASH ] ) ) {
if ( ! elementPath || elementPath . length < 2 || elementPath [ 0 ] === TRASH ) {
debug ( "Can't move an element from the trash to the trash: " , elementPath ) ;
return ;
}
var key = elementPath [ elementPath . length - 1 ] ;
var elName = isPathIn ( elementPath , [ 'hrefArray' ] ) ? getTitle ( element ) : key ;
var parentPath = elementPath . slice ( ) ;
parentPath . pop ( ) ;
pushToTrash ( elName , element , parentPath ) ;
return true ;
}
// Move to hrefArray
if ( isPathIn ( newParentPath , [ 'hrefArray' ] ) ) {
if ( isFolder ( element ) ) {
log ( Messages . fo _moveUnsortedError ) ;
return ;
} else {
if ( elementPath [ 0 ] === newParentPath [ 0 ] ) { return ; }
var fileRoot = newParentPath [ 0 ] ;
if ( files [ fileRoot ] . indexOf ( element ) === - 1 ) {
files [ fileRoot ] . push ( element ) ;
}
return true ;
var move = exp . move = function ( paths , newPath , cb ) {
if ( sframeChan ) {
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "move" ,
data : {
paths : paths ,
newPath : newPath
}
} , cb ) ;
}
// Move to root
var newName = isFile ( element ) ?
getAvailableName ( newParent , Hash . createChannelId ( ) ) :
isInTrashRoot ( elementPath ) ?
elementPath [ 1 ] : elementPath . pop ( ) ;
if ( typeof ( newParent [ newName ] ) !== "undefined" ) {
log ( Messages . fo _unavailableName ) ;
return ;
}
newParent [ newName ] = element ;
return true ;
} ;
var move = exp . move = function ( paths , newPath , cb ) {
// Copy the elements to their new location
var toRemove = [ ] ;
paths . forEach ( function ( p ) {
@ -573,13 +491,21 @@ define([
return ;
}
// Try to copy, and if success, remove the element from the old location
if ( copyElement( p . slice ( ) , newPath ) ) {
if ( exp. copyElement( p . slice ( ) , newPath ) ) {
toRemove . push ( p ) ;
}
} ) ;
exp . delete ( toRemove , cb ) ;
} ;
exp . restore = function ( path , cb ) {
if ( sframeChan ) {
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "restore" ,
data : {
path : path
}
} , cb ) ;
}
if ( ! isInTrashRoot ( path ) ) { return ; }
var parentPath = path . slice ( ) ;
parentPath . pop ( ) ;
@ -589,165 +515,66 @@ define([
// ADD
var add = exp . add = function ( id , path ) {
if ( ! loggedIn && ! config . testMode ) { return ; }
var data = files [ FILES _DATA ] [ id ] ;
if ( ! data || typeof ( data ) !== "object" ) { return ; }
var newPath = path , parentEl ;
if ( path && ! Array . isArray ( path ) ) {
newPath = decodeURIComponent ( path ) . split ( ',' ) ;
}
// Add to href array
if ( path && isPathIn ( newPath , [ 'hrefArray' ] ) ) {
parentEl = find ( newPath ) ;
parentEl . push ( id ) ;
return ;
}
// Add to root if path is ROOT or if no path
var filesList = getFiles ( [ ROOT , TRASH , 'hrefArray' ] ) ;
if ( path && isPathIn ( newPath , [ ROOT ] ) || filesList . indexOf ( id ) === - 1 ) {
parentEl = find ( newPath || [ ROOT ] ) ;
if ( parentEl ) {
var newName = getAvailableName ( parentEl , Hash . createChannelId ( ) ) ;
parentEl [ newName ] = id ;
return ;
exp . addFolder = function ( folderPath , name , cb ) {
if ( sframeChan ) {
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "addFolder" ,
data : {
path : folderPath ,
name : name
}
} , cb ) ;
}
} ;
exp . addFolder = function ( folderPath , name , cb ) {
var parentEl = find ( folderPath ) ;
var folderName = getAvailableName ( parentEl , name || NEW _FOLDER _NAME ) ;
parentEl [ folderName ] = { } ;
var newPath = folderPath . slice ( ) ;
newPath . push ( folderName ) ;
cb ( void 0 , {
cb ( {
newPath : newPath
} ) ;
} ;
// FORGET (move with href not path)
exp . forget = function ( href ) {
var id = getIdFromHref ( href ) ;
if ( ! id ) { return ; }
if ( ! loggedIn && ! config . testMode ) {
// delete permanently
exp . removePadAttribute ( href ) ;
spliceFileData ( id ) ;
return ;
}
var paths = findFile ( id ) ;
move ( paths , [ TRASH ] ) ;
} ;
// DELETE
// Permanently delete multiple files at once using a list of paths
// NOTE: We have to be careful when removing elements from arrays (trash root, unsorted or template)
var removePadAttribute = exp . removePadAttribute = function ( f ) {
if ( typeof ( f ) !== 'string' ) {
console . error ( "Can't find pad attribute for an undefined pad" ) ;
return ;
}
Object . keys ( files ) . forEach ( function ( key ) {
var hash = f . indexOf ( '#' ) !== - 1 ? f . slice ( f . indexOf ( '#' ) + 1 ) : null ;
if ( hash && key . indexOf ( hash ) === 0 ) {
debug ( "Deleting pad attribute in the realtime object" ) ;
delete files [ key ] ;
exp . delete = function ( paths , cb , nocheck ) {
if ( sframeChan ) {
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "delete" ,
data : {
paths : paths ,
nocheck : nocheck
}
} ) ;
} ;
var checkDeletedFiles = function ( ) {
// Nothing in OLD_FILES_DATA for workgroups
if ( workgroup || ( ! loggedIn && ! config . testMode ) ) { return ; }
var filesList = getFiles ( [ ROOT , 'hrefArray' , TRASH ] ) ;
getFiles ( [ FILES _DATA ] ) . forEach ( function ( id ) {
if ( filesList . indexOf ( id ) === - 1 ) {
spliceFileData ( id ) ;
} , cb ) ;
}
} ) ;
} ;
var deleteHrefs = function ( ids ) {
ids . forEach ( function ( obj ) {
var idx = files [ obj . root ] . indexOf ( obj . id ) ;
files [ obj . root ] . splice ( idx , 1 ) ;
} ) ;
} ;
var deleteMultipleTrashRoot = function ( roots ) {
roots . forEach ( function ( obj ) {
var idx = files [ TRASH ] [ obj . name ] . indexOf ( obj . el ) ;
files [ TRASH ] [ obj . name ] . splice ( idx , 1 ) ;
} ) ;
} ;
var deleteMultiplePermanently = function ( paths , nocheck ) {
var hrefPaths = paths . filter ( function ( x ) { return isPathIn ( x , [ 'hrefArray' ] ) ; } ) ;
var rootPaths = paths . filter ( function ( x ) { return isPathIn ( x , [ ROOT ] ) ; } ) ;
var trashPaths = paths . filter ( function ( x ) { return isPathIn ( x , [ TRASH ] ) ; } ) ;
var allFilesPaths = paths . filter ( function ( x ) { return isPathIn ( x , [ FILES _DATA ] ) ; } ) ;
if ( ! loggedIn && ! config . testMode ) {
allFilesPaths . forEach ( function ( path ) {
var el = find ( path ) ;
if ( ! el ) { return ; }
var id = getIdFromHref ( el . href ) ;
if ( ! id ) { return ; }
spliceFileData ( id ) ;
removePadAttribute ( el . href ) ;
} ) ;
return ;
}
var ids = [ ] ;
hrefPaths . forEach ( function ( path ) {
var id = find ( path ) ;
ids . push ( {
root : path [ 0 ] ,
id : id
} ) ;
} ) ;
deleteHrefs ( ids ) ;
rootPaths . forEach ( function ( path ) {
var parentPath = path . slice ( ) ;
var key = parentPath . pop ( ) ;
var parentEl = find ( parentPath ) ;
delete parentEl [ key ] ;
} ) ;
var trashRoot = [ ] ;
trashPaths . forEach ( function ( path ) {
var parentPath = path . slice ( ) ;
var key = parentPath . pop ( ) ;
var parentEl = find ( parentPath ) ;
// Trash root: we have array here, we can't just splice with the path otherwise we might break the path
// of another element in the loop
if ( path . length === 4 ) {
trashRoot . push ( {
name : path [ 1 ] ,
el : parentEl
} ) ;
return ;
}
// Trash but not root: it's just a tree so remove the key
delete parentEl [ key ] ;
} ) ;
deleteMultipleTrashRoot ( trashRoot ) ;
// In some cases, we want to remove pads from a location without removing them from
// OLD_FILES_DATA (replaceHref)
if ( ! nocheck ) { checkDeletedFiles ( ) ; }
} ;
exp . delete = function ( paths , cb , nocheck ) {
deleteMultiplePermanently ( paths , nocheck ) ;
exp . deleteMultiplePermanently ( paths , nocheck ) ;
if ( typeof cb === "function" ) { cb ( ) ; }
} ;
exp . emptyTrash = function ( cb ) {
if ( sframeChan ) {
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "emptyTrash"
} , cb ) ;
}
files [ TRASH ] = { } ;
checkDeletedFiles ( ) ;
exp . checkDeletedFiles ( ) ;
if ( cb ) { cb ( ) ; }
} ;
// RENAME
exp . rename = function ( path , newName , cb ) {
if ( sframeChan ) {
console . log ( path , newName ) ;
return void sframeChan . query ( "Q_DRIVE_USEROBJECT" , {
cmd : "rename" ,
data : {
path : path ,
newName : newName
}
} , cb ) ;
}
console . log ( path , newName ) ;
if ( path . length <= 1 ) {
logError ( 'Renaming `root` is forbidden' ) ;
return ;
@ -784,322 +611,6 @@ define([
if ( typeof cb === "function" ) { cb ( ) ; }
} ;
// REPLACE
exp . replace = function ( o , n ) {
var idO = getIdFromHref ( o ) ;
if ( ! idO || ! isFile ( idO ) ) { return ; }
var data = getFileData ( idO ) ;
if ( ! data ) { return ; }
data . href = n ;
} ;
// If all the occurences of an href are in the trash, remvoe them and add the file in root.
// This is use with setPadTitle when we open a stronger version of a deleted pad
exp . restoreHref = function ( href ) {
var idO = getIdFromHref ( href ) ;
if ( ! idO || ! isFile ( idO ) ) { return ; }
var paths = findFile ( idO ) ;
// Remove all the occurences in the trash
// If all the occurences are in the trash or no occurence, add the pad to root
var allInTrash = true ;
paths . forEach ( function ( p ) {
if ( p [ 0 ] === TRASH ) {
exp . delete ( p , null , true ) ; // 3rd parameter means skip "checkDeletedFiles"
return ;
}
allInTrash = false ;
} ) ;
if ( allInTrash ) {
add ( idO ) ;
}
} ;
/ * *
* INTEGRITY CHECK
* /
exp . migrate = function ( cb ) {
// Make sure unsorted doesn't exist anymore
// Note: Unsorted only works with the old structure where pads are href
// It should be called before the migration code
var fixUnsorted = function ( ) {
if ( ! files [ UNSORTED ] || ! files [ OLD _FILES _DATA ] ) { return ; }
debug ( "UNSORTED still exists in the object, removing it..." ) ;
var us = files [ UNSORTED ] ;
if ( us . length === 0 ) {
delete files [ UNSORTED ] ;
return ;
}
us . forEach ( function ( el ) {
if ( typeof el !== "string" ) {
return ;
}
var data = files [ OLD _FILES _DATA ] . filter ( function ( x ) {
return x . href === el ;
} ) ;
if ( data . length === 0 ) {
files [ OLD _FILES _DATA ] . push ( {
href : el
} ) ;
}
return ;
} ) ;
delete files [ UNSORTED ] ;
} ;
// mergeDrive...
var migrateToNewFormat = function ( todo ) {
if ( ! files [ OLD _FILES _DATA ] ) {
return void todo ( ) ;
}
try {
debug ( "Migrating file system..." ) ;
files . migrate = 1 ;
var next = function ( ) {
var oldData = files [ OLD _FILES _DATA ] . slice ( ) ;
if ( ! files [ FILES _DATA ] ) {
files [ FILES _DATA ] = { } ;
}
var newData = files [ FILES _DATA ] ;
//var oldFiles = oldData.map(function (o) { return o.href; });
oldData . forEach ( function ( obj ) {
if ( ! obj || ! obj . href ) { return ; }
var href = obj . href ;
var id = Util . createRandomInteger ( ) ;
var paths = findFile ( href ) ;
var data = obj ;
var key = Hash . createChannelId ( ) ;
if ( data ) {
newData [ id ] = data ;
} else {
newData [ id ] = { href : href } ;
}
paths . forEach ( function ( p ) {
var parentPath = p . slice ( ) ;
var okey = parentPath . pop ( ) ; // get the parent
var parent = find ( parentPath ) ;
if ( isInTrashRoot ( p ) ) {
parent . element = id ;
newData [ id ] . filename = p [ 1 ] ;
return ;
}
if ( isPathIn ( p , [ 'hrefArray' ] ) ) {
parent [ okey ] = id ;
return ;
}
// else root or trash (not trashroot)
parent [ key ] = id ;
newData [ id ] . filename = okey ;
delete parent [ okey ] ;
} ) ;
} ) ;
delete files [ OLD _FILES _DATA ] ;
delete files . migrate ;
console . log ( 'done' ) ;
todo ( ) ;
} ;
if ( exp . rt ) {
exp . rt . sync ( ) ;
// TODO
Realtime . whenRealtimeSyncs ( exp . rt , next ) ;
} else {
window . setTimeout ( next , 1000 ) ;
}
} catch ( e ) {
console . error ( e ) ;
todo ( ) ;
}
} ;
fixUnsorted ( ) ;
migrateToNewFormat ( cb ) ;
} ;
exp . fixFiles = function ( ) {
// Explore the tree and check that everything is correct:
// * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects
// * ROOT: Folders are objects, files are href
// * TRASH: Trash root contains only arrays, each element of the array is an object {element:.., path:..}
// * OLD_FILES_DATA: - Data (title, cdate, adte) are stored in filesData. filesData contains only href keys linking to object with title, cdate, adate.
// - Dates (adate, cdate) can be parsed/formatted
// - All files in filesData should be either in 'root', 'trash' or 'unsorted'. If that's not the case, copy the fily to 'unsorted'
// * TEMPLATE: Contains only files (href), and does not contains files that are in ROOT
debug ( "Cleaning file system..." ) ;
var before = JSON . stringify ( files ) ;
var fixRoot = function ( elem ) {
if ( typeof ( files [ ROOT ] ) !== "object" ) { debug ( "ROOT was not an object" ) ; files [ ROOT ] = { } ; }
var element = elem || files [ ROOT ] ;
for ( var el in element ) {
if ( ! isFile ( element [ el ] , true ) && ! isFolder ( element [ el ] ) ) {
debug ( "An element in ROOT was not a folder nor a file. " , element [ el ] ) ;
delete element [ el ] ;
continue ;
}
if ( isFolder ( element [ el ] ) ) {
fixRoot ( element [ el ] ) ;
continue ;
}
if ( typeof element [ el ] === "string" ) {
// We have an old file (href) which is not in filesData: add it
var id = Util . createRandomInteger ( ) ;
var key = Hash . createChannelId ( ) ;
files [ FILES _DATA ] [ id ] = { href : element [ el ] , filename : el } ;
element [ key ] = id ;
delete element [ el ] ;
}
if ( typeof element [ el ] === "number" ) {
var data = files [ FILES _DATA ] [ element [ el ] ] ;
if ( ! data ) {
debug ( "An element in ROOT doesn't have associated data" , element [ el ] , el ) ;
delete element [ el ] ;
}
}
}
} ;
var fixTrashRoot = function ( ) {
if ( typeof ( files [ TRASH ] ) !== "object" ) { debug ( "TRASH was not an object" ) ; files [ TRASH ] = { } ; }
var tr = files [ TRASH ] ;
var toClean ;
var addToClean = function ( obj , idx , el ) {
if ( typeof ( obj ) !== "object" ) { toClean . push ( idx ) ; return ; }
if ( ! isFile ( obj . element , true ) && ! isFolder ( obj . element ) ) { toClean . push ( idx ) ; return ; }
if ( ! Array . isArray ( obj . path ) ) { toClean . push ( idx ) ; return ; }
if ( typeof obj . element === "string" ) {
// We have an old file (href) which is not in filesData: add it
var id = Util . createRandomInteger ( ) ;
files [ FILES _DATA ] [ id ] = { href : obj . element , filename : el } ;
obj . element = id ;
}
if ( isFolder ( obj . element ) ) { fixRoot ( obj . element ) ; }
if ( typeof obj . element === "number" ) {
var data = files [ FILES _DATA ] [ obj . element ] ;
if ( ! data ) {
debug ( "An element in TRASH doesn't have associated data" , obj . element , el ) ;
toClean . push ( idx ) ;
}
}
} ;
for ( var el in tr ) {
if ( ! Array . isArray ( tr [ el ] ) ) {
debug ( "An element in TRASH root is not an array. " , tr [ el ] ) ;
delete tr [ el ] ;
} else if ( tr [ el ] . length === 0 ) {
debug ( "Empty array in TRASH root. " , tr [ el ] ) ;
delete tr [ el ] ;
} else {
toClean = [ ] ;
for ( var j = 0 ; j < tr [ el ] . length ; j ++ ) {
addToClean ( tr [ el ] [ j ] , j , el ) ;
}
for ( var i = toClean . length - 1 ; i >= 0 ; i -- ) {
tr [ el ] . splice ( toClean [ i ] , 1 ) ;
}
}
}
} ;
var fixTemplate = function ( ) {
if ( ! Array . isArray ( files [ TEMPLATE ] ) ) { debug ( "TEMPLATE was not an array" ) ; files [ TEMPLATE ] = [ ] ; }
files [ TEMPLATE ] = Util . deduplicateString ( files [ TEMPLATE ] . slice ( ) ) ;
var us = files [ TEMPLATE ] ;
var rootFiles = getFiles ( [ ROOT ] ) . slice ( ) ;
var toClean = [ ] ;
us . forEach ( function ( el , idx ) {
if ( ! isFile ( el , true ) || rootFiles . indexOf ( el ) !== - 1 ) {
toClean . push ( el ) ;
}
if ( typeof el === "string" ) {
// We have an old file (href) which is not in filesData: add it
var id = Util . createRandomInteger ( ) ;
files [ FILES _DATA ] [ id ] = { href : el } ;
us [ idx ] = id ;
}
if ( typeof el === "number" ) {
var data = files [ FILES _DATA ] [ el ] ;
if ( ! data ) {
debug ( "An element in TEMPLATE doesn't have associated data" , el ) ;
toClean . push ( el ) ;
}
}
} ) ;
toClean . forEach ( function ( el ) {
var idx = us . indexOf ( el ) ;
if ( idx !== - 1 ) {
us . splice ( idx , 1 ) ;
}
} ) ;
} ;
var fixFilesData = function ( ) {
if ( typeof files [ FILES _DATA ] !== "object" ) { debug ( "OLD_FILES_DATA was not an object" ) ; files [ FILES _DATA ] = { } ; }
var fd = files [ FILES _DATA ] ;
var rootFiles = getFiles ( [ ROOT , TRASH , 'hrefArray' ] ) ;
var root = find ( [ ROOT ] ) ;
var toClean = [ ] ;
for ( var id in fd ) {
id = Number ( id ) ;
var el = fd [ id ] ;
if ( ! el || typeof ( el ) !== "object" ) {
debug ( "An element in filesData was not an object." , el ) ;
toClean . push ( id ) ;
continue ;
}
if ( ! el . href ) {
debug ( "Removing an element in filesData with a missing href." , el ) ;
toClean . push ( id ) ;
continue ;
}
if ( /^https*:\/\// . test ( el . href ) ) { el . href = Hash . getRelativeHref ( el . href ) ; }
if ( ! el . ctime ) { el . ctime = el . atime ; }
var parsed = Hash . parsePadUrl ( el . href ) ;
if ( ! el . title ) { el . title = Hash . getDefaultName ( parsed ) ; }
if ( ! parsed . hash ) {
debug ( "Removing an element in filesData with a invalid href." , el ) ;
toClean . push ( id ) ;
continue ;
}
if ( ! parsed . type ) {
debug ( "Removing an element in filesData with a invalid type." , el ) ;
toClean . push ( id ) ;
continue ;
}
if ( ( loggedIn || config . testMode ) && rootFiles . indexOf ( id ) === - 1 ) {
debug ( "An element in filesData was not in ROOT, TEMPLATE or TRASH." , id , el ) ;
var newName = Hash . createChannelId ( ) ;
root [ newName ] = id ;
continue ;
}
}
toClean . forEach ( function ( id ) {
spliceFileData ( id ) ;
} ) ;
} ;
var fixDrive = function ( ) {
Object . keys ( files ) . forEach ( function ( key ) {
if ( key . slice ( 0 , 1 ) === '/' ) { delete files [ key ] ; }
} ) ;
} ;
fixRoot ( ) ;
fixTrashRoot ( ) ;
if ( ! workgroup ) {
fixTemplate ( ) ;
fixFilesData ( ) ;
}
fixDrive ( ) ;
if ( JSON . stringify ( files ) !== before ) {
debug ( "Your file system was corrupted. It has been cleaned so that the pads you visit can be stored safely" ) ;
return ;
}
debug ( "File system was clean" ) ;
} ;
return exp ;
} ;
return module ;