Initial commit
This commit is contained in:
commit
65e0da7e11
1397 changed files with 596542 additions and 0 deletions
46
site/OFF_plugins/imagekit/changelog.md
Normal file
46
site/OFF_plugins/imagekit/changelog.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# ImageKit Changelog
|
||||
|
||||
- Recent changes (not part of an official release yet)
|
||||
- Add redirect detection to Widget API, so the indexing feature works with templates, that only send a redirect to the browser instead of showing content.
|
||||
- Re-Create placeholder files (`index.html` and `.gitkeep`), often used in Git repositories after thumbs cache has been cleaned.
|
||||
- Discovery feature does now validate the `href` attribute of links, when indexing the whole site.
|
||||
|
||||
- `1.1.3` (2017/01/07)
|
||||
- Add redirect detection to Widget API, so the indexing feature works with templates, that only send a redirect to the browser instead of showing content.
|
||||
|
||||
- `1.1.2` (2016/12/11)
|
||||
- Remove Whoops handler to restore Widget compatibility with Kirby 2.4.1.
|
||||
|
||||
- `1.1.1` (2016/11/27)
|
||||
- Fix path to panel JS
|
||||
|
||||
- `1.1.0` (2016/11/24)
|
||||
- Fix error with overridden optimizer options.
|
||||
- Make `imagekit.lazy` overridable for single thumbnails
|
||||
|
||||
- `1.1.0-beta2` (2016/10/29)
|
||||
- Widget API now displays more helpful errors in most situations (only browsers, that support the `foreignContent` feature of SVG. Currently, most browsers will still only show the old error (but looks great in Firefox).
|
||||
- Widget Errors are now recoverable. You don’t have to reload the panel any more, if a server-side error occurs.
|
||||
- Better integration with *Whoops* for error-handling for the panel widget.
|
||||
- Confirm dialog for clearing thumbs folder is not displaying as overlay, rather than as system dialod. Supports ESC key for cancel and ENTER for confirming the action.
|
||||
|
||||
- `1.1.0-beta1` (2016/09/21)
|
||||
- **Optimization:** ImageKit is now capable of applying several optimizations to your images, using popular command-line tools.
|
||||
- **Better Error Handling:** The `ComplaingThumb` class now handles out-of-memory errors more reliable.
|
||||
- **Compatibilitly:** Widget should now work with Kirby 2.4-beta1
|
||||
|
||||
- `1.0.0` (2016/08/19)
|
||||
- **Release!** Initial version of the plugin is now final. Licenses are availabel at my [store](http://sites.fastspring.com/fabianmichael/product/imagekit).
|
||||
- **Bugfix:** Fix handling of images that are located at the top-level of the `content` directory.
|
||||
|
||||
- `1.0.0-beta2` (2016/07/25)
|
||||
- **Changed Job-File Suffix:** Pending thumbs aka placeholder files aka job files now have a suffix of `-imagekitjob.php` instead of `.imagekitjob.php`. This fixes errors with Apache’s `MultiViews` feature (read [explanation](http://stackoverflow.com/questions/25423141/what-exactly-does-the-the-multiviews-options-in-htaccess)). You should clear your thumbs folder after upgrading.
|
||||
- **Error Handling:** ImageKit now tries it’s best to show you if there was an error in the thumbnail creating process. The widget is now able to display errors and if thumbnail creation failed, an error image is returned instead of nothing.
|
||||
- **Discovery Feature:** The widget now scans your whole site for thumbnails, so you don’t have to open every page manually.
|
||||
- **Widget Code:** The widget logic has been improved on both the server and the client side for better extensibility.
|
||||
- **Widget UI:** Added text underneath the progress bar to give the user a better understanding of what the widget is currently doing. Added animation while the progress bar is visible. If an operation is cancelled, Widget UI is now blocked until another operation can be started.
|
||||
- **Permissions:** The widget now shows an error message when the user has been logged out. The widget is now accessible for all logged-in panel users by default.
|
||||
- **Refactoring:** The whole plugin has been refactored here and there …
|
||||
|
||||
- `1.0.0-beta1` (2016/06/04)
|
||||
- First public release
|
||||
43
site/OFF_plugins/imagekit/gulpfile.js
Normal file
43
site/OFF_plugins/imagekit/gulpfile.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*jshint expr:true, -W083, esversion: 6, unused: false */
|
||||
const gulp = require("gulp");
|
||||
const rename = require("gulp-rename");
|
||||
const csso = require("gulp-csso");
|
||||
const uglify = require("gulp-uglify");
|
||||
const sass = require("gulp-sass");
|
||||
const toc = require("gulp-doctoc");
|
||||
const postcss = require("gulp-postcss");
|
||||
const assets = require("postcss-assets");
|
||||
|
||||
gulp.task("styles", function () {
|
||||
return gulp.src([ "widgets/imagekit/assets/scss/*.scss" ])
|
||||
.pipe(sass())
|
||||
.pipe(postcss([
|
||||
assets({ loadPaths: ['widgets/imagekit/assets/images/'] }),
|
||||
]))
|
||||
.pipe(csso())
|
||||
.pipe(rename({ suffix: ".min" }))
|
||||
.pipe(gulp.dest("widgets/imagekit/assets/css"));
|
||||
});
|
||||
|
||||
gulp.task("scripts", function () {
|
||||
return gulp.src([ "widgets/imagekit/assets/js/src/*.js" ])
|
||||
.pipe(uglify())
|
||||
.pipe(rename({ suffix: ".min" }))
|
||||
.pipe(gulp.dest("widgets/imagekit/assets/js/dist"));
|
||||
});
|
||||
|
||||
gulp.task( 'readme', function() {
|
||||
return gulp.src(['readme.md'])
|
||||
.pipe(toc({
|
||||
mode: "github.com",
|
||||
title: "**Table of Contents**",
|
||||
}))
|
||||
.pipe(gulp.dest('.'));
|
||||
});
|
||||
|
||||
gulp.task("default", ['styles', 'scripts', 'readme']);
|
||||
|
||||
gulp.task("watch", ['default'], () => {
|
||||
gulp.watch('widgets/imagekit/assets/scss/**/*.scss', [ 'styles' ]);
|
||||
gulp.watch('widgets/imagekit/assets/js/src/**/*.js', [ 'scripts' ]);
|
||||
});
|
||||
5
site/OFF_plugins/imagekit/helpers.php
Normal file
5
site/OFF_plugins/imagekit/helpers.php
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
function imagekit() {
|
||||
return \Kirby\Plugins\ImageKit\ImageKit::instance();
|
||||
}
|
||||
28
site/OFF_plugins/imagekit/imagekit.php
Normal file
28
site/OFF_plugins/imagekit/imagekit.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
|
||||
load([
|
||||
'kirby\\plugins\\imagekit\\imagekit' => 'lib' . DS . 'imagekit.php',
|
||||
'kirby\\plugins\\imagekit\\component\\thumb' => 'lib' . DS . 'component' . DS . 'thumb.php',
|
||||
'kirby\\plugins\\imagekit\\lazythumb' => 'lib' . DS . 'lazythumb.php',
|
||||
'kirby\\plugins\\imagekit\\complainingthumb' => 'lib' . DS . 'complainingthumb.php',
|
||||
'kirby\\plugins\\imagekit\\proxyasset' => 'lib' . DS . 'proxyasset.php',
|
||||
'kirby\\plugins\\imagekit\\optimizer' => 'lib' . DS . 'optimizer.php',
|
||||
|
||||
// Only the base optimizer class is autoloaded, all other
|
||||
// optimizers are loaded by scanning the directory.
|
||||
'kirby\\plugins\\imagekit\\optimizer\\base' => 'lib' . DS . 'optimizer' . DS . 'base.php',
|
||||
], __DIR__);
|
||||
|
||||
require_once __DIR__ . DS . 'helpers.php';
|
||||
|
||||
// Initialize the plugin
|
||||
|
||||
$kirby = kirby();
|
||||
|
||||
$kirby->set('component', 'thumb', '\\Kirby\\Plugins\\ImageKit\\Component\\Thumb');
|
||||
|
||||
if($kirby->option('imagekit.widget')) {
|
||||
require_once __DIR__ . DS . 'widgets' . DS . 'imagekit' . DS . 'bootstrap.php';
|
||||
}
|
||||
225
site/OFF_plugins/imagekit/lib/complainingthumb.php
Normal file
225
site/OFF_plugins/imagekit/lib/complainingthumb.php
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
|
||||
use Response;
|
||||
use Thumb;
|
||||
use Str;
|
||||
|
||||
|
||||
/**
|
||||
* An extended version of Kirby’s thumb class which is able
|
||||
* to throw an error, if thumbs are resized with the
|
||||
* GD Library and PHP’s memory limit is exceeded or if
|
||||
* thumbnail creation failed for another reason.
|
||||
*/
|
||||
class ComplainingThumb extends Thumb {
|
||||
|
||||
private static $_errorData = [];
|
||||
private static $_errorFormat = 'image';
|
||||
|
||||
private static $_errorListening = false;
|
||||
private static $_creating = false;
|
||||
private static $_errorReporting;
|
||||
private static $_displayErrors;
|
||||
private static $_targetDimensions;
|
||||
private static $_sendError = false;
|
||||
|
||||
private static $_reservedMemory;
|
||||
|
||||
public static function setErrorFormat($format = null) {
|
||||
if (!is_null($format)) static::$_errorFormat = $format;
|
||||
static::$_errorFormat;
|
||||
}
|
||||
|
||||
public static function enableSendError() {
|
||||
static::$_sendError = true;
|
||||
}
|
||||
|
||||
public function create() {
|
||||
|
||||
if(!static::$_sendError) {
|
||||
// Don’t setup a error handlers, if complaining is
|
||||
// not enabled and just return the result of create().
|
||||
return parent::create();
|
||||
}
|
||||
|
||||
$this->prepareErrorHandler();
|
||||
$result = parent::create();
|
||||
$this->restoreErrorHandler();
|
||||
|
||||
if(!file_exists($this->destination->root)) {
|
||||
|
||||
$message = str::template('Thumbnail creation for "{file}" failed. Please ensure, that the thumbs directory is writable and your driver configuration is correct.', [
|
||||
'file' => static::$_errorData['file'],
|
||||
]);
|
||||
|
||||
static::sendErrorResponse($message);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function prepareErrorHandler() {
|
||||
|
||||
// Reserve one additional megabyte of memory to make
|
||||
// catching of out-of-memory errors more reliable.
|
||||
// The variable’s content is deleted in the shutdown
|
||||
// function to have more available memory to prepare an
|
||||
// error.
|
||||
static::$_reservedMemory = str_repeat('#', 1024 * 1024);
|
||||
|
||||
$dimensions = $this->source->dimensions();
|
||||
$filename = str_replace(kirby()->roots()->index() . DS, '', $this->source->root());
|
||||
|
||||
$asset = new ProxyAsset($this->destination->root);
|
||||
$asset->options($this->options);
|
||||
$asset->original($this->source);
|
||||
$targetDimensions = $asset->dimensions();
|
||||
|
||||
static::$_errorData = [
|
||||
'file' => $filename,
|
||||
'width' => $dimensions->width,
|
||||
'height' => $dimensions->height,
|
||||
'size' => $this->source->size(),
|
||||
'targetWidth' => $targetDimensions->width,
|
||||
'targetHeight' => $targetDimensions->height,
|
||||
];
|
||||
|
||||
static::$_displayErrors = ini_get('display_errors');
|
||||
static::$_errorReporting = error_reporting();
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
if (!static::$_errorListening) {
|
||||
// As of PHP 7.0 there is not way of de-registering a
|
||||
// shutdown callback. So we only register it once at
|
||||
// the first time, this method is called.
|
||||
static::$_errorListening = true;
|
||||
register_shutdown_function([__CLASS__, 'shutdownCallback']);
|
||||
}
|
||||
|
||||
static::$_creating = true;
|
||||
}
|
||||
|
||||
private function restoreErrorHandler() {
|
||||
|
||||
// Delete the reserved memory, because if thumbnail
|
||||
// creation succeeded, it is not needed any more.
|
||||
static::$_reservedMemory = null;
|
||||
|
||||
ini_set('display_errors', static::$_displayErrors);
|
||||
error_reporting(static::$_errorReporting);
|
||||
|
||||
static::$_creating = false;
|
||||
}
|
||||
|
||||
public static function shutdownCallback() {
|
||||
|
||||
// Delete the reserved memory to have more memory for
|
||||
// preparing an error message.
|
||||
static::$_reservedMemory = null;
|
||||
|
||||
$error = error_get_last();
|
||||
if(!$error) return;
|
||||
|
||||
if($error['type'] == E_ERROR || $error['type'] === E_WARNING) {
|
||||
|
||||
if(str::contains($error['message'], 'Allowed Memory Size')) {
|
||||
|
||||
$message = str::template('Thumbnail creation for "{file}" failed, because source image is probably too large ({width} × {height} pixels / {size}) To fix this issue, increase the memory limit of PHP or upload a smaller version of this image.', [
|
||||
'file' => static::$_errorData['file'],
|
||||
'width' => number_format(static::$_errorData['width']),
|
||||
'height' => number_format(static::$_errorData['height']),
|
||||
'size' => number_format(static::$_errorData['size'] / (1024 * 1024), 2) . " MB",
|
||||
]);
|
||||
|
||||
static::sendErrorResponse($message);
|
||||
|
||||
} else {
|
||||
static::sendErrorResponse($error['message']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function sendErrorResponse($message = '') {
|
||||
|
||||
// Make sure, that the error message is non-cachable
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
if(static::$_errorFormat === 'image') {
|
||||
|
||||
// The returned error image is an SVG file, because it
|
||||
// can be created just by joined a couple of XML tags
|
||||
// together and is supported by every modern browser,
|
||||
// starting with IE 9 (which is of course not
|
||||
// modern any more …).
|
||||
header('Content-Type: image/svg+xml');
|
||||
|
||||
// Although this is technically not correct, we have
|
||||
// to send status code 200, otherwise the image does
|
||||
// not show up in Firefox and Safari, although it
|
||||
// works with code 500 in Chrome and Edge. Also tested
|
||||
// in IE 10, IE 11
|
||||
http_response_code(200);
|
||||
|
||||
$width = static::$_errorData['targetWidth'];
|
||||
$height = static::$_errorData['targetHeight'];
|
||||
|
||||
// Return an SVG File with the thumb’s dimensions
|
||||
// Icon Credit: fontawesome.io
|
||||
?><svg version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="<?= $width ?>" height="<?= $height ?>"
|
||||
viewBox="0 0 <?= $width ?> <?= $height ?>"
|
||||
preserveAspectRatio="none">
|
||||
|
||||
<symbol id="icon">
|
||||
<svg viewBox="0 0 48 44.52" width="48" height="44.52" preserveAspectRatio="xMinYMax meet">
|
||||
<path d="M27.425,36.789V31.705a0.854,0.854,0,0,0-.254-0.629,0.823,0.823,0,0,0-.6-0.254H21.431a0.823,0.823,0,0,0-.6.254,0.854,0.854,0,0,0-.254.629v5.084a0.854,0.854,0,0,0,.254.629,0.823,0.823,0,0,0,.6.254h5.137a0.823,0.823,0,0,0,.6-0.254A0.854,0.854,0,0,0,27.425,36.789ZM27.371,26.782L27.853,14.5a0.589,0.589,0,0,0-.268-0.508,1.034,1.034,0,0,0-.642-0.294H21.057a1.034,1.034,0,0,0-.642.294,0.64,0.64,0,0,0-.268.562L20.6,26.782a0.514,0.514,0,0,0,.268.441,1.152,1.152,0,0,0,.642.174h4.95a1.088,1.088,0,0,0,.629-0.174A0.6,0.6,0,0,0,27.371,26.782ZM27,1.793L47.545,39.464a3.192,3.192,0,0,1-.054,3.371,3.422,3.422,0,0,1-2.943,1.686H3.452A3.422,3.422,0,0,1,.509,42.835a3.192,3.192,0,0,1-.054-3.371L21,1.793A3.417,3.417,0,0,1,22.261.482a3.381,3.381,0,0,1,3.478,0A3.417,3.417,0,0,1,27,1.793Z" fill="#ffffff"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<rect width="100%" height="100%" fill="#F4999D" />
|
||||
|
||||
<switch>
|
||||
<foreignObject width="100%" height="100%" requiredExtensions="http://www.w3.org/1999/xhtml">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="background:#F4999D;text-align:center;color:#fff;box-sizing:border-box;margin:0;padding:0;font-size:12px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif">
|
||||
<p style="margin:0;word-wrap:break-word;position:absolute;top:50%;transform:translateY(-50%);width: 100%;box-sizing:border-box;padding: 0 1em;">
|
||||
<svg viewBox="0 0 48 44.52" width="24" height="22.125" xmlns="http://www.w3.org/2000/svg" style="display: block; margin: 0 auto 12px;"><path d="M27.425,36.789V31.705a0.854,0.854,0,0,0-.254-0.629,0.823,0.823,0,0,0-.6-0.254H21.431a0.823,0.823,0,0,0-.6.254,0.854,0.854,0,0,0-.254.629v5.084a0.854,0.854,0,0,0,.254.629,0.823,0.823,0,0,0,.6.254h5.137a0.823,0.823,0,0,0,.6-0.254A0.854,0.854,0,0,0,27.425,36.789ZM27.371,26.782L27.853,14.5a0.589,0.589,0,0,0-.268-0.508,1.034,1.034,0,0,0-.642-0.294H21.057a1.034,1.034,0,0,0-.642.294,0.64,0.64,0,0,0-.268.562L20.6,26.782a0.514,0.514,0,0,0,.268.441,1.152,1.152,0,0,0,.642.174h4.95a1.088,1.088,0,0,0,.629-0.174A0.6,0.6,0,0,0,27.371,26.782ZM27,1.793L47.545,39.464a3.192,3.192,0,0,1-.054,3.371,3.422,3.422,0,0,1-2.943,1.686H3.452A3.422,3.422,0,0,1,.509,42.835a3.192,3.192,0,0,1-.054-3.371L21,1.793A3.417,3.417,0,0,1,22.261.482a3.381,3.381,0,0,1,3.478,0A3.417,3.417,0,0,1,27,1.793Z" fill="#ffffff"/></svg>
|
||||
<?= $message ?>
|
||||
</p>
|
||||
</body>
|
||||
</foreignObject>
|
||||
<!-- Fallback -->
|
||||
<use xlink:href="#icon" transform="translate(<?= number_format($width / 2 - 48 / 2,1,'.','') ?>, <?= number_format($height / 2 - 44.52 / 2,1,'.','') ?>)" />
|
||||
</switch>
|
||||
</svg><?php
|
||||
|
||||
} else {
|
||||
|
||||
// If error format has been set to JSON, return JSON ;-)
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
http_response_code(500);
|
||||
|
||||
echo json_encode([
|
||||
'status' => '',
|
||||
'code' => 500,
|
||||
'message' => $message,
|
||||
'data' => [
|
||||
'file' => static::$_errorData,
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
128
site/OFF_plugins/imagekit/lib/component/thumb.php
Normal file
128
site/OFF_plugins/imagekit/lib/component/thumb.php
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Component;
|
||||
|
||||
use Asset;
|
||||
use F;
|
||||
use Header;
|
||||
use Kirby\Component\Thumb as ThumbComponent;
|
||||
use Kirby\Plugins\ImageKit\LazyThumb;
|
||||
use Kirby\Plugins\ImageKit\ComplainingThumb;
|
||||
use Kirby\Plugins\ImageKit\ProxyAsset;
|
||||
use Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
|
||||
/**
|
||||
* Replacement for Kirby’s built-in `thumb` component with
|
||||
* asynchronous thumb creation and image optimization
|
||||
* capabilities.
|
||||
*/
|
||||
class Thumb extends ThumbComponent {
|
||||
|
||||
public function defaults() {
|
||||
|
||||
return array_merge(parent::defaults(), [
|
||||
'imagekit.lazy' => true,
|
||||
'imagekit.complain' => true,
|
||||
'imagekit.widget' => true,
|
||||
'imagekit.widget.step' => 5,
|
||||
'imagekit.widget.discover' => true,
|
||||
|
||||
'imagekit.optimize' => false,
|
||||
'imagekit.engine' => null,
|
||||
|
||||
'imagekit.license' => '',
|
||||
|
||||
// Used for the development of the plugin, currently
|
||||
// not officialy documented.
|
||||
'imagekit.debug' => false,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function configure() {
|
||||
parent::configure();
|
||||
|
||||
// Register route to catch non-existing files within the
|
||||
// thumbs directory.
|
||||
$base = ltrim(substr($this->kirby->roots->thumbs(), strlen($this->kirby->roots->index())), DS);
|
||||
|
||||
// Setup optimizer if enabled.
|
||||
if($this->kirby->option('imagekit.optimize')) {
|
||||
optimizer::register();
|
||||
}
|
||||
|
||||
$this->kirby->set('route', [
|
||||
'pattern' => "{$base}/(:all)", // $base = 'thumbs' by default
|
||||
'action' => function ($path) {
|
||||
|
||||
if($this->kirby->option('imagekit.complain')) {
|
||||
complainingthumb::enableSendError();
|
||||
complainingthumb::setErrorFormat('image');
|
||||
}
|
||||
|
||||
// Try to load a jobfile for given thumb url and
|
||||
// execute if exists
|
||||
$thumb = lazythumb::process($path);
|
||||
|
||||
if($thumb) {
|
||||
// Serve the image, if everything went fine :-D
|
||||
|
||||
$root = $thumb->result->root();
|
||||
|
||||
// Make sure, we’re sending a 200 status, telling
|
||||
// the browser that everything’s okay.
|
||||
header::status(200);
|
||||
|
||||
// Don’t tell anyone that this image was just
|
||||
// created by PHP ;-)
|
||||
header_remove('X-Powered-By');
|
||||
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', f::modified($root)) . ' GMT');
|
||||
header('Content-Type: ' . f::mime($root));
|
||||
header('Content-Length: ' . f::size($root));
|
||||
|
||||
// Send file and stop script execution
|
||||
readfile($root);
|
||||
|
||||
exit;
|
||||
|
||||
} else {
|
||||
// Show a 404 error, if the job could not be
|
||||
// found or executed
|
||||
return site()->errorPage();
|
||||
}
|
||||
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
public function create($file, $params) {
|
||||
|
||||
if (!$this->kirby->option('imagekit.lazy') || (isset($params['imagekit.lazy']) && !$params['imagekit.lazy'])) {
|
||||
return parent::create($file, $params);
|
||||
}
|
||||
|
||||
if(!$file->isWebsafe()) return $file;
|
||||
|
||||
// Instead of a Thumb, a Job will be created for later
|
||||
// execution
|
||||
$thumb = new LazyThumb($file, $params);
|
||||
|
||||
if($thumb->result instanceof ProxyAsset) {
|
||||
// If the thumb is yet to be generated, use the
|
||||
// virtual asset, created by the LazyThumb class
|
||||
$asset = $thumb->result;
|
||||
} else {
|
||||
// Otherwise, create a new asset from the returned
|
||||
// media object.
|
||||
$asset = new Asset($thumb->result);
|
||||
}
|
||||
|
||||
// store a reference to the original file
|
||||
$asset->original($file);
|
||||
|
||||
return $asset;
|
||||
}
|
||||
|
||||
}
|
||||
73
site/OFF_plugins/imagekit/lib/imagekit.php
Normal file
73
site/OFF_plugins/imagekit/lib/imagekit.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
|
||||
use F;
|
||||
use Obj;
|
||||
use Str;
|
||||
|
||||
|
||||
/**
|
||||
* Utility class for retrieving information about the plugin
|
||||
* version and it’s license.
|
||||
*/
|
||||
class ImageKit {
|
||||
|
||||
protected $version;
|
||||
|
||||
protected function __construct() {
|
||||
// Just declared to prevent direct instantiation of this
|
||||
// class (singleton pattern).
|
||||
}
|
||||
|
||||
public static function instance() {
|
||||
static $instance;
|
||||
return ($instance ?: $instance = new static());
|
||||
}
|
||||
|
||||
public function version() {
|
||||
if(is_null($this->version)) {
|
||||
$package = json_decode(f::read(dirname(__DIR__) . DS . 'package.json'));
|
||||
$this->version = $package->version;
|
||||
}
|
||||
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function root() {
|
||||
return dirname(__DIR__);
|
||||
}
|
||||
|
||||
public function license() {
|
||||
$key = kirby()->option('imagekit.license');
|
||||
$type = 'trial';
|
||||
|
||||
/**
|
||||
* Hey there,
|
||||
*
|
||||
* if you have digged deep into Kirby’s source code,
|
||||
* than you’ve probably stumbled across a similiar
|
||||
* message, asking you to be honest when using the
|
||||
* software. I ask you the same, if your intention is to
|
||||
* use ImageKit. Writing this plugin took a lot of time
|
||||
* and it hopefully saves you a lot of headaches. If you
|
||||
* would use a cloud-provider instead of rolling your own
|
||||
* thumb engine, then your would also have to pay them.
|
||||
*
|
||||
* Anyway, have a nice day!
|
||||
*
|
||||
* Fabian
|
||||
*/
|
||||
if (str::startsWith($key, 'IMGKT1') && str::length($key) === 39) {
|
||||
$type = 'ImageKit 1';
|
||||
} else {
|
||||
$key = null;
|
||||
}
|
||||
|
||||
return new Obj(array(
|
||||
'key' => $key,
|
||||
'type' => $type,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
293
site/OFF_plugins/imagekit/lib/lazythumb.php
Normal file
293
site/OFF_plugins/imagekit/lib/lazythumb.php
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
|
||||
use Asset;
|
||||
use Dir;
|
||||
use Error;
|
||||
use Exception;
|
||||
use F;
|
||||
use File;
|
||||
use Media;
|
||||
use Str;
|
||||
use Thumb;
|
||||
// Honestly, who in the PHP team is responsible for naming things?!?
|
||||
use RecursiveIteratorIterator as Walker;
|
||||
use RecursiveDirectoryIterator as DirWalker;
|
||||
|
||||
|
||||
/**
|
||||
* Extended version of Kirby’s thumb class for
|
||||
* creating “lazy” thumbnails.
|
||||
*/
|
||||
class LazyThumb extends Thumb {
|
||||
|
||||
const JOBFILE_SUFFIX = '-imagekitjob.php';
|
||||
|
||||
public function __construct($source, $params = []) {
|
||||
|
||||
$this->source = $this->result = is_a($source, 'Media') ? $source : new Media($source);
|
||||
$this->options = array_merge(static::$defaults, $this->params($params));
|
||||
$this->destination = $this->destination();
|
||||
|
||||
// don't create the thumbnail if it's not necessary
|
||||
if($this->isObsolete()) return;
|
||||
|
||||
// don't create the thumbnail if it exists
|
||||
if(!$this->isThere()) {
|
||||
|
||||
// try to create the thumb folder if it is not there yet
|
||||
dir::make(dirname($this->destination->root));
|
||||
|
||||
// check for a valid image
|
||||
if(!$this->source->exists() || $this->source->type() != 'image') {
|
||||
throw new Error('The given image is invalid', static::ERROR_INVALID_IMAGE);
|
||||
}
|
||||
|
||||
// check for a valid driver
|
||||
if(!array_key_exists($this->options['driver'], static::$drivers)) {
|
||||
throw new Error('Invalid thumbnail driver', static::ERROR_INVALID_DRIVER);
|
||||
}
|
||||
|
||||
// create a jobfile for the thumbnail
|
||||
$this->create();
|
||||
|
||||
// create a virtual asset, on which methods like width()
|
||||
// and height() can be called on.
|
||||
$this->result = new ProxyAsset(new Media($this->destination->root, $this->destination->url));
|
||||
$this->result->original($this->source);
|
||||
$this->result->options($this->options);
|
||||
|
||||
} else {
|
||||
|
||||
// create the result object
|
||||
$this->result = new Media($this->destination->root, $this->destination->url);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function create() {
|
||||
|
||||
$root = static::jobfile($this->destination->root);
|
||||
|
||||
if(f::exists($root)) return;
|
||||
|
||||
if(is_a($this->source, 'File')) {
|
||||
// Source file belongs to a page
|
||||
$pageid = $this->source->page()->id();
|
||||
$dir = null;
|
||||
} else {
|
||||
// Source file is an outlaw, hiding somewhere else in
|
||||
// the file tree
|
||||
$pageid = null;
|
||||
$dir = substr($this->source->root(), str::length(kirby()->roots->index));
|
||||
$dir = pathinfo(ltrim($dir , DS), PATHINFO_DIRNAME);
|
||||
}
|
||||
|
||||
$options = [
|
||||
'imagekit.version' => imagekit()->version(),
|
||||
'source' => [
|
||||
'filename' => $this->source->filename(),
|
||||
'dir' => $dir,
|
||||
'page' => $pageid,
|
||||
],
|
||||
'options' => $this->options,
|
||||
];
|
||||
|
||||
// Remove `destination` option before export, because
|
||||
// closures cannot be exported and this option is a
|
||||
// closure by default.
|
||||
unset($options['options']['destination']);
|
||||
|
||||
$export = "<?php\nreturn " . var_export($options, true) . ';';
|
||||
|
||||
f::write($root, $export);
|
||||
}
|
||||
|
||||
|
||||
// ===== API Methods ========================================================
|
||||
|
||||
public static function process($path) {
|
||||
|
||||
$thumbs = kirby()->roots->thumbs();
|
||||
if(!str::startsWith($path, $thumbs)) {
|
||||
$path = $thumbs . DS . $path;
|
||||
}
|
||||
|
||||
$jobfile = static::jobfile($path);
|
||||
|
||||
if(!$thumbinfo = @include($jobfile)) {
|
||||
// Abort, if there is no matching jobfile for the
|
||||
// requested thumb.
|
||||
return false;
|
||||
}
|
||||
|
||||
// This option is a closure by default, which cannot be
|
||||
// restored. Currently, we can only restore it by
|
||||
// overriding it the the default option of the thumb
|
||||
// class. So this does not work, when a custom
|
||||
// 'destination' option was set for this particular
|
||||
// thumbnail or the option has been changed between
|
||||
// jobfile creation and execution of this method.
|
||||
$thumbinfo['options']['destination'] = thumb::$defaults['destination'];
|
||||
|
||||
if (!is_null($thumbinfo['source']['page'])) {
|
||||
// Try to relocate the image and get it’s association
|
||||
// with the original parent page or site
|
||||
if ($thumbinfo['source']['page'] === '') {
|
||||
// Image was uploaded to the "content" directory
|
||||
$image = site()->image($thumbinfo['source']['filename']);
|
||||
} else {
|
||||
// Image belongs to a specific page
|
||||
$image = page($thumbinfo['source']['page'])->image($thumbinfo['source']['filename']);
|
||||
}
|
||||
|
||||
if(!$image) {
|
||||
// If source image does not exist any more, remove
|
||||
// the jobfile.
|
||||
f::remove($jobfile);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If the image does not belong to a specific page,
|
||||
// just use an `Asset` as source.
|
||||
$image = new Asset($thumbinfo['source']['dir'] . DS . $thumbinfo['source']['filename']);
|
||||
|
||||
if(!$image->exists()) {
|
||||
f::remove($jobfile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// override url and root of the thumbs directory to the
|
||||
// current values. This prevents ImageKit from failing
|
||||
// after your Kirby installation has been moved.
|
||||
$thumbinfo['options']['ul'] = kirby()->urls->thumbs();
|
||||
$thumbinfo['options']['root'] = kirby()->roots->thumbs();
|
||||
|
||||
// Finally execute job file by creating a thumb
|
||||
$thumb = new ComplainingThumb($image, $thumbinfo['options']);
|
||||
|
||||
if(!kirby()->option('imagekit.debug') && f::exists($thumb->destination()->root)) {
|
||||
// Delete job file if thumbnail has been generated
|
||||
// successfully and we’re not in debug mode.
|
||||
f::remove($jobfile);
|
||||
}
|
||||
|
||||
return $thumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of a thumbnails jobfile. The jobfile
|
||||
* contains instructions about how to create the actual
|
||||
* thumbnail.
|
||||
*
|
||||
* @return string A thumbnail’s jobfile.
|
||||
*/
|
||||
public static function jobfile($path) {
|
||||
return !str::endsWith($path, self::JOBFILE_SUFFIX) ? $path . self::JOBFILE_SUFFIX : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all pending thumbnails, i.e. thumbnails that
|
||||
* have not been created yet. This works by looking for
|
||||
* jobfiles in the thumbs directory.
|
||||
*
|
||||
* @return array A list of all pending thumbnails
|
||||
*/
|
||||
public static function pending() {
|
||||
|
||||
$pending = [];
|
||||
$iterator = new Walker(new DirWalker(kirby()->roots()->thumbs()), Walker::SELF_FIRST);
|
||||
|
||||
foreach($iterator as $file) {
|
||||
$pathname = $file->getPathname();
|
||||
|
||||
if(str::endsWith($pathname, self::JOBFILE_SUFFIX)) {
|
||||
$thumb = str::substr($pathname, 0, -str::length(self::JOBFILE_SUFFIX));
|
||||
if(!file_exists($thumb)) {
|
||||
$pending[] = $pathname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the thumbs directory, searches for image files
|
||||
* and returns a list of those.
|
||||
*
|
||||
* @return array A list of all websafe image files within
|
||||
* the thumbs directory.
|
||||
*/
|
||||
public static function created() {
|
||||
|
||||
$created = [];
|
||||
$iterator = new Walker(new DirWalker(kirby()->roots()->thumbs()), Walker::SELF_FIRST);
|
||||
|
||||
foreach($iterator as $file) {
|
||||
$pathname = $file->getPathname();
|
||||
if(in_array(pathinfo($pathname, PATHINFO_EXTENSION), ['jpg', 'jpeg', 'png', 'gif'])) {
|
||||
$created[] = $pathname;
|
||||
}
|
||||
}
|
||||
|
||||
return $created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual status of generated and pending thumbs
|
||||
* on your site.
|
||||
*
|
||||
* @return array An associative array containing stats
|
||||
* about your thumbs folder.
|
||||
*/
|
||||
public static function status() {
|
||||
return [
|
||||
'pending' => sizeof(static::pending()),
|
||||
'created' => sizeof(static::created()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the entire thumbs directory.
|
||||
*
|
||||
* @return boolen `true` if cleaning was successful,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
public static function clear() {
|
||||
|
||||
$root = kirby()->roots()->thumbs();
|
||||
|
||||
// Look for placeholder files used by many projects
|
||||
// when working with git. these files are used to add
|
||||
// empty directories to repositories. Files will be
|
||||
// re-created after zhe cache has been flushed. Although
|
||||
// these files are usually empty, it’s more secure to
|
||||
// read their contents before deleting them, just in case …
|
||||
$indexFile = $root . DS . 'index.html';
|
||||
$index = f::exists($indexFile) ? f::read($indexFile) : false;
|
||||
$gitkeepFile = $root . DS . '.gitkeep';
|
||||
$gitkeep = f::exists($gitkeepFile) ? f::read($gitkeepFile) : false;
|
||||
|
||||
$result = dir::clean($root);
|
||||
|
||||
if($result) {
|
||||
// Only re-create if thumbs dir cleanup was successful
|
||||
|
||||
if($index !== false) {
|
||||
// Re-create index.html if it existed before
|
||||
f::write($indexFile, $index);
|
||||
}
|
||||
if($gitkeep !== false) {
|
||||
// Re-create .gitkeep file, if it existed before
|
||||
f::write($gitkeepFile, $gitkeep);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
169
site/OFF_plugins/imagekit/lib/optimizer.php
Normal file
169
site/OFF_plugins/imagekit/lib/optimizer.php
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
use A;
|
||||
use Dir;
|
||||
use F;
|
||||
use Thumb;
|
||||
|
||||
|
||||
class Optimizer {
|
||||
|
||||
protected static $kirby;
|
||||
protected static $optimizers = [];
|
||||
|
||||
// These variables store all loaded optimizers of an
|
||||
// actual instance of the Optimizer object, sorted by
|
||||
// their priority.
|
||||
protected $pre;
|
||||
protected $post;
|
||||
|
||||
/**
|
||||
* Creates an optimmizer for given Thumb
|
||||
*
|
||||
* @param Thumb $thumb
|
||||
* @param array $pre Optimizers to apply prior to
|
||||
* thumbnail creation.
|
||||
* @param array $post Optimizers to apply after
|
||||
* thumbnail creation.
|
||||
*/
|
||||
protected function __construct($thumb, $pre, $post) {
|
||||
static::init();
|
||||
$this->thumb = $thumb;
|
||||
$this->pre = $pre;
|
||||
$this->post = $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class for given thumb.
|
||||
*
|
||||
* @param Thumb $thumb
|
||||
* @return Optimizer
|
||||
*/
|
||||
public static function create(Thumb $thumb) {
|
||||
static::init();
|
||||
|
||||
$pre = [];
|
||||
$post = [];
|
||||
|
||||
// Get optimizers parameter
|
||||
$optimizers = a::get($thumb->options, 'imagekit.optimize', kirby()->option('imagekit.optimize'), true);
|
||||
|
||||
foreach(static::$optimizers as $optimizerClass) {
|
||||
if($optimizers === true || (is_array($optimizers) && in_array($optimizerClass::name(), $optimizers))) {
|
||||
if($optimizer = $optimizerClass::create($thumb)) {
|
||||
if($optimizer->priority('pre') !== false) {
|
||||
$pre[] = $optimizer;
|
||||
}
|
||||
if($optimizer->priority('post') !== false) {
|
||||
$post[] = $optimizer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort all applicable optimization operations.
|
||||
usort($pre, function($a, $b) {
|
||||
if($a === $b) return 0;
|
||||
return ($a->priority('pre') < $b->priority('pre')) ? -1 : 1;
|
||||
});
|
||||
|
||||
usort($post, function($a, $b) {
|
||||
if($a === $b) return 0;
|
||||
return ($a->priority('post') < $b->priority('post')) ? -1 : 1;
|
||||
});
|
||||
|
||||
return new static($thumb, $pre, $post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all operations that should happen before thumbnail
|
||||
* creation.
|
||||
*/
|
||||
public function pre() {
|
||||
foreach($this->pre as $optimizer) {
|
||||
$optimizer->pre();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all operations that should happen after thumbnail
|
||||
* creation.
|
||||
*/
|
||||
public function post() {
|
||||
foreach($this->post as $optimizer) {
|
||||
$optimizer->post();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the optimizer by extending all thumbnail
|
||||
* drivers in Kirby’s toolkit.
|
||||
*/
|
||||
public static function register() {
|
||||
static $registred;
|
||||
if($registred) return;
|
||||
|
||||
foreach(thumb::$drivers as $name => $driver) {
|
||||
thumb::$drivers[$name] = function($thumb) use ($driver) {
|
||||
|
||||
if(a::get($thumb->options, 'imagekit.optimize', kirby()->option('imagekit.optimize')) !== false) {
|
||||
$optimizer = static::create($thumb);
|
||||
|
||||
$optimizer->pre();
|
||||
$driver($thumb);
|
||||
$optimizer->post();
|
||||
|
||||
} else {
|
||||
$driver($thumb);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$registred = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans `optimizer` subdir for available optimizers and
|
||||
* loads them, if they’re available.
|
||||
*
|
||||
* @param Kirby $kirby
|
||||
*/
|
||||
public static function init($kirby = null) {
|
||||
static $initialized;
|
||||
if ($initialized) return;
|
||||
|
||||
static::$kirby = $kirby ?: kirby();
|
||||
|
||||
$lib = imagekit()->root() . DS . 'lib' . DS . 'optimizer';
|
||||
|
||||
// Load and initialize all optimizers
|
||||
foreach(dir::read($lib, ['base.php']) as $basename) {
|
||||
require_once($lib . DS . $basename);
|
||||
$optimizerClass = __NAMESPACE__ . '\\Optimizer\\' . f::name($basename);
|
||||
|
||||
// Setup defaults
|
||||
static::$kirby->options = array_merge($optimizerClass::defaults(), static::$kirby->options);
|
||||
|
||||
$optimizerClass::configure(static::$kirby);
|
||||
|
||||
if ($optimizerClass::available()) {
|
||||
static::$optimizers[] = $optimizerClass;
|
||||
}
|
||||
}
|
||||
|
||||
$initialized = true;
|
||||
}
|
||||
|
||||
public static function available($name) {
|
||||
static::init();
|
||||
$name = strtolower($name);
|
||||
|
||||
foreach(static::$optimizers as $optimizer) {
|
||||
if($optimizer::name() === $name) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
256
site/OFF_plugins/imagekit/lib/optimizer/base.php
Normal file
256
site/OFF_plugins/imagekit/lib/optimizer/base.php
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
use Exception;
|
||||
use F;
|
||||
use ReflectionClass;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for the optimizer class. An optimizer is
|
||||
* created for a specific thumbnail by calling the
|
||||
* `create($thumb)` method.
|
||||
*/
|
||||
interface BaseInterface {
|
||||
/**
|
||||
* Should implement at least some basic checks to make
|
||||
* sure, that the optimizer is working. This method should
|
||||
* check for executables being in place,
|
||||
* for PHP extensions, operating system etc.
|
||||
*
|
||||
* @return boolean Return `true`, if the optimizer is
|
||||
* available, otherwise `false`.
|
||||
*/
|
||||
public static function available();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The base class for ImageKit’s optimizers.
|
||||
*/
|
||||
abstract class Base implements BaseInterface {
|
||||
|
||||
/**
|
||||
* Defines the file types, this optimizer can handle.
|
||||
*
|
||||
* @var string|array Either string with a value of '*' or
|
||||
* an array containing a list of mime types.
|
||||
*/
|
||||
public static $selector = '*';
|
||||
|
||||
/**
|
||||
* Defines the priority of this optimizer’s operations.
|
||||
* @var array An array of two elements, where each can be
|
||||
* either a positive integer, zero or false.
|
||||
* The first value is the priority of
|
||||
* pre-operations, the second one of
|
||||
* post-operations. Priority is not set static
|
||||
* to make synamic changed possible.
|
||||
*/
|
||||
public $priority = [10, 10];
|
||||
|
||||
/**
|
||||
* Kirby’s instance.
|
||||
*
|
||||
* @var Kirby
|
||||
*/
|
||||
public static $kirby;
|
||||
|
||||
/**
|
||||
* Thumbnail will be set by create method.
|
||||
*
|
||||
* @var Thumb
|
||||
*/
|
||||
protected $thumb;
|
||||
|
||||
/**
|
||||
* Constructor of this optimizer
|
||||
*
|
||||
* @param Thumb An instance of the Thumb class.
|
||||
*/
|
||||
protected function __construct($thumb) {
|
||||
$this->thumb = $thumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all available setting variables of
|
||||
* this optimizer.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function defaults() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after defaults have been added to the global
|
||||
* Kirby instance. Can be used for further operations
|
||||
* that need all options to be in place.
|
||||
*/
|
||||
public static function configure($kirby) {
|
||||
static::$kirby = $kirby;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to create an instance of given
|
||||
* optimizer.
|
||||
*/
|
||||
public static function create($thumb) {
|
||||
if(!static::matches($thumb)) {
|
||||
// Don’t create optimizer for given thumb, if it
|
||||
// cannot handle it’s file type.
|
||||
return null;
|
||||
} else {
|
||||
return new static($thumb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations to performed before thumbnail creation. This
|
||||
* can be used to modify parameters on the passed $thumb
|
||||
* object.
|
||||
*
|
||||
* @param Thumb $thumb
|
||||
*/
|
||||
public function pre() {
|
||||
// Do some crazy stuff here in a subclass …
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations to be performed after the thumbnai has been
|
||||
* created by the thumbs driver.
|
||||
*
|
||||
* @param Thumb $thumb
|
||||
*/
|
||||
public function post() {
|
||||
// Do some crazy stuff here in a subclass …
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority of this optimizer.
|
||||
*
|
||||
* @param string $which Must be either 'pre' or 'post'.
|
||||
* @return int|boolean The priority of either 'pre' or
|
||||
* 'post' operations or false, if this
|
||||
* optimizer does not have a pre/post
|
||||
* operation defined.
|
||||
*/
|
||||
public function priority($which) {
|
||||
switch($which) {
|
||||
case 'pre':
|
||||
return $this->priority[0];
|
||||
|
||||
case 'post':
|
||||
return $this->priority[1];
|
||||
|
||||
default:
|
||||
throw new Exception('`$which` parameter must have a value of either `"pre"` or `"post"`.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, checks the extension of a thumb
|
||||
* destination file against the mime types, this optimizer
|
||||
* can handle. Additional checks are not performed.
|
||||
*
|
||||
* @param Thumb $thumb
|
||||
* @return bool `true`, if Optimizer can handle given
|
||||
* thumb, otherwise `false`.
|
||||
*/
|
||||
public static function matches($thumb) {
|
||||
$mime = f::extensionToMime(f::extension($thumb->destination->root));
|
||||
return in_array($mime, static::$selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the optimizer class in lowercase
|
||||
* without namespace.
|
||||
*
|
||||
* @return string The optimizer’s class name without
|
||||
* namespace.
|
||||
*/
|
||||
public static function name() {
|
||||
return strtolower(str_replace(__NAMESPACE__ . '\\', '', get_called_class()));
|
||||
}
|
||||
|
||||
|
||||
/* ===== Utility Functions ============================================== */
|
||||
|
||||
/**
|
||||
* Returns a temporary filename, based on the original
|
||||
* filename of the thumbnail destination.
|
||||
*
|
||||
* @param string $extension Optionally change the
|
||||
* extension of the temporary
|
||||
* file by providing this
|
||||
* parameter.
|
||||
* @return string The full path to the
|
||||
* temporary file.
|
||||
*/
|
||||
protected function getTemporaryFilename($extension = null) {
|
||||
$parts = pathinfo($this->thumb->destination->root);
|
||||
|
||||
if (!$extension) {
|
||||
$extension = $parts['extension'];
|
||||
}
|
||||
|
||||
// Add a unique suffix
|
||||
$suffix = '-' . uniqid();
|
||||
|
||||
return $parts['dirname'] . DS . $parts['filename'] . $suffix . '.' . $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the filesize of $target and $alternative and
|
||||
* only keeps the smallest of both files. If $alternative
|
||||
* is smaller than $target, $target will be replaced by
|
||||
* $alternative.
|
||||
*
|
||||
* @param string $target Full path to target file.
|
||||
* @param string $alternative Full path to alternative file.
|
||||
*
|
||||
*/
|
||||
protected function keepSmallestFile($target, $alternative) {
|
||||
if(f::size($alternative) <= f::size($target)) {
|
||||
f::remove($target);
|
||||
f::move($alternative, $target);
|
||||
} else {
|
||||
f::remove($alternative);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the driver of a given thumb is given driver id.
|
||||
*
|
||||
* @param string $driver Name of the thumbnail engine,
|
||||
* (i.e. 'im' or 'gd').
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isDriver($driver) {
|
||||
return (
|
||||
(isset($this->thumb->options['driver']) && $this->thumb->options['driver'] === $driver) ||
|
||||
(static::$kirby->option('imagekit.driver') === $driver)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the value of an option from given Thumb
|
||||
* object. If not set, returns the global value of this
|
||||
* option.
|
||||
*
|
||||
* @param Thumb $thumb An instance of the Thumb class
|
||||
* from Kirby’s toolkit.
|
||||
* @param string $key The option key.
|
||||
* @return mixed Either local or global value of
|
||||
* the option.
|
||||
*/
|
||||
protected function option($key, $default = null) {
|
||||
if(isset($this->thumb->options[$key])) {
|
||||
return $this->thumb->options[$key];
|
||||
} else {
|
||||
return static::$kirby->option($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
74
site/OFF_plugins/imagekit/lib/optimizer/gifsicle.php
Normal file
74
site/OFF_plugins/imagekit/lib/optimizer/gifsicle.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
use F;
|
||||
|
||||
|
||||
/**
|
||||
* Lossless optimization of GIF files by using `gifsicle`.
|
||||
* Supports animated GIFs.
|
||||
*
|
||||
* See: https://www.lcdf.org/gifsicle/
|
||||
*/
|
||||
class Gifsicle extends Base {
|
||||
|
||||
public static $selector = ['image/gif'];
|
||||
public $priority = [false, 50];
|
||||
|
||||
protected $targetFile;
|
||||
protected $tempFile;
|
||||
|
||||
|
||||
public static function defaults() {
|
||||
return [
|
||||
'imagekit.gifsicle.bin' => null,
|
||||
'imagekit.gifsicle.level' => 3,
|
||||
'imagekit.gifsicle.colors' => false,
|
||||
'imagekit.gifsicle.flags' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function available() {
|
||||
return !empty(static::$kirby->option('imagekit.gifsicle.bin'));
|
||||
}
|
||||
|
||||
public function post() {
|
||||
|
||||
$tmpFile = $this->getTemporaryFilename();
|
||||
|
||||
$command = [];
|
||||
|
||||
$command[] = static::$kirby->option('imagekit.gifsicle.bin');
|
||||
|
||||
if($this->thumb->options['interlace']) {
|
||||
$command[] = '--interlace';
|
||||
}
|
||||
|
||||
// Set colors
|
||||
$colors = $this->option('imagekit.gifsicle.colors');
|
||||
if($colors !== false) {
|
||||
$command[] = "--colors $colors";
|
||||
}
|
||||
|
||||
// Set optimization level.
|
||||
$command[] = '--optimize=' . $this->option('imagekit.gifsicle.level');
|
||||
|
||||
$flags = $this->option('imagekit.gifsicle.flags');
|
||||
if(!empty($flags)) {
|
||||
// Add exra flags, if defined by user.
|
||||
$command[] = $flags;
|
||||
}
|
||||
|
||||
// Set output file
|
||||
$command[] = '--output "' . $tmpFile . '"';
|
||||
|
||||
// Set input file
|
||||
$command[] = '"' . $this->thumb->destination->root . '"';
|
||||
|
||||
exec(implode(' ', $command));
|
||||
|
||||
$this->keepSmallestFile($this->thumb->destination->root, $tmpFile);
|
||||
}
|
||||
|
||||
}
|
||||
79
site/OFF_plugins/imagekit/lib/optimizer/jpegtran.php
Normal file
79
site/OFF_plugins/imagekit/lib/optimizer/jpegtran.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
use F;
|
||||
|
||||
|
||||
/**
|
||||
* Lossless optimization of JPEG files by using `jpegtran`.
|
||||
*
|
||||
* See: http://jpegclub.org/jpegtran/
|
||||
* and: http://linux.die.net/man/1/jpegtran
|
||||
*/
|
||||
class JPEGTran extends Base {
|
||||
|
||||
public static $selector = ['image/jpeg'];
|
||||
public $priority = [false, 50];
|
||||
|
||||
protected $targetFile;
|
||||
protected $tempFile;
|
||||
|
||||
|
||||
public static function defaults() {
|
||||
return [
|
||||
'imagekit.jpegtran.bin' => null,
|
||||
'imagekit.jpegtran.optimize' => true,
|
||||
'imagekit.jpegtran.copy' => 'none',
|
||||
'imagekit.jpegtran.flags' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function available() {
|
||||
return !empty(static::$kirby->option('imagekit.jpegtran.bin'));
|
||||
}
|
||||
|
||||
public function post() {
|
||||
|
||||
$tmpFile = $this->getTemporaryFilename();
|
||||
|
||||
$command = [];
|
||||
|
||||
$command[] = static::$kirby->option('imagekit.jpegtran.bin');
|
||||
|
||||
if($this->thumb->options['interlace']) {
|
||||
$command[] = '-progressive';
|
||||
}
|
||||
|
||||
if($this->thumb->options['grayscale']) {
|
||||
$command[] = '-grayscale';
|
||||
}
|
||||
|
||||
// Copy metadata (or not)?
|
||||
if($copy = $this->option('imagekit.jpegtran.copy')) {
|
||||
$command[] = "-copy $copy";
|
||||
}
|
||||
|
||||
if($this->option('imagekit.jpegtran.optimize')) {
|
||||
$command[] = '-optimize';
|
||||
}
|
||||
|
||||
// Write to a temporary file, so we can compare filesizes
|
||||
// after optimization and keep only the smaller file as
|
||||
// jpegtran does not always create smaller files.
|
||||
$command[] = '-outfile "' . $tmpFile . '"';
|
||||
|
||||
$flags = $this->option('imagekit.jpegtran.flags');
|
||||
if(!empty($flags)) {
|
||||
// Add exra flags, if defined by user.
|
||||
$command[] = $flags;
|
||||
}
|
||||
|
||||
$command[] = '"' . $this->thumb->destination->root . '"';
|
||||
|
||||
exec(implode(' ', $command));
|
||||
|
||||
$this->keepSmallestFile($this->thumb->destination->root, $tmpFile);
|
||||
}
|
||||
|
||||
}
|
||||
100
site/OFF_plugins/imagekit/lib/optimizer/mozjpeg.php
Normal file
100
site/OFF_plugins/imagekit/lib/optimizer/mozjpeg.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
|
||||
/**
|
||||
* Uses `mozjpeg` for encoding JPEG files. This often creates
|
||||
* much smaller JPEG files than most other encoders at a
|
||||
* comparable quality.
|
||||
*
|
||||
* See: https://github.com/mozilla/mozjpeg
|
||||
*/
|
||||
class MozJPEG extends Base {
|
||||
|
||||
public static $selector = ['image/jpeg'];
|
||||
public $priority = [100, 5];
|
||||
|
||||
protected $targetFile;
|
||||
protected $tmpFile;
|
||||
|
||||
|
||||
public static function defaults() {
|
||||
return [
|
||||
'imagekit.mozjpeg.bin' => null,
|
||||
'imagekit.mozjpeg.quality' => 85,
|
||||
'imagekit.mozjpeg.flags' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function available() {
|
||||
return !empty(static::$kirby->option('imagekit.mozjpeg.bin'));
|
||||
}
|
||||
|
||||
public function pre() {
|
||||
$this->targetFile = $this->thumb->destination->root;
|
||||
|
||||
if($this->isDriver('im')) {
|
||||
// Instruct imagemagick driver to write out a temporary,
|
||||
// uncrompressed TGA file, so our JPEG will not be
|
||||
// compressed twice. I played around with PNM too,
|
||||
// because it’s much faster as an intermediate format,
|
||||
// but some images got corrupted by mozjpeg.
|
||||
$this->tmpFile = $this->getTemporaryFilename('tga');
|
||||
$this->thumb->destination->root = $this->tmpFile;
|
||||
} else {
|
||||
// If GD driver (or an unknown driver) is active, we
|
||||
// need to encode twice, because SimpleImage can only
|
||||
// save to JPEG, PNG or GIF. As saving a 24-bit
|
||||
// lossless PNG as an intermediate step is too
|
||||
// expensive for large images, we need to encode
|
||||
// as JPEG :-(
|
||||
// This also needs a temporary file, because it seems
|
||||
// that mozjpeg cannot overwrite the it’s file.
|
||||
$this->tmpFile = $this->getTemporaryFilename();
|
||||
$this->thumb->destination->root = $this->tmpFile;
|
||||
$this->thumb->options['quality'] = 99;
|
||||
}
|
||||
}
|
||||
|
||||
public function post() {
|
||||
|
||||
$command = [];
|
||||
|
||||
$command[] = static::$kirby->option('imagekit.mozjpeg.bin');
|
||||
|
||||
// Quality
|
||||
$command[] = '-quality ' . $this->option('imagekit.mozjpeg.quality');
|
||||
|
||||
// Interlace
|
||||
if($this->thumb->options['interlace']) {
|
||||
$command[] = '-progressive';
|
||||
}
|
||||
|
||||
// Grayscale
|
||||
if($this->thumb->options['grayscale']) {
|
||||
$command[] = '-grayscale';
|
||||
}
|
||||
|
||||
// Set output file.
|
||||
$command[] = '-outfile "' . $this->targetFile . '"';
|
||||
|
||||
$flags = $this->option('imagekit.mozjpeg.flags');
|
||||
if(!empty($flags)) {
|
||||
// Add exra flags, if defined by user.
|
||||
$command[] = $flags;
|
||||
}
|
||||
|
||||
// Use tmp file as input.
|
||||
$command[] = '"' . $this->tmpFile . '"';
|
||||
|
||||
exec(implode(' ', $command));
|
||||
// Delete temporary file and restore destination path
|
||||
// on thumb object. This only needs to be done, if
|
||||
// ImageMagick driver is used and the input file was
|
||||
// in PNM format.
|
||||
@unlink($this->tmpFile);
|
||||
$this->thumb->destination->root = $this->targetFile;
|
||||
}
|
||||
|
||||
}
|
||||
64
site/OFF_plugins/imagekit/lib/optimizer/optipng.php
Normal file
64
site/OFF_plugins/imagekit/lib/optimizer/optipng.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
|
||||
/**
|
||||
* Lossless optimization of PNG images using `optipng`.
|
||||
*
|
||||
* See: http://optipng.sourceforge.net/
|
||||
* and: http://optipng.sourceforge.net/pngtech/optipng.html
|
||||
*/
|
||||
class OptiPNG extends Base {
|
||||
|
||||
public static $selector = ['image/png'];
|
||||
public $priority = [false, 50];
|
||||
|
||||
protected $targetFile;
|
||||
protected $tmpFile;
|
||||
|
||||
|
||||
public static function defaults() {
|
||||
return [
|
||||
'imagekit.optipng.bin' => null,
|
||||
'imagekit.optipng.level' => 2,
|
||||
'imagekit.optipng.strip' => 'all',
|
||||
'imagekit.optipng.flags' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function available() {
|
||||
return !empty(static::$kirby->option('imagekit.optipng.bin'));
|
||||
}
|
||||
|
||||
public function post() {
|
||||
|
||||
$command = [];
|
||||
|
||||
$command[] = static::$kirby->option('imagekit.optipng.bin');
|
||||
|
||||
// Optimization Level
|
||||
$level = $this->option('imagekit.optipng.level');
|
||||
if($level !== false) { // Level can be 0, so strict comparison is neccessary
|
||||
$command[] = "-o$level";
|
||||
}
|
||||
|
||||
// Should we strip Metadata?
|
||||
if($strip = $this->option('imagekit.optipng.strip')) {
|
||||
$command[] = "-strip $strip";
|
||||
}
|
||||
|
||||
$flags = $this->option('imagekit.optipng.flags');
|
||||
if(!empty($flags)) {
|
||||
// Add exra flags, if defined by user.
|
||||
$command[] = $flags;
|
||||
}
|
||||
|
||||
// Set file to optimize
|
||||
$command[] = '"' . $this->thumb->destination->root . '"';
|
||||
|
||||
exec(implode(' ', $command));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
127
site/OFF_plugins/imagekit/lib/optimizer/pngquant.php
Normal file
127
site/OFF_plugins/imagekit/lib/optimizer/pngquant.php
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Optimizer;
|
||||
|
||||
|
||||
/**
|
||||
* Lossy optimization by using `pngquant` for converting
|
||||
* 24-bit PNGs to an 8-bit palette while preserving the
|
||||
* alpha-channel.
|
||||
*
|
||||
* See: https://pngquant.org/
|
||||
*/
|
||||
class PNGQuant extends Base {
|
||||
|
||||
public static $selector = ['image/png'];
|
||||
public $priority = [100, 5];
|
||||
|
||||
protected $targetFile;
|
||||
protected $tmpFile;
|
||||
|
||||
public static function defaults() {
|
||||
return [
|
||||
'imagekit.pngquant.bin' => null,
|
||||
'imagekit.pngquant.quality' => null,
|
||||
'imagekit.pngquant.speed' => 3,
|
||||
'imagekit.pngquant.posterize' => false,
|
||||
'imagekit.pngquant.colors' => false,
|
||||
'imagekit.pngquant.flags' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function available() {
|
||||
return !empty(static::$kirby->option('imagekit.pngquant.bin'));
|
||||
}
|
||||
|
||||
public function pre() {
|
||||
$this->targetFile = $this->thumb->destination->root;
|
||||
|
||||
if($this->isDriver('im')) {
|
||||
// Instruct imagemagick driver to write out a
|
||||
// temporary, uncrompressed PNM file, so our PNG will
|
||||
// not need to be encoded twice.
|
||||
$this->tmpFile = $this->getTemporaryFilename('pnm');
|
||||
$this->thumb->destination->root = $this->tmpFile;
|
||||
} else {
|
||||
// If driver is anything else but IM, we do not create
|
||||
// a temporary file.
|
||||
$this->tmpFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function post() {
|
||||
|
||||
$command = [];
|
||||
|
||||
$command[] = static::$kirby->option('imagekit.pngquant.bin');
|
||||
|
||||
// Quality
|
||||
$quality = $this->option('imagekit.pngquant.quality');
|
||||
if($quality !== null) {
|
||||
$command[] = "--quality $quality";
|
||||
}
|
||||
|
||||
// Speed
|
||||
if($speed = $this->option('imagekit.pngquant.speed')) {
|
||||
$command[] = "--speed $speed";
|
||||
}
|
||||
|
||||
// Posterize
|
||||
$posterize = $this->option('imagekit.pngquant.posterize');
|
||||
if($posterize !== false) { // need verbose check,
|
||||
// because posterize can have
|
||||
// value of 0
|
||||
$command[] = "--posterize $posterize";
|
||||
}
|
||||
|
||||
$copy = $this->option('imagekit.pngquant.copy');
|
||||
if($copy !== null) {
|
||||
$command[] = "--copy $copy";
|
||||
}
|
||||
|
||||
if(is_null($this->tmpFile)) {
|
||||
// Only save optimized file, if it is smaller than the
|
||||
// original. This only makes sense, if input file a
|
||||
// PNG image. If input is PNM, the result should
|
||||
// always be saved.
|
||||
$command[] = '--skip-if-larger';
|
||||
}
|
||||
|
||||
$flags = $this->option('imagekit.pngquant.flags');
|
||||
if(!empty($flags)) {
|
||||
$command[] = $flags;
|
||||
}
|
||||
|
||||
// Force pngquant to override original file, if it was used
|
||||
// as input (i.e. when no temporary file was created).
|
||||
$command[] = '--force --output "' . $this->targetFile . '"';
|
||||
|
||||
// Colors
|
||||
$colors = $this->option('imagekit.pngquant.colors');
|
||||
if($colors != false) {
|
||||
$command[] = $colors;
|
||||
}
|
||||
|
||||
// Separator between options and input file as
|
||||
// recommended according by the pngquant docs.
|
||||
$command[] = '--';
|
||||
|
||||
if(!is_null($this->tmpFile)) {
|
||||
// Use tmp file as input.
|
||||
$command[] = '"' . $this->tmpFile . '"';
|
||||
} else {
|
||||
// Use target file as input
|
||||
$command[] = '"' . $this->targetFile . '"';
|
||||
}
|
||||
|
||||
exec(implode(' ', $command));
|
||||
|
||||
if(!is_null($this->tmpFile)) {
|
||||
// Delete temporary file and restore destination path on thumb object.
|
||||
@unlink($this->tmpFile);
|
||||
$this->thumb->destination->root = $this->targetFile;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
268
site/OFF_plugins/imagekit/lib/proxyasset.php
Normal file
268
site/OFF_plugins/imagekit/lib/proxyasset.php
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit;
|
||||
|
||||
use A;
|
||||
use Asset;
|
||||
use Dimensions;
|
||||
use Exception;
|
||||
use F;
|
||||
use Kirby;
|
||||
use Media;
|
||||
use Str;
|
||||
use Thumb;
|
||||
use Url;
|
||||
|
||||
|
||||
/**
|
||||
* An extended version of Kirby’s Asset class, which also
|
||||
* works with files that do not exist yet.
|
||||
*/
|
||||
class ProxyAsset extends Asset {
|
||||
|
||||
// Thumb parameters like you would path to the `Thumb`
|
||||
// class’ constructor
|
||||
protected $options = [];
|
||||
|
||||
// Will be changed to true if thumbnail has been generated
|
||||
protected $generated = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Media|string $path
|
||||
*/
|
||||
public function __construct($path) {
|
||||
// This constructor function mimics the behavior of both
|
||||
// Asset’s and Media’s constructors. Because `realpath()`
|
||||
// (used in Media’s constructor) does not work with
|
||||
// non-existing files, the complete constructors of both
|
||||
// classes are redeclared here, using a different function
|
||||
// for resolving paths of
|
||||
// non-existing files. This constructor should always try
|
||||
// to match the behavior of Kirby’s original Asset class.
|
||||
|
||||
// Asset’s constructor
|
||||
$this->kirby = kirby::instance();
|
||||
|
||||
if($path instanceof Media) {
|
||||
// Because “root” of non-existing files does not work,
|
||||
// when they’re initialized as Media objects, we’ll
|
||||
// reconstruct the file’s path from it’s URL.
|
||||
$root = $this->kirby->roots()->index() . str_replace(kirby()->urls->index, '', $path->url());
|
||||
$url = $path->url();
|
||||
} else {
|
||||
$root = url::isAbsolute($path) ? null : $this->kirby->roots()->index() . DS . ltrim($path, DS);
|
||||
$url = url::makeAbsolute($path);
|
||||
}
|
||||
|
||||
// Media’s constructor
|
||||
$this->url = $url;
|
||||
$this->root = $root === null ? $root : static::normalizePath($root);
|
||||
$this->filename = basename($root);
|
||||
$this->name = pathinfo($root, PATHINFO_FILENAME);
|
||||
$this->extension = strtolower(pathinfo($root, PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to normalize a given path by resolving `..`
|
||||
* and `.`. Tries to mimick the behavoir of `realpath()`
|
||||
* which does not work on non-existing files.
|
||||
* Source: http://php.net/manual/de/function.realpath.php#84012
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected static function normalizePath($path) {
|
||||
$path = str_replace(['/', '\\'], DS, $path);
|
||||
$parts = explode(DS, $path);
|
||||
$absolutes = [];
|
||||
foreach($parts as $part) {
|
||||
if('.' === $part) continue;
|
||||
if('..' === $part)
|
||||
array_pop($absolutes);
|
||||
else
|
||||
$absolutes[] = $part;
|
||||
}
|
||||
return implode(DS, $absolutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter and getter for transformation parameters
|
||||
*
|
||||
* @param array $options
|
||||
* @return string
|
||||
*/
|
||||
public function options(array $options = null) {
|
||||
if($options === null) {
|
||||
return $this->options;
|
||||
} else {
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dimensions of the file if possible. If the
|
||||
* proxy asset has not been generated yet, dimensions are
|
||||
* read from source file and then calculated according to
|
||||
* given thumb options.
|
||||
*
|
||||
* @return Dimensions
|
||||
*/
|
||||
public function dimensions() {
|
||||
|
||||
if($this->generated) {
|
||||
// If the thumbnail has been generated, get dimensions
|
||||
// from thumb file.
|
||||
return parent::dimensions();
|
||||
}
|
||||
|
||||
if(isset($this->cache['dimensions'])) {
|
||||
return $this->cache['dimensions'];
|
||||
}
|
||||
|
||||
if(!$this->original) {
|
||||
throw new Exception('Cannot calculate dimensions of ProxyAsset without a valid original.');
|
||||
}
|
||||
|
||||
if(!is_array($this->options)) {
|
||||
throw new Exception('You have to set transformation options on ProxyAsset before calling `dimensions()`');
|
||||
}
|
||||
|
||||
if(in_array($this->original->mime(), ['image/jpeg', 'image/png', 'image/gif'])) {
|
||||
$size = (array)getimagesize($this->original->root());
|
||||
$width = a::get($size, 0, 0);
|
||||
$height = a::get($size, 1, 0);
|
||||
} else {
|
||||
$width = 0;
|
||||
$height = 0;
|
||||
}
|
||||
|
||||
// Create dimensions object and resize according to thumb options.
|
||||
$dimensions = new Dimensions($width, $height);
|
||||
|
||||
if($this->options['crop']) {
|
||||
$dimensions->crop($this->options['width'], $this->options['height']);
|
||||
} else {
|
||||
$dimensions->fitWidthAndHeight($this->options['width'], $this->options['height'], $this->options['upscale']);
|
||||
}
|
||||
|
||||
return $this->cache['dimensions'] = $dimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the actual thumbnail. This function is triggered
|
||||
* by certain methods, which need the final thumbnail to be
|
||||
* there for returning reasonable results.
|
||||
*/
|
||||
public function generate() {
|
||||
|
||||
if($this->generated) return;
|
||||
|
||||
$thumb = new Thumb($this->original, $this->options);
|
||||
|
||||
// Just to be sure to have all corrent data of the
|
||||
// resulting object in place, we override this object’s
|
||||
// properties with those of thumb’s result.
|
||||
$this->reset();
|
||||
foreach(['url', 'root', 'filename', 'name', 'extension', 'content'] as $prop) {
|
||||
$this->$prop = $thumb->result->$prop;
|
||||
}
|
||||
|
||||
$this->generated = true;
|
||||
}
|
||||
|
||||
public function mime() {
|
||||
return f::mime($this->generated ? $this->root : $this->original->root());
|
||||
}
|
||||
|
||||
public function type() {
|
||||
return f::type($this->generated ? $this->root : $this->original->root());
|
||||
}
|
||||
|
||||
public function is($value) {
|
||||
return f::is($this->generated ? $this->root : $this->original->root(), $value);
|
||||
}
|
||||
|
||||
public function read($format = null) {
|
||||
$this->generate();
|
||||
return parent::read($format);
|
||||
}
|
||||
|
||||
public function content($content = null, $format = null) {
|
||||
if(is_null($content)) $this->generate();
|
||||
return parent::content($content, $format);
|
||||
}
|
||||
|
||||
public function move($to) {
|
||||
$this->generate();
|
||||
return parent::move($to);
|
||||
}
|
||||
|
||||
public function copy($to) {
|
||||
$this->generate();
|
||||
return parent::copy($to);
|
||||
}
|
||||
|
||||
public function size() {
|
||||
$this->generate();
|
||||
return parent::size();
|
||||
}
|
||||
|
||||
public function modified($format = null, $handler = 'date') {
|
||||
$this->generate();
|
||||
return parent::modified($format, $handler);
|
||||
}
|
||||
|
||||
public function base64() {
|
||||
$this->generate();
|
||||
return parent::base64();
|
||||
}
|
||||
|
||||
public function exists() {
|
||||
$this->generate();
|
||||
return parent::exists();
|
||||
}
|
||||
|
||||
public function isWritable() {
|
||||
$this->generate();
|
||||
return parent::isWritable();
|
||||
}
|
||||
|
||||
public function isReadable() {
|
||||
$this->generate();
|
||||
return parent::isReadable();
|
||||
}
|
||||
|
||||
public function load($data = array()) {
|
||||
$this->generate();
|
||||
return parent::load($data);
|
||||
}
|
||||
|
||||
public function show() {
|
||||
$this->generate();
|
||||
return parent::show();
|
||||
}
|
||||
|
||||
public function download($filename = null) {
|
||||
$this->generate();
|
||||
return parent::download($filename);
|
||||
}
|
||||
|
||||
public function exif() {
|
||||
$this->generate();
|
||||
return parent::exif();
|
||||
}
|
||||
|
||||
public function imagesize() {
|
||||
$this->generate();
|
||||
return parent::imagesize();
|
||||
}
|
||||
|
||||
// Methods that don’t need to be overloaded:
|
||||
// thumb, resize, crop, width, height, ratio, scale, bw, blur
|
||||
// => thumb() fails automatically, if called on a (Proxy)Asset with original set.
|
||||
// isThumb, isWebsafe
|
||||
// => Don’t need the result file to be in place and work without any further help.
|
||||
}
|
||||
73
site/OFF_plugins/imagekit/license.md
Normal file
73
site/OFF_plugins/imagekit/license.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# ImageKit End User License Agreement
|
||||
|
||||
This End User License Agreement (the "Agreement") is a binding legal agreement between you and the Fabian Michael (the "Author"). By installing or using the ImageKit Plugin (the "Software"), you agree to be bound by the terms of this Agreement. If you do not agree to the Agreement, do not download, install, or use the Software. Installation or use of the Software signifies that you have read, understood, and agreed to be bound by the Agreement.
|
||||
|
||||
Revised on: 20 October, 2016
|
||||
|
||||
## Usage
|
||||
|
||||
This Agreement grants a non-exclusive, non-transferable license to install and use a single instance of the Software on a specific Website. Additional Software licenses must be purchased in order to install and use the Software on additional Websites. The Author reserves the right to determine whether use of the Software qualifies under this Agreement. The Author owns all rights, title and interest to the Software (including all intellectual property rights) and reserves all rights to the Software that are not expressly granted in this Agreement.
|
||||
|
||||
## Backups
|
||||
|
||||
You may make copies of the Software in any machine readable form solely for back-up purposes, provided that you reproduce the Software in its original form and with all proprietary notices on the back-up copy. All rights to the Software not expressly granted herein are reserved by the Author.
|
||||
|
||||
## Technical Support
|
||||
|
||||
Technical support is provided as described on <https://github.com/fabianmichael/kirby-imagekit>. No representations or guarantees are made regarding the response time in which support questions are answered.
|
||||
|
||||
## Refund Policy
|
||||
|
||||
We offer a 14-day, money back refund policy.
|
||||
|
||||
## Restrictions
|
||||
|
||||
You understand and agree that you shall only use the Software in a manner that complies with any and all applicable laws in the jurisdictions in which you use the Software. Your use shall be in accordance with applicable restrictions concerning privacy and intellectual property rights.
|
||||
|
||||
### You may not:
|
||||
|
||||
Distribute derivative works based on the Software;
|
||||
Reproduce the Software except as described in this Agreement;
|
||||
Sell, assign, license, disclose, distribute, or otherwise transfer or make available the Software or its Source Code, in whole or in part, in any form to any third parties;
|
||||
Use the Software to provide services to others;
|
||||
Remove or alter any proprietary notices on the Software.
|
||||
|
||||
## No Warranty
|
||||
|
||||
THE SOFTWARE IS OFFERED ON AN "AS-IS" BASIS AND NO WARRANTY, EITHER EXPRESSED OR IMPLIED, IS GIVEN. THE AUTHOR EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. YOU ASSUME ALL RISK ASSOCIATED WITH THE QUALITY, PERFORMANCE, INSTALLATION AND USE OF THE SOFTWARE INCLUDING, BUT NOT LIMITED TO, THE RISKS OF PROGRAM ERRORS, DAMAGE TO EQUIPMENT, LOSS OF DATA OR SOFTWARE PROGRAMS, OR UNAVAILABILITY OR INTERRUPTION OF OPERATIONS. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USE THE SOFTWARE AND ASSUME ALL RISKS ASSOCIATED WITH ITS USE.
|
||||
|
||||
## Term, Termination, and Modification.
|
||||
|
||||
You may use the Software under this Agreement until either party terminates this Agreement as set forth in this paragraph. Either party may terminate the Agreement at any time, upon written notice to the other party. Upon termination, all licenses granted to you will terminate, and you will immediately uninstall and cease all use of the Software. The Sections entitled "No Warranty," "Indemnification," and "Limitation of Liability" will survive any termination of this Agreement.
|
||||
|
||||
The Author may modify the Software and this Agreement with notice to you either in email or by publishing content on the Software website, including but not limited to changing the functionality or appearance of the Software, and such modification will become binding on you unless you terminate this Agreement.
|
||||
|
||||
## Indemnification.
|
||||
|
||||
By accepting the Agreement, you agree to indemnify and otherwise hold harmless the Author, its officers, employers, agents, subsidiaries, affiliates and other partners from any direct, indirect, incidental, special, consequential or exemplary damages arising out of, relating to, or resulting from your use of the Software or any other matter relating to the Software.
|
||||
|
||||
## Limitation of Liability.
|
||||
|
||||
YOU EXPRESSLY UNDERSTAND AND AGREE THAT THE AUTHOR SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES, INCLUDING BUT NOT LIMITED TO, DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER INTANGIBLE LOSSES (EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES). SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU. IN NO EVENT WILL THE AUTHOR'S TOTAL CUMULATIVE DAMAGES EXCEED THE FEES YOU PAID TO THE AUTHOR UNDER THIS AGREEMENT IN THE MOST RECENT TWELVE-MONTH PERIOD.
|
||||
|
||||
# Definitions
|
||||
|
||||
## Definition of Website
|
||||
|
||||
A "Website" is defined as a single domain including sub-domains that operate as a single entity. What constitutes a single entity shall be at the sole discretion of the Author.
|
||||
|
||||
## Definition of Source Code
|
||||
|
||||
The "Source Code" is defined as the contents of all HTML, CSS, JavaScript, and PHP files provided with the Software and includes all related image files and database schemas.
|
||||
|
||||
## Definition of an Update
|
||||
|
||||
An "Update" of the Software is defined as that which adds minor functionality enhancements or any bug fix to the current version. This class of release is identified by the change of the revision to the right of the decimal point, i.e. X.1 to X.2
|
||||
|
||||
The assignment to the category of Update or Upgrade shall be at the sole discretion of the Author.
|
||||
|
||||
## Definition of an Upgrade
|
||||
|
||||
An "Upgrade" is a major release of the Software and is defined as that which incorporates major new features or enhancement that increase the core functionality of the software. This class of release is identified by the change of the revision to the left of the decimal point, i.e. 4.X to 5.X
|
||||
|
||||
The assignment to the category of Update or Upgrade shall be at the sole discretion of the Author.
|
||||
29
site/OFF_plugins/imagekit/package.json
Normal file
29
site/OFF_plugins/imagekit/package.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "imagekit",
|
||||
"description": "Asynchronous thumbs API and image optimization for Kirby CMS.",
|
||||
"author": "Fabian Michael <hallo@fabianmichael.de>",
|
||||
"license": "SEE LICENSE IN license.md",
|
||||
"version": "1.1.3",
|
||||
|
||||
"type": "kirby-plugin",
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fabianmichael/kirby-imagekit"
|
||||
},
|
||||
|
||||
"bugs": {
|
||||
"url": "https://github.com/fabianmichael/kirby-imagekit/issues"
|
||||
},
|
||||
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-csso": "^2.0.0",
|
||||
"gulp-doctoc": "^0.1.4",
|
||||
"gulp-postcss": "^6.1.1",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-sass": "^2.3.2",
|
||||
"gulp-uglify": "^1.5.4",
|
||||
"postcss-assets": "^4.1.0"
|
||||
}
|
||||
}
|
||||
282
site/OFF_plugins/imagekit/readme.md
Normal file
282
site/OFF_plugins/imagekit/readme.md
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
# ImageKit
|
||||
|
||||
  
|
||||
|
||||
ImageKit provides an asynchronous thumbnail API and advanced image optimization for [Kirby CMS](http://getkirby.com).
|
||||
|
||||
**NOTE:** This is not be a free plugin. In order to use it on a production server, you need to buy a license. For details on ImageKit’s license model, scroll down to the [License](#8-license) section of this document.
|
||||
|
||||
<img src="https://shared.fabianmichael.de/imagekit-widget-v2.gif" alt="ImageKit’s Dashboard Widget" width="460" height="231" />
|
||||
|
||||
***
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents**
|
||||
|
||||
- [1 Key Features](#1-key-features)
|
||||
- [2 Download and Installation](#2-download-and-installation)
|
||||
- [2.1 Requirements](#21-requirements)
|
||||
- [2.2 Kirby CLI](#22-kirby-cli)
|
||||
- [2.3 Git Submodule](#23-git-submodule)
|
||||
- [2.4 Copy and Paste](#24-copy-and-paste)
|
||||
- [3 Usage](#3-usage)
|
||||
- [4 How it works](#4-how-it-works)
|
||||
- [4.1 Discovery mode](#41-discovery-mode)
|
||||
- [5 Basic Configuration](#5-basic-configuration)
|
||||
- [6 Image Optimization](#6-image-optimization)
|
||||
- [6.1 Setup](#61-setup)
|
||||
- [6.2 Overriding Global Settings](#62-overriding-global-settings)
|
||||
- [6.3 Available Optimizers](#63-available-optimizers)
|
||||
- [6.3.1 mozjpeg](#631-mozjpeg)
|
||||
- [6.3.2 jpegtran](#632-jpegtran)
|
||||
- [6.3.3 pngquant](#633-pngquant)
|
||||
- [6.3.4 optipng](#634-optipng)
|
||||
- [6.3.5 gifsicle](#635-gifsicle)
|
||||
- [7 Troubleshooting](#7-troubleshooting)
|
||||
- [8 License](#8-license)
|
||||
- [9 Technical Support](#9-technical-support)
|
||||
- [10 Credits](#10-credits)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
***
|
||||
|
||||
## 1 Key Features
|
||||
|
||||
- **Image-resizing on demand:** Kirby’s built-in thumbnail engine resizes images on-the-fly while executing the code in your template files. On image-heavy pages, the first page-load can take very long or even exceed the maximum execution time of PHP. ImageKit resizes images only on-demand as soon as they are requested by the client.
|
||||
- **Optimization:** ImageKit can utilize several command-line utilities to apply superior compression to your images. Both lossless and lossy optimizers are available. Your images look as shiny as before, but your pages will load much faster.*
|
||||
- **Security:** A lot of thumbnail libraries for PHP still offer the generation of resized images through URL parameters (e.g. `thumbnail.php?file=ambrosia.jpg&width=500`), which is a potential vector for DoS attacks. ImageKit only generates the thumbnails whose are defined in your page templates.
|
||||
- **Widget:** Pre-Generate your thumbnails right from the panel with a single click.
|
||||
- **Discovery Feature:** The widget scans you whole site for new thumbnails, before creating them.
|
||||
- **Error-Handling:** ImageKit let’s you know, when errors occur during thumbnail creation *(experimental)*.
|
||||
- **Self-Hosted:** Unlike many other image-resizing-services, ImageKit just sits in Kirby’s plugin directory, so you have everything under control without depending on external providers. No monthly fees. No visitor data is exposed to external companies. tl;dr: No bullshit!
|
||||
|
||||
*) To use optimization features, your need to have the corresponding command-line utilities installed on your server or have sufficient permissions to install them. The effectiveness of compression also depends heavily on your source images.
|
||||
|
||||
***
|
||||
|
||||
## 2 Download and Installation
|
||||
|
||||
### 2.1 Requirements
|
||||
|
||||
- PHP 5.4.0+ (With *libxml* if you’re using discovery mode. This extension is usually installed on most hosting providers.)
|
||||
- Kirby 2.3.0+
|
||||
- GD Library for PHP or ImageMagick command-line tools to resize images.
|
||||
- Tested on Apache 2 with mod_rewrite (but it should also work with other servers like nginx)
|
||||
- Permission to install and execute several command-line utilities on your server, if your want to use the optimization feature.
|
||||
|
||||
### 2.2 Kirby CLI
|
||||
|
||||
If you’re using the [Kirby CLI](https://github.com/getkirby/cli), you need to `cd` to the root directory of your Kirby installation and run the following command:
|
||||
|
||||
```
|
||||
kirby plugin:install fabianmichael/kirby-imagekit
|
||||
```
|
||||
|
||||
This will download and copy *ImageKit* into `site/plugins/imagekit`.
|
||||
|
||||
### 2.3 Git Submodule
|
||||
|
||||
To install this plugin as a git submodule, execute the following command from the root of your kirby project:
|
||||
|
||||
```
|
||||
$ git submodule add https://github.com/fabianmichael/kirby-imagekit.git site/plugins/imagekit
|
||||
```
|
||||
|
||||
### 2.4 Copy and Paste
|
||||
|
||||
1. [Download](https://github.com/fabianmichael/kirby-imagekit/archive/master.zip) the contents of this repository as ZIP-file.
|
||||
2. Rename the extracted folder to `imagekit` and copy it into the `site/plugins/` directory in your Kirby project.
|
||||
|
||||
## 3 Usage
|
||||
|
||||
Just use it like the built-in thumbnail API of Kirby. You can learn more about Kirby’s image processing capabilities in the [Kirby Docs](https://getkirby.com/docs/templates/thumbnails).
|
||||
|
||||
Due to the fact that thumbs created by ImageKit remain *virtual* until the the actual thumb file has been requested by a visitor of your website, some API methods will trigger instant creation of a thumbnail. You should avoid to call methods like `size()`, `base64()` or `modified()` on your thumb, whenever possible, because they only work after the actual thumbnail has been created. However, you can safely use methods like `width()`, `height()` and `ratio()` because dimensions are calculated prior to thumbnail creation.
|
||||
|
||||
If you don’t want to let the first visitors of your site need to wait for images to appear, all thumbnails on your site can be generated from ImageKit’s dashboard widget in advance.
|
||||
|
||||
## 4 How it works
|
||||
|
||||
Rather than doing the expensive task of image conversion on page load (default behavior of Kirby’s built-in thumbs API), thumbnails are stored as a »job« instead as the API is called by your template code. So they will only be generated, when a particular image size is requested by the browser. ImageKit also comes with a widget, so you can trigger creation of all thumbnails right from the panel.
|
||||
|
||||
### 4.1 Discovery mode
|
||||
|
||||
If the `imagekit.widget.discover` *(automatic indexing)* option is active, the widget will not only scan your thumbs folder for pending thumbnails, but will also make a HTTP request to every single page of your Kirby installation to execute every page‘s template code once. This feature also works with pagination and/or prev- and next links. Just make sure, that the pagination links have `rel` attributes of either `'next'` or `'prev'`. This way, ImageKit can even scan through paginated pages.
|
||||
|
||||
```
|
||||
<link href="<?= $pagination->prevPageURL() ?>" rel="prev">
|
||||
<link href="<?= $pagination->nextPageURL() ?>" rel="next">
|
||||
<a href="<?= $pagination->prevPageURL() ?>" rel="prev">Previous page</a>
|
||||
<a href="<?= $pagination->nextPageURL() ?>" rel="next">Next page</a>
|
||||
```
|
||||
|
||||
This currently works by using PHP’s DOM interface (`DOMDocument`), so if your HTML contains a lot of errors, this might fail. If you are experiencing any trouble with this feature, please report a bug so I can make it work with your project.
|
||||
|
||||
## 5 Basic Configuration
|
||||
|
||||
| Option | Default value | Description |
|
||||
|:--------------------|:--------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `imagekit.license` | `''` | Enter your license code here, once your site goes live.<br>*See the [License](#8-license) section of this document for more information.* |
|
||||
| `imagekit.lazy` | `true` | Set to `false` to temporary disable asynchronous thumbnail generation. This will restore the default behavior of Kirby. |
|
||||
| `imagekit.complain` | `true` | If enabled, ImageKit will try to return a placeholder showing an error symbol whenever thumbnail creation fails. If you don’t like this behavior, you can turn this feature off and ImageKit will fail silently.
|
||||
| `imagekit.widget` | `true` | Enables the dashboard widget. |
|
||||
| `imagekit.widget.step` | `5` | Sets how many pending thumbnails will be generated by the widget in one step. If thumbnail generation exceeds the max execution time on your server, you should set this to a lower value. If your server is blazingly fast, you can safely increase the value. |
|
||||
| `imagekit.widget.discover` | `true` | If enabled, the widget scans your whole site before creating thumbnails. If this feature is not compatible with your setup, disable it. It can also take very long on large site, every single page has to be rendered in order to get all pending thumbnails. In order to do this, the plugin will flush your site cache before running. |
|
||||
|
||||
## 6 Image Optimization
|
||||
|
||||
### 6.1 Setup
|
||||
|
||||
As of *version 1.1*, ImageKit is also capable of optimizing thumbnails. There are different optimizers, providing both lossless and lossy optimization. It works similar to third-party services (e.g. [TinyPNG](https://tinypng.com/), [Kraken.io](https://kraken.io/)), but on your own server. If you want to use this feature, you have to install the corresponding command-line utilities first—if they’re not already installed on your server.
|
||||
|
||||
ℹ️ If your hosting provider doesn’t let you compile software on your webspace (most likely for shared hosting), you can get binaries for most operation systems from a WordPress plugin called [EWWW-Image-Optimizer](https://wordpress.org/plugins/ewww-image-optimizer/). Just download the plugin and upload it’s the pre-compiled utilities to your server (look into the folder `binaries` within the ZIP archive). There are many other places, where you can get pre-compiled versions of the image optimation tools, but please be careful and do not download any of these tools from some strange russian server. The only tool I couldn’t find as a pre-compiled binary for Linux / OS X hosts is `mozjpeg`.
|
||||
|
||||
|
||||
| Option | Default value | Description |
|
||||
|:--------------------|:--------------|:------------|
|
||||
| `imagekit.optimize` | `false` | Set to `true` to enable optimization. In addition, you have to configure at least one of the optimizers listed below. |
|
||||
| `imagekit.driver` | `null` | This option only needs to be set, if your Kirby installation uses a custom ImageMagick driver, that has a different name than `'im'`. If this is the case, set this value to `'im'` to tell ImageKit, that you’re using ImageMagick for thumbnail processing, as there is no other way to detect this reliably. In most cases, you can safely ignore this setting.<br>*This settings does not change the thumbs driver to ImageMagick! If you want to use ImageMagick as your image processing backend, please refer to the corresponding pages in the Kirby documentation or have a look into the troubleshooting section of this document.* |
|
||||
|
||||
By default, all optimizers will be loaded and ImageKit checks if you have set the path to a valid binary (e.g. `imagekit.mozjpeg.bin`). If the binary is set and executable, ImageKit will then activate the optimizer automatically for supported image types. All optimizers come with a sane default configuration, but you can tweak them according to your needs.
|
||||
|
||||
### 6.2 Overriding Global Settings
|
||||
|
||||
If you need different optimization configuration settings for different images, you can override any of the settings (except for the path to an optimizers’s binary) you defined in `config.php` by passing them to the `thumb()` method. The parameter `imagekit.optimize` can also take an array of optimizers. Note, that optimizers will only become active, if the input image is in a format supported by them (e.g. If you provide a JPEG to the example below, `pngquant` will be skipped, because it can only handle PNG images.)
|
||||
|
||||
```php
|
||||
$page->image()->thumb([
|
||||
'width' => 600,
|
||||
'imagekit.optimize' => ['mozjpeg', 'pngquant'],
|
||||
'imagekit.mozjpeg.quality' => 60,
|
||||
]);
|
||||
```
|
||||
|
||||
Overriding global settings might become useful, if you want to apply lossless optimization for some images and lossy optimization for others. A typical use-case would be a photo gallery with lots of small preview images on an index page, where you want to squeeze the last byte out of your thumbnails using `mozjpeg`. For the enlarged view of a photo, image quality might be more important than filesize, so you might prefer `jpegtran` over `mozjpeg` for lossless optimization.
|
||||
|
||||
### 6.3 Available Optimizers
|
||||
|
||||
#### 6.3.1 mozjpeg
|
||||
|
||||
Mozjpeg is an improved JPEG encoder that produces much smaller images at a similar perceived quality as those created by GD Library, ImageMagick, or Photoshop. I really recommend to try out this optimizer, because it can significantly reduce the size of your thumbnails.
|
||||
|
||||
[<img src="https://img.shields.io/badge/%E2%80%BA-Download%20mozjpeg-lightgrey.svg" alt="Download mozjpeg">](https://github.com/mozilla/mozjpeg)
|
||||
|
||||
| Option | Default value | Possible Values | Description |
|
||||
|:--------------------|:--------------|:------------|:------------|
|
||||
| `imagekit.mozjpeg.bin` | `null` | — | Enter the path to mozjpeg’s encoder executable (`cjpeg`) to activate this optimizer.<br>*(tested with mozjpeg 3.1)* |
|
||||
| `imagekit.mozjpeg.quality` | `85` | `0-100` | Sets the quality level of the generated image. Choose from a scale between 0-100, where 100 is the highest quality level. The scale is not identical to that of other JPEG encoders, so you should try different settings and compare the results if you want to get the optimal results for your project.
|
||||
| `imagekit.mozjpeg.flags` | `''` | — | Use this parameter to pass additional options to the optimizer. Have a look at mozjpeg’s documentation for available flags. |
|
||||
|
||||
ℹ️ I recommend that you don’t upscale images that have been compressed by `mozjpeg`, bacause it will add a lot of artifacts to thumbnails. Those are mostly invisible when the image is viewed at full size or downscaled. But they can give your images an unpleasant look, if they’re upscaled.
|
||||
|
||||
#### 6.3.2 jpegtran
|
||||
|
||||
Jpegtran applies lossless compression to your thumbnails by optimizing the JPEG data and stripping out metadata like EXIF. If you use mozjpeg, there is no reason to also use jpegtran, as my tests did not show any benefit in thumbnail size, when both are used together.
|
||||
|
||||
[<img src="https://img.shields.io/badge/%E2%80%BA-Download%20jpegtran-lightgrey.svg" alt="Download jpegtran">](http://jpegclub.org/jpegtran/)
|
||||
|
||||
| Option | Default value | Possible Values | Description |
|
||||
|:--------------------|:--------------|:------------|:------------|
|
||||
| `imagekit.jpegtran.bin` | `null` | — | Enter the path to the optipng executable to activate this optimizer.<br>*(tested with jpegtran 0.7.6)* |
|
||||
| `imagekit.jpegtran.optimize` | `true` | `true`, `false` | Enables lossless optimization of image data. |
|
||||
| `imagekit.jpegtran.copy` | `'none'` | `'all'`, `'comments'`, `'none'` | Sets which metadata should be copied from source file. |
|
||||
| `imagekit.jpegtran.flags` | `''` | — | Use this parameter to pass additional options to the optimizer. Have a look at jpegtran’s documentation for available flags. |
|
||||
|
||||
#### 6.3.3 pngquant
|
||||
|
||||
Pngquant performs lossy optimization on PNG images by converting 24-bit images to indexed color (8-bit), while alpha-transparency is kept. The files can be displayed in all modern browsers and this kind of lossy optimization works great for most non-photographic images and screenshots. You may notice some color shifts on photographic images with a lot of different colors (you usually should not use PNG for displaying photos on the web anyway …).
|
||||
|
||||
[<img src="https://img.shields.io/badge/%E2%80%BA-Download%20pngquant-lightgrey.svg" alt="Download pngquant">](https://pngquant.org/)
|
||||
|
||||
| Option | Default value | Possible Values | Description |
|
||||
|:--------------------|:--------------|:------------|:------------|
|
||||
| `imagekit.pngquant.bin` | `null` | — | Enter the path to the `pngquant` executable to activate this optimizer.<br>*(tested with optipng 2.7.2)* |
|
||||
| `imagekit.pngquant.quality` | `null` | `null`, `'min-max'` (e.g. `'0-100'`) | Sets minimum and maximum quality of the resulting image. Has to be a string. |
|
||||
| `imagekit.pngquant.speed` | `3` | `1` = slow,<br>`3` = default,<br>`11` = fast & rough |Slower speed means a better quality, but optimization takes longer *(for large images from a few megapixels and above, we’re talking about tens of seconds or even minutes, when using a speed setting of `1`)*. |
|
||||
| `imagekit.pngquant.posterize` | `false` | `false`,<br>`0-4` | Output lower-precision color if set to further reduce filesize. |
|
||||
| `imagekit.pngquant.colors` | `false` | `false`, `2`-`256`| Sets the number of colors for optimized images. Less colors mean smaller images, but also reduction of quality. |
|
||||
| `imagekit.pngquant.flags` | `''` | — | Use this parameter to pass additional options to the optimizer. Have a look at pngquant’s documentation for available flags. |
|
||||
|
||||
#### 6.3.4 optipng
|
||||
|
||||
Optipng performs lossless optimizations on PNG images by stripping meta data and optimizing the PNG data itself.
|
||||
|
||||
[<img src="https://img.shields.io/badge/%E2%80%BA-Download%20optipng-lightgrey.svg" alt="Download optipng">](http://optipng.sourceforge.net/)
|
||||
|
||||
| Option | Default value | Possible Values | Description |
|
||||
|:--------------------|:--------------|:------------|:------------|
|
||||
| `imagekit.optipng.bin` | `null` | — | Enter the path to the `optipng` executable to activate this optimizer.<br>*(tested with optipng 0.7.6)* |
|
||||
| `imagekit.optipng.level` | `2` | `0`-`7` | Sets the optimization level. Note, that a high optimization level can make processing of large image files very slow, while having only little impact on filesize. |
|
||||
| `imagekit.optipng.strip` | `'all'` | `'all'`, `false` | Strips all metadata from the PNG file. |
|
||||
| `imagekit.optipng.flags` | `''` | — | Use this parameter to pass additional options to the optimizer. Have a look at optipng’s documentation for available flags. |
|
||||
|
||||
#### 6.3.5 gifsicle
|
||||
|
||||
Gifsicle optimizes the data of GIF images. Especially for animations, using this optimizer can lead to a great improvement in file size, but can also take very long for large animations. Static GIF images will also benefit from using Gifsicle.
|
||||
|
||||
[<img src="https://img.shields.io/badge/%E2%80%BA-Download%20gifsicle-lightgrey.svg" alt="Download gifsicle">](https://www.lcdf.org/gifsicle/)
|
||||
|
||||
| Option | Default value | Possible Values | Description |
|
||||
|:--------------------|:--------------|:------------|:------------|
|
||||
| `imagekit.gifsicle.bin` | `null` | — | Enter the path to the `optipng` executable to activate this optimizer.<br>*(tested with optipng 1.88)* |
|
||||
| `imagekit.gifsicle.level` | `3` | `false`, `1`-`3` | Sets the level of optimization, where `3` is the highest possible value. |
|
||||
| `imagekit.gifsicle.colors` | `false` | `false`, `2`-`256` | Sets the amount of colors in the resulting thumbnail. By default, color palettes are not reduced. |
|
||||
| `imagekit.gifsicle.flags` | `''` | — | Use this parameter to pass additional options to the optimizer. Have a look at gifsicle’s documentation for available flags. |
|
||||
|
||||
## 7 Troubleshooting
|
||||
|
||||
<details>
|
||||
<summary><strong>How can I activate ImageMagick?</strong></summary>
|
||||
As ImageKit acts as a proxy for Kirby’s built-in thumbnail engine, you have to activate it on your `config.php` file, just as you would do without ImageKit like below:
|
||||
|
||||
```
|
||||
c::set('thumbs.driver','gd');
|
||||
c::set('thumbs.bin', '/usr/local/bin/convert');
|
||||
```
|
||||
|
||||
→ Kirby documentation for [`thumbs.driver`](https://getkirby.com/docs/cheatsheet/options/thumbs-driver) and [`thumbs.bin`](https://getkirby.com/docs/cheatsheet/options/thumbs-bin)
|
||||
|
||||
Please note, that Kirby uses the command-line version of ImageMagick, rather than its PHP extension. In order to use ImageMagick as your processing backend, the ImageMagick executable (`convert`) has to be installed on your server.*
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary><strong>Thumbnail creation always fails …</strong></summary>
|
||||
This may happen because of several reasons. First, make sure that your thumbs folder is writable for Kirby. If you’re using the GD Library driver, make sure that PHP’s memory limit is set to a high-enough value. Increasing the memory limit allows GD to process larger source files. Or if you favor ImageMagick (I do), make sure that the path to the `convert` executable is correctly configured.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>The Discovery Feature does not work with my site:</strong></summary>
|
||||
Discovery works by creating a sitemap of your entire site and then sends an HTTP request to every of those URLs to trigger rendering of every single page. When doing so, ImageKit sees everything from a logged-in user’s perspective. It tries it’s best to find pagination on pages, but it cannot create thumbnails whose are – for example – only available on a search results page, where entries are only displayed when a certain keyword was entered into a form. Also make sure, that your Server’s PHP installation comes with `libxml`, which is used by PHP’s DOM interface.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Can I also optimize the images in my content folder?</strong></summary>
|
||||
This is currently not possible, because it would need a whole UI for the admin panel and would also be very risky to apply some bulk processing on your source images without knowing the actual results of optimization. If you need optimized images in your content folder, I really recommend that you use tools like <a href="https://imageoptim.com/mac">ImageOptim</a> and <a href="https://pngmini.com/">ImageAlpha</a> to optimize your images prior to uploading them. This saves space on your server and also speeds up your backups.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>404 Errors with nginx</strong></summary>
|
||||
ImageKit may have problems with certain nginx configurations, resulting 404 errors, when a thumbnail is requested for the first time. See <a href="https://github.com/fabianmichael/kirby-imagekit/issues/9">this issue</a> to learn, how you have to configure nginx to solve this issue.
|
||||
</details>
|
||||
|
||||
## 8 License
|
||||
|
||||
ImageKit can be evaluated as long as you want on how many private servers you want. To deploy ImageKit on any public server, you need to buy a license. See `license.md` for terms and conditions.
|
||||
|
||||
*The plugin is also available as a bundle with [ImageSet](https://github.com/fabianmichael/kirby-imageset), a plugin for bringing responsive images with superpowers to you Kirby-driven site.*
|
||||
|
||||
→ [Buy ImageKit](http://sites.fastspring.com/fabianmichael/product/imagekit)
|
||||
→ [Buy the ImageKit + ImageSet Bundle](http://sites.fastspring.com/fabianmichael/product/imgbundle1)
|
||||
|
||||
However, even with a valid license code, it is discouraged to use it in any project, that promotes racism, sexism, homophobia, animal abuse or any other form of hate-speech.
|
||||
|
||||
## 9 Technical Support
|
||||
|
||||
Technical support is provided via Email and on GitHub. If you’re facing any problems with running or setting up ImageKit, please send your request to [support@fabianmichael.de](mailto:support@fabianmichael.de) or [create a new issue](https://github.com/fabianmichael/kirby-imagekit/issues/new) in this GitHub repository. No representations or guarantees are made regarding the response time in which support questions are answered.
|
||||
|
||||
## 10 Credits
|
||||
|
||||
ImageKit is developed and maintained by [Fabian Michael](https://fabianmichael.de), a graphic designer & web developer from Germany.
|
||||
1
site/OFF_plugins/imagekit/widgets/imagekit/assets/css/widget.min.css
vendored
Normal file
1
site/OFF_plugins/imagekit/widgets/imagekit/assets/css/widget.min.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.imagekit-stats{width:100%}.imagekit-stats th{font-weight:400;text-align:left;white-space:nowrap;overflow:hidden}.imagekit-stats th::after{content:"";display:inline-block;width:100%;height:1px;background:currentColor;position:relative;bottom:.25em;margin-left:.35em;opacity:.2}.imagekit-stats td{padding-left:.35em;width:25%}.imagekit-action--disabled{opacity:.5;color:inherit!important;cursor:default!important}.imagekit-modal{background:rgba(255,255,255,.9);position:absolute;top:0;left:0;width:100%;height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;box-sizing:border-box;padding:1em 4em}.imagekit-modal p{margin-bottom:1em}.imagekit-modal p:last-child{margin-bottom:0}.imagekit-modal-buttons{padding-top:1em}.imagekit-error-icon{display:inline-block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAABACAQAAADl/nw5AAAAuElEQVR4Ae3St7nCUBQE4dMM7bxqpA5wFdCQ+iCjDfzc5PDtc3BNsDuZ3C9MxOWzbUhdUA80+KltScH1QYPLmxUwv4DB/uBEMy2iDeVtqDpoUEJHmihoSYWIDHYAZwLSoIgZ7AiWghQ0PmhQ9SUKyqLBduCefgueyOA44IF2JMHUigpQMtgPJPknCqJXiAUZ7AcqOAOlct5gPzBE8oTB4UD6M1Ay2AHMi1/2y9UHDZKAdL+/1GAl8Aq7a0QNCPzaUwAAAABJRU5ErkJggg==) 0 0/28px 32px no-repeat;width:28px;height:32px;margin-bottom:.75em}@keyframes imagekit-progress-indeterminate{0%{background-position:0 0}to{background-position:-40px 0}}.imagekit-progress{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:12px;background:#efefef;border:2px solid #000;animation:1s imagekit-progress-indeterminate linear infinite;background-size:40px 40px}.imagekit-progress::-webkit-progress-value{background:0 0}.imagekit-progress::-moz-progress-bar{background:0 0}.imagekit-progress[value]::-moz-progress-bar{background:#000}.imagekit-progress[value]::-webkit-progress-value{background:#000}.imagekit-progress:not([value]){background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQAQAAAACmas8AAAAAiUlEQVR4Ae3MN2ECABQAUdLHSIgUpIE0pCCBjd7+Ow1suemmt9B9WqxnV3Yzu7Tb2T+7m/21h9kfe5n9sLfZN3sHt8E22AbbYBtsg22wDW6DbbANtsE22AbbYBvcBttgG2yDbbANtsE2uA22wTbYBttgG2yD7cDDBeOCccG4YFwwLhgHtv/wS+EH/ASOgIJwaM8AAAAASUVORK5CYII=);opacity:.5}.imagekit-progress[value]{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////5eXlCYLQawAAAJZJREFUeNrs1rENwEAMw0By/6UzwtsAixTWANeKOBzjnXjiiSeeeOKJJ5544okn/kw0FjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWMRYxFjEWXw+xFp8nthXfP7sUBymwEye1shJHQbURZ823EIdZOhen5TwWx3E/FT8BBgBWkgyBWPq8ewAAAABJRU5ErkJggg==)}.imagekit-progress.is-hidden,.imagekit-progress.is-hidden+.imagekit-progress-text{visibility:hidden}.imagekit-progress.is-disabled{animation-play-state:paused}.imagekit-progress-text{font-size:14px;font-style:italic}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 241 B |
Binary file not shown.
|
After Width: | Height: | Size: 194 B |
Binary file not shown.
|
After Width: | Height: | Size: 262 B |
1
site/OFF_plugins/imagekit/widgets/imagekit/assets/js/dist/widget.min.js
vendored
Normal file
1
site/OFF_plugins/imagekit/widgets/imagekit/assets/js/dist/widget.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,543 @@
|
|||
(function(window, document, $) {
|
||||
|
||||
/* ===== Utility Functions ================================================ */
|
||||
|
||||
function i18n(key) {
|
||||
var str = window.ImageKitSettings.translations[key];
|
||||
if(str !== undefined) {
|
||||
return str;
|
||||
} else {
|
||||
return '[' + key + ']';
|
||||
}
|
||||
}
|
||||
|
||||
function arrayUnique(array) {
|
||||
var a = array.concat();
|
||||
for(var i=0; i<a.length; ++i) {
|
||||
for(var j=i+1; j<a.length; ++j) {
|
||||
if(a[i] === a[j])
|
||||
a.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* ===== ImageKit API ===================================================== */
|
||||
|
||||
function ImageKitAPI(options) {
|
||||
var self = this,
|
||||
settings = $.extend({
|
||||
error: function(response) {
|
||||
console.error(response.message);
|
||||
},
|
||||
}, options),
|
||||
_running = false,
|
||||
_cancelled = false;
|
||||
|
||||
var ACTION_CREATE = "create",
|
||||
ACTION_CLEAR = "clear",
|
||||
ACTION_INDEX = "index";
|
||||
|
||||
function api(command, callback, data, method) {
|
||||
method = method || 'GET';
|
||||
data = data || {};
|
||||
callback = callback || function(){};
|
||||
|
||||
var url = settings.api + command;
|
||||
|
||||
return $.ajax({
|
||||
url : url,
|
||||
dataType : 'json',
|
||||
method : method,
|
||||
data : data,
|
||||
success : function(response) {
|
||||
callback(response);
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
settings.error(xhr.responseJSON);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function start(action) {
|
||||
_running = action;
|
||||
}
|
||||
|
||||
function stop() {
|
||||
_running = false;
|
||||
}
|
||||
|
||||
function running(running) {
|
||||
if(running === undefined) {
|
||||
return _running;
|
||||
} else {
|
||||
return (_running === running);
|
||||
}
|
||||
}
|
||||
|
||||
function status(callback) {
|
||||
return api("status", callback);
|
||||
}
|
||||
|
||||
function clear(callback) {
|
||||
reset();
|
||||
start(ACTION_CLEAR);
|
||||
return api(ACTION_CLEAR, function(response) {
|
||||
stop(ACTION_CLEAR);
|
||||
callback(response.data);
|
||||
});
|
||||
}
|
||||
|
||||
function create(step, complete) {
|
||||
reset();
|
||||
start(ACTION_CREATE);
|
||||
|
||||
step = step || function(){};
|
||||
complete = complete || function(){};
|
||||
|
||||
function doCreate() {
|
||||
api(ACTION_CREATE, function (response) {
|
||||
if (response.data.pending > 0 && !cancelled()) {
|
||||
step(response.data);
|
||||
doCreate();
|
||||
} else {
|
||||
stop(ACTION_CREATE);
|
||||
complete(response.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
doCreate();
|
||||
}
|
||||
|
||||
function index(step, complete, error) {
|
||||
reset();
|
||||
start(ACTION_INDEX);
|
||||
|
||||
step = step || function(){};
|
||||
complete = complete || function(){};
|
||||
error = error || function(){};
|
||||
|
||||
api(ACTION_INDEX, function (response) {
|
||||
var i = 0;
|
||||
var pageUrls = response.data;
|
||||
|
||||
var triggerPageLoad = function() {
|
||||
$.ajax({
|
||||
url: pageUrls[i],
|
||||
headers: {
|
||||
"X-ImageKit-Indexing": 1,
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.data.links.length > 0) {
|
||||
pageUrls = arrayUnique(pageUrls.concat(response.data.links));
|
||||
}
|
||||
if (++i >= pageUrls.length || cancelled()) {
|
||||
stop(ACTION_INDEX);
|
||||
complete({ total: pageUrls.length, status: response.data.status });
|
||||
} else {
|
||||
step({ current: i, total: pageUrls.length, url: pageUrls[i], status: response.data.status });
|
||||
triggerPageLoad();
|
||||
}
|
||||
},
|
||||
error: function(response) {
|
||||
error(response.responseJSON);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
triggerPageLoad();
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
_cancelled = true;
|
||||
}
|
||||
|
||||
function cancelled() {
|
||||
return _cancelled;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
_running = false;
|
||||
_cancelled = false;
|
||||
}
|
||||
|
||||
return {
|
||||
status : status,
|
||||
clear : clear,
|
||||
create : create,
|
||||
index : index,
|
||||
cancel : cancel,
|
||||
cancelled : cancelled,
|
||||
running : running,
|
||||
reset : reset,
|
||||
};
|
||||
}
|
||||
|
||||
/* ===== Progress Bar ===================================================== */
|
||||
|
||||
function ProgressBar() {
|
||||
|
||||
var progressElm = document.querySelector(".js-imagekit-progress"),
|
||||
progressTextElm = document.querySelector(".js-imagekit-progress-text"),
|
||||
_visible = false,
|
||||
self = this,
|
||||
_public = {};
|
||||
|
||||
function toggle(show) {
|
||||
if (show === _visible) return self;
|
||||
progressElm.classList[show ? "remove" : "add"]("is-hidden");
|
||||
_visible = show;
|
||||
return _public;
|
||||
}
|
||||
|
||||
function disable() {
|
||||
progressElm.classList.add("is-disabled");
|
||||
return _public;
|
||||
}
|
||||
|
||||
function enable() {
|
||||
progressElm.classList.remove("is-disabled");
|
||||
return _public;
|
||||
}
|
||||
|
||||
function show() {
|
||||
return toggle(true);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
return toggle(false);
|
||||
}
|
||||
|
||||
function value(value) {
|
||||
if (value !== null && value !== false) {
|
||||
progressElm.setAttribute("value", value);
|
||||
} else {
|
||||
progressElm.removeAttribute("value");
|
||||
}
|
||||
return _public;
|
||||
}
|
||||
|
||||
function text(msg) {
|
||||
if (msg) {
|
||||
progressTextElm.innerHTML = msg;
|
||||
return _public;
|
||||
} else {
|
||||
return progressTextElm.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
_public = {
|
||||
show : show,
|
||||
hide : hide,
|
||||
value : value,
|
||||
text : text,
|
||||
enable : enable,
|
||||
disable : disable,
|
||||
};
|
||||
|
||||
return _public;
|
||||
}
|
||||
|
||||
|
||||
/* ===== Actions ========================================================== */
|
||||
|
||||
function Actions() {
|
||||
|
||||
var _public = {},
|
||||
actions = {
|
||||
clear: {
|
||||
element: $('[href="#imagekit-action-clear"]'),
|
||||
icon: $('[href="#imagekit-action-clear"] i'),
|
||||
},
|
||||
create: {
|
||||
element: $('[href="#imagekit-action-create"]'),
|
||||
icon: $('[href="#imagekit-action-create"] i'),
|
||||
}
|
||||
};
|
||||
|
||||
function disable(action) {
|
||||
if(action) {
|
||||
actions[action].element.addClass("imagekit-action--disabled");
|
||||
} else {
|
||||
$.each(actions, function() { this.element.addClass("imagekit-action--disabled"); });
|
||||
}
|
||||
return _public;
|
||||
}
|
||||
|
||||
function enable(action) {
|
||||
if(action) {
|
||||
actions[action].element.removeClass("imagekit-action--disabled");
|
||||
} else {
|
||||
$.each(actions, function() { this.element.removeClass("imagekit-action--disabled"); });
|
||||
}
|
||||
return _public;
|
||||
}
|
||||
|
||||
function icon(action, oldClass, newClass) {
|
||||
|
||||
var elm = actions[action].icon;
|
||||
|
||||
elm.removeClass(oldClass);
|
||||
elm.addClass(newClass);
|
||||
|
||||
return _public;
|
||||
}
|
||||
|
||||
function register(action, callback) {
|
||||
actions[action].element.click(function(e) {
|
||||
e.preventDefault();
|
||||
callback();
|
||||
});
|
||||
return _public;
|
||||
}
|
||||
|
||||
_public = {
|
||||
disable : disable,
|
||||
enable : enable,
|
||||
icon : icon,
|
||||
register : register,
|
||||
};
|
||||
|
||||
return _public;
|
||||
}
|
||||
|
||||
|
||||
/* ===== ImageKit Widget ================================================== */
|
||||
|
||||
function Widget(options) {
|
||||
var settings = options,
|
||||
api = new ImageKitAPI($.extend(ImageKitSettings, {
|
||||
error: function(response) {
|
||||
error(response.message);
|
||||
}
|
||||
})),
|
||||
actions = new Actions(),
|
||||
|
||||
infoElm = document.querySelector(".js-imagekit-info"),
|
||||
|
||||
|
||||
createdElm = document.querySelector(".js-imagekit-created"),
|
||||
pendingElm = document.querySelector(".js-imagekit-pending"),
|
||||
|
||||
progress = new ProgressBar();
|
||||
|
||||
/* ----- Internal Interface Methods --------------------------------------- */
|
||||
|
||||
function updateStatus(status) {
|
||||
createdElm.innerHTML = status.created;
|
||||
pendingElm.innerHTML = status.pending;
|
||||
}
|
||||
|
||||
function error(message, onClose) {
|
||||
onClose = onClose || false;
|
||||
actions.disable();
|
||||
progress.disable();
|
||||
|
||||
var $overlay = $("<div/>").addClass("imagekit-modal");
|
||||
$overlay.append('<i class="imagekit-error-icon">'); // fa fa-exclamation-triangle fa-2x
|
||||
$overlay.append($('<p/>').html(message));
|
||||
$("#imagekit-widget").append($overlay);
|
||||
|
||||
if(onClose) {
|
||||
$overlay.append($('<a href="#" class="btn btn-rounded">OK</a>').click(function() {
|
||||
$overlay.remove();
|
||||
api.reset();
|
||||
progress.hide();
|
||||
actions.enable().icon("create", "fa-stop-circle-o", "fa-play-circle-o");
|
||||
status();
|
||||
onClose();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function confirm(message, onClose) {
|
||||
var $overlay = $("<div/>").addClass("imagekit-modal"),
|
||||
esc,
|
||||
close;
|
||||
|
||||
$overlay.append($('<p/>').html(message));
|
||||
$("#imagekit-widget").append($overlay);
|
||||
|
||||
esc = function(e) {
|
||||
if("key" in e ? (e.key == "Escape" || e.key == "Esc") : (e.keyCode == 27)) {
|
||||
close(false);
|
||||
} else if ("key" in e ? e.key == "Enter" : e.key == 13) {
|
||||
close(true);
|
||||
}
|
||||
};
|
||||
|
||||
close = function(result) {
|
||||
$overlay.remove();
|
||||
onClose(result);
|
||||
document.removeEventListener("keydown", esc);
|
||||
};
|
||||
|
||||
var $buttons = $('<p class="imagekit-modal-buttons"/>');
|
||||
$buttons.append($('<a href="#" class="btn btn-rounded">' + i18n('cancel') + '</a>').click(function() { close(false); } ));
|
||||
$buttons.append(" ");
|
||||
$buttons.append($('<a href="#" class="btn btn-rounded">' + i18n('ok') + '</a>').click(function() { close(true); } ));
|
||||
$overlay.append($buttons);
|
||||
|
||||
document.addEventListener("keydown", esc);
|
||||
}
|
||||
|
||||
/* ----- Widget Actions --------------------------------------------------- */
|
||||
|
||||
function status() {
|
||||
if(api.running()) return;
|
||||
|
||||
api.status(function(result) {
|
||||
updateStatus(result.data);
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
if(api.running()) return;
|
||||
|
||||
|
||||
confirm(i18n('imagekit.widget.clear.confirm'), function(confirmed) {
|
||||
if(confirmed) {
|
||||
actions.disable();
|
||||
|
||||
progress
|
||||
.value(false)
|
||||
.text(i18n("imagekit.widget.progress.clearing"))
|
||||
.show();
|
||||
|
||||
api.clear(function(status) {
|
||||
progress.hide();
|
||||
actions.enable();
|
||||
updateStatus(status);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// if(window.confirm(i18n('imagekit.widget.clear.confirm'))) {
|
||||
// actions.disable();
|
||||
|
||||
// progress
|
||||
// .value(false)
|
||||
// .text(i18n("imagekit.widget.progress.clearing"))
|
||||
// .show();
|
||||
|
||||
// api.clear(function(status) {
|
||||
// progress.hide();
|
||||
// actions.enable();
|
||||
// updateStatus(status);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
function index(callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
progress.text(i18n("imagekit.widget.progress.scanning"));
|
||||
|
||||
api.index(function (result) {
|
||||
// step
|
||||
progress
|
||||
.value(result.current / result.total)
|
||||
.text(i18n("imagekit.widget.progress.scanning") + " " + result.current + "/" + result.total);
|
||||
|
||||
updateStatus(result.status);
|
||||
|
||||
}, function (result) {
|
||||
// complete
|
||||
progress
|
||||
.value(1)
|
||||
.text(i18n("imagekit.widget.progress.scanned"));
|
||||
|
||||
updateStatus(result.status);
|
||||
callback();
|
||||
}, function (result) {
|
||||
// error
|
||||
error(result.message, function() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function create(callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
progress
|
||||
.value(false)
|
||||
.text(i18n('imagekit.widget.progress.creating'));
|
||||
|
||||
api.create(function (result) {
|
||||
// step
|
||||
var total = result.pending + result.created;
|
||||
progress.value(result.created / total);
|
||||
updateStatus(result);
|
||||
}, function (result) {
|
||||
// complete
|
||||
progress.value(1);
|
||||
updateStatus(result);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function run() {
|
||||
|
||||
actions
|
||||
.disable("clear")
|
||||
.icon("create", "fa-play-circle-o", "fa-stop-circle-o");
|
||||
|
||||
progress
|
||||
.value(false)
|
||||
.show();
|
||||
|
||||
function complete() {
|
||||
progress.hide();
|
||||
|
||||
actions
|
||||
.enable()
|
||||
.icon("create", "fa-stop-circle-o", "fa-play-circle-o");
|
||||
}
|
||||
|
||||
if (ImageKitSettings.discover) {
|
||||
index(function() {
|
||||
if(!api.cancelled()) {
|
||||
create(complete);
|
||||
} else {
|
||||
complete();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
create(complete);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (api.running("index") || api.running("create")) {
|
||||
actions.disable();
|
||||
progress
|
||||
.value(false)
|
||||
.text(i18n('imagekit.widget.progress.cancelling'));
|
||||
api.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
actions.register("clear", clear);
|
||||
actions.register("create", function() {
|
||||
if (!api.running()) {
|
||||
run();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
status : status,
|
||||
};
|
||||
}
|
||||
|
||||
$(function() {
|
||||
var widget = new Widget();
|
||||
widget.status();
|
||||
});
|
||||
|
||||
|
||||
})(window, document, jQuery);
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
.imagekit-stats {
|
||||
width: 100%;
|
||||
|
||||
th {
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: currentColor;
|
||||
position: relative;
|
||||
bottom: .25em;
|
||||
margin-left: .35em;
|
||||
opacity: .2;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding-left: .35em;
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.imagekit-action--disabled {
|
||||
opacity: .5;
|
||||
color: inherit !important;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.imagekit-modal {
|
||||
background: rgba(#fff, .9);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
padding: 1em 4em;
|
||||
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imagekit-modal-buttons {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.imagekit-error-icon {
|
||||
display: inline-block;
|
||||
background: inline('../images/icon-error@2x.png') 0 0 / 28px 32px no-repeat;
|
||||
width: 28px;
|
||||
height: 32px;
|
||||
margin-bottom: .75em;
|
||||
}
|
||||
|
||||
@keyframes imagekit-progress-indeterminate {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: -40px 0; }
|
||||
}
|
||||
|
||||
.imagekit-progress {
|
||||
/* Reset the default appearance */
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
background: #efefef;
|
||||
border: 2px solid #000;
|
||||
|
||||
animation: 1s imagekit-progress-indeterminate linear infinite;
|
||||
background-size: 40px 40px;
|
||||
|
||||
&::-webkit-progress-value {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-moz-progress-bar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&[value]::-moz-progress-bar {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
&[value]::-webkit-progress-value {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
&:not([value]) {
|
||||
background-image: inline('../images/progress-indeterminate@2x.png');
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
&[value] {
|
||||
background-image: inline('../images/progress-running@2x.png')
|
||||
}
|
||||
|
||||
&.is-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
}
|
||||
|
||||
.imagekit-progress-text {
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
|
||||
.imagekit-progress.is-hidden + & {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
16
site/OFF_plugins/imagekit/widgets/imagekit/bootstrap.php
Normal file
16
site/OFF_plugins/imagekit/widgets/imagekit/bootstrap.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
|
||||
load([
|
||||
'kirby\\plugins\\imagekit\\widget\\widget' => 'lib' . DS . 'widget.php',
|
||||
'kirby\\plugins\\imagekit\\widget\\translations' => 'lib' . DS . 'translations.php',
|
||||
'kirby\\plugins\\imagekit\\widget\\api' => 'lib' . DS . 'api.php',
|
||||
'kirby\\plugins\\imagekit\\widget\\apicrawlerresponse' => 'lib' . DS . 'apicrawlerresponse.php',
|
||||
], __DIR__);
|
||||
|
||||
|
||||
// Initialize Widget and API
|
||||
Widget::instance();
|
||||
API::instance();
|
||||
48
site/OFF_plugins/imagekit/widgets/imagekit/imagekit.html.php
Normal file
48
site/OFF_plugins/imagekit/widgets/imagekit/imagekit.html.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<style><?= f::read(__DIR__ . '/assets/css/widget.min.css') ?></style>
|
||||
|
||||
<div class="dashboard-box">
|
||||
<div class="js-imagekit-info / text">
|
||||
<table class="imagekit-stats">
|
||||
<tr>
|
||||
<th><?= $translations->get('imagekit.widget.status.pending') ?></th>
|
||||
<td class="js-imagekit-pending">…</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= $translations->get('imagekit.widget.status.created') ?></th>
|
||||
<td class="js-imagekit-created">…</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<progress class="imagekit-progress is-hidden / js-imagekit-progress"></progress>
|
||||
<p class="marginalia imagekit-progress-text / js-imagekit-progress-text">…</span>
|
||||
|
||||
</p>
|
||||
|
||||
<?php if (imagekit()->license()->type === 'trial'): ?>
|
||||
<p class="debug-warning marginalia" style="position: relative; padding-left: 30px; font-size: 14px; padding-top: 12px;">
|
||||
<span class="fa fa-exclamation-triangle" style="position: absolute; top: 15px; left: 5px; font-size: 14px;"></span>
|
||||
<?php printf($translations->get('imagekit.widget.license.trial'), 'http://sites.fastspring.com/fabianmichael/product/imagekit') ?>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
|
||||
<script>
|
||||
<?php
|
||||
echo 'window.ImageKitSettings = ' . json_encode([
|
||||
'api' => kirby()->urls()->index() . '/plugins/imagekit/widget/api/',
|
||||
'translations' => array_merge(
|
||||
$translations->get(), [
|
||||
'cancel' => i18n('cancel'),
|
||||
'ok' => i18n('ok'),
|
||||
]),
|
||||
'discover' => kirby()->option('imagekit.widget.discover'),
|
||||
]) . ';';
|
||||
|
||||
if(kirby()->option('imagekit.debug')) {
|
||||
echo f::read(__DIR__ . '/assets/js/src/widget.js');
|
||||
} else {
|
||||
echo f::read(__DIR__ . '/assets/js/dist/widget.min.js');
|
||||
}
|
||||
?>
|
||||
</script>
|
||||
32
site/OFF_plugins/imagekit/widgets/imagekit/imagekit.php
Normal file
32
site/OFF_plugins/imagekit/widgets/imagekit/imagekit.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
use Tpl;
|
||||
|
||||
$translations = Translations::load();
|
||||
|
||||
return [
|
||||
|
||||
'title' => [
|
||||
'text' => $translations->get('imagekit.widget.title'),
|
||||
],
|
||||
|
||||
'options' => [
|
||||
[
|
||||
'text' => $translations->get('imagekit.widget.action.clear'),
|
||||
'icon' => 'trash-o',
|
||||
'link' => '#imagekit-action-clear',
|
||||
],
|
||||
[
|
||||
'text' => $translations->get('imagekit.widget.action.create'),
|
||||
'icon' => 'play-circle-o',
|
||||
'link' => '#imagekit-action-create',
|
||||
],
|
||||
],
|
||||
|
||||
'html' => function() use ($translations) {
|
||||
return tpl::load(__DIR__ . DS . 'imagekit.html.php', compact('translations'));
|
||||
}
|
||||
|
||||
];
|
||||
122
site/OFF_plugins/imagekit/widgets/imagekit/lib/api.php
Normal file
122
site/OFF_plugins/imagekit/widgets/imagekit/lib/api.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
use Response;
|
||||
use Exception;
|
||||
|
||||
use Kirby\Plugins\ImageKit\LazyThumb;
|
||||
use Kirby\Plugins\ImageKit\ComplainingThumb;
|
||||
|
||||
use Whoops\Handler\Handler;
|
||||
use Whoops\Handler\CallbackHandler;
|
||||
|
||||
|
||||
class API {
|
||||
|
||||
public $kirby;
|
||||
|
||||
public static function instance() {
|
||||
static $instance;
|
||||
return $instance ?: $instance = new static();
|
||||
}
|
||||
|
||||
protected function __construct() {
|
||||
$self = $this;
|
||||
|
||||
$this->kirby = kirby();
|
||||
|
||||
$this->kirby->set('route', [
|
||||
'pattern' => 'plugins/imagekit/widget/api/(:any)',
|
||||
'action' => function($action) use ($self) {
|
||||
if($error = $this->authorize()) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
if(method_exists($self, $action)) {
|
||||
return $this->$action();
|
||||
} else {
|
||||
throw new Exception('Invalid plugin action. The action "' . html($action) . '" is not defined.');
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
if(isset($_SERVER['HTTP_X_IMAGEKIT_INDEXING'])) {
|
||||
// Handle indexing request (discovery feature).
|
||||
$this->handleCrawlerRequest();
|
||||
}
|
||||
}
|
||||
|
||||
protected function authorize() {
|
||||
$user = kirby()->site()->user();
|
||||
if (!$user || !$user->hasPanelAccess()) {
|
||||
throw new Exception('Only logged-in users can use the ImageKit widget. Please reload this page to go to the login form.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleCrawlerRequest() {
|
||||
|
||||
if($error = $this->authorize()) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
if($this->kirby->option('representations.accept')) {
|
||||
throw new Exception('ImageKit’s discover mode does currently not work, when the <code>representations.accept</code> setting is turned on. Please disable either this setting or disable <code>imagekit.widget.discover</code>.');
|
||||
}
|
||||
|
||||
kirby()->set('component', 'response', '\\kirby\\plugins\\imagekit\\widget\\apicrawlerresponse');
|
||||
}
|
||||
|
||||
public function status() {
|
||||
return Response::success(true, lazythumb::status());
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
return Response::success(lazythumb::clear(), lazythumb::status());
|
||||
}
|
||||
|
||||
public function create() {
|
||||
|
||||
$pending = lazythumb::pending();
|
||||
$step = kirby()->option('imagekit.widget.step');
|
||||
|
||||
// Always complain when trying to create thumbs from the widget
|
||||
complainingthumb::enableSendError();
|
||||
complainingthumb::setErrorFormat('json');
|
||||
|
||||
for($i = 0; $i < sizeof($pending) && $i < $step; $i++) {
|
||||
lazythumb::process($pending[$i]);
|
||||
}
|
||||
|
||||
return Response::success(true, lazythumb::status());
|
||||
}
|
||||
|
||||
public function index() {
|
||||
|
||||
$index = [];
|
||||
|
||||
$this->kirby->cache()->flush();
|
||||
|
||||
$site = site();
|
||||
$isMultilang = $site->multilang() && $site->languages()->count() > 1;
|
||||
|
||||
if($isMultilang) {
|
||||
$languageCodes = [];
|
||||
foreach($site->languages() as $language) {
|
||||
$languageCodes[] = $language->code();
|
||||
}
|
||||
}
|
||||
|
||||
foreach($site->index() as $page) {
|
||||
if($isMultilang) {
|
||||
foreach($languageCodes as $code) {
|
||||
$index[] = $page->url($code);
|
||||
}
|
||||
} else {
|
||||
$index[] = $page->url();
|
||||
}
|
||||
}
|
||||
|
||||
return Response::success(true, $index);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
use Exception;
|
||||
use DOMDocument;
|
||||
use Kirby;
|
||||
use Response;
|
||||
use Kirby\Plugins\ImageKit\LazyThumb;
|
||||
use Url;
|
||||
use V;
|
||||
|
||||
class APICrawlerResponse extends \Kirby\Component\Response {
|
||||
|
||||
public function __construct(Kirby $kirby) {
|
||||
parent::__construct($kirby);
|
||||
|
||||
// Register listeners for redirects
|
||||
header_register_callback([$this,'detectRedirectRequest']);
|
||||
register_shutdown_function([$this,'detectRedirectRequest']);
|
||||
}
|
||||
|
||||
public function detectRedirectRequest() {
|
||||
// Redirects should be ignored by the widget, so
|
||||
// override a redirect and just return a valid json
|
||||
// response.
|
||||
$redirect = in_array(http_response_code(), [301, 302, 303, 304, 307]);
|
||||
$sent = headers_sent();
|
||||
|
||||
if($redirect && !$sent) {
|
||||
header_remove('location');
|
||||
echo Response::success(true, [
|
||||
'links' => [],
|
||||
'status' => LazyThumb::status(),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function make($response) {
|
||||
|
||||
// Try to generate response by calling Kirby’s native
|
||||
// respionse component.
|
||||
$html = parent::make($response);
|
||||
|
||||
if(!class_exists('\DOMDocument')) {
|
||||
throw new Exception('The discovery feature of ImageKit needs PHP with the <strong>libxml</strong> extension to run.');
|
||||
}
|
||||
|
||||
$links = [];
|
||||
|
||||
try {
|
||||
$doc = new DOMDocument();
|
||||
libxml_use_internal_errors(true);
|
||||
$doc->loadHTML($html);
|
||||
libxml_clear_errors();
|
||||
|
||||
$elements = array_merge(
|
||||
iterator_to_array($doc->getElementsByTagName('a')),
|
||||
iterator_to_array($doc->getElementsByTagName('link'))
|
||||
);
|
||||
|
||||
foreach($elements as $elm) {
|
||||
$rel = $elm->getAttribute('rel');
|
||||
if($rel === 'next' || $rel === 'prev') {
|
||||
$href = $elm->getAttribute('href');
|
||||
if(v::url($href) && url::host($href) === url::host()) {
|
||||
// Only add, if href is either a URL on the same
|
||||
// domain as the API call was made to, as links
|
||||
// could possibly link to sth. like `#page2` or
|
||||
// `javascript:;` on AJAX-powered websites.
|
||||
$links[] = $href;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch(Exception $e) {
|
||||
return Response::error($e->getMessage(), 500);
|
||||
}
|
||||
|
||||
return Response::success(true, [
|
||||
'links' => array_unique($links),
|
||||
'status' => LazyThumb::status(),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
/**
|
||||
* A very simple translations class, which can load an
|
||||
* associative PHP array of language strings.
|
||||
*/
|
||||
class Translations {
|
||||
|
||||
protected static $cache;
|
||||
|
||||
protected $translations = [];
|
||||
|
||||
public function __construct($code = 'en') {
|
||||
$language_directory = dirname(__DIR__) . DS . 'translations';
|
||||
|
||||
if ($code !== 'en') {
|
||||
if (!preg_match('/^[a-z]{2}([_-][a-z0-9]{2,})?$/i', $code) ||
|
||||
!file_exists($language_directory . DS . $code . '.php')) {
|
||||
// Set to fallback language, if not a valid code or no translation available.
|
||||
$code = 'en';
|
||||
}
|
||||
}
|
||||
|
||||
$this->translations = require($language_directory . DS . $code . '.php');
|
||||
}
|
||||
|
||||
public function get($key = null) {
|
||||
if(is_null($key)) {
|
||||
return $this->translations;
|
||||
} else if (isset($this->translations[$key])) {
|
||||
return $this->translations[$key];
|
||||
} else {
|
||||
return '[missing translation: ' . $key . ']';
|
||||
}
|
||||
}
|
||||
|
||||
public static function load($code = null) {
|
||||
|
||||
if(is_null($code)) {
|
||||
$code = panel()->translation()->code();
|
||||
}
|
||||
|
||||
if (!isset(static::$cache[$code])) {
|
||||
static::$cache[$code] = new static($code);
|
||||
}
|
||||
|
||||
return static::$cache[$code];
|
||||
}
|
||||
|
||||
}
|
||||
20
site/OFF_plugins/imagekit/widgets/imagekit/lib/widget.php
Normal file
20
site/OFF_plugins/imagekit/widgets/imagekit/lib/widget.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugins\ImageKit\Widget;
|
||||
|
||||
class Widget {
|
||||
|
||||
public static function instance() {
|
||||
static $instance;
|
||||
return $instance ?: $instance = new static();
|
||||
}
|
||||
|
||||
protected function __construct() {
|
||||
|
||||
$kirby = kirby();
|
||||
|
||||
// Register the Widget
|
||||
$kirby->set('widget', 'imagekit', dirname(__DIR__));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'imagekit.widget.title' => 'Thumbnails',
|
||||
'imagekit.widget.action.create' => 'Erstellen',
|
||||
'imagekit.widget.action.clear' => 'Löschen',
|
||||
'imagekit.widget.clear.confirm' => 'Sollen wirklich alle Thumbnails glöscht werden? Dies löscht alle Dateien im Ordner ‘thumbs’.',
|
||||
|
||||
'imagekit.widget.status.pending' => 'In Warteschlange',
|
||||
'imagekit.widget.status.created' => 'Erstellt',
|
||||
|
||||
'imagekit.widget.progress.clearing' => 'Lösche thumbnails …',
|
||||
'imagekit.widget.progress.scanning' => 'Durchsuche alle Seiten …',
|
||||
'imagekit.widget.progress.scanned' => 'Suche abgeschlossen',
|
||||
|
||||
'imagekit.widget.progress.creating' => 'Erstelle thumbnails …',
|
||||
'imagekit.widget.progress.cancelling' => 'Vorgang wird abgebrochen …',
|
||||
|
||||
'imagekit.widget.license.trial' => 'ImageKit läuft im Testmodus. Bitte unterstützen Sie die Entwicklung des plugins und <a href="%s" target="_blank">kaufen Sie eine Lizenz</a>. Wenn Sie bereits einen Lizenzschlüssel haben, tragen Sie ihn bitte in die Datei <code title="site/config/config.php" style="border-bottom: 1px dotted; font-family: monospace;">config.php</code> ein.',
|
||||
];
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'imagekit.widget.title' => 'Thumbnails',
|
||||
'imagekit.widget.action.create' => 'Create',
|
||||
'imagekit.widget.action.clear' => 'Clear',
|
||||
'imagekit.widget.clear.confirm' => 'Do you really want to clear your thumbnails? This will delete all files in your thumbs folder.',
|
||||
|
||||
'imagekit.widget.status.pending' => 'Pending',
|
||||
'imagekit.widget.status.created' => 'Created',
|
||||
|
||||
'imagekit.widget.progress.clearing' => 'Clearing thumbs folder …',
|
||||
'imagekit.widget.progress.scanning' => 'Scanning pages …',
|
||||
'imagekit.widget.progress.scanned' => 'Scan complete',
|
||||
|
||||
'imagekit.widget.progress.creating' => 'Creating thumbnails …',
|
||||
'imagekit.widget.progress.cancelling' => 'Cancelling …',
|
||||
|
||||
'imagekit.widget.license.trial' => 'ImageKit is running in trial mode. Please support the development of this plugin and <a href="%s" target="_blank">buy a license</a>. If you already have a license key, please add it to your <code title="site/config/config.php" style="border-bottom: 1px dotted; font-family: monospace;">config.php</code> file.',
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue