Merge pull request #3 from cryol/2.6.1

2.6.1
This commit is contained in:
Anton Baranov 2020-06-14 03:26:30 +03:00 committed by GitHub
commit f5a1261ddc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 690 additions and 1788 deletions

14
.gitattributes vendored
View File

@ -1,9 +1,9 @@
ifm.php -diff
ifm.min.php -diff
build/* -diff
dist/ifm.php -diff
dist/ifm.min.php -diff
dist/* -diff
src/includes/ace.js -diff
src export-ignore
compiler.php export-ignore
.gitignore export-ignore
.gitattributes export-ignore
src export-ignore
compiler.php export-ignore
.gitignore export-ignore
.gitattributes export-ignore

3
.gitignore vendored
View File

@ -2,4 +2,5 @@
*.zip
misc
src/includes/ace/*
sftp-config.json
sftp-config.json
dist/*

View File

@ -10,20 +10,21 @@ chdir( realpath( dirname( __FILE__ ) ) );
// output files and common attrs
define( "IFM_CDN", true );
define( "IFM_VERSION", "v2.5.2" );
define( "IFM_STANDALONE", "dist/ifm.php" );
define( "IFM_STANDALONE_GZ", "dist/ifm.min.php" );
define( "IFM_LIB", "dist/libifm.php" );
define( "IFM_VERSION", "<a href='https://github.com/misterunknown/ifm/tree/cryol-2.6.1' target=_blank>v2.6.1</a>" );
define( "IFM_RELEASE_DIR", "dist/");
define( "IFM_STANDALONE", "ifm.php" );
define( "IFM_STANDALONE_GZ", "ifm.min.php" );
define( "IFM_LIB", "libifm.php" );
if( IFM_CDN ){
$main_src = "src/main.cdn.php";
$IFM_ASSETS = "src/assets.cdn.part";
} else {
$main_src = "src/main.php";
$IFM_ASSETS = "src/assets.part";
}
// php source files
$IFM_SRC_PHP = array(
0 => $main_src,
0 => "src/main.php",
1 => "src/ifmarchive.php",
2 => "src/htpasswd.php"
);
@ -57,6 +58,7 @@ foreach( $IFM_SRC_PHP as $phpfile ) {
}
$compiled = join( $compiled );
$compiled = str_replace( "IFM_ASSETS", file_get_contents( $IFM_ASSETS ), $compiled );
/**
* Process file includes
*/
@ -92,13 +94,13 @@ foreach( $includes as $var )
$compiled = str_replace( 'IFM_VERSION', IFM_VERSION, $compiled );
if (!is_dir('dist/')){
mkdir('dist');
if (!is_dir(IFM_RELEASE_DIR)){
mkdir(IFM_RELEASE_DIR);
}
// build standalone ifm
file_put_contents( IFM_STANDALONE, $compiled );
file_put_contents( IFM_STANDALONE, '
file_put_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : 'simple.') . IFM_STANDALONE, $compiled );
file_put_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : 'simple.') . IFM_STANDALONE, '
/**
* start IFM
*/
@ -108,9 +110,9 @@ $ifm->run();
// build compressed ifm
file_put_contents(
IFM_STANDALONE_GZ,
IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : 'simple.') . IFM_STANDALONE_GZ,
'<?php eval( gzdecode( file_get_contents( __FILE__, false, null, 85 ) ) ); exit(0); ?>'
. gzencode( file_get_contents( "./dist/ifm.php", false, null, 5 ) )
. gzencode( file_get_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : 'simple.') .IFM_STANDALONE, false, null, 5 ) )
);
// build lib
file_put_contents( IFM_LIB, $compiled );
file_put_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : 'simple.') . IFM_LIB, $compiled );

0
docker-startup.sh → docker/docker-startup.sh Executable file → Normal file
View File

32
src/assets.cdn.part Normal file
View File

@ -0,0 +1,32 @@
public function getCSS() {
print '
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.20/datatables.min.css"/>
<style type="text/css">';?> @@@file:src/includes/bootstrap-treeview.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/fontello-embedded.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/animation.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/style.css@@@ <?php print '</style>
';
}
public function getJS() {
print '
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.20/datatables.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.8/ace.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.2/mustache.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mouse0270-bootstrap-notify/3.1.7/bootstrap-notify.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.6/index.min.js"></script>
';
echo <<<'f00bar'
<script>
@@@file:src/includes/bootstrap-treeview.min.js@@@
@@@file:src/includes/BootstrapMenu.min.js@@@
@@@file:src/ifm.js@@@
</script>
f00bar;
}

31
src/assets.part Normal file
View File

@ -0,0 +1,31 @@
public function getCSS() {
print '
<style type="text/css">';?> @@@file:src/includes/bootstrap.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/bootstrap-treeview.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/datatables.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/fontello-embedded.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/animation.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/style.css@@@ <?php print '</style>
';
}
public function getJS() {
echo <<<'f00bar'
<script>
@@@file:src/includes/jquery.min.js@@@
@@@file:src/includes/jquery.ui.min.js@@@
@@@file:src/includes/popper.min.js@@@
@@@file:src/includes/bootstrap.min.js@@@
@@@file:src/includes/bootstrap-notify.min.js@@@
@@@file:src/includes/bootstrap-treeview.min.js@@@
@@@file:src/includes/datatables.min.js@@@
@@@file:src/includes/lodash.min.js@@@
@@@file:src/includes/classnames.js@@@
@@@file:src/includes/BootstrapMenu.min.js@@@
@@@file:src/includes/mustache.min.js@@@
@@@file:src/includes/ace.js@@@
@@@acedir:src/includes/ace@@@
@@@file:src/ifm.js@@@
</script>
f00bar;
}

View File

@ -18,7 +18,7 @@
"edit": "Edit",
"editor_options": "Editor Options",
"error": "Error:",
"extract": "extract",
"extract": "Extract",
"extract_error": "Could not extract archive.",
"extract_filename": "Extract file - ",
"extract_success": "Archive extracted successfully.",
@ -105,6 +105,6 @@
"upload_file": "Upload File",
"upload_remote": "Remote Upload",
"upload_remote_url": "Remote Upload URL",
"username": "username",
"username": "Username",
"word_wrap": "Word Wrap"
}

View File

@ -18,7 +18,7 @@
"edit": "Editer",
"editor_options": "Options de l'éditeur",
"error": "Erreur:",
"extract": "extraire",
"extract": "Extraire",
"extract_error": "Echec lors de l'extraction de l'archive.",
"extract_filename": "Extraire le fichier - ",
"extract_success": "Archive extraite avec succès.",
@ -104,6 +104,6 @@
"upload_file": "Envoyer fichier",
"upload_remote": "Envoi distant",
"upload_remote_url": "URL pour l'envoi distant",
"username": "nom d'utilisateur",
"username": "Nom d'utilisateur",
"word_wrap": "Revenir à la ligne"
}

View File

@ -18,7 +18,7 @@
"edit": "Editar",
"editor_options": "Opções do Editor",
"error": "Erro:",
"extract": "extrair",
"extract": "Extrair",
"extract_error": "Não foi possível extrair o arquivo.",
"extract_filename": "Extrair arquivo - ",
"extract_success": "Arquivo extraído com sucesso.",
@ -104,6 +104,6 @@
"upload_file": "Enviar Arquivo",
"upload_remote": "Envio Remoto",
"upload_remote_url": "URL para Envio Remoto",
"username": "nome de usuário",
"username": "Nome de usuário",
"word_wrap": "Quebra de Linha"
}

View File

@ -18,7 +18,7 @@
"edit": "Редактировать",
"editor_options": "Параметры редактора",
"error": "Ошибка:",
"extract": "извлечь",
"extract": "Извлечь",
"extract_error": "Не удалось извлечь архив.",
"extract_filename": "Извлечь файл - ",
"extract_success": "Архив извлечен успешно.",
@ -104,6 +104,6 @@
"upload_file": "Загрузить файла",
"upload_remote": "Удаленная загрузка",
"upload_remote_url": "Удаленная загрузка по URL",
"username": "пользователь",
"username": "Имя пользователя",
"word_wrap": "Перенос строк"
}

View File

