From f3a71b549e77aeb3d2b01c4bfeb1241ff2d66760 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 7 Aug 2017 10:39:15 +0200 Subject: [PATCH 01/19] add drag and drop of filetable items --- build/libifm.php | 379 +++++++++++++++++++++-------------- ifm.php | 379 +++++++++++++++++++++-------------- src/ifm.js | 169 ++++++++++------ src/main.php | 208 ++++++++++--------- src/templates/filetable.html | 2 +- 5 files changed, 669 insertions(+), 468 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 4cb492f..79a85fd 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -250,7 +250,7 @@ body { f00bar; $templates['filetable'] = <<<'f00bar' {{#items}} - + @@ -1171,6 +1171,7 @@ function IFM( params ) { } } if( ! self.inArray( item.name, [".", ".."] ) ) { + item.dragdrop = 'draggable="true"'; if( self.config.copymove ) item.button.push({ action: "copymove", @@ -1725,42 +1726,38 @@ function IFM( params ) { /** * Copy or moves a file * - * @params {string} source - name of the file + * @params {string} sources - array of fileCache items * @params {string} destination - target directory * @params {string} action - action (copy|move) */ this.copyMove = function( sources, destination, action ) { - if( ! Array.isArray( sources ) ) - sources = [sources]; - sources.forEach( function( source ) { - var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); - $.ajax({ - url: self.api, - type: "POST", - data: { - dir: self.currentDir, - api: "copyMove", - action: action, - filename: source.name, - destination: destination - }, - dataType: "json", - success: function( data ) { - if( data.status == "OK" ) { - self.showMessage( data.message, "s" ); - } else { - self.showMessage( data.message, "e" ); - } - self.refreshFileTable(); - }, - error: function() { - self.showMessage( "General error occured.", "e" ); - }, - complete: function() { - self.task_done( id ); + var id = self.generateGuid(); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " files to " + destination } ); + $.ajax({ + url: self.api, + type: "POST", + data: { + dir: self.currentDir, + api: "copyMove", + action: action, + filenames: sources.map( function( e ) { return e.name } ), + destination: destination + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( data.message, "s" ); + } else { + self.showMessage( data.message, "e" ); } - }); + self.refreshFileTable(); + }, + error: function() { + self.showMessage( "General error occured.", "e" ); + }, + complete: function() { + self.task_done( id ); + } }); }; @@ -2585,34 +2582,94 @@ function IFM( params ) { if( self.config.ajaxrequest ) document.getElementById( 'buttonAjaxRequest' ).onclick = function() { self.showAjaxRequestDialog(); }; if( self.config.upload ) - document.addEventListener( 'dragover', function( e ) { - e.preventDefault(); - e.stopPropagation(); - var div = document.getElementById( 'filedropoverlay' ); - div.style.display = 'block'; - div.ondrop = function( e ) { + document.addEventListener( 'drag', function( e ) { + if( e.dataTransfer.files.length > 0 ) { e.preventDefault(); e.stopPropagation(); - var files = e.dataTransfer.files; - for( var i = 0; i < files.length; i++ ) { - self.uploadFile( files[i] ); - } - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; - div.ondragleave = function( e ) { - e.preventDefault(); - e.stopPropagation(); - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; + var div = document.getElementById( 'filedropoverlay' ); + div.style.display = 'block'; + div.ondrop = function( e ) { + e.preventDefault(); + e.stopPropagation(); + var files = e.dataTransfer.files; + for( var i = 0; i < files.length; i++ ) { + self.uploadFile( files[i] ); + } + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + div.ondragleave = function( e ) { + e.preventDefault(); + e.stopPropagation(); + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + } }); + + // drag and drop of filetable items + if( self.config.copymove ) { + document.addEventListener( 'dragstart', function( e ) { + var selectedItems = document.getElementsByClassName( 'selectedItem' ); + var data; + if( selectedItems.length > 0 ) + data = self.fileCache.filter( + x => self.inArray( + x.guid, + [].slice.call( selectedItems ).map( function( e ) { return e.dataset.id; } ) + ) + ); + else + data = self.fileCache.find( x => x.guid === e.target.dataset.id ); + e.dataTransfer.setData( 'text/plain', JSON.stringify( data ) ); + var dragImage = document.createElement( 'div' ); + dragImage.style.display = 'inline'; + dragImage.style.padding = '10px'; + dragImage.innerHTML = ' move '+( data.length || data.name ); + document.body.appendChild( dragImage ); + setTimeout(function() { + dragImage.remove(); + }); + e.dataTransfer.setDragImage( dragImage, 0, 0 ); + }); + document.addEventListener( 'dragover', function( e ) { e.preventDefault(); } ); + document.addEventListener( 'dragenter', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.add( 'highlightedItem' ); + }); + document.addEventListener( 'dragleave', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.remove( 'highlightedItem' ); + }); + document.addEventListener( 'drop', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) { + try { + var source = JSON.parse( e.dataTransfer.getData( 'text' ) ); + console.log( "source:" ); + console.log( source ); + var destination = self.fileCache.find( x => x.guid === e.target.firstElementChild.id ); + if( ! Array.isArray( source ) ) + source = [source]; + if( source.find( x => x.name === destination.name ) ) + self.showMessage( "Source and destination are equal." ); + else + self.copyMove( source, destination.name, "move" ); + } catch( e ) { + console.log( e ); + } finally { + [].slice.call( document.getElementsByClassName( 'highlightedItem' ) ).forEach( function( e ) { + e.classList.remove( 'highlightedItem' ); + }); + } + } + }); + } // handle keystrokes document.onkeydown = self.handleKeystrokes; @@ -2660,9 +2717,9 @@ function IFM( params ) { private function handleRequest() { if( $_REQUEST["api"] == "getRealpath" ) { if( isset( $_REQUEST["dir"] ) && $_REQUEST["dir"] != "" ) - echo $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); + $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); else - echo $this->jsonResponse( array( "realpath" => "" ) ); + $this->jsonResponse( array( "realpath" => "" ) ); } elseif( $_REQUEST["api"] == "getFiles" ) { if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) @@ -2676,9 +2733,9 @@ function IFM( params ) { elseif( $_REQUEST["api"] == "getFolders" ) { $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { - echo $this->jsonResponse( $this->templates ); + $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - echo $this->jsonResponse( $this->i18n[$this->config['language']] ); + $this->jsonResponse( $this->i18n[$this->config['language']] ); } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); @@ -2703,7 +2760,7 @@ function IFM( params ) { case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; case "createArchive": $this->createArchive( $_REQUEST ); break; default: - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); break; } } else { @@ -2813,7 +2870,7 @@ function IFM( params ) { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; $ret['isDocroot'] = ( $this->getRootDir() == $this->getScriptRoot() ) ? true : false; - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } private function getFolders( $d ) { @@ -2841,7 +2898,7 @@ function IFM( params ) { ), $ret ); - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } } @@ -2853,9 +2910,9 @@ function IFM( params ) { } try { $results = $this->searchItemsRecursive( $d['pattern'] ); - echo $this->jsonResponse( $results ); + $this->jsonResponse( $results ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } @@ -2872,7 +2929,7 @@ function IFM( params ) { } private function getFolderTree( $d ) { - echo $this->jsonResponse( + $this->jsonResponse( array_merge( array( 0 => array( @@ -2911,65 +2968,75 @@ function IFM( params ) { private function copyMove( $d ) { if( $this->config['copymove'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + $this->jsonResponse( 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 $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); exit( 1 ); } - if( ! file_exists( $d['filename'] ) || $d['filename'] == ".." ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given." ) ); + if( ! is_array( $d['filenames'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid parameters given" ) ); exit( 1 ); } - if( $d['action'] == "copy" ) { - if( $this->xcopy( $d['filename'], $d['destination'] ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully copied." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } elseif( $d['action'] == "move" ) { - if( rename( $d['filename'], $this->pathCombine( $d['destination'], basename( $d['filename'] ) ) ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully moved." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given." ) ); + if( ! in_array( $d['action'], array( 'copy', 'move' ) ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given" ) ); exit( 1 ); } + $err = array(); $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors + foreach( $d['filenames'] as $file ) { + if( ! file_exists( $file ) || $file == ".." || ! $this->isFilenameValid( $file ) ) { + array_push( $err, $file ); + } + if( $d['action'] == "copy" ) { + if( $this->xcopy( $file, $d['destination'] ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } elseif( $d['action'] == "move" ) { + if( rename( $file, $this->pathCombine( $d['destination'], basename( $file ) ) ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } + } + $action = ( $d['action'] == "copy" ? "copied" : "moved" ); + if( empty( $err ) ) { + $this->jsonResponse( array( "status" => "OK", "message" => "File(s) $action successfully", "errflag" => "1" ) ); + } + else { + $errmsg = "The following files could not be deleted:"; + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + } } // creates a directory private function createDir($w, $dn) { if( $this->config['createdir'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); exit( 1 ); } if( $dn == "" ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); elseif( ! $this->isFilenameValid( $dn ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); else { $this->chDirIfNecessary( $w ); if( @mkdir( $dn ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); } } // save a file private function saveFile( $d ) { if( ( file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['edit'] != 1 ) || ( ! file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['createfile'] != 1 ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); exit( 1 ); } if( isset( $d['filename'] ) && $this->isFilenameValid( $d['filename'] ) ) { @@ -2978,28 +3045,28 @@ function IFM( params ) { // work around magic quotes $content = get_magic_quotes_gpc() == 1 ? stripslashes( $d['content'] ) : $d['content']; if( @file_put_contents( $d['filename'], $content ) !== false ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); } // gets the content of a file // notice: if the content is not JSON encodable it returns an error private function getContent( array $d ) { if( $this->config['edit'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( isset( $d['filename'] ) && $this->isFilenameAllowed( $d['filename'] ) && file_exists( $d['filename'] ) && is_readable( $d['filename'] ) ) { $content = @file_get_contents( $d['filename'] ); if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $content, "UTF-8" ) ) $content = utf8_encode( $content ); - echo $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); - } else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); + $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); + } else $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); } } @@ -3028,14 +3095,14 @@ function IFM( params ) { } } if( empty( $err ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); } else { $errmsg = "The following files could not be deleted:"; - echo $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); } } } @@ -3043,22 +3110,22 @@ function IFM( params ) { // renames a file private function renameFile( array $d ) { if( $this->config['rename'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); } elseif( ! $this->isFilenameValid( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); if( strpos( $d['newname'], '/' ) !== false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); else { if( @rename( $d['filename'], $d['newname'] ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); } } } @@ -3066,11 +3133,11 @@ function IFM( params ) { // provides a file for downloading private function downloadFile( array $d ) { if( $this->config['download'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); else { $this->chDirIfNecessary( $d["dir"] ); $this->fileDownload( $d['filename'] ); @@ -3080,34 +3147,34 @@ function IFM( params ) { // extracts a zip-archive private function extractFile( array $d ) { if( $this->config['extract'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); exit( 1 ); } if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) $d['targetdir'] = "./"; if( ! $this->isPathValid( $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); exit( 1 ); } if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); exit( 1 ); } if( substr( strtolower( $d['filename'] ), -4 ) == ".zip" ) { if( ! IFMArchive::extractZip( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } else { if( ! IFMArchive::extractTar( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } } @@ -3116,35 +3183,35 @@ function IFM( params ) { // uploads a file private function uploadFile( array $d ) { if( $this->config['upload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); elseif( !isset( $_FILES['file'] ) ) - echo $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); + $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); else { $this->chDirIfNecessary( $d['dir'] ); $newfilename = ( isset( $d["newfilename"] ) && $d["newfilename"]!="" ) ? $d["newfilename"] : $_FILES['file']['name']; if( ! $this->isFilenameValid( $newfilename ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); else { if( $_FILES['file']['tmp_name'] ) { if( is_writable( getcwd( ) ) ) { if( move_uploaded_file( $_FILES['file']['tmp_name'], $newfilename ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); } } } // change permissions of a file private function changePermissions( array $d ) { - if( $this->config['chmod'] != 1 ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); - elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); - elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } + if( $this->config['chmod'] != 1 ) $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); + elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); + elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); $chmod = $d["chmod"]; $cmi = true; if( ! is_numeric( $chmod ) ) { @@ -3169,12 +3236,12 @@ function IFM( params ) { if( $cmi ) { try { chmod( $d["filename"], (int)octdec( $chmod ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); } catch ( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); } } - else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); + else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); } } @@ -3182,13 +3249,13 @@ function IFM( params ) { // it creates a temporary zip file in the current directory, so it has to be as much space free as the file size is private function zipnload( array $d ) { if( $this->config['zipnload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); elseif ( ! $this->isFilenameValid( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); else { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename @@ -3213,59 +3280,59 @@ function IFM( params ) { // uploads a file from an other server using the curl extention private function remoteUpload( array $d ) { if( $this->config['remoteupload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); elseif( !isset( $d['method'] ) || !in_array( $d['method'], array( "curl", "file" ) ) ) - echo $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == true ) { $filename = ( isset( $d['filename'] )&&$d['filename']!="" )?$d['filename']:"curl_".uniqid( ); $this->chDirIfNecessary( $d['dir'] ); $ch = curl_init( ); if( $ch ) { if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); elseif( filter_var( $d['url'], FILTER_VALIDATE_URL ) === false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); else { $fp = fopen( $filename, "w" ); if( $fp ) { if( !curl_setopt( $ch, CURLOPT_URL, $d['url'] ) || !curl_setopt( $ch, CURLOPT_FILE, $fp ) || !curl_setopt( $ch, CURLOPT_HEADER, 0 ) || !curl_exec( $ch ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); else { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); } curl_close( $ch ); fclose( $fp ); } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); } } } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); } } elseif( $d['method']=='file' ) { $filename = ( isset( $d['filename'] ) && $d['filename']!="" ) ? $d['filename'] : "curl_".uniqid( ); if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); else { $this->chDirIfNecessary( $d['dir'] ); try { file_put_contents( $filename, file_get_contents( $d['url'] ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } } else - echo $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } private function createArchive( $d ) { // if( $config['createarchive'] != 1 ) { -// echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); +// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); // return false; // } // $this->chDirIfNecessary( $d['dir'] ); @@ -3345,9 +3412,9 @@ function IFM( params ) { } else { if( isset( $_POST["api"] ) ) { if( $login_failed === true ) - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); else - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); } else { $this->loginForm($login_failed); } diff --git a/ifm.php b/ifm.php index 09a841d..608def5 100644 --- a/ifm.php +++ b/ifm.php @@ -250,7 +250,7 @@ body { f00bar; $templates['filetable'] = <<<'f00bar' {{#items}} - + @@ -1171,6 +1171,7 @@ function IFM( params ) { } } if( ! self.inArray( item.name, [".", ".."] ) ) { + item.dragdrop = 'draggable="true"'; if( self.config.copymove ) item.button.push({ action: "copymove", @@ -1725,42 +1726,38 @@ function IFM( params ) { /** * Copy or moves a file * - * @params {string} source - name of the file + * @params {string} sources - array of fileCache items * @params {string} destination - target directory * @params {string} action - action (copy|move) */ this.copyMove = function( sources, destination, action ) { - if( ! Array.isArray( sources ) ) - sources = [sources]; - sources.forEach( function( source ) { - var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); - $.ajax({ - url: self.api, - type: "POST", - data: { - dir: self.currentDir, - api: "copyMove", - action: action, - filename: source.name, - destination: destination - }, - dataType: "json", - success: function( data ) { - if( data.status == "OK" ) { - self.showMessage( data.message, "s" ); - } else { - self.showMessage( data.message, "e" ); - } - self.refreshFileTable(); - }, - error: function() { - self.showMessage( "General error occured.", "e" ); - }, - complete: function() { - self.task_done( id ); + var id = self.generateGuid(); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " files to " + destination } ); + $.ajax({ + url: self.api, + type: "POST", + data: { + dir: self.currentDir, + api: "copyMove", + action: action, + filenames: sources.map( function( e ) { return e.name } ), + destination: destination + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( data.message, "s" ); + } else { + self.showMessage( data.message, "e" ); } - }); + self.refreshFileTable(); + }, + error: function() { + self.showMessage( "General error occured.", "e" ); + }, + complete: function() { + self.task_done( id ); + } }); }; @@ -2585,34 +2582,94 @@ function IFM( params ) { if( self.config.ajaxrequest ) document.getElementById( 'buttonAjaxRequest' ).onclick = function() { self.showAjaxRequestDialog(); }; if( self.config.upload ) - document.addEventListener( 'dragover', function( e ) { - e.preventDefault(); - e.stopPropagation(); - var div = document.getElementById( 'filedropoverlay' ); - div.style.display = 'block'; - div.ondrop = function( e ) { + document.addEventListener( 'drag', function( e ) { + if( e.dataTransfer.files.length > 0 ) { e.preventDefault(); e.stopPropagation(); - var files = e.dataTransfer.files; - for( var i = 0; i < files.length; i++ ) { - self.uploadFile( files[i] ); - } - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; - div.ondragleave = function( e ) { - e.preventDefault(); - e.stopPropagation(); - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; + var div = document.getElementById( 'filedropoverlay' ); + div.style.display = 'block'; + div.ondrop = function( e ) { + e.preventDefault(); + e.stopPropagation(); + var files = e.dataTransfer.files; + for( var i = 0; i < files.length; i++ ) { + self.uploadFile( files[i] ); + } + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + div.ondragleave = function( e ) { + e.preventDefault(); + e.stopPropagation(); + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + } }); + + // drag and drop of filetable items + if( self.config.copymove ) { + document.addEventListener( 'dragstart', function( e ) { + var selectedItems = document.getElementsByClassName( 'selectedItem' ); + var data; + if( selectedItems.length > 0 ) + data = self.fileCache.filter( + x => self.inArray( + x.guid, + [].slice.call( selectedItems ).map( function( e ) { return e.dataset.id; } ) + ) + ); + else + data = self.fileCache.find( x => x.guid === e.target.dataset.id ); + e.dataTransfer.setData( 'text/plain', JSON.stringify( data ) ); + var dragImage = document.createElement( 'div' ); + dragImage.style.display = 'inline'; + dragImage.style.padding = '10px'; + dragImage.innerHTML = ' move '+( data.length || data.name ); + document.body.appendChild( dragImage ); + setTimeout(function() { + dragImage.remove(); + }); + e.dataTransfer.setDragImage( dragImage, 0, 0 ); + }); + document.addEventListener( 'dragover', function( e ) { e.preventDefault(); } ); + document.addEventListener( 'dragenter', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.add( 'highlightedItem' ); + }); + document.addEventListener( 'dragleave', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.remove( 'highlightedItem' ); + }); + document.addEventListener( 'drop', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) { + try { + var source = JSON.parse( e.dataTransfer.getData( 'text' ) ); + console.log( "source:" ); + console.log( source ); + var destination = self.fileCache.find( x => x.guid === e.target.firstElementChild.id ); + if( ! Array.isArray( source ) ) + source = [source]; + if( source.find( x => x.name === destination.name ) ) + self.showMessage( "Source and destination are equal." ); + else + self.copyMove( source, destination.name, "move" ); + } catch( e ) { + console.log( e ); + } finally { + [].slice.call( document.getElementsByClassName( 'highlightedItem' ) ).forEach( function( e ) { + e.classList.remove( 'highlightedItem' ); + }); + } + } + }); + } // handle keystrokes document.onkeydown = self.handleKeystrokes; @@ -2660,9 +2717,9 @@ function IFM( params ) { private function handleRequest() { if( $_REQUEST["api"] == "getRealpath" ) { if( isset( $_REQUEST["dir"] ) && $_REQUEST["dir"] != "" ) - echo $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); + $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); else - echo $this->jsonResponse( array( "realpath" => "" ) ); + $this->jsonResponse( array( "realpath" => "" ) ); } elseif( $_REQUEST["api"] == "getFiles" ) { if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) @@ -2676,9 +2733,9 @@ function IFM( params ) { elseif( $_REQUEST["api"] == "getFolders" ) { $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { - echo $this->jsonResponse( $this->templates ); + $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - echo $this->jsonResponse( $this->i18n[$this->config['language']] ); + $this->jsonResponse( $this->i18n[$this->config['language']] ); } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); @@ -2703,7 +2760,7 @@ function IFM( params ) { case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; case "createArchive": $this->createArchive( $_REQUEST ); break; default: - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); break; } } else { @@ -2813,7 +2870,7 @@ function IFM( params ) { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; $ret['isDocroot'] = ( $this->getRootDir() == $this->getScriptRoot() ) ? true : false; - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } private function getFolders( $d ) { @@ -2841,7 +2898,7 @@ function IFM( params ) { ), $ret ); - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } } @@ -2853,9 +2910,9 @@ function IFM( params ) { } try { $results = $this->searchItemsRecursive( $d['pattern'] ); - echo $this->jsonResponse( $results ); + $this->jsonResponse( $results ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } @@ -2872,7 +2929,7 @@ function IFM( params ) { } private function getFolderTree( $d ) { - echo $this->jsonResponse( + $this->jsonResponse( array_merge( array( 0 => array( @@ -2911,65 +2968,75 @@ function IFM( params ) { private function copyMove( $d ) { if( $this->config['copymove'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + $this->jsonResponse( 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 $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); exit( 1 ); } - if( ! file_exists( $d['filename'] ) || $d['filename'] == ".." ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given." ) ); + if( ! is_array( $d['filenames'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid parameters given" ) ); exit( 1 ); } - if( $d['action'] == "copy" ) { - if( $this->xcopy( $d['filename'], $d['destination'] ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully copied." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } elseif( $d['action'] == "move" ) { - if( rename( $d['filename'], $this->pathCombine( $d['destination'], basename( $d['filename'] ) ) ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully moved." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given." ) ); + if( ! in_array( $d['action'], array( 'copy', 'move' ) ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given" ) ); exit( 1 ); } + $err = array(); $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors + foreach( $d['filenames'] as $file ) { + if( ! file_exists( $file ) || $file == ".." || ! $this->isFilenameValid( $file ) ) { + array_push( $err, $file ); + } + if( $d['action'] == "copy" ) { + if( $this->xcopy( $file, $d['destination'] ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } elseif( $d['action'] == "move" ) { + if( rename( $file, $this->pathCombine( $d['destination'], basename( $file ) ) ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } + } + $action = ( $d['action'] == "copy" ? "copied" : "moved" ); + if( empty( $err ) ) { + $this->jsonResponse( array( "status" => "OK", "message" => "File(s) $action successfully", "errflag" => "1" ) ); + } + else { + $errmsg = "The following files could not be deleted:"; + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + } } // creates a directory private function createDir($w, $dn) { if( $this->config['createdir'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); exit( 1 ); } if( $dn == "" ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); elseif( ! $this->isFilenameValid( $dn ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); else { $this->chDirIfNecessary( $w ); if( @mkdir( $dn ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); } } // save a file private function saveFile( $d ) { if( ( file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['edit'] != 1 ) || ( ! file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['createfile'] != 1 ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); exit( 1 ); } if( isset( $d['filename'] ) && $this->isFilenameValid( $d['filename'] ) ) { @@ -2978,28 +3045,28 @@ function IFM( params ) { // work around magic quotes $content = get_magic_quotes_gpc() == 1 ? stripslashes( $d['content'] ) : $d['content']; if( @file_put_contents( $d['filename'], $content ) !== false ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); } // gets the content of a file // notice: if the content is not JSON encodable it returns an error private function getContent( array $d ) { if( $this->config['edit'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( isset( $d['filename'] ) && $this->isFilenameAllowed( $d['filename'] ) && file_exists( $d['filename'] ) && is_readable( $d['filename'] ) ) { $content = @file_get_contents( $d['filename'] ); if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $content, "UTF-8" ) ) $content = utf8_encode( $content ); - echo $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); - } else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); + $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); + } else $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); } } @@ -3028,14 +3095,14 @@ function IFM( params ) { } } if( empty( $err ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); } else { $errmsg = "The following files could not be deleted:"; - echo $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); } } } @@ -3043,22 +3110,22 @@ function IFM( params ) { // renames a file private function renameFile( array $d ) { if( $this->config['rename'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); } elseif( ! $this->isFilenameValid( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); if( strpos( $d['newname'], '/' ) !== false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); else { if( @rename( $d['filename'], $d['newname'] ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); } } } @@ -3066,11 +3133,11 @@ function IFM( params ) { // provides a file for downloading private function downloadFile( array $d ) { if( $this->config['download'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); else { $this->chDirIfNecessary( $d["dir"] ); $this->fileDownload( $d['filename'] ); @@ -3080,34 +3147,34 @@ function IFM( params ) { // extracts a zip-archive private function extractFile( array $d ) { if( $this->config['extract'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); exit( 1 ); } if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) $d['targetdir'] = "./"; if( ! $this->isPathValid( $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); exit( 1 ); } if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); exit( 1 ); } if( substr( strtolower( $d['filename'] ), -4 ) == ".zip" ) { if( ! IFMArchive::extractZip( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } else { if( ! IFMArchive::extractTar( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } } @@ -3116,35 +3183,35 @@ function IFM( params ) { // uploads a file private function uploadFile( array $d ) { if( $this->config['upload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); elseif( !isset( $_FILES['file'] ) ) - echo $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); + $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); else { $this->chDirIfNecessary( $d['dir'] ); $newfilename = ( isset( $d["newfilename"] ) && $d["newfilename"]!="" ) ? $d["newfilename"] : $_FILES['file']['name']; if( ! $this->isFilenameValid( $newfilename ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); else { if( $_FILES['file']['tmp_name'] ) { if( is_writable( getcwd( ) ) ) { if( move_uploaded_file( $_FILES['file']['tmp_name'], $newfilename ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); } } } // change permissions of a file private function changePermissions( array $d ) { - if( $this->config['chmod'] != 1 ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); - elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); - elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } + if( $this->config['chmod'] != 1 ) $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); + elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); + elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); $chmod = $d["chmod"]; $cmi = true; if( ! is_numeric( $chmod ) ) { @@ -3169,12 +3236,12 @@ function IFM( params ) { if( $cmi ) { try { chmod( $d["filename"], (int)octdec( $chmod ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); } catch ( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); } } - else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); + else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); } } @@ -3182,13 +3249,13 @@ function IFM( params ) { // it creates a temporary zip file in the current directory, so it has to be as much space free as the file size is private function zipnload( array $d ) { if( $this->config['zipnload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); elseif ( ! $this->isFilenameValid( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); else { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename @@ -3213,59 +3280,59 @@ function IFM( params ) { // uploads a file from an other server using the curl extention private function remoteUpload( array $d ) { if( $this->config['remoteupload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); elseif( !isset( $d['method'] ) || !in_array( $d['method'], array( "curl", "file" ) ) ) - echo $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == true ) { $filename = ( isset( $d['filename'] )&&$d['filename']!="" )?$d['filename']:"curl_".uniqid( ); $this->chDirIfNecessary( $d['dir'] ); $ch = curl_init( ); if( $ch ) { if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); elseif( filter_var( $d['url'], FILTER_VALIDATE_URL ) === false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); else { $fp = fopen( $filename, "w" ); if( $fp ) { if( !curl_setopt( $ch, CURLOPT_URL, $d['url'] ) || !curl_setopt( $ch, CURLOPT_FILE, $fp ) || !curl_setopt( $ch, CURLOPT_HEADER, 0 ) || !curl_exec( $ch ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); else { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); } curl_close( $ch ); fclose( $fp ); } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); } } } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); } } elseif( $d['method']=='file' ) { $filename = ( isset( $d['filename'] ) && $d['filename']!="" ) ? $d['filename'] : "curl_".uniqid( ); if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); else { $this->chDirIfNecessary( $d['dir'] ); try { file_put_contents( $filename, file_get_contents( $d['url'] ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } } else - echo $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } private function createArchive( $d ) { // if( $config['createarchive'] != 1 ) { -// echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); +// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); // return false; // } // $this->chDirIfNecessary( $d['dir'] ); @@ -3345,9 +3412,9 @@ function IFM( params ) { } else { if( isset( $_POST["api"] ) ) { if( $login_failed === true ) - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); else - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); } else { $this->loginForm($login_failed); } diff --git a/src/ifm.js b/src/ifm.js index 5e51fa6..a589cf2 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -140,6 +140,7 @@ function IFM( params ) { } } if( ! self.inArray( item.name, [".", ".."] ) ) { + item.dragdrop = 'draggable="true"'; if( self.config.copymove ) item.button.push({ action: "copymove", @@ -694,42 +695,38 @@ function IFM( params ) { /** * Copy or moves a file * - * @params {string} source - name of the file + * @params {string} sources - array of fileCache items * @params {string} destination - target directory * @params {string} action - action (copy|move) */ this.copyMove = function( sources, destination, action ) { - if( ! Array.isArray( sources ) ) - sources = [sources]; - sources.forEach( function( source ) { - var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); - $.ajax({ - url: self.api, - type: "POST", - data: { - dir: self.currentDir, - api: "copyMove", - action: action, - filename: source.name, - destination: destination - }, - dataType: "json", - success: function( data ) { - if( data.status == "OK" ) { - self.showMessage( data.message, "s" ); - } else { - self.showMessage( data.message, "e" ); - } - self.refreshFileTable(); - }, - error: function() { - self.showMessage( "General error occured.", "e" ); - }, - complete: function() { - self.task_done( id ); + var id = self.generateGuid(); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " files to " + destination } ); + $.ajax({ + url: self.api, + type: "POST", + data: { + dir: self.currentDir, + api: "copyMove", + action: action, + filenames: sources.map( function( e ) { return e.name } ), + destination: destination + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( data.message, "s" ); + } else { + self.showMessage( data.message, "e" ); } - }); + self.refreshFileTable(); + }, + error: function() { + self.showMessage( "General error occured.", "e" ); + }, + complete: function() { + self.task_done( id ); + } }); }; @@ -1554,34 +1551,94 @@ function IFM( params ) { if( self.config.ajaxrequest ) document.getElementById( 'buttonAjaxRequest' ).onclick = function() { self.showAjaxRequestDialog(); }; if( self.config.upload ) - document.addEventListener( 'dragover', function( e ) { - e.preventDefault(); - e.stopPropagation(); - var div = document.getElementById( 'filedropoverlay' ); - div.style.display = 'block'; - div.ondrop = function( e ) { + document.addEventListener( 'drag', function( e ) { + if( e.dataTransfer.files.length > 0 ) { e.preventDefault(); e.stopPropagation(); - var files = e.dataTransfer.files; - for( var i = 0; i < files.length; i++ ) { - self.uploadFile( files[i] ); - } - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; - div.ondragleave = function( e ) { - e.preventDefault(); - e.stopPropagation(); - if( e.target.id == 'filedropoverlay' ) - e.target.style.display = 'none'; - else if( e.target.parentElement.id == 'filedropoverlay' ) { - e.target.parentElement.style.display = 'none'; - } - }; + var div = document.getElementById( 'filedropoverlay' ); + div.style.display = 'block'; + div.ondrop = function( e ) { + e.preventDefault(); + e.stopPropagation(); + var files = e.dataTransfer.files; + for( var i = 0; i < files.length; i++ ) { + self.uploadFile( files[i] ); + } + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + div.ondragleave = function( e ) { + e.preventDefault(); + e.stopPropagation(); + if( e.target.id == 'filedropoverlay' ) + e.target.style.display = 'none'; + else if( e.target.parentElement.id == 'filedropoverlay' ) { + e.target.parentElement.style.display = 'none'; + } + }; + } }); + + // drag and drop of filetable items + if( self.config.copymove ) { + document.addEventListener( 'dragstart', function( e ) { + var selectedItems = document.getElementsByClassName( 'selectedItem' ); + var data; + if( selectedItems.length > 0 ) + data = self.fileCache.filter( + x => self.inArray( + x.guid, + [].slice.call( selectedItems ).map( function( e ) { return e.dataset.id; } ) + ) + ); + else + data = self.fileCache.find( x => x.guid === e.target.dataset.id ); + e.dataTransfer.setData( 'text/plain', JSON.stringify( data ) ); + var dragImage = document.createElement( 'div' ); + dragImage.style.display = 'inline'; + dragImage.style.padding = '10px'; + dragImage.innerHTML = ' move '+( data.length || data.name ); + document.body.appendChild( dragImage ); + setTimeout(function() { + dragImage.remove(); + }); + e.dataTransfer.setDragImage( dragImage, 0, 0 ); + }); + document.addEventListener( 'dragover', function( e ) { e.preventDefault(); } ); + document.addEventListener( 'dragenter', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.add( 'highlightedItem' ); + }); + document.addEventListener( 'dragleave', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) + e.target.parentElement.classList.remove( 'highlightedItem' ); + }); + document.addEventListener( 'drop', function( e ) { + if( e.target.parentElement.classList.contains( 'isDir' ) ) { + try { + var source = JSON.parse( e.dataTransfer.getData( 'text' ) ); + console.log( "source:" ); + console.log( source ); + var destination = self.fileCache.find( x => x.guid === e.target.firstElementChild.id ); + if( ! Array.isArray( source ) ) + source = [source]; + if( source.find( x => x.name === destination.name ) ) + self.showMessage( "Source and destination are equal." ); + else + self.copyMove( source, destination.name, "move" ); + } catch( e ) { + console.log( e ); + } finally { + [].slice.call( document.getElementsByClassName( 'highlightedItem' ) ).forEach( function( e ) { + e.classList.remove( 'highlightedItem' ); + }); + } + } + }); + } // handle keystrokes document.onkeydown = self.handleKeystrokes; diff --git a/src/main.php b/src/main.php index 311449f..2ce1dbc 100644 --- a/src/main.php +++ b/src/main.php @@ -228,9 +228,9 @@ f00bar; private function handleRequest() { if( $_REQUEST["api"] == "getRealpath" ) { if( isset( $_REQUEST["dir"] ) && $_REQUEST["dir"] != "" ) - echo $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); + $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); else - echo $this->jsonResponse( array( "realpath" => "" ) ); + $this->jsonResponse( array( "realpath" => "" ) ); } elseif( $_REQUEST["api"] == "getFiles" ) { if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) @@ -244,9 +244,9 @@ f00bar; elseif( $_REQUEST["api"] == "getFolders" ) { $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { - echo $this->jsonResponse( $this->templates ); + $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - echo $this->jsonResponse( $this->i18n[$this->config['language']] ); + $this->jsonResponse( $this->i18n[$this->config['language']] ); } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); @@ -271,7 +271,7 @@ f00bar; case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; case "createArchive": $this->createArchive( $_REQUEST ); break; default: - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); break; } } else { @@ -381,7 +381,7 @@ f00bar; $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; $ret['isDocroot'] = ( $this->getRootDir() == $this->getScriptRoot() ) ? true : false; - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } private function getFolders( $d ) { @@ -409,7 +409,7 @@ f00bar; ), $ret ); - echo $this->jsonResponse( $ret ); + $this->jsonResponse( $ret ); } } @@ -421,9 +421,9 @@ f00bar; } try { $results = $this->searchItemsRecursive( $d['pattern'] ); - echo $this->jsonResponse( $results ); + $this->jsonResponse( $results ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } @@ -440,7 +440,7 @@ f00bar; } private function getFolderTree( $d ) { - echo $this->jsonResponse( + $this->jsonResponse( array_merge( array( 0 => array( @@ -479,65 +479,75 @@ f00bar; private function copyMove( $d ) { if( $this->config['copymove'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + $this->jsonResponse( 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 $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); exit( 1 ); } - if( ! file_exists( $d['filename'] ) || $d['filename'] == ".." ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given." ) ); + if( ! is_array( $d['filenames'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid parameters given" ) ); exit( 1 ); } - if( $d['action'] == "copy" ) { - if( $this->xcopy( $d['filename'], $d['destination'] ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully copied." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } elseif( $d['action'] == "move" ) { - if( rename( $d['filename'], $this->pathCombine( $d['destination'], basename( $d['filename'] ) ) ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File(s) were successfully moved." ) ); - exit( 0 ); - } else { - $err = error_get_last(); - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $err['message'] ) ); - exit( 1 ); - } - } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given." ) ); + if( ! in_array( $d['action'], array( 'copy', 'move' ) ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given" ) ); exit( 1 ); } + $err = array(); $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors + foreach( $d['filenames'] as $file ) { + if( ! file_exists( $file ) || $file == ".." || ! $this->isFilenameValid( $file ) ) { + array_push( $err, $file ); + } + if( $d['action'] == "copy" ) { + if( $this->xcopy( $file, $d['destination'] ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } elseif( $d['action'] == "move" ) { + if( rename( $file, $this->pathCombine( $d['destination'], basename( $file ) ) ) ) + $errFlag = 0; + else + array_push( $err, $file ); + } + } + $action = ( $d['action'] == "copy" ? "copied" : "moved" ); + if( empty( $err ) ) { + $this->jsonResponse( array( "status" => "OK", "message" => "File(s) $action successfully", "errflag" => "1" ) ); + } + else { + $errmsg = "The following files could not be deleted:"; + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + } } // creates a directory private function createDir($w, $dn) { if( $this->config['createdir'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create directories.") ); exit( 1 ); } if( $dn == "" ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name") ); elseif( ! $this->isFilenameValid( $dn ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid directory name" ) ); else { $this->chDirIfNecessary( $w ); if( @mkdir( $dn ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Directory successful created" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create directory" ) ); } } // save a file private function saveFile( $d ) { if( ( file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['edit'] != 1 ) || ( ! file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['createfile'] != 1 ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) ); exit( 1 ); } if( isset( $d['filename'] ) && $this->isFilenameValid( $d['filename'] ) ) { @@ -546,28 +556,28 @@ f00bar; // work around magic quotes $content = get_magic_quotes_gpc() == 1 ? stripslashes( $d['content'] ) : $d['content']; if( @file_put_contents( $d['filename'], $content ) !== false ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully saved" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not write content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Got no content" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); } // gets the content of a file // notice: if the content is not JSON encodable it returns an error private function getContent( array $d ) { if( $this->config['edit'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( isset( $d['filename'] ) && $this->isFilenameAllowed( $d['filename'] ) && file_exists( $d['filename'] ) && is_readable( $d['filename'] ) ) { $content = @file_get_contents( $d['filename'] ); if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $content, "UTF-8" ) ) $content = utf8_encode( $content ); - echo $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); - } else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); + $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); + } else $this->jsonResponse( array( "status" => "ERROR", "message" => "File not found or not readable." ) ); } } @@ -596,14 +606,14 @@ f00bar; } } if( empty( $err ) ) { - echo $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); } else { $errmsg = "The following files could not be deleted:"; - echo $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); } } } @@ -611,22 +621,22 @@ f00bar; // renames a file private function renameFile( array $d ) { if( $this->config['rename'] != 1 ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); } elseif( ! $this->isFilenameValid( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); if( strpos( $d['newname'], '/' ) !== false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); else { if( @rename( $d['filename'], $d['newname'] ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successful renamed" ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); } } } @@ -634,11 +644,11 @@ f00bar; // provides a file for downloading private function downloadFile( array $d ) { if( $this->config['download'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); else { $this->chDirIfNecessary( $d["dir"] ); $this->fileDownload( $d['filename'] ); @@ -648,34 +658,34 @@ f00bar; // extracts a zip-archive private function extractFile( array $d ) { if( $this->config['extract'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "No valid archive found" ) ); exit( 1 ); } if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) $d['targetdir'] = "./"; if( ! $this->isPathValid( $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); exit( 1 ); } if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "Could not create target directory." ) ); exit( 1 ); } if( substr( strtolower( $d['filename'] ), -4 ) == ".zip" ) { if( ! IFMArchive::extractZip( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } else { if( ! IFMArchive::extractTar( $d['filename'], $d['targetdir'] ) ) { - echo $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + $this->jsonResponse( array( "status" => "ERROR","message" => "File could not be extracted" ) ); } else { - echo $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); + $this->jsonResponse( array( "status" => "OK","message" => "File successfully extracted." ) ); } } } @@ -684,35 +694,35 @@ f00bar; // uploads a file private function uploadFile( array $d ) { if( $this->config['upload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); elseif( !isset( $_FILES['file'] ) ) - echo $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); + $this->jsonResponse( array( "file" => $_FILE,"files" => $_FILES ) ); else { $this->chDirIfNecessary( $d['dir'] ); $newfilename = ( isset( $d["newfilename"] ) && $d["newfilename"]!="" ) ? $d["newfilename"] : $_FILES['file']['name']; if( ! $this->isFilenameValid( $newfilename ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid filename given" ) ); else { if( $_FILES['file']['tmp_name'] ) { if( is_writable( getcwd( ) ) ) { if( move_uploaded_file( $_FILES['file']['tmp_name'], $newfilename ) ) - echo $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); } else - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No file found" ) ); } } } // change permissions of a file private function changePermissions( array $d ) { - if( $this->config['chmod'] != 1 ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); - elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); - elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } + if( $this->config['chmod'] != 1 ) $this->jsonResponse( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); + elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); + elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { $this->jsonResponse( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } else { $this->chDirIfNecessary( $d['dir'] ); $chmod = $d["chmod"]; $cmi = true; if( ! is_numeric( $chmod ) ) { @@ -737,12 +747,12 @@ f00bar; if( $cmi ) { try { chmod( $d["filename"], (int)octdec( $chmod ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); } catch ( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); } } - else echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); + else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); } } @@ -750,13 +760,13 @@ f00bar; // it creates a temporary zip file in the current directory, so it has to be as much space free as the file size is private function zipnload( array $d ) { if( $this->config['zipnload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); else { $this->chDirIfNecessary( $d['dir'] ); if( ! file_exists( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Directory not found" ) ); elseif ( ! $this->isFilenameValid( $d['filename'] ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Filename not valid" ) ); else { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename @@ -781,59 +791,59 @@ f00bar; // uploads a file from an other server using the curl extention private function remoteUpload( array $d ) { if( $this->config['remoteupload'] != 1 ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); elseif( !isset( $d['method'] ) || !in_array( $d['method'], array( "curl", "file" ) ) ) - echo $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Invalid method given. Valid methods: ['curl', 'file']" ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); elseif( $d['method']=="curl" && $this->checkCurl( ) == true ) { $filename = ( isset( $d['filename'] )&&$d['filename']!="" )?$d['filename']:"curl_".uniqid( ); $this->chDirIfNecessary( $d['dir'] ); $ch = curl_init( ); if( $ch ) { if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); elseif( filter_var( $d['url'], FILTER_VALIDATE_URL ) === false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); else { $fp = fopen( $filename, "w" ); if( $fp ) { if( !curl_setopt( $ch, CURLOPT_URL, $d['url'] ) || !curl_setopt( $ch, CURLOPT_FILE, $fp ) || !curl_setopt( $ch, CURLOPT_HEADER, 0 ) || !curl_exec( $ch ) ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); else { - echo $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); } curl_close( $ch ); fclose( $fp ); } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to open file" ) ); } } } else { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); } } elseif( $d['method']=='file' ) { $filename = ( isset( $d['filename'] ) && $d['filename']!="" ) ? $d['filename'] : "curl_".uniqid( ); if( $this->isFilenameValid( $filename ) == false ) - echo $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => "This filename is not valid." ) ); else { $this->chDirIfNecessary( $d['dir'] ); try { file_put_contents( $filename, file_get_contents( $d['url'] ) ); - echo $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => "File successfully uploaded" ) ); } catch( Exception $e ) { - echo $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); } } } else - echo $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); + $this->jsonResponse( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } private function createArchive( $d ) { // if( $config['createarchive'] != 1 ) { -// echo $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); +// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); // return false; // } // $this->chDirIfNecessary( $d['dir'] ); @@ -913,9 +923,9 @@ f00bar; } else { if( isset( $_POST["api"] ) ) { if( $login_failed === true ) - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); else - echo $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); + $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); } else { $this->loginForm($login_failed); } diff --git a/src/templates/filetable.html b/src/templates/filetable.html index 9330f76..5dd0a08 100644 --- a/src/templates/filetable.html +++ b/src/templates/filetable.html @@ -1,5 +1,5 @@ {{#items}} - + From bb424522da765c48a0844b53fc84c2d941f3b362 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 7 Aug 2017 11:00:48 +0200 Subject: [PATCH 02/19] highlight current item if active element is an .ifmitem --- build/libifm.php | 5 ++++- ifm.php | 5 ++++- src/ifm.js | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 79a85fd..be070e3 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -2222,7 +2222,10 @@ function IFM( params ) { var highlightedItem = document.getElementsByClassName( 'highlightedItem' )[0]; if( ! highlightedItem ) { - highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); + if( document.activeElement.classList.contains( 'ifmitem' ) ) + highlight( document.activeElement.parentElement.parentElement ); + else + highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); } else { var newItem = ( direction=="next" ? highlightedItem.nextElementSibling : highlightedItem.previousElementSibling ); if( newItem != null ) diff --git a/ifm.php b/ifm.php index 608def5..8e05db6 100644 --- a/ifm.php +++ b/ifm.php @@ -2222,7 +2222,10 @@ function IFM( params ) { var highlightedItem = document.getElementsByClassName( 'highlightedItem' )[0]; if( ! highlightedItem ) { - highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); + if( document.activeElement.classList.contains( 'ifmitem' ) ) + highlight( document.activeElement.parentElement.parentElement ); + else + highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); } else { var newItem = ( direction=="next" ? highlightedItem.nextElementSibling : highlightedItem.previousElementSibling ); if( newItem != null ) diff --git a/src/ifm.js b/src/ifm.js index a589cf2..7636eed 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -1191,7 +1191,10 @@ function IFM( params ) { var highlightedItem = document.getElementsByClassName( 'highlightedItem' )[0]; if( ! highlightedItem ) { - highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); + if( document.activeElement.classList.contains( 'ifmitem' ) ) + highlight( document.activeElement.parentElement.parentElement ); + else + highlight( document.getElementById( 'filetable' ).tBodies[0].firstElementChild ); } else { var newItem = ( direction=="next" ? highlightedItem.nextElementSibling : highlightedItem.previousElementSibling ); if( newItem != null ) From cbbaf65330bbb98e7bf3b84893b4c713979bbe59 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 8 Aug 2017 16:18:19 +0200 Subject: [PATCH 03/19] add create archive feature --- build/libifm.php | 257 ++++++++++++++++++++----- ifm.php | 257 ++++++++++++++++++++----- src/i18n/de.json | 7 +- src/ifm.js | 85 +++++++- src/ifmarchive.php | 100 ++++++---- src/main.php | 53 ++++- src/templates/modal.createarchive.html | 12 ++ 7 files changed, 612 insertions(+), 159 deletions(-) create mode 100644 src/templates/modal.createarchive.html diff --git a/build/libifm.php b/build/libifm.php index be070e3..19c1e01 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -13,7 +13,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -39,6 +39,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -85,6 +86,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -375,6 +377,21 @@ f00bar; +f00bar; + $templates['createarchive'] = <<<'f00bar' +
+ + +
+ f00bar; $templates['deletefile'] = <<<'f00bar'
@@ -597,6 +614,7 @@ f00bar; $i18n['de'] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -606,11 +624,11 @@ f00bar; "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", @@ -1275,7 +1293,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -1338,6 +1356,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -2044,6 +2078,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -2066,6 +2101,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- @@ -2734,6 +2835,7 @@ function IFM( params ) { $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -3263,7 +3365,7 @@ function IFM( params ) { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -3334,14 +3436,41 @@ function IFM( params ) { } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* @@ -3702,38 +3831,42 @@ function IFM( params ) { } -/* ======================================================================= +/** + * ======================================================================= * Improved File Manager * --------------------- * License: This project is provided under the terms of the MIT LICENSE * http://github.com/misterunknown/ifm/blob/master/LICENSE * ======================================================================= * - * zip class - * - * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 + * archive class + * + * This class provides support for various archive types for the IFM. It can + * create and extract the following formats: + * * zip + * * tar + * * tar.gz + * * tar.bz2 */ class IFMArchive { + /** - * Add a folder to the zip file + * Add a folder to an archive */ - private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + private static function addFolder( &$archive, $folder, $offset=0 ) { + if( $offset == 0 ) + $offset = strlen( dirname( $folder ) ) + 1; + $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -3742,22 +3875,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -3765,17 +3900,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -3783,15 +3939,10 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } /** * htpasswd parser diff --git a/ifm.php b/ifm.php index 8e05db6..c9d0e98 100644 --- a/ifm.php +++ b/ifm.php @@ -13,7 +13,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -39,6 +39,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -85,6 +86,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -375,6 +377,21 @@ f00bar;
+f00bar; + $templates['createarchive'] = <<<'f00bar' +
+ + +
+ f00bar; $templates['deletefile'] = <<<'f00bar'
@@ -597,6 +614,7 @@ f00bar; $i18n['de'] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -606,11 +624,11 @@ f00bar; "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", @@ -1275,7 +1293,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -1338,6 +1356,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -2044,6 +2078,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -2066,6 +2101,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- @@ -2734,6 +2835,7 @@ function IFM( params ) { $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -3263,7 +3365,7 @@ function IFM( params ) { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -3334,14 +3436,41 @@ function IFM( params ) { } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* @@ -3702,38 +3831,42 @@ function IFM( params ) { } -/* ======================================================================= +/** + * ======================================================================= * Improved File Manager * --------------------- * License: This project is provided under the terms of the MIT LICENSE * http://github.com/misterunknown/ifm/blob/master/LICENSE * ======================================================================= * - * zip class - * - * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 + * archive class + * + * This class provides support for various archive types for the IFM. It can + * create and extract the following formats: + * * zip + * * tar + * * tar.gz + * * tar.bz2 */ class IFMArchive { + /** - * Add a folder to the zip file + * Add a folder to an archive */ - private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + private static function addFolder( &$archive, $folder, $offset=0 ) { + if( $offset == 0 ) + $offset = strlen( dirname( $folder ) ) + 1; + $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -3742,22 +3875,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -3765,17 +3900,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -3783,15 +3939,10 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } /** * htpasswd parser diff --git a/src/i18n/de.json b/src/i18n/de.json index 265daec..26b6e4e 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -1,5 +1,6 @@ { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -9,11 +10,11 @@ "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", diff --git a/src/ifm.js b/src/ifm.js index 7636eed..1e5cc28 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -244,7 +244,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -307,6 +307,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -1013,6 +1029,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -1035,6 +1052,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- diff --git a/src/ifmarchive.php b/src/ifmarchive.php index 55ae23c..9ef1f08 100644 --- a/src/ifmarchive.php +++ b/src/ifmarchive.php @@ -1,37 +1,41 @@ addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -40,22 +44,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -63,17 +69,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -81,13 +108,8 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } diff --git a/src/main.php b/src/main.php index 2ce1dbc..ab74310 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.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -40,6 +40,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -86,6 +87,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -123,6 +125,9 @@ f00bar; f00bar; $templates['createdir'] = <<<'f00bar' @@@file:src/templates/modal.createdir.html@@@ +f00bar; + $templates['createarchive'] = <<<'f00bar' +@@@file:src/templates/modal.createarchive.html@@@ f00bar; $templates['deletefile'] = <<<'f00bar' @@@file:src/templates/modal.deletefile.html@@@ @@ -242,6 +247,7 @@ f00bar; $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -771,7 +777,7 @@ f00bar; unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -842,14 +848,41 @@ f00bar; } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* diff --git a/src/templates/modal.createarchive.html b/src/templates/modal.createarchive.html new file mode 100644 index 0000000..17ae5b6 --- /dev/null +++ b/src/templates/modal.createarchive.html @@ -0,0 +1,12 @@ + + + +
From 82f6651038b4be98bb196c0fa5dc13405640f182 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 8 Aug 2017 16:18:19 +0200 Subject: [PATCH 04/19] add create archive feature; closes #71 --- build/libifm.php | 257 ++++++++++++++++++++----- ifm.php | 257 ++++++++++++++++++++----- src/i18n/de.json | 7 +- src/ifm.js | 85 +++++++- src/ifmarchive.php | 100 ++++++---- src/main.php | 53 ++++- src/templates/modal.createarchive.html | 12 ++ 7 files changed, 612 insertions(+), 159 deletions(-) create mode 100644 src/templates/modal.createarchive.html diff --git a/build/libifm.php b/build/libifm.php index be070e3..19c1e01 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -13,7 +13,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -39,6 +39,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -85,6 +86,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -375,6 +377,21 @@ f00bar; +f00bar; + $templates['createarchive'] = <<<'f00bar' +
+ + +
+ f00bar; $templates['deletefile'] = <<<'f00bar'
@@ -597,6 +614,7 @@ f00bar; $i18n['de'] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -606,11 +624,11 @@ f00bar; "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", @@ -1275,7 +1293,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -1338,6 +1356,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -2044,6 +2078,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -2066,6 +2101,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- @@ -2734,6 +2835,7 @@ function IFM( params ) { $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -3263,7 +3365,7 @@ function IFM( params ) { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -3334,14 +3436,41 @@ function IFM( params ) { } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* @@ -3702,38 +3831,42 @@ function IFM( params ) { } -/* ======================================================================= +/** + * ======================================================================= * Improved File Manager * --------------------- * License: This project is provided under the terms of the MIT LICENSE * http://github.com/misterunknown/ifm/blob/master/LICENSE * ======================================================================= * - * zip class - * - * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 + * archive class + * + * This class provides support for various archive types for the IFM. It can + * create and extract the following formats: + * * zip + * * tar + * * tar.gz + * * tar.bz2 */ class IFMArchive { + /** - * Add a folder to the zip file + * Add a folder to an archive */ - private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + private static function addFolder( &$archive, $folder, $offset=0 ) { + if( $offset == 0 ) + $offset = strlen( dirname( $folder ) ) + 1; + $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -3742,22 +3875,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -3765,17 +3900,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -3783,15 +3939,10 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } /** * htpasswd parser diff --git a/ifm.php b/ifm.php index 8e05db6..c9d0e98 100644 --- a/ifm.php +++ b/ifm.php @@ -13,7 +13,7 @@ error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); class IFM { - const VERSION = '2.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -39,6 +39,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -85,6 +86,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -375,6 +377,21 @@ f00bar;
+f00bar; + $templates['createarchive'] = <<<'f00bar' +
+ + +
+ f00bar; $templates['deletefile'] = <<<'f00bar'
@@ -597,6 +614,7 @@ f00bar; $i18n['de'] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -606,11 +624,11 @@ f00bar; "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", @@ -1275,7 +1293,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -1338,6 +1356,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -2044,6 +2078,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -2066,6 +2101,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- @@ -2734,6 +2835,7 @@ function IFM( params ) { $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -3263,7 +3365,7 @@ function IFM( params ) { unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -3334,14 +3436,41 @@ function IFM( params ) { } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* @@ -3702,38 +3831,42 @@ function IFM( params ) { } -/* ======================================================================= +/** + * ======================================================================= * Improved File Manager * --------------------- * License: This project is provided under the terms of the MIT LICENSE * http://github.com/misterunknown/ifm/blob/master/LICENSE * ======================================================================= * - * zip class - * - * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 + * archive class + * + * This class provides support for various archive types for the IFM. It can + * create and extract the following formats: + * * zip + * * tar + * * tar.gz + * * tar.bz2 */ class IFMArchive { + /** - * Add a folder to the zip file + * Add a folder to an archive */ - private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + private static function addFolder( &$archive, $folder, $offset=0 ) { + if( $offset == 0 ) + $offset = strlen( dirname( $folder ) ) + 1; + $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -3742,22 +3875,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -3765,17 +3900,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -3783,15 +3939,10 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } /** * htpasswd parser diff --git a/src/i18n/de.json b/src/i18n/de.json index 265daec..26b6e4e 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -1,5 +1,6 @@ { "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", @@ -9,11 +10,11 @@ "editor_options": "Editor Optionen", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", "filename": "Dateiname", "filename_new": "Neuer Dateiname", "folder_new": "Neue Ordner", diff --git a/src/ifm.js b/src/ifm.js index 7636eed..1e5cc28 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -244,7 +244,7 @@ function IFM( params ) { }, actionsGroups:[ ['edit', 'extract', 'rename'], - ['copymove', 'download', 'delete'] + ['copymove', 'download', 'createarchive', 'delete'] ], actions: { edit: { @@ -307,6 +307,22 @@ function IFM( params ) { iconClass: "icon icon-download", isShown: function() { return !!self.config.download; } }, + createarchive: { + name: function( data ) { + if( data.selected.length > 0 ) + return 'create archive '+data.selected.length+''; + else + return 'create archive'; + }, + onClick: function( data ) { + if( data.selected.length > 0 ) + self.showCreateArchiveDialog( data.selected ); + else + self.showCreateArchiveDialog( data.clicked ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { return !!( self.config.createarchive && data.clicked.name != ".." ); } + }, 'delete': { name: function( data ) { if( data.selected.length > 0 ) @@ -1013,6 +1029,7 @@ function IFM( params ) { if( e.key == 'Enter' ) { e.preventDefault(); if( e.target.value.trim() === '' ) return; + document.getElementById( 'searchResults' ).tBodies[0].innerHTML = ''; self.search.lastSearch = e.target.value; $.ajax({ url: self.api, @@ -1035,6 +1052,72 @@ function IFM( params ) { }); }; + /** + * Shows the create archive dialog + */ + this.showCreateArchiveDialog = function( items ) { + self.showModal( Mustache.render( self.templates.createarchive, { i18n: self.i18n } ) ); + + var form = document.forms.formCreateArchive; + form.elements.archivename.addEventListener( 'keypress', function( e ) { + if( e.key == 'Enter' ) { + e.preventDefault(); + self.createArchive( items, e.target.value ); + self.hideModal(); + } + }); + form.addEventListener( 'click', function( e ) { + if( e.target.id == 'buttonSave' ) { + e.preventDefault(); + self.createArchive( items, form.elements.archivename.value ); + self.hideModal(); + } else if( e.target.id == 'buttonCancel' ) { + e.preventDefault(); + self.hideModal(); + } + }, false ); + }; + + this.createArchive = function( items, archivename ) { + var type = ""; + if( archivename.substr( -3 ).toLowerCase() == "zip" ) + type = "zip"; + else if( archivename.substr( -3 ).toLowerCase() == "tar" ) + type = "tar"; + else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + type = "tar.gz"; + else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + type = "tar.bz2"; + else { + self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + return; + } + var id = self.generateGuid(); + self.task_add( { id: id, name: "Create archive "+archivename } ); + + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "createArchive", + dir: self.currentDir, + archivename: archivename, + filenames: items.map( function( e ) { return e.name; } ), + format: type + }, + dataType: "json", + success: function( data ) { + if( data.status == "OK" ) { + self.showMessage( "Archive successfully created.", "s" ); + self.refreshFileTable(); + } else + self.showMessage( data.message, "e" ); + }, + error: function() { self.showMessage( "General error occured.", "e" ); }, + complete: function() { self.task_done( id ); } + }); + }; + // -------------------- // helper functions // -------------------- diff --git a/src/ifmarchive.php b/src/ifmarchive.php index 55ae23c..9ef1f08 100644 --- a/src/ifmarchive.php +++ b/src/ifmarchive.php @@ -1,37 +1,41 @@ addEmptyDir( $folder, substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } + $filePath = $folder . '/' . $f; + if( file_exists( $filePath ) && is_readable( $filePath ) ) + if( is_file( $filePath ) ) + $archive->addFile( $filePath, substr( $filePath, $offset ) ); + elseif( is_dir( $filePath ) ) + self::addFolder( $archive, $filePath, $offset ); } } closedir( $handle ); @@ -40,22 +44,24 @@ class IFMArchive { /** * Create a zip file */ - public static function createZip( $src, $out, $root=false ) + public static function createZip( $src, $out ) { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } + $a = new ZipArchive(); + $a->open( $out, ZIPARCHIVE::CREATE); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) + 1 ) ); + try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } + return $a->close(); } catch ( Exception $e ) { - throw $e; + return false; } } @@ -63,17 +69,38 @@ class IFMArchive { * Unzip a zip file */ public static function extractZip( $file, $destination="./" ) { + if( ! file_exists( $file ) ) + return false; $zip = new ZipArchive; $res = $zip->open( $file ); if( $res === true ) { $zip->extractTo( $destination ); $zip->close(); return true; - } else { + } else return false; - } } + /** + * Creates a tar archive + */ + public static function createTar( $src, $out ) { + $tar = new PharData( $out ); + + if( ! is_array( $src ) ) + $src = array( $src ); + + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + return true; + } + + /** + * Extracts a tar archive + */ public static function extractTar( $file, $destination="./" ) { if( ! file_exists( $file ) ) return false; @@ -81,13 +108,8 @@ class IFMArchive { try { $tar->extractTo( $destination, null, true ); return true; - } catch (Exception $e) { + } catch( Exception $e ) { return false; } } - - public static function createTar( $src, $out, $root=false ) { - $tar = new PharData( $out ); - $tar->buildFromDirectory( $src ); - } } diff --git a/src/main.php b/src/main.php index 2ce1dbc..ab74310 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.4.2'; + const VERSION = '3.0.0'; private $defaultconfig = array( // general config @@ -40,6 +40,7 @@ class IFM { "remoteupload" => 1, "rename" => 1, "zipnload" => 1, + "createarchive" => 1, // gui controls "showlastmodified" => 0, @@ -86,6 +87,7 @@ class IFM { $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; + $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; @@ -123,6 +125,9 @@ f00bar; f00bar; $templates['createdir'] = <<<'f00bar' @@@file:src/templates/modal.createdir.html@@@ +f00bar; + $templates['createarchive'] = <<<'f00bar' +@@@file:src/templates/modal.createarchive.html@@@ f00bar; $templates['deletefile'] = <<<'f00bar' @@@file:src/templates/modal.deletefile.html@@@ @@ -242,6 +247,7 @@ f00bar; $this->getConfig(); } elseif( $_REQUEST["api"] == "getFolders" ) { + sleep( 5 ); $this->getFolders( $_REQUEST ); } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); @@ -771,7 +777,7 @@ f00bar; unset( $zip ); $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename try { - IFMArchive::createZip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + IFMArchive::createZip( realpath( $d['filename'] ), $dfile ); if( $d['filename'] == "." ) { if( getcwd() == $this->getScriptRoot() ) $d['filename'] = "root"; @@ -842,14 +848,41 @@ f00bar; } private function createArchive( $d ) { -// if( $config['createarchive'] != 1 ) { -// $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); -// return false; -// } -// $this->chDirIfNecessary( $d['dir'] ); -// switch( $d['format'] ) { -// case "zip": -// + if( $this->config['createarchive'] != 1 ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to create archives" ) ); + return false; + } + if( ! $this->isFilenameValid( $d['archivename'] ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid archive filename given." ) ); + return false; + } + $this->chDirIfNecessary( $d['dir'] ); + $filenames = array(); + foreach( $d['filenames'] as $file ) + if( ! $this->isFilenameValid( $file ) ) { + $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid file name given" ) ); + exit( 1 ); + } else + array_push( $filenames, realpath( $file ) ); + switch( $d['format'] ) { + case "zip": + if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + case "tar": + case "tar.gz": + case "tar.bz2": + if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); + else + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); + break; + default: + $this->jsonResponse( array( "status" => "ERROR", "message" => "Unsupported archive format." ) ); + break; + } } /* diff --git a/src/templates/modal.createarchive.html b/src/templates/modal.createarchive.html new file mode 100644 index 0000000..17ae5b6 --- /dev/null +++ b/src/templates/modal.createarchive.html @@ -0,0 +1,12 @@ + + + +
From 382c402953b11c895b59ec7b2e5853e47ed20c59 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Tue, 8 Aug 2017 17:48:39 +0200 Subject: [PATCH 05/19] add compiler options for languages, closes #72 --- build/libifm.php | 70 ++++++------------------------------------------ compiler.php | 28 ++++++++++++++++--- ifm.php | 70 ++++++------------------------------------------ src/main.php | 18 ++++++------- 4 files changed, 49 insertions(+), 137 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 19c1e01..771d0f9 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -554,7 +554,7 @@ f00bar; $this->templates = $templates; $i18n = array(); - $i18n['en'] = <<<'f00bar' + $i18n["en"] = <<<'f00bar' { "ajax_request": "AJAX Request", "cancel": "Cancel", @@ -610,67 +610,8 @@ f00bar; "word_wrap": "Word Wrap" } f00bar; - $i18n['en'] = json_decode($i18n['en'], true); - $i18n['de'] = <<<'f00bar' -{ - "ajax_request": "AJAX Request", - "archivename": "Name des Archivs", - "cancel": "Abbrechen", - "close": "Schließen", - "copy": "Kopieren", - "data": "Daten", - "delete": "Löschen", - "directoryname": "Ordner Name", - "editor_options": "Editor Optionen", - "extract": "Auspacken", - "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", - "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", - "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", - "filename": "Dateiname", - "filename_new": "Neuer Dateiname", - "folder_new": "Neue Ordner", - "footer": "IFM - verbesserter file manager | ifm.php versteckt |", - "github": "Besuche das Projekt auf GitHub", - "group": "Gruppe", - "last_modified": "Zuletzt geändert", - "login": "Anmeldung", - "logout": "Abmelden", - "method": "Methode", - "move": "Verschieben", - "options": "Optionen", - "owner": "Besitzer", - "password": "Passwort", - "path_content": "Inhalt von", - "permissions": "Berechtigungen", - "refresh": "Auffrischen", - "rename": "Umbenennen", - "rename_filename": "Folgende Datei umbenennen -", - "request": "Anfrage", - "response": "Antwort", - "save": "Speichen", - "save_wo_close": "Speichen ohne Schließen", - "search": "Suchen", - "search_pattern": "Muster", - "select_destination": "Zielort auswählen", - "size": "Größe", - "soft_tabs": "Leichte Tabulatoren", - "tab_size": "Tabulatoren Größe", - "tasks": "Aufgaben", - "toggle_nav": "Navigation umschalten", - "upload": "Hochladen", - "upload_drop": "Dateien zum hochladen hier hinziehen", - "upload_file": "Datei hochladen", - "upload_remote": "Hochladen von ausserhalb", - "upload_remote_url": "Entfernte URL zum hochladen", - "username": "Benutzername", - "word_wrap": "Zeilenumbruch" -} +$i18n["en"] = json_decode( $i18n["en"], true ); -f00bar; - $i18n['de'] = json_decode($i18n['de'], true); $this->i18n = $i18n; } @@ -2840,7 +2781,12 @@ function IFM( params ) { } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - $this->jsonResponse( $this->i18n[$this->config['language']] ); + if( isset( $this->i18n[$this->config['language']] ) ) + $this->jsonResponse( $this->i18n[$this->config['language']] ); + else { + foreach( $this->i18n as $lang ) break; + $this->jsonResponse( $lang ); + } } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); diff --git a/compiler.php b/compiler.php index d483e19..2cade4c 100755 --- a/compiler.php +++ b/compiler.php @@ -18,6 +18,21 @@ $IFM_BUILD_STANDALONE = "ifm.php"; $IFM_BUILD_STANDALONE_COMPRESSED = "build/ifm.min.php"; $IFM_BUILD_LIB_PHP = "build/libifm.php"; +$options = getopt( null, array( "language::" ) ); +$vars['languages'] = isset( $options['language'] ) ? explode( ',', $options['language'] ) : array( "en" ); +$vars['defaultlanguage'] = $vars['languages'][0]; +$vars['languageincludes'] = ""; +foreach( $vars['languages'] as $l ) { + if( file_exists( "src/i18n/".$l.".json" ) ) + $vars['languageincludes'] .= + '$i18n["'.$l.'"] = <<<\'f00bar\'' . "\n" + . file_get_contents( "src/i18n/".$l.".json" ) . "\n" + . 'f00bar;' . "\n" + . '$i18n["'.$l.'"] = json_decode( $i18n["'.$l.'"], true );' . "\n" ; + else + print "WARNING: Language file src/i18n/".$l.".json not found.\n"; +} + /** * Concat PHP Files */ @@ -30,13 +45,20 @@ foreach( $IFM_SRC_PHP as $phpfile ) { $compiled = join( $compiled ); /** - * Process includes + * Process file includes */ $includes = NULL; preg_match_all( "/\@\@\@file:([^\@]+)\@\@\@/", $compiled, $includes, PREG_SET_ORDER ); -foreach( $includes as $file ) { +foreach( $includes as $file ) $compiled = str_replace( $file[0], file_get_contents( $file[1] ), $compiled ); -} + +/** + * Process variable includes + */ +$includes = NULL; +preg_match_all( "/\@\@\@vars:([^\@]+)\@\@\@/", $compiled, $includes, PREG_SET_ORDER ); +foreach( $includes as $var ) + $compiled = str_replace( $var[0], $vars[$var[1]], $compiled ); /** * Build standalone script diff --git a/ifm.php b/ifm.php index c9d0e98..5843bbd 100644 --- a/ifm.php +++ b/ifm.php @@ -554,7 +554,7 @@ f00bar; $this->templates = $templates; $i18n = array(); - $i18n['en'] = <<<'f00bar' + $i18n["en"] = <<<'f00bar' { "ajax_request": "AJAX Request", "cancel": "Cancel", @@ -610,67 +610,8 @@ f00bar; "word_wrap": "Word Wrap" } f00bar; - $i18n['en'] = json_decode($i18n['en'], true); - $i18n['de'] = <<<'f00bar' -{ - "ajax_request": "AJAX Request", - "archivename": "Name des Archivs", - "cancel": "Abbrechen", - "close": "Schließen", - "copy": "Kopieren", - "data": "Daten", - "delete": "Löschen", - "directoryname": "Ordner Name", - "editor_options": "Editor Optionen", - "extract": "Auspacken", - "extract_filename": "Folgende Datei auspacken -", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", - "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", - "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", - "filename": "Dateiname", - "filename_new": "Neuer Dateiname", - "folder_new": "Neue Ordner", - "footer": "IFM - verbesserter file manager | ifm.php versteckt |", - "github": "Besuche das Projekt auf GitHub", - "group": "Gruppe", - "last_modified": "Zuletzt geändert", - "login": "Anmeldung", - "logout": "Abmelden", - "method": "Methode", - "move": "Verschieben", - "options": "Optionen", - "owner": "Besitzer", - "password": "Passwort", - "path_content": "Inhalt von", - "permissions": "Berechtigungen", - "refresh": "Auffrischen", - "rename": "Umbenennen", - "rename_filename": "Folgende Datei umbenennen -", - "request": "Anfrage", - "response": "Antwort", - "save": "Speichen", - "save_wo_close": "Speichen ohne Schließen", - "search": "Suchen", - "search_pattern": "Muster", - "select_destination": "Zielort auswählen", - "size": "Größe", - "soft_tabs": "Leichte Tabulatoren", - "tab_size": "Tabulatoren Größe", - "tasks": "Aufgaben", - "toggle_nav": "Navigation umschalten", - "upload": "Hochladen", - "upload_drop": "Dateien zum hochladen hier hinziehen", - "upload_file": "Datei hochladen", - "upload_remote": "Hochladen von ausserhalb", - "upload_remote_url": "Entfernte URL zum hochladen", - "username": "Benutzername", - "word_wrap": "Zeilenumbruch" -} +$i18n["en"] = json_decode( $i18n["en"], true ); -f00bar; - $i18n['de'] = json_decode($i18n['de'], true); $this->i18n = $i18n; } @@ -2840,7 +2781,12 @@ function IFM( params ) { } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - $this->jsonResponse( $this->i18n[$this->config['language']] ); + if( isset( $this->i18n[$this->config['language']] ) ) + $this->jsonResponse( $this->i18n[$this->config['language']] ); + else { + foreach( $this->i18n as $lang ) break; + $this->jsonResponse( $lang ); + } } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); diff --git a/src/main.php b/src/main.php index ab74310..8453ff8 100644 --- a/src/main.php +++ b/src/main.php @@ -24,7 +24,7 @@ class IFM { "tmp_dir" => "", "defaulttimezone" => "Europe/Berlin", "forbiddenChars" => array(), - "language" => "en", + "language" => "@@@vars:defaultlanguage@@@", // api controls "ajaxrequest" => 1, @@ -159,14 +159,7 @@ f00bar; $this->templates = $templates; $i18n = array(); - $i18n['en'] = <<<'f00bar' -@@@file:src/i18n/en.json@@@ -f00bar; - $i18n['en'] = json_decode($i18n['en'], true); - $i18n['de'] = <<<'f00bar' -@@@file:src/i18n/de.json@@@ -f00bar; - $i18n['de'] = json_decode($i18n['de'], true); + @@@vars:languageincludes@@@ $this->i18n = $i18n; } @@ -252,7 +245,12 @@ f00bar; } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - $this->jsonResponse( $this->i18n[$this->config['language']] ); + if( isset( $this->i18n[$this->config['language']] ) ) + $this->jsonResponse( $this->i18n[$this->config['language']] ); + else { + foreach( $this->i18n as $lang ) break; + $this->jsonResponse( $lang ); + } } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); From 9b74386ad8680f4618a1272467bc74e888187ea0 Mon Sep 17 00:00:00 2001 From: Jannis Rondorf Date: Tue, 8 Aug 2017 21:35:47 +0200 Subject: [PATCH 06/19] ifm.js translation --- build/libifm.php | 120 +++++++++++++++++++--------- ifm.php | 120 +++++++++++++++++++--------- src/i18n/de.json | 24 ++++++ src/i18n/en.json | 24 ++++++ src/ifm.js | 70 ++++++++-------- src/templates/modal.renamefile.html | 2 +- 6 files changed, 252 insertions(+), 108 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 4cb492f..b6bfd92 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -479,7 +479,7 @@ f00bar; @@ -547,20 +547,42 @@ f00bar; "delete": "Delete", "directoryname": "Directory Name", "editor_options": "Editor Options", + "error": "Error:", "extract": "Extract", "extract_filename": "Extract file - ", + "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", + "file_delete_error": "File(s) could not be deleted", + "file_delete_success": "File(s) successfully deleted", + "file_display_error": "This file can not be displayed or edited", "file_edit_success": "File successfully edited / created.", + "file_extract_error": "File could not be extracted: ", + "file_extract_success": "File successfully extracted", + "file_load_error": "The content of this file cannot be fetched", "file_multi_delete_confirm": "Do you really want to delete these files -", "file_new": "New File", + "file_rename": "Rename File", + "file_rename_error": "File could not be renamed: ", + "file_rename_success": "File successfully renamed", "file_save_confirm": "Do you want to save the following file -", + "file_save_error": "File could not be edited or created: ", + "file_upload_error": "File could not be uploaded: ", + "file_upload_success": "File successfully uploaded", "filename": "Filename", "filename_new": "New Filename", + "folder_create_error": "Directory could not be created: ", + "folder_create_success": "Directory sucessfully created", "folder_new": "New Folder", + "folder_tree_load_error": "Error while fetching the folder tree", "footer": "IFM - improved file manager | ifm.php hidden |", + "general_error": "General error occured: No or broken response", "github": "Visit the project on GitHub", "group": "Group", + "invalid_data": "Invalid data from server", "last_modified": "Last Modified", + "load_config_error": "Could not load configuration", + "load_template_error": "Could not load templates", + "load_text_error": "Could not load texts", "login": "Login", "logout": "Log Off", "method": "Method", @@ -569,6 +591,8 @@ f00bar; "owner": "Owner", "password": "Password", "path_content": "Content of", + "permission_change_error": "Permissions could not be changed: ", + "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", "refresh": "Refresh", "rename": "Rename", @@ -604,20 +628,42 @@ f00bar; "delete": "Löschen", "directoryname": "Ordner Name", "editor_options": "Editor Optionen", + "error": "Fehler:", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", + "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_error": "Datei(en) konnten nicht gelöscht werden", + "file_delete_success": "Datei(en) erfolgreich gelöscht", + "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", "file_edit_success": "Datei erfolgreich geändert / angelegt.", + "file_extract_error": "Datei konnte nicht entpackt werden: ", + "file_extract_success": "Datei erfolgreich entpackt", + "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", "file_new": "Neue Datei", + "file_rename": "Datei umbenennen", + "file_rename_error": "Datei konnte nicht umbenannt werden: ", + "file_rename_success": "Datei erfogreich umbenannt", "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", + "file_upload_error": "Datei konnte nicht hochgeladen werden: ", + "file_upload_success": "Datei erfolgreich hochgeladen", "filename": "Dateiname", "filename_new": "Neuer Dateiname", + "folder_create_error": "Verzeichnis konnte nicht angelegt werden: ", + "folder_create_success": "Verzeichnis erfolgreich angelegt", "folder_new": "Neue Ordner", + "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums", "footer": "IFM - verbesserter file manager | ifm.php versteckt |", + "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", + "invalid_data": "Fehlerhafte Daten vom Server erhalten", "last_modified": "Zuletzt geändert", + "load_config_error": "Konfiguration konnte nicht geladen werden", + "load_template_error": "Vorlagen konnten nicht geladen werden", + "load_text_error": "Texte konnten nicht geladen werden", "login": "Anmeldung", "logout": "Abmelden", "method": "Methode", @@ -626,6 +672,8 @@ f00bar; "owner": "Besitzer", "password": "Passwort", "path_content": "Inhalt von", + "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", + "permission_change_success": "Berechtigungen erfolgreich geändert", "permissions": "Berechtigungen", "refresh": "Auffrischen", "rename": "Umbenennen", @@ -1108,7 +1156,7 @@ function IFM( params ) { }, dataType: "json", success: self.rebuildFileTable, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( taskid ); } }); }; @@ -1123,7 +1171,7 @@ function IFM( params ) { this.showMessage( data.message, "e" ); return; } else if ( ! Array.isArray( data ) ) { - this.showMessage( "Invalid data from server", "e" ); + this.showMessage( self.i18n.invalid_data, "e" ); return; } data.forEach( function( item ) { @@ -1383,7 +1431,7 @@ function IFM( params ) { $( "#currentDir" ).val( self.currentDir ); if( config.pushState ) history.pushState( { dir: self.currentDir }, self.currentDir, "#"+encodeURIComponent( self.currentDir ) ); }, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1478,9 +1526,9 @@ function IFM( params ) { if( data.status == "OK" ) { self.showMessage( self.i18n.file_edit_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be edited/created:" + data.message, "e" ); + } else self.showMessage( self.i18n.file_save_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); self.fileChanged = false; }; @@ -1505,11 +1553,11 @@ function IFM( params ) { self.showFileDialog( data.data.filename, data.data.content ); } else if( data.status == "OK" && data.data.content == null ) { - self.showMessage( "The content of this file cannot be fetched.", "e" ); + self.showMessage( self.i18n.file_load_error, "e" ); } - else self.showMessage( "Error: "+data.message, "e" ); + else self.showMessage( self.i18n.error +data.message, "e" ); }, - error: function() { self.showMessage( "This file can not be displayed or edited.", "e" ); } + error: function() { self.showMessage( self.i18n.file_display_error, "e" ); } }); }; @@ -1553,14 +1601,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Directory sucessfully created.", "s" ); + self.showMessage( self.i18n.folder_create_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Directory could not be created: "+data.message, "e" ); + self.showMessage( self.i18n.folder_create_error +data.message, "e" ); } }, - error: function() { self.showMessage( "General error occured.", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1606,11 +1654,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File(s) successfully deleted", "s" ); + self.showMessage( self.i18n.file_delete_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File(s) could not be deleted", "e" ); + } else self.showMessage( self.i18n.file_delete_error, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1659,11 +1707,11 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - ifm.showMessage("File successfully renamed", "s"); + ifm.showMessage( self.i18n.file_rename_success, "s"); ifm.refreshFileTable(); - } else ifm.showMessage("File could not be renamed: "+data.message, "e"); + } else ifm.showMessage( self.i18n.file_rename_error +data.message, "e"); }, - error: function() { ifm.showMessage("General error occured", "e"); } + error: function() { ifm.showMessage( self.i18n.general_error, "e"); } }); }; @@ -1703,7 +1751,7 @@ function IFM( params ) { } }); }, - error: function() { self.hideModal(); self.showMessage( "Error while fetching the folder tree.", "e" ) } + error: function() { self.hideModal(); self.showMessage( self.i18n.folder_tree_load_error, "e" ) } }); var form = document.forms.formCopyMove; form.addEventListener( 'click', function( e ) { @@ -1734,7 +1782,7 @@ function IFM( params ) { sources = [sources]; sources.forEach( function( source ) { var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " " + self.i18n.file_copy_to + " " + destination } ); $.ajax({ url: self.api, type: "POST", @@ -1755,7 +1803,7 @@ function IFM( params ) { self.refreshFileTable(); }, error: function() { - self.showMessage( "General error occured.", "e" ); + self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); @@ -1818,11 +1866,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File successfully extracted", "s" ); + self.showMessage( self.i18n.file_extract_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be extracted. Error: " + data.message, "e" ); + } else self.showMessage( self.i18n.file_extract_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -1883,11 +1931,11 @@ function IFM( params ) { }, success: function(data) { if(data.status == "OK") { - self.showMessage("File successfully uploaded", "s"); + self.showMessage( self.i18n.file_upload_success, "s"); if(data.cd == self.currentDir) self.refreshFileTable(); - } else self.showMessage("File could not be uploaded: "+data.message, "e"); + } else self.showMessage( self.i18n.file_upload_error +data.message, "e"); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Upload " + file.name } ); @@ -1912,14 +1960,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Permissions successfully changed.", "s" ); + self.showMessage( self.i18n.permission_change_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Permissions could not be changed: "+data.message, "e"); + self.showMessage( self.i18n.permission_change_error +data.message, "e"); } }, - error: function() { self.showMessage("General error occured.", "e"); } + error: function() { self.showMessage( self.i18n.general_error, "e"); } }); }; @@ -1970,12 +2018,12 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - self.showMessage( "File successfully uploaded", "s" ); + self.showMessage( self.i18n.file_upload_success, "s" ); self.refreshFileTable(); } else - self.showMessage( "File could not be uploaded:
" + data.message, "e" ); + self.showMessage( self.i18n.file_upload_error + data.message, "e" ); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Remote upload: "+filename } ); @@ -2508,7 +2556,7 @@ function IFM( params ) { self.initLoadTemplates(); }, error: function() { - throw new Error( "IFM: could not load configuration" ); + throw new Error( self.i18n.load_config_error ); } }); }; @@ -2528,7 +2576,7 @@ function IFM( params ) { self.initLoadI18N(); }, error: function() { - throw new Error( "IFM: could not load templates" ); + throw new Error( self.i18n.load_template_error ); } }); }; @@ -2548,7 +2596,7 @@ function IFM( params ) { self.initApplication(); }, error: function() { - throw new Error( "IFM: could not load I18N" ); + throw new Error( self.i18n.load_text_error ); } }); }; diff --git a/ifm.php b/ifm.php index 09a841d..d4a8ed3 100644 --- a/ifm.php +++ b/ifm.php @@ -479,7 +479,7 @@ f00bar; @@ -547,20 +547,42 @@ f00bar; "delete": "Delete", "directoryname": "Directory Name", "editor_options": "Editor Options", + "error": "Error:", "extract": "Extract", "extract_filename": "Extract file - ", + "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", + "file_delete_error": "File(s) could not be deleted", + "file_delete_success": "File(s) successfully deleted", + "file_display_error": "This file can not be displayed or edited", "file_edit_success": "File successfully edited / created.", + "file_extract_error": "File could not be extracted: ", + "file_extract_success": "File successfully extracted", + "file_load_error": "The content of this file cannot be fetched", "file_multi_delete_confirm": "Do you really want to delete these files -", "file_new": "New File", + "file_rename": "Rename File", + "file_rename_error": "File could not be renamed: ", + "file_rename_success": "File successfully renamed", "file_save_confirm": "Do you want to save the following file -", + "file_save_error": "File could not be edited or created: ", + "file_upload_error": "File could not be uploaded: ", + "file_upload_success": "File successfully uploaded", "filename": "Filename", "filename_new": "New Filename", + "folder_create_error": "Directory could not be created: ", + "folder_create_success": "Directory sucessfully created", "folder_new": "New Folder", + "folder_tree_load_error": "Error while fetching the folder tree", "footer": "IFM - improved file manager | ifm.php hidden |", + "general_error": "General error occured: No or broken response", "github": "Visit the project on GitHub", "group": "Group", + "invalid_data": "Invalid data from server", "last_modified": "Last Modified", + "load_config_error": "Could not load configuration", + "load_template_error": "Could not load templates", + "load_text_error": "Could not load texts", "login": "Login", "logout": "Log Off", "method": "Method", @@ -569,6 +591,8 @@ f00bar; "owner": "Owner", "password": "Password", "path_content": "Content of", + "permission_change_error": "Permissions could not be changed: ", + "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", "refresh": "Refresh", "rename": "Rename", @@ -604,20 +628,42 @@ f00bar; "delete": "Löschen", "directoryname": "Ordner Name", "editor_options": "Editor Optionen", + "error": "Fehler:", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", + "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_error": "Datei(en) konnten nicht gelöscht werden", + "file_delete_success": "Datei(en) erfolgreich gelöscht", + "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", "file_edit_success": "Datei erfolgreich geändert / angelegt.", + "file_extract_error": "Datei konnte nicht entpackt werden: ", + "file_extract_success": "Datei erfolgreich entpackt", + "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", "file_new": "Neue Datei", + "file_rename": "Datei umbenennen", + "file_rename_error": "Datei konnte nicht umbenannt werden: ", + "file_rename_success": "Datei erfogreich umbenannt", "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", + "file_upload_error": "Datei konnte nicht hochgeladen werden: ", + "file_upload_success": "Datei erfolgreich hochgeladen", "filename": "Dateiname", "filename_new": "Neuer Dateiname", + "folder_create_error": "Verzeichnis konnte nicht angelegt werden: ", + "folder_create_success": "Verzeichnis erfolgreich angelegt", "folder_new": "Neue Ordner", + "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums", "footer": "IFM - verbesserter file manager | ifm.php versteckt |", + "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", + "invalid_data": "Fehlerhafte Daten vom Server erhalten", "last_modified": "Zuletzt geändert", + "load_config_error": "Konfiguration konnte nicht geladen werden", + "load_template_error": "Vorlagen konnten nicht geladen werden", + "load_text_error": "Texte konnten nicht geladen werden", "login": "Anmeldung", "logout": "Abmelden", "method": "Methode", @@ -626,6 +672,8 @@ f00bar; "owner": "Besitzer", "password": "Passwort", "path_content": "Inhalt von", + "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", + "permission_change_success": "Berechtigungen erfolgreich geändert", "permissions": "Berechtigungen", "refresh": "Auffrischen", "rename": "Umbenennen", @@ -1108,7 +1156,7 @@ function IFM( params ) { }, dataType: "json", success: self.rebuildFileTable, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( taskid ); } }); }; @@ -1123,7 +1171,7 @@ function IFM( params ) { this.showMessage( data.message, "e" ); return; } else if ( ! Array.isArray( data ) ) { - this.showMessage( "Invalid data from server", "e" ); + this.showMessage( self.i18n.invalid_data, "e" ); return; } data.forEach( function( item ) { @@ -1383,7 +1431,7 @@ function IFM( params ) { $( "#currentDir" ).val( self.currentDir ); if( config.pushState ) history.pushState( { dir: self.currentDir }, self.currentDir, "#"+encodeURIComponent( self.currentDir ) ); }, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1478,9 +1526,9 @@ function IFM( params ) { if( data.status == "OK" ) { self.showMessage( self.i18n.file_edit_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be edited/created:" + data.message, "e" ); + } else self.showMessage( self.i18n.file_save_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); self.fileChanged = false; }; @@ -1505,11 +1553,11 @@ function IFM( params ) { self.showFileDialog( data.data.filename, data.data.content ); } else if( data.status == "OK" && data.data.content == null ) { - self.showMessage( "The content of this file cannot be fetched.", "e" ); + self.showMessage( self.i18n.file_load_error, "e" ); } - else self.showMessage( "Error: "+data.message, "e" ); + else self.showMessage( self.i18n.error +data.message, "e" ); }, - error: function() { self.showMessage( "This file can not be displayed or edited.", "e" ); } + error: function() { self.showMessage( self.i18n.file_display_error, "e" ); } }); }; @@ -1553,14 +1601,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Directory sucessfully created.", "s" ); + self.showMessage( self.i18n.folder_create_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Directory could not be created: "+data.message, "e" ); + self.showMessage( self.i18n.folder_create_error +data.message, "e" ); } }, - error: function() { self.showMessage( "General error occured.", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1606,11 +1654,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File(s) successfully deleted", "s" ); + self.showMessage( self.i18n.file_delete_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File(s) could not be deleted", "e" ); + } else self.showMessage( self.i18n.file_delete_error, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -1659,11 +1707,11 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - ifm.showMessage("File successfully renamed", "s"); + ifm.showMessage( self.i18n.file_rename_success, "s"); ifm.refreshFileTable(); - } else ifm.showMessage("File could not be renamed: "+data.message, "e"); + } else ifm.showMessage( self.i18n.file_rename_error +data.message, "e"); }, - error: function() { ifm.showMessage("General error occured", "e"); } + error: function() { ifm.showMessage( self.i18n.general_error, "e"); } }); }; @@ -1703,7 +1751,7 @@ function IFM( params ) { } }); }, - error: function() { self.hideModal(); self.showMessage( "Error while fetching the folder tree.", "e" ) } + error: function() { self.hideModal(); self.showMessage( self.i18n.folder_tree_load_error, "e" ) } }); var form = document.forms.formCopyMove; form.addEventListener( 'click', function( e ) { @@ -1734,7 +1782,7 @@ function IFM( params ) { sources = [sources]; sources.forEach( function( source ) { var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " " + self.i18n.file_copy_to + " " + destination } ); $.ajax({ url: self.api, type: "POST", @@ -1755,7 +1803,7 @@ function IFM( params ) { self.refreshFileTable(); }, error: function() { - self.showMessage( "General error occured.", "e" ); + self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); @@ -1818,11 +1866,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File successfully extracted", "s" ); + self.showMessage( self.i18n.file_extract_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be extracted. Error: " + data.message, "e" ); + } else self.showMessage( self.i18n.file_extract_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -1883,11 +1931,11 @@ function IFM( params ) { }, success: function(data) { if(data.status == "OK") { - self.showMessage("File successfully uploaded", "s"); + self.showMessage( self.i18n.file_upload_success, "s"); if(data.cd == self.currentDir) self.refreshFileTable(); - } else self.showMessage("File could not be uploaded: "+data.message, "e"); + } else self.showMessage( self.i18n.file_upload_error +data.message, "e"); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Upload " + file.name } ); @@ -1912,14 +1960,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Permissions successfully changed.", "s" ); + self.showMessage( self.i18n.permission_change_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Permissions could not be changed: "+data.message, "e"); + self.showMessage( self.i18n.permission_change_error +data.message, "e"); } }, - error: function() { self.showMessage("General error occured.", "e"); } + error: function() { self.showMessage( self.i18n.general_error, "e"); } }); }; @@ -1970,12 +2018,12 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - self.showMessage( "File successfully uploaded", "s" ); + self.showMessage( self.i18n.file_upload_success, "s" ); self.refreshFileTable(); } else - self.showMessage( "File could not be uploaded:
" + data.message, "e" ); + self.showMessage( self.i18n.file_upload_error + data.message, "e" ); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Remote upload: "+filename } ); @@ -2508,7 +2556,7 @@ function IFM( params ) { self.initLoadTemplates(); }, error: function() { - throw new Error( "IFM: could not load configuration" ); + throw new Error( self.i18n.load_config_error ); } }); }; @@ -2528,7 +2576,7 @@ function IFM( params ) { self.initLoadI18N(); }, error: function() { - throw new Error( "IFM: could not load templates" ); + throw new Error( self.i18n.load_template_error ); } }); }; @@ -2548,7 +2596,7 @@ function IFM( params ) { self.initApplication(); }, error: function() { - throw new Error( "IFM: could not load I18N" ); + throw new Error( self.i18n.load_text_error ); } }); }; diff --git a/src/i18n/de.json b/src/i18n/de.json index 265daec..c55284f 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -7,20 +7,42 @@ "delete": "Löschen", "directoryname": "Ordner Name", "editor_options": "Editor Optionen", + "error": "Fehler:", "extract": "Auspacken", "extract_filename": "Folgende Datei auspacken -", + "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden -", + "file_delete_error": "Datei(en) konnten nicht gelöscht werden", + "file_delete_success": "Datei(en) erfolgreich gelöscht", + "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", "file_edit_success": "Datei erfolgreich geändert / angelegt.", + "file_extract_error": "Datei konnte nicht entpackt werden: ", + "file_extract_success": "Datei erfolgreich entpackt", + "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", "file_new": "Neue Datei", + "file_rename": "Datei umbenennen", + "file_rename_error": "Datei konnte nicht umbenannt werden: ", + "file_rename_success": "Datei erfogreich umbenannt", "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", + "file_upload_error": "Datei konnte nicht hochgeladen werden: ", + "file_upload_success": "Datei erfolgreich hochgeladen", "filename": "Dateiname", "filename_new": "Neuer Dateiname", + "folder_create_error": "Verzeichnis konnte nicht angelegt werden: ", + "folder_create_success": "Verzeichnis erfolgreich angelegt", "folder_new": "Neue Ordner", + "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums", "footer": "IFM - verbesserter file manager | ifm.php versteckt |", + "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", + "invalid_data": "Fehlerhafte Daten vom Server erhalten", "last_modified": "Zuletzt geändert", + "load_config_error": "Konfiguration konnte nicht geladen werden", + "load_template_error": "Vorlagen konnten nicht geladen werden", + "load_text_error": "Texte konnten nicht geladen werden", "login": "Anmeldung", "logout": "Abmelden", "method": "Methode", @@ -29,6 +51,8 @@ "owner": "Besitzer", "password": "Passwort", "path_content": "Inhalt von", + "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", + "permission_change_success": "Berechtigungen erfolgreich geändert", "permissions": "Berechtigungen", "refresh": "Auffrischen", "rename": "Umbenennen", diff --git a/src/i18n/en.json b/src/i18n/en.json index c564d46..1300946 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -7,20 +7,42 @@ "delete": "Delete", "directoryname": "Directory Name", "editor_options": "Editor Options", + "error": "Error:", "extract": "Extract", "extract_filename": "Extract file - ", + "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", + "file_delete_error": "File(s) could not be deleted", + "file_delete_success": "File(s) successfully deleted", + "file_display_error": "This file can not be displayed or edited", "file_edit_success": "File successfully edited / created.", + "file_extract_error": "File could not be extracted: ", + "file_extract_success": "File successfully extracted", + "file_load_error": "The content of this file cannot be fetched", "file_multi_delete_confirm": "Do you really want to delete these files -", "file_new": "New File", + "file_rename": "Rename File", + "file_rename_error": "File could not be renamed: ", + "file_rename_success": "File successfully renamed", "file_save_confirm": "Do you want to save the following file -", + "file_save_error": "File could not be edited or created: ", + "file_upload_error": "File could not be uploaded: ", + "file_upload_success": "File successfully uploaded", "filename": "Filename", "filename_new": "New Filename", + "folder_create_error": "Directory could not be created: ", + "folder_create_success": "Directory sucessfully created", "folder_new": "New Folder", + "folder_tree_load_error": "Error while fetching the folder tree", "footer": "IFM - improved file manager | ifm.php hidden |", + "general_error": "General error occured: No or broken response", "github": "Visit the project on GitHub", "group": "Group", + "invalid_data": "Invalid data from server", "last_modified": "Last Modified", + "load_config_error": "Could not load configuration", + "load_template_error": "Could not load templates", + "load_text_error": "Could not load texts", "login": "Login", "logout": "Log Off", "method": "Method", @@ -29,6 +51,8 @@ "owner": "Owner", "password": "Password", "path_content": "Content of", + "permission_change_error": "Permissions could not be changed: ", + "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", "refresh": "Refresh", "rename": "Rename", diff --git a/src/ifm.js b/src/ifm.js index 5e51fa6..d24b5fe 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -77,7 +77,7 @@ function IFM( params ) { }, dataType: "json", success: self.rebuildFileTable, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( taskid ); } }); }; @@ -92,7 +92,7 @@ function IFM( params ) { this.showMessage( data.message, "e" ); return; } else if ( ! Array.isArray( data ) ) { - this.showMessage( "Invalid data from server", "e" ); + this.showMessage( self.i18n.invalid_data, "e" ); return; } data.forEach( function( item ) { @@ -352,7 +352,7 @@ function IFM( params ) { $( "#currentDir" ).val( self.currentDir ); if( config.pushState ) history.pushState( { dir: self.currentDir }, self.currentDir, "#"+encodeURIComponent( self.currentDir ) ); }, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -447,9 +447,9 @@ function IFM( params ) { if( data.status == "OK" ) { self.showMessage( self.i18n.file_edit_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be edited/created:" + data.message, "e" ); + } else self.showMessage( self.i18n.file_save_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); self.fileChanged = false; }; @@ -474,11 +474,11 @@ function IFM( params ) { self.showFileDialog( data.data.filename, data.data.content ); } else if( data.status == "OK" && data.data.content == null ) { - self.showMessage( "The content of this file cannot be fetched.", "e" ); + self.showMessage( self.i18n.file_load_error, "e" ); } - else self.showMessage( "Error: "+data.message, "e" ); + else self.showMessage( self.i18n.error +data.message, "e" ); }, - error: function() { self.showMessage( "This file can not be displayed or edited.", "e" ); } + error: function() { self.showMessage( self.i18n.file_display_error, "e" ); } }); }; @@ -522,14 +522,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Directory sucessfully created.", "s" ); + self.showMessage( self.i18n.folder_create_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Directory could not be created: "+data.message, "e" ); + self.showMessage( self.i18n.folder_create_error +data.message, "e" ); } }, - error: function() { self.showMessage( "General error occured.", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -575,11 +575,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File(s) successfully deleted", "s" ); + self.showMessage( self.i18n.file_delete_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File(s) could not be deleted", "e" ); + } else self.showMessage( self.i18n.file_delete_error, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); } + error: function() { self.showMessage( self.i18n.general_error, "e" ); } }); }; @@ -628,11 +628,11 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - ifm.showMessage("File successfully renamed", "s"); + ifm.showMessage( self.i18n.file_rename_success, "s"); ifm.refreshFileTable(); - } else ifm.showMessage("File could not be renamed: "+data.message, "e"); + } else ifm.showMessage( self.i18n.file_rename_error +data.message, "e"); }, - error: function() { ifm.showMessage("General error occured", "e"); } + error: function() { ifm.showMessage( self.i18n.general_error, "e"); } }); }; @@ -672,7 +672,7 @@ function IFM( params ) { } }); }, - error: function() { self.hideModal(); self.showMessage( "Error while fetching the folder tree.", "e" ) } + error: function() { self.hideModal(); self.showMessage( self.i18n.folder_tree_load_error, "e" ) } }); var form = document.forms.formCopyMove; form.addEventListener( 'click', function( e ) { @@ -703,7 +703,7 @@ function IFM( params ) { sources = [sources]; sources.forEach( function( source ) { var id = self.generateGuid(); - self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " to " + destination } ); + self.task_add( { id: id, name: action.charAt(0).toUpperCase() + action.slice(1) + " " + source.name + " " + self.i18n.file_copy_to + " " + destination } ); $.ajax({ url: self.api, type: "POST", @@ -724,7 +724,7 @@ function IFM( params ) { self.refreshFileTable(); }, error: function() { - self.showMessage( "General error occured.", "e" ); + self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); @@ -787,11 +787,11 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "File successfully extracted", "s" ); + self.showMessage( self.i18n.file_extract_success, "s" ); self.refreshFileTable(); - } else self.showMessage( "File could not be extracted. Error: " + data.message, "e" ); + } else self.showMessage( self.i18n.file_extract_error + data.message, "e" ); }, - error: function() { self.showMessage( "General error occured", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -852,11 +852,11 @@ function IFM( params ) { }, success: function(data) { if(data.status == "OK") { - self.showMessage("File successfully uploaded", "s"); + self.showMessage( self.i18n.file_upload_success, "s"); if(data.cd == self.currentDir) self.refreshFileTable(); - } else self.showMessage("File could not be uploaded: "+data.message, "e"); + } else self.showMessage( self.i18n.file_upload_error +data.message, "e"); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Upload " + file.name } ); @@ -881,14 +881,14 @@ function IFM( params ) { dataType: "json", success: function( data ){ if( data.status == "OK" ) { - self.showMessage( "Permissions successfully changed.", "s" ); + self.showMessage( self.i18n.permission_change_success, "s" ); self.refreshFileTable(); } else { - self.showMessage( "Permissions could not be changed: "+data.message, "e"); + self.showMessage( self.i18n.permission_change_error +data.message, "e"); } }, - error: function() { self.showMessage("General error occured.", "e"); } + error: function() { self.showMessage( self.i18n.general_error, "e"); } }); }; @@ -939,12 +939,12 @@ function IFM( params ) { dataType: "json", success: function(data) { if(data.status == "OK") { - self.showMessage( "File successfully uploaded", "s" ); + self.showMessage( self.i18n.file_upload_success, "s" ); self.refreshFileTable(); } else - self.showMessage( "File could not be uploaded:
" + data.message, "e" ); + self.showMessage( self.i18n.file_upload_error + data.message, "e" ); }, - error: function() { self.showMessage("General error occured", "e"); }, + error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); self.task_add( { id: id, name: "Remote upload: "+filename } ); @@ -1477,7 +1477,7 @@ function IFM( params ) { self.initLoadTemplates(); }, error: function() { - throw new Error( "IFM: could not load configuration" ); + throw new Error( self.i18n.load_config_error ); } }); }; @@ -1497,7 +1497,7 @@ function IFM( params ) { self.initLoadI18N(); }, error: function() { - throw new Error( "IFM: could not load templates" ); + throw new Error( self.i18n.load_template_error ); } }); }; @@ -1517,7 +1517,7 @@ function IFM( params ) { self.initApplication(); }, error: function() { - throw new Error( "IFM: could not load I18N" ); + throw new Error( self.i18n.load_text_error ); } }); }; diff --git a/src/templates/modal.renamefile.html b/src/templates/modal.renamefile.html index 65f00eb..d5de338 100644 --- a/src/templates/modal.renamefile.html +++ b/src/templates/modal.renamefile.html @@ -6,7 +6,7 @@ From e8a7053003a3fc861695b4266c30e6ebe40e007b Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Wed, 9 Aug 2017 01:36:47 +0200 Subject: [PATCH 07/19] fixed bugs with the createArchive function --- build/libifm.php | 44 ++++++++++++++++++++++++++++++-------------- ifm.php | 44 ++++++++++++++++++++++++++++++-------------- src/ifm.js | 4 ++-- src/ifmarchive.php | 38 +++++++++++++++++++++++++++----------- src/main.php | 2 +- 5 files changed, 90 insertions(+), 42 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 86ba089..a5ca468 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -2187,9 +2187,9 @@ function IFM( params ) { type = "zip"; else if( archivename.substr( -3 ).toLowerCase() == "tar" ) type = "tar"; - else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + else if( archivename.substr( -6 ).toLowerCase() == "tar.gz" ) type = "tar.gz"; - else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); @@ -3520,7 +3520,7 @@ function IFM( params ) { case "tar": case "tar.gz": case "tar.bz2": - if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + if( IFMArchive::createTar( $filenames, $d['archivename'], $d['format'] ) ) $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); @@ -3915,7 +3915,7 @@ class IFMArchive { private static function addFolder( &$archive, $folder, $offset=0 ) { if( $offset == 0 ) $offset = strlen( dirname( $folder ) ) + 1; - $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); + $archive->addEmptyDir( substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { @@ -3973,18 +3973,34 @@ class IFMArchive { /** * Creates a tar archive */ - public static function createTar( $src, $out ) { - $tar = new PharData( $out ); + public static function createTar( $src, $out, $t ) { + $tmpf = substr( $out, 0, strlen( $out ) - strlen( $t ) ) . "tar"; + $a = new PharData( $tmpf ); - if( ! is_array( $src ) ) - $src = array( $src ); + try { + if( ! is_array( $src ) ) + $src = array( $src ); - foreach( $src as $s ) - if( is_dir( $s ) ) - self::addFolder( $a, $s ); - elseif( is_file( $s ) ) - $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); - return true; + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + switch( $t ) { + case "tar.gz": + $a->compress( Phar::GZ ); + @unlink( $tmpf ); + break; + case "tar.bz2": + $a->compress( Phar::BZ2 ); + @unlink( $tmpf ); + break; + } + return true; + } catch( Exception $e ) { + @unlink( $tmpf ); + return false; + } } /** diff --git a/ifm.php b/ifm.php index 1427dda..58c728e 100644 --- a/ifm.php +++ b/ifm.php @@ -2187,9 +2187,9 @@ function IFM( params ) { type = "zip"; else if( archivename.substr( -3 ).toLowerCase() == "tar" ) type = "tar"; - else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + else if( archivename.substr( -6 ).toLowerCase() == "tar.gz" ) type = "tar.gz"; - else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); @@ -3520,7 +3520,7 @@ function IFM( params ) { case "tar": case "tar.gz": case "tar.bz2": - if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + if( IFMArchive::createTar( $filenames, $d['archivename'], $d['format'] ) ) $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); @@ -3915,7 +3915,7 @@ class IFMArchive { private static function addFolder( &$archive, $folder, $offset=0 ) { if( $offset == 0 ) $offset = strlen( dirname( $folder ) ) + 1; - $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); + $archive->addEmptyDir( substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { @@ -3973,18 +3973,34 @@ class IFMArchive { /** * Creates a tar archive */ - public static function createTar( $src, $out ) { - $tar = new PharData( $out ); + public static function createTar( $src, $out, $t ) { + $tmpf = substr( $out, 0, strlen( $out ) - strlen( $t ) ) . "tar"; + $a = new PharData( $tmpf ); - if( ! is_array( $src ) ) - $src = array( $src ); + try { + if( ! is_array( $src ) ) + $src = array( $src ); - foreach( $src as $s ) - if( is_dir( $s ) ) - self::addFolder( $a, $s ); - elseif( is_file( $s ) ) - $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); - return true; + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + switch( $t ) { + case "tar.gz": + $a->compress( Phar::GZ ); + @unlink( $tmpf ); + break; + case "tar.bz2": + $a->compress( Phar::BZ2 ); + @unlink( $tmpf ); + break; + } + return true; + } catch( Exception $e ) { + @unlink( $tmpf ); + return false; + } } /** diff --git a/src/ifm.js b/src/ifm.js index a721411..0bed7aa 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -1086,9 +1086,9 @@ function IFM( params ) { type = "zip"; else if( archivename.substr( -3 ).toLowerCase() == "tar" ) type = "tar"; - else if( archivename.substr( -5 ).toLowerCase() == "tar.gz" ) + else if( archivename.substr( -6 ).toLowerCase() == "tar.gz" ) type = "tar.gz"; - else if( archivename.substr( -6 ).toLowerCase() == "tar.bz2" ) + else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); diff --git a/src/ifmarchive.php b/src/ifmarchive.php index 9ef1f08..b19d448 100644 --- a/src/ifmarchive.php +++ b/src/ifmarchive.php @@ -26,7 +26,7 @@ class IFMArchive { private static function addFolder( &$archive, $folder, $offset=0 ) { if( $offset == 0 ) $offset = strlen( dirname( $folder ) ) + 1; - $archive->addEmptyDir( $folder, substr( $folder, $offset ) ); + $archive->addEmptyDir( substr( $folder, $offset ) ); $handle = opendir( $folder ); while( false !== $f = readdir( $handle ) ) { if( $f != '.' && $f != '..' ) { @@ -84,18 +84,34 @@ class IFMArchive { /** * Creates a tar archive */ - public static function createTar( $src, $out ) { - $tar = new PharData( $out ); + public static function createTar( $src, $out, $t ) { + $tmpf = substr( $out, 0, strlen( $out ) - strlen( $t ) ) . "tar"; + $a = new PharData( $tmpf ); - if( ! is_array( $src ) ) - $src = array( $src ); + try { + if( ! is_array( $src ) ) + $src = array( $src ); - foreach( $src as $s ) - if( is_dir( $s ) ) - self::addFolder( $a, $s ); - elseif( is_file( $s ) ) - $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); - return true; + foreach( $src as $s ) + if( is_dir( $s ) ) + self::addFolder( $a, $s ); + elseif( is_file( $s ) ) + $a->addFile( $s, substr( $s, strlen( dirname( $s ) ) +1 ) ); + switch( $t ) { + case "tar.gz": + $a->compress( Phar::GZ ); + @unlink( $tmpf ); + break; + case "tar.bz2": + $a->compress( Phar::BZ2 ); + @unlink( $tmpf ); + break; + } + return true; + } catch( Exception $e ) { + @unlink( $tmpf ); + return false; + } } /** diff --git a/src/main.php b/src/main.php index 4039368..f857613 100644 --- a/src/main.php +++ b/src/main.php @@ -871,7 +871,7 @@ f00bar; case "tar": case "tar.gz": case "tar.bz2": - if( IFMArchive::createTar( $filenames, $d['archivename'] ) ) + if( IFMArchive::createTar( $filenames, $d['archivename'], $d['format'] ) ) $this->jsonResponse( array( "status" => "OK", "message" => "Archive successfully created." ) ); else $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not create archive." ) ); From 564b7b4a01e13a0e084252e1d50a07c69c35b7c4 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Wed, 9 Aug 2017 10:53:13 +0200 Subject: [PATCH 08/19] remove ifm.js from build dir --- build/ifm.js | 1240 -------------------------------------------------- 1 file changed, 1240 deletions(-) delete mode 100644 build/ifm.js diff --git a/build/ifm.js b/build/ifm.js deleted file mode 100644 index 0631a4c..0000000 --- a/build/ifm.js +++ /dev/null @@ -1,1240 +0,0 @@ -/** - * IFM constructor - * - * @param object params - object with some configuration values, currently you only can set the api url - */ -function IFM( params ) { - var self = this; // reference to ourself, because "this" does not work within callbacks - - // set the backend for the application - params = params || {}; - self.api = params.api || window.location.pathname; - - 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 - this.rootElement = ""; - - /** - * 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" ) - .attr( 'id', 'ifmmodal' ) - .attr( 'role', 'dialog' ); - var modalDialog = $( document.createElement( 'div' ) ) - .addClass( "modal-dialog" ) - .attr( 'role', 'document' ); - if( options.large == true ) modalDialog.addClass( 'modal-lg' ); - var modalContent = $(document.createElement('div')) - .addClass("modal-content") - .append( content ); - modalDialog.append( modalContent ); - modal.append( modalDialog ); - $( document.body ).append( modal ); - modal.on('hide.bs.modal', function () { $(this).remove(); }); - modal.on('shown.bs.modal', function () { - var formElements = $(this).find('input, button'); - if( formElements.length > 0 ) { - formElements.first().focus(); - } - }); - 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 ); - $.ajax({ - url: self.api, - type: "POST", - data: { - api: "getFiles", - dir: self.currentDir - }, - dataType: "json", - success: self.rebuildFileTable, - 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 ) { - data.forEach( function( item ) { - item.guid = self.generateGuid(); - item.linkname = ( item.name == ".." ) ? "[ up ]" : item.name; - item.download = {}; - item.download.name = ( item.name == ".." ) ? "." : item.name; - item.download.allowed = self.config.download; - item.download.currentDir = self.currentDir; - if( ! self.config.chmod ) - item.readonly = "readonly"; - if( self.config.edit || self.config.rename || self.config.delete || self.config.extract || self.config.copymove ) { - item.ftbuttons = true; - item.button = []; - } - if( item.type == "dir" ) { - item.download.action = "zipnload"; - item.download.icon = "icon icon-download-cloud"; - item.rowclasses = "isDir"; - } else { - item.download.action = "download"; - item.download.icon = "icon icon-download"; - if( item.icon.indexOf( 'file-image' ) !== -1 && self.config.isDocroot ) - item.tooltip = 'data-toggle="tooltip" title=""'; - if( item.name.toLowerCase().substr(-4) == ".zip" ) - item.eaction = "extract"; - else - item.eaction = "edit"; - if( self.config.edit && item.name.toLowerCase().substr(-4) != ".zip" ) - item.button.push({ - action: "edit", - icon: "icon icon-pencil", - title: "edit" - }); - else - item.button.push({ - action: "extract", - icon: "icon icon-archive", - title: "extract" - }); - } - if( ! self.inArray( item.name, [".", ".."] ) ) { - if( self.config.copymove ) - item.button.push({ - action: "copymove", - icon: "icon icon-folder-open-empty", - title: "copy/move" - }); - if( self.config.rename ) - item.button.push({ - action: "rename", - icon: "icon icon-terminal", - title: "rename" - }); - if( self.config.delete ) - item.button.push({ - action: "delete", - icon: "icon icon-trash", - title: "delete" - }); - } - }); - var newTBody = Mustache.render( self.templates.filetable, { items: data, config: self.config } ); - $( "#filetable tbody" ).remove(); - $( "#filetable" ).append( $(newTBody) ); - $( '.clickable-row' ).click( function( event ) { - if( event.ctrlKey ) { - $( this ).toggleClass( 'selectedItem' ); - } - }); - $( 'a[data-toggle="tooltip"]' ).tooltip({ - animated: 'fade', - placement: 'right', - html: true - }); - $( 'a.ifmitem' ).each( function() { - if( $(this).data( "type" ) == "dir" ) { - $(this).on( 'click', function( e ) { - e.stopPropagation(); - self.changeDirectory( $(this).parent().parent().data( 'filename' ) ); - return false; - }); - } else { - if( self.config.isDocroot ) - $(this).attr( "href", self.pathCombine( self.currentDir, $(this).parent().parent().data( 'filename' ) ) ); - else - $(this).on( 'click', function() { - $( '#d_' + this.id ).submit(); - return false; - }); - } - }); - $( 'a[name="start_download"]' ).on( 'click', function(e) { - e.stopPropagation(); - $( '#d_' + $(this).data( 'guid' ) ).submit(); - return false; - }); - $( 'input[name="newpermissions"]' ).on( 'keypress', function( e ) { - if( e.key == "Enter" ) { - e.stopPropagation(); - self.changePermissions( $( this ).data( 'filename' ), $( this ).val() ); - return false; - } - }); - $( 'a[name^="do-"]' ).on( 'click', function() { - var action = this.name.substr( this.name.indexOf( '-' ) + 1 ); - switch( action ) { - case "rename": - self.showRenameFileDialog( $(this).data( 'name' ) ); - break; - case "extract": - self.showExtractFileDialog( $(this).data( 'name' ) ); - break; - case "edit": - self.editFile( $(this).data( 'name' ) ); - break; - case "delete": - self.showDeleteFileDialog( $(this).data( 'name' ) ); - break; - case "copymove": - self.showCopyMoveDialog( $(this).data( 'name' ) ); - break; - } - }); - - }; - - /** - * 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.api, - type: "POST", - data: ({ - api: "getRealpath", - dir: newdir - }), - dataType: "json", - success: function( data ) { - self.currentDir = data.realpath; - self.refreshFileTable(); - $( "#currentDir" ).val( self.currentDir ); - if( config.pushState ) history.pushState( { dir: self.currentDir }, self.currentDir, "#"+self.currentDir ); - }, - error: function() { self.showMessage( "General error occured: No or broken response", "e" ); } - }); - }; - - /** - * Shows a file, either a new file or an existing - */ - this.showFileDialog = function () { - var filename = arguments.length > 0 ? arguments[0] : "newfile.txt"; - var content = arguments.length > 1 ? arguments[1] : ""; - self.showModal( Mustache.render( self.templates.file, { filename: filename } ), { large: true } ); - var form = $('#formFile'); - form.find('input[name="filename"]').on( 'keypress', self.preventEnter ); - form.find('#buttonSave').on( 'click', function() { - self.saveFile( form.find('input[name=filename]').val(), self.editor.getValue() ); - self.hideModal(); - return false; - }); - form.find('#buttonSaveNotClose').on( 'click', function() { - self.saveFile( form.find('input[name=filename]').val(), self.editor.getValue() ); - return false; - }); - form.find('#buttonClose').on( 'click', function() { - self.hideModal(); - return false; - }); - form.find('#editoroptions').popover({ - html: true, - title: function() { return $('#editoroptions-head').html(); }, - content: function() { - var content = $('#editoroptions-content').clone() - var aceSession = self.editor.getSession(); - content.removeClass( 'hide' ); - content.find( '#editor-wordwrap' ) - .prop( 'checked', ( aceSession.getOption( 'wrap' ) == 'off' ? false : true ) ) - .on( 'change', function() { self.editor.setOption( 'wrap', $( this ).is( ':checked' ) ); }); - content.find( '#editor-softtabs' ) - .prop( 'checked', aceSession.getOption( 'useSoftTabs' ) ) - .on( 'change', function() { self.editor.setOption( 'useSoftTabs', $( this ).is( ':checked' ) ); }); - content.find( '#editor-tabsize' ) - .val( aceSession.getOption( 'tabSize' ) ) - .on( 'keydown', function( e ) { if( e.key == 'Enter' ) { self.editor.setOption( 'tabSize', $( this ).val() ); } }); - return content; - } - }); - form.on( 'remove', function () { self.editor = null; self.fileChanged = false; }); - // Start ACE - self.editor = ace.edit("content"); - self.editor.$blockScrolling = 'Infinity'; - self.editor.getSession().setValue(content); - self.editor.focus(); - self.editor.on("change", function() { self.fileChanged = true; }); - // word wrap checkbox - $('#aceWordWrap').on( 'change', function (event) { - self.editor.getSession().setUseWrapMode( $(this).is(':checked') ); - }); - }; - - /** - * Saves a file - */ - this.saveFile = function( filename, content ) { - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "saveFile", - dir: self.currentDir, - filename: filename, - content: content - }), - dataType: "json", - success: function( data ) { - if( data.status == "OK" ) { - self.showMessage( "File successfully edited/created.", "s" ); - self.refreshFileTable(); - } else self.showMessage( "File could not be edited/created:" + data.message, "e" ); - }, - error: function() { self.showMessage( "General error occured", "e" ); } - }); - self.fileChanged = false; - }; - - /** - * Edit a file - * - * @params string name - name of the file - */ - this.editFile = function( name ) { - $.ajax({ - url: self.api, - type: "POST", - dataType: "json", - data: ({ - api: "getContent", - dir: self.currentDir, - filename: name - }), - success: function( data ) { - if( data.status == "OK" && data.data.content != null ) { - self.showFileDialog( data.data.filename, data.data.content ); - } - else if( data.status == "OK" && data.data.content == null ) { - self.showMessage( "The content of this file cannot be fetched.", "e" ); - } - else self.showMessage( "Error: "+data.message, "e" ); - }, - error: function() { self.showMessage( "This file can not be displayed or edited.", "e" ); } - }); - }; - - /** - * Shows the create directory dialog - */ - this.showCreateDirDialog = function() { - self.showModal( self.templates.createdir ); - var form = $( '#formCreateDir' ); - form.find( 'input[name=dirname]' ).on( 'keypress', self.preventEnter ); - form.find( '#buttonSave' ).on( 'click', function() { - self.createDir( form.find( 'input[name=dirname] ').val() ); - self.hideModal(); - return false; - }); - form.find( '#buttonCancel' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Create a directory - */ - this.createDir = function( dirname ) { - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "createDir", - dir: self.currentDir, - dirname: dirname - }), - dataType: "json", - success: function( data ){ - if( data.status == "OK" ) { - self.showMessage( "Directory sucessfully created.", "s" ); - self.refreshFileTable(); - } - else { - self.showMessage( "Directory could not be created: "+data.message, "e" ); - } - }, - error: function() { self.showMessage( "General error occured.", "e" ); } - }); - }; - - - /** - * Shows the delete file dialog - * - * @param string name - name of the file - */ - this.showDeleteFileDialog = function( filename ) { - self.showModal( Mustache.render( self.templates.deletefile, { filename: name } ) ); - var form = $( '#formDeleteFile' ); - form.find( '#buttonYes' ).on( 'click', function() { - self.deleteFile( self.JSEncode( filename ) ); - self.hideModal(); - return false; - }); - form.find( '#buttonNo' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Deletes a file - * - * @params string name - name of the file - */ - this.deleteFile = function( filename ) { - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "delete", - dir: self.currentDir, - filename: filename - }), - dataType: "json", - success: function(data) { - if(data.status == "OK") { - self.showMessage("File successfully deleted", "s"); - self.refreshFileTable(); - } else self.showMessage("File could not be deleted", "e"); - }, - error: function() { self.showMessage("General error occured", "e"); } - }); - }; - - /** - * Show the rename file dialog - * - * @params string name - name of the file - */ - this.showRenameFileDialog = function( filename ) { - self.showModal( Mustache.render( self.templates.renamefile, { filename: filename } ) ); - var form = $( '#formRenameFile' ); - form.find( 'input[name=newname]' ).on( 'keypress', self.preventEnter ); - form.find( '#buttonRename' ).on( 'click', function() { - self.renameFile( filename, form.find( 'input[name=newname]' ).val() ); - self.hideModal(); - return false; - }); - form.find( '#buttonCancel' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Renames a file - * - * @params string name - name of the file - */ - this.renameFile = function( filename, newname ) { - $.ajax({ - url: ifm.api, - type: "POST", - data: ({ - api: "rename", - dir: ifm.currentDir, - filename: filename, - newname: newname - }), - dataType: "json", - success: function(data) { - if(data.status == "OK") { - ifm.showMessage("File successfully renamed", "s"); - ifm.refreshFileTable(); - } else ifm.showMessage("File could not be renamed: "+data.message, "e"); - }, - error: function() { ifm.showMessage("General error occured", "e"); } - }); - }; - - /** - * Show the copy/move dialog - * - * @params string name - name of the file - */ - this.showCopyMoveDialog = function( name ) { - self.showModal( self.templates.copymove ); - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "getFolderTree", - dir: self.currentDir - }), - dataType: "json", - success: function( data ) { - $( '#copyMoveTree' ).treeview( { data: data, levels: 0, expandIcon: "icon icon-folder-empty", collapseIcon: "icon icon-folder-open-empty" } ); - }, - error: function() { self.hideModal(); self.showMessage( "Error while fetching the folder tree.", "e" ) } - }); - $( '#copyButton' ).on( 'click', function() { - self.copyMove( name, $('#copyMoveTree .node-selected').data('path'), 'copy' ); - self.hideModal(); - return false; - }); - $( '#moveButton' ).on( 'click', function() { - self.copyMove( name, $('#copyMoveTree .node-selected').data('path'), 'move' ); - self.hideModal(); - return false; - }); - $( '#cancelButton' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Copy or moves a file - * - * @params string name - name of the file - */ - this.copyMove = function( source, destination, action ) { - var id = self.generateGuid(); - self.task_add( action.charAt(0).toUpperCase() + action.slice(1) + " " + source + " to " + destination, id ); - $.ajax({ - url: self.api, - type: "POST", - data: { - dir: self.currentDir, - api: "copyMove", - action: action, - filename: source, - destination: destination - }, - dataType: "json", - success: function(data) { - if( data.status == "OK" ) { - self.showMessage( data.message, "s" ); - } else { - self.showMessage( data.message, "e" ); - } - self.refreshFileTable(); - }, - error: function() { - self.showMessage( "General error occured.", "e" ); - }, - complete: function() { - self.task_done( id ); - } - }); - }; - - /** - * Shows the extract file dialog - * - * @param string name - name of the file - */ - this.showExtractFileDialog = function( filename ) { - var targetDirSuggestion = ''; - if( filename.lastIndexOf( '.' ) > 1 ) - targetDirSuggestion = filename.substr( 0, filename.lastIndexOf( '.' ) ); - else targetDirSuggestion = filename; - self.showModal( Mustache.render( self.templates.extractfile, { filename: filename, destination: targetDirSuggestion } ) ); - var form = $('#formExtractFile'); - form.find('#buttonExtract').on( 'click', function() { - var t = form.find('input[name=extractTargetLocation]:checked').val(); - if( t == "custom" ) t = form.find('#extractCustomLocation').val(); - self.extractFile( self.JSEncode( filename ), t ); - self.hideModal(); - return false; - }); - form.find('#buttonCancel').on( 'click', function() { - self.hideModal(); - return false; - }); - form.find('#extractCustomLocation').on( 'click', function(e) { - $(e.target).prev().children().first().prop( 'checked', true ); - }); - }; - - /** - * Extracts a file - * - * @param string filename - name of the file - * @param string destination - name of the target directory - */ - this.extractFile = function( filename, destination ) { - $.ajax({ - url: self.api, - type: "POST", - data: { - api: "extract", - dir: self.currentDir, - filename: filename, - targetdir: destination - }, - dataType: "json", - success: function( data ) { - if( data.status == "OK" ) { - self.showMessage( "File successfully extracted", "s" ); - self.refreshFileTable(); - } else self.showMessage( "File could not be extracted. Error: " + data.message, "e" ); - }, - error: function() { self.showMessage( "General error occured", "e" ); } - }); - }; - - /** - * Shows the upload file dialog - */ - this.showUploadFileDialog = function() { - self.showModal( self.templates.uploadfile ); - var form = $('#formUploadFile'); - form.find( 'input[name=newfilename]' ).on( 'keypress', self.preventEnter ); - form.find( '#buttonUpload' ).on( 'click', function() { - self.uploadFile(); - self.hideModal(); - return false; - }); - form.find( '#buttonCancel' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Uploads a file - */ - this.uploadFile = function() { - var ufile = document.getElementById( 'ufile' ).files[0]; - var data = new FormData(); - var newfilename = $("#formUploadFile input[name^=newfilename]").val(); - data.append('api', 'upload'); - data.append('dir', self.currentDir); - data.append('file', ufile); - data.append('newfilename', newfilename); - var id = self.generateGuid(); - $.ajax({ - url: self.api, - type: "POST", - data: data, - processData: false, - contentType: false, - dataType: "json", - xhr: function(){ - var xhr = $.ajaxSettings.xhr() ; - xhr.upload.onprogress = function(evt){ self.task_update(evt.loaded/evt.total*100,id); } ; - xhr.upload.onload = function(){ console.log('Uploading '+newfilename+' done.') } ; - return xhr ; - }, - success: function(data) { - if(data.status == "OK") { - self.showMessage("File successfully uploaded", "s"); - if(data.cd == self.currentDir) self.refreshFileTable(); - } else self.showMessage("File could not be uploaded: "+data.message, "e"); - }, - error: function() { self.showMessage("General error occured", "e"); }, - complete: function() { self.task_done(id); } - }); - self.task_add("Upload "+ufile.name, id); - }; - - /** - * Change the permissions of a file - * - * @params object e - event object - * @params string name - name of the file - */ - this.changePermissions = function( filename, newperms) { - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "changePermissions", - dir: self.currentDir, - filename: filename, - chmod: newperms - }), - dataType: "json", - success: function( data ){ - if( data.status == "OK" ) { - self.showMessage( "Permissions successfully changed.", "s" ); - self.refreshFileTable(); - } - else { - self.showMessage( "Permissions could not be changed: "+data.message, "e"); - } - }, - error: function() { self.showMessage("General error occured.", "e"); } - }); - }; - - /** - * Show the remote upload dialog - */ - this.showRemoteUploadDialog = function() { - self.showModal( self.templates.remoteupload ); - var form = $('#formRemoteUpload'); - form.find( '#url' ) - .on( 'keypress', self.preventEnter ) - .on( 'change keyup', function() { - $("#filename").val($(this).val().substr($(this).val().lastIndexOf("/")+1)); - }); - form.find( '#filename' ) - .on( 'keypress', self.preventEnter ) - .on( 'keyup', function() { $("#url").off( 'change keyup' ); }); - form.find( '#buttonUpload' ).on( 'click', function() { - self.remoteUpload(); - self.hideModal(); - return false; - }); - form.find( '#buttonCancel' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Remote uploads a file - */ - this.remoteUpload = function() { - var filename = $("#formRemoteUpload #filename").val(); - var id = ifm.generateGuid(); - $.ajax({ - url: ifm.api, - type: "POST", - data: ({ - api: "remoteUpload", - dir: ifm.currentDir, - filename: filename, - method: $("#formRemoteUpload input[name=method]:checked").val(), - url: encodeURI($("#url").val()) - }), - dataType: "json", - success: function(data) { - if(data.status == "OK") { - ifm.showMessage("File successfully uploaded", "s"); - ifm.refreshFileTable(); - } else ifm.showMessage("File could not be uploaded:
"+data.message, "e"); - }, - error: function() { ifm.showMessage("General error occured", "e"); }, - complete: function() { ifm.task_done(id); } - }); - ifm.task_add("Remote upload: "+filename, id); - }; - - /** - * Shows the ajax request dialog - */ - this.showAjaxRequestDialog = function() { - self.showModal( self.templates.ajaxrequest ); - var form = $('#formAjaxRequest'); - form.find( '#ajaxurl' ).on( 'keypress', self.preventEnter ); - form.find( '#buttonRequest' ).on( 'click', function() { - self.ajaxRequest(); - return false; - }); - form.find( '#buttonClose' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Performs an ajax request - */ - this.ajaxRequest = function() { - $.ajax({ - url : $("#ajaxurl").val(), - cache : false, - data : $('#ajaxdata').val().replace(/\n/g,"&"), - type : $('#ajaxrequest input[name=arMethod]:checked').val(), - success : function(response) { $("#ajaxresponse").text(response); }, - error : function(e) { self.showMessage("Error: "+e, "e"); console.log(e); } - }); - }; - - /** - * Shows the delete dialog for multiple files - */ - this.showMultiDeleteDialog = function() { - self.showModal( Mustache.render( self.templates.multidelete, { count: $('#filetable tr.selectedItem').length } ) ); - var form = $('#formDeleteFiles'); - form.find( '#buttonYes' ).on( 'click', function() { - self.multiDelete(); - self.hideModal(); - return false; - }); - form.find( '#buttonNo' ).on( 'click', function() { - self.hideModal(); - return false; - }); - }; - - /** - * Deletes multiple files - */ - this.multiDelete = function() { - var elements = $('#filetable tr.selectedItem'); - var filenames = []; - for(var i=0;typeof(elements[i])!='undefined';filenames.push(elements[i++].getAttribute('data-filename'))); - $.ajax({ - url: self.api, - type: "POST", - data: ({ - api: "multidelete", - dir: self.currentDir, - filenames: filenames - }), - dataType: "json", - success: function(data) { - if(data.status == "OK") { - if(data.errflag == 1) - ifm.showMessage("All files successfully deleted.", "s"); - else if(data.errflag == 0) - ifm.showMessage("Some files successfully deleted. "+data.message); - else - ifm.showMessage("Files could not be deleted. "+data.message, "e"); - ifm.refreshFileTable(); - } else ifm.showMessage("Files could not be deleted:
"+data.message, "e"); - }, - error: function() { ifm.showMessage("General error occured", "e"); } - }); - }; - - // -------------------- - // helper functions - // -------------------- - - /** - * Shows a notification - * - * @param string m - message text - * @param string t - message type (e: error, s: success) - */ - this.showMessage = function(m, t) { - var msgType = (t == "e")?"danger":(t == "s")?"success":"info"; - var element = ( self.config.inline ) ? self.rootElement : "body"; - $.notify( - { message: m }, - { type: msgType, delay: 5000, mouse_over: 'pause', offset: { x: 15, y: 65 }, element: element } - ); - }; - - /** - * Combines two path components - * - * @param string a - component 1 - * @param string b - component 2 - */ - this.pathCombine = function(a, b) { - if(a == "" && b == "") return ""; - if(b[0] == "/") b = b.substring(1); - if(a == "") return b; - if(a[a.length-1] == "/") a = a.substring(0, a.length-1); - if(b == "") return a; - return a+"/"+b; - }; - - /** - * Prevents a user to submit a form via clicking enter - * - * @param object e - click event - */ - this.preventEnter = function(e) { - if( e.keyCode == 13 ) return false; - else return true; - } - - /** - * Checks if an element is part of an array - * - * @param obj needle - search item - * @param array haystack - array to search - */ - this.inArray = function(needle, haystack) { - for(var i = 0; i < haystack.length; i++) { if(haystack[i] == needle) return true; } return false; - }; - - /** - * Adds a task to the taskbar. - * - * @param string name - description of the task - * @param string id - identifier for the task - */ - this.task_add = function( name, id ) { - if( ! document.getElementById( "waitqueue" ) ) { - $( document.body ).prepend( '
' ); - } - $( "#waitqueue" ).prepend('\ -
\ -
\ -
\ -
\ - '+name+'\ -
\ -
\ -
\ - '); - }; - - /** - * Removes a task from the taskbar - * - * @param string id - task identifier - */ - this.task_done = function(id) { - $("#"+id).remove(); - if($("#waitqueue>div").length == 0) { - $("#waitqueue").remove(); - } - }; - - /** - * Updates a task - * - * @param integer progress - percentage of status - * @param string id - task identifier - */ - this.task_update = function(progress, id) { - $('#'+id+' .progress-bar').css('width', progress+'%').attr('aria-valuenow', progress); - }; - - /** - * Highlights an item in the file table - * - * @param object param - either an element id or a jQuery object - */ - this.highlightItem = function( param ) { - var highlight = function( el ) { - el.addClass( 'highlightedItem' ).siblings().removeClass( 'highlightedItem' ); - el.find( 'a' ).first().focus(); - if( ! self.isElementInViewport( el ) ) { - var scrollOffset = 0; - if( param=="prev" ) - scrollOffset = el.offset().top - ( window.innerHeight || document.documentElement.clientHeight ) + el.height() + 15; - else - scrollOffset = el.offset().top - 55; - $('html, body').animate( { scrollTop: scrollOffset }, 200 ); - } - }; - if( param.jquery ) { - highlight( param ); - } else { - var highlightedItem = $('.highlightedItem'); - if( ! highlightedItem.length ) { - highlight( $('#filetable tbody tr:first-child') ); - } else { - var newItem = ( param=="next" ? highlightedItem.next() : highlightedItem.prev() ); - - if( newItem.is( 'tr' ) ) { - highlight( newItem ); - } - } - } - }; - - /** - * Checks if an element is within the viewport - * - * @param object el - element object - */ - this.isElementInViewport = function (el) { - if (typeof jQuery === "function" && el instanceof jQuery) { - el = el[0]; - } - var rect = el.getBoundingClientRect(); - return ( - rect.top >= 60 && - rect.left >= 0 && - rect.bottom <= ( (window.innerHeight || document.documentElement.clientHeight) ) && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) - ); - } - - /** - * Generates a GUID - */ - this.generateGuid = function() { - var result, i, j; - result = ''; - for(j=0; j<20; j++) { - i = Math.floor(Math.random()*16).toString(16).toUpperCase(); - result = result + i; - } - return result; - }; - - /** - * Logs a message if debug mode is on - * - * @param string m - message text - */ - this.log = function( m ) { - if( self.config.debug ) { - console.log( "IFM (debug): " + m ); - } - }; - - /** - * Encodes a string for use within javascript - * - * @param string s - encoding string - */ - this.JSEncode = function(s) { - return s.replace(/'/g, '\\x27').replace(/"/g, '\\x22'); - }; - - /** - * Handles the javascript pop states - * - * @param object event - event object - */ - this.historyPopstateHandler = function(event) { - var dir = ""; - if( event.state && event.state.dir ) dir = event.state.dir; - self.changeDirectory( dir, { pushState: false, absolute: true } ); - }; - - /** - * Handles keystrokes - * - * @param object e - event object - */ - this.handleKeystrokes = function( e ) { - // bind 'del' key - if( $(e.target).closest('input')[0] || $(e.target).closest('textarea')[0] ) { - return; - } - - switch( e.key ) { - case 'Delete': - if( self.config.delete ) { - if( $('#filetable tr.selectedItem').length > 0 ) { - e.preventDefault(); - self.showMultiDeleteDialog(); - } else { - var item = $('.highlightedItem'); - if( item.length ) - self.showDeleteFileDialog( item.data( 'filename' ) ); - } - } - break; - case 'e': - if( self.config.edit ) { - var item = $('.highlightedItem'); - if( item.length && ! item.hasClass( 'isDir' ) ) { - e.preventDefault(); - var action = item.data( 'eaction' ); - switch( action ) { - case 'extract': - self.showExtractFileDialog( item.data( 'filename' ) ); - break; - case 'edit': - self.editFile( item.data( 'filename' ) ); - } - } - } - break; - case 'g': - e.preventDefault(); - $('#currentDir').focus(); - break; - case 'r': - e.preventDefault(); - self.refreshFileTable(); - break; - case 'u': - if( self.config.upload ) { - e.preventDefault(); - self.showUploadFileDialog(); - } - break; - case 'o': - if( self.config.remoteupload ) { - e.preventDefault(); - self.showRemoteUploadDialog(); - } - break; - case 'a': - if( self.config.ajaxrequest ) { - e.preventDefault(); - self.showAjaxRequestDialog(); - } - break; - case 'F': - if( self.config.createfile ) { - e.preventDefault(); - self.showFileDialog(); - } - break; - case 'D': - if( self.config.createdir ) { - e.preventDefault(); - self.showCreateDirDialog(); - } - break; - case 'h': - case 'ArrowLeft': - e.preventDefault(); - self.changeDirectory( '..' ); - break; - case 'l': - case 'ArrowRight': - e.preventDefault(); - var item = $('.highlightedItem'); - if( item.hasClass('isDir') ) - self.changeDirectory( item.data( 'filename' ) ); - break; - case 'j': - case 'ArrowDown': - e.preventDefault(); - self.highlightItem('next'); - break; - case 'k': - case 'ArrowUp': - e.preventDefault(); - self.highlightItem('prev'); - break; - case 'Escape': - if( $(':focus').is( '.clickable-row td:first-child a:first-child' ) && $('.highlightedItem').length ) { - e.preventDefault(); - $('.highlightedItem').removeClass( 'highlightedItem' ); - } - break; - case ' ': // todo: make it work only when noting other is focused - case 'Enter': - if( $(':focus').is( '.clickable-row td:first-child a:first-child' ) ) { - var trParent = $(':focus').parent().parent(); - if( e.key == 'Enter' && trParent.hasClass( 'isDir' ) ) { - e.preventDefault(); - e.stopPropagation(); - self.changeDirectory( trParent.data( 'filename' ) ); - } else if( e.key == ' ' && ! trParent.is( ':first-child' ) ) { - e.preventDefault(); - e.stopPropagation(); - var item = $('.highlightedItem'); - if( item.is( 'tr' ) ) - item.toggleClass( 'selectedItem' ); - } - } - break; - } - } - - /** - * Initializes the application - */ - this.initLoadConfig = function() { - $.ajax({ - url: self.api, - type: "POST", - data: { - api: "getConfig" - }, - dataType: "json", - success: function(d) { - self.config = d; - self.log( "configuration loaded" ); - self.initLoadTemplates(); - }, - error: function() { - throw new Error( "IFM: could not load configuration" ); - } - }); - }; - - this.initLoadTemplates = function() { - // load the templates from the backend - $.ajax({ - url: self.api, - type: "POST", - data: { - api: "getTemplates" - }, - dataType: "json", - success: function(d) { - self.templates = d; - self.log( "templates loaded" ); - self.initApplication(); - }, - error: function() { - throw new Error( "IFM: could not load templates" ); - } - }); - }; - - this.initApplication = function() { - self.rootElement.html( - Mustache.render( - self.templates.app, - { - showpath: "/", - config: self.config, - ftbuttons: function(){ - return ( self.config.edit || self.config.rename || self.config.delete || self.config.zipnload || self.config.extract ); - } - } - ) - ); - // bind static buttons - $("#refresh").click(function(){ - self.refreshFileTable(); - }); - $("#createFile").click(function(){ - self.showFileDialog(); - }); - $("#createDir").click(function(){ - self.showCreateDirDialog(); - }); - $("#upload").click(function(){ - self.showUploadFileDialog(); - }); - $('#currentDir').on( 'keypress', function (event) { - if( event.keyCode == 13 ) { - event.preventDefault(); - self.changeDirectory( $(this).val(), { absolute: true } ); - } - }); - $('#buttonRemoteUpload').on( 'click', function() { - self.showRemoteUploadDialog(); - return false; - }); - $('#buttonAjaxRequest').on( 'click', function() { - self.showAjaxRequestDialog(); - return false; - }); - // handle keystrokes - $(document).on( 'keydown', self.handleKeystrokes ); - // handle history manipulation - window.onpopstate = self.historyPopstateHandler; - // load initial file table - if( window.location.hash ) { - self.changeDirectory( window.location.hash.substring( 1 ) ); - } else { - this.refreshFileTable(); - } - }; - - this.init = function( id ) { - self.rootElement = $('#'+id); - this.initLoadConfig(); - }; -} From e11faedc9d38a3854646adcba293a9bdd69c78cb Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Wed, 9 Aug 2017 11:53:51 +0200 Subject: [PATCH 09/19] finalize i18n in the js part --- build/libifm.php | 61 ++++++++++++++++++++++++++++-------------------- ifm.php | 61 ++++++++++++++++++++++++++++-------------------- src/i18n/de.json | 13 +++++++---- src/i18n/en.json | 14 +++++++---- src/ifm.js | 36 ++++++++++++++-------------- 5 files changed, 109 insertions(+), 76 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index a5ca468..3eb0669 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -557,15 +557,20 @@ f00bar; $i18n["en"] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name of the archive", + "archive_create_sucess": "Archive successfully created.", "cancel": "Cancel", "close": "Close", "copy": "Copy", + "create_archive": "Create archive", "data": "Data", "delete": "Delete", "directoryname": "Directory Name", + "download": "Download", + "edit": "edit", "editor_options": "Editor Options", "error": "Error:", - "extract": "Extract", + "extract": "extract", "extract_filename": "Extract file - ", "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", @@ -596,6 +601,7 @@ f00bar; "github": "Visit the project on GitHub", "group": "Group", "invalid_data": "Invalid data from server", + "invalid_archive_format": "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "last_modified": "Last Modified", "load_config_error": "Could not load configuration", "load_template_error": "Could not load templates", @@ -611,8 +617,8 @@ f00bar; "permission_change_error": "Permissions could not be changed: ", "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", - "refresh": "Refresh", - "rename": "Rename", + "refresh": "refresh", + "rename": "rename", "rename_filename": "Rename file -", "request": "Request", "response": "Response", @@ -633,22 +639,27 @@ f00bar; "username": "username", "word_wrap": "Word Wrap" } + f00bar; $i18n["en"] = json_decode( $i18n["en"], true ); $i18n["de"] = <<<'f00bar' { "ajax_request": "AJAX Request", "archivename": "Name des Archivs", + "archive_create_sucess": "Archive successfully created.", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", + "create_archive": "Archiv erstellen", "data": "Daten", "delete": "Löschen", "directoryname": "Ordner Name", + "download": "Download", + "edit": "Bearbeiten", "editor_options": "Editor Optionen", "error": "Fehler:", - "extract": "Auspacken", - "extract_filename": "Folgende Datei auspacken -", + "extract": "Entpacken", + "extract_filename": "Folgende Datei entpacken -", "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_delete_error": "Datei(en) konnten nicht gelöscht werden", @@ -681,6 +692,7 @@ $i18n["de"] = <<<'f00bar' "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", "invalid_data": "Fehlerhafte Daten vom Server erhalten", + "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", "last_modified": "Zuletzt geändert", "load_config_error": "Konfiguration konnte nicht geladen werden", "load_template_error": "Vorlagen konnten nicht geladen werden", @@ -702,7 +714,7 @@ $i18n["de"] = <<<'f00bar' "request": "Anfrage", "response": "Antwort", "save": "Speichen", - "save_wo_close": "Speichen ohne Schließen", + "save_wo_close": "Speichen ohne schließen", "search": "Suchen", "search_pattern": "Muster", "select_destination": "Zielort auswählen", @@ -719,7 +731,6 @@ $i18n["de"] = <<<'f00bar' "username": "Benutzername", "word_wrap": "Zeilenumbruch" } - f00bar; $i18n["de"] = json_decode( $i18n["de"], true ); @@ -1168,7 +1179,7 @@ function IFM( params ) { */ this.refreshFileTable = function () { var taskid = self.generateGuid(); - self.task_add( { id: taskid, name: "Refresh" } ); + self.task_add( { id: taskid, name: self.i18n.refresh } ); $.ajax({ url: self.api, type: "POST", @@ -1349,7 +1360,7 @@ function IFM( params ) { ], actions: { edit: { - name: "edit", + name: self.i18n.edit, onClick: function( data ) { self.editFile( data.clicked.name ); }, @@ -1359,7 +1370,7 @@ function IFM( params ) { } }, extract: { - name: "extract", + name: self.i18n.extract, onClick: function( data ) { self.showExtractFileDialog( data.clicked.name ); }, @@ -1369,7 +1380,7 @@ function IFM( params ) { } }, rename: { - name: "rename", + name: self.i18n.rename, onClick: function( data ) { self.showRenameFileDialog( data.clicked.name ); }, @@ -1379,9 +1390,9 @@ function IFM( params ) { copymove: { name: function( data ) { if( data.selected.length > 0 ) - return 'copy/move '+data.selected.length+''; + return self.i18n.copy+'/'+self.i18n.move+' '+data.selected.length+''; else - return 'copy/move'; + return self.i18n.copy+'/'+self.i18n.move; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1395,9 +1406,9 @@ function IFM( params ) { download: { name: function( data ) { if( data.selected.length > 0 ) - return 'download '+data.selected.length+''; + return self.i18n.download+' '+data.selected.length+''; else - return 'download'; + return self.i18n.download; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1411,9 +1422,9 @@ function IFM( params ) { createarchive: { name: function( data ) { if( data.selected.length > 0 ) - return 'create archive '+data.selected.length+''; + return self.i18n.create_archive+' '+data.selected.length+''; else - return 'create archive'; + return self.i18n.create_archive; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1427,9 +1438,9 @@ function IFM( params ) { 'delete': { name: function( data ) { if( data.selected.length > 0 ) - return 'delete '+data.selected.length+''; + return self.i18n.delete+' '+data.selected.length+''; else - return 'delete'; + return self.i18n.delete; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -2063,7 +2074,7 @@ function IFM( params ) { error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); - self.task_add( { id: id, name: "Remote upload: "+filename } ); + self.task_add( { id: id, name: self.i18n.upload_remote+" "+filename } ); }; /** @@ -2192,11 +2203,11 @@ function IFM( params ) { else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { - self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + self.showMessage( self.i18n.invalid_archive_format, "e" ); return; } var id = self.generateGuid(); - self.task_add( { id: id, name: "Create archive "+archivename } ); + self.task_add( { id: id, name: self.i18n.create_archive+" "+archivename } ); $.ajax({ url: self.api, @@ -2211,12 +2222,12 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "Archive successfully created.", "s" ); + self.showMessage( self.i18n.archive_create_success, "s" ); self.refreshFileTable(); } else self.showMessage( data.message, "e" ); }, - error: function() { self.showMessage( "General error occured.", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -2789,7 +2800,7 @@ function IFM( params ) { var dragImage = document.createElement( 'div' ); dragImage.style.display = 'inline'; dragImage.style.padding = '10px'; - dragImage.innerHTML = ' move '+( data.length || data.name ); + dragImage.innerHTML = ' '+self.i18n.move+' '+( data.length || data.name ); document.body.appendChild( dragImage ); setTimeout(function() { dragImage.remove(); diff --git a/ifm.php b/ifm.php index 58c728e..469c3ca 100644 --- a/ifm.php +++ b/ifm.php @@ -557,15 +557,20 @@ f00bar; $i18n["en"] = <<<'f00bar' { "ajax_request": "AJAX Request", + "archivename": "Name of the archive", + "archive_create_sucess": "Archive successfully created.", "cancel": "Cancel", "close": "Close", "copy": "Copy", + "create_archive": "Create archive", "data": "Data", "delete": "Delete", "directoryname": "Directory Name", + "download": "Download", + "edit": "edit", "editor_options": "Editor Options", "error": "Error:", - "extract": "Extract", + "extract": "extract", "extract_filename": "Extract file - ", "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", @@ -596,6 +601,7 @@ f00bar; "github": "Visit the project on GitHub", "group": "Group", "invalid_data": "Invalid data from server", + "invalid_archive_format": "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "last_modified": "Last Modified", "load_config_error": "Could not load configuration", "load_template_error": "Could not load templates", @@ -611,8 +617,8 @@ f00bar; "permission_change_error": "Permissions could not be changed: ", "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", - "refresh": "Refresh", - "rename": "Rename", + "refresh": "refresh", + "rename": "rename", "rename_filename": "Rename file -", "request": "Request", "response": "Response", @@ -633,22 +639,27 @@ f00bar; "username": "username", "word_wrap": "Word Wrap" } + f00bar; $i18n["en"] = json_decode( $i18n["en"], true ); $i18n["de"] = <<<'f00bar' { "ajax_request": "AJAX Request", "archivename": "Name des Archivs", + "archive_create_sucess": "Archive successfully created.", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", + "create_archive": "Archiv erstellen", "data": "Daten", "delete": "Löschen", "directoryname": "Ordner Name", + "download": "Download", + "edit": "Bearbeiten", "editor_options": "Editor Optionen", "error": "Fehler:", - "extract": "Auspacken", - "extract_filename": "Folgende Datei auspacken -", + "extract": "Entpacken", + "extract_filename": "Folgende Datei entpacken -", "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_delete_error": "Datei(en) konnten nicht gelöscht werden", @@ -681,6 +692,7 @@ $i18n["de"] = <<<'f00bar' "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", "invalid_data": "Fehlerhafte Daten vom Server erhalten", + "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", "last_modified": "Zuletzt geändert", "load_config_error": "Konfiguration konnte nicht geladen werden", "load_template_error": "Vorlagen konnten nicht geladen werden", @@ -702,7 +714,7 @@ $i18n["de"] = <<<'f00bar' "request": "Anfrage", "response": "Antwort", "save": "Speichen", - "save_wo_close": "Speichen ohne Schließen", + "save_wo_close": "Speichen ohne schließen", "search": "Suchen", "search_pattern": "Muster", "select_destination": "Zielort auswählen", @@ -719,7 +731,6 @@ $i18n["de"] = <<<'f00bar' "username": "Benutzername", "word_wrap": "Zeilenumbruch" } - f00bar; $i18n["de"] = json_decode( $i18n["de"], true ); @@ -1168,7 +1179,7 @@ function IFM( params ) { */ this.refreshFileTable = function () { var taskid = self.generateGuid(); - self.task_add( { id: taskid, name: "Refresh" } ); + self.task_add( { id: taskid, name: self.i18n.refresh } ); $.ajax({ url: self.api, type: "POST", @@ -1349,7 +1360,7 @@ function IFM( params ) { ], actions: { edit: { - name: "edit", + name: self.i18n.edit, onClick: function( data ) { self.editFile( data.clicked.name ); }, @@ -1359,7 +1370,7 @@ function IFM( params ) { } }, extract: { - name: "extract", + name: self.i18n.extract, onClick: function( data ) { self.showExtractFileDialog( data.clicked.name ); }, @@ -1369,7 +1380,7 @@ function IFM( params ) { } }, rename: { - name: "rename", + name: self.i18n.rename, onClick: function( data ) { self.showRenameFileDialog( data.clicked.name ); }, @@ -1379,9 +1390,9 @@ function IFM( params ) { copymove: { name: function( data ) { if( data.selected.length > 0 ) - return 'copy/move '+data.selected.length+''; + return self.i18n.copy+'/'+self.i18n.move+' '+data.selected.length+''; else - return 'copy/move'; + return self.i18n.copy+'/'+self.i18n.move; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1395,9 +1406,9 @@ function IFM( params ) { download: { name: function( data ) { if( data.selected.length > 0 ) - return 'download '+data.selected.length+''; + return self.i18n.download+' '+data.selected.length+''; else - return 'download'; + return self.i18n.download; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1411,9 +1422,9 @@ function IFM( params ) { createarchive: { name: function( data ) { if( data.selected.length > 0 ) - return 'create archive '+data.selected.length+''; + return self.i18n.create_archive+' '+data.selected.length+''; else - return 'create archive'; + return self.i18n.create_archive; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -1427,9 +1438,9 @@ function IFM( params ) { 'delete': { name: function( data ) { if( data.selected.length > 0 ) - return 'delete '+data.selected.length+''; + return self.i18n.delete+' '+data.selected.length+''; else - return 'delete'; + return self.i18n.delete; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -2063,7 +2074,7 @@ function IFM( params ) { error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); - self.task_add( { id: id, name: "Remote upload: "+filename } ); + self.task_add( { id: id, name: self.i18n.upload_remote+" "+filename } ); }; /** @@ -2192,11 +2203,11 @@ function IFM( params ) { else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { - self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + self.showMessage( self.i18n.invalid_archive_format, "e" ); return; } var id = self.generateGuid(); - self.task_add( { id: id, name: "Create archive "+archivename } ); + self.task_add( { id: id, name: self.i18n.create_archive+" "+archivename } ); $.ajax({ url: self.api, @@ -2211,12 +2222,12 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "Archive successfully created.", "s" ); + self.showMessage( self.i18n.archive_create_success, "s" ); self.refreshFileTable(); } else self.showMessage( data.message, "e" ); }, - error: function() { self.showMessage( "General error occured.", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -2789,7 +2800,7 @@ function IFM( params ) { var dragImage = document.createElement( 'div' ); dragImage.style.display = 'inline'; dragImage.style.padding = '10px'; - dragImage.innerHTML = ' move '+( data.length || data.name ); + dragImage.innerHTML = ' '+self.i18n.move+' '+( data.length || data.name ); document.body.appendChild( dragImage ); setTimeout(function() { dragImage.remove(); diff --git a/src/i18n/de.json b/src/i18n/de.json index a57a2fd..eb222b2 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -1,16 +1,20 @@ { "ajax_request": "AJAX Request", "archivename": "Name des Archivs", + "archive_create_sucess": "Archive successfully created.", "cancel": "Abbrechen", "close": "Schließen", "copy": "Kopieren", + "create_archive": "Archiv erstellen", "data": "Daten", "delete": "Löschen", "directoryname": "Ordner Name", + "download": "Download", + "edit": "Bearbeiten", "editor_options": "Editor Optionen", "error": "Fehler:", - "extract": "Auspacken", - "extract_filename": "Folgende Datei auspacken -", + "extract": "Entpacken", + "extract_filename": "Folgende Datei entpacken -", "file_copy_to": "zu", "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", "file_delete_error": "Datei(en) konnten nicht gelöscht werden", @@ -43,6 +47,7 @@ "github": "Besuche das Projekt auf GitHub", "group": "Gruppe", "invalid_data": "Fehlerhafte Daten vom Server erhalten", + "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", "last_modified": "Zuletzt geändert", "load_config_error": "Konfiguration konnte nicht geladen werden", "load_template_error": "Vorlagen konnten nicht geladen werden", @@ -64,7 +69,7 @@ "request": "Anfrage", "response": "Antwort", "save": "Speichen", - "save_wo_close": "Speichen ohne Schließen", + "save_wo_close": "Speichen ohne schließen", "search": "Suchen", "search_pattern": "Muster", "select_destination": "Zielort auswählen", @@ -80,4 +85,4 @@ "upload_remote_url": "Entfernte URL zum hochladen", "username": "Benutzername", "word_wrap": "Zeilenumbruch" -} +} \ No newline at end of file diff --git a/src/i18n/en.json b/src/i18n/en.json index 1300946..3f4d803 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -1,14 +1,19 @@ { "ajax_request": "AJAX Request", + "archivename": "Name of the archive", + "archive_create_sucess": "Archive successfully created.", "cancel": "Cancel", "close": "Close", "copy": "Copy", + "create_archive": "Create archive", "data": "Data", "delete": "Delete", "directoryname": "Directory Name", + "download": "Download", + "edit": "edit", "editor_options": "Editor Options", "error": "Error:", - "extract": "Extract", + "extract": "extract", "extract_filename": "Extract file - ", "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", @@ -39,6 +44,7 @@ "github": "Visit the project on GitHub", "group": "Group", "invalid_data": "Invalid data from server", + "invalid_archive_format": "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "last_modified": "Last Modified", "load_config_error": "Could not load configuration", "load_template_error": "Could not load templates", @@ -54,8 +60,8 @@ "permission_change_error": "Permissions could not be changed: ", "permission_change_success": "Permissions successfully changed", "permissions": "Permissions", - "refresh": "Refresh", - "rename": "Rename", + "refresh": "refresh", + "rename": "rename", "rename_filename": "Rename file -", "request": "Request", "response": "Response", @@ -75,4 +81,4 @@ "upload_remote_url": "Remote Upload URL", "username": "username", "word_wrap": "Word Wrap" -} \ No newline at end of file +} diff --git a/src/ifm.js b/src/ifm.js index 0bed7aa..4de2aac 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -67,7 +67,7 @@ function IFM( params ) { */ this.refreshFileTable = function () { var taskid = self.generateGuid(); - self.task_add( { id: taskid, name: "Refresh" } ); + self.task_add( { id: taskid, name: self.i18n.refresh } ); $.ajax({ url: self.api, type: "POST", @@ -248,7 +248,7 @@ function IFM( params ) { ], actions: { edit: { - name: "edit", + name: self.i18n.edit, onClick: function( data ) { self.editFile( data.clicked.name ); }, @@ -258,7 +258,7 @@ function IFM( params ) { } }, extract: { - name: "extract", + name: self.i18n.extract, onClick: function( data ) { self.showExtractFileDialog( data.clicked.name ); }, @@ -268,7 +268,7 @@ function IFM( params ) { } }, rename: { - name: "rename", + name: self.i18n.rename, onClick: function( data ) { self.showRenameFileDialog( data.clicked.name ); }, @@ -278,9 +278,9 @@ function IFM( params ) { copymove: { name: function( data ) { if( data.selected.length > 0 ) - return 'copy/move '+data.selected.length+''; + return self.i18n.copy+'/'+self.i18n.move+' '+data.selected.length+''; else - return 'copy/move'; + return self.i18n.copy+'/'+self.i18n.move; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -294,9 +294,9 @@ function IFM( params ) { download: { name: function( data ) { if( data.selected.length > 0 ) - return 'download '+data.selected.length+''; + return self.i18n.download+' '+data.selected.length+''; else - return 'download'; + return self.i18n.download; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -310,9 +310,9 @@ function IFM( params ) { createarchive: { name: function( data ) { if( data.selected.length > 0 ) - return 'create archive '+data.selected.length+''; + return self.i18n.create_archive+' '+data.selected.length+''; else - return 'create archive'; + return self.i18n.create_archive; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -326,9 +326,9 @@ function IFM( params ) { 'delete': { name: function( data ) { if( data.selected.length > 0 ) - return 'delete '+data.selected.length+''; + return self.i18n.delete+' '+data.selected.length+''; else - return 'delete'; + return self.i18n.delete; }, onClick: function( data ) { if( data.selected.length > 0 ) @@ -962,7 +962,7 @@ function IFM( params ) { error: function() { self.showMessage( self.i18n.general_error, "e"); }, complete: function() { self.task_done(id); } }); - self.task_add( { id: id, name: "Remote upload: "+filename } ); + self.task_add( { id: id, name: self.i18n.upload_remote+" "+filename } ); }; /** @@ -1091,11 +1091,11 @@ function IFM( params ) { else if( archivename.substr( -7 ).toLowerCase() == "tar.bz2" ) type = "tar.bz2"; else { - self.showMessage( "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "e" ); + self.showMessage( self.i18n.invalid_archive_format, "e" ); return; } var id = self.generateGuid(); - self.task_add( { id: id, name: "Create archive "+archivename } ); + self.task_add( { id: id, name: self.i18n.create_archive+" "+archivename } ); $.ajax({ url: self.api, @@ -1110,12 +1110,12 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( "Archive successfully created.", "s" ); + self.showMessage( self.i18n.archive_create_success, "s" ); self.refreshFileTable(); } else self.showMessage( data.message, "e" ); }, - error: function() { self.showMessage( "General error occured.", "e" ); }, + error: function() { self.showMessage( self.i18n.general_error, "e" ); }, complete: function() { self.task_done( id ); } }); }; @@ -1688,7 +1688,7 @@ function IFM( params ) { var dragImage = document.createElement( 'div' ); dragImage.style.display = 'inline'; dragImage.style.padding = '10px'; - dragImage.innerHTML = ' move '+( data.length || data.name ); + dragImage.innerHTML = ' '+self.i18n.move+' '+( data.length || data.name ); document.body.appendChild( dragImage ); setTimeout(function() { dragImage.remove(); From 407e8702522ec1b94e0503223ece314615579a24 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Wed, 9 Aug 2017 20:35:43 +0200 Subject: [PATCH 10/19] add build with english language only --- build/libifm.php | 91 ------------------------------------------------ ifm.php | 91 ------------------------------------------------ 2 files changed, 182 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 3eb0669..de83065 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -642,97 +642,6 @@ f00bar; f00bar; $i18n["en"] = json_decode( $i18n["en"], true ); -$i18n["de"] = <<<'f00bar' -{ - "ajax_request": "AJAX Request", - "archivename": "Name des Archivs", - "archive_create_sucess": "Archive successfully created.", - "cancel": "Abbrechen", - "close": "Schließen", - "copy": "Kopieren", - "create_archive": "Archiv erstellen", - "data": "Daten", - "delete": "Löschen", - "directoryname": "Ordner Name", - "download": "Download", - "edit": "Bearbeiten", - "editor_options": "Editor Optionen", - "error": "Fehler:", - "extract": "Entpacken", - "extract_filename": "Folgende Datei entpacken -", - "file_copy_to": "zu", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", - "file_delete_error": "Datei(en) konnten nicht gelöscht werden", - "file_delete_success": "Datei(en) erfolgreich gelöscht", - "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", - "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", - "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", - "file_extract_error": "Datei konnte nicht entpackt werden: ", - "file_extract_success": "Datei erfolgreich entpackt", - "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", - "file_new": "Neue Datei", - "file_rename": "Datei umbenennen", - "file_rename_error": "Datei konnte nicht umbenannt werden: ", - "file_rename_success": "Datei erfogreich umbenannt", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", - "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", - "file_upload_error": "Datei konnte nicht hochgeladen werden: ", - "file_upload_success": "Datei erfolgreich hochgeladen", - "filename": "Dateiname", - "filename_new": "Neuer Dateiname", - "folder_create_error": "Verzeichnis konnte nicht angelegt werden: ", - "folder_create_success": "Verzeichnis erfolgreich angelegt", - "folder_new": "Neue Ordner", - "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums", - "footer": "IFM - verbesserter file manager | ifm.php versteckt |", - "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", - "github": "Besuche das Projekt auf GitHub", - "group": "Gruppe", - "invalid_data": "Fehlerhafte Daten vom Server erhalten", - "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", - "last_modified": "Zuletzt geändert", - "load_config_error": "Konfiguration konnte nicht geladen werden", - "load_template_error": "Vorlagen konnten nicht geladen werden", - "load_text_error": "Texte konnten nicht geladen werden", - "login": "Anmeldung", - "logout": "Abmelden", - "method": "Methode", - "move": "Verschieben", - "options": "Optionen", - "owner": "Besitzer", - "password": "Passwort", - "path_content": "Inhalt von", - "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", - "permission_change_success": "Berechtigungen erfolgreich geändert", - "permissions": "Berechtigungen", - "refresh": "Auffrischen", - "rename": "Umbenennen", - "rename_filename": "Folgende Datei umbenennen -", - "request": "Anfrage", - "response": "Antwort", - "save": "Speichen", - "save_wo_close": "Speichen ohne schließen", - "search": "Suchen", - "search_pattern": "Muster", - "select_destination": "Zielort auswählen", - "size": "Größe", - "soft_tabs": "Leichte Tabulatoren", - "tab_size": "Tabulatoren Größe", - "tasks": "Aufgaben", - "toggle_nav": "Navigation umschalten", - "upload": "Hochladen", - "upload_drop": "Dateien zum hochladen hier hinziehen", - "upload_file": "Datei hochladen", - "upload_remote": "Hochladen von ausserhalb", - "upload_remote_url": "Entfernte URL zum hochladen", - "username": "Benutzername", - "word_wrap": "Zeilenumbruch" -} -f00bar; -$i18n["de"] = json_decode( $i18n["de"], true ); $this->i18n = $i18n; } diff --git a/ifm.php b/ifm.php index 469c3ca..9bc1978 100644 --- a/ifm.php +++ b/ifm.php @@ -642,97 +642,6 @@ f00bar; f00bar; $i18n["en"] = json_decode( $i18n["en"], true ); -$i18n["de"] = <<<'f00bar' -{ - "ajax_request": "AJAX Request", - "archivename": "Name des Archivs", - "archive_create_sucess": "Archive successfully created.", - "cancel": "Abbrechen", - "close": "Schließen", - "copy": "Kopieren", - "create_archive": "Archiv erstellen", - "data": "Daten", - "delete": "Löschen", - "directoryname": "Ordner Name", - "download": "Download", - "edit": "Bearbeiten", - "editor_options": "Editor Optionen", - "error": "Fehler:", - "extract": "Entpacken", - "extract_filename": "Folgende Datei entpacken -", - "file_copy_to": "zu", - "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", - "file_delete_error": "Datei(en) konnten nicht gelöscht werden", - "file_delete_success": "Datei(en) erfolgreich gelöscht", - "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", - "file_edit_success": "Datei erfolgreich geändert / angelegt.", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden:", - "file_new": "Neue Datei", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden:", - "file_extract_error": "Datei konnte nicht entpackt werden: ", - "file_extract_success": "Datei erfolgreich entpackt", - "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", - "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", - "file_new": "Neue Datei", - "file_rename": "Datei umbenennen", - "file_rename_error": "Datei konnte nicht umbenannt werden: ", - "file_rename_success": "Datei erfogreich umbenannt", - "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", - "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", - "file_upload_error": "Datei konnte nicht hochgeladen werden: ", - "file_upload_success": "Datei erfolgreich hochgeladen", - "filename": "Dateiname", - "filename_new": "Neuer Dateiname", - "folder_create_error": "Verzeichnis konnte nicht angelegt werden: ", - "folder_create_success": "Verzeichnis erfolgreich angelegt", - "folder_new": "Neue Ordner", - "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums", - "footer": "IFM - verbesserter file manager | ifm.php versteckt |", - "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", - "github": "Besuche das Projekt auf GitHub", - "group": "Gruppe", - "invalid_data": "Fehlerhafte Daten vom Server erhalten", - "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", - "last_modified": "Zuletzt geändert", - "load_config_error": "Konfiguration konnte nicht geladen werden", - "load_template_error": "Vorlagen konnten nicht geladen werden", - "load_text_error": "Texte konnten nicht geladen werden", - "login": "Anmeldung", - "logout": "Abmelden", - "method": "Methode", - "move": "Verschieben", - "options": "Optionen", - "owner": "Besitzer", - "password": "Passwort", - "path_content": "Inhalt von", - "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", - "permission_change_success": "Berechtigungen erfolgreich geändert", - "permissions": "Berechtigungen", - "refresh": "Auffrischen", - "rename": "Umbenennen", - "rename_filename": "Folgende Datei umbenennen -", - "request": "Anfrage", - "response": "Antwort", - "save": "Speichen", - "save_wo_close": "Speichen ohne schließen", - "search": "Suchen", - "search_pattern": "Muster", - "select_destination": "Zielort auswählen", - "size": "Größe", - "soft_tabs": "Leichte Tabulatoren", - "tab_size": "Tabulatoren Größe", - "tasks": "Aufgaben", - "toggle_nav": "Navigation umschalten", - "upload": "Hochladen", - "upload_drop": "Dateien zum hochladen hier hinziehen", - "upload_file": "Datei hochladen", - "upload_remote": "Hochladen von ausserhalb", - "upload_remote_url": "Entfernte URL zum hochladen", - "username": "Benutzername", - "word_wrap": "Zeilenumbruch" -} -f00bar; -$i18n["de"] = json_decode( $i18n["de"], true ); $this->i18n = $i18n; } From 69239609a0f5233051699469d89aacd029b08f1c Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Sat, 19 Aug 2017 01:30:40 +0200 Subject: [PATCH 11/19] Fixed interfering drag and drop functions for files and filetable items. Added some translations. Broke the encoding of the translations files. This commit is a mess. --- build/libifm.php | 398 +++++++++++++++++++++++++++++++---------------- ifm.php | 398 +++++++++++++++++++++++++++++++---------------- src/i18n/de.json | 47 ++++-- src/i18n/en.json | 51 +++--- src/ifm.js | 46 ++++-- src/main.php | 186 +++++++++++----------- 6 files changed, 724 insertions(+), 402 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index de83065..511597d 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -559,66 +559,77 @@ f00bar; "ajax_request": "AJAX Request", "archivename": "Name of the archive", "archive_create_sucess": "Archive successfully created.", + "archive_create_error": "Could not create archive.", + "archive_invalid_format": "Invalid archive format given.", "cancel": "Cancel", "close": "Close", "copy": "Copy", + "copy_error": "The following files could not be copied:", + "copy_success": "File(s) copied successfully.", "create_archive": "Create archive", "data": "Data", "delete": "Delete", "directoryname": "Directory Name", "download": "Download", - "edit": "edit", + "edit": "Edit", "editor_options": "Editor Options", "error": "Error:", "extract": "extract", + "extract_error": "Could not extract archive.", "extract_filename": "Extract file - ", + "extract_success": "Archive extracted successfully.", "file_copy_to": "to", "file_delete_confirm": "Do you really want to delete the following file -", - "file_delete_error": "File(s) could not be deleted", - "file_delete_success": "File(s) successfully deleted", - "file_display_error": "This file can not be displayed or edited", - "file_edit_success": "File successfully edited / created.", + "file_delete_error": "File(s) could not be deleted.", + "file_delete_success": "File(s) successfully deleted.", + "file_display_error": "This file can not be displayed or edited.", "file_extract_error": "File could not be extracted: ", - "file_extract_success": "File successfully extracted", - "file_load_error": "The content of this file cannot be fetched", - "file_multi_delete_confirm": "Do you really want to delete these files -", + "file_extract_success": "File successfully extracted.", "file_new": "New File", + "file_open_error": "Could not open the file.", "file_rename": "Rename File", "file_rename_error": "File could not be renamed: ", - "file_rename_success": "File successfully renamed", + "file_rename_success": "File successfully renamed.", "file_save_confirm": "Do you want to save the following file -", "file_save_error": "File could not be edited or created: ", + "file_save_success": "File successfully edited / created.", "file_upload_error": "File could not be uploaded: ", - "file_upload_success": "File successfully uploaded", + "file_upload_success": "File successfully uploaded.", "filename": "Filename", "filename_new": "New Filename", "folder_create_error": "Directory could not be created: ", - "folder_create_success": "Directory sucessfully created", + "folder_create_success": "Directory sucessfully created.", "folder_new": "New Folder", - "folder_tree_load_error": "Error while fetching the folder tree", + "folder_tree_load_error": "Error while fetching the folder tree.", "footer": "IFM - improved file manager | ifm.php hidden |", - "general_error": "General error occured: No or broken response", + "general_error": "General error occured: No or broken response.", "github": "Visit the project on GitHub", "group": "Group", - "invalid_data": "Invalid data from server", + "invalid_data": "Invalid data from server.", + "invalid_dir": "Invalid directory given.", + "invalid_params": "Invalid parameter given.", "invalid_archive_format": "Invalid archive format given. Use zip, tar, tar.gz or tar.bz2.", "last_modified": "Last Modified", - "load_config_error": "Could not load configuration", - "load_template_error": "Could not load templates", - "load_text_error": "Could not load texts", + "load_config_error": "Could not load configuration.", + "load_template_error": "Could not load templates.", + "load_text_error": "Could not load texts.", "login": "Login", "logout": "Log Off", "method": "Method", "move": "Move", + "move_error": "The following files could not be moved:", + "move_success": "File(s) successfully moved.", + "nopermissions": "You don't have the permission to do that.", "options": "Options", "owner": "Owner", "password": "Password", "path_content": "Content of", + "pattern_error_slashes": "Pattern must not contain slashes.", "permission_change_error": "Permissions could not be changed: ", - "permission_change_success": "Permissions successfully changed", + "permission_change_success": "Permissions successfully changed.", "permissions": "Permissions", - "refresh": "refresh", - "rename": "rename", + "refresh": "Refresh", + "rename": "Rename", "rename_filename": "Rename file -", "request": "Request", "response": "Response", @@ -642,8 +653,128 @@ f00bar; f00bar; $i18n["en"] = json_decode( $i18n["en"], true ); +$i18n["de"] = <<<'f00bar' +{ + "ajax_request": "AJAX Request", + "archivename": "Name des Archivs", + "archive_create_sucess": "Das Archiv wurde erfolgreich erstellt.", + "archive_create_error": "Das Archiv konnte nicht erstellt werden.", + "archive_invalid_format": "Ungültiges Archivformat angegeben.", + "cancel": "Abbrechen", + "close": "Schließen", + "copy": "Kopieren", + "copy_error": "Folgende Dateien konnten nicht kopiert werden:", + "copy_success": "Datei(en) erfolgreich kopiert.", + "create_archive": "Archiv erstellen", + "data": "Daten", + "delete": "Löschen", + "directoryname": "Ordner Name", + "download": "Download", + "edit": "Bearbeiten", + "editor_options": "Editor Optionen", + "error": "Fehler:", + "extract": "Entpacken", + "extract_error": "Das Archiv konnte nicht entpackt werden.", + "extract_filename": "Folgende Datei entpacken -", + "extract_success": "Das Archiv wurde erfolgreich entpackt.", + "file_copy_to": "zu", + "file_delete_confirm": "Soll die folgende Datei wirklich gelöscht werden:", + "file_delete_error": "Folgende Dateien konnten nicht gelöscht werden:", + "file_delete_success": "Datei(en) erfolgreich gelöscht", + "file_display_error": "Die Datei kann nicht angezeigt oder geändert werden", + "file_extract_error": "Datei konnte nicht entpackt werden: ", + "file_extract_success": "Datei erfolgreich entpackt", + "file_new": "Neue Datei", + "file_open_error": "Die Datei konnte nicht geöffnet werden", + "file_load_error": "Der Inhalt der Datei konnte nicht geladen werden", + "file_multi_delete_confirm": "Sollen diese Dateien wirklich gelöscht werden -", + "file_new": "Neue Datei", + "file_no_permission": "Sie haben keine Berechtigung diese Datei zu erstellen/bearbeiten.", + "file_not_found": "Die Datei wurde nicht gefunden, oder kann nicht geoeffnet werden.", + "file_rename": "Datei umbenennen", + "file_rename_error": "Datei konnte nicht umbenannt werden: ", + "file_rename_success": "Datei erfogreich umbenannt.", + "file_save_error": "Datei konnte nicht gespeichert werden.", + "file_save_success": "Datei erfolgreich gespeichert.", + "file_save_confirm": "Soll diese Datei wirklich gelöscht werden -", + "file_save_confirm": "Soll diese Datei wirklich gespeichert werden -", + "file_save_error": "Datei konnte nicht geändert oder angelegt werden: ", + "file_upload_error": "Datei konnte nicht hochgeladen werden: ", + "file_upload_success": "Datei erfolgreich hochgeladen", + "filename": "Dateiname", + "filename_new": "Neuer Dateiname", + "filename_slashes": "Der Dateiname darf keine Schrägstriche enthalten.", + "folder_create_error": "Verzeichnis konnte nicht angelegt werden.", + "folder_create_success": "Verzeichnis erfolgreich angelegt.", + "folder_new": "Neue Ordner", + "folder_not_found": "Das Verzeichnis wurde nicht gefunden.", + "folder_tree_load_error": "Fehler bei Laden des Verzeichnisbaums.", + "footer": "IFM - verbesserter file manager | ifm.php versteckt |", + "general_error": "Genereller Fehler aufgetreten: Keine oder unvollständige Antwort", + "github": "Besuche das Projekt auf GitHub", + "group": "Gruppe", + "invalid_action": "Fehlerhafte Aktion übergeben.", + "invalid_archive_format": "Ungültiges Archiv-Format. Möglich sind zip, tar, tar.gz oder tar.bz2.", + "invalid_data": "Fehlerhafte Daten vom Server erhalten", + "invalid_dir": "Ungültiges Verzeichnis übergegeben.", + "invalid_filename": "Ungültiger Dateiname übergegeben.", + "invalid_params": "Ungültige Parameter übergegeben.", + "invalid_url": "Ungültige URL übergegeben.", + "json_encode_error": "Konnte die Antwort nicht als JSON formatieren:", + "last_modified": "Zuletzt geändert", + "load_config_error": "Konfiguration konnte nicht geladen werden", + "load_template_error": "Vorlagen konnten nicht geladen werden", + "load_text_error": "Texte konnten nicht geladen werden", + "login": "Anmeldung", + "login_failed": "Login fehlgeschlagen", + "logout": "Abmelden", + "method": "Methode", + "move": "Verschieben", + "move_error": "Folgende Dateien konnten nicht verschoben werden:", + "move_success": "Datei(en) erfolgreich verschoben.", + "nopermissions": "Sie haben nicht die nötige Berechtigung dafür.", + "options": "Optionen", + "owner": "Besitzer", + "password": "Passwort", + "path_content": "Inhalt von", + "pattern_error_slashes": "Das Muster darf keine Slashes enthalten.", + "permission_change_error": "Berechtigungen konnten nicht geändert werden: ", + "permission_change_success": "Berechtigungen erfolgreich geändert", + "permission_parse_error": "Berechtigungen konnten nicht identifiziert werden.", + "permissions": "Berechtigungen", + "refresh": "Auffrischen", + "rename": "Umbenennen", + "rename_filename": "Folgende Datei umbenennen -", + "request": "Anfrage", + "response": "Antwort", + "save": "Speichen", + "save_wo_close": "Speichen ohne schließen", + "search": "Suchen", + "search_pattern": "Muster", + "select_destination": "Zielort auswählen", + "size": "Größe", + "soft_tabs": "Leichte Tabulatoren", + "tab_size": "Tabulatoren Größe", + "tasks": "Aufgaben", + "toggle_nav": "Navigation umschalten", + "upload": "Hochladen", + "upload_drop": "Dateien zum hochladen hier hinziehen", + "upload_file": "Datei hochladen", + "upload_remote": "Hochladen von ausserhalb", + "upload_remote_url": "Entfernte URL zum hochladen", + "username": "Benutzername", + "word_wrap": "Zeilenumbruch" +} + +f00bar; +$i18n["de"] = json_decode( $i18n["de"], true ); $this->i18n = $i18n; + + if( in_array( $this->config['language'], array_keys( $this->i18n ) ) ) + $this->l = $this->i18n[$this->config['language']]; + else + $this->l = $this->i18n[0]; } /** @@ -1218,7 +1349,7 @@ function IFM( params ) { } else if( e.target.parentElement.name && e.target.parentElement.name.substring(0, 3) == "do-" ) { e.stopPropagation(); e.preventDefault(); - var item = self.fileCache.find( x => x.guid === e.target.parentElement.dataset.id ); + var item = self.fileCache.find( function( x ) { if( x.guid === e.target.parentElement.dataset.id ) return x; } ); switch( e.target.parentElement.name.substr( 3 ) ) { case "rename": self.showRenameFileDialog( item.name ); @@ -1483,7 +1614,7 @@ function IFM( params ) { dataType: "json", success: function( data ) { if( data.status == "OK" ) { - self.showMessage( self.i18n.file_edit_success, "s" ); + self.showMessage( self.i18n.file_save_success, "s" ); self.refreshFileTable(); } else self.showMessage( self.i18n.file_save_error + data.message, "e" ); }, @@ -2064,11 +2195,16 @@ function IFM( params ) { }, dataType: "json", success: function( data ) { - data.forEach( function(e) { - e.folder = e.name.substr( 0, e.name.lastIndexOf( '/' ) ); - e.linkname = e.name.substr( e.name.lastIndexOf( '/' ) + 1 ); - }); - updateResults( data ); + if( data.status == 'ERROR' ) { + self.hideModal(); + self.showMessage( data.message, "e" ); + } else { + data.forEach( function(e) { + e.folder = e.name.substr( 0, e.name.lastIndexOf( '/' ) ); + e.linkname = e.name.substr( e.name.lastIndexOf( '/' ) + 1 ); + }); + updateResults( data ); + } } }); } @@ -2660,8 +2796,8 @@ function IFM( params ) { if( self.config.ajaxrequest ) document.getElementById( 'buttonAjaxRequest' ).onclick = function() { self.showAjaxRequestDialog(); }; if( self.config.upload ) - document.addEventListener( 'drag', function( e ) { - if( e.dataTransfer.files.length > 0 ) { + document.addEventListener( 'dragover', function( e ) { + if( Array.prototype.indexOf.call(e.dataTransfer.types, "Files") != -1 ) { e.preventDefault(); e.stopPropagation(); var div = document.getElementById( 'filedropoverlay' ); @@ -2688,11 +2824,16 @@ function IFM( params ) { e.target.parentElement.style.display = 'none'; } }; + } else { + var div = document.getElementById( 'filedropoverlay' ); + if( div.style.display == 'block' ) + div.stye.display == 'none'; } }); // drag and drop of filetable items if( self.config.copymove ) { + var isFile = function(e) { return Array.prototype.indexOf.call(e.dataTransfer.types, "Files") != -1 }; document.addEventListener( 'dragstart', function( e ) { var selectedItems = document.getElementsByClassName( 'selectedItem' ); var data; @@ -2701,8 +2842,8 @@ function IFM( params ) { x => self.inArray( x.guid, [].slice.call( selectedItems ).map( function( e ) { return e.dataset.id; } ) - ) - ); + ) + ); else data = self.fileCache.find( x => x.guid === e.target.dataset.id ); e.dataTransfer.setData( 'text/plain', JSON.stringify( data ) ); @@ -2716,21 +2857,23 @@ function IFM( params ) { }); e.dataTransfer.setDragImage( dragImage, 0, 0 ); }); - document.addEventListener( 'dragover', function( e ) { e.preventDefault(); } ); + document.addEventListener( 'dragover', function( e ) { if( ! isFile( e ) && e.target.parentElement.classList.contains( 'isDir' ) ) e.preventDefault(); } ); document.addEventListener( 'dragenter', function( e ) { - if( e.target.parentElement.classList.contains( 'isDir' ) ) + if( ! isFile( e ) && e.target.tagName == "TD" && e.target.parentElement.classList.contains( 'isDir' ) ) e.target.parentElement.classList.add( 'highlightedItem' ); }); document.addEventListener( 'dragleave', function( e ) { - if( e.target.parentElement.classList.contains( 'isDir' ) ) + if( ! isFile( e ) && e.target.tagName == "TD" && e.target.parentElement.classList.contains( 'isDir' ) ) e.target.parentElement.classList.remove( 'highlightedItem' ); }); document.addEventListener( 'drop', function( e ) { - if( e.target.parentElement.classList.contains( 'isDir' ) ) { + if( ! isFile( e ) && e.target.tagName == "TD" && e.target.parentElement.classList.contains( 'isDir' ) ) { + e.preventDefault(); + e.stopPropagation(); try { var source = JSON.parse( e.dataTransfer.getData( 'text' ) ); - console.log( "source:" ); - console.log( source ); + self.log( "source:" ); + self.log( source ); var destination = self.fileCache.find( x => x.guid === e.target.firstElementChild.id ); if( ! Array.isArray( source ) ) source = [source]; @@ -2813,12 +2956,7 @@ function IFM( params ) { } elseif( $_REQUEST["api"] == "getTemplates" ) { $this->jsonResponse( $this->templates ); } elseif( $_REQUEST["api"] == "getI18N" ) { - if( isset( $this->i18n[$this->config['language']] ) ) - $this->jsonResponse( $this->i18n[$this->config['language']] ); - else { - foreach( $this->i18n as $lang ) break; - $this->jsonResponse( $lang ); - } + $this->jsonResponse( $this->l ); } elseif( $_REQUEST["api"] == "logout" ) { unset( $_SESSION ); session_destroy(); @@ -2875,6 +3013,7 @@ function IFM( params ) { api functions */ + private function getFiles( $dir ) { $this->chDirIfNecessary( $dir ); @@ -2988,14 +3127,14 @@ function IFM( params ) { private function searchItems( $d ) { $this->chDirIfNecessary( $d['dir'] ); if( strpos( $d['pattern'], '/' ) !== false ) { - echo json_decode( array( "status" => "ERROR", "message" => "Pattern must not contain slashes" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['pattern_error_slashes'] ) ); exit( 1 ); } try { $results = $this->searchItemsRecursive( $d['pattern'] ); $this->jsonResponse( $results ); } catch( Exception $e ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error'] . " " . $e->getMessage() ) ); } } @@ -3051,20 +3190,20 @@ function IFM( params ) { private function copyMove( $d ) { if( $this->config['copymove'] != 1 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); exit( 1 ); } $this->chDirIfNecessary( $d['dir'] ); if( ! isset( $d['destination'] ) || ! $this->isPathValid( realpath( $d['destination'] ) ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid destination directory given." ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) ); exit( 1 ); } if( ! is_array( $d['filenames'] ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid parameters given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_params'] ) ); exit( 1 ); } if( ! in_array( $d['action'], array( 'copy', 'move' ) ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid action given" ) ); + $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_action'] ) ); exit( 1 ); } $err = array(); $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors @@ -3086,11 +3225,11 @@ function IFM( params ) { } $action = ( $d['action'] == "copy" ? "copied" : "moved" ); if( empty( $err ) ) { - $this->jsonResponse( array( "status" => "OK", "message" => "File(s) $action successfully", "errflag" => "1" ) ); + $this->jsonResponse( array( "status" => "OK", "message" => ( $d['action'] == "copy" ? $this->l['copy_success'] : $this->l['move_success'] ), "errflag" => "1" ) ); } else { - $errmsg = "The following files could not be copied/moved: