From 4bb4ef970c55bb0d84d6e2b226b8d608b5613907 Mon Sep 17 00:00:00 2001 From: ozh Date: Sat, 30 Aug 2014 21:47:17 +0200 Subject: [PATCH] Include BookmarkletGen --- includes/BookmarkletGen/BookmarkletGen.php | 190 +++++++++++++++++++++ includes/BookmarkletGen/README.md | 5 + includes/functions-formatting.php | 18 ++ 3 files changed, 213 insertions(+) create mode 100644 includes/BookmarkletGen/BookmarkletGen.php create mode 100644 includes/BookmarkletGen/README.md diff --git a/includes/BookmarkletGen/BookmarkletGen.php b/includes/BookmarkletGen/BookmarkletGen.php new file mode 100644 index 0000000..cbe5228 --- /dev/null +++ b/includes/BookmarkletGen/BookmarkletGen.php @@ -0,0 +1,190 @@ +replace_strings( $out ); + $out = $this->kill_comments( $out ); + $out = $this->compress_white_space( $out ); + $out = $this->combine_strings( $out ); + $out = $this->restore_strings( $out ); + $out = $this->encodeURIComponent( $out ); + $out = 'javascript:' . $out; + + return $out; + } + + /** + * PHP port of Javascript function encodeURIComponent + * + * From http://stackoverflow.com/a/1734255/36850 + * + * @since + * @param string $str String to encode + * @return string Encoded string + */ + // + private function encodeURIComponent( $str ) { + $revert = array( + '%21'=>'!', '%2A'=>'*', '%28'=>'(', '%29'=>')', + ); + + return strtr( rawurlencode( $str ), $revert ); + } + + /** + * Kill comment lines and blocks + * + * @param string $code Commented Javascript code + * @return string Commentless code + */ + private function kill_comments( $code ) { + $code = preg_replace( '!\s*//.+$!m', '', $code ); + $code = preg_replace( '!/\*.+?\*/!sm', '', $code ); // s modifier: dot matches new lines + + return $code; + } + + /** + * Compress white space + * + * Remove some extraneous spaces and make the whole script a one liner + * + * @param string $code Javascript code + * @return string Compressed code + */ + private function compress_white_space( $code ) { + // Tabs to space, no more than 1 consecutive space + $code = preg_replace( '!\t!m', ' ', $code ); + $code = preg_replace( '![ ]{2,}!m', ' ', $code ); + + // Remove uneccessary white space around operators, braces and brackets. + // \xHH sequence is: !%&()*+,-/:;<=>?[]\{|}~ + $code = preg_replace( '/\s([\x21\x25\x26\x28\x29\x2a\x2b\x2c\x2d\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x5b\x5d\x5c\x7b\x7c\x7d\x7e])/m', "$1", $code ); + $code = preg_replace( '/([\x21\x25\x26\x28\x29\x2a\x2b\x2c\x2d\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x5b\x5d\x5c\x7b\x7c\x7d\x7e])\s/m', "$1", $code ); + + // Split on each line, trim leading/trailing white space, kill empty lines, combine everything in one line + $code = preg_split( '/\r\n|\r|\n/', $code ); + foreach( $code as $i => $line ) { + $code[ $i ] = trim( $line ); + } + $code = implode( '', $code ); + + return $code; + } + + /** + * Combine any consecutive strings + * + * In the case we have two consecutive quoted strings (eg: "hello" + "world"), save a couple more + * length and combine them + * + * @param string $code Javascript code + * @return string Javascript code + */ + private function combine_strings( $code ) { + $code = preg_replace('/"\+"/m', "", $code); + $code = preg_replace("/'\+'/m", "", $code); + + return $code; + } + + + /** + * Replace all literal strings (eg: "hello world") with a placeholder and collect them in an array + * + * The idea is that strings cannot be trimmed or white-space optimized: take them out first before uglifying + * the code, then we'll reinject them back in later + * + * @param string $code Javascript code + * @return string Javascript code with placeholders (eg "__1__") instead of literal strings + */ + private function replace_strings( $code ) { + $return = ""; + + // Split script into individual lines. + $lines = explode("\n", $code); + for( $i = 0; $i < count( $lines ); $i++ ) { + + $j = 0; + $inQuote = false; + while ($j < strlen( $lines[$i] ) ) { + $c = $lines[ $i ][ $j ]; + + // If not already in a string, look for the start of one. + if (!$inQuote) { + if ($c == '"' || $c == "'") { + $inQuote = true; + $escaped = false; + $quoteChar = $c; + $literal = $c; + } + else + $return .= $c; + } + + // Already in a string, look for end and copy characters. + else { + if ($c == $quoteChar && !$escaped) { + $inQuote = false; + $literal .= $quoteChar; + $return .= "__" . count( $this->literal_strings ) . "__"; + $this->literal_strings[ count( $this->literal_strings ) ] = $literal; + } + else if ($c == "\\" && !$escaped) + $escaped = true; + else + $escaped = false; + $literal .= $c; + } + $j++; + } + $return .= "\n"; + } + + return $return; + } + + /** + * Restore literal strings by replacing their placeholders with actual strings + * + * @param string $code Javascript code with placeholders + * @return string Javascript code with actual strings + */ + function restore_strings( $code ) { + foreach( $this->literal_strings as $i => $string ) { + $code = preg_replace( '/__' . $i . '__/', $string, $code, 1 ); + } + + return $code; + } + +} diff --git a/includes/BookmarkletGen/README.md b/includes/BookmarkletGen/README.md new file mode 100644 index 0000000..51f9f48 --- /dev/null +++ b/includes/BookmarkletGen/README.md @@ -0,0 +1,5 @@ +# Bookmarklet Gen + +Convert readable Javascript code into bookmarklet links + +Home: https://github.com/ozh/bookmarkletgen diff --git a/includes/functions-formatting.php b/includes/functions-formatting.php index 9fd8a26..ea6ddc4 100644 --- a/includes/functions-formatting.php +++ b/includes/functions-formatting.php @@ -621,3 +621,21 @@ function yourls_rawurldecode_while_encoded( $string ) { } return $string; } + +/** + * Converts readable Javascript code into a valid bookmarklet link + * + * Uses https://github.com/ozh/bookmarkletgen + * + * @since 1.7.1 + * @param string $code Javascript code + * @return string Bookmarklet link + */ +function yourls_make_bookmarklet( $code ) { + if ( !class_exists( 'BookmarkletGen', false ) ) { + require_once YOURLS_INC . '/BookmarkletGen/BookmarkletGen.php'; + } + + $book = new BookmarkletGen; + return $book->crunch( $code ); +} -- 2.45.0