Version 5.1 - All the GraphQL #32
@ -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
|
@ -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
|
@ -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;
|
||||
|
@ -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
70
public/js/base/ajax.js
Normal 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);
|
@ -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
41
public/js/base/event.js
Normal 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);
|
@ -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);
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user