From e720bce160ba1bae73ccd5c8de76e307025867b3 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Fri, 28 Jul 2017 15:36:33 +0200 Subject: [PATCH 01/11] added server-side search function --- build/libifm.php | 120 +++++++++++++++++++++++++++------------------ ifm.php | 120 +++++++++++++++++++++++++++------------------ src/main.php | 124 +++++++++++++++++++++++++++++------------------ 3 files changed, 226 insertions(+), 138 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index 26010dd..8aafba3 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -2206,6 +2206,7 @@ function IFM( params ) { case "zipnload": $this->zipnload( $_REQUEST); break; case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; case "multidelete": $this->deleteMultipleFiles( $_REQUEST ); break; + case "searchItems": $this->searchItems( $_REQUEST ); break; case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; default: echo json_encode( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); @@ -2253,52 +2254,8 @@ function IFM( params ) { elseif( $result == "." ) {} elseif( $result != ".." && substr( $result, 0, 1 ) == "." && $this->config['showhiddenfiles'] != 1 ) {} else { - $item = array(); - $item["name"] = $result; - if( is_dir( $result ) ) { - $item["type"] = "dir"; - if( $result == ".." ) - $item["icon"] = "icon icon-up-open"; - else - $item["icon"] = "icon icon-folder-empty"; - } else { - $item["type"] = "file"; - if( in_array( substr( $result, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) - $type = substr( $result, -6 ); - elseif( substr( $result, -8 ) == ".tar.bz2" ) - $type = "tar.bz2"; - else - $type = substr( strrchr( $result, "." ), 1 ); - $item["icon"] = $this->getTypeIcon( $type ); - $item["ext"] = strtolower($type); - } - if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); } - if( $this->config['showfilesize'] == 1 ) { - $item["size"] = filesize( $result ); - if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; - elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; - elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; - else $item["size"] = $item["size"] . " Byte"; - } - if( $this->config['showpermissions'] > 0 ) { - if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 ); - elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) ); - if( $item["fileperms"] == "" ) $item["fileperms"] = " "; - $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; - } - if( $this->config['showowner'] == 1 ) { - if ( function_exists( "posix_getpwuid" ) && fileowner($result) !== false ) { - $ownerarr = posix_getpwuid( fileowner( $result ) ); - $item["owner"] = $ownerarr['name']; - } else $item["owner"] = false; - } - if( $this->config['showgroup'] == 1 ) { - if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) { - $grouparr = posix_getgrgid( filegroup( $result ) ); - $item["group"] = $grouparr['name']; - } else $item["group"] = false; - } - if( is_dir( $result ) ) $dirs[] = $item; + $item = $this->getItemInformation( $result ); + if( $item['type'] == "dir" ) $dirs[] = $item; else $files[] = $item; } } @@ -2309,6 +2266,55 @@ function IFM( params ) { echo json_encode( array_merge( $dirs, $files ) ); } + private function getItemInformation( $name ) { + $item = array(); + $item["name"] = $name; + if( is_dir( $name ) ) { + $item["type"] = "dir"; + if( $name == ".." ) + $item["icon"] = "icon icon-up-open"; + else + $item["icon"] = "icon icon-folder-empty"; + } else { + $item["type"] = "file"; + if( in_array( substr( $name, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) + $type = substr( $name, -6 ); + elseif( substr( $name, -8 ) == ".tar.bz2" ) + $type = "tar.bz2"; + else + $type = substr( strrchr( $name, "." ), 1 ); + $item["icon"] = $this->getTypeIcon( $type ); + $item["ext"] = strtolower($type); + } + if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $name ) ); } + if( $this->config['showfilesize'] == 1 ) { + $item["size"] = filesize( $name ); + if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; + elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; + elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; + else $item["size"] = $item["size"] . " Byte"; + } + if( $this->config['showpermissions'] > 0 ) { + if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $name ) ), -3 ); + elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $name ) ); + if( $item["fileperms"] == "" ) $item["fileperms"] = " "; + $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; + } + if( $this->config['showowner'] == 1 ) { + if ( function_exists( "posix_getpwuid" ) && fileowner($name) !== false ) { + $ownerarr = posix_getpwuid( fileowner( $name ) ); + $item["owner"] = $ownerarr['name']; + } else $item["owner"] = false; + } + if( $this->config['showgroup'] == 1 ) { + if( function_exists( "posix_getgrgid" ) && filegroup( $name ) !== false ) { + $grouparr = posix_getgrgid( filegroup( $name ) ); + $item["group"] = $grouparr['name']; + } else $item["group"] = false; + } + return $item; + } + private function getConfig() { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; @@ -2345,6 +2351,28 @@ function IFM( params ) { } } + private function searchItems( $d ) { + $this->chDirIfNecessary( $d['dir'] ); + try { + $results = $this->searchItemsRecursive( $d['pattern'] ); + echo json_encode( $results ); + } catch( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + } + } + + private function searchItemsRecursive( $pattern, $dir="" ) { + $items = array(); + $dir = $dir ? $dir : '.'; + foreach( glob( $this->pathCombine( $dir, $pattern ) ) as $result ) { + array_push( $items, $this->getItemInformation( $result ) ); + } + foreach( glob( $this->pathCombine( $dir, '*') , GLOB_ONLYDIR ) as $subdir ) { + $items = array_merge( $items, $this->searchItemsRecursive( $pattern, $subdir ) ); + } + return $items; + } + private function getFolderTree( $d ) { echo json_encode( array_merge( diff --git a/ifm.php b/ifm.php index fac3357..6d390d2 100644 --- a/ifm.php +++ b/ifm.php @@ -2206,6 +2206,7 @@ function IFM( params ) { case "zipnload": $this->zipnload( $_REQUEST); break; case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; case "multidelete": $this->deleteMultipleFiles( $_REQUEST ); break; + case "searchItems": $this->searchItems( $_REQUEST ); break; case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; default: echo json_encode( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); @@ -2253,52 +2254,8 @@ function IFM( params ) { elseif( $result == "." ) {} elseif( $result != ".." && substr( $result, 0, 1 ) == "." && $this->config['showhiddenfiles'] != 1 ) {} else { - $item = array(); - $item["name"] = $result; - if( is_dir( $result ) ) { - $item["type"] = "dir"; - if( $result == ".." ) - $item["icon"] = "icon icon-up-open"; - else - $item["icon"] = "icon icon-folder-empty"; - } else { - $item["type"] = "file"; - if( in_array( substr( $result, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) - $type = substr( $result, -6 ); - elseif( substr( $result, -8 ) == ".tar.bz2" ) - $type = "tar.bz2"; - else - $type = substr( strrchr( $result, "." ), 1 ); - $item["icon"] = $this->getTypeIcon( $type ); - $item["ext"] = strtolower($type); - } - if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); } - if( $this->config['showfilesize'] == 1 ) { - $item["size"] = filesize( $result ); - if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; - elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; - elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; - else $item["size"] = $item["size"] . " Byte"; - } - if( $this->config['showpermissions'] > 0 ) { - if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 ); - elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) ); - if( $item["fileperms"] == "" ) $item["fileperms"] = " "; - $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; - } - if( $this->config['showowner'] == 1 ) { - if ( function_exists( "posix_getpwuid" ) && fileowner($result) !== false ) { - $ownerarr = posix_getpwuid( fileowner( $result ) ); - $item["owner"] = $ownerarr['name']; - } else $item["owner"] = false; - } - if( $this->config['showgroup'] == 1 ) { - if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) { - $grouparr = posix_getgrgid( filegroup( $result ) ); - $item["group"] = $grouparr['name']; - } else $item["group"] = false; - } - if( is_dir( $result ) ) $dirs[] = $item; + $item = $this->getItemInformation( $result ); + if( $item['type'] == "dir" ) $dirs[] = $item; else $files[] = $item; } } @@ -2309,6 +2266,55 @@ function IFM( params ) { echo json_encode( array_merge( $dirs, $files ) ); } + private function getItemInformation( $name ) { + $item = array(); + $item["name"] = $name; + if( is_dir( $name ) ) { + $item["type"] = "dir"; + if( $name == ".." ) + $item["icon"] = "icon icon-up-open"; + else + $item["icon"] = "icon icon-folder-empty"; + } else { + $item["type"] = "file"; + if( in_array( substr( $name, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) + $type = substr( $name, -6 ); + elseif( substr( $name, -8 ) == ".tar.bz2" ) + $type = "tar.bz2"; + else + $type = substr( strrchr( $name, "." ), 1 ); + $item["icon"] = $this->getTypeIcon( $type ); + $item["ext"] = strtolower($type); + } + if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $name ) ); } + if( $this->config['showfilesize'] == 1 ) { + $item["size"] = filesize( $name ); + if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; + elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; + elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; + else $item["size"] = $item["size"] . " Byte"; + } + if( $this->config['showpermissions'] > 0 ) { + if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $name ) ), -3 ); + elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $name ) ); + if( $item["fileperms"] == "" ) $item["fileperms"] = " "; + $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; + } + if( $this->config['showowner'] == 1 ) { + if ( function_exists( "posix_getpwuid" ) && fileowner($name) !== false ) { + $ownerarr = posix_getpwuid( fileowner( $name ) ); + $item["owner"] = $ownerarr['name']; + } else $item["owner"] = false; + } + if( $this->config['showgroup'] == 1 ) { + if( function_exists( "posix_getgrgid" ) && filegroup( $name ) !== false ) { + $grouparr = posix_getgrgid( filegroup( $name ) ); + $item["group"] = $grouparr['name']; + } else $item["group"] = false; + } + return $item; + } + private function getConfig() { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; @@ -2345,6 +2351,28 @@ function IFM( params ) { } } + private function searchItems( $d ) { + $this->chDirIfNecessary( $d['dir'] ); + try { + $results = $this->searchItemsRecursive( $d['pattern'] ); + echo json_encode( $results ); + } catch( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + } + } + + private function searchItemsRecursive( $pattern, $dir="" ) { + $items = array(); + $dir = $dir ? $dir : '.'; + foreach( glob( $this->pathCombine( $dir, $pattern ) ) as $result ) { + array_push( $items, $this->getItemInformation( $result ) ); + } + foreach( glob( $this->pathCombine( $dir, '*') , GLOB_ONLYDIR ) as $subdir ) { + $items = array_merge( $items, $this->searchItemsRecursive( $pattern, $subdir ) ); + } + return $items; + } + private function getFolderTree( $d ) { echo json_encode( array_merge( diff --git a/src/main.php b/src/main.php index 68e2f32..58b3c99 100644 --- a/src/main.php +++ b/src/main.php @@ -243,6 +243,7 @@ f00bar; case "zipnload": $this->zipnload( $_REQUEST); break; case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; case "multidelete": $this->deleteMultipleFiles( $_REQUEST ); break; + case "searchItems": $this->searchItems( $_REQUEST ); break; case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; default: echo json_encode( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); @@ -290,52 +291,8 @@ f00bar; elseif( $result == "." ) {} elseif( $result != ".." && substr( $result, 0, 1 ) == "." && $this->config['showhiddenfiles'] != 1 ) {} else { - $item = array(); - $item["name"] = $result; - if( is_dir( $result ) ) { - $item["type"] = "dir"; - if( $result == ".." ) - $item["icon"] = "icon icon-up-open"; - else - $item["icon"] = "icon icon-folder-empty"; - } else { - $item["type"] = "file"; - if( in_array( substr( $result, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) - $type = substr( $result, -6 ); - elseif( substr( $result, -8 ) == ".tar.bz2" ) - $type = "tar.bz2"; - else - $type = substr( strrchr( $result, "." ), 1 ); - $item["icon"] = $this->getTypeIcon( $type ); - $item["ext"] = strtolower($type); - } - if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); } - if( $this->config['showfilesize'] == 1 ) { - $item["size"] = filesize( $result ); - if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; - elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; - elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; - else $item["size"] = $item["size"] . " Byte"; - } - if( $this->config['showpermissions'] > 0 ) { - if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 ); - elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) ); - if( $item["fileperms"] == "" ) $item["fileperms"] = " "; - $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; - } - if( $this->config['showowner'] == 1 ) { - if ( function_exists( "posix_getpwuid" ) && fileowner($result) !== false ) { - $ownerarr = posix_getpwuid( fileowner( $result ) ); - $item["owner"] = $ownerarr['name']; - } else $item["owner"] = false; - } - if( $this->config['showgroup'] == 1 ) { - if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) { - $grouparr = posix_getgrgid( filegroup( $result ) ); - $item["group"] = $grouparr['name']; - } else $item["group"] = false; - } - if( is_dir( $result ) ) $dirs[] = $item; + $item = $this->getItemInformation( $result ); + if( $item['type'] == "dir" ) $dirs[] = $item; else $files[] = $item; } } @@ -346,6 +303,55 @@ f00bar; echo json_encode( array_merge( $dirs, $files ) ); } + private function getItemInformation( $name ) { + $item = array(); + $item["name"] = $name; + if( is_dir( $name ) ) { + $item["type"] = "dir"; + if( $name == ".." ) + $item["icon"] = "icon icon-up-open"; + else + $item["icon"] = "icon icon-folder-empty"; + } else { + $item["type"] = "file"; + if( in_array( substr( $name, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) + $type = substr( $name, -6 ); + elseif( substr( $name, -8 ) == ".tar.bz2" ) + $type = "tar.bz2"; + else + $type = substr( strrchr( $name, "." ), 1 ); + $item["icon"] = $this->getTypeIcon( $type ); + $item["ext"] = strtolower($type); + } + if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $name ) ); } + if( $this->config['showfilesize'] == 1 ) { + $item["size"] = filesize( $name ); + if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; + elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; + elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; + else $item["size"] = $item["size"] . " Byte"; + } + if( $this->config['showpermissions'] > 0 ) { + if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $name ) ), -3 ); + elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $name ) ); + if( $item["fileperms"] == "" ) $item["fileperms"] = " "; + $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; + } + if( $this->config['showowner'] == 1 ) { + if ( function_exists( "posix_getpwuid" ) && fileowner($name) !== false ) { + $ownerarr = posix_getpwuid( fileowner( $name ) ); + $item["owner"] = $ownerarr['name']; + } else $item["owner"] = false; + } + if( $this->config['showgroup'] == 1 ) { + if( function_exists( "posix_getgrgid" ) && filegroup( $name ) !== false ) { + $grouparr = posix_getgrgid( filegroup( $name ) ); + $item["group"] = $grouparr['name']; + } else $item["group"] = false; + } + return $item; + } + private function getConfig() { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; @@ -382,6 +388,32 @@ f00bar; } } + 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" ) ); + exit( 1 ); + } + try { + $results = $this->searchItemsRecursive( $d['pattern'] ); + echo json_encode( $results ); + } catch( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + } + } + + private function searchItemsRecursive( $pattern, $dir="" ) { + $items = array(); + $dir = $dir ? $dir : '.'; + foreach( glob( $this->pathCombine( $dir, $pattern ) ) as $result ) { + array_push( $items, $this->getItemInformation( $result ) ); + } + foreach( glob( $this->pathCombine( $dir, '*') , GLOB_ONLYDIR ) as $subdir ) { + $items = array_merge( $items, $this->searchItemsRecursive( $pattern, $subdir ) ); + } + return $items; + } + private function getFolderTree( $d ) { echo json_encode( array_merge( From 18c48c806bd38b72a4736367f309fcde289bc926 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Sun, 30 Jul 2017 05:20:07 +0200 Subject: [PATCH 02/11] added search function to the frontend; fixed some bugs --- build/libifm.php | 148 ++++++++++++++++++++++++- ifm.php | 148 ++++++++++++++++++++++++- src/ifm.js | 56 ++++++++++ src/main.php | 60 +++++++++- src/templates/modal.search.html | 10 ++ src/templates/modal.searchresults.html | 11 ++ 6 files changed, 419 insertions(+), 14 deletions(-) create mode 100644 src/templates/modal.search.html create mode 100644 src/templates/modal.searchresults.html diff --git a/build/libifm.php b/build/libifm.php index 8aafba3..facc4d1 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -478,6 +478,33 @@ f00bar; +f00bar; + $templates['search'] = <<<'f00bar' +
+ +
+ +f00bar; + $templates['searchresults'] = <<<'f00bar' + +{{#items}} + + + + {{linkname}} ({{folder}}) + + + +{{/items}} + + f00bar; $templates['uploadfile'] = <<<'f00bar'
@@ -786,6 +813,7 @@ function IFM( params ) { 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 = ""; + this.search = {}; /** * Shows a bootstrap modal @@ -840,7 +868,9 @@ function IFM( params ) { dir: self.currentDir }, dataType: "json", - success: self.rebuildFileTable, + success: function( data ) { + self.rebuildFileTable( data ); + }, error: function( response ) { self.showMessage( "General error occured: No or broken response", "e" ); }, complete: function() { self.task_done( id ); } }); @@ -852,6 +882,13 @@ function IFM( params ) { * @param object data - object with items */ this.rebuildFileTable = function( data ) { + if( data.status == "ERROR" ) { + this.showMessage( data.message, "e" ); + return; + } else if ( ! Array.isArray( data ) ) { + this.showMessage( "Invalid data from server", "e" ); + return; + } data.forEach( function( item ) { item.guid = self.generateGuid(); item.linkname = ( item.name == ".." ) ? "[ up ]" : item.name; @@ -1622,6 +1659,50 @@ function IFM( params ) { }); }; + this.showSearchDialog = function() { + self.showModal( Mustache.render( self.templates.search, { lastSearch: self.search.lastSearch } ) ); + $( '#searchResults tbody' ).remove(); + $( '#searchResults' ).append( Mustache.render( self.templates.searchresults, { items: self.search.data } ) ); + $( '#searchPattern' ).on( 'keypress', function( e ) { + if( e.keyCode == 13 ) { + e.preventDefault(); + e.stopPropagation(); + self.search.lastSearch = e.target.value; + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "searchItems", + dir: self.currentDir, + pattern: e.target.value + }, + 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 ); + }); + self.search.data = data; + $('#searchResults').html( Mustache.render( self.templates.searchresults, { items: data } ) ); + } + }); + } + }); + $( document ).on( 'click', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + e.stopPropagation(); + self.changeDirectory( e.target.dataset.folder || e.target.parentNode.dataset.folder, { absolute: true } ); + self.hideModal(); + }); + $( document ).on( 'keypress', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + if( e.key == "Enter" ) + e.target.click(); + }); + } + // -------------------- // helper functions // -------------------- @@ -1871,6 +1952,10 @@ function IFM( params ) { return; switch( e.key ) { + case '/': + e.preventDefault(); + self.showSearchDialog(); + break; case 'g': e.preventDefault(); $('#currentDir').focus(); @@ -2242,7 +2327,7 @@ function IFM( params ) { */ private function getFiles( $dir ) { - $dir = $this->getValidDir( $dir ); + $this->log( '$dir: '.$dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -2263,7 +2348,10 @@ function IFM( params ) { } usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - echo json_encode( array_merge( $dirs, $files ) ); + + $this->log( '$files: '.print_r($files, true ) ); + $this->log( '$dirs: '.print_r($dirs, true ) ); + $this->jsonResponse( array_merge( $dirs, $files ) ); } private function getItemInformation( $name ) { @@ -2353,6 +2441,10 @@ 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" ) ); + exit( 1 ); + } try { $results = $this->searchItemsRecursive( $d['pattern'] ); echo json_encode( $results ); @@ -2788,12 +2880,58 @@ function IFM( params ) { echo json_encode( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } - //apis - /* help functions */ + private function log( $string ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), $string, FILE_APPEND ); + } + + private function jsonResponse( $array ) { + $this->convertToUTF8( $array ); + $json = json_encode( $array ); + if( $json === false ) { + switch(json_last_error()) { + case JSON_ERROR_NONE: + $err = ' - Keine Fehler'; + break; + case JSON_ERROR_DEPTH: + $err = ' - Maximale Stacktiefe überschritten'; + break; + case JSON_ERROR_STATE_MISMATCH: + $err = ' - Unterlauf oder Nichtübereinstimmung der Modi'; + break; + case JSON_ERROR_CTRL_CHAR: + $err = ' - Unerwartetes Steuerzeichen gefunden'; + break; + case JSON_ERROR_SYNTAX: + $err = ' - Syntaxfehler, ungültiges JSON'; + break; + case JSON_ERROR_UTF8: + $err = ' - Missgestaltete UTF-8 Zeichen, möglicherweise fehlerhaft kodiert'; + break; + default: + $err = ' - Unbekannter Fehler'; + break; + } + + $this->jsonResponse( array( "status" => "ERROR", "message" => $err ) ); + } else { + echo $json; + } + } + + private function convertToUTF8( &$item ) { + if( is_array( $item ) ) + array_walk( + $item, + array( $this, 'convertToUTF8' ) + ); + else + $item = utf8_encode( $item ); + } + public function checkAuth() { if( $this->config['auth'] == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) { $login_failed = false; diff --git a/ifm.php b/ifm.php index 6d390d2..ffeb78f 100644 --- a/ifm.php +++ b/ifm.php @@ -478,6 +478,33 @@ f00bar;
+f00bar; + $templates['search'] = <<<'f00bar' +
+ +
+ +f00bar; + $templates['searchresults'] = <<<'f00bar' + +{{#items}} + + + + {{linkname}} ({{folder}}) + + + +{{/items}} + + f00bar; $templates['uploadfile'] = <<<'f00bar'
@@ -786,6 +813,7 @@ function IFM( params ) { 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 = ""; + this.search = {}; /** * Shows a bootstrap modal @@ -840,7 +868,9 @@ function IFM( params ) { dir: self.currentDir }, dataType: "json", - success: self.rebuildFileTable, + success: function( data ) { + self.rebuildFileTable( data ); + }, error: function( response ) { self.showMessage( "General error occured: No or broken response", "e" ); }, complete: function() { self.task_done( id ); } }); @@ -852,6 +882,13 @@ function IFM( params ) { * @param object data - object with items */ this.rebuildFileTable = function( data ) { + if( data.status == "ERROR" ) { + this.showMessage( data.message, "e" ); + return; + } else if ( ! Array.isArray( data ) ) { + this.showMessage( "Invalid data from server", "e" ); + return; + } data.forEach( function( item ) { item.guid = self.generateGuid(); item.linkname = ( item.name == ".." ) ? "[ up ]" : item.name; @@ -1622,6 +1659,50 @@ function IFM( params ) { }); }; + this.showSearchDialog = function() { + self.showModal( Mustache.render( self.templates.search, { lastSearch: self.search.lastSearch } ) ); + $( '#searchResults tbody' ).remove(); + $( '#searchResults' ).append( Mustache.render( self.templates.searchresults, { items: self.search.data } ) ); + $( '#searchPattern' ).on( 'keypress', function( e ) { + if( e.keyCode == 13 ) { + e.preventDefault(); + e.stopPropagation(); + self.search.lastSearch = e.target.value; + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "searchItems", + dir: self.currentDir, + pattern: e.target.value + }, + 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 ); + }); + self.search.data = data; + $('#searchResults').html( Mustache.render( self.templates.searchresults, { items: data } ) ); + } + }); + } + }); + $( document ).on( 'click', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + e.stopPropagation(); + self.changeDirectory( e.target.dataset.folder || e.target.parentNode.dataset.folder, { absolute: true } ); + self.hideModal(); + }); + $( document ).on( 'keypress', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + if( e.key == "Enter" ) + e.target.click(); + }); + } + // -------------------- // helper functions // -------------------- @@ -1871,6 +1952,10 @@ function IFM( params ) { return; switch( e.key ) { + case '/': + e.preventDefault(); + self.showSearchDialog(); + break; case 'g': e.preventDefault(); $('#currentDir').focus(); @@ -2242,7 +2327,7 @@ function IFM( params ) { */ private function getFiles( $dir ) { - $dir = $this->getValidDir( $dir ); + $this->log( '$dir: '.$dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -2263,7 +2348,10 @@ function IFM( params ) { } usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - echo json_encode( array_merge( $dirs, $files ) ); + + $this->log( '$files: '.print_r($files, true ) ); + $this->log( '$dirs: '.print_r($dirs, true ) ); + $this->jsonResponse( array_merge( $dirs, $files ) ); } private function getItemInformation( $name ) { @@ -2353,6 +2441,10 @@ 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" ) ); + exit( 1 ); + } try { $results = $this->searchItemsRecursive( $d['pattern'] ); echo json_encode( $results ); @@ -2788,12 +2880,58 @@ function IFM( params ) { echo json_encode( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } - //apis - /* help functions */ + private function log( $string ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), $string, FILE_APPEND ); + } + + private function jsonResponse( $array ) { + $this->convertToUTF8( $array ); + $json = json_encode( $array ); + if( $json === false ) { + switch(json_last_error()) { + case JSON_ERROR_NONE: + $err = ' - Keine Fehler'; + break; + case JSON_ERROR_DEPTH: + $err = ' - Maximale Stacktiefe überschritten'; + break; + case JSON_ERROR_STATE_MISMATCH: + $err = ' - Unterlauf oder Nichtübereinstimmung der Modi'; + break; + case JSON_ERROR_CTRL_CHAR: + $err = ' - Unerwartetes Steuerzeichen gefunden'; + break; + case JSON_ERROR_SYNTAX: + $err = ' - Syntaxfehler, ungültiges JSON'; + break; + case JSON_ERROR_UTF8: + $err = ' - Missgestaltete UTF-8 Zeichen, möglicherweise fehlerhaft kodiert'; + break; + default: + $err = ' - Unbekannter Fehler'; + break; + } + + $this->jsonResponse( array( "status" => "ERROR", "message" => $err ) ); + } else { + echo $json; + } + } + + private function convertToUTF8( &$item ) { + if( is_array( $item ) ) + array_walk( + $item, + array( $this, 'convertToUTF8' ) + ); + else + $item = utf8_encode( $item ); + } + public function checkAuth() { if( $this->config['auth'] == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) { $login_failed = false; diff --git a/src/ifm.js b/src/ifm.js index 4dddb86..041b532 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -14,6 +14,7 @@ function IFM( params ) { 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 = ""; + this.search = {}; /** * Shows a bootstrap modal @@ -80,6 +81,13 @@ function IFM( params ) { * @param object data - object with items */ this.rebuildFileTable = function( data ) { + if( data.status == "ERROR" ) { + this.showMessage( data.message, "e" ); + return; + } else if ( ! Array.isArray( data ) ) { + this.showMessage( "Invalid data from server", "e" ); + return; + } data.forEach( function( item ) { item.guid = self.generateGuid(); item.linkname = ( item.name == ".." ) ? "[ up ]" : item.name; @@ -850,6 +858,50 @@ function IFM( params ) { }); }; + this.showSearchDialog = function() { + self.showModal( Mustache.render( self.templates.search, { lastSearch: self.search.lastSearch } ) ); + $( '#searchResults tbody' ).remove(); + $( '#searchResults' ).append( Mustache.render( self.templates.searchresults, { items: self.search.data } ) ); + $( '#searchPattern' ).on( 'keypress', function( e ) { + if( e.keyCode == 13 ) { + e.preventDefault(); + e.stopPropagation(); + self.search.lastSearch = e.target.value; + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "searchItems", + dir: self.currentDir, + pattern: e.target.value + }, + 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 ); + }); + self.search.data = data; + $('#searchResults').html( Mustache.render( self.templates.searchresults, { items: data } ) ); + } + }); + } + }); + $( document ).on( 'click', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + e.stopPropagation(); + self.changeDirectory( e.target.dataset.folder || e.target.parentNode.dataset.folder, { absolute: true } ); + self.hideModal(); + }); + $( document ).on( 'keypress', 'a.searchitem', function( e ) { + console.log( e ); + e.preventDefault(); + if( e.key == "Enter" ) + e.target.click(); + }); + } + // -------------------- // helper functions // -------------------- @@ -1099,6 +1151,10 @@ function IFM( params ) { return; switch( e.key ) { + case '/': + e.preventDefault(); + self.showSearchDialog(); + break; case 'g': e.preventDefault(); $('#currentDir').focus(); diff --git a/src/main.php b/src/main.php index 58b3c99..3364a0a 100644 --- a/src/main.php +++ b/src/main.php @@ -136,6 +136,12 @@ f00bar; f00bar; $templates['renamefile'] = <<<'f00bar' @@@src/templates/modal.renamefile.html@@@ +f00bar; + $templates['search'] = <<<'f00bar' +@@@src/templates/modal.search.html@@@ +f00bar; + $templates['searchresults'] = <<<'f00bar' +@@@src/templates/modal.searchresults.html@@@ f00bar; $templates['uploadfile'] = <<<'f00bar' @@@src/templates/modal.uploadfile.html@@@ @@ -279,7 +285,6 @@ f00bar; */ private function getFiles( $dir ) { - $dir = $this->getValidDir( $dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -300,7 +305,8 @@ f00bar; } usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - echo json_encode( array_merge( $dirs, $files ) ); + + $this->jsonResponse( array_merge( $dirs, $files ) ); } private function getItemInformation( $name ) { @@ -829,12 +835,58 @@ f00bar; echo json_encode( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } - //apis - /* help functions */ + private function log( $d ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), ( is_array( $d ) ? print_r( $d, true ) : $d ), FILE_APPEND ); + } + + private function jsonResponse( $array ) { + $this->convertToUTF8( $array ); + $json = json_encode( $array ); + if( $json === false ) { + switch(json_last_error()) { + case JSON_ERROR_NONE: + echo ' - No errors'; + break; + case JSON_ERROR_DEPTH: + echo ' - Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + echo ' - Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + echo ' - Unexpected control character found'; + break; + case JSON_ERROR_SYNTAX: + echo ' - Syntax error, malformed JSON'; + break; + case JSON_ERROR_UTF8: + echo ' - Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + echo ' - Unknown error'; + break; + } + + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not encode json: " . $err ) ); + } else { + echo $json; + } + } + + private function convertToUTF8( &$item ) { + if( is_array( $item ) ) + array_walk( + $item, + array( $this, 'convertToUTF8' ) + ); + else + $item = utf8_encode( $item ); + } + public function checkAuth() { if( $this->config['auth'] == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) { $login_failed = false; diff --git a/src/templates/modal.search.html b/src/templates/modal.search.html new file mode 100644 index 0000000..469ffda --- /dev/null +++ b/src/templates/modal.search.html @@ -0,0 +1,10 @@ + + +
diff --git a/src/templates/modal.searchresults.html b/src/templates/modal.searchresults.html new file mode 100644 index 0000000..486d9dd --- /dev/null +++ b/src/templates/modal.searchresults.html @@ -0,0 +1,11 @@ + +{{#items}} + + + + {{linkname}} ({{folder}}) + + + +{{/items}} + From bfbee57fee8c9772d74e9a3ab6915a3d09a19beb Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Sun, 30 Jul 2017 05:24:34 +0200 Subject: [PATCH 03/11] new builds --- build/libifm.php | 29 ++++++++++++----------------- ifm.php | 29 ++++++++++++----------------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index facc4d1..ee23154 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -868,9 +868,7 @@ function IFM( params ) { dir: self.currentDir }, dataType: "json", - success: function( data ) { - self.rebuildFileTable( data ); - }, + success: self.rebuildFileTable, error: function( response ) { self.showMessage( "General error occured: No or broken response", "e" ); }, complete: function() { self.task_done( id ); } }); @@ -2327,7 +2325,6 @@ function IFM( params ) { */ private function getFiles( $dir ) { - $this->log( '$dir: '.$dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -2349,8 +2346,6 @@ function IFM( params ) { usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - $this->log( '$files: '.print_r($files, true ) ); - $this->log( '$dirs: '.print_r($dirs, true ) ); $this->jsonResponse( array_merge( $dirs, $files ) ); } @@ -2884,8 +2879,8 @@ function IFM( params ) { help functions */ - private function log( $string ) { - file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), $string, FILE_APPEND ); + private function log( $d ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), ( is_array( $d ) ? print_r( $d, true ) : $d ), FILE_APPEND ); } private function jsonResponse( $array ) { @@ -2894,29 +2889,29 @@ function IFM( params ) { if( $json === false ) { switch(json_last_error()) { case JSON_ERROR_NONE: - $err = ' - Keine Fehler'; + echo ' - No errors'; break; case JSON_ERROR_DEPTH: - $err = ' - Maximale Stacktiefe überschritten'; + echo ' - Maximum stack depth exceeded'; break; case JSON_ERROR_STATE_MISMATCH: - $err = ' - Unterlauf oder Nichtübereinstimmung der Modi'; + echo ' - Underflow or the modes mismatch'; break; case JSON_ERROR_CTRL_CHAR: - $err = ' - Unerwartetes Steuerzeichen gefunden'; + echo ' - Unexpected control character found'; break; case JSON_ERROR_SYNTAX: - $err = ' - Syntaxfehler, ungültiges JSON'; + echo ' - Syntax error, malformed JSON'; break; case JSON_ERROR_UTF8: - $err = ' - Missgestaltete UTF-8 Zeichen, möglicherweise fehlerhaft kodiert'; + echo ' - Malformed UTF-8 characters, possibly incorrectly encoded'; break; default: - $err = ' - Unbekannter Fehler'; + echo ' - Unknown error'; break; } - - $this->jsonResponse( array( "status" => "ERROR", "message" => $err ) ); + + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not encode json: " . $err ) ); } else { echo $json; } diff --git a/ifm.php b/ifm.php index ffeb78f..62a82b9 100644 --- a/ifm.php +++ b/ifm.php @@ -868,9 +868,7 @@ function IFM( params ) { dir: self.currentDir }, dataType: "json", - success: function( data ) { - self.rebuildFileTable( data ); - }, + success: self.rebuildFileTable, error: function( response ) { self.showMessage( "General error occured: No or broken response", "e" ); }, complete: function() { self.task_done( id ); } }); @@ -2327,7 +2325,6 @@ function IFM( params ) { */ private function getFiles( $dir ) { - $this->log( '$dir: '.$dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -2349,8 +2346,6 @@ function IFM( params ) { usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - $this->log( '$files: '.print_r($files, true ) ); - $this->log( '$dirs: '.print_r($dirs, true ) ); $this->jsonResponse( array_merge( $dirs, $files ) ); } @@ -2884,8 +2879,8 @@ function IFM( params ) { help functions */ - private function log( $string ) { - file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), $string, FILE_APPEND ); + private function log( $d ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), ( is_array( $d ) ? print_r( $d, true ) : $d ), FILE_APPEND ); } private function jsonResponse( $array ) { @@ -2894,29 +2889,29 @@ function IFM( params ) { if( $json === false ) { switch(json_last_error()) { case JSON_ERROR_NONE: - $err = ' - Keine Fehler'; + echo ' - No errors'; break; case JSON_ERROR_DEPTH: - $err = ' - Maximale Stacktiefe überschritten'; + echo ' - Maximum stack depth exceeded'; break; case JSON_ERROR_STATE_MISMATCH: - $err = ' - Unterlauf oder Nichtübereinstimmung der Modi'; + echo ' - Underflow or the modes mismatch'; break; case JSON_ERROR_CTRL_CHAR: - $err = ' - Unerwartetes Steuerzeichen gefunden'; + echo ' - Unexpected control character found'; break; case JSON_ERROR_SYNTAX: - $err = ' - Syntaxfehler, ungültiges JSON'; + echo ' - Syntax error, malformed JSON'; break; case JSON_ERROR_UTF8: - $err = ' - Missgestaltete UTF-8 Zeichen, möglicherweise fehlerhaft kodiert'; + echo ' - Malformed UTF-8 characters, possibly incorrectly encoded'; break; default: - $err = ' - Unbekannter Fehler'; + echo ' - Unknown error'; break; } - - $this->jsonResponse( array( "status" => "ERROR", "message" => $err ) ); + + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not encode json: " . $err ) ); } else { echo $json; } From 524a01b5df9a7688b36a4c2d314e19b5a18d6cab Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 31 Jul 2017 00:18:16 +0200 Subject: [PATCH 04/11] Added basic context menu, like requested in #47. Still a lot functions missing. --- build/libifm.php | 36 +++++++++++++++++++++++++++++++++++- ifm.php | 36 +++++++++++++++++++++++++++++++++++- src/ifm.js | 19 ++++++++++++++++++- src/main.php | 2 ++ 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/build/libifm.php b/build/libifm.php index ee23154..0ae52fd 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -49,6 +49,7 @@ class IFM { "showhtdocs" => 0, "showhiddenfiles" => 1, "showpath" => 0, + "contextmenu" => 1 ); private $config = array(); @@ -795,6 +796,22 @@ if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires j this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); + + + '; From 2d9ceb7f6b5aac8604a741b45a1dc75620873eb9 Mon Sep 17 00:00:00 2001 From: Marco Dickert Date: Mon, 31 Jul 2017 09:03:51 +0200 Subject: [PATCH 05/11] added missing bootstrap menu library --- src/includes/BootstrapMenu.min.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/includes/BootstrapMenu.min.js diff --git a/src/includes/BootstrapMenu.min.js b/src/includes/BootstrapMenu.min.js new file mode 100644 index 0000000..4934a19 --- /dev/null +++ b/src/includes/BootstrapMenu.min.js @@ -0,0 +1,16 @@ +!function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={exports:{},id:e,loaded:!1};return t[e].call(i.exports,i,i.exports,n),i.loaded=!0,i.exports}var o={};return n.m=t,n.c=o,n.p="",n(0)}([function(t,n,o){window.BootstrapMenu=o(1)},function(t,n,o){"use strict";function e(t){var n=f('