Fix #8, make minfiers output correctly

This commit is contained in:
Timothy Warren 2016-02-08 10:57:44 -05:00
parent dcf5bebb9b
commit 3019e9f62e
10 changed files with 280 additions and 73 deletions

View File

@ -36,11 +36,6 @@ class CSSMin extends BaseMin {
$this->group = $groups[$group];
$this->last_modified = $this->get_last_modified();
$this->requested_time = $this->get_if_modified();
}
public function __destruct()
{
$this->send();
}
@ -51,11 +46,10 @@ class CSSMin extends BaseMin {
*/
protected function send()
{
/*if($this->last_modified >= $this->requested_time)
if($this->last_modified >= $this->get_if_modified() && $this->is_not_debug())
{
header('304 Not Modified');
die();
}*/
throw new FileNotChangedException();
}
$css = ( ! array_key_exists('debug', $_GET))
? $this->compress($this->get_css())
@ -70,7 +64,7 @@ class CSSMin extends BaseMin {
* @param string $buffer
* @return string
*/
public function compress($buffer)
protected function compress($buffer)
{
//Remove CSS comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
@ -142,7 +136,7 @@ class CSSMin extends BaseMin {
// Correct paths that have changed due to concatenation
// based on rules in the config file
// $css = str_replace($this->path_from, $this->path_to, $css);
$css = str_replace($this->path_from, $this->path_to, $css);
return $css;
}
@ -152,20 +146,16 @@ class CSSMin extends BaseMin {
*
* @return void
*/
public function output($css)
protected function output($css)
{
//This GZIPs the CSS for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
$etag = md5($css);
header("Content-Type: text/css; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $this->last_modified)." GMT");
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime(basename(__FILE__)) + 691200))." GMT");
if ($etag === $this->get_if_none_match() && $this->is_not_debug())
{
throw new FileNotChangedException();
}
echo $css;
ob_end_flush();
$this->send_final_output($css, 'text/css', $this->last_modified, $etag);
}
}
@ -177,6 +167,18 @@ class CSSMin extends BaseMin {
$config = require('../app/config/minify_config.php');
$groups = require($config['css_groups_file']);
if ( ! array_key_exists($_GET['g'], $groups))
{
throw new InvalidArgumentException('You must specify a css group that exists');
}
try
{
new CSSMin($config, $groups);
}
catch (FileNotChangedException $e)
{
BaseMin::send304();
}
//End of css.php

View File

@ -44,48 +44,42 @@ class JSMin extends BaseMin {
$this->cache_file = "{$this->js_root}cache/{$group}";
$this->last_modified = $this->get_last_modified();
$this->requested_time = $this->get_if_modified();
$this->cache_modified = (is_file($this->cache_file))
? filemtime($this->cache_file)
: 0;
}
public function __destruct()
{
// Output some JS!
$this->send();
}
protected function send()
{
// If the browser's cached version is up to date,
// don't resend the file
/*if($this->last_modified === $this->requested_time)
{
header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified');
exit();
}*/
//Determine what to do: rebuild cache, send files as is, or send cache.
// If debug is set, just concatenate
if(array_key_exists('debug', $_GET))
// Override caching if debug key is set
if($this->is_debug_call())
{
return $this->output($this->get_files());
}
else if($this->cache_modified < $this->last_modified)
// If the browser's cached version is up to date,
// don't resend the file
if($this->last_modified >= $this->get_if_modified() && $this->is_not_debug())
{
throw new FileNotChangedException();
}
if($this->cache_modified < $this->last_modified)
{
$js = $this->minify($this->get_files());
//Make sure cache file gets created/updated
if (file_put_contents($this->cache_file, $js) === FALSE)
{
die('Cache file was not created. Make sure you have the correct folder permissions.');
echo 'Cache file was not created. Make sure you have the correct folder permissions.';
return;
}
return $this->output($js);
}
// Otherwise, send the cached file
else
{
return $this->output(file_get_contents($this->cache_file));
@ -185,7 +179,7 @@ class JSMin extends BaseMin {
* @param string $js
* @return string
*/
public function minify($js)
protected function minify($js)
{
$options = [
'output_info' => 'errors',
@ -218,19 +212,14 @@ class JSMin extends BaseMin {
*/
protected function output($js)
{
//This GZIPs the js for transmission to the user
//making file size smaller and transfer rate quicker
ob_start('ob_gzhandler');
$etag = md5($js);
// Set important caching headers
header('Content-Type: application/javascript; charset=utf8');
header('Cache-control: public, max-age=691200, must-revalidate');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $this->last_modified).' GMT');
header('Expires: '.gmdate('D, d M Y H:i:s', (filemtime(__FILE__) + 691200)).' GMT');
if (($etag === $this->get_if_none_match()) && ! $this->is_debug_call())
{
throw new FileNotChangedException();
}
echo $js;
ob_end_flush();
$this->send_final_output($js, 'application/javascript', $this->last_modified, $etag);
}
}
@ -249,11 +238,16 @@ if ( ! is_dir($cache_dir))
if ( ! array_key_exists($_GET['g'], $groups))
{
header('Content-Type: application/javascript; charset=utf8');
echo '// You must specify a group that exists';
die();
throw new InvalidArgumentException('You must specify a js group that exists');
}
try
{
new JSMin($config, $groups);
}
catch (FileNotChangedException $e)
{
BaseMin::send304();
}
//end of js.php

View File

@ -18,7 +18,7 @@
};
$.get('/public/templates/anime-ajax-search-results.html', tempHtml => {
$('#search').on('keypress', AnimeClient.throttle(250, function(e) {
AnimeClient.on('#search', 'keypress', AnimeClient.throttle(250, function(e) {
let query = encodeURIComponent($(this).val());
if (query === '') {
return;

View File

@ -34,12 +34,11 @@
}
// okay, lets actually make some changes!
$.ajax({
AnimeClient.ajax(AnimeClient.url('/anime/update'), {
data: data,
dataType: 'json',
type: 'POST',
mimeType: 'application/json',
url: AnimeClient.url('/anime/update'),
success: (res) => {
if (res.status === 'completed') {
$(this).closest('article, tr').hide();

70
public/js/base/ajax.js Normal file
View File

@ -0,0 +1,70 @@
AnimeClient = (function (ac) {
/**
* Url encoding for non-get requests
*
* @param data
* @returns {string}
* @private
*/
function serialize(data) {
let pairs = [];
Object.keys(data).forEach((name) => {
let value = data[name].toString();
name = encodeURIComponent(name);
value = encodeURIComponent(value);
pairs.push(`${name}=${value}`);
});
return pairs.join("&");
};
ac.ajax = function(url, config) {
// Set some sane defaults
config = config || {};
config.data = config.data || {};
config.type = config.type || 'GET';
config.dataType = config.dataType || 'json';
config.success = config.success || ac.noop;
config.error = config.error || ac.noop;
let request = new XMLHttpRequest();
let method = String(config.type).toUpperCase();
request.open(method, url);
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status > 400) {
config.error.call(request.statusText, request.statusText, request.response);
} else {
config.success.call(request.responseText, request.response, request.responseText);
}
}
};
switch (method) {
case "GET":
request.send(null);
break;
default:
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(serialize(config.data));
break;
}
};
ac.get = function(url, data, callback) {
return ac.ajax(url, {
data: data,
success: callback
});
};
return ac;
})(AnimeClient);

View File

@ -1,8 +1,39 @@
const AnimeClient = (function($, w) {
var AnimeClient = (function(w) {
'use strict';
const slice = Array.prototype.slice;
return {
/**
* Placeholder function
*/
noop: () => {},
/**
* DOM selector
*
* @param {string} selector - The dom selector string
* @param {object} context
* @return {array} - arrau of dom elements
*/
$(selector, context) {
if (typeof selector != "string" || selector === undefined) {
return selector;
}
context = (context != null && context.nodeType === 1)
? context
: document;
let elements = [];
if (selector.match(/^#([\w]+$)/)) {
elements.push(document.getElementById(selector.split('#')[1]));
} else {
elements = slice.apply(context.querySelectorAll(selector));
}
return elements;
},
/**
* Scroll to the top of the Page
*
@ -71,4 +102,4 @@ const AnimeClient = (function($, w) {
};
},
};
})(Zepto, window);
})(window);

41
public/js/base/event.js Normal file
View File

@ -0,0 +1,41 @@
AnimeClient = (function (ac) {
'use strict';
function add(sel, event, listener) {
// Recurse!
if (! event.match(/^([\w\-]+)$/)) {
event.split(' ').forEach((evt) => {
add(sel, evt, listener);
});
}
sel.addEventListener(event, listener, false);
}
function delegate(sel, target, event, listener) {
// Attach the listener to the parent
add(sel, event, (e) => {
// Get live version of the target selector
ac.$(target, sel).forEach((element) => {
if(e.target == element) {
listener.call(element, e);
e.stopPropagation();
}
});
});
}
ac.on = function (sel, event, target, listener) {
if (arguments.length === 3) {
listener = target;
ac.$(sel).forEach((el) => {
add(el, event, listener);
});
} else {
ac.$(sel).forEach((el) => {
delegate(el, target, event, listener);
});
}
}
return ac;
})(AnimeClient);

View File

@ -1,13 +1,13 @@
/**
* Event handlers
*/
(($) => {
((ac) => {
'use strict';
// Close event for messages
$('header').on('click', '.message', function() {
$(this).hide();
ac.on('header', 'click', '.message', function () {
this.setAttribute('hidden', 'hidden');
});
})(Zepto);
})(AnimeClient);

View File

@ -25,13 +25,12 @@
// Update the total count
data[type + "s_read"] = ++completed;
$.ajax({
AnimeClient.ajax(AnimeClient.url('/manga/update'), {
data: data,
dataType: 'json',
type: 'POST',
mimeType: 'application/json',
url: AnimeClient.url('/manga/update'),
success: (res, status) => {
success: (res) => {
parent_sel.find(`.${type}s_read`).text(completed);
AnimeClient.showMessage('success', `Sucessfully updated ${manga_name}`);
AnimeClient.scrollToTop();

View File

@ -30,18 +30,89 @@ while($i < $pia_len)
$i = $j + 1;
};
class FileNotChangedException extends \Exception {}
class BaseMin {
public function get_if_modified()
/**
* Get value of the if-modified-since header
*
* @return int - timestamp to compare for cache control
*/
protected function get_if_modified()
{
return (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: time();
}
public function get_if_none_match()
/**
* Get value of etag to compare to hash of output
*
* @return string - the etag to compare
*/
protected function get_if_none_match()
{
return (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER))
? $_SERVER['HTTP_IF_NONE_MATCH']
: '';
}
/**
* Determine whether or not to send debug version
*
* @return boolean
*/
protected function is_not_debug()
{
return ! $this->is_debug_call();
}
/**
* Determine whether or not to send debug version
*
* @return boolean
*/
protected function is_debug_call()
{
return array_key_exists('debug', $_GET);
}
/**
* Send actual output to browser
*
* @param string $content - the body of the response
* @param string $mime_type - the content type
* @param int $last_modified - the last modified date
* @return void
*/
protected function send_final_output($content, $mime_type, $last_modified, $etag)
{
//This GZIPs the CSS for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
$expires = $last_modified + 691200;
$last_modified_date = gmdate('D, d M Y H:i:s', $last_modified);
$expires_date = gmdate('D, d M Y H:i:s', $expires);
header("Content-Type: {$mime_type}; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Etag: {$etag}");
header("Last-Modified: {$last_modified_date} GMT");
header("Expires: {$expires_date} GMT");
echo $content;
ob_end_flush();
}
/**
* Send a 304 Not Modified header
*
* @return void
*/
public static function send304()
{
header("status: 304 Not Modified", true, 304);
}
}