@ -129,7 +129,7 @@ function IFM(params) {
}
item.rowclasses = "isDir";
} else {
if( self.config.download && self.config.zipnload ) {
if( self.config.download ) {
item.download.action = "download";
item.download.icon = "icon icon-download";
}
@ -166,7 +166,7 @@ function IFM(params) {
}
}
item.download.link = self.api+"?api="+item.download.action+"&dir="+self.hrefEncode(self.currentDir)+"&filename="+self.hrefEncode(item.download.name);
if( self.config.isDocroot )
if( self.config.isDocroot && !self.config.forceproxy )
item.link = self.hrefEncode( self.pathCombine( window.location.path, self.currentDir, item.name ) );
else if (self.config.download && self.config.zipnload) {
if (self.config.root_public_url) {
@ -480,11 +480,11 @@ function IFM(params) {
title: self.i18n.options,
content: function() {
// see https://github.com/twbs/bootstrap/issues/12571
var ihatethisfuckingpopoverworkaround = $('#editoroptions').data('bs.popover');
ihatethisfuckingpopoverworkaround.$tip.find( '.popover-content' ).empty();
// var ihatethisfuckingpopoverworkaround = $('#editoroptions').data('bs.popover');
// $(ihatethisfuckingpopoverworkaround.tip).find( '.popover-body' ).empty();
var aceSession = self.editor.getSession();
var content = self.getNodesFromString(
var content = self.getNodeFromString(
Mustache.render(
self.templates.file_editoroptions,
{
@ -499,28 +499,33 @@ function IFM(params) {
}
)
);
content.forEach( function( el ) {
if( el.id == "editor-wordwrap" )
el.addEventListener( 'change', function( e ) {
self.editor.setOption( 'wrap', e.srcElement.checked );
});
else if( el.id == "editor-softtabs" )
el.addEventListener( 'change', function( e ) {
self.editor.setOption( 'useSoftTabs', e.srcElement.checked );
});
else if( el.lastChild && el.lastChild.id == "editor-tabsize" )
el.lastChild.addEventListener( 'keydown', function( e ) {
if( e.key == 'Enter' ) {
e.preventDefault();
self.editor.setOption( 'tabSize', e.srcElement.value );
}
});
else if( el.id == "editor-syntax" )
el.addEventListener( 'change', function( e ) {
self.editor.getSession().setMode( e.target.value );
});
});
if( el = content.querySelector("#editor-wordwrap" )) {
el.addEventListener( 'change', function( e ) {
aceSession.setOption( 'wrap', e.srcElement.checked );
});
}
if( el = content.querySelector("#editor-softtabs" ))
el.addEventListener( 'change', function( e ) {
aceSession.setOption( 'useSoftTabs', e.srcElement.checked );
});
if( el = content.querySelector("#editor-tabsize" )) {
console.log("Found tabSize");
el.addEventListener( 'keydown', function( e ) {
console.log("Got keydown");
console.log("Set tabsize to "+e.srcElement.value);
if( e.key == 'Enter' ) {
console.log("Saw ENTER key");
e.preventDefault();
aceSession.setOption( 'tabSize', e.srcElement.value );
}
});
}
if( el = content.querySelector("#editor-syntax" ))
el.addEventListener( 'change', function( e ) {
aceSession.getSession().setMode( e.target.value );
});
return content;
}
});
@ -1131,7 +1136,7 @@ function IFM(params) {
searchresults.tBodies[0].addEventListener( 'click', function( e ) {
if( e.target.classList.contains( 'searchitem' ) || e.target.parentElement.classList.contains( 'searchitem' ) ) {
e.preventDefault();
self.changeDirectory( self.pathCombine( self.search.data.currentDir, e.target.dataset.folder || e.target.parentElement.dataset.foldera ), { absolute: true } );
self.changeDirectory( self.pathCombine( self.search.data.currentDir, e.target.dataset.folder || e.target.parentElement.dataset.folder ), { absolute: true });
self.hideModal();
}
});
@ -1329,7 +1334,7 @@ function IFM(params) {
this.formatDate = function( timestamp ) {
var d = new Date( timestamp * 1000 );
return d.toLocaleString();
return d.toLocaleString(self.config.dateLocale);
};
this.getClipboardLink = function( relpath ) {
@ -1584,8 +1589,10 @@ function IFM(params) {
// global key events
switch( e.key ) {
case '/':
e.preventDefault();
self.showSearchDialog();
if (self.config.search) {
e.preventDefault();
self.showSearchDialog();
}
break;
case 'g':
e.preventDefault();
@ -1593,9 +1600,10 @@ function IFM(params) {
return;
break;
case 'r':
e.preventDefault();
self.refreshFileTable();
return;
if (self.config.showrefresh) {
e.preventDefault();
self.refreshFileTable();
}
break;
case 'u':
if( self.config.upload ) {
@ -1822,8 +1830,12 @@ function IFM(params) {
});
// bind static buttons
document.getElementById( 'refresh' ).onclick = function() { self.refreshFileTable(); };
document.getElementById( 'search' ).onclick = function() { self.showSearchDialog(); };
if (el_r = document.getElementById('refresh'))
el_r.onclick = function() { self.refreshFileTable(); };
if (el_s = document.getElementById('search'))
el_s.onclick = function() { self.showSearchDialog(); };
//document.getElementById( 'refresh' ).onclick = function() { self.refreshFileTable(); };
//document.getElementById( 'search' ).onclick = function() { self.showSearchDialog(); };
if( self.config.createfile )
document.getElementById( 'createFile' ).onclick = function() { self.showFileDialog(); };
if( self.config.createdir )

View File

@ -23,44 +23,53 @@ class IFMArchive {
/**
* Add a folder to an archive
*/
private static function addFolder( &$archive, $folder, $offset=0 ) {
if( $offset == 0 )
$offset = strlen( dirname( $folder ) ) + 1;
$archive->addEmptyDir( substr( $folder, $offset ) );
$handle = opendir( $folder );
while( false !== $f = readdir( $handle ) ) {
if( $f != '.' && $f != '..' ) {
private static function addFolder(&$archive, $folder, $offset=0, $exclude_callback=null) {
if ($offset == 0)
$offset = strlen(dirname($folder)) + 1;
$archive->addEmptyDir(substr($folder, $offset));
$handle = opendir($folder);
while (false !== $f = readdir($handle)) {
if ($f != '.' && $f != '..') {
$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 );
if (file_exists($filePath) && is_readable($filePath))
if (is_file($filePath))
if (!is_callable($exclude_callback) || $exclude_callback($f))
$archive->addFile( $filePath, substr( $filePath, $offset ) );
elseif (is_dir($filePath))
if (is_callable($exclude_callback))
self::addFolder($archive, $filePath, $offset, $exclude_callback);
else
self::addFolder($archive, $filePath, $offset);
}
}
closedir( $handle );
closedir($handle);
}
/**
* Create a zip file
*/
public static function createZip( $src, $out )
{
public static function createZip($src, $out, $exclude_callback=null) {
$a = new ZipArchive();
$a->open( $out, ZIPARCHIVE::CREATE);
$a->open($out, ZIPARCHIVE::CREATE);
if( ! is_array( $src ) )
$src = array( $src );
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 ) );
file_put_contents("debug.ifm.log", var_export(is_callable($exclude_callback), true)."\n");
foreach ($src as $s)
if (is_dir($s))
if (is_callable($exclude_callback))
self::addFolder( $a, $s, null, $exclude_callback );
else
self::addFolder( $a, $s );
elseif (is_file($s))
if (!is_callable($exclude_callback) || $exclude_callback($s))
$a->addFile($s, substr($s, strlen(dirname($s)) + 1));
try {
return $a->close();
} catch ( Exception $e ) {
} catch (Exception $e) {
return false;
}
}
@ -68,13 +77,13 @@ class IFMArchive {
/**
* Unzip a zip file
*/
public static function extractZip( $file, $destination="./" ) {
if( ! file_exists( $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 );
$res = $zip->open($file);
if ($res === true) {
$zip->extractTo($destination);
$zip->close();
return true;
} else
@ -84,32 +93,32 @@ class IFMArchive {
/**
* Creates a tar archive
*/
public static function createTar( $src, $out, $t ) {
$tmpf = substr( $out, 0, strlen( $out ) - strlen( $t ) ) . "tar";
$a = new PharData( $tmpf );
public static function createTar($src, $out, $t) {
$tmpf = substr($out, 0, strlen($out) - strlen($t)) . "tar";
$a = new PharData($tmpf);
try {
if( ! is_array( $src ) )
$src = array( $src );
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 ) );
switch( $t ) {
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 );
$a->compress(Phar::GZ);
@unlink($tmpf);
break;
case "tar.bz2":
$a->compress( Phar::BZ2 );
@unlink( $tmpf );
$a->compress(Phar::BZ2);
@unlink($tmpf);
break;
}
return true;
} catch( Exception $e ) {
@unlink( $tmpf );
} catch (Exception $e) {
@unlink($tmpf);
return false;
}
}
@ -117,14 +126,14 @@ class IFMArchive {
/**
* Extracts a tar archive
*/
public static function extractTar( $file, $destination="./" ) {
if( ! file_exists( $file ) )
public static function extractTar($file, $destination="./") {
if (!file_exists($file))
return false;
$tar = new PharData( $file );
$tar = new PharData($file);
try {
$tar->extractTo( $destination, null, true );
$tar->extractTo($destination, null, true);
return true;
} catch( Exception $e ) {
} catch (Exception $e) {
return false;
}
}

View File

@ -1,9 +1,9 @@
(function(){function l(b){var a=$('<div class="dropdown bootstrapMenu" style="z-index:10000;position:absolute;" />'),c=$('<ul class="dropdown-menu" style="position:static;display:block;font-size:0.9em;" />'),e=[[]];_.each(b.options.actionsGroups,function(b,a){e[a+1]=[]});var d=!1;_.each(b.options.actions,function(a,c){var h=!1;_.each(b.options.actionsGroups,function(b,a){_.includes(b,c)&&(e[a+1].push(c),h=!0)});!1===h&&e[0].push(c);"undefined"!==typeof a.iconClass&&(d=!0)});var g=!0;_.each(e,function(a){0!=
a.length&&(!1===g&&c.append('<li class="divider"></li>'),g=!1,_.each(a,function(a){var h=b.options.actions[a];!0===d?c.append('<li role="presentation" data-action="'+a+'"><a href="#" role="menuitem"><i class="fa fa-fw fa-lg '+(h.iconClass||"")+'"></i> <span class="actionName"></span></a></li>'):c.append('<li role="presentation" data-action="'+a+'"><a href="#" role="menuitem"><span class="actionName"></span></a></li>')}),c.append('<li role="presentation" class="noActionsMessage disabled"><a href="#" role="menuitem"><span>'+
(function(){function l(b){var a=$('<div class="dropdown bootstrapMenu" style="z-index:10000;position:absolute;" />'),c=$('<ul class="dropdown-menu" style="position:static;display:block;font-size:0.9em;" />'),e=[[]];_.each(b.options.actionsGroups,function(b,a){e[a+1]=[]});var d=!1;_.each(b.options.actions,function(a,c){var h=!1;_.each(b.options.actionsGroups,function(b,a){_.includes(b,c)&&(e[a+1].push(c),h=!0)});!1===h&&e[0].push(c);"undefined"!==typeof a.iconClass&&(d=!0)});var f=!0;_.each(e,function(a){0!=
a.length&&(!1===f&&c.append('<li class="dropdown-divider"></li>'),f=!1,_.each(a,function(a){var h=b.options.actions[a];!0===d?c.append('<li role="presentation" data-action="'+a+'"><a href="#" role="menuitem" class="dropdown-item"><i class="fa fa-fw fa-lg '+(h.iconClass||"")+'"></i> <span class="actionName"></span></a></li>'):c.append('<li role="presentation" data-action="'+a+'"><a href="#" role="menuitem" class="dropdown-item"><span class="actionName"></span></a></li>')}),c.append('<li role="presentation" class="noActionsMessage disabled"><a href="#" role="menuitem" class="dropdown-item"><span>'+
b.options.noActionsMessage+"</span></a></li>"))});return a.append(c)}function m(b){var a=null;switch(b.options.menuEvent){case "click":a="click";break;case "right-click":a="contextmenu";break;case "hover":a="mouseenter";break;default:throw Error("Unknown BootstrapMenu 'menuEvent' option");}b.$container.on(a+b.namespace,b.selector,function(a){var c=$(this);b.open(c,a);return!1})}function n(b){b.$menu.on(b.options._actionSelectEvent+b.namespace,function(a){a.preventDefault();a.stopPropagation();if((a=
$(a.target).closest("[data-action]"))&&a.length&&!a.is(".disabled")){a=a.data("action");var c=b.options.fetchElementData(b.$openTarget);b.options.actions[a].onClick(c);b.close()}})}function p(b){switch(b.options.menuEvent){case "click":break;case "right-click":break;case "hover":var a=b.$openTarget.add(b.$menu);a.on("mouseleave"+b.closeNamespace,function(c){c=c.toElement||c.relatedTarget;b.$openTarget.is(c)||b.$menu.is(c)||(a.off(b.closeNamespace),b.close())});break;default:throw Error("Unknown BootstrapMenu 'menuEvent' option");
}b.$container.on("click"+b.closeNamespace,function(){b.close()})}var q={container:"body",fetchElementData:_.noop,menuSource:"mouse",menuPosition:"belowLeft",menuEvent:"right-click",actionsGroups:[],noActionsMessage:"No available actions",_actionSelectEvent:"click"},d=function(b,a){this.selector=b;this.options=_.extend({},q,a);this.namespace=_.uniqueId(".BootstrapMenu_");this.closeNamespace=_.uniqueId(".BootstrapMenuClose_");this.init()},f=[];d.prototype.init=function(){this.$container=$(this.options.container);
this.$menu=l(this);this.$menuList=this.$menu.children();this.$menu.hide().appendTo(this.$container);this.openEvent=this.$openTarget=null;m(this);n(this);f.push(this)};d.prototype.updatePosition=function(){switch(this.options.menuSource){case "element":var b=this.$openTarget;break;case "mouse":b=this.openEvent;break;default:throw Error("Unknown BootstrapMenu 'menuSource' option");}switch(this.options.menuPosition){case "belowRight":var a="right top";var c="right bottom";break;case "belowLeft":a="left top";
c="left bottom";break;case "aboveRight":a="right bottom";c="right top";break;case "aboveLeft":a="left bottom";c="left top";break;default:throw Error("Unknown BootstrapMenu 'menuPosition' option");}this.$menu.css({display:"block"});this.$menu.css({height:this.$menuList.height(),width:this.$menuList.width()});this.$menu.position({my:a,at:c,of:b})};d.prototype.open=function(b,a){var c=this;d.closeAll();this.$openTarget=b;this.openEvent=a;var e=c.options.fetchElementData(c.$openTarget),f=this.$menu.find("[data-action]"),
g=this.$menu.find(".noActionsMessage");f.show();g.hide();var k=0;f.each(function(){var b=$(this),a=b.data("action");a=c.options.actions[a];var d=a.classNames||null;d&&_.isFunction(d)&&(d=d(e));b.attr("class",classNames(d||""));a.isShown&&!1===a.isShown(e)?b.hide():(k++,b.find(".actionName").html(_.isFunction(a.name)&&a.name(e)||a.name),a.isEnabled&&!1===a.isEnabled(e)&&b.addClass("disabled"))});0===k&&g.show();this.updatePosition();this.$menu.show();p(this)};d.prototype.close=function(){this.$menu.hide();
this.$container.off(this.closeNamespace)};d.prototype.destroy=function(){this.close();this.$container.off(this.namespace);this.$menu.off(this.namespace);f.splice(f.indexOf(this),1)};d.closeAll=function(){_.each(f,function(b){b.close()})};window.BootstrapMenu=d})(jQuery);
}b.$container.on("click"+b.closeNamespace,function(){b.close()})}var q={container:"body",fetchElementData:_.noop,menuSource:"mouse",menuPosition:"belowLeft",menuEvent:"right-click",actionsGroups:[],noActionsMessage:"No available actions",_actionSelectEvent:"click"},d=function(b,a){this.selector=b;this.options=_.extend({},q,a);this.namespace=_.uniqueId(".BootstrapMenu_");this.closeNamespace=_.uniqueId(".BootstrapMenuClose_");this.init()},g=[];d.prototype.init=function(){this.$container=$(this.options.container);
this.$menu=l(this);this.$menuList=this.$menu.children();this.$menu.hide().appendTo(this.$container);this.openEvent=this.$openTarget=null;m(this);n(this);g.push(this)};d.prototype.updatePosition=function(){switch(this.options.menuSource){case "element":var b=this.$openTarget;break;case "mouse":b=this.openEvent;break;default:throw Error("Unknown BootstrapMenu 'menuSource' option");}switch(this.options.menuPosition){case "belowRight":var a="right top";var c="right bottom";break;case "belowLeft":a="left top";
c="left bottom";break;case "aboveRight":a="right bottom";c="right top";break;case "aboveLeft":a="left bottom";c="left top";break;default:throw Error("Unknown BootstrapMenu 'menuPosition' option");}this.$menu.css({display:"block"});this.$menu.css({height:this.$menuList.height(),width:this.$menuList.width()});this.$menu.position({my:a,at:c,of:b})};d.prototype.open=function(b,a){var c=this;d.closeAll();this.$openTarget=b;this.openEvent=a;var e=c.options.fetchElementData(c.$openTarget),g=this.$menu.find("[data-action]"),
f=this.$menu.find(".noActionsMessage");g.show();f.hide();var k=0;g.each(function(){var b=$(this),a=b.data("action");a=c.options.actions[a];var d=a.classNames||null;d&&_.isFunction(d)&&(d=d(e));b.attr("class",classNames(d||""));a.isShown&&!1===a.isShown(e)?b.hide():(k++,b.find(".actionName").html(_.isFunction(a.name)&&a.name(e)||a.name),a.isEnabled&&!1===a.isEnabled(e)&&b.addClass("disabled"))});0===k&&f.show();this.updatePosition();this.$menu.show();p(this)};d.prototype.close=function(){this.$menu.hide();
this.$container.off(this.closeNamespace)};d.prototype.destroy=function(){this.close();this.$container.off(this.namespace);this.$menu.off(this.namespace)};d.closeAll=function(){_.each(g,function(b){b.close()})};window.BootstrapMenu=d})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#bs/dt-1.10.20
* https://datatables.net/download/#bs4/dt-1.10.20
*
* Included libraries:
* DataTables 1.10.20
@ -174,7 +174,7 @@ sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers"
aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,
aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:p,oAjaxData:p,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==D(this)?1*this._iRecordsTotal:
this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==D(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};q.ext=C={buttons:{},
classes:{},builder:"bs/dt-1.10.20",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:q.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:q.version};f.extend(C,{afnFiltering:C.search,aTypes:C.type.detect,ofnSearch:C.type.search,oSort:C.type.order,afnSortData:C.order,aoFeatures:C.feature,oApi:C.internal,oStdClasses:C.classes,oPagination:C.pager});
classes:{},builder:"bs4/dt-1.10.20",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:q.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:q.version};f.extend(C,{afnFiltering:C.search,aTypes:C.type.detect,ofnSearch:C.type.search,oSort:C.type.order,afnSortData:C.order,aoFeatures:C.feature,oApi:C.internal,oStdClasses:C.classes,oPagination:C.pager});
f.extend(q.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",
sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",
sJUIHeader:"",sJUIFooter:""});var Pb=q.ext.pager;f.extend(Pb,{simple:function(a,b){return["previous","next"]},full:function(a,b){return["first","previous","next","last"]},numbers:function(a,b){return[ka(a,b)]},simple_numbers:function(a,b){return["previous",ka(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ka(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ka(a,b),"last"]},_numbers:ka,numbers_length:7});f.extend(!0,q.ext.renderer,{pageButton:{_:function(a,b,
@ -193,14 +193,15 @@ f.each(q,function(a,b){f.fn.DataTable[a]=b});return f.fn.dataTable});
/*!
DataTables Bootstrap 3 integration
©2011-2015 SpryMedia Ltd - datatables.net/license
DataTables Bootstrap 4 integration
©2011-2017 SpryMedia Ltd - datatables.net/license
*/
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,b,c){a instanceof String&&(a=String(a));for(var e=a.length,d=0;d<e;d++){var k=a[d];if(b.call(c,k,d,a))return{i:d,v:k}}return{i:-1,v:void 0}};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);
$jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;e<a.length-1;e++){var d=a[e];d in c||(c[d]={});c=c[d]}a=a[a.length-1];e=c[a];b=b(e);b!=e&&null!=b&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:b})}};$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,c){return $jscomp.findInternal(this,a,c).v}},"es6","es3");
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);c&&c.fn.dataTable||(c=require("datatables.net")(b,c).$);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a,b,c,e){var d=a.fn.dataTable;a.extend(!0,d.defaults,{dom:"<'row'<'col-sm-6'l><'col-sm-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-5'i><'col-sm-7'p>>",renderer:"bootstrap"});a.extend(d.ext.classes,
{sWrapper:"dataTables_wrapper form-inline dt-bootstrap",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm",sProcessing:"dataTables_processing panel panel-default"});d.ext.renderer.pageButton.bootstrap=function(b,l,v,w,m,r){var k=new d.Api(b),x=b.oClasses,n=b.oLanguage.oPaginate,y=b.oLanguage.oAria.paginate||{},g,h,t=0,u=function(c,d){var e,l=function(b){b.preventDefault();a(b.currentTarget).hasClass("disabled")||k.page()==b.data.action||k.page(b.data.action).draw("page")};
var q=0;for(e=d.length;q<e;q++){var f=d[q];if(a.isArray(f))u(c,f);else{h=g="";switch(f){case "ellipsis":g="&#x2026;";h="disabled";break;case "first":g=n.sFirst;h=f+(0<m?"":" disabled");break;case "previous":g=n.sPrevious;h=f+(0<m?"":" disabled");break;case "next":g=n.sNext;h=f+(m<r-1?"":" disabled");break;case "last":g=n.sLast;h=f+(m<r-1?"":" disabled");break;default:g=f+1,h=m===f?"active":""}if(g){var p=a("<li>",{"class":x.sPageButton+" "+h,id:0===v&&"string"===typeof f?b.sTableId+"_"+f:null}).append(a("<a>",
{href:"#","aria-controls":b.sTableId,"aria-label":y[f],"data-dt-idx":t,tabindex:b.iTabIndex}).html(g)).appendTo(c);b.oApi._fnBindAction(p,{action:f},l);t++}}}};try{var p=a(l).find(c.activeElement).data("dt-idx")}catch(z){}u(a(l).empty().html('<ul class="pagination"/>').children("ul"),w);p!==e&&a(l).find("[data-dt-idx="+p+"]").focus()};return d});
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);c&&c.fn.dataTable||(c=require("datatables.net")(b,c).$);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a,b,c,e){var d=a.fn.dataTable;a.extend(!0,d.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
renderer:"bootstrap"});a.extend(d.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"custom-select custom-select-sm form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"});d.ext.renderer.pageButton.bootstrap=function(b,l,v,w,m,r){var k=new d.Api(b),x=b.oClasses,n=b.oLanguage.oPaginate,y=b.oLanguage.oAria.paginate||{},g,h,t=0,u=function(c,d){var e,l=function(b){b.preventDefault();
a(b.currentTarget).hasClass("disabled")||k.page()==b.data.action||k.page(b.data.action).draw("page")};var q=0;for(e=d.length;q<e;q++){var f=d[q];if(a.isArray(f))u(c,f);else{h=g="";switch(f){case "ellipsis":g="&#x2026;";h="disabled";break;case "first":g=n.sFirst;h=f+(0<m?"":" disabled");break;case "previous":g=n.sPrevious;h=f+(0<m?"":" disabled");break;case "next":g=n.sNext;h=f+(m<r-1?"":" disabled");break;case "last":g=n.sLast;h=f+(m<r-1?"":" disabled");break;default:g=f+1,h=m===f?"active":""}if(g){var p=
a("<li>",{"class":x.sPageButton+" "+h,id:0===v&&"string"===typeof f?b.sTableId+"_"+f:null}).append(a("<a>",{href:"#","aria-controls":b.sTableId,"aria-label":y[f],"data-dt-idx":t,tabindex:b.iTabIndex,"class":"page-link"}).html(g)).appendTo(c);b.oApi._fnBindAction(p,{action:f},l);t++}}}};try{var p=a(l).find(c.activeElement).data("dt-idx")}catch(z){}u(a(l).empty().html('<ul class="pagination"/>').children("ul"),w);p!==e&&a(l).find("[data-dt-idx="+p+"]").focus()};return d});

5
src/includes/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ class IFM {
"tmp_dir" => "",
"timezone" => "",
"forbiddenChars" => array(),
"dateLocale" => "en-US",
"language" => "@@@vars:defaultlanguage@@@",
"selfoverwrite" => 0,
@ -41,6 +42,7 @@ class IFM {
"rename" => 1,
"zipnload" => 1,
"createarchive" => 1,
"search" => 1,
// gui controls
"showlastmodified" => 0,
@ -52,7 +54,9 @@ class IFM {
"showhiddenfiles" => 1,
"showpath" => 0,
"contextmenu" => 1,
"disable_mime_detection" => 0
"disable_mime_detection" => 0,
"showrefresh" => 1,
"forceproxy" => 0
);
private $config = array();
@ -72,6 +76,7 @@ class IFM {
$this->config['root_public_url'] = getenv('IFM_ROOT_PUBLIC_URL') !== false ? getenv('IFM_ROOT_PUBLIC_URL') : $this->config['root_public_url'] ;
$this->config['tmp_dir'] = getenv('IFM_TMP_DIR') !== false ? getenv('IFM_TMP_DIR') : $this->config['tmp_dir'] ;
$this->config['timezone'] = getenv('IFM_TIMEZONE') !== false ? getenv('IFM_TIMEZONE') : $this->config['timezone'] ;
$this->config['dateLocale'] = getenv('IFM_DATELOCALE') !== false ? getenv('IFM_DATELOCALE') : $this->config['dateLocale'] ;
$this->config['forbiddenChars'] = getenv('IFM_FORBIDDENCHARS') !== false ? str_split( getenv('IFM_FORBIDDENCHARS') ) : $this->config['forbiddenChars'] ;
$this->config['language'] = getenv('IFM_LANGUAGE') !== false ? getenv('IFM_LANGUAGE') : $this->config['language'] ;
$this->config['selfoverwrite'] = getenv('IFM_SELFOVERWRITE') !== false ? getenv('IFM_SELFOVERWRITE') : $this->config['selfoverwrite'] ;
@ -98,6 +103,9 @@ class IFM {
$this->config['showhiddenfiles'] = getenv('IFM_GUI_SHOWHIDDENFILES') !== false ? intval( getenv('IFM_GUI_SHOWHIDDENFILES') ) : $this->config['showhiddenfiles'] ;
$this->config['showpath'] = getenv('IFM_GUI_SHOWPATH') !== false ? intval( getenv('IFM_GUI_SHOWPATH') ) : $this->config['showpath'] ;
$this->config['contextmenu'] = getenv('IFM_GUI_CONTEXTMENU') !== false ? intval( getenv('IFM_GUI_CONTEXTMENU') ) : $this->config['contextmenu'] ;
$this->config['search'] = getenv('IFM_API_SEARCH') !== false ? intval( getenv('IFM_API_SEARCH') ) : $this->config['search'] ;
$this->config['showrefresh'] = getenv('IFM_GUI_REFRESH') !== false ? intval( getenv('IFM_GUI_REFRESH') ) : $this->config['showrefresh'] ;
$this->config['forceproxy'] = getenv('IFM_GUI_FORCEPROXY') !== false ? intval( getenv('IFM_GUI_FORCEPROXY') ) : $this->config['forceproxy'] ;
// optional settings
if( getenv('IFM_SESSION_LIFETIME') !== false )
@ -201,36 +209,7 @@ f00bar;
$this->getJS();
}
public function getCSS() {
print '
<style type="text/css">';?> @@@file:src/includes/bootstrap.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/bootstrap-treeview.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/datatables.min.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/fontello-embedded.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/includes/animation.css@@@ <?php print '</style>
<style type="text/css">';?> @@@file:src/style.css@@@ <?php print '</style>
';
}
public function getJS() {
echo <<<'f00bar'
<script>
@@@file:src/includes/jquery.min.js@@@
@@@file:src/includes/jquery.ui.min.js@@@
@@@file:src/includes/bootstrap.min.js@@@
@@@file:src/includes/bootstrap-notify.min.js@@@
@@@file:src/includes/bootstrap-treeview.min.js@@@
@@@file:src/includes/datatables.min.js@@@
@@@file:src/includes/lodash.min.js@@@
@@@file:src/includes/classnames.js@@@
@@@file:src/includes/bootstrap-contextmenu.js@@@
@@@file:src/includes/mustache.min.js@@@
@@@file:src/includes/ace.js@@@
@@@acedir:src/includes/ace@@@
@@@file:src/ifm.js@@@
</script>
f00bar;
}
IFM_ASSETS
public function getHTMLHeader() {
print '<!DOCTYPE HTML>
@ -417,7 +396,8 @@ f00bar;
private function getConfig() {
$ret = $this->config;
$ret['inline'] = ( $this->mode == "inline" ) ? true : false;
$ret['isDocroot'] = ( $this->getRootDir() == $this->getScriptRoot() ) ? true : false;
$ret['isDocroot'] = ($this->getRootDir() == $this->getScriptRoot());
foreach (array("auth_source", "root_dir") as $field) {
unset($ret[$field]);
}
@ -454,6 +434,11 @@ f00bar;
}
private function searchItems( $d ) {
if( $this->config['search'] != 1 ) {
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) );
return;
}
if( strpos( $d['pattern'], '/' ) !== false ) {
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['pattern_error_slashes'] ) );
exit( 1 );
@ -680,6 +665,8 @@ f00bar;
private function downloadFile( array $d, $forceDL=true ) {
if( $this->config['download'] != 1 )
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) );
elseif( ! $this->isFilenameValid( $d['filename'] ) )
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) );
elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) )
$this->jsonResponse( array( "status" => "ERROR", "message"=> $this->l['nopermissions'] ) );
elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) )
@ -819,20 +806,22 @@ f00bar;
else {
if( ! file_exists( $d['filename'] ) )
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['folder_not_found'] ) );
elseif ( ! $this->isFilenameValid( $d['filename'] ) )
elseif (!$this->isPathValid($d['filename']))
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) );
elseif ($d['filename'] != "." && !$this->isFilenameValid($d['filename']))
$this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) );
else {
unset( $zip );
$dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename
$dfile = $this->pathCombine( __DIR__, $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename
try {
IFMArchive::createZip( realpath( $d['filename'] ), $dfile );
IFMArchive::createZip(realpath($d['filename']), $dfile, array($this, 'isFilenameValid'));
if( $d['filename'] == "." ) {
if( getcwd() == $this->getScriptRoot() )
$d['filename'] = "root";
else
$d['filename'] = basename( getcwd() );
}
$this->fileDownload( array( "file" => $dfile, "name" => $d['filename'] . ".zip" ) );
$this->fileDownload( array( "file" => $dfile, "name" => $d['filename'] . ".zip", "forceDL" => true ) );
} catch ( Exception $e ) {
echo $this->l['error'] . " " . $e->getMessage();
} finally {
@ -1005,8 +994,8 @@ f00bar;
if( ! isset( $_SESSION['ifmauth'] ) || $_SESSION['ifmauth'] !== true ) {
$login_failed = false;
if( isset( $_POST["user"] ) && isset( $_POST["pass"] ) ) {
if( $this->checkCredentials( $_POST["user"], $_POST["pass"] ) ) {
if( isset( $_POST["inputLogin"] ) && isset( $_POST["inputPassword"] ) ) {
if( $this->checkCredentials( $_POST["inputLogin"], $_POST["inputPassword"] ) ) {
$_SESSION['ifmauth'] = true;
}
else {
@ -1094,7 +1083,7 @@ f00bar;
private function loginForm($loginFailed=false) {
$err = "";
if( $loginFailed )
$err = '<div class="alert alert-danger">'.$this->l['login_failed'].'</div>';
$err = '<div class="alert alert-primary" role="alert">'.$this->l['login_failed'].'</div>';
$this->getHTMLHeader();
$html = str_replace( "{{error}}", $err, $this->templates['login'] );
$html = str_replace( "{{i18n.username}}", $this->l['username'], $html );
@ -1245,17 +1234,16 @@ f00bar;
}
// combines two parts to a valid path
private function pathCombine( $a, $b ) {
if( trim( $a ) == "" && trim( $b ) == "" )
return "";
elseif( trim( $a ) == "" )
return ltrim( $b, '/' );
else
return rtrim( $a, '/' ) . '/' . trim( $b, '/' );
private function pathCombine(...$parts) {
$ret = "";
foreach($parts as $part)
if (trim($part) != "")
$ret .= (empty($ret)?rtrim($part,"/"):trim($part, '/'))."/";
return rtrim($ret, "/");
}
// check if filename is allowed
private function isFilenameValid( $f ) {
public function isFilenameValid( $f ) {
if( ! $this->isFilenameAllowed( $f ) )
return false;
if( strtoupper( substr( PHP_OS, 0, 3 ) ) == "WIN" ) {

View File

@ -1,30 +1,6 @@
body {
padding-top: 70px;
overflow-y: scroll !important;
}
/*
* This prevents the content from moving when opening a modal
*/
.modal-open {
padding-right: 0 !important;
}
.icon {
font-size: 14pt;
}
#filetable td:nth-child(5), #filetable th:nth-child(5) {
text-align: center;
}
#filetable td:nth-child(6), #filetable th:nth-child(6) {
text-align: center;
}
#filetable tr td:last-child {
text-align: right;
}
#filetable td:last-child a:hover {
text-decoration: none;
padding-top: 70px;
overflow-y: scroll !important;
}
a { cursor: pointer !important; }
@ -32,9 +8,59 @@ a.ifmitem:focus { outline: 0 }
img.imgpreview { max-width: 100%; }
div#content { width: 100%; height: 350px; }
div#content { width: 100%; height: 350px; } /* is for the ACE editor */
input[name=newpermissions] { padding: 6px 8px; }
label {
display: inline-block;
margin-bottom: .5rem;
font-weight: 700;
}
/* Make tables more compact (overwrites bootstrap default of 0.75rem) */
.table td, .table th {
padding: 0.25rem;
}
/* narrow navbar */
.navbar {
padding: 0.3rem;
}
/*
* Icon size
*/
.icon {
font-size: 14pt;
}
@media (max-width: 768px) {
.icon { font-size: 12pt; }
#filetable tr th.buttons { min-width: 85px !important; }
}
/*
* Filetable related settings
*/
#filetable th {
border-top: 0;
}
#filetable td:nth-child(5), #filetable th:nth-child(5) {
text-align: center;
}
#filetable td:nth-child(6), #filetable th:nth-child(6) {
text-align: center;
}
#filetable tr td:last-child {
text-align: right;
}
#filetable td:last-child a:hover {
text-decoration: none;
}
.td-permissions { width: 1px; }
input[name=newpermissions] {
padding: 6px 8px;
width: 6.5rem;
}
#filetable tr th.buttons { min-width: 95px; }
#filetable tbody tr.highlightedItem { box-shadow: 0px 0px 10px 2px #337ab7; }
@ -43,52 +69,51 @@ input[name=newpermissions] { padding: 6px 8px; }
#filetable tbody tr.selectedItem * a { color: #FFF; }
#filetable tbody tr td { vertical-align: inherit; }
#navbar { max-width: 100%; }
div.ifminfo { color: #adadad; font-size: 10pt; }
div.ifminfo div.panel div.panel-body { padding: 0px !important; text-align: center; }
@media (max-width: 768px) {
.icon { font-size: 12pt; }
#filetable tr th.buttons { min-width: 85px !important; }
}
/*
* Footer / Task-Queue settings
*/
footer {
position: fixed;
padding-top: 1em;
border-top: 1px;
background-color: #EEE;
bottom: 0;
width: 100%;
max-height: 6em;
overflow:hidden;
position: fixed;
padding-top: 1em;
border-top: 1px;
background-color: #EEE;
bottom: 0;
width: 100%;
max-height: 6em;
overflow: hidden;
}
#waitqueue .progress {
position:relative;
margin-bottom: 0;
position: relative;
margin-bottom: 0;
}
#waitqueue .progbarlabel {
position:absolute;
top: 0;
left: 10px;
font-weight: bold;
position:absolute;
top: 0;
left: 10px;
font-weight: bold;
}
/*
* File drop overlay
*/
#filedropoverlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
color: #FFF;
background-color: lightblue;
filter: alpha(opacity=70);
-moz-opacity: 0.7;
opacity: 0.7;
z-index: 1000;
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
color: #FFF;
background-color: lightblue;
filter: alpha(opacity=70);
-moz-opacity: 0.7;
opacity: 0.7;
z-index: 1000;
}
#filedropoverlay h1 {
@ -96,41 +121,69 @@ footer {
color: #000;
position:relative;
top:50%;
font-size: 6em;
pointer-events: none;
font-size: 6em;
pointer-events: none;
}
.td-permissions { width: 1px; }
/* datatables */
/*
* Datatables related settings
*/
table.dataTable thead th {
position: relative;
background-image: none !important;
position: relative;
background-image: none !important;
}
/* remove original sort icons */
table.dataTable thead .sorting:before,
table.dataTable thead .sorting_asc:before,
table.dataTable thead .sorting_desc:before,
table.dataTable thead .sorting_asc_disabled:before,
table.dataTable thead .sorting_desc_disabled:before {
right: 0 !important;
content: "" !important;
}
/* custom sort icons */
table.dataTable thead th.sorting:after,
table.dataTable thead th.sorting_asc:after,
table.dataTable thead th.sorting_desc:after {
position: absolute;
top: 12px;
right: 8px;
display: block;
font-family: fontello;
position: absolute;
top: 6px;
right: 8px;
display: block;
font-family: fontello;
font-size: 0.8em;
opacity: 1;
color: #000;
}
table.dataTable thead th.sorting:after {
content: "\F0DC";
font-size: 0.8em;
padding-top: 0.12em;
content: "\F0DC";
color: #ddd;
}
table.dataTable thead th.sorting_asc:after {
content: "\f0de";
content: "\f0de";
}
table.dataTable thead th.sorting_desc:after {
content: "\f0dd";
content: "\f0dd";
}
/*
* Modal related settings
*/
#copyMoveTree {
max-height: 80vh;
overflow: auto;
max-height: 80vh;
overflow: auto;
}
@media (min-width: 576px) {
.modal-dialog {
max-width: 600px;
margin: 1.75rem auto;
}
}
@media (min-width: 992px) {
.modal-lg, .modal-xl {
max-width: 800px;
}
}

View File

@ -1,91 +1,108 @@
<nav class="navbar navbar-inverse
{{^config.inline}}
navbar-fixed-top
{{/config.inline}}
">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand">IFM</a>
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar">
<span class="sr-only">{{i18n.toggle_nav}}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse" id="navbar">
<form class="navbar-form navbar-left">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" id="currentDirLabel">{{i18n.path_content}} <span id="docroot">{{showpath}}</span></span>
<input class="form-control" id="currentDir" aria-describedby="currentDirLabel" type="text">
</div>
</div>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a id="refresh"><span title="{{i18n.refresh}}" class="icon icon-arrows-cw"></span> <span class="visible-xs">{{i18n.refresh}}</span></a></li>
<li><a id="search"><span title="{{i18n.search}}" class="icon icon-search"></span> <span class="visible-xs">{{i18n.search}}</span></a></li>
{{#config.upload}}
<li><a id="upload"><span title="{{i18n.upload}}" class="icon icon-upload"></span> <span class="visible-xs">{{i18n.upload}}</span></a></li>
{{/config.upload}}
{{#config.createfile}}
<li><a id="createFile"><span title="{{i18n.file_new}}" class="icon icon-doc-inv"></span> <span class="visible-xs">{{i18n.file_new}}</span></a></li>
{{/config.createfile}}
{{#config.createdir}}
<li><a id="createDir"><span title="{{i18n.folder_new}}" class="icon icon-folder"></span> <span class="visible-xs">{{i18n.folder_new}}</span></a></li>
{{/config.createdir}}
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="icon icon-down-open"></span></a>
<ul class="dropdown-menu" role="menu">
{{#config.remoteupload}}
<li><a id="buttonRemoteUpload"><span class="icon icon-upload-cloud"></span> {{i18n.upload_remote}}</a></li>
{{/config.remoteupload}}
{{#config.ajaxrequest}}
<li><a id="buttonAjaxRequest"><span class="icon icon-link-ext"></span> {{i18n.ajax_request}}</a></li>
{{/config.ajaxrequest}}
{{#config.auth}}
<li><a id="buttonLogout" href="?api=logout"><span class="icon icon-logout"></span> {{i18n.logout}}</a></li>
{{/config.auth}}
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div id="filedropoverlay">
<h1>{{i18n.upload_drop}}</h1>
</div>
<div class="container">
<table id="filetable" class="table">
<thead>
<tr>
<th class="th-meta hidden" data-visible="false"></th>
<th class="th-filename">{{i18n.filename}}</th>
{{#config.download}}
<th class="th-download"><!-- column for download link --></th>
{{/config.download}}
{{#config.showlastmodified}}
<th class="th-lastmod">{{i18n.last_modified}}</th>
{{/config.showlastmodified}}
{{#config.showfilesize}}
<th class="th-size">{{i18n.size}}</th>
{{/config.showfilesize}}
{{#config.showpermissions}}
<th class="th-permissions hidden-xs">{{i18n.permissions}}</th>
{{/config.showpermissions}}
{{#config.showowner}}
<th class="th-owner hidden-xs hidden-sm">{{i18n.owner}}</th>
{{/config.showowner}}
{{#config.showgroup}}
<th class="th-group hidden-xs hidden-sm hidden-md">{{i18n.group}}</th>
{{/config.showgroup}}
<th class="th-buttons buttons"><!-- column for buttons --></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="container">
<div class="panel panel-default ifminfo"><div class="panel-body"><div style="float:left; padding-left: 10px;">{{i18n.footer}} IFM_VERSION</div>
<a style="float:right; padding-right: 10px;" href="http://github.com/misterunknown/ifm">{{i18n.github}}</a></div>
</div>
<nav class="navbar navbar-expand-lg navbar-dark
{{^config.inline}}
fixed-top
{{/config.inline}} bg-dark">
<div class="container">
<a class="navbar-brand" href="#">IFM</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="true" aria-label="{{i18n.toggle_nav}}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<div class="navbar-nav mr-auto">
<form class="form-inline mt-2 mt-md-0">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="currentDirLabel">{{i18n.path_content}} {{showpath}}</span>
</div>
<input class="form-control" id="currentDir" aria-describedby="currentDirLabel" type="text">
</div>
</form>
</div>
<ul class="navbar-nav">
{{#config.showrefresh}}
<li class="nav-item">
<a id="refresh" class="nav-link"><span title="{{i18n.refresh}}" class="icon icon-arrows-cw" href="#"></span> <span class="d-inline d-sm-none">{{i18n.refresh}}</span></a>
</li>
{{/config.showrefresh}}
{{#config.search}}
<li class="nav-item">
<a id="search" class="nav-link"><span title="{{i18n.search}}" class="icon icon-search" href="#"></span> <span class="d-inline d-sm-none">{{i18n.search}}</span></a>
</li>
{{/config.search}}
{{#config.upload}}
<li class="nav-item">
<a id="upload" class="nav-link"><span title="{{i18n.upload}}" class="icon icon-upload" href="#"></span> <span class="d-inline d-sm-none">{{i18n.upload}}</span></a>
</li>
{{/config.upload}}
{{#config.createfile}}
<li class="nav-item">
<a id="createFile" class="nav-link"><span title="{{i18n.file_new}}" class="icon icon-doc-inv" href="#"></span> <span class="d-inline d-sm-none">{{i18n.file_new}}</span></a>
</li>
{{/config.createfile}}
{{#config.createdir}}
<li class="nav-item">
<a id="createDir" class="nav-link"><span title="{{i18n.folder_new}}" class="icon icon-folder" href="#"></span> <span class="d-inline d-sm-none">{{i18n.folder_new}}</span></a>
</li>
{{/config.createdir}}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></a>
<div class="dropdown-menu" aria-labelledby="menu">
{{#config.remoteupload}}
<a class="dropdown-item" href="#" id="buttonRemoteUpload"><span class="icon icon-upload-cloud"></span> {{i18n.upload_remote}}</a>
{{/config.remoteupload}}
{{#config.ajaxrequest}}
<a class="dropdown-item" href="#" id="buttonAjaxRequest"><span class="icon icon-link-ext"></span> {{i18n.ajax_request}}</a>
{{/config.ajaxrequest}}
{{#config.auth}}
<a class="dropdown-item" href="?api=logout" id="buttonLogout"><span class="icon icon-logout"></span> {{i18n.logout}}</a>
{{/config.auth}}
</div>
</li>
</ul>
</div>
</div>
</nav>
<div id="filedropoverlay">
<h1>{{i18n.upload_drop}}</h1>
</div>
<main role="main">
<div class="container">
<table id="filetable" class="table">
<thead>
<tr>
<th class="th-meta hidden" data-visible="false"></th>
<th class="th-filename">{{i18n.filename}}</th>
{{#config.download}}
<th class="th-download"></th>
{{/config.download}}
{{#config.showlastmodified}}
<th class="th-lastmod">{{i18n.last_modified}}</th>
{{/config.showlastmodified}}
{{#config.showfilesize}}
<th class="th-size">{{i18n.size}}</th>
{{/config.showfilesize}}
{{#config.showpermissions}}
<th class="th-permissions d-none d-md-table-cell">{{i18n.permissions}}</th>
{{/config.showpermissions}}
{{#config.showowner}}
<th class="th-owner d-none d-lg-table-cell">{{i18n.owner}}</th>
{{/config.showowner}}
{{#config.showgroup}}
<th class="th-group d-none d-xl-table-cell">{{i18n.group}}</th>
{{/config.showgroup}}
<th class="th-buttons buttons"></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="container">
<div class="card ifminfo">
<div class="card-body p-2">
<div style="float:left; padding-left: 10px;">{{i18n.footer}} IFM_VERSION</div>
<a style="float:right; padding-right: 10px;" href="http://github.com/misterunknown/ifm">{{i18n.github}}</a>
</div>
</div>
</div>
</main>

View File

@ -24,17 +24,17 @@
<td data-order="{{size_raw}}">{{size}}</td>
{{/config.showfilesize}}
{{#config.showpermissions}}
<td class="hidden-xs td-permissions">
<td class="d-none d-md-table-cell">
<input type="text" size="11" name="newpermissions" class="form-control {{filepermmode}}" value="{{fileperms}}" data-filename="{{name}}" {{readonly}}>
</td>
{{/config.showpermissions}}
{{#config.showowner}}
<td class="hidden-xs hidden-sm">
<td class="d-none d-lg-table-cell">
{{owner}}
</td>
{{/config.showowner}}
{{#config.showgroup}}
<td class="hidden-xs hidden-sm hidden-md">
<td class="d-none d-xl-table-cell">
{{group}}
</td>
{{/config.showgroup}}

View File

@ -1,11 +1,11 @@
<footer class="footer">
<div class="container">
<div class="row">
<div class="col-xs-1">
<a name="showAll">{{i18n.tasks}} <span class="badge" name="taskCount">1</span></a>
</div>
<div id="waitqueue" class="col-xs-11">
</div>
</div> <!-- row -->
</div> <!-- container -->
</footer>
<footer class="footer mt-auto py-3">
<div class="container">
<div class="row">
<div class="col-1">
<a type="button" class="btn btn-light" name="showAll">{{i18n.tasks}} <span class="badge badge-secondary" name="taskCount">1</span></a>
</div>
<div id="waitqueue" class="col-11">
</div>
</div>
</div>
</footer>

View File

@ -1,54 +1,120 @@
<style type="text/css">
html,
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
height: 100%;
}
body {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
width: 100%;
max-width: 420px;
padding: 15px;
margin: auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
.form-label-group {
position: relative;
margin-bottom: 1rem;
}
.form-signin .checkbox {
font-weight: normal;
.form-label-group > input,
.form-label-group > label {
height: 3.125rem;
padding: .75rem;
}
.form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
.form-label-group > label {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
margin-bottom: 0; /* Override default `<label>` margin */
line-height: 1.5;
color: #495057;
pointer-events: none;
cursor: text; /* Match the input under the label */
border: 1px solid transparent;
border-radius: .25rem;
transition: all .1s ease-in-out;
}
.form-signin .form-control:focus {
z-index: 2;
.form-label-group input::-webkit-input-placeholder {
color: transparent;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
.form-label-group input:-ms-input-placeholder {
color: transparent;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
.form-label-group input::-ms-input-placeholder {
color: transparent;
}
.form-label-group input::-moz-placeholder {
color: transparent;
}
.form-label-group input::placeholder {
color: transparent;
}
.form-label-group input:not(:placeholder-shown) {
padding-top: 1.25rem;
padding-bottom: .25rem;
}
.form-label-group input:not(:placeholder-shown) ~ label {
padding-top: .25rem;
padding-bottom: .25rem;
font-size: 12px;
color: #777;
}
/* Fallback for Edge
-------------------------------------------------- */
@supports (-ms-ime-align: auto) {
.form-label-group > label {
display: none;
}
.form-label-group input::-ms-input-placeholder {
color: #777;
}
}
/* Fallback for IE
-------------------------------------------------- */
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.form-label-group > label {
display: none;
}
.form-label-group input:-ms-input-placeholder {
color: #777;
}
}
</style>
<div class="container">
<form action="" method="post" class="form-signin">
<h2 class="form-signin-heading text-center">IFM {{i18n.login}}</h2>
{{error}}
<label for="inputEmail" class="sr-only">{{i18n.username}}</label>
<input type="text" id="user" name="user" class="form-control" placeholder="{{i18n.username}}" required autofocus>
<label for="inputPassword" class="sr-only">{{i18n.password}}</label>
<input type="password" id="pass" name="pass" class="form-control" placeholder="{{i18n.password}}" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">{{i18n.login}}</button>
</form>
</div> <!-- /container -->
<form class="form-signin" method="POST" action>
<div class="text-center mb-4">
<h1 class="h3 mb-3 font-weight-normal">IFM {{i18n.login}}</h1>
</div>
<div class="form-label-group">
<input type="text" name="inputLogin" id="inputLogin" class="form-control" placeholder="{{i18n.username}}" required="" autofocus="">
<label for="inputLogin">{{i18n.username}}</label>
</div>
<div class="form-label-group">
<input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="{{i18n.password}}" required="">
<label for="inputPassword">{{i18n.password}}</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">{{i18n.login}}</button>
</form>

View File

@ -8,7 +8,7 @@
<label>{{i18n.method}}</label><br>
<input type="radio" name="arMethod" value="GET">GET</input><input type="radio" name="arMethod" value="POST" checked="checked">POST</input><br>
<button type="button" class="btn btn-success" id="buttonRequest">{{i18n.request}}</button>
<button type="button" class="btn btn-default" id="buttonClose">{{i18n.cancel}}</button><br>
<button type="button" class="btn btn-secondary" id="buttonClose">{{i18n.cancel}}</button><br>
<label>{{i18n.response}}</label><br>
<textarea class="form-control" id="ajaxresponse"></textarea>
</fieldset>

View File

@ -5,9 +5,9 @@
<div id="copyMoveTree"><div class="text-center"><span class="icon icon-spin5 animate-spin"></span></div></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="copyButton">{{i18n.copy}}</button>
<button type="button" class="btn btn-default" id="moveButton">{{i18n.move}}</button>
<button type="button" class="btn btn-default" id="cancelButton">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="copyButton">{{i18n.copy}}</button>
<button type="button" class="btn btn-secondary" id="moveButton">{{i18n.move}}</button>
<button type="button" class="btn btn-secondary" id="cancelButton">{{i18n.cancel}}</button>
</div>
</fieldset>
</form>

View File

@ -6,7 +6,7 @@
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="buttonSave">{{i18n.save}}</button>
<button type="button" class="btn btn-default" id="buttonCancel">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="buttonSave">{{i18n.save}}</button>
<button type="button" class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -6,7 +6,7 @@
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="buttonSave">{{i18n.save}}</button>
<button type="button" class="btn btn-default" id="buttonCancel">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="buttonSave">{{i18n.save}}</button>
<button type="button" class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -9,6 +9,6 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" id="buttonYes">{{i18n.delete}}</button>
<button type="button" class="btn btn-default" id="buttonNo">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="buttonNo">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -3,21 +3,27 @@
<fieldset>
<label>{{i18n.extract_filename}} {{filename}}:</label>
<div class="input-group">
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="./" checked="checked"></span>
<div class="input-group-prepend">
<span class="input-group-text"><input type="radio" name="extractTargetLocation" value="./" checked="checked"></span>
</div>
<span class="form-control">./</span>
</div>
<div class="input-group">
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="./{{destination}}"></span>
<div class="input-group-prepend">
<span class="input-group-text"><input type="radio" name="extractTargetLocation" value="./{{destination}}"></span>
</div>
<span class="form-control">./{{destination}}</span>
</div>
<div class="input-group">
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="custom"></span>
<div class="input-group-prepend">
<span class="input-group-text"><input type="radio" name="extractTargetLocation" value="custom"></span>
</div>
<input id="extractCustomLocation" type="text" class="form-control" placeholder="custom location" value="">
</div>
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="buttonExtract">{{i18n.extract}}</button>
<button type="button" class="btn btn-default" id="buttonCancel">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="buttonExtract">{{i18n.extract}}</button>
<button type="button" class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -4,12 +4,12 @@
<label>{{i18n.filename}}:</label>
<input type="text" class="form-control" name="filename" value="{{filename}}"><br>
<div id="content" name="content"></div><br>
<button type="button" class="btn btn-default" id="editoroptions">{{i18n.editor_options}}</button>
<button type="button" class="btn btn-secondary" id="editoroptions">{{i18n.editor_options}}</button>
</fieldset>
</div>
<div class="modal-footer">
<button type="button" id="buttonSave" class="btn btn-default">{{i18n.save}}</button>
<button type="button" id="buttonSaveNotClose" class="btn btn-default">{{i18n.save_wo_close}}</button>
<button type="button" id="buttonClose" class="btn btn-default">{{i18n.close}}</button>
<button type="button" id="buttonSave" class="btn btn-secondary">{{i18n.save}}</button>
<button type="button" id="buttonSaveNotClose" class="btn btn-secondary">{{i18n.save_wo_close}}</button>
<button type="button" id="buttonClose" class="btn btn-secondary">{{i18n.close}}</button>
</div>
</form>

View File

@ -1,14 +1,22 @@
<input type="checkbox" id="editor-wordwrap"
{{#wordwrap}}
checked="checked"
{{/wordwrap}}
> {{i18n.word_wrap}}</input><br>
<input type="checkbox" id="editor-softtabs"
{{#softtabs}}
checked="checked"
{{/softtabs}}
> {{i18n.soft_tabs}}</input>
<div class="input-group"><span class="input-group-addon">{{i18n.tab_size}}</span><input class="form-control" type="text" size="2" id="editor-tabsize" title="{{i18n.tab_size}}" value="{{tabsize}}"></div>
<div>
<div class="form-check p-0">
<input type="checkbox" id="editor-wordwrap"
{{#wordwrap}}
checked="checked"
{{/wordwrap}}
>
<label class="form-check-label" for="editor-wordwrap">{{i18n.word_wrap}}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="editor-softtabs"
{{#softtabs}}
checked="checked"
{{/softtabs}}
>
<label class="form-check-label" for="editor-softtabs">{{i18n.soft_tabs}}</label>
</div>
<div class="input-group">
<div class="input-group-prepend"><span class="input-group-text">{{i18n.tab_size}}</span></div><input class="form-control" type="text" size="2" id="editor-tabsize" title="{{i18n.tab_size}}" value="{{tabsize}}"></div>
{{#ace_includes}}
<select class="form-control selectpicker" data-toggle="dropdown" data-live-search="true" data-size="15" id="editor-syntax">
{{#modes}}
@ -16,3 +24,4 @@
{{/modes}}
</select>
{{/ace_includes}}
</div>

View File

@ -10,7 +10,7 @@
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="buttonUpload">{{i18n.upload}}</button>
<button type="button" class="btn btn-default" id="buttonCancel">{{i18n.cancel}}</button>
<button type="button" class="btn btn-secondary" id="buttonUpload">{{i18n.upload}}</button>
<button type="button" class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -6,7 +6,7 @@
</fieldset>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="buttonRename">{{i18n.file_rename}}</button>
<button type="button" class="btn btn-default" id="buttonCancel">{{i18n.cancel}} </button>
<button type="button" class="btn btn-secondary" id="buttonRename">{{i18n.file_rename}}</button>
<button type="button" class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}} </button>
</div>
</form>

View File

@ -2,13 +2,13 @@
<div class="modal-body">
<fieldset>
<label>{{i18n.upload_file}}</label><br>
<input class="file" type="file" name="files" multiple><br>
<input class="form-control-file" type="file" name="files" multiple><br>
<label>{{i18n.filename_new}}</label>
<input class="form-control" type="text" name="newfilename"><br>
</fieldset>
</div>
<div class="modal-footer">
<button class="btn btn-default" id="buttonUpload">{{i18n.upload}}</button>
<button class="btn btn-default" id="buttonCancel">{{i18n.cancel}}</button>
<button class="btn btn-secondary" id="buttonUpload">{{i18n.upload}}</button>
<button class="btn btn-secondary" id="buttonCancel">{{i18n.cancel}}</button>
</div>
</form>

View File

@ -1,8 +1,9 @@
<div id="{{id}}" class="panel panel-default">
<div class="panel-body">
<div id="{{id}}" class="card">
<div class="card-body">
<div class="progress">
<div class="progress-bar progress-bar-{{type}} progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemax="100" style="width:100%"></div>
<span class="progbarlabel">{{name}}</span>
<div class="progress-bar bg-{{type}} progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemax="100" style="width:100%">
{{name}}
</div>
</div>
</div>
</div>