c9974758070c77f1dceb48ba8f02532efcf76195
Author: AD7six
Date: 2009-04-18 18:05:08 +0200
diff --git a/config/bootstrap.php b/config/bootstrap.php
index 54c7c49..fb9b98a 100644
--- a/config/bootstrap.php
+++ b/config/bootstrap.php
@@ -54,6 +54,10 @@ $langs = array('ar', 'en', 'fa', 'fr', 'de', 'es', 'pt', 'nl', 'id', 'it', 'ja',
sort($langs);
Configure::write('Languages.all', $langs);
+Configure::write('MiCompressor.clearCache', false);
+Configure::write('MiCompressor.cacheDir', CACHE . 'assets' . DS);
+Configure::write('MiCompressor.salt', trim(file_get_contents(APP . '.git/refs/heads/master')));
+
define('ADMIN', '800');
define('EDITOR', '700');
define('MODERATOR', '600');
diff --git a/tmp/cache/assets/empty b/tmp/cache/assets/empty
new file mode 100644
index 0000000..e69de29
diff --git a/vendors/css/mini.css b/vendors/css/mini.css
index ca0f11b..f103ea2 100644
--- a/vendors/css/mini.css
+++ b/vendors/css/mini.css
@@ -22,12 +22,5 @@
*/
App::import('Vendor', 'MiCompressor');
list($_, $request) = explode('?', $_SERVER['REQUEST_URI']);
-echo MiCompressor::serve(compact('request')); return;
-echo MiCompressor::serve(array(
- 'request' => $request,
- 'compress' => Configure::read() < 2,
- 'clear' => false,
- 'log' => true,
- 'type' => 'css'
-));
+echo MiCompressor::serve($request, 'css');
?>
\ No newline at end of file
diff --git a/vendors/js/mini.js b/vendors/js/mini.js
index a5c8024..52328b7 100644
--- a/vendors/js/mini.js
+++ b/vendors/js/mini.js
@@ -22,12 +22,5 @@
*/
App::import('Vendor', 'MiCompressor');
list($_, $request) = explode('?', $_SERVER['REQUEST_URI']);
-echo MiCompressor::serve(compact('request')); return;
-echo MiCompressor::serve(array(
- 'request' => $request,
- 'compress' => Configure::read() < 2,
- 'clear' => true,
- 'log' => true,
- 'type' => 'js'
-));
+echo MiCompressor::serve($request, 'js'); return;
?>
\ No newline at end of file
diff --git a/vendors/mi_compressor.php b/vendors/mi_compressor.php
index a821e6d..0883a9b 100644
--- a/vendors/mi_compressor.php
+++ b/vendors/mi_compressor.php
@@ -1,9 +1,11 @@
<?php
-/* SVN FILE: $Id: mi_compressor.php 800 2009-02-26 18:49:55Z ad7six $ */
+/* SVN FILE: $Id: mi_compressor.php 939 2009-04-16 21:25:05Z ad7six $ */
/**
- * Short description for mi_compressor.php
+ * MiCompressor, a class used for shrinking CSS and JS files
*
- * Long description for mi_compressor.php
+ * MiCompressor is a utility which serves 2 purposes:
+ * Ask the class to return the request(s) necessary for a set of css/js files
+ * Process a request for css/js file(s)
*
* PHP version 5
*
@@ -18,18 +20,33 @@
* @package base
* @subpackage base.vendors
* @since v 1.0
- * @version $Revision: 800 $
+ * @version $Revision: 939 $
* @modifiedby $LastChangedBy: ad7six $
- * @lastmodified $Date: 2009-02-26 19:49:55 +0100 (Thu, 26 Feb 2009) $
+ * @lastmodified $Date: 2009-04-16 23:25:05 +0200 (Thu, 16 Apr 2009) $
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
/**
* MiCompressor class
*
- * Compress multiple css and js files into a single file on demand.
+ * Compress and minify multiple css and js files into a single file on demand.
*
* By default, in debug mode it only concatonates, in production mode contents are also runs the output through a
- * minifying routine
+ * minifying routine. Some term definitions:
+ * compress is used within the class to refer to data-compression (such as gzip etc.);
+ * minify means stripping whitespace, rewriting to be less chars etc.
+ *
+ * This class is designed to be used with CakePHP but can be used alone (dependent on Minify only, if minified assets
+ * don't already exist). If Minify can't be found minification will be skipped
+ *
+ * Note:
+ * To avoid stale js/css files being served, The default salt is a constant SITE_VERSION (if defined). The salt
+ * is used for the hash generation/comparison logic and allows you to avoid stale css/js e.g.:
+ * define('SITE_VERSION', filemtime('somefilethatgetsupdatedwhenyoudeploy'));
+ * In CakePHP a suggestion would be:
+ * define('SITE_VERSION', filemtime('/app/config/bootstrap.php'));
+ * Or call this before using the class:
+ * MiCompressor::config(array('salt' => 'some value'));
+ *
*
* @abstract
* @package base
@@ -37,22 +54,6 @@
*/
abstract class MiCompressor {
/**
- * start property
- *
- * @static
- * @var mixed null
- * @access public
- */
- public static $start = null;
-/**
- * cacheDuration property
- *
- * @static
- * @var string '+1 year'
- * @access public
- */
- public static $cacheDuration = '+1 year';
-/**
* map property
*
* To allow disassociation from parameters used in the request, and file path locations
@@ -66,38 +67,95 @@ abstract class MiCompressor {
'jquery' => array(
'aplugin' => 'subfolder/path/here.js'
)
+ ),
+ 'css' => array(
+ 'jquery' => array(
+ 'aplugin' => 'subfolder/path/here.css',
+ 'aplugin' => array(
+ 'subfolder/path/moreThan.css',
+ 'subfolder/path/oneFileRequired.css'
+ )
+ )
)
+
);
/**
- * compressCss method
+ * settings property
+ *
+ * Active settings - edit/set/see via MiCompressor::config()
+ *
+ * @var array
+ * @access protected
+ */
+ protected static $settings = array();
+/**
+ * defaultSettings property
+ *
+ * Don't edit this.
+ * The settings which can be auto-set are set here, these settings are used as a fallback if a requested setting
+ * hasn't been set, or the Configure class (if it exists) return null
+ *
+ * @var array
+ * @access protected
+ */
+ protected static $defaultSettings = array(
+ 'MiCompressor.debug' => null,
+ 'MiCompressor.log' => null,
+ 'MiCompressor.cacheClear' => null,
+ 'MiCompressor.cacheDuration' => null,
+ 'MiCompressor.cacheDir' => null,
+ 'MiCompressor.salt' => null,
+ 'MiCompressor.bypassLoadMinifyLib' => null,
+ 'MiCompressor.minify' => null,
+ 'MiCompressor.minify.css' => null,
+ 'MiCompressor.minify.js' => null,
+ 'Asset.compress' => null,
+ );
+/**
+ * initialized property
+ *
+ * Flag to know if the class variables have been initialized yet.
+ *
+ * @var bool false
+ * @access protected
+ */
+ protected static $initialized = false;
+/**
+ * start property
+ *
+ * Start time
*
- * @param mixed $css
- * @param string $file
- * @param string $logPrefix
* @static
- * @return void
- * @access public
+ * @var mixed null
+ * @access protected
*/
- public static function compressCss($css, $file = '', $logPrefix = '') {
- MiCompressor::log("$logPrefix compress $file.css");
- return Minify_CSS::minify($css);
- }
+ protected static $start = null;
/**
- * compressJs method
+ * loadedFiles property
*
- * This can be rather intensive - use with care
+ * To prevent a valid request which includes the same file twice (either expicitly or through @import logic)
+ * this variable holds the names of the files already loaded for the current request
*
- * @TODO don't strip license blocks
- * @param mixed $js
- * @param string $file
- * @param string $logPrefix
+ * @var array
+ * @access protected
+ */
+ protected static $loadedFiles = array();
+/**
+ * config method
+ *
+ * Set/See settings
+ *
+ * @param array $settings array()
+ * @param bool $reset false - reset to defaults before porcessing $settings?
* @static
- * @return void
+ * @return current settings
* @access public
*/
- public static function compressJs($js, $file = '', $logPrefix = '') {
- MiCompressor::log("$logPrefix compressing $file.js");
- return JSMin::minify($js);
+ public static function config($settings = array(), $reset = false) {
+ if ($reset) {
+ MiCompressor::$settings = array();
+ }
+ return MiCompressor::$settings = array_merge(MiCompressor::$settings, $settings);
}
/**
* log method
@@ -106,7 +164,7 @@ abstract class MiCompressor {
*
* @param mixed $string
* @static
- * @return void
+ * @return logs contents if requested, otherwise null
* @access public
*/
public static function log($string = null) {
@@ -115,9 +173,16 @@ abstract class MiCompressor {
}
static $log = array();
if ($string === null) {
- $log = am(array(
- 'MiCompressor log - only generated in debug mode. Generated ' . date("D, M jS Y, H:i:s"),
- null), $log);
+ $settings = MiCompressor::$settings;
+ ksort($settings);
+ foreach ($settings as $k => &$v) {
+ $v = ' ' . str_pad(str_replace('MiCompressor.', '', $k), 15, ' ', STR_PAD_RIGHT) . "\t: " . $v;
+ }
+ $settings[] = '';
+ $head = array_merge(array(
+ 'MiCompressor log - (only generated in debug mode, or if MiCompressor.log is set to true) ' . date("D, M jS Y, H:i:s"),
+ null), $settings);
+ $log = array_merge($head, $log);
$return = "/**\r\n * " . implode("\r\n * ", $log) . "\r\n */\r\n";
$log = array();
return $return;
@@ -126,85 +191,53 @@ abstract class MiCompressor {
$log[] = str_pad(number_format($time, 3, '.', ''), 6, ' ', STR_PAD_LEFT) . 's ' . $string;
}
/**
- * parse method
+ * minifyCss method
*
- * Used to determine which component files, and sub files have been requested
- * For the request string of the form: file|file2|file3|file4,x,y=300,z|file5.. generate an array of the form:
- * array(
- * file => array(),
- * file2 => array(),
- * file3 => array(),
- * file4 => array('x', 'y' => 300, 'z'),
- * file5 => array()
- * )
- * This format allows passing parameters to scripts when included (accessible as $params);
+ * Pass in a string of css, get out a minified version
*
- * A hash is automatically added to the url by the MiHtml and MiJavascript helpers. The hash is checked in this
- * method and if it doesn't match (this should never happen for a valid request), will either add a log message if not
- * in production mode or return false. Compressing (in particular Js files) is expensive, therefore using a hash
- * prevents a malicious user from requesting arbritary varying urls and tying up the server
+ * @param mixed $css
+ * @param string $logPrefix the indent
+ * @static
+ * @return string minified css
+ * @access public
+ */
+ public static function minifyCss($css, $logPrefix = '') {
+ MiCompressor::log("{$logPrefix}minifying combined css file");
+ return Minify_CSS::minify($css);
+ }
+/**
+ * minifyJs method
*
- * The hash is returned primarily to be used as the default cache key
+ * Pass in a string of javascript, and get out a minified version
+ * This can be rather intensive - use with care
*
- * @param string $requestString
- * @param mixed $hash
+ * @TODO don't strip license blocks
+ * @param mixed $js
+ * @param string $file
+ * @param string $logPrefix the indent
* @static
- * @return mixed array of files to process, or false for an invalid/doctored request
+ * @return minified js
* @access public
*/
- public static function parse($requestString = '', &$hash = null) {
- $debug = (class_exists('Configure')?Configure::read():false);
- $requests = explode('|', $requestString);
- $hash = array_pop($requests);
- $problem = false;
- if (strpos($hash, 'hash=') !== 0) {
- $problem = true;
- MiCompressor::log('PROBLEM: No hash in the request string');
- } else {
- list(,$hash) = explode('=', $hash);
- uses('Security');
- $salt = defined('SITE_VERSION')?SITE_VERSION:'';
- if ($hash != Security::hash($salt . implode('|', $requests), null, true)) {
- $problem = true;
- MiCompressor::log('PROBLEM: Hash doesn\'t match');
- }
- }
- if ($problem && $debug) {
- return false;
- }
-
- $return = array();
- foreach ($requests as $filename) {
- $params = array();
- if (strpos($filename, ',')) {
- $params = explode(',', $filename);
- $filename = array_shift($params);
- foreach ($params as $k => $v) {
- if (strpos($v, '=')) {
- unset ($params[$k]);
- list($k, $v) = explode('=', $v);
- $params[$k] = $v;
- }
- }
- }
- $return[$filename] = $params;
- }
- return $return;
+ public static function minifyJs($js, $file = '', $logPrefix = '') {
+ MiCompressor::log("$logPrefix minifying $file.js");
+ return JSMin::minify($js);
}
/**
* process method
*
- * For each of the requested files, find them, concatonate them - if requested compress them - and return
- * For js files, each individual file is compressed. For css, their combined contents are compressed
+ * For each of the requested files, find them, concatonate them - if requested minify them - and return
+ * For js files, each individual file is minifyed. For css, their combined contents are minifyed
+ * Called internally by serve, public to allow other (external) parse logic if necessary
*
* @param mixed $files
* @param mixed $type
- * @param mixed $compress
+ * @param mixed $minify
* @static
- * @return string the files' contents, optionally compressed, as a string
+ * @return string the files contents, optionally minifyed, as a string
* @access public
*/
- public static function process($files, $type = null, $compress = null) {
+ public static function process($files, $type = null, $minify = null) {
if ($type === null) {
if (strpos($_GET['url'], 'js/') === 0) {
$type = 'js';
@@ -212,21 +245,17 @@ abstract class MiCompressor {
$type = 'css';
}
}
- $debug = (class_exists('Configure')?Configure::read():false);
- if ($compress === null) {
- $compress = !$debug;
+ if ($minify === null) {
+ $minify = MiCompressor::cRead('MiCompressor.minify.' . $type, 'minify');
}
- if ($compress && !MiCompressor::loadCompressLib($type)) {
- MiCompressor::log("PROBLEM: Unable to load $type compressor. No minifying");
- $compress = false;
+
+ if ($minify && !MiCompressor::loadMinifyLib($type)) {
+ MiCompressor::log("PROBLEM: Unable to load $type . No minifying");
+ $minify = false;
}
$files = (array)$files;
$return = '';
- if ($type === 'css') {
- $_compress = $compress;
- $compress = false;
- }
foreach ($files as $filename => $params) {
if (is_string($params) && is_numeric($filename)) {
$filename = $params;
@@ -235,18 +264,26 @@ abstract class MiCompressor {
if (substr($filename, - strlen($type)) === $type) {
$filename = substr($filename, 0, - strlen($type) - 1);
}
- $method = 'load' . Inflector::camelize($type) . Inflector::camelize($filename);
+ $iType = $type;
+ $iType[0] = strtoupper($iType[0]);
+ $iFilename = $filename;
+ $iFilename[0] = strtoupper($iFilename[0]);
+ $method = 'load' . $iType . $iFilename;
if (method_exists('MiCompressor', $method)) {
MiCompressor::log("Loading $filename.$type with method $method");
- $return .= MiCompressor::$method($params, $compress) . "\r\n";
+ $return .= MiCompressor::$method($params, $minify) . "\r\n";
+ } elseif (strpos($filename, 'jquery.') === 0) {
+ $method = "load{$iType}JqueryPlugin";
+ MiCompressor::log("Loading $filename.$type with method $method");
+ $return .= MiCompressor::$method(str_replace('jquery.', '', $filename), $minify) . "\r\n";
} else {
MiCompressor::log("Loading $filename.$type with method loadFile");
- $return .= MiCompressor::loadFile($filename, $params, $compress, $type) . "\r\n";
+ $return .= MiCompressor::loadFile($filename, $params, $minify, $type) . "\r\n";
}
}
- if (!empty($_compress) && $type === 'css') {
- $return = MiCompressor::compressCss($return, 'combined');
+ if ($minify && $type === 'css') {
+ $return = MiCompressor::minifyCss($return, "\t");
}
return $return;
}
@@ -257,39 +294,53 @@ abstract class MiCompressor {
* If the request is invalid issue a 404 header and return no content
* otherwise generate the content and send to the browser
*
- * If in debug mode, the cache duration is set to +10 minutes. otherwise it is +1 year
- * $compress defaults to true in production mode, false in debug mode
- * $log defaults to true in production mode, false in debug mode
- * $cachePath defaults to $type _ the hash _ d(ebug)|p(roduction) . t(emp)|p(ermanent)
- * $clear defaults to false in production mode, true in debug mode
+ * Example Cake use (contents of mini.css file):
+ * App::import('Vendor', 'MiCompressor');
+ * list($_, $request) = explode('?', $_SERVER['REQUEST_URI']);
+ * echo MiCompressor::serve($request, 'css');
*
- * A cache file is always generated, but if $clear is true, the cache is cleared for all cache files of the same type
- * The log is always generated - but it's only included in the content if $log is true. Otherwise it is available
- * for debugging purposes
+ * Example Standalone use (contents of mini.css file):
+ * $base = '/path/to/mi_compressor/containing/folder/';
+ * include($base . 'mi_compressor.php');
+ * // Optional Start
+ * ini_set('include_path', $base . 'minify/lib:' . ini_get('include_path'));
+ * include($base . 'minify/lib/JSMin.php');
+ * include($base . 'minify/lib/Minify/CSS.php');
+ * include($base . 'minify/lib/HTTP/ConditionalGet.php');
+ * // Optional End
+ * MiCompressor::config(array(
+ * 'MiCompressor.debug' => 0,
+ * 'MiCompressor.minify' => 1,
+ * ));
+ * echo MiCompressor::serve($_GET, 'css');
*
* @param string $request
* @param mixed $type
- * @param mixed $compress
- * @param mixed $log
- * @param mixed $cachePath
- * @param mixed $clear
* @static
- * @return void
+ * @return contents to be served up
* @access public
*/
- public static function serve($request = '', $type = null, $compress = null, $log = null, $cachePath = null, $clear = null) {
+ public static function serve($request = '', $type = null) {
+ MiCompressor::$loadedFiles = array();
+
if (is_array($request)) {
- extract($request);
+ if (count($request) == 1 && !isset($request['request'])) {
+ $hash = current($request);
+ $request = key($request);
+ } else {
+ extract($request);
+ }
}
MiCompressor::log('Request String: ' . $request);
$start = getMicrotime();
ob_start();
- if (Configure::read('Asset.compress') && @ini_get("zlib.output_compression") != true && extension_loaded("zlib") &&
+ if (MiCompressor::cRead('Asset.compress') && @ini_get("zlib.output_compression") != true && extension_loaded("zlib") &&
(strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false)) {
MiCompressor::log('Enabling compression, turn on zlib.output_compression if possible');
ob_start('ob_gzhandler');
}
$requests = MiCompressor::parse($request, $hash);
+
if (!$requests) {
header('HTTP/1.0 404 Not Found');
return false;
@@ -301,179 +352,454 @@ abstract class MiCompressor {
$type = 'css';
}
}
- $appDebug = (class_exists('Configure')?Configure::read():false);
- if ($compress === null) {
- if (!class_exists('Configure')) {
- $compress = true;
- } else {
- $compress = Configure::read('Asset.compress.' . $type);
- if ($compress === null) {
- $compress = Configure::read('Asset.compress');
- }
- if ($compress === null) {
- $compress = !$appDebug;
- }
- }
- }
- if ($log === null) {
- $log = $appDebug;
- }
- if ($clear === null) {
- $clear = $appDebug;
- }
- if ($cachePath === null) {
- $cachePath = MiCompressor::__cachePath($type, $hash, $appDebug, $clear, true);
- }
- MiCompressor::log('Cache Path: ' . $cachePath);
- if ($appDebug) {
- MiCompressor::$cacheDuration = '+10 minutes';
- }
-
- if ($clear && function_exists('uses')) {
- uses('Folder');
- if (class_exists('Folder')) {
- $folder = new Folder(CACHE . 'views/');
- $files = $folder->find($type . '_' . '.*');
+ if ($cachePath = MiCompressor::cachePath($type, $hash, true)) {
+ MiCompressor::log('Cache Path: ' . $cachePath);
+ if (MiCompressor::cRead('cacheClear')) {
+ $path = MiCompressor::cRead('cacheDir') . $type . '_*';
+ $files = glob($path);
foreach ($files as $file) {
- MiCompressor::log("Removing Cache File " . $file);
- @unlink(CACHE . 'views/' . $file);
+ MiCompressor::log("Removing Cache File " . str_replace(MiCompressor::cRead('cacheDir'), '', $file));
+ @unlink($file);
}
}
- }
- if ($cachePath) {
- $cached = cache($cachePath, null, MiCompressor::$cacheDuration);
+ $cached = cache($cachePath, null, MiCompressor::cRead('cacheDuration'));
if ($cached) {
MiCompressor::log("Cache File: $cachePath found and returned");
return MiCompressor::out($cachePath, $cached);
}
}
- $return = MiCompressor::process($requests, $type, $compress);
+ $return = MiCompressor::process($requests, $type);
$eTag = md5($return);
if ($cachePath) {
- MiCompressor::log("Generating cache file $cachePath to expire in " . MiCompressor::$cacheDuration);
+ MiCompressor::log("Generating cache file $cachePath to expire in " . MiCompressor::cRead('cacheDuration'));
}
MiCompressor::log('eTag: ' . $eTag);
MiCompressor::log('Finished');
- if ($log) {
+ if (MiCompressor::cRead('log')) {
$return = MiCompressor::log() . $return;
}
$return = '/* eTag:' . $eTag . ' */' . $return;
// Slightly out of sequence so the cache file contains the log
if ($cachePath) {
- cache($cachePath, $return, MiCompressor::$cacheDuration);
+ cache($cachePath, $return, MiCompressor::cRead('cacheDuration'));
}
- return MiCompressor::out(CACHE . $cachePath, $return);
+ return MiCompressor::out(MiCompressor::cRead('cacheDir') . $cachePath, $return);
}
/**
- * loadCompressLib method
+ * url method
+ *
+ * Generate the url(s) corresponding to the requested files
+ *
+ * @param array $request
+ * @param array $params
+ * @static
+ * @return mixed string or array of strings correpsonding to the request
+ * @access public
+ */
+ public static function url($request = array(), $params = array()) {
+ extract(am(array(
+ 'sendAlone' => MiCompressor::cRead(),
+ 'type' => 'js',
+ 'sizeLimit' => false,
+ ), $params));
+ $stack = array();
+ $i = 0;
+ foreach ($request as $key => &$value) {
+ $_sendAlone = $sendAlone;
+ if (is_string($key)) {
+ if (is_array($value) && isset($value['sendAlone'])) {
+ $_sendAlone = $value['sendAlone'];
+ unset($value['sendAlone']);
+ }
+ if (!$value) {
+ $value = $key;
+ } elseif($type === 'js' && $key === 'jquery' && ($sizeLimit || $_sendAlone)) {
+ $i++;
+ $stack[$i][] = 'jquery';
+ foreach ($value as $plugin) {
+ $i++;
+ $stack[$i][] = 'jquery.' . $plugin;
+ $i++;
+ }
+ continue;
+ } else {
+ foreach ($value as $_k => &$_v) {
+ if (!is_numeric($_k)) {
+ $_v = $_k . '=' . $_v;
+ }
+ }
+ $value = $key . ',' . implode(',', $value);
+ }
+ }
+ if ($_sendAlone) {
+ $i++;
+ }
+ $stack[$i][] = $value;
+ if ($_sendAlone) {
+ $i++;
+ }
+ }
+ $return = array();
+ foreach ($stack as &$files) {
+ $url = MiCompressor::_url($files, $type, $sizeLimit);
+ foreach((array)$url as $u) {
+ $return[] = $u;
+ }
+ }
+ if (count($return) === 1) {
+ return $return[0];
+ }
+ return $return;
+ }
+/**
+ * cachePath method
*
* @param mixed $type
+ * @param mixed $hash
+ * @param bool $relative return a relative or absolute path
* @static
- * @return void
- * @access private
+ * @return string the absolute/relative path to the corresponding cache file
+ * @access protected
+ */
+ protected static function cachePath($type, $hash, $relative = false) {
+ $debug = MiCompressor::cRead();
+ $clear = MiCompressor::cRead('cacheClear');
+ $return = $type . '_' . $hash . '_' . ($debug?'d':'p') . ($clear?'t':'p');
+ $return = MiCompressor::cRead('cacheDir') . $return;
+ if ($relative) {
+ return str_replace(CACHE, '', $return);
+ }
+ return $return;
+ }
+/**
+ * c(onfigure)Read method
+ *
+ * Write default settings as appropriate on first read
+ * Use the Configure class if it exists, otherwise use default setting
+ * First none-null result encountered wins.
+ *
+ * Call with multiple paramters naming fallback settings e.g.
+ * $debug = MiCompressor::cRead('cacheClear', 'debug', 'Asset.someothersetting');
+ * Again, first none-null result wins.
+ *
+ * @param string $setting 'debug'
+ * @param bool $prefix true
+ * @static
+ * @return mixed, config value
+ * @access protected
+ */
+ protected static function cRead($setting = 'debug', $prefix = true) {
+ if (!strpos($setting, '.') && $prefix) {
+ $setting = 'MiCompressor.' . $setting;
+ }
+ if (!MiCompressor::$initialized) {
+ MiCompressor::$initialized = true;
+
+ $debug = MiCompressor::cRead('debug');
+ if ($debug === null) {
+ $debug = MiCompressor::cRead('debug', false);
+ }
+ if ($debug) {
+ MiCompressor::$defaultSettings['MiCompressor.cacheDuration'] = '+10 minutes';
+ } else {
+ MiCompressor::$defaultSettings['MiCompressor.cacheDuration'] = '+1 year';
+ }
+ MiCompressor::$settings['MiCompressor.debug'] = $debug;
+ unset (MiCompressor::$settings['debug']);
+
+ MiCompressor::cRead('log', 'debug');
+ MiCompressor::cRead('cacheClear', 'debug');
+
+ $minify = MiCompressor::cRead('minify');
+ if ($minify === null) {
+ MiCompressor::$settings['MiCompressor.minify'] = !$debug;
+ }
+
+ $dir = MiCompressor::cRead('cacheDir');
+ if (!$dir) {
+ MiCompressor::$defaultSettings['MiCompressor.cacheDir'] = CACHE;
+ }
+ MiCompressor::$defaultSettings['MiCompressor.webrootDir'] = WWW_ROOT;
+ MiCompressor::$defaultSettings['MiCompressor.cssDir'] = CSS;
+ MiCompressor::$defaultSettings['MiCompressor.jsDir'] = JS;
+ $salt = MiCompressor::cRead('salt');
+ if (!$salt) {
+ MiCompressor::$defaultSettings['MiCompressor.salt'] = SITE_VERSION;
+ }
+
+ if (!class_exists('App')) {
+ MiCompressor::$defaultSettings['MiCompressor.bypassLoadMinifyLib'] = true;
+ }
+ }
+ if (array_key_exists($setting, MiCompressor::$settings)) {
+ return MiCompressor::$settings[$setting];
+ }
+
+ if (isset(MiCompressor::$defaultSettings[$setting])) {
+ return MiCompressor::$settings[$setting] = MiCompressor::$defaultSettings[$setting];
+ }
+
+ if (class_exists('Configure')) {
+ $return = Configure::read($setting);
+ $fallbacks = func_get_args();
+ array_shift($fallbacks);
+ if ($return === null && $fallbacks) {
+ $return = call_user_func_array(array('MiCompressor', 'cRead'), $fallbacks);
+ }
+ return MiCompressor::$settings[$setting] = $return;
+ }
+
+ $return = MiCompressor::$defaultSettings[$setting];
+ $fallbacks = func_get_args();
+ array_shift($fallbacks);
+ if ($return === null && $fallbacks) {
+ $return = call_user_func_array(array('MiCompressor', 'cRead'), $fallbacks);
+ }
+ return MiCompressor::$settings[$setting] = $return;
+ }
+/**
+ * hash method
+ *
+ * Return the hash to be used for the passed arg
+ *
+ * @param mixed $arg array or string of requests
+ * @static
+ * @return string the hash of the passed arg
+ * @access protected
*/
- private static function loadCompressLib($type) {
+ protected static function hash($arg) {
+ $salt = MiCompressor::cRead('salt');
+ if (is_array($arg)) {
+ $arg = implode('|', $arg);
+ }
+ if (function_exists('uses')) {
+ uses('Security');
+ return Security::hash($salt . $arg, null, true);
+ }
+ return sha1($salt . $arg);
+ }
+/**
+ * loadMinifyLib method
+ *
+ * @param mixed $type
+ * @static
+ * @return bool true on success
+ * @access protected
+ */
+ protected static function loadMinifyLib($type) {
+ if (MiCompressor::cRead('bypassLoadMinifyLib')) {
+ if (!class_exists('HTTP_ConditionalGet')) {
+ MiCompressor::log('PROBLEM: HTTP_ConditionalGet (part of the Minify lib) not found, couldn\'t load the minify classes.');
+ return false;
+ }
+ return true;
+ }
+ if (!class_exists('App')) {
+ MiCompressor::log('PROBLEM: App class (part of CakePHP lib) not found, couldn\'t load the minify classes.');
+ MiCompressor::log(' To Resolve set MiCompressor.bypassLoadMinifyLib to true and include the minify classes manually.');
+ return false;
+ }
if($type === 'js') {
return App::import('Vendor', $type . 'Min', array('file' => 'minify/lib/JSMin.php'));
} elseif ($type === 'css') {
- ini_set('include_path', dirname(__FILE__) . '/minify/lib:' . ini_get('include_path'));
+ ini_set('include_path', dirname(__FILE__) . '/minify/lib'. PATH_SEPARATOR . ini_get('include_path'));
return App::import('Vendor', $type . 'Min', array('file' => 'minify/lib/Minify/CSS.php'));
} else {
return App::import('Vendor', $type . 'Min', array('file' => 'minify/lib/HTTP/ConditionalGet.php'));
}
}
/**
+ * loadCssJqueryPlugin method
+ *
+ * @param string $plugin ''
+ * @param bool $minify false
+ * @return void
+ * @access protected
+ */
+ protected static function loadCssJqueryPlugin($plugin = '', $minify = false) {
+ if (isset(MiCompressor::$map['css']['jquery'][$plugin])) {
+ $filename = MiCompressor::$map['css']['jquery'][$plugin];
+ } else {
+ $filename = "jquery.$plugin.css";
+ }
+ if (is_array($filename)) {
+ $return = '';
+ foreach($filename as $f) {
+ $return .= MiCompressor::loadCssJqueryPlugin($f, $minify);
+ }
+ return $return;
+ }
+ if ($minify) {
+ $found = true;
+ $filename = str_replace('.css', '.min.css', $filename);
+ if (file_exists(CSS . $filename)) {
+ MiCompressor::log(' ' . $filename);
+ MiCompressor::log(' File ' . CSS . "$filename found");
+ echo file_get_contents(CSS . $filename);
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "css/jquery/$filename"))) {
+ MiCompressor::log(' ' . $filename);
+ MiCompressor::log(" Found vendor version css/jquery/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "css/$filename"))) {
+ MiCompressor::log(' ' . $filename);
+ MiCompressor::log(" Found vendor version css/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
+ MiCompressor::log(' ' . $filename);
+ MiCompressor::log(" Found vendor version jquery/plugins/$plugin/$filename for Jquery $plugin");
+ } else {
+ $found = false;
+ }
+ if ($found) {
+ return ob_get_clean();
+ }
+ $filename = str_replace('.min.css', '.css', $filename);
+ }
+ MiCompressor::log(' ' . $filename);
+ if (file_exists(CSS . $filename)) {
+ MiCompressor::log(' File ' . CSS . "$filename found");
+ echo file_get_contents(CSS . $filename);
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "css/jquery/$filename"))) {
+ MiCompressor::log(" Found vendor version css/jquery/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "css/$filename"))) {
+ MiCompressor::log(" Found vendor version css/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'css/jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
+ MiCompressor::log(" Found vendor version jquery/plugins/$plugin/$filename for Jquery $plugin");
+ } else {
+ MiCompressor::log(" PROBLEM: The jquery plugin jquery/plugins/$plugin/$filename could not be loaded.");
+ }
+ return ob_get_clean();
+
+ }
+/**
* loadFile method
*
- * For the requested file, find it and return it. if compress is set to true send through compress(Css|Js) as
- * appropriate first
+ * For the requested file, find it and return it. if minify is set to true send through minify(Css|Js) as
+ * appropriate first.
+ *
+ * For CSS files, check for @import declarations and auto-correct any url() references in the file
*
* @param string $filename
* @param mixed $params
- * @param bool $compress
+ * @param bool $minify
* @static
- * @return void
- * @access private
+ * @return string the file's contents if appropriate
+ * @access protected
*/
- private static function loadFile($filename = '', $params = array(), $compress = false, $type = 'js') {
- if ($type === 'js') {
- $base = JS;
+ protected static function loadFile($filename = '', $params = array(), $minify = false, $type = 'js') {
+ if ($filename[0] === '/') {
+ $base = MiCompressor::cRead('webrootDir');
+ } elseif ($type === 'js') {
+ $base = MiCompressor::cRead('jsDir');
} elseif($type === 'css') {
- $base = CSS;
+ $base = MiCompressor::cRead('cssDir');
} else {
var_dump($base); die;
}
$file = $base . $filename . '.' . $type;
- if ($compress && file_exists($base . $filename . '.min.' . $type)) {
- $file = $base . $filename . '.min.' . $type;
+ $minFile = $base . $filename . '.min.' . $type;
+ if (in_array($filename . '.' . $type, MiCompressor::$loadedFiles)) {
+ MiCompressor::log("File $filename.type already loaded");
+ return;
+ }
+ MiCompressor::$loadedFiles[] = $filename . '.' . $type;
+
+ if ($minify && file_exists($minFile)) {
+ $file = $minFile;
MiCompressor::log("File $file found");
return file_get_contents($file);
} elseif (file_exists($file)) {
MiCompressor::log("File $file found");
$return = file_get_contents($file);
} else {
+ if ($filename[0] === '/') {
+ $vendorFile = substr($filename . '.' . $type, 1);
+ } else {
+ $vendorFile = $type . '/' . $filename . '.' . $type;
+ }
ob_start();
- if (!App::import('Vendor', str_replace('.', '_', $filename . $type), array('file' => $type . '/' . $filename . '.' . $type))) {
- $compress = false;
- MiCompressor::log("PROBLEM: No file for $type/$filename.{$type} could be found");
+ if (class_exists('App') &&
+ !App::import('Vendor', str_replace('.', '_', $filename . $type), array('file' => $vendorFile))) {
+ $minify = false;
+ MiCompressor::log("PROBLEM: No file for $vendorFile could be found");
}
$return = ob_get_clean();
}
if ($type === 'css') {
+ if (strpos($filename, '/', 1)) {
+ $baseFolder = dirname($filename) . '/';
+ } else {
+ $baseFolder = '';
+ }
preg_match_all('/@import\s*(?:url\()?(?:["\'])([^"\']*)\.css(?:["\'])\)?;/', $return, $matches);
foreach ($matches[1] as $i => $cssFile) {
- $cssFile = dirname($filename) . '/' . $cssFile;
- $import = MiCompressor::loadFile($cssFile, $params, false, 'css');
- $return = str_replace($matches[0][$i], $import, $return);
+ if ($minify) {
+ $return = str_replace($matches[0][$i], '', $return);
+ $return .= MiCompressor::loadFile($baseFolder . $cssFile, $params, $minify, 'css');
+ } elseif ($baseFolder) {
+ $replace = str_replace($cssFile, $baseFolder . $cssFile, $matches[0][$i]);
+ $return = str_replace($matches[0][$i], $replace, $return);
+ }
}
- }
- if ($compress) {
- $compressMethod = 'compress' . Inflector::camelize($type);
- return MiCompressor::$compressMethod($return, $filename);
+ if ($baseFolder && strpos($return, 'url')) {
+ preg_match_all('@url\s*\((?:[\s"\']*)([^\s"\']*)(?:[\s"\']*)\)@', $return, $matches);
+ $corrected = false;
+ $urls = array_unique($matches[1]);
+ foreach ($urls as $url) {
+ if (strpos($url, $baseFolder) !== 0 && $url[0] !== '/') {
+ $corrected = true;
+ $return = str_replace($url, $baseFolder . $url, $return);
+ }
+ }
+ if ($corrected) {
+ MiCompressor::log("\t Auto corrected url paths in $filename");
+ }
+ }
+ } elseif ($minify) {
+ $minifyMethod = 'minify' . Inflector::camelize($type);
+ return MiCompressor::$minifyMethod($return, $filename);
}
return $return;
}
/**
* Bespoke load method for Jquery.
*
- * Allow for loading the distributed, already compressed, version of jquery; and load plugins from
+ * Allow for loading the distributed, already minifyed, version of jquery; and load plugins from
* parameters for ease in views. requesting 'mini.js?...|jquery,abc,xyz|...' will load jquery, with the abc and xyz
* plugins
*
* @param array $plugins
- * @param bool $compress
+ * @param bool $minify
* @static
* @return void
- * @access private
+ * @access protected
*/
- private static function loadJsJquery($plugins = array(), $compress = false) {
+ protected static function loadJsJquery($plugins = array(), $minify = false) {
ob_start();
- if ($compress && file_exists(JS . 'jquery.min.js')) {
+ if ($minify && file_exists(JS . 'jquery.min.js')) {
MiCompressor::log(' File ' . JS . 'jquery.min.js found');
echo file_get_contents(JS . 'jquery.min.js');
} elseif (file_exists(JS . 'jquery.js')) {
MiCompressor::log(' File ' . JS . 'jquery.js found');
$return = file_get_contents(JS . 'jquery.js');
- if ($compress) {
- MiCompressor::log(' WARNING: ' . JS . 'jquery.min.js not found. compressing on the fly');
- echo MiCompressor::compressJs($return, 'jquery');
+ if ($minify) {
+ MiCompressor::log(' WARNING: ' . JS . 'jquery.min.js not found. minifying on the fly');
+ echo MiCompressor::minifyJs($return, 'jquery');
} else {
echo $return;
}
- } elseif ($compress && App::import('Vendor', 'jquery', array('file' => 'jquery/jquery/dist/jquery.min.js'))) {
+ } elseif ($minify && App::import('Vendor', 'jquery', array('file' => 'jquery/jquery/dist/jquery.min.js'))) {
MiCompressor::log(' Found vendor version for jquery/jquery/dist/jquery.min.js');
} elseif (App::import('Vendor', 'jquery', array('file' => 'jquery/jquery/dist/jquery.js'))) {
- if ($compress) {
+ if ($minify) {
MiCompressor::log(' WARNING: No vendor version for jquery/jquery/dist/jquery.min.js.'
- . ' compressing on the fly');
+ . ' minifying on the fly');
$contents = ob_get_clean();
ob_start();
- echo MiCompressor::compressJs($contents, 'jquery', "\t");
+ echo MiCompressor::minifyJs($contents, 'jquery', "\t");
} else {
MiCompressor::log(' Found vendor version for jquery/jquery/dist/jquery.js');
}
} else {
- if ($compress) {
+ if ($minify) {
MiCompressor::log(' PROBLEM: No vendor version for jquery/jquery/dist/jquery.min.js');
}
MiCompressor::log(' PROBLEM: No vendor version for jquery/jquery/dist/jquery.js found');
@@ -483,41 +809,40 @@ abstract class MiCompressor {
MiCompressor::log(' make');
}
foreach ($plugins as $plugin) {
- if (isset(MiCompressor::$map['js']['jquery'][$plugin])) {
- $filename = MiCompressor::$map['js']['jquery'][$plugin];
- } else {
- $filename = "jquery.$plugin.js";
- }
- $_compress = $compress;
- ob_start();
- echo "\r\n";
- if ($compress) {
- $found = true;
- $filename = str_replace('.js', '.min.js', $filename);
- if (file_exists(JS . $filename)) {
- MiCompressor::log(' ' . $filename);
- MiCompressor::log(' File ' . JS . "$filename found");
- echo file_get_contents(JS . $filename);
- } elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/jquery/$filename"))) {
- MiCompressor::log(' ' . $filename);
- MiCompressor::log(" Found vendor version js/jquery/$filename for Jquery $plugin");
- } elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/$filename"))) {
- MiCompressor::log(' ' . $filename);
- MiCompressor::log(" Found vendor version js/$filename for Jquery $plugin");
- } elseif (App::import('Vendor', 'jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
- MiCompressor::log(' ' . $filename);
- MiCompressor::log(" Found vendor version jquery/plugins/$plugin/$filename for Jquery $plugin");
- } else {
- $found = false;
- }
- if ($found) {
- echo ob_get_clean();
- continue;
- }
- $filename = str_replace('.min.js', '.js', $filename);
+ echo MiCompressor::loadJsJqueryPlugin($plugin, $minify);
+ }
+ return ob_get_clean();
+ }
+/**
+ * Bespoke load method for a Jquery plugin file
+ *
+ * @param stirng $plugin
+ * @param bool $minify
+ * @static
+ * @return void
+ * @access protected
+ */
+ protected static function loadJsJqueryPlugin($plugin = '', $minify = false) {
+ if (isset(MiCompressor::$map['js']['jquery'][$plugin])) {
+ $filename = MiCompressor::$map['js']['jquery'][$plugin];
+ } else {
+ $filename = "jquery.$plugin.js";
+ }
+ if (is_array($filename)) {
+ $return = '';
+ foreach($filename as $f) {
+ $return .= MiCompressor::loadJsJqueryPlugin($f, $minify);
}
- MiCompressor::log(' ' . $filename);
+ return $return;
+ }
+
+ $_minify = $minify;
+ echo "\r\n";
+ if ($minify) {
+ $found = true;
+ $filename = str_replace('.js', '.min.js', $filename);
if (file_exists(JS . $filename)) {
+ MiCompressor::log(' ' . $filename);
MiCompressor::log(' File ' . JS . "$filename found");
echo file_get_contents(JS . $filename);
} elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/jquery/$filename"))) {
@@ -526,18 +851,37 @@ abstract class MiCompressor {
} elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/$filename"))) {
MiCompressor::log(' ' . $filename);
MiCompressor::log(" Found vendor version js/$filename for Jquery $plugin");
- } elseif (App::import('Vendor', 'jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
+ } elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
+ MiCompressor::log(' ' . $filename);
MiCompressor::log(" Found vendor version jquery/plugins/$plugin/$filename for Jquery $plugin");
} else {
- MiCompressor::log(" PROBLEM: The jquery plugin jquery/plugins/$plugin/$filename could not be loaded.");
- $_compress = false;
+ $found = false;
}
- if ($_compress) {
- $pluginContents = ob_get_clean();
- ob_start();
- echo MiCompressor::compressJs($pluginContents, 'jquery.' . $plugin, "\t");
+ if ($found) {
+ echo ob_get_clean();
+ return;
}
- echo ob_get_clean();
+ $filename = str_replace('.min.js', '.js', $filename);
+ }
+ ob_start();
+ MiCompressor::log(' ' . $filename);
+ if (file_exists(JS . $filename)) {
+ MiCompressor::log(' File ' . JS . "$filename found");
+ echo file_get_contents(JS . $filename);
+ } elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/jquery/$filename"))) {
+ MiCompressor::log(" Found vendor version js/jquery/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'js/jquery/' . $plugin, array('file' => "js/$filename"))) {
+ MiCompressor::log(" Found vendor version js/$filename for Jquery $plugin");
+ } elseif (App::import('Vendor', 'jquery/' . $plugin, array('file' => "jquery/plugins/$plugin/$filename"))) {
+ MiCompressor::log(" Found vendor version jquery/plugins/$plugin/$filename for Jquery $plugin");
+ } else {
+ MiCompressor::log(" PROBLEM: The jquery plugin jquery/plugins/$plugin/$filename could not be loaded.");
+ $_minify = false;
+ }
+ if ($_minify) {
+ $pluginContents = ob_get_clean();
+ ob_start();
+ echo MiCompressor::minifyJs($pluginContents, 'jquery.' . $plugin, "\t");
}
return ob_get_clean();
}
@@ -550,21 +894,16 @@ abstract class MiCompressor {
* @param string $contents
* @static
* @return string the contents to output, or null if no output is to be sent (to trigger a 304 header upstream)
- * @access private
+ * @access protected
*/
- private static function out($file, $contents = null, $eTag = null) {
- if ($contents === null) {
- $contents = file_get_contents($file);
- debug ($contents);
- die;
- }
+ protected static function out($file, $contents = null, $eTag = null) {
if (preg_match('@^/\* eTag:(\S+) \*/@', $contents, $match)) {
$eTag = $match['1'];
}
if ($eTag) {
$contents = str_replace('/* eTag:' . $eTag .' */', '', $contents);
}
- if (!MiCompressor::loadCompressLib('headers')) {
+ if (!MiCompressor::loadMinifyLib('headers')) {
return $contents;
}
if (file_exists($file)) {
@@ -572,7 +911,7 @@ abstract class MiCompressor {
} else {
$fileCreated = time();
}
- $fileExpires = strtotime(MiCompressor::$cacheDuration, $fileCreated);
+ $fileExpires = strtotime(MiCompressor::cRead('cacheDuration'), $fileCreated);
$params = array(
'lastModifiedTime' => $fileCreated,
@@ -589,111 +928,95 @@ abstract class MiCompressor {
return $contents;
}
/**
- * url method
+ * parse method
*
- * @param array $request
- * @param array $params
- * @return void
- * @access public
+ * Used to determine which component files, and sub files have been requested
+ * For the request string of the form: file|file2|file3|file4,x,y=300,z|file5.. generate an array of the form:
+ * array(
+ * file => array(),
+ * file2 => array(),
+ * file3 => array(),
+ * file4 => array('x', 'y' => 300, 'z'),
+ * file5 => array()
+ * )
+ * This format allows passing parameters to scripts when included (accessible as $params);
+ *
+ * A hash is automatically added to the url by the MiHtml and MiJavascript helpers. The hash is checked in this
+ * method and if it doesn't match (this should never happen for a valid request), will either add a log message if not
+ * in production mode or return false. Compressing (in particular Js files) is expensive, therefore using a hash
+ * prevents a malicious user from requesting arbritary varying urls and tying up the server
+ *
+ * The hash is returned primarily to be used as the default cache key
+ *
+ * @param string $requestString
+ * @param mixed $hash
+ * @static
+ * @return mixed array of files to process, or false for an invalid/doctored request
+ * @access protected
*/
- function url($request = array(), $params = array()) {
- extract(am(array(
- 'salt' => defined('SITE_VERSION')?SITE_VERSION:'',
- 'sendAlone' => Configure::read(),
- 'type' => 'js',
- 'sizeLimit' => false,
- ), $params));
- $stack = array();
- $i = 0;
- foreach ($request as $key => &$value) {
- $_sendAlone = $sendAlone;
- if (is_string($key)) {
- if (is_array($value) && isset($value['sendAlone'])) {
- $_sendAlone = $value['sendAlone'];
- unset($value['sendAlone']);
- }
- if (!$value) {
- $value = $key;
- } elseif($type === 'js' && $key === 'jquery' && ($sizeLimit || $_sendAlone)) {
- $i++;
- $stack[$i][] = 'jquery';
- foreach ($value as $plugin) {
- $i++;
- $stack[$i][] = 'jquery.' . $plugin;
- $i++;
- }
- continue;
- } else {
- foreach ($value as $_k => &$_v) {
- if (!is_numeric($_k)) {
- $_v = $_k . '=' . $_v;
- }
- }
- $value = $key . ',' . implode(',', $value);
- }
- }
- if ($_sendAlone) {
- $i++;
+ protected static function parse($requestString = '', &$hash = null) {
+ if ($hash === null) {
+ $requests = explode('|', $requestString);
+ $hash = array_pop($requests);
+ } else {
+ $requests = explode('|', $requestString);
+ if ($key = array_search('hash', $requests)) {
+ unset ($requests[$key]);
+ $hash = 'hash=' . $hash;
}
- $stack[$i][] = $value;
- if ($_sendAlone) {
- $i++;
+ }
+ $problem = false;
+ if (strpos($hash, 'hash=') !== 0) {
+ $problem = true;
+ MiCompressor::log('PROBLEM: No hash in the request string');
+ } else {
+ list(,$hash) = explode('=', $hash);
+ $_hash = MiCompressor::hash($requests);
+ if ($hash !== $_hash) {
+ $problem = true;
+ MiCompressor::log('PROBLEM: Hash doesn\'t match. Expected: ' . $_hash);
}
}
+ if ($problem && !MiCompressor::cRead()) {
+ return false;
+ }
+
$return = array();
- foreach ($stack as &$files) {
- $url = MiCompressor::__url($files, $type, $salt, $sizeLimit);
- foreach((array)$url as $u) {
- $return[] = $u;
+ foreach ($requests as $filename) {
+ $params = array();
+ if (strpos($filename, ',')) {
+ $params = explode(',', $filename);
+ $filename = array_shift($params);
+ foreach ($params as $k => $v) {
+ if (strpos($v, '=')) {
+ unset ($params[$k]);
+ list($k, $v) = explode('=', $v);
+ $params[$k] = $v;
+ }
+ }
}
- }
- if (count($return) === 1) {
- return $return[0];
+ $return[$filename] = $params;
}
return $return;
}
/**
- * cachePath method
- *
- * @param mixed $type
- * @param mixed $hash
- * @param mixed $appDebug
- * @param bool $clear
- * @param bool $relative
- * @return void
- * @access private
- */
- function __cachePath($type, $hash, $appDebug = null, $clear = false, $relative = false) {
- if ($appDebug === null) {
- $appDebug = (class_exists('Configure')?Configure::read():false);
- }
- if ($clear === null) {
- $clear = $appDebug;
- }
- $return = 'views/' . $type . '_' . $hash . '_' . ($appDebug?'d':'p') . ($clear?'t':'p');
- if ($relative) {
- return $return;
- }
- return CACHE . $return;
- }
-/**
* url method
*
* @param mixed $files
* @param string $type
- * @param string $salt
* @param bool $sizeLimit
- * @return void
- * @access private
+ * @static
+ * @return mixed the url or urls corresponding to the requested files
+ * @access protected
*/
- function __url($files, $type = 'js', $salt = '', $sizeLimit = false) {
+ protected static function _url($files, $type = 'js', $sizeLimit = false) {
$string = implode('|', $files);
- $hash = Security::hash($salt . $string, null, true);
+ $hash = MiCompressor::hash($string);
if ($sizeLimit && count($files) > 1) {
- $cachePath = MiCompressor::__cachePath($type, $hash);
+ $cachePath = MiCompressor::cachePath($type, $hash);
if (file_exists($cachePath) && filesize($cachePath) > ($sizeLimit - 45)) {
foreach($files as $file) {
- $return[] = MiCompressor::__url(array($file), $type, $salt);
+ $return[] = MiCompressor::_url(array($file), $type);
}
return $return;
}
@@ -705,11 +1028,25 @@ abstract class MiCompressor {
/**
* Included for compatibility to allow use and testing in a standalone manner
*/
+if (!defined('DS')) {
+ define('DS', DIRECTORY_SEPARATOR);
+}
+if (!defined('WWW_ROOT')) {
+ define('WWW_ROOT', dirname(__FILE__));
+}
+if (!defined('CSS')) {
+ define('CSS', WWW_ROOT . 'css' . DS);
+}
+if (!defined('JS')) {
+ define('JS', WWW_ROOT . 'js' . DS);
+}
if (!defined('CACHE')) {
- define('CACHE', 'cache');
- define('CSS', 'css');
- define('JS', 'js');
+ define('CACHE', dirname(__FILE__) . DS . 'cache' . DS);
+}
+if (!defined('SITE_VERSION')) {
+ define('SITE_VERSION', 42);
}
+
if (!function_exists('getMicrotime')) {
/**
* Returns microtime for execution time checking
@@ -721,4 +1058,42 @@ if (!function_exists('getMicrotime')) {
return ((float)$usec + (float)$sec);
}
}
+if (!function_exists('cache')) {
+/**
+ * cache method
+ *
+ * Duplicate of CakePHP cache method to allow using this script standalone
+ *
+ * @param mixed $path
+ * @param mixed $data
+ * @param mixed $expires null
+ * @return string cache contents
+ * @access public
+ */
+ function cache($path, $data, $expires = null) {
+ $now = time();
+ if (!is_numeric($expires)) {
+ $expires = strtotime($expires, $now);
+ }
+
+ $filename = MiCompressor::cRead('cacheDir') . $path;
+ $timediff = $expires - $now;
+ $filetime = false;
+ if (file_exists($filename)) {
+ $filetime = @filemtime($filename);
+ }
+ if ($data === null) {
+ if (file_exists($filename) && $filetime !== false) {
+ if ($filetime + $timediff < $now) {
+ @unlink($filename);
+ } else {
+ $data = @file_get_contents($filename);
+ }
+ }
+ } elseif (is_writable(dirname($filename))) {
+ @file_put_contents($filename, $data);
+ }
+ return $data;
+ }
+}
?>
\ No newline at end of file
diff --git a/views/elements/markitup.ctp b/views/elements/markitup.ctp
index c7c1bab..c081691 100644
--- a/views/elements/markitup.ctp
+++ b/views/elements/markitup.ctp
@@ -1,9 +1,9 @@
<?php /* SVN FILE: $Id: markitup.ctp 673 2008-10-06 14:05:17Z AD7six $ */
-$miJavascript->link('markitup/jquery.markitup.pack.js', false);
+$miJavascript->link('markitup/jquery.markitup.js', false);
$miJavascript->link('markitup/sets/default/set.js', false);
$html->css(array('/js/markitup/skins/markitup/style.css', '/js/markitup/sets/default/style.css'), null, array(), false);
$miJavascript->codeBlock(
'$(document).ready(function() {
$("' . $process . '").markItUp(mySettings);
});', array('inline' => false));
-?>
+?>
\ No newline at end of file
diff --git a/webroot/css/cake.cookbook.css b/webroot/css/cake.cookbook.css
index b0298c2..5b67e38 100644
--- a/webroot/css/cake.cookbook.css
+++ b/webroot/css/cake.cookbook.css
@@ -476,7 +476,7 @@ a.leavePopup {
margin:-10px 0 0;
padding:1px;
position:absolute;
- right:1.5em;
+ right:26px;
top:50%;
width:19px;
}
\ No newline at end of file
diff --git a/webroot/js/markitup/jquery.markitup.min.js b/webroot/js/markitup/jquery.markitup.min.js
new file mode 100644
index 0000000..73c8c01
--- /dev/null
+++ b/webroot/js/markitup/jquery.markitup.min.js
@@ -0,0 +1,9 @@
+// ----------------------------------------------------------------------------
+// markItUp! Universal MarkUp Engine, JQuery plugin
+// v 1.1.0 beta
+// Dual licensed under the MIT and GPL licenses.
+// ----------------------------------------------------------------------------
+// Copyright (C) 2007-2008 Jay Salvat
+// http://markitup.jaysalvat.com/
+// ----------------------------------------------------------------------------
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3($){$.2L.Y=3(f,g){C k,u,A,I;u=A=I=l;k={B:\'\',17:\'\',T:\'\',1w:\'\',1U:o,2w:\'2s\',1j:\'~/3l/1D.15\',1c:\'\',28:\'25\',1k:o,1B:\'\',1A:\'\',1z:{},1X:{},1V:{},1T:{},2E:[{}]};$.R(k,f,g);2(!k.T){$(\'3v\').1f(3(a,b){1N=$(b).11(0).3j.3f(/(.*)3c\\.3a(\\.37)?\\.34$/);2(1N!==2g){k.T=1N[1]}})}4 G.1f(3(){C d,q,16,18,m,D,J,L,Z,1x,w,1u,K,14;d=$(G);q=G;16=[];14=l;18=m=0;D=-1;k.1c=1i(k.1c);k.1j=1i(k.1j);3 1i(a,b){2(b){4 a.W(/("|\')~\\//g,"$1"+k.T)}4 a.W(/^~\\//,k.T)}3 2C(){B=\'\';17=\'\';2(k.B){B=\'B="\'+k.B+\'"\'}7 2(d.1S("B")){B=\'B="Y\'+(d.1S("B").2y(0,1).3z())+(d.1S("B").2y(1))+\'"\'}2(k.17){17=\'O="\'+k.17+\'"\'}d.1P(\'<v \'+17+\'"></v>\');d.1P(\'<v \'+B+\' O="Y"></v>\');d.1P(\'<v O="3u"></v>\');d.2r("2q");Z=$(\'<v O="3r"></v>\').2p(d);$(1M(k.2E)).1L(Z);1x=$(\'<v O="3p"></v>\').1K(d);2(k.1k===o&&$.1a.3k!==o){1k=$(\'<v O="3i"></v>\').1K(d).1b("3d",3(e){C h=d.2a(),y=e.2d,1n,1o;1n=3(e){d.2u("2a",31.30(20,e.2d+h-y)+"2Y");4 l};1o=3(e){$("15").1I("2t",1n).1I("1t",1o);4 l};$("15").1b("2t",1n).1b("1t",1o)});1x.2n(1k)}d.23(1Q).2R(1Q);d.1b("1C",3(e,a){2(a.1r!==l){11()}2(q===$.Y.21){V(a)}});d.1h(3(){$.Y.21=G})}3 1M(b){C c=$(\'<U></U>\'),i=0;$(\'z:1Y > U\',c).2u(\'2M\',\'p\');$(b).1f(3(){C a=G,t=\'\',1m,z,j;1m=(a.12)?(a.1W||\'\')+\' [3K+\'+a.12+\']\':(a.1W||\'\');12=(a.12)?\'2J="\'+a.12+\'"\':\'\';2(a.2I){z=$(\'<z O="3J">\'+(a.2I||\'\')+\'</z>\').1L(c)}7{i++;2H(j=16.5-1;j>=0;j--){t+=16[j]+"-"}z=$(\'<z O="2G 2G\'+t+(i)+\' \'+(a.3I||\'\')+\'"><a 3H="" \'+12+\' 1m="\'+1m+\'">\'+(a.1W||\'\')+\'</a></z>\').1b("3G",3(){4 l}).2F(3(){4 l}).1t(3(){2(a.2D){3F(a.2D)()}V(a);4 l}).1Y(3(){$(\'> U\',G).3E();$(N).3D(\'2F\',3(){$(\'U U\',Z).2A()})},3(){$(\'> U\',G).2A()}).1L(c);2(a.2z){16.3C(i);$(z).2r(\'3B\').2n(1M(a.2z))}}});16.3A();4 c}3 2x(c){2(c){c=c.3w();c=c.W(/\\(\\!\\(([\\s\\S]*?)\\)\\!\\)/g,3(x,a){C b=a.1R(\'|!|\');2(I===o){4(b[1]!==2v)?b[1]:b[0]}7{4(b[1]===2v)?"":b[0]}});c=c.W(/\\[\\!\\[([\\s\\S]*?)\\]\\!\\]/g,3(x,a){C b=a.1R(\':!:\');2(14===o){4 l}1O=3t(b[0],(b[1])?b[1]:\'\');2(1O===2g){14=o}4 1O});4 c}4""}3 F(a){2($.3s(a)){a=a(L)}4 2x(a)}3 1g(a){H=F(J.H);19=F(J.19);Q=F(J.Q);M=F(J.M);2(Q!==""){p=H+Q+M}7 2(6===\'\'&&19!==\'\'){p=H+19+M}7{p=H+(a||6)+M}4{p:p,H:H,Q:Q,19:19,M:M}}3 V(a){C b,j,n,i;L=J=a;11();$.R(L,{1v:"",T:k.T,q:q,6:(6||\'\'),m:m});F(k.1B);F(J.1B);2(u===o&&A===o){F(J.3q)}$.R(L,{1v:1});2(u===o&&A===o){P=6.1R(/\\r?\\n/);2H(j=0,n=P.5,i=0;i<n;i++){2($.3o(P[i])!==\'\'){$.R(L,{1v:++j,6:P[i]});P[i]=1g(P[i]).p}7{P[i]=""}}8={p:P.3n(\'\\n\')};X=m;b=8.p.5+(($.1a.2m)?n:0)}7 2(u===o){8=1g(6);X=m+8.H.5;b=8.p.5-8.H.5-8.M.5;b-=1q(8.p)}7 2(A===o){8=1g(6);X=m;b=8.p.5;b-=1q(8.p)}7{8=1g(6);X=m+8.p.5;b=0;X-=1q(8.p)}2((6===\'\'&&8.Q===\'\')){D+=1J(8.p);X=m+8.H.5;b=8.p.5-8.H.5-8.M.5;D=d.E().1e(m,d.E().5).5;D-=1J(d.E().1e(0,m))}$.R(L,{m:m,18:18});2(8.p!==6&&14===l){2l(8.p);1H(X,b)}7{D=-1}11();$.R(L,{1v:\'\',6:6});2(u===o&&A===o){F(J.3h)}F(J.1A);F(k.1A);2(w&&k.1U){1F()}A=I=u=14=l}3 1J(a){2($.1a.2m){4 a.5-a.W(/\\n*/g,\'\').5}4 0}3 1q(a){2($.1a.2i){4 a.5-a.W(/\\r*/g,\'\').5}4 0}3 2l(a){2(N.6){C b=N.6.1E();b.2h=a}7{d.E(d.E().1e(0,m)+a+d.E().1e(m+6.5,d.E().5))}}3 1H(a,b){2(q.2e){1d=q.2e();1d.3b(o);1d.29(\'1G\',a);1d.39(\'1G\',b);1d.38()}7 2(q.2c){q.2c(a,a+b)}q.2b=18;q.1h()}3 11(){q.1h();18=q.2b;2(N.6){6=N.6.1E().2h;2($.1a.2i){C a=N.6.1E(),1p=a.36();1p.35(q);m=-1;33(1p.32(a)){1p.29(\'1G\');m++}}7{m=q.2k}}7{m=q.2k;6=d.E().1e(m,q.3e)}4 6}3 1D(){2(!w||w.2Z){2(k.1w){w=3g.2f(\'\',\'1D\',k.1w)}7{K=$(\'<2j O="2X"></2j>\');2(k.2w==\'2s\'){K.1K(1x)}7{K.2p(Z)}w=K[K.5-1].2W||2V[K.5-1]}}7 2(I===o){2(K){K.3m()}w.27();w=K=l}2(!k.1U){1F()}2(k.1w){w.1h()}}3 1F(){2(w){w.N.2f();w.N.2U(26());w.N.27()}}3 26(){2(k.1c!==\'\'){$.2o({24:\'2T\',2K:l,2B:k.1c,25:k.28+\'=\'+2S(d.E()),22:3(a){15=1i(a,1)}})}7{2(!1u){$.2o({2K:l,2B:k.1j,22:3(a){1u=1i(a,1)}})}15=1u.W(/<!-- 3x -->/g,d.E())}4 15}3 1Q(e){A=e.A;I=e.I;u=(!(e.I&&e.u))?e.u:l;$.R(L,{u:u,A:A,I:I});2(e.24===\'23\'){2(u===o){z=$("a[2J="+3y.2Q(e.1l)+"]",Z).1s(\'z\');2(z.5!==0){u=l;z.2P(\'1t\');4 l}}2(e.1l===13||e.1l===10){2(u===o){u=l;V(k.1V);4 k.1V.1y}7 2(A===o){A=l;V(k.1X);4 k.1X.1y}7{V(k.1z);4 k.1z.1y}}2(e.1l===9){2(D!==-1){11();D=d.E().5-D;1H(D,0);D=-1;4 l}7{V(k.1T);4 k.1T.1y}}}}2C()})};$.2L.2O=3(){4 G.1f(3(){$$=$(G).1I().2N(\'2q\');$$.1s(\'v\').1s(\'v.Y\').1s(\'v\').Q($$)})};$.Y=3(a){C b={1r:l};$.R(b,a);2(b.1r){4 $(b.1r).1f(3(){$(G).1h();$(G).1Z(\'1C\',[b])})}7{$(\'q\').1Z(\'1C\',[b])}}})(3L);',62,234,'||if|function|return|length|selection|else|string|||||||||||||false|caretPosition||true|block|textarea||||ctrlKey|div|previewWindow|||li|shiftKey|id|var|caretOffset|val|prepare|this|openWith|altKey|clicked|iFrame|hash|closeWith|document|class|lines|replaceWith|extend||root|ul|markup|replace|start|markItUp|header||get|key||abort|html|levels|nameSpace|scrollPosition|placeHolder|browser|bind|previewParserPath|range|substring|each|build|focus|localize|previewTemplatePath|resizeHandle|keyCode|title|mouseMove|mouseUp|rangeCopy|fixIeBug|target|parent|mouseup|template|line|previewInWindow|footer|keepDefault|onEnter|afterInsert|beforeInsert|insertion|preview|createRange|refreshPreview|character|set|unbind|fixOperaBug|insertAfter|appendTo|dropMenus|miuScript|value|wrap|keyPressed|split|attr|onTab|previewAutoRefresh|onCtrlEnter|name|onShiftEnter|hover|trigger||focused|success|keydown|type|data|renderPreview|close|previewParserVar|moveStart|height|scrollTop|setSelectionRange|clientY|createTextRange|open|null|text|msie|iframe|selectionStart|insert|opera|append|ajax|insertBefore|markItUpEditor|addClass|after|mousemove|css|undefined|previewPosition|magicMarkups|substr|dropMenu|hide|url|init|call|markupSet|click|markItUpButton|for|separator|accesskey|async|fn|display|removeClass|markItUpRemove|triggerHandler|fromCharCode|keyup|encodeURIComponent|POST|write|frame|contentWindow|markItUpPreviewFrame|px|closed|max|Math|inRange|while|js|moveToElementText|duplicate|pack|select|moveEnd|markitup|collapse|jquery|mousedown|selectionEnd|match|window|afterMultiInsert|markItUpResizeHandle|src|safari|templates|remove|join|trim|markItUpFooter|beforeMultiInsert|markItUpHeader|isFunction|prompt|markItUpContainer|script|toString|content|String|toUpperCase|pop|markItUpDropMenu|push|one|show|eval|contextmenu|href|className|markItUpSeparator|Ctrl|jQuery'.split('|'),0,{}))
\ No newline at end of file
diff --git a/webroot/js/markitup/jquery.markitup.pack.js b/webroot/js/markitup/jquery.markitup.pack.js
deleted file mode 100644
index 73c8c01..0000000
--- a/webroot/js/markitup/jquery.markitup.pack.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// ----------------------------------------------------------------------------
-// markItUp! Universal MarkUp Engine, JQuery plugin
-// v 1.1.0 beta
-// Dual licensed under the MIT and GPL licenses.
-// ----------------------------------------------------------------------------
-// Copyright (C) 2007-2008 Jay Salvat
-// http://markitup.jaysalvat.com/
-// ----------------------------------------------------------------------------
-eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3($){$.2L.Y=3(f,g){C k,u,A,I;u=A=I=l;k={B:\'\',17:\'\',T:\'\',1w:\'\',1U:o,2w:\'2s\',1j:\'~/3l/1D.15\',1c:\'\',28:\'25\',1k:o,1B:\'\',1A:\'\',1z:{},1X:{},1V:{},1T:{},2E:[{}]};$.R(k,f,g);2(!k.T){$(\'3v\').1f(3(a,b){1N=$(b).11(0).3j.3f(/(.*)3c\\.3a(\\.37)?\\.34$/);2(1N!==2g){k.T=1N[1]}})}4 G.1f(3(){C d,q,16,18,m,D,J,L,Z,1x,w,1u,K,14;d=$(G);q=G;16=[];14=l;18=m=0;D=-1;k.1c=1i(k.1c);k.1j=1i(k.1j);3 1i(a,b){2(b){4 a.W(/("|\')~\\//g,"$1"+k.T)}4 a.W(/^~\\//,k.T)}3 2C(){B=\'\';17=\'\';2(k.B){B=\'B="\'+k.B+\'"\'}7 2(d.1S("B")){B=\'B="Y\'+(d.1S("B").2y(0,1).3z())+(d.1S("B").2y(1))+\'"\'}2(k.17){17=\'O="\'+k.17+\'"\'}d.1P(\'<v \'+17+\'"></v>\');d.1P(\'<v \'+B+\' O="Y"></v>\');d.1P(\'<v O="3u"></v>\');d.2r("2q");Z=$(\'<v O="3r"></v>\').2p(d);$(1M(k.2E)).1L(Z);1x=$(\'<v O="3p"></v>\').1K(d);2(k.1k===o&&$.1a.3k!==o){1k=$(\'<v O="3i"></v>\').1K(d).1b("3d",3(e){C h=d.2a(),y=e.2d,1n,1o;1n=3(e){d.2u("2a",31.30(20,e.2d+h-y)+"2Y");4 l};1o=3(e){$("15").1I("2t",1n).1I("1t",1o);4 l};$("15").1b("2t",1n).1b("1t",1o)});1x.2n(1k)}d.23(1Q).2R(1Q);d.1b("1C",3(e,a){2(a.1r!==l){11()}2(q===$.Y.21){V(a)}});d.1h(3(){$.Y.21=G})}3 1M(b){C c=$(\'<U></U>\'),i=0;$(\'z:1Y > U\',c).2u(\'2M\',\'p\');$(b).1f(3(){C a=G,t=\'\',1m,z,j;1m=(a.12)?(a.1W||\'\')+\' [3K+\'+a.12+\']\':(a.1W||\'\');12=(a.12)?\'2J="\'+a.12+\'"\':\'\';2(a.2I){z=$(\'<z O="3J">\'+(a.2I||\'\')+\'</z>\').1L(c)}7{i++;2H(j=16.5-1;j>=0;j--){t+=16[j]+"-"}z=$(\'<z O="2G 2G\'+t+(i)+\' \'+(a.3I||\'\')+\'"><a 3H="" \'+12+\' 1m="\'+1m+\'">\'+(a.1W||\'\')+\'</a></z>\').1b("3G",3(){4 l}).2F(3(){4 l}).1t(3(){2(a.2D){3F(a.2D)()}V(a);4 l}).1Y(3(){$(\'> U\',G).3E();$(N).3D(\'2F\',3(){$(\'U U\',Z).2A()})},3(){$(\'> U\',G).2A()}).1L(c);2(a.2z){16.3C(i);$(z).2r(\'3B\').2n(1M(a.2z))}}});16.3A();4 c}3 2x(c){2(c){c=c.3w();c=c.W(/\\(\\!\\(([\\s\\S]*?)\\)\\!\\)/g,3(x,a){C b=a.1R(\'|!|\');2(I===o){4(b[1]!==2v)?b[1]:b[0]}7{4(b[1]===2v)?"":b[0]}});c=c.W(/\\[\\!\\[([\\s\\S]*?)\\]\\!\\]/g,3(x,a){C b=a.1R(\':!:\');2(14===o){4 l}1O=3t(b[0],(b[1])?b[1]:\'\');2(1O===2g){14=o}4 1O});4 c}4""}3 F(a){2($.3s(a)){a=a(L)}4 2x(a)}3 1g(a){H=F(J.H);19=F(J.19);Q=F(J.Q);M=F(J.M);2(Q!==""){p=H+Q+M}7 2(6===\'\'&&19!==\'\'){p=H+19+M}7{p=H+(a||6)+M}4{p:p,H:H,Q:Q,19:19,M:M}}3 V(a){C b,j,n,i;L=J=a;11();$.R(L,{1v:"",T:k.T,q:q,6:(6||\'\'),m:m});F(k.1B);F(J.1B);2(u===o&&A===o){F(J.3q)}$.R(L,{1v:1});2(u===o&&A===o){P=6.1R(/\\r?\\n/);2H(j=0,n=P.5,i=0;i<n;i++){2($.3o(P[i])!==\'\'){$.R(L,{1v:++j,6:P[i]});P[i]=1g(P[i]).p}7{P[i]=""}}8={p:P.3n(\'\\n\')};X=m;b=8.p.5+(($.1a.2m)?n:0)}7 2(u===o){8=1g(6);X=m+8.H.5;b=8.p.5-8.H.5-8.M.5;b-=1q(8.p)}7 2(A===o){8=1g(6);X=m;b=8.p.5;b-=1q(8.p)}7{8=1g(6);X=m+8.p.5;b=0;X-=1q(8.p)}2((6===\'\'&&8.Q===\'\')){D+=1J(8.p);X=m+8.H.5;b=8.p.5-8.H.5-8.M.5;D=d.E().1e(m,d.E().5).5;D-=1J(d.E().1e(0,m))}$.R(L,{m:m,18:18});2(8.p!==6&&14===l){2l(8.p);1H(X,b)}7{D=-1}11();$.R(L,{1v:\'\',6:6});2(u===o&&A===o){F(J.3h)}F(J.1A);F(k.1A);2(w&&k.1U){1F()}A=I=u=14=l}3 1J(a){2($.1a.2m){4 a.5-a.W(/\\n*/g,\'\').5}4 0}3 1q(a){2($.1a.2i){4 a.5-a.W(/\\r*/g,\'\').5}4 0}3 2l(a){2(N.6){C b=N.6.1E();b.2h=a}7{d.E(d.E().1e(0,m)+a+d.E().1e(m+6.5,d.E().5))}}3 1H(a,b){2(q.2e){1d=q.2e();1d.3b(o);1d.29(\'1G\',a);1d.39(\'1G\',b);1d.38()}7 2(q.2c){q.2c(a,a+b)}q.2b=18;q.1h()}3 11(){q.1h();18=q.2b;2(N.6){6=N.6.1E().2h;2($.1a.2i){C a=N.6.1E(),1p=a.36();1p.35(q);m=-1;33(1p.32(a)){1p.29(\'1G\');m++}}7{m=q.2k}}7{m=q.2k;6=d.E().1e(m,q.3e)}4 6}3 1D(){2(!w||w.2Z){2(k.1w){w=3g.2f(\'\',\'1D\',k.1w)}7{K=$(\'<2j O="2X"></2j>\');2(k.2w==\'2s\'){K.1K(1x)}7{K.2p(Z)}w=K[K.5-1].2W||2V[K.5-1]}}7 2(I===o){2(K){K.3m()}w.27();w=K=l}2(!k.1U){1F()}2(k.1w){w.1h()}}3 1F(){2(w){w.N.2f();w.N.2U(26());w.N.27()}}3 26(){2(k.1c!==\'\'){$.2o({24:\'2T\',2K:l,2B:k.1c,25:k.28+\'=\'+2S(d.E()),22:3(a){15=1i(a,1)}})}7{2(!1u){$.2o({2K:l,2B:k.1j,22:3(a){1u=1i(a,1)}})}15=1u.W(/<!-- 3x -->/g,d.E())}4 15}3 1Q(e){A=e.A;I=e.I;u=(!(e.I&&e.u))?e.u:l;$.R(L,{u:u,A:A,I:I});2(e.24===\'23\'){2(u===o){z=$("a[2J="+3y.2Q(e.1l)+"]",Z).1s(\'z\');2(z.5!==0){u=l;z.2P(\'1t\');4 l}}2(e.1l===13||e.1l===10){2(u===o){u=l;V(k.1V);4 k.1V.1y}7 2(A===o){A=l;V(k.1X);4 k.1X.1y}7{V(k.1z);4 k.1z.1y}}2(e.1l===9){2(D!==-1){11();D=d.E().5-D;1H(D,0);D=-1;4 l}7{V(k.1T);4 k.1T.1y}}}}2C()})};$.2L.2O=3(){4 G.1f(3(){$$=$(G).1I().2N(\'2q\');$$.1s(\'v\').1s(\'v.Y\').1s(\'v\').Q($$)})};$.Y=3(a){C b={1r:l};$.R(b,a);2(b.1r){4 $(b.1r).1f(3(){$(G).1h();$(G).1Z(\'1C\',[b])})}7{$(\'q\').1Z(\'1C\',[b])}}})(3L);',62,234,'||if|function|return|length|selection|else|string|||||||||||||false|caretPosition||true|block|textarea||||ctrlKey|div|previewWindow|||li|shiftKey|id|var|caretOffset|val|prepare|this|openWith|altKey|clicked|iFrame|hash|closeWith|document|class|lines|replaceWith|extend||root|ul|markup|replace|start|markItUp|header||get|key||abort|html|levels|nameSpace|scrollPosition|placeHolder|browser|bind|previewParserPath|range|substring|each|build|focus|localize|previewTemplatePath|resizeHandle|keyCode|title|mouseMove|mouseUp|rangeCopy|fixIeBug|target|parent|mouseup|template|line|previewInWindow|footer|keepDefault|onEnter|afterInsert|beforeInsert|insertion|preview|createRange|refreshPreview|character|set|unbind|fixOperaBug|insertAfter|appendTo|dropMenus|miuScript|value|wrap|keyPressed|split|attr|onTab|previewAutoRefresh|onCtrlEnter|name|onShiftEnter|hover|trigger||focused|success|keydown|type|data|renderPreview|close|previewParserVar|moveStart|height|scrollTop|setSelectionRange|clientY|createTextRange|open|null|text|msie|iframe|selectionStart|insert|opera|append|ajax|insertBefore|markItUpEditor|addClass|after|mousemove|css|undefined|previewPosition|magicMarkups|substr|dropMenu|hide|url|init|call|markupSet|click|markItUpButton|for|separator|accesskey|async|fn|display|removeClass|markItUpRemove|triggerHandler|fromCharCode|keyup|encodeURIComponent|POST|write|frame|contentWindow|markItUpPreviewFrame|px|closed|max|Math|inRange|while|js|moveToElementText|duplicate|pack|select|moveEnd|markitup|collapse|jquery|mousedown|selectionEnd|match|window|afterMultiInsert|markItUpResizeHandle|src|safari|templates|remove|join|trim|markItUpFooter|beforeMultiInsert|markItUpHeader|isFunction|prompt|markItUpContainer|script|toString|content|String|toUpperCase|pop|markItUpDropMenu|push|one|show|eval|contextmenu|href|className|markItUpSeparator|Ctrl|jQuery'.split('|'),0,{}))
\ No newline at end of file
