From e2bafe919bf2bb04c84946d00e972c88bfe6ff1c Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Wed, 28 Jun 2017 10:22:29 +0200 Subject: [PATCH 01/36] improved extraction file dialog --- ifm.php | 29 +++++++++++++++-------------- src/ifm.js | 29 +++++++++++++++-------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/ifm.php b/ifm.php index 4fe3dca..f588dbd 100644 --- a/ifm.php +++ b/ifm.php @@ -854,24 +854,25 @@ function IFM() { }; this.extractFileDialog = function(name) { - var fuckWorkarounds=""; + var targetDirSuggestion=""; if(name.lastIndexOf(".") > 1) - fuckWorkarounds = name.substr(0,name.length-4); - else fuckWorkarounds = name; - self.showModal( ''); +
./
\ +
./'+targetDirSuggestion+'
\ +
\ + \ + \ + '); }; this.extractFile = function(name, t) { - var td = (t == 1)? name.substr(0,name.length-4) : ""; $.ajax({ url: self.IFM_SCFN, type: "POST", @@ -879,7 +880,7 @@ function IFM() { api: "extractFile", dir: self.currentDir, filename: name, - targetdir: td + targetdir: t }), dataType: "json", success: function(data) { diff --git a/src/ifm.js b/src/ifm.js index eaab79d..1d0cc7f 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -386,24 +386,25 @@ function IFM() { }; this.extractFileDialog = function(name) { - var fuckWorkarounds=""; + var targetDirSuggestion=""; if(name.lastIndexOf(".") > 1) - fuckWorkarounds = name.substr(0,name.length-4); - else fuckWorkarounds = name; - self.showModal( ''); +
./
\ +
./'+targetDirSuggestion+'
\ +
\ + \ + \ + '); }; this.extractFile = function(name, t) { - var td = (t == 1)? name.substr(0,name.length-4) : ""; $.ajax({ url: self.IFM_SCFN, type: "POST", @@ -411,7 +412,7 @@ function IFM() { api: "extractFile", dir: self.currentDir, filename: name, - targetdir: td + targetdir: t }), dataType: "json", success: function(data) { From 72c55861360c88f673b61d038f3585f02be5e921 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 3 Jul 2017 10:29:52 +0200 Subject: [PATCH 02/36] improved extraction function The extraction function now enables custom destination paths. --- ifm.php | 95 ++++++++++++++++++++++++++++------------------------ src/ifm.js | 20 +++++++++-- src/main.php | 71 ++++++++++++++++++--------------------- 3 files changed, 102 insertions(+), 84 deletions(-) diff --git a/ifm.php b/ifm.php index f588dbd..af93fe0 100644 --- a/ifm.php +++ b/ifm.php @@ -861,15 +861,29 @@ function IFM() { self.showModal( '
\ \ \
'); + $('#extractFileButton').on( 'click', function() { + var t = $('input[name=extractTargetLocation]:checked').val(); + if( t == "custom" ) t = $('#extractCustomLocation').val(); + self.extractFile( self.JSEncode( name ), t ); + self.hideModal(); + return false; + }); + $('#extractCancelButton').on( 'click', function() { + self.hideModal(); + return false; + }); + $('#extractCustomLocation').on( 'click', function(e) { + $(e.target).prev().children().first().prop( 'checked', true ); + }); }; this.extractFile = function(name, t) { @@ -1608,39 +1622,24 @@ ifm.init(); echo json_encode( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); else { $this->chDirIfNecessary( $d['dir'] ); - if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) + if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) { echo json_encode( array( "status" => "ERROR","message" => "No valid zip file found" ) ); - else { - if( ! isset( $d['targetdir'] ) ) - $d['targetdir'] = ""; - if( strpos( $d['targetdir'], "/" ) !== false ) - echo json_encode( array( "status" => "ERROR","message" => "Target directory must not contain slashes" ) ); - else { - switch( $d['targetdir'] ){ - case "": - if( $this->unzip( $_POST["filename"] ) ) - echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); - else - echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); - break; - default: - if( ! mkdir( $d['targetdir'] ) ) - echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory" ) ); - else { - chdir( $d['targetdir'] ); - if( ! $this->unzip( "../" . $d["filename"] ) ) { - chdir( ".." ); - rmdir( $d['targetdir'] ); - echo json_encode( array( "status" => "ERROR","message" => "Could not extract file" ) ); - } - else { - chdir( ".." ); - echo json_encode( array( "status" => "OK","message" => "File successfully extracted" ) ); - } - } - break; - } - } + exit( 1 ); + } + if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) + $d['targetdir'] = "./"; + if( ! $this->isPathValid( $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + exit( 1 ); + } + if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + exit( 1 ); + } + if( ! $this->unzip( $d['filename'], $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + } else { + echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); } } } @@ -1903,15 +1902,25 @@ ifm.init(); } private function isPathValid( $dir ) { - $rpDir = realpath( $dir ); - $rpConfig = realpath( IFMConfig::root_dir ); + /** + * This function is also used to check non-existent paths, but the PHP realpath function returns false for + * nonexistent paths. Hence we need to check the path manually in the following lines. + */ + $tmp_d = $dir; + $tmp_missing_parts = array(); + while( realpath( $tmp_d ) === false ) { + $tmp_i = pathinfo( $tmp_d ); + array_push( $tmp_missing_parts, $tmp_i['filename'] ); + $tmp_d = dirname( $tmp_d ); + } + $rpDir = $this->pathCombine( realpath( $tmp_d ), implode( "/", array_reverse( $tmp_missing_parts ) ) ); + $rpConfig = ( IFMConfig::root_dir == "" ) ? realpath( dirname( __FILE__ ) ) : realpath( IFMConfig::root_dir ); if( ! is_string( $rpDir ) || ! is_string( $rpConfig ) ) // can happen if open_basedir is in effect return false; elseif( $rpDir == $rpConfig ) return true; - elseif( 0 === strpos( $rpDir, $rpConfig ) ) { + elseif( 0 === strpos( $rpDir, $rpConfig ) ) return true; - } else return false; } @@ -1996,11 +2005,11 @@ ifm.init(); } // unzip an archive - private function unzip( $file ) { + private function unzip( $file, $destination="./" ) { $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { - $zip->extractTo( './' ); + $zip->extractTo( $destination ); $zip->close(); return true; } else { diff --git a/src/ifm.js b/src/ifm.js index 1d0cc7f..206defd 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -395,13 +395,27 @@ function IFM() { \
./
\
./'+targetDirSuggestion+'
\ -
\ +
\ \ \ '); + $('#extractFileButton').on( 'click', function() { + var t = $('input[name=extractTargetLocation]:checked').val(); + if( t == "custom" ) t = $('#extractCustomLocation').val(); + self.extractFile( self.JSEncode( name ), t ); + self.hideModal(); + return false; + }); + $('#extractCancelButton').on( 'click', function() { + self.hideModal(); + return false; + }); + $('#extractCustomLocation').on( 'click', function(e) { + $(e.target).prev().children().first().prop( 'checked', true ); + }); }; this.extractFile = function(name, t) { diff --git a/src/main.php b/src/main.php index eae3cab..7cbdae6 100644 --- a/src/main.php +++ b/src/main.php @@ -408,39 +408,24 @@ class IFM { echo json_encode( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); else { $this->chDirIfNecessary( $d['dir'] ); - if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) + if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) { echo json_encode( array( "status" => "ERROR","message" => "No valid zip file found" ) ); - else { - if( ! isset( $d['targetdir'] ) ) - $d['targetdir'] = ""; - if( strpos( $d['targetdir'], "/" ) !== false ) - echo json_encode( array( "status" => "ERROR","message" => "Target directory must not contain slashes" ) ); - else { - switch( $d['targetdir'] ){ - case "": - if( $this->unzip( $_POST["filename"] ) ) - echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); - else - echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); - break; - default: - if( ! mkdir( $d['targetdir'] ) ) - echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory" ) ); - else { - chdir( $d['targetdir'] ); - if( ! $this->unzip( "../" . $d["filename"] ) ) { - chdir( ".." ); - rmdir( $d['targetdir'] ); - echo json_encode( array( "status" => "ERROR","message" => "Could not extract file" ) ); - } - else { - chdir( ".." ); - echo json_encode( array( "status" => "OK","message" => "File successfully extracted" ) ); - } - } - break; - } - } + exit( 1 ); + } + if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) + $d['targetdir'] = "./"; + if( ! $this->isPathValid( $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + exit( 1 ); + } + if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + exit( 1 ); + } + if( ! $this->unzip( $d['filename'], $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + } else { + echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); } } } @@ -703,15 +688,25 @@ class IFM { } private function isPathValid( $dir ) { - $rpDir = realpath( $dir ); - $rpConfig = realpath( IFMConfig::root_dir ); + /** + * This function is also used to check non-existent paths, but the PHP realpath function returns false for + * nonexistent paths. Hence we need to check the path manually in the following lines. + */ + $tmp_d = $dir; + $tmp_missing_parts = array(); + while( realpath( $tmp_d ) === false ) { + $tmp_i = pathinfo( $tmp_d ); + array_push( $tmp_missing_parts, $tmp_i['filename'] ); + $tmp_d = dirname( $tmp_d ); + } + $rpDir = $this->pathCombine( realpath( $tmp_d ), implode( "/", array_reverse( $tmp_missing_parts ) ) ); + $rpConfig = ( IFMConfig::root_dir == "" ) ? realpath( dirname( __FILE__ ) ) : realpath( IFMConfig::root_dir ); if( ! is_string( $rpDir ) || ! is_string( $rpConfig ) ) // can happen if open_basedir is in effect return false; elseif( $rpDir == $rpConfig ) return true; - elseif( 0 === strpos( $rpDir, $rpConfig ) ) { + elseif( 0 === strpos( $rpDir, $rpConfig ) ) return true; - } else return false; } @@ -796,11 +791,11 @@ class IFM { } // unzip an archive - private function unzip( $file ) { + private function unzip( $file, $destination="./" ) { $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { - $zip->extractTo( './' ); + $zip->extractTo( $destination ); $zip->close(); return true; } else { From 7f1d14bd21055e624e8c970c21232da4181d682d Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 13 Jun 2017 11:18:08 +0200 Subject: [PATCH 03/36] fix merge conflicts with master --- ifm.php | 45 +++++++++++++++++++++++++++++++++++++-------- src/config.php | 10 +++++++++- src/main.php | 35 ++++++++++++++++++++++++++++------- 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/ifm.php b/ifm.php index af93fe0..5abaa6e 100644 --- a/ifm.php +++ b/ifm.php @@ -46,14 +46,22 @@ class IFMConfig { configured. The credential information can be either set inline or read from a file. The password has to be a hash generated by PHPs password_hash function. The default credentials are admin:admin. - + If you specify a file it should only contain one line, with the credentials in the following format: : + + LDAP auth syntax + + const auth_source = 'ldap;:'; + + The script will add "uid=," to the rootdn for binding. If your ldap server + does not use uid for usernames you can change it in the function checkCredentials. examples: const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; const auth_source = 'file;/path/to/file'; + const auth_source = 'ldap;:'; */ const auth = 0; const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; @@ -1830,21 +1838,42 @@ ifm.init(); } } - private function checkCredentials($user, $pass) { - list($src, $srcopt) = explode(";", IFMConfig::auth_source, 2); - switch($src) { + private function checkCredentials( $user, $pass ) { + list( $src, $srcopt ) = explode( ";", IFMConfig::auth_source, 2 ); + switch( $src ) { case "inline": - list($uname, $hash) = explode(":", $srcopt); + list( $uname, $hash ) = explode( ":", $srcopt ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; break; case "file": - if(@file_exists($srcopt) && @is_readable($srcopt)) { - list($uname, $hash) = explode(":", fgets(fopen($srcopt, 'r'))); + if( @file_exists( $srcopt ) && @is_readable( $srcopt ) ) { + list( $uname, $hash ) = explode( ":", fgets( fopen( $srcopt, 'r' ) ) ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; } else { return false; } break; + case "ldap": + $authenticated = false; + list( $ldap_server, $rootdn ) = explode( ":", $srcopt ); + $u = "uid=" . $user . "," . $rootdn; + $ds = ldap_connect( $ldap_server ) or ( trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); return false; ); + ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 ); + if( $ds ) { + $ldbind = @ldap_bind( $ds, $u, $pass ); + if( $ldbind ) { + $authenticated = true; + } else { + $authenticated = false; + } + ldap_unbind( $ds ); + } else { + $authenticated = false; + } + return $authenticated; + break; } - return password_verify($pass, trim($hash))?($uname == $user):false; + return false; } private function loginForm($loginFailed=false) { diff --git a/src/config.php b/src/config.php index 8c0ed61..04b9c99 100644 --- a/src/config.php +++ b/src/config.php @@ -46,14 +46,22 @@ class IFMConfig { configured. The credential information can be either set inline or read from a file. The password has to be a hash generated by PHPs password_hash function. The default credentials are admin:admin. - + If you specify a file it should only contain one line, with the credentials in the following format: : + + LDAP auth syntax + + const auth_source = 'ldap;:'; + + The script will add "uid=," to the rootdn for binding. If your ldap server + does not use uid for usernames you can change it in the function checkCredentials. examples: const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; const auth_source = 'file;/path/to/file'; + const auth_source = 'ldap;:'; */ const auth = 0; const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; diff --git a/src/main.php b/src/main.php index 7cbdae6..b62dc27 100644 --- a/src/main.php +++ b/src/main.php @@ -616,21 +616,42 @@ class IFM { } } - private function checkCredentials($user, $pass) { - list($src, $srcopt) = explode(";", IFMConfig::auth_source, 2); - switch($src) { + private function checkCredentials( $user, $pass ) { + list( $src, $srcopt ) = explode( ";", IFMConfig::auth_source, 2 ); + switch( $src ) { case "inline": - list($uname, $hash) = explode(":", $srcopt); + list( $uname, $hash ) = explode( ":", $srcopt ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; break; case "file": - if(@file_exists($srcopt) && @is_readable($srcopt)) { - list($uname, $hash) = explode(":", fgets(fopen($srcopt, 'r'))); + if( @file_exists( $srcopt ) && @is_readable( $srcopt ) ) { + list( $uname, $hash ) = explode( ":", fgets( fopen( $srcopt, 'r' ) ) ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; } else { return false; } break; + case "ldap": + $authenticated = false; + list( $ldap_server, $rootdn ) = explode( ":", $srcopt ); + $u = "uid=" . $user . "," . $rootdn; + $ds = ldap_connect( $ldap_server ) or ( trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); return false; ); + ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 ); + if( $ds ) { + $ldbind = @ldap_bind( $ds, $u, $pass ); + if( $ldbind ) { + $authenticated = true; + } else { + $authenticated = false; + } + ldap_unbind( $ds ); + } else { + $authenticated = false; + } + return $authenticated; + break; } - return password_verify($pass, trim($hash))?($uname == $user):false; + return false; } private function loginForm($loginFailed=false) { From f4a7ae20534d1ce9f96b3226f9b217459d49ecf6 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 3 Jul 2017 11:30:11 +0200 Subject: [PATCH 04/36] finalized ldap support --- ifm.php | 10 +++++++--- src/config.php | 2 +- src/main.php | 8 ++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ifm.php b/ifm.php index 5abaa6e..023f233 100644 --- a/ifm.php +++ b/ifm.php @@ -53,7 +53,7 @@ class IFMConfig { LDAP auth syntax - const auth_source = 'ldap;:'; + const auth_source = 'ldap;;'; The script will add "uid=," to the rootdn for binding. If your ldap server does not use uid for usernames you can change it in the function checkCredentials. @@ -1855,15 +1855,19 @@ ifm.init(); break; case "ldap": $authenticated = false; - list( $ldap_server, $rootdn ) = explode( ":", $srcopt ); + list( $ldap_server, $rootdn ) = explode( ";", $srcopt ); $u = "uid=" . $user . "," . $rootdn; - $ds = ldap_connect( $ldap_server ) or ( trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); return false; ); + if( ! $ds = ldap_connect( $ldap_server ) ) { + trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); + return false; + } ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 ); if( $ds ) { $ldbind = @ldap_bind( $ds, $u, $pass ); if( $ldbind ) { $authenticated = true; } else { + trigger_error( ldap_error( $ds ), E_USER_ERROR ); $authenticated = false; } ldap_unbind( $ds ); diff --git a/src/config.php b/src/config.php index 04b9c99..b48fd37 100644 --- a/src/config.php +++ b/src/config.php @@ -53,7 +53,7 @@ class IFMConfig { LDAP auth syntax - const auth_source = 'ldap;:'; + const auth_source = 'ldap;;'; The script will add "uid=," to the rootdn for binding. If your ldap server does not use uid for usernames you can change it in the function checkCredentials. diff --git a/src/main.php b/src/main.php index b62dc27..9118d72 100644 --- a/src/main.php +++ b/src/main.php @@ -633,15 +633,19 @@ class IFM { break; case "ldap": $authenticated = false; - list( $ldap_server, $rootdn ) = explode( ":", $srcopt ); + list( $ldap_server, $rootdn ) = explode( ";", $srcopt ); $u = "uid=" . $user . "," . $rootdn; - $ds = ldap_connect( $ldap_server ) or ( trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); return false; ); + if( ! $ds = ldap_connect( $ldap_server ) ) { + trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); + return false; + } ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 ); if( $ds ) { $ldbind = @ldap_bind( $ds, $u, $pass ); if( $ldbind ) { $authenticated = true; } else { + trigger_error( ldap_error( $ds ), E_USER_ERROR ); $authenticated = false; } ldap_unbind( $ds ); From 8ba3f99e8f9a7bf62ada67d5433b486baa09e92d Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 3 Jul 2017 11:31:21 +0200 Subject: [PATCH 05/36] adjusted version number --- src/main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.php b/src/main.php index 9118d72..0a95c72 100644 --- a/src/main.php +++ b/src/main.php @@ -14,7 +14,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.3.1'; + const VERSION = '2.4.0'; public function __construct() { session_start(); From c8df517b2b1dba6f95f2c1db74a40fe4d2d37e21 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 3 Jul 2017 17:55:44 +0200 Subject: [PATCH 06/36] added copy and move functionality for files and directories, disable logging for every keystroke --- ifm.php | 194 +++++++++++++++++++++++- src/config.php | 1 + src/ifm.js | 80 +++++++++- src/includes/bootstrap-treeview.min.css | 1 + src/includes/bootstrap-treeview.min.js | 1 + src/main.php | 109 ++++++++++++- 6 files changed, 375 insertions(+), 11 deletions(-) create mode 100644 src/includes/bootstrap-treeview.min.css create mode 100644 src/includes/bootstrap-treeview.min.js diff --git a/ifm.php b/ifm.php index 023f233..4c9ccbe 100644 --- a/ifm.php +++ b/ifm.php @@ -27,6 +27,7 @@ class IFMConfig { const createdir = 1; // allow to create directorys const createfile = 1; // allow to create files const zipnload = 1; // allow to zip and download directorys + const copymove = 1; // allow to copy and move files and directories // view controls const multiselect = 1; // implement multiselect of files and directories @@ -174,7 +175,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.3.1'; + const VERSION = '2.4.0'; public function __construct() { session_start(); @@ -306,6 +307,8 @@ class IFM { .icon-file-code:before { content: '\f1c9'; } /* '' */ .icon-sliders:before { content: '\f1de'; } /* '' */ .icon-trash:before { content: '\f1f8'; } /* '' */ + ").appendTo("head")},d.prototype.buildStyle=function(){var e=".node-"+this.elementId+"{";return this.options.color&&(e+="color:"+this.options.color+";"),this.options.backColor&&(e+="background-color:"+this.options.backColor+";"),this.options.showBorder?this.options.borderColor&&(e+="border:1px solid "+this.options.borderColor+";"):e+="border:none;",e+="}",this.options.onhoverColor&&(e+=".node-"+this.elementId+":not(.node-disabled):hover{background-color:"+this.options.onhoverColor+";}"),this.css+e},d.prototype.template={list:'
    ',item:'
  • ',indent:'',icon:'',link:'',badge:''},d.prototype.css=".treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}",d.prototype.getNode=function(e){return this.nodes[e]},d.prototype.getParent=function(e){var t=this.identifyNode(e);return this.nodes[t.parentId]},d.prototype.getSiblings=function(e){var t=this.identifyNode(e),o=this.getParent(t),s=o?o.nodes:this.tree;return s.filter(function(e){return e.nodeId!==t.nodeId})},d.prototype.getSelected=function(){return this.findNodes("true","g","state.selected")},d.prototype.getUnselected=function(){return this.findNodes("false","g","state.selected")},d.prototype.getExpanded=function(){return this.findNodes("true","g","state.expanded")},d.prototype.getCollapsed=function(){return this.findNodes("false","g","state.expanded")},d.prototype.getChecked=function(){return this.findNodes("true","g","state.checked")},d.prototype.getUnchecked=function(){return this.findNodes("false","g","state.checked")},d.prototype.getDisabled=function(){return this.findNodes("true","g","state.disabled")},d.prototype.getEnabled=function(){return this.findNodes("false","g","state.disabled")},d.prototype.selectNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setSelectedState(e,!0,t)},this)),this.render()},d.prototype.unselectNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setSelectedState(e,!1,t)},this)),this.render()},d.prototype.toggleNodeSelected=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.toggleSelectedState(e,t)},this)),this.render()},d.prototype.collapseAll=function(t){var o=this.findNodes("true","g","state.expanded");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setExpandedState(e,!1,t)},this)),this.render()},d.prototype.collapseNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setExpandedState(e,!1,t)},this)),this.render()},d.prototype.expandAll=function(t){if(t=e.extend({},i.options,t),t&&t.levels)this.expandLevels(this.tree,t.levels,t);else{var o=this.findNodes("false","g","state.expanded");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setExpandedState(e,!0,t)},this))}this.render()},d.prototype.expandNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setExpandedState(e,!0,t),e.nodes&&t&&t.levels&&this.expandLevels(e.nodes,t.levels-1,t)},this)),this.render()},d.prototype.expandLevels=function(t,o,s){s=e.extend({},i.options,s),e.each(t,e.proxy(function(e,t){this.setExpandedState(t,o>0?!0:!1,s),t.nodes&&this.expandLevels(t.nodes,o-1,s)},this))},d.prototype.revealNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){for(var o=this.getParent(e);o;)this.setExpandedState(o,!0,t),o=this.getParent(o)},this)),this.render()},d.prototype.toggleNodeExpanded=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.toggleExpandedState(e,t)},this)),this.render()},d.prototype.checkAll=function(t){var o=this.findNodes("false","g","state.checked");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setCheckedState(e,!0,t)},this)),this.render()},d.prototype.checkNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setCheckedState(e,!0,t)},this)),this.render()},d.prototype.uncheckAll=function(t){var o=this.findNodes("true","g","state.checked");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setCheckedState(e,!1,t)},this)),this.render()},d.prototype.uncheckNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setCheckedState(e,!1,t)},this)),this.render()},d.prototype.toggleNodeChecked=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.toggleCheckedState(e,t)},this)),this.render()},d.prototype.disableAll=function(t){var o=this.findNodes("false","g","state.disabled");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setDisabledState(e,!0,t)},this)),this.render()},d.prototype.disableNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setDisabledState(e,!0,t)},this)),this.render()},d.prototype.enableAll=function(t){var o=this.findNodes("true","g","state.disabled");this.forEachIdentifier(o,t,e.proxy(function(e,t){this.setDisabledState(e,!1,t)},this)),this.render()},d.prototype.enableNode=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setDisabledState(e,!1,t)},this)),this.render()},d.prototype.toggleNodeDisabled=function(t,o){this.forEachIdentifier(t,o,e.proxy(function(e,t){this.setDisabledState(e,!e.state.disabled,t)},this)),this.render()},d.prototype.forEachIdentifier=function(t,o,s){o=e.extend({},i.options,o),t instanceof Array||(t=[t]),e.each(t,e.proxy(function(e,t){s(this.identifyNode(t),o)},this))},d.prototype.identifyNode=function(e){return"number"==typeof e?this.nodes[e]:e},d.prototype.search=function(t,o){o=e.extend({},i.searchOptions,o),this.clearSearch({render:!1});var s=[];if(t&&t.length>0){o.exactMatch&&(t="^"+t+"$");var n="g";o.ignoreCase&&(n+="i"),s=this.findNodes(t,n),e.each(s,function(e,t){t.searchResult=!0})}return o.revealResults?this.revealNode(s):this.render(),this.$element.trigger("searchComplete",e.extend(!0,{},s)),s},d.prototype.clearSearch=function(t){t=e.extend({},{render:!0},t);var o=e.each(this.findNodes("true","g","searchResult"),function(e,t){t.searchResult=!1});t.render&&this.render(),this.$element.trigger("searchCleared",e.extend(!0,{},o))},d.prototype.findNodes=function(t,o,s){o=o||"g",s=s||"text";var n=this;return e.grep(this.nodes,function(e){var i=n.getNodeValue(e,s);return"string"==typeof i?i.match(new RegExp(t,o)):void 0})},d.prototype.getNodeValue=function(e,t){var o=t.indexOf(".");if(o>0){var n=e[t.substring(0,o)],i=t.substring(o+1,t.length);return this.getNodeValue(n,i)}return e.hasOwnProperty(t)?e[t].toString():s};var r=function(e){t.console&&t.console.error(e)};e.fn[n]=function(t,o){var s;return this.each(function(){var i=e.data(this,n);"string"==typeof t?i?e.isFunction(i[t])&&"_"!==t.charAt(0)?(o instanceof Array||(o=[o]),s=i[t].apply(i,o)):r("No such method : "+t):r("Not initialized, can not call method : "+t):"boolean"==typeof t?s=i:e.data(this,n,new d(this,e.extend(!0,{},t)))}),s||this}}(jQuery,window,document); + + @@ -146,11 +148,17 @@ class IFM { case "downloadFile": $this->downloadFile( $_REQUEST ); break; case "extractFile": $this->extractFile( $_REQUEST ); break; case "uploadFile": $this->uploadFile( $_REQUEST ); break; + case "copyMove": $this->copyMove( $_REQUEST ); break; case "changePermissions": $this->changePermissions( $_REQUEST ); break; case "zipnload": $this->zipnload( $_REQUEST); break; case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; case "deleteMultipleFiles": $this->deleteMultipleFiles( $_REQUEST ); break; - default: echo json_encode(array("status"=>"ERROR", "message"=>"No valid api action given")); break; + case "getFolderTree": + echo json_encode( array_merge( array( 0 => array( "text" => "/ [root]", "nodes" => array(), "dataAttributes" => array( "path" => realpath( IFMConfig::root_dir ) ) ) ), $this->getFolderTreeRecursive( IFMConfig::root_dir ) ) ); + break; + default: + echo json_encode( array( "status" => "ERROR", "message" => "No valid api action given" ) ); + break; } } else { print json_encode(array("status"=>"ERROR", "message"=>"No valid working directory")); @@ -248,6 +256,58 @@ class IFM { echo json_encode( array_merge( $dirs, $files ) ); } + private function getFolderTreeRecursive( $start_dir ) { + $ret = array(); + $start_dir = realpath( $start_dir ); + if( $handle = opendir( $start_dir ) ) { + while (false !== ( $result = readdir( $handle ) ) ) { + if( is_dir( $this->pathCombine( $start_dir, $result ) ) && $result != "." && $result != ".." ) { + array_push( $ret, array( "text" => $result, "dataAttributes" => array( "path" => $this->pathCombine( $start_dir, $result ) ), "nodes" => $this->getFolderTreeRecursive( $this->pathCombine( $start_dir, $result ) ) ) ); + } + } + } + sort( $ret ); + return $ret; + } + + private function copyMove( $d ) { + if( IFMConfig::copymove != 1 ) { + echo json_encode( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + exit( 1 ); + } + $this->chDirIfNecessary( $d['dir'] ); + if( ! isset( $d['destination'] ) || ! $this->isPathValid( realpath( $d['destination'] ) ) ) { + echo json_encode( array( "status" => "ERROR", "message" => "No valid destination directory given." ) ); + exit( 1 ); + } + if( ! file_exists( $d['filename'] ) ) { + echo json_encode( array( "status" => "ERROR", "message" => "No valid filename given." ) ); + exit( 1 ); + } + if( $d['action'] == "copy" ) { + if( $this->copyr( $d['filename'], $d['destination'] ) ) { + echo json_encode( array( "status" => "OK", "message" => "File(s) were successfully copied." ) ); + exit( 0 ); + } else { + $err = error_get_last(); + echo json_encode( array( "status" => "ERROR", "message" => $err['message'] ) ); + exit( 1 ); + } + } elseif( $d['action'] == "move" ) { + if( rename( $d['filename'], $this->pathCombine( $d['destination'], basename( $d['filename'] ) ) ) ) { + echo json_encode( array( "status" => "OK", "message" => "File(s) were successfully moved." ) ); + exit( 0 ); + } else { + $err = error_get_last(); + echo json_encode( array( "status" => "ERROR", "message" => $err['message'] ) ); + exit( 1 ); + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "No valid action given." ) ); + exit( 1 ); + } + } + // creates a directory private function createDir($w, $dn) { if( $dn == "" ) { @@ -788,6 +848,53 @@ class IFM { return 0; } + /** + * Copy a file, or recursively copy a folder and its contents + * + * @author Aidan Lister + * @version 1.0.1 + * @link http://aidanlister.com/2004/04/recursively-copying-directories-in-php/ + * @param string $source Source path + * @param string $dest Destination path + * @return bool Returns TRUE on success, FALSE on failure + */ + private function copyr( $source, $dest ) + { + // Check for symlinks + if (is_link($source)) { + return symlink(readlink($source), $dest); + } + + // Simple copy for a file + if (is_file($source)) { + $dest = ( is_dir( $dest ) ) ? $this->pathCombine( $dest, basename( $source ) ) : $dest; + return copy($source, $dest); + } else { + $dest = $this->pathCombine( $dest, basename( $source ) ); + } + + // Make destination directory + if (!is_dir($dest)) { + mkdir($dest); + } + + // Loop through the folder + $dir = dir($source); + while (false !== $entry = $dir->read()) { + // Skip pointers + if ($entry == '.' || $entry == '..') { + continue; + } + + // Deep copy directories + $this->copyr("$source/$entry", "$dest/$entry"); + } + + // Clean up + $dir->close(); + return true; + } + // combines two parts to a valid path private function pathCombine( $a, $b ) { if( trim( $a ) == "" && trim( $b ) == "" ) From d3d02f4253e38c42b62dd25cb02a4f3ab35557d9 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 4 Jul 2017 12:56:41 +0200 Subject: [PATCH 07/36] consolidate zip class, remove unzip function from main class --- ifm.php | 34 +++++++++++++++------------------- src/ifmzip.php | 17 +++++++++++++---- src/main.php | 17 ++--------------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/ifm.php b/ifm.php index 4c9ccbe..65d8c0a 100644 --- a/ifm.php +++ b/ifm.php @@ -108,6 +108,9 @@ class IFMConfig { */ class IFMZip { + /** + * Add a folder to the zip file + */ private static function folderToZip($folder, &$zipFile, $exclusiveLength) { $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { @@ -129,7 +132,10 @@ class IFMZip { closedir( $handle ); } - public static function create_zip( $src, $out, $root=false ) + /** + * Create a zip file + */ + public static function create( $src, $out, $root=false ) { $z = new ZipArchive(); $z->open( $out, ZIPARCHIVE::CREATE); @@ -148,11 +154,14 @@ class IFMZip { } } - public static function unzip_file( $file ) { - $zip = new ZipArchive(); + /** + * Unzip a zip file + */ + public function extract( $file, $destination="./" ) { + $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { - $zip->extractTo( './' ); + $zip->extractTo( $destination ); $zip->close(); return true; } else { @@ -1779,7 +1788,7 @@ ifm.init(); echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory." ) ); exit( 1 ); } - if( ! $this->unzip( $d['filename'], $d['targetdir'] ) ) { + if( ! IFMZip::extract( $d['filename'], $d['targetdir'] ) ) { echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); @@ -1871,7 +1880,7 @@ ifm.init(); unset( $zip ); $dfile = $this->pathCombine( IFMConfig::tmp_dir, uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMZip::create_zip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMZip::create( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -2219,19 +2228,6 @@ ifm.init(); return ( strtolower( $a['name'] ) < strtolower( $b['name'] ) ) ? -1 : 1; } - // unzip an archive - private function unzip( $file, $destination="./" ) { - $zip = new ZipArchive; - $res = $zip->open( $file ); - if( $res === true ) { - $zip->extractTo( $destination ); - $zip->close(); - return true; - } else { - return false; - } - } - // is cURL extention avaliable? private function checkCurl() { if( !function_exists( "curl_init" ) || diff --git a/src/ifmzip.php b/src/ifmzip.php index 5f93593..cbc501e 100644 --- a/src/ifmzip.php +++ b/src/ifmzip.php @@ -13,6 +13,9 @@ */ class IFMZip { + /** + * Add a folder to the zip file + */ private static function folderToZip($folder, &$zipFile, $exclusiveLength) { $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { @@ -34,7 +37,10 @@ class IFMZip { closedir( $handle ); } - public static function create_zip( $src, $out, $root=false ) + /** + * Create a zip file + */ + public static function create( $src, $out, $root=false ) { $z = new ZipArchive(); $z->open( $out, ZIPARCHIVE::CREATE); @@ -53,11 +59,14 @@ class IFMZip { } } - public static function unzip_file( $file ) { - $zip = new ZipArchive(); + /** + * Unzip a zip file + */ + public function extract( $file, $destination="./" ) { + $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { - $zip->extractTo( './' ); + $zip->extractTo( $destination ); $zip->close(); return true; } else { diff --git a/src/main.php b/src/main.php index 73efef6..14b4761 100644 --- a/src/main.php +++ b/src/main.php @@ -482,7 +482,7 @@ class IFM { echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory." ) ); exit( 1 ); } - if( ! $this->unzip( $d['filename'], $d['targetdir'] ) ) { + if( ! IFMZip::extract( $d['filename'], $d['targetdir'] ) ) { echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); @@ -574,7 +574,7 @@ class IFM { unset( $zip ); $dfile = $this->pathCombine( IFMConfig::tmp_dir, uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMZip::create_zip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMZip::create( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -922,19 +922,6 @@ class IFM { return ( strtolower( $a['name'] ) < strtolower( $b['name'] ) ) ? -1 : 1; } - // unzip an archive - private function unzip( $file, $destination="./" ) { - $zip = new ZipArchive; - $res = $zip->open( $file ); - if( $res === true ) { - $zip->extractTo( $destination ); - $zip->close(); - return true; - } else { - return false; - } - } - // is cURL extention avaliable? private function checkCurl() { if( !function_exists( "curl_init" ) || From ea3f3922f3b7e8fc309e990f8d8d21a3a96c5daf Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 4 Jul 2017 12:58:23 +0200 Subject: [PATCH 08/36] fix ldap auth example --- ifm.php | 2 +- src/config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ifm.php b/ifm.php index 65d8c0a..78d5c1e 100644 --- a/ifm.php +++ b/ifm.php @@ -62,7 +62,7 @@ class IFMConfig { examples: const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; const auth_source = 'file;/path/to/file'; - const auth_source = 'ldap;:'; + const auth_source = 'ldap;;'; */ const auth = 0; const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; diff --git a/src/config.php b/src/config.php index 5527666..2b8d6a5 100644 --- a/src/config.php +++ b/src/config.php @@ -62,7 +62,7 @@ class IFMConfig { examples: const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; const auth_source = 'file;/path/to/file'; - const auth_source = 'ldap;:'; + const auth_source = 'ldap;;'; */ const auth = 0; const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; From ffb9447352eea9a28db838154c15ebca36bda11e Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 4 Jul 2017 16:02:45 +0200 Subject: [PATCH 09/36] some organizational code changes, prepare for JS templates --- ifm.php | 693 ++++++++++++++++++++++++++++++++++----------------- src/ifm.js | 671 +++++++++++++++++++++++++++++++++---------------- src/main.php | 21 +- 3 files changed, 933 insertions(+), 452 deletions(-) diff --git a/ifm.php b/ifm.php index 78d5c1e..9ad20c5 100644 --- a/ifm.php +++ b/ifm.php @@ -186,14 +186,21 @@ ini_set( 'display_errors', 'OFF' ); class IFM { const VERSION = '2.4.0'; - public function __construct() { + private $config = array(); + + public function __construct( $config ) { session_start(); + if( ! is_array( $config ) ) { + trigger_error( "IFM: could not load config" ); + exit( 1 ); + } else { + $this->config = $config; + } } - /* - this function contains the client-side application + /** + * This function contains the client-side application */ - public function getApplication() { print ' @@ -488,19 +495,49 @@ this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+th //# sourceMappingURL=ekko-lightbox.min.js.map - + @@ -1443,6 +1681,9 @@ ifm.init(); $this->getFiles( $_REQUEST["dir"] ); else $this->getFiles( "" ); + } + elseif( $_REQUEST["api"] == "getConfig" ) { + echo json_encode( IFMConfig::getConstants() ); } else { if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) { switch( $_REQUEST["api"] ) { @@ -2262,5 +2503,5 @@ ifm.init(); start program */ -$ifm = new IFM(); +$ifm = new IFM( IFMConfig::getConstants() ); $ifm->run(); diff --git a/src/ifm.js b/src/ifm.js index 71498a9..aafe3e2 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -1,16 +1,44 @@ -// IFM - js app - -function IFM() { +/** + * IFM constructor + */ +function IFM( params ) { var self = this; // reference to ourself, because "this" does not work within callbacks - this.IFM_SCFN = ""; - this.config = jQuery.parseJSON(''); // serialize the PHP config array, so we can use it in JS too + // set the backend for the application + if( ! params.api ) { + throw new Error( "IFM: no backend configured" ); + } else { + self.api = params.api; + } + + // load the configuration from the backend + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "getConfig" + }, + dataType: "json", + success: function(d) { + self.config = d; + self.log( "configuration loaded" ); + }, + error: function() { + throw new Error( "IFM: could not load configuration" ); + } + }); + this.isDocroot = ; this.editor = null; // global ace editor this.fileChanged = false; // flag for check if file was changed already this.currentDir = ""; // this is the global variable for the current directory; it is used for AJAX requests - // modal functions + /** + * Shows a bootstrap modal + * + * @param string content - content of the modal + * @param object options - options for the modal + */ this.showModal = function( content, options = {} ) { var modal = $( document.createElement( 'div' ) ) .addClass( "modal fade" ) @@ -36,24 +64,38 @@ function IFM() { modal.modal('show'); }; + /** + * Hides a bootstrap modal + */ this.hideModal = function() { $('#ifmmodal').modal('hide'); }; + /** + * Reloads the file table + */ this.refreshFileTable = function () { - var id=self.generateGuid(); - self.task_add("Refresh", id); + var id = self.generateGuid(); + self.task_add( "Refresh", id ); $.ajax({ - url: self.IFM_SCFN, + url: self.api, type: "POST", - data: "api=getFiles&dir=" + self.currentDir, + data: { + api: "getFiles", + dir: self.currentDir + }, dataType: "json", success: self.rebuildFileTable, - error: function(response) { ifm.showMessage("General error occured: No or broken response", "e"); }, + error: function( response ) { self.showMessage( "General error occured: No or broken response", "e" ); }, complete: function() { self.task_done( id ); } }); }; + /** + * Rebuilds the file table with fetched items + * + * @param object data - object with items + */ this.rebuildFileTable = function( data ) { var newTBody = $(document.createElement('tbody')); for( var i=0; i < data.length; i++ ) { @@ -142,12 +184,18 @@ function IFM() { }); }; + /** + * Changes the current directory + * + * @param string newdir - target directory + * @param object options - options for changing the directory + */ this.changeDirectory = function( newdir, options={} ) { config = { absolute: false, pushState: true }; jQuery.extend( config, options ); if( ! config.absolute ) newdir = self.pathCombine( self.currentDir, newdir ); $.ajax({ - url: self.IFM_SCFN, + url: self.api, type: "POST", data: ({ api: "getRealpath", @@ -164,6 +212,9 @@ function IFM() { }); }; + /** + * Shows a file, either a new file or an existing + */ this.showFileForm = function () { var filename = arguments.length > 0 ? arguments[0] : "newfile.txt"; var content = arguments.length > 1 ? arguments[1] : ""; @@ -211,6 +262,9 @@ function IFM() { }); }; + /** + * Shows the create directory dialog + */ this.createDirForm = function() { self.showModal( '
    \