diff --git a/.gitignore b/.gitignore index 59492093ad..0c05e127de 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,6 @@ web.config /twig-templates/ # Backups *~ -# Javascript line counts -/js/line_counts.php # API documentation /apidoc/ /doc/linkcheck/ diff --git a/doc/faq.rst b/doc/faq.rst index 591e912220..e8c0458e2b 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -686,7 +686,7 @@ A list of files and corresponding functionality which degrade gracefully when re * :file:`./locale/` folder, or unused subfolders (interface translations) * Any unused themes in :file:`./themes/` * :file:`./js/vendor/jquery/src/` (included for licensing reasons) -* :file:`./js/line_counts.php` +* :file:`./js/line_counts.php` (removed in phpMyAdmin 4.8) * :file:`./doc/` (documentation) * :file:`./setup/` (setup script) * :file:`./examples/` diff --git a/js/ajax.js b/js/ajax.js index 011980b646..da1e37e892 100644 --- a/js/ajax.js +++ b/js/ajax.js @@ -534,9 +534,10 @@ var AJAX = { _scriptsToBeLoaded: [], /** * @var array _scriptsToBeFired The list of files for which - * to fire the onload event + * to fire the onload and unload events */ _scriptsToBeFired: [], + _scriptsCompleted: false, /** * Records that a file has been downloaded * @@ -572,7 +573,7 @@ var AJAX = { self._scripts = []; self._scriptsVersion = PMA_commonParams.get('PMA_VERSION'); } - self._scriptsToBeLoaded = []; + self._scriptsCompleted = false; self._scriptsToBeFired = []; for (var i in files) { self._scriptsToBeLoaded.push(files[i].name); @@ -580,64 +581,60 @@ var AJAX = { self._scriptsToBeFired.push(files[i].name); } } - // Generate a request string - var request = []; - var needRequest = false; - for (var index in self._scriptsToBeLoaded) { - var script = self._scriptsToBeLoaded[index]; + for (var i in files) { + var script = files[i].name; // Only for scripts that we don't already have if ($.inArray(script, self._scripts) === -1) { - needRequest = true; this.add(script); - request.push('scripts%5B%5D=' + script); - if (request.length >= 10) { - // Download scripts in chunks - this.appendScript(request); - request = []; - needRequest = false; - } + this.appendScript(script, callback); + } else { + self.done(script, callback); } } - request.push('call_done=1'); - request.push('v=' + encodeURIComponent(PMA_commonParams.get('PMA_VERSION'))); - // Download the composite js file, if necessary - if (needRequest) { - this.appendScript(request); - } else { - self.done(callback); - } + // Trigger callback if there is nothing to load + self.done(null, callback); }, /** * Called whenever all files are loaded * * @return void */ - done: function (callback) { - if ($.isFunction(callback)) { - callback(); - } + done: function (script, callback) { if (typeof ErrorReport !== 'undefined') { ErrorReport.wrap_global_functions(); } - for (var i in this._scriptsToBeFired) { - AJAX.fireOnload(this._scriptsToBeFired[i]); + if ($.inArray(script, this._scriptsToBeFired)) { + AJAX.fireOnload(script); + } + if ($.inArray(script, this._scriptsToBeLoaded)) { + this._scriptsToBeLoaded.splice($.inArray(script, this._scriptsToBeLoaded), 1); + } + if (script === null) { + this._scriptsCompleted = true; + } + /* We need to wait for last signal (with null) or last script load */ + AJAX.active = (this._scriptsToBeLoaded.length > 0) || ! this._scriptsCompleted; + /* Run callback on last script */ + if (! AJAX.active && $.isFunction(callback)) { + callback(); } - AJAX.active = false; }, /** * Appends a script element to the head to load the scripts * * @return void */ - appendScript: function (request) { + appendScript: function (name, callback) { var head = document.head || document.getElementsByTagName('head')[0]; var script = document.createElement('script'); + var self = this; - request.push('call_done=1'); - request.push('v=' + encodeURIComponent(PMA_commonParams.get('PMA_VERSION'))); script.type = 'text/javascript'; - script.src = 'js/get_scripts.js.php?' + request.join('&'); + script.src = 'js/' + name + '?' + 'v=' + encodeURIComponent(PMA_commonParams.get('PMA_VERSION')); script.async = false; + script.onload = function () { + self.done(name, callback); + }; head.appendChild(script); }, /** diff --git a/js/get_scripts.js.php b/js/get_scripts.js.php deleted file mode 100644 index 2605ff9f6e..0000000000 --- a/js/get_scripts.js.php +++ /dev/null @@ -1,72 +0,0 @@ -start(); -if (!defined('TESTSUITE')) { - register_shutdown_function( - function () { - echo PhpMyAdmin\OutputBuffering::getInstance()->getContents(); - } - ); -} - -$_GET['scripts'] = json_decode($_GET['scripts']); -if (! empty($_GET['scripts']) && is_array($_GET['scripts'])) { - // Only up to 10 scripts as this is what we generate - foreach (array_slice($_GET['scripts'], 0, 10) as $script) { - // Sanitise filename - $script_name = 'js'; - - $path = explode("/", $script); - foreach ($path as $filename) { - // Allow alphanumeric, "." and "-" chars only, no files starting - // with . - if (preg_match("@^[\w][\w\.-]+$@", $filename)) { - $script_name .= DIRECTORY_SEPARATOR . $filename; - } - } - - // Output file contents - if (preg_match("@\.js$@", $script_name) && is_readable($script_name)) { - readfile($script_name); - echo ";\n\n"; - } - } -} - -if (isset($_GET['call_done'])) { - echo "AJAX.scriptHandler.done();"; -} diff --git a/libraries/classes/Controllers/Database/DatabaseStructureController.php b/libraries/classes/Controllers/Database/DatabaseStructureController.php index 196afb5b29..ef51e52165 100644 --- a/libraries/classes/Controllers/Database/DatabaseStructureController.php +++ b/libraries/classes/Controllers/Database/DatabaseStructureController.php @@ -119,6 +119,7 @@ class DatabaseStructureController extends DatabaseController array( 'db_structure.js', 'tbl_change.js', + 'vendor/jquery/jquery.validate.js', 'vendor/jquery/jquery-ui-timepicker-addon.js' ) ); diff --git a/libraries/classes/Controllers/Table/TableSearchController.php b/libraries/classes/Controllers/Table/TableSearchController.php index 63f1971fd5..8d0677f48d 100644 --- a/libraries/classes/Controllers/Table/TableSearchController.php +++ b/libraries/classes/Controllers/Table/TableSearchController.php @@ -201,6 +201,7 @@ class TableSearchController extends TableController 'sql.js', 'tbl_select.js', 'tbl_change.js', + 'vendor/jquery/jquery.validate.js', 'vendor/jquery/jquery-ui-timepicker-addon.js', 'vendor/jquery/jquery.uitablefilter.js', 'gis_data_editor.js', @@ -239,6 +240,7 @@ class TableSearchController extends TableController 'vendor/jqplot/plugins/jqplot.highlighter.js', 'vendor/jqplot/plugins/jqplot.cursor.js', 'vendor/jquery/jquery-ui-timepicker-addon.js', + 'vendor/jquery/jquery.validate.js', 'tbl_zoom_plot_jqplot.js', 'tbl_change.js', ) diff --git a/libraries/classes/ErrorReport.php b/libraries/classes/ErrorReport.php index 6bc29d14e5..976b7bbb06 100644 --- a/libraries/classes/ErrorReport.php +++ b/libraries/classes/ErrorReport.php @@ -188,89 +188,6 @@ class ErrorReport return $response; } - /** - * Returns number of lines in given javascript file. - * - * @param string $filename javascript filename - * - * @return Number of lines - * - * @todo Should gracefully handle non existing files - */ - public static function countLines($filename) - { - /** - * The generated file that contains the line numbers for the js files - * If you change any of the js files you can run the scripts/line-counts.sh - */ - if (is_readable('js/line_counts.php')) { - include_once 'js/line_counts.php'; - } - - global $LINE_COUNT; - if (defined('LINE_COUNTS')) { - return $LINE_COUNT[$filename]; - } - - // ensure that the file is inside the phpMyAdmin folder - $depath = 1; - foreach (explode('/', $filename) as $part) { - if ($part == '..') { - $depath--; - } elseif ($part != '.' || $part === '') { - $depath++; - } - if ($depath < 0) { - return 0; - } - } - - $linecount = 0; - $handle = fopen('./js/' . $filename, 'r'); - while (!feof($handle)) { - $line = fgets($handle); - if ($line === false) { - break; - } - $linecount++; - } - fclose($handle); - return $linecount; - } - - /** - * returns the translated line number and the file name from the cumulative line - * number and an array of files - * - * uses the $LINE_COUNT global array of file names and line numbers - * - * @param array $filenames list of files in order of concatenation - * @param Integer $cumulative_number the cumulative line number in the - * concatenated files - * - * @return array the filename and line number - * Returns two variables in an array: - * - A String $filename the filename where the requested cumulative number - * exists - * - Integer $linenumber the translated line number in the returned file - */ - public static function getLineNumber(array $filenames, $cumulative_number) - { - $cumulative_sum = 0; - foreach ($filenames as $filename) { - $filecount = self::countLines($filename); - if ($cumulative_number <= $cumulative_sum + $filecount + 2) { - $linenumber = $cumulative_number - $cumulative_sum; - break; - } - $cumulative_sum += $filecount + 2; - } - if (! isset($filename)) { - $filename = ''; - } - return array($filename, $linenumber); - } - /** * translates the cumulative line numbers in the stack trace as well as sanitize * urls and trim long lines in the context @@ -287,19 +204,10 @@ class ErrorReport $line = mb_substr($line, 0, 75) . "//..."; } } - if (preg_match("", $level["url"], $matches)) { - parse_str($matches[1], $vars); - List($file_name, $line_number) = self::getLineNumber( - $vars["scripts"], $level["line"] - ); - $level["filename"] = $file_name; - $level["line"] = $line_number; - } else { - unset($level["context"]); - List($uri, $script_name) = self::sanitizeUrl($level["url"]); - $level["uri"] = $uri; - $level["scriptname"] = $script_name; - } + unset($level["context"]); + List($uri, $script_name) = self::sanitizeUrl($level["url"]); + $level["uri"] = $uri; + $level["scriptname"] = $script_name; unset($level["url"]); } unset($level); diff --git a/libraries/classes/Header.php b/libraries/classes/Header.php index 8a3cbdac24..3981be2a04 100644 --- a/libraries/classes/Header.php +++ b/libraries/classes/Header.php @@ -184,7 +184,7 @@ class Header // Here would not be a good place to add CodeMirror because // the user preferences have not been merged at this point - $this->_scripts->addFile('messages.php', false, array('l' => $GLOBALS['lang'])); + $this->_scripts->addFile('messages.php', array('l' => $GLOBALS['lang'])); // Append the theme id to this url to invalidate // the cache on a theme change. Though this might be // unavailable for fatal errors. diff --git a/libraries/classes/InsertEdit.php b/libraries/classes/InsertEdit.php index 860aa13f94..d58f354a3c 100644 --- a/libraries/classes/InsertEdit.php +++ b/libraries/classes/InsertEdit.php @@ -1871,6 +1871,9 @@ class InsertEdit $response = Response::getInstance(); $header = $response->getHeader(); $scripts = $header->getScripts(); + $scripts->addFile('vendor/jquery/jquery-ui-timepicker-addon.js'); + $scripts->addFile('vendor/jquery/jquery.validate.js'); + $scripts->addFile('vendor/jquery/additional-methods.js'); $scripts->addFile('tbl_change.js'); if (!defined('TESTSUITE')) { include 'tbl_change.php'; diff --git a/libraries/classes/Scripts.php b/libraries/classes/Scripts.php index 81bcbbc818..58aaf238a0 100644 --- a/libraries/classes/Scripts.php +++ b/libraries/classes/Scripts.php @@ -44,42 +44,19 @@ class Scripts */ private function _includeFiles(array $files) { - $first = []; - $result = []; - $scripts = array(); - $separator = Url::getArgSeparator(); + $result = ''; foreach ($files as $value) { if (strpos($value['filename'], ".php") !== false) { $file_name = $value['filename'] . Url::getCommon($value['params'] + array('v' => PMA_VERSION)); - if ($value['before_statics'] === true) { - $first[] - = ""; - } else { - $result[] = ""; - } + $result .= "\n"; } else { - $scripts[] = "scripts%5B%5D=" . $value['filename']; + $result .= '' . "\n"; } } - $separator = Url::getArgSeparator(); - // Using chunks of 10 files to avoid too long URLs - // as some servers are set to 512 bytes URL limit - $script_chunks = array_chunk($scripts, 10); - foreach ($script_chunks as $script_chunk) { - $url = 'js/get_scripts.js.php?' - . implode($separator, $script_chunk) - . $separator . Header::getVersionParameter(); - - $result[] = sprintf( - '', - htmlspecialchars($url) - ); - } - return implode("\n", $first) . implode("\n", $result); + return $result; } /** @@ -97,15 +74,12 @@ class Scripts * Adds a new file to the list of scripts * * @param string $filename The name of the file to include - * @param bool $before_statics Whether this dynamic script should be - * included before the static ones * @param array $params Additional parameters to pass to the file * * @return void */ public function addFile( $filename, - $before_statics = false, array $params = array() ) { $hash = md5($filename); @@ -118,7 +92,6 @@ class Scripts 'has_onload' => $has_onload, 'filename' => $filename, 'params' => $params, - 'before_statics' => $before_statics ); } diff --git a/scripts/line-counts.sh b/scripts/line-counts.sh deleted file mode 100755 index c4657ca097..0000000000 --- a/scripts/line-counts.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# Do not run as CGI -if [ -n "$GATEWAY_INTERFACE" ] ; then - echo 'Can not invoke as CGI!' - exit 1 -fi - -cat > js/line_counts.php <> js/line_counts.php diff --git a/tbl_replace.php b/tbl_replace.php index 7c704ac21d..69c5ba0e71 100644 --- a/tbl_replace.php +++ b/tbl_replace.php @@ -454,6 +454,9 @@ if (! empty($return_to_sql_query)) { $GLOBALS['sql_query'] = $return_to_sql_query; } +$scripts->addFile('vendor/jquery/jquery-ui-timepicker-addon.js'); +$scripts->addFile('vendor/jquery/jquery.validate.js'); +$scripts->addFile('vendor/jquery/additional-methods.js'); $scripts->addFile('tbl_change.js'); $active_page = $goto_include; diff --git a/test/classes/InsertEditTest.php b/test/classes/InsertEditTest.php index 44eea3babd..a5d4e5784a 100644 --- a/test/classes/InsertEditTest.php +++ b/test/classes/InsertEditTest.php @@ -1842,7 +1842,7 @@ class InsertEditTest extends TestCase ->setMethods(array('addFile')) ->getMock(); - $scriptsMock->expects($this->once()) + $scriptsMock->expects($this->exactly(4)) ->method('addFile'); $headerMock = $this->getMockBuilder('PhpMyAdmin\Header') diff --git a/test/classes/ScriptsTest.php b/test/classes/ScriptsTest.php index 54c196621e..d793c236af 100644 --- a/test/classes/ScriptsTest.php +++ b/test/classes/ScriptsTest.php @@ -77,8 +77,7 @@ class ScriptsTest extends PmaTestCase { $this->assertEquals( '', + . 'src="js/common.js?v=' . PMA_VERSION . '">' . "\n", $this->_callPrivateFunction( '_includeFiles', array( @@ -105,8 +104,7 @@ class ScriptsTest extends PmaTestCase $this->assertRegExp( '@' + . 'src="js/common.js\?v=' . PMA_VERSION . '">' . "\n" . '