full rewrite for namespace
16
_define.php
|
@ -10,6 +10,10 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!class_exists('dcCore') || is_null(dcCore::app()->auth)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->registerModule(
|
||||
'Noodles',
|
||||
'Add users gravatars everywhere',
|
||||
|
@ -18,13 +22,13 @@ $this->registerModule(
|
|||
[
|
||||
'requires' => [['core', '2.24']],
|
||||
'permissions' => dcCore::app()->auth->makePermissions([
|
||||
dcAuth::PERMISSION_CONTENT_ADMIN,
|
||||
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
|
||||
]),
|
||||
'type' => 'plugin',
|
||||
'support' => 'https://github.com/JcDenis/noodles',
|
||||
'details' => 'http://plugins.dotaddict.org/dc2/details/noodles',
|
||||
'repository' => 'https://raw.githubusercontent.com/JcDenis/noodles/master/dcstore.xml',
|
||||
'settings' => [
|
||||
'type' => 'plugin',
|
||||
'support' => 'https://github.com/JcDenis/' . basename(__DIR__),
|
||||
'details' => 'http://plugins.dotaddict.org/dc2/details/' . basename(__DIR__),
|
||||
'repository' => 'https://raw.githubusercontent.com/JcDenis/' . basename(__DIR__) . '/master/dcstore.xml',
|
||||
'settings' => [
|
||||
'self' => '',
|
||||
],
|
||||
]
|
||||
|
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.2 KiB |
|
@ -1,105 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
require __DIR__ . '/class.noodles.php';
|
||||
|
||||
global $__default_noodles;
|
||||
$__default_noodles = new noodles();
|
||||
|
||||
# Posts (by public behavior)
|
||||
$__default_noodles
|
||||
->add('posts', __('Entries'), '', ['othersNoodles', 'publicPosts'])
|
||||
->size(48)
|
||||
->css('float:right;margin:4px;');
|
||||
|
||||
# Comments (by public behavior)
|
||||
$__default_noodles
|
||||
->add('comments', __('Comments'), '', ['othersNoodles', 'publicComments'])
|
||||
->active(true)
|
||||
->size(48)
|
||||
->css('float:left;margin:4px;');
|
||||
|
||||
# Block with post title link (like homepage posts)
|
||||
$__default_noodles
|
||||
->add('titlesposts', __('Entries titles'), ['genericNoodles', 'postURL'])
|
||||
->target('.post-title a')
|
||||
->css('margin-right:2px;');
|
||||
|
||||
if (dcCore::app()->plugins->moduleExists('widgets')) {
|
||||
# Widget Selected entries
|
||||
$__default_noodles
|
||||
->add('bestof', __('Selected entries'), ['genericNoodles', 'postURL'])
|
||||
->target('.selected li a')
|
||||
->css('margin-right:2px;');
|
||||
|
||||
# Widget Last entries
|
||||
$__default_noodles
|
||||
->add('lastposts', __('Last entries'), ['genericNoodles', 'postURL'])
|
||||
->target('.lastposts li a')
|
||||
->css('margin-right:2px;');
|
||||
|
||||
# Widget Last comments
|
||||
$__default_noodles
|
||||
->add('lastcomments', __('Last comments'), ['widgetsNoodles', 'lastcomments'])
|
||||
->active(true)
|
||||
->target('.lastcomments li a')
|
||||
->css('margin-right:2px;');
|
||||
}
|
||||
|
||||
# Plugin auhtorMode
|
||||
if (dcCore::app()->plugins->moduleExists('authorMode')
|
||||
&& dcCore::app()->blog->settings->authormode->authormode_active
|
||||
) {
|
||||
$__default_noodles
|
||||
->add('authorswidget', __('Authors widget'), ['authormodeNoodles', 'authors'])
|
||||
->target('#authors ul li a')
|
||||
->css('margin-right:2px;');
|
||||
|
||||
$__default_noodles
|
||||
->add('author', __('Author'), '', ['authormodeNoodles', 'author'])
|
||||
->active(true)
|
||||
->size(48)
|
||||
->target('.dc-author #content-info h2')
|
||||
->css('clear:left; float:left;margin-right:2px;');
|
||||
|
||||
$__default_noodles
|
||||
->add('authors', __('Authors'), ['authormodeNoodles', 'authors'])
|
||||
->active(true)
|
||||
->size(32)
|
||||
->target('.dc-authors .author-info h2 a')
|
||||
->css('clear:left; float:left; margin:4px;');
|
||||
}
|
||||
|
||||
# Plugin rateIt
|
||||
if (dcCore::app()->plugins->moduleExists('rateIt')
|
||||
&& dcCore::app()->blog->settings->rateit->rateit_active
|
||||
) {
|
||||
$__default_noodles
|
||||
->add('rateitpostsrank', __('Top rated entries'), ['genericNoodles', 'postURL'])
|
||||
->target('.rateitpostsrank.rateittypepost ul li a') // Only "post" type
|
||||
->css('margin-right:2px;');
|
||||
}
|
||||
|
||||
# Plugin lastpostsExtend
|
||||
if (dcCore::app()->plugins->moduleExists('lastpostsExtend')) {
|
||||
$__default_noodles
|
||||
->add('lastpostsextend', __('Last entries (extend)'), ['genericNoodles', 'postURL'])
|
||||
->target('.lastpostsextend ul li a')
|
||||
->css('margin-right:2px;');
|
||||
}
|
||||
|
||||
# --BEHAVIOR-- initDefaultNoodles
|
||||
dcCore::app()->callBehavior('initDefaultNoodles', $__default_noodles);
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* @package Dotclear
|
||||
*
|
||||
* @copyright Olivier Meunier & Association Dotclear
|
||||
* @copyright GPL-2.0-only
|
||||
*/
|
||||
#
|
||||
# DOT NOT MODIFY THIS FILE !
|
||||
#
|
||||
|
||||
use Dotclear\Helper\L10n;
|
||||
|
||||
L10n::$locales['Entries titles'] = 'Titres des billets';
|
||||
L10n::$locales['Authors widget'] = 'Widgets des auteurs';
|
||||
L10n::$locales['Begin'] = 'Début';
|
||||
L10n::$locales['End'] = 'Fin';
|
||||
L10n::$locales['Before'] = 'Avant';
|
||||
L10n::$locales['After'] = 'Après';
|
||||
L10n::$locales['Maximum file size exceeded'] = 'Taille maximum de fichier dépassée';
|
||||
L10n::$locales['Something went wrong while download file'] = 'Une erreur est survenue lors du téléchargement de l\'image';
|
||||
L10n::$locales['Image must be in png format'] = 'L\'image doit être au format png';
|
||||
L10n::$locales['Failed to save image'] = 'Impossible de sauvegarder l\'image';
|
||||
L10n::$locales['Something went wrong while search file'] = 'Une erreur est survenue pendant la recherche de fichier';
|
||||
L10n::$locales['Enable plugin noodles on this blog'] = 'Activer le plugin Noodles sur ce blog';
|
||||
L10n::$locales['Select default avatar to display on unknown users.'] = 'Selectionner l\'avatar par défaut à afficher pour les utilisateurs inconnus.';
|
||||
L10n::$locales['Blog default image'] = 'Image du blog';
|
||||
L10n::$locales['Upload a new avatar'] = 'Téléverser un nouvel avatar';
|
||||
L10n::$locales['Image must be in "png" format and have a maximum file size of 30Ko'] = 'L\'image doit être au format "png" et avoir une taille maximum de 30Ko';
|
||||
L10n::$locales['API default image'] = 'Image par défaut de l\'API';
|
||||
L10n::$locales['Public directory is not writable, you can not use custom gravatar.'] = 'Le répertoire public n\'est pas accissble en écriture, vous ne pouvez pas utiliser les avatars customisés';
|
||||
L10n::$locales['Search area'] = 'Zone de recherche';
|
||||
L10n::$locales['Size'] = 'Taille';
|
||||
L10n::$locales['Rating'] = 'Évaluation';
|
||||
L10n::$locales['Target'] = 'Cible';
|
||||
L10n::$locales['Place'] = 'Emplacement';
|
||||
L10n::$locales['Adjust avatar CSS'] = 'Ajuster la CSS de l\'image';
|
||||
L10n::$locales['Target and Place are for javascript.'] = 'Les cible et emplacement sont utilisés par les scripts javascript.';
|
||||
L10n::$locales['Add users gravatars everywhere'] = 'Ajouter les avatars partout';
|
|
@ -10,14 +10,52 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_CONTEXT_ADMIN')) {
|
||||
return;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
|
||||
__('Noodles'),
|
||||
dcCore::app()->adminurl->get('admin.plugin.noodles'),
|
||||
dcPage::getPF('noodles/icon.png'),
|
||||
preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.noodles')) . '(&.*)?$/', $_SERVER['REQUEST_URI']),
|
||||
dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id)
|
||||
);
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcAdmin;
|
||||
use dcCore;
|
||||
use dcMenu;
|
||||
use dcNsProcess;
|
||||
use dcPage;
|
||||
|
||||
class Backend extends dcNsProcess
|
||||
{
|
||||
public static function init(): bool
|
||||
{
|
||||
static::$init = defined('DC_CONTEXT_ADMIN')
|
||||
&& My::phpCompliant()
|
||||
&& !is_null(dcCore::app()->auth) && !is_null(dcCore::app()->blog)
|
||||
&& dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
||||
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
|
||||
]), dcCore::app()->blog->id);
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null(dcCore::app()->auth)
|
||||
|| is_null(dcCore::app()->blog)
|
||||
|| is_null(dcCore::app()->adminurl)
|
||||
|| !(dcCore::app()->menu[dcAdmin::MENU_PLUGINS] instanceof dcMenu)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
|
||||
My::name(),
|
||||
dcCore::app()->adminurl->get('admin.plugin.' . My::id()),
|
||||
dcPage::getPF(My::id() . '/icon.png'),
|
||||
preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . My::id())) . '(&.*)?$/', $_SERVER['REQUEST_URI']),
|
||||
dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_CONTENT_ADMIN]), dcCore::app()->blog->id)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
class Combo
|
||||
{
|
||||
/**
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function api(): array
|
||||
{
|
||||
return [
|
||||
'gravatar' => 'http://www.gravatar.com/',
|
||||
'libravatar' => 'http://cdn.libravatar.org/',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,int>
|
||||
*/
|
||||
public static function local(): array
|
||||
{
|
||||
return [
|
||||
__('API') => 0,
|
||||
__('Local') => 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function place(): array
|
||||
{
|
||||
return [
|
||||
__('Begin') => 'prepend',
|
||||
__('End') => 'append',
|
||||
__('Before') => 'before',
|
||||
__('After') => 'after',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function rating(): array
|
||||
{
|
||||
return [
|
||||
'G' => 'g',
|
||||
'PG' => 'pg',
|
||||
'R' => 'r',
|
||||
'X' => 'x',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,int>
|
||||
*/
|
||||
public static function size(): array
|
||||
{
|
||||
return [
|
||||
'16px' => 16,
|
||||
'24px' => 24,
|
||||
'32px' => 32,
|
||||
'48px' => 48,
|
||||
'56px' => 56,
|
||||
'64px' => 64,
|
||||
'92px' => 92,
|
||||
'128px' => 128,
|
||||
'256px' => 256,
|
||||
];
|
||||
}
|
||||
}
|
268
src/Frontend.php
|
@ -10,234 +10,54 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
if (!dcCore::app()->blog->settings->noodles->noodles_active) {
|
||||
return null;
|
||||
}
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
include __DIR__ . '/inc/_default_noodles.php';
|
||||
require_once __DIR__ . '/inc/_noodles_functions.php';
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
use dcUtils;
|
||||
|
||||
dcCore::app()->addBehavior('publicHeadContent', ['publicNoodles', 'publicHeadContent']);
|
||||
|
||||
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates');
|
||||
|
||||
global $__noodles;
|
||||
$__noodles = noodles::decode(dcCore::app()->blog->settings->noodles->noodles_object);
|
||||
|
||||
if ($__noodles->isEmpty()) {
|
||||
$__noodles = $__default_noodles;
|
||||
}
|
||||
|
||||
//$GLOBALS['__noodles'] =& $__noodles;
|
||||
|
||||
foreach ($__noodles->noodles() as $noodle) {
|
||||
if ($noodle->active && $noodle->hasPhpCallback()) {
|
||||
$noodle->phpCallback(dcCore::app());
|
||||
}
|
||||
}
|
||||
|
||||
class publicNoodles
|
||||
class Frontend extends dcNsProcess
|
||||
{
|
||||
public static function publicHeadContent()
|
||||
public static function init(): bool
|
||||
{
|
||||
echo
|
||||
dcUtils::cssLoad(dcCore::app()->blog->url . dcCore::app()->url->getURLFor('noodlescss')) .
|
||||
dcUtils::jsLoad(dcCore::app()->blog->url . dcCore::app()->url->getBase('noodlesmodule') . '/js/jquery.noodles.js') .
|
||||
dcUtils::jsLoad(dcCore::app()->blog->url . dcCore::app()->url->getURLFor('noodlesjs'));
|
||||
}
|
||||
}
|
||||
|
||||
class urlNoodles extends dcUrlHandlers
|
||||
{
|
||||
public static function css($args)
|
||||
{
|
||||
global $__noodles;
|
||||
|
||||
$css = '';
|
||||
foreach ($__noodles->noodles() as $noodle) {
|
||||
if (!$noodle->active || !$noodle->hasJsCallback()) {
|
||||
continue;
|
||||
}
|
||||
$css .= '.noodles-' . $noodle->id() . '{' . $noodle->css . '}' . "\n";
|
||||
}
|
||||
|
||||
header('Content-Type: text/css; charset=UTF-8');
|
||||
|
||||
echo $css;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function js($args)
|
||||
{
|
||||
global $__noodles;
|
||||
|
||||
$targets = [];
|
||||
foreach ($__noodles->noodles() as $noodle) {
|
||||
if (!$noodle->active || !$noodle->hasJsCallback()) {
|
||||
continue;
|
||||
}
|
||||
$targets[] = '$(\'' . html::escapeJS($noodle->target) . '\').noodles({' .
|
||||
' imgId:\'' . html::escapeJS($noodle->id()) . '\',' .
|
||||
' imgPlace:\'' . html::escapeJS($noodle->place) . '\'' .
|
||||
'});';
|
||||
}
|
||||
|
||||
header('Content-Type: text/javascript; charset=UTF-8');
|
||||
|
||||
echo
|
||||
"\$(function(){if(!document.getElementById){return;} \n" .
|
||||
"\$.fn.noodles.defaults.service_url = '" . html::escapeJS(dcCore::app()->blog->url . dcCore::app()->url->getBase('noodlesservice') . '/') . "'; \n" .
|
||||
"\$.fn.noodles.defaults.service_func = '" . html::escapeJS('getNoodle') . "'; \n" .
|
||||
implode("\n", $targets) .
|
||||
"})\n";
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function service($args)
|
||||
{
|
||||
header('Content-Type: text/xml; charset=UTF-8');
|
||||
|
||||
$rsp = new xmlTag('rsp');
|
||||
|
||||
$i = !empty($_POST['noodleId']) ? $_POST['noodleId'] : null;
|
||||
$c = !empty($_POST['noodleContent']) ? $_POST['noodleContent'] : null;
|
||||
|
||||
if (!dcCore::app()->blog->settings->noodles->noodles_active) {
|
||||
$rsp->status = 'failed';
|
||||
$rsp->message(__('noodles is disabled on this blog'));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($i === null || $c === null) {
|
||||
$rsp->status = 'failed';
|
||||
$rsp->message(__('noodles failed because of missing informations'));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$__noodles = noodles::decode(dcCore::app()->blog->settings->noodles->noodles_object);
|
||||
|
||||
if ($__noodles->isEmpty()) {
|
||||
$__noodles = $GLOBALS['__default_noodles'];
|
||||
}
|
||||
} catch (Excetpion $e) {
|
||||
$rsp->status = 'failed';
|
||||
$rsp->message(__('Failed to load default noodles'));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$__noodles->exists($i)) {
|
||||
$rsp->status = 'failed';
|
||||
$rsp->message(__('Failed to load noodle'));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$m = $__noodles->get($i)->jsCallback($__noodles->get($i), $c);
|
||||
$s = $__noodles->get($i)->size;
|
||||
$r = $__noodles->get($i)->rating;
|
||||
$d = dcCore::app()->blog->settings->noodles->noodles_image ?
|
||||
urlencode(noodlesLibImagePath::getUrl('noodles')) : '';
|
||||
|
||||
$u = dcCore::app()->blog->settings->noodles->noodles_api;
|
||||
if (empty($u)) {
|
||||
$u = 'http://www.gravatar.com/';
|
||||
}
|
||||
if (!$m) {
|
||||
$m = 'nobody@nowhere.tld';
|
||||
}
|
||||
if (!$s) {
|
||||
$s = 32;
|
||||
}
|
||||
if (!$r) {
|
||||
$r = 'g';
|
||||
}
|
||||
|
||||
$m = md5(strtolower(trim($m)));
|
||||
$im = new xmlTag('noodle');
|
||||
$im->size = $s;
|
||||
$im->src = sprintf('%savatar/%s?s=%s&r=%s&d=%s', $u, $m, $s, $r, $d);
|
||||
$rsp->insertNode($im);
|
||||
|
||||
$rsp->status = 'ok';
|
||||
echo $rsp->toXML(true);
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function noodles($args)
|
||||
{
|
||||
if (!dcCore::app()->blog->settings->noodles->noodles_active) {
|
||||
self::p404();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preg_match('#^(.*?)$#', $args, $m)) {
|
||||
self::p404();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$f = $m[1];
|
||||
|
||||
if (!($f = self::searchTplFiles($f))) {
|
||||
self::p404();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$allowed_types = ['png', 'jpg', 'jpeg', 'gif', 'css', 'js', 'swf'];
|
||||
if (!in_array(files::getExtension($f), $allowed_types)) {
|
||||
self::p404();
|
||||
|
||||
return;
|
||||
}
|
||||
$type = files::getMimeType($f);
|
||||
|
||||
header('Content-Type: ' . $type . '; charset=UTF-8');
|
||||
header('Content-Length: ' . filesize($f));
|
||||
|
||||
if ($type != 'text/css' || dcCore::app()->blog->settings->system->url_scan == 'path_info') {
|
||||
readfile($f);
|
||||
} else {
|
||||
echo preg_replace(
|
||||
'#url\((?!(http:)|/)#',
|
||||
'url(' . dcCore::app()->blog->url . dcCore::app()->url->getBase('noodlesmodule') . '/',
|
||||
file_get_contents($f)
|
||||
);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
# Search noodles files like JS, CSS in default-templates subdirectories
|
||||
private static function searchTplFiles($file)
|
||||
{
|
||||
if (strstr($file, '..') !== false) {
|
||||
return false;
|
||||
}
|
||||
$paths = dcCore::app()->tpl->getPath();
|
||||
|
||||
foreach ($paths as $path) {
|
||||
if (preg_match('/tpl(\/|)$/', $path)) {
|
||||
$path = path::real($path . '/..');
|
||||
}
|
||||
if (file_exists($path . '/' . $file)) {
|
||||
return $path . '/' . $file;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
static::$init = My::phpCompliant();
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$targets = Targets::instance();
|
||||
|
||||
if (!$targets->active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), My::path() . '/default-templates');
|
||||
|
||||
foreach ($targets->dump() as $target) {
|
||||
if ($target->active() && $target->hasPhpCallback()) {
|
||||
$target->phpCallback();
|
||||
}
|
||||
}
|
||||
|
||||
dcCore::app()->addBehavior('publicHeadContent', function (): void {
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo
|
||||
dcUtils::cssLoad(dcCore::app()->blog->url . dcCore::app()->url->getURLFor('noodles_css')) .
|
||||
dcUtils::jsLoad(dcCore::app()->blog->url . dcCore::app()->url->getBase('noodles_file') . '/js/jquery.noodles.js') .
|
||||
dcUtils::jsLoad(dcCore::app()->blog->url . dcCore::app()->url->getURLFor('noodles_js'));
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,18 +10,25 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
class noodlesLibImagePath
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use Dotclear\Helper\File\Path;
|
||||
|
||||
class Image
|
||||
{
|
||||
public static $version = '1.1';
|
||||
/** @var string The current class major version */
|
||||
public const VERSION = '2';
|
||||
|
||||
public static function getArray($m = '')
|
||||
/**
|
||||
* @return array<string, array{dir: null|string, url: null|string}> The Image possible paths
|
||||
*/
|
||||
public static function getArray(): array
|
||||
{
|
||||
if (!dcCore::app()->plugins->moduleExists($m)
|
||||
|| !dcCore::app()->url->getBase($m . 'module')
|
||||
if (is_null(dcCore::app()->blog)
|
||||
|| !dcCore::app()->url->getBase('noodles_file')
|
||||
) {
|
||||
return [
|
||||
'theme' => ['dir' => null, 'url' => null],
|
||||
|
@ -30,27 +37,35 @@ class noodlesLibImagePath
|
|||
];
|
||||
}
|
||||
|
||||
$public_url = dcCore::app()->blog->settings->get('system')->get('public_url');
|
||||
if (!is_string($public_url)) {
|
||||
$public_url = '';
|
||||
}
|
||||
|
||||
return [
|
||||
'theme' => [
|
||||
'dir' => path::real(dcCore::app()->blog->themes_path . '/' . dcCore::app()->blog->settings->system->theme . '/img') . '/' . $m . '-default-image.png',
|
||||
'url' => dcCore::app()->blog->settings->system->themes_url . dcCore::app()->blog->settings->system->theme . '/img/' . $m . '-default-image.png',
|
||||
'dir' => Path::real(dcCore::app()->blog->themes_path . '/' . dcCore::app()->blog->settings->get('system')->get('theme') . '/img') . '/' . My::IMAGE,
|
||||
'url' => dcCore::app()->blog->settings->get('system')->get('themes_url') . dcCore::app()->blog->settings->get('system')->get('theme') . '/img/' . My::IMAGE,
|
||||
],
|
||||
'public' => [
|
||||
'dir' => path::real(dcCore::app()->blog->public_path) . '/' . $m . '-default-image.png',
|
||||
'url' => dcCore::app()->blog->host . path::clean(dcCore::app()->blog->settings->system->public_url) . '/' . $m . '-default-image.png',
|
||||
'dir' => Path::real(dcCore::app()->blog->public_path) . '/' . My::IMAGE,
|
||||
'url' => dcCore::app()->blog->host . Path::clean($public_url) . '/' . My::IMAGE,
|
||||
],
|
||||
'module' => [
|
||||
'dir' => path::real(dcCore::app()->plugins->moduleRoot($m) . '/default-templates/img') . '/' . $m . '-default-image.png',
|
||||
'url' => dcCore::app()->blog->url . dcCore::app()->url->getBase($m . 'module') . '/img/' . $m . '-default-image.png',
|
||||
'dir' => Path::real(My::path() . '/default-templates/img') . '/' . My::IMAGE,
|
||||
'url' => dcCore::app()->blog->url . dcCore::app()->url->getBase('noodles_file') . '/img/' . My::IMAGE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function getUrl($m = '')
|
||||
/**
|
||||
* @return null|string The image URL
|
||||
*/
|
||||
public static function getUrl(): ?string
|
||||
{
|
||||
$files = self::getArray($m);
|
||||
$files = self::getArray();
|
||||
foreach ($files as $k => $file) {
|
||||
if (file_exists($files[$k]['dir'])) {
|
||||
if (is_string($files[$k]['dir']) && file_exists($files[$k]['dir'])) {
|
||||
return $files[$k]['url'];
|
||||
}
|
||||
}
|
||||
|
@ -58,25 +73,18 @@ class noodlesLibImagePath
|
|||
return null;
|
||||
}
|
||||
|
||||
public static function getPath($m = '')
|
||||
/**
|
||||
* @return null|string The image path
|
||||
*/
|
||||
public static function getPath(): ?string
|
||||
{
|
||||
$files = self::getArray($m);
|
||||
$files = self::getArray();
|
||||
foreach ($files as $k => $file) {
|
||||
if (file_exists($files[$k]['dir'])) {
|
||||
if (is_string($files[$k]['dir']) && file_exists($files[$k]['dir'])) {
|
||||
return $files[$k]['dir'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getSize($m = '')
|
||||
{
|
||||
if (!($img = self::getPath($m))) {
|
||||
return ['w' => 16, 'h' => 16];
|
||||
}
|
||||
$info = getimagesize($img);
|
||||
|
||||
return ['w' => $info[0], 'h' => floor($info[1] / 3)];
|
||||
}
|
||||
}
|
||||
|
|
102
src/Install.php
|
@ -10,62 +10,48 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_CONTEXT_ADMIN')) {
|
||||
return null;
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
use Exception;
|
||||
|
||||
class Install extends dcNsProcess
|
||||
{
|
||||
public static function init(): bool
|
||||
{
|
||||
static::$init = defined('DC_CONTEXT_ADMIN')
|
||||
&& My::phpCompliant()
|
||||
&& is_string(dcCore::app()->plugins->moduleInfo(My::id(), 'version'))
|
||||
&& dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version'));
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$s = dcCore::app()->blog?->settings->get(My::id());
|
||||
if (is_null($s)) {
|
||||
return false;
|
||||
}
|
||||
# Set module settings
|
||||
$s->put('active', false, 'boolean', 'enable module', false, true);
|
||||
$s->put('api', 'http://www.gravatar.com/', 'string', 'external API', false, true);
|
||||
$s->put('local', false, 'boolean', 'use local image', false, true);
|
||||
$s->put('settings', '[]', 'string', 'noodles settings', false, true);
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
dcCore::app()->error->add($e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$mod_conf = [
|
||||
[
|
||||
'noodles_active',
|
||||
false,
|
||||
'boolean',
|
||||
'Enable extension',
|
||||
],
|
||||
[
|
||||
'noodles_api',
|
||||
'http://www.gravatar.com/',
|
||||
'string',
|
||||
'external API to use',
|
||||
],
|
||||
[
|
||||
'noodles_image',
|
||||
'',
|
||||
'string',
|
||||
'Image filename',
|
||||
],
|
||||
[
|
||||
'noodles_object',
|
||||
'',
|
||||
'string',
|
||||
'Noodles behaviors',
|
||||
],
|
||||
];
|
||||
|
||||
# -- Nothing to change below --
|
||||
try {
|
||||
# Check module version
|
||||
if (!dcCore::app()->newVersion(
|
||||
basename(__DIR__),
|
||||
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version')
|
||||
)) {
|
||||
return null;
|
||||
}
|
||||
# Set module settings
|
||||
dcCore::app()->blog->settings->addNamespace(basename(__DIR__));
|
||||
foreach ($mod_conf as $v) {
|
||||
dcCore::app()->blog->settings->__get(basename(__DIR__))->put(
|
||||
$v[0],
|
||||
$v[1],
|
||||
$v[2],
|
||||
$v[3],
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
dcCore::app()->error->add($e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
390
src/Manage.php
|
@ -10,262 +10,168 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_CONTEXT_ADMIN')) {
|
||||
return null;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
dcPage::check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_CONTENT_ADMIN]));
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
include __DIR__ . '/inc/_default_noodles.php';
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
use dcPage;
|
||||
use Exception;
|
||||
|
||||
$s = dcCore::app()->blog->settings->noodles;
|
||||
use form;
|
||||
|
||||
$__noodles = noodles::decode($s->noodles_object);
|
||||
if ($__noodles->isEmpty()) {
|
||||
$__noodles = $__default_noodles;
|
||||
} else {
|
||||
$default_noodles_array = $__default_noodles->noodles();
|
||||
foreach ($default_noodles_array as $id => $noodle) {
|
||||
if ($__noodles->exists($id)) {
|
||||
continue;
|
||||
}
|
||||
$__noodles->set($id, $noodle);
|
||||
class Manage extends dcNsProcess
|
||||
{
|
||||
public static function init(): bool
|
||||
{
|
||||
static::$init = defined('DC_CONTEXT_ADMIN')
|
||||
&& My::phpCompliant()
|
||||
&& !is_null(dcCore::app()->auth) && !is_null(dcCore::app()->blog)
|
||||
&& dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
||||
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
|
||||
]), dcCore::app()->blog->id);
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
}
|
||||
$public_path = path::real(dcCore::app()->blog->public_path);
|
||||
if (!is_dir($public_path) || !is_writable($public_path)) {
|
||||
$public_path = false;
|
||||
}
|
||||
$default_images = files::scandir(__DIR__ . '/default-templates/img/');
|
||||
if (!is_array($default_images)) {
|
||||
$default_images = [];
|
||||
}
|
||||
$default_image = $s->noodles_image;
|
||||
|
||||
$combo_api = [
|
||||
'gravatar' => 'http://www.gravatar.com/',
|
||||
'libravatar' => 'http://cdn.libravatar.org/',
|
||||
];
|
||||
|
||||
$combo_place = [
|
||||
__('Begin') => 'prepend',
|
||||
__('End') => 'append',
|
||||
__('Before') => 'before',
|
||||
__('After') => 'after',
|
||||
];
|
||||
$combo_rating = [
|
||||
'G' => 'g',
|
||||
'PG' => 'pg',
|
||||
'R' => 'r',
|
||||
'X' => 'x',
|
||||
];
|
||||
$combo_size = [
|
||||
'16px' => 16,
|
||||
'24px' => 24,
|
||||
'32px' => 32,
|
||||
'48px' => 48,
|
||||
'56px' => 56,
|
||||
'64px' => 64,
|
||||
'92px' => 92,
|
||||
'128px' => 128,
|
||||
'256px' => 256,
|
||||
];
|
||||
|
||||
if (!empty($_POST['save'])) {
|
||||
try {
|
||||
$public_file = $public_path . '/noodles-default-image.png';
|
||||
$s->put('noodles_active', !empty($_POST['noodles_active']), 'boolean');
|
||||
$s->put('noodles_api', $_POST['noodles_api'], 'string');
|
||||
|
||||
// user upload image
|
||||
if ($_POST['noodles_image'] == 'user' && !empty($public_path)) {
|
||||
if (2 == $_FILES['noodlesuserfile']['error']) {
|
||||
throw new Exception(__('Maximum file size exceeded'));
|
||||
}
|
||||
if (0 != $_FILES['noodlesuserfile']['error']) {
|
||||
throw new Exception(__('Something went wrong while download file'));
|
||||
}
|
||||
if (!in_array($_FILES['noodlesuserfile']['type'], ['image/png', 'image/x-png'])) {
|
||||
throw new Exception(__('Image must be in png format'));
|
||||
}
|
||||
if (move_uploaded_file($_FILES['noodlesuserfile']['tmp_name'], $public_file)) {
|
||||
$s->put('noodles_image', 1, 'boolean');
|
||||
} else {
|
||||
throw new Exception(__('Failed to save image'));
|
||||
}
|
||||
|
||||
// Default gravatar.com avatar
|
||||
} elseif ($_POST['noodles_image'] == 'gravatar.com') {
|
||||
$s->put('noodles_image', 0, 'boolean');
|
||||
|
||||
// existsing noodles image on blog
|
||||
} elseif ($_POST['noodles_image'] == 'existing') {
|
||||
$s->put('noodles_image', 1, 'boolean');
|
||||
|
||||
// noodles image
|
||||
} elseif (preg_match('/^gravatar-[0-9]+.png$/', $_POST['noodles_image']) && !empty($public_path)) {
|
||||
$source = dirname(__FILE__) . '/default-templates/img/' . $_POST['noodles_image'];
|
||||
if (!file_exists($source)) {
|
||||
throw new Exception(__('Something went wrong while search file'));
|
||||
}
|
||||
if (files::putContent($public_file, file_get_contents($source))) {
|
||||
$s->put('noodles_image', 1, 'boolean');
|
||||
}
|
||||
|
||||
// Default gravatar.com avatar
|
||||
} else { //if ($_POST['noodles_image'] == 'gravatar.com') {
|
||||
$s->put('noodles_image', 0, 'boolean');
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// behaviors
|
||||
foreach ($_POST['noodle'] as $id => $bloc) {
|
||||
$__noodles->get($id)
|
||||
->set('active', !empty($bloc['active']))
|
||||
->set('rating', $bloc['rating'] ?? 'g')
|
||||
->set('size', $bloc['size'] ?? '16')
|
||||
->set('css', $bloc['css'] ?? '')
|
||||
->set('target', $bloc['target'] ?? '')
|
||||
->set('place', $bloc['place'] ?? 'prepend')
|
||||
;
|
||||
// nullsafe check
|
||||
if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) {
|
||||
return false;
|
||||
}
|
||||
$s->put('noodles_object', $__noodles->encode(), 'string');
|
||||
|
||||
dcCore::app()->blog->triggerBlog();
|
||||
dcAdminNotices::addSuccessNotice(__('Configuration successfully updated'));
|
||||
dcCore::app()->adminurl->redirect('admin.plugin.noodles');
|
||||
} catch (Exception $e) {
|
||||
dcCore::app()->error->add($e->getMessage());
|
||||
if (empty($_POST['save'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$s = dcCore::app()->blog->settings->get(My::id());
|
||||
$targets = Targets::instance();
|
||||
|
||||
try {
|
||||
$s->put('active', !empty($_POST['noodles_active']), 'boolean');
|
||||
$s->put('api', $_POST['noodles_api'], 'string');
|
||||
$s->put('local', !empty($_POST['noodles_local']), 'boolean');
|
||||
|
||||
// behaviors
|
||||
foreach ($_POST['noodle'] as $id => $bloc) {
|
||||
$target = $targets->get($id);
|
||||
if (is_null($target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$target
|
||||
->setActive(!empty($bloc['active']))
|
||||
->setRating($bloc['rating'] ?? 'g')
|
||||
->setSize($bloc['size'] ?? '16')
|
||||
->setCss($bloc['css'] ?? '')
|
||||
->setTarget($bloc['target'] ?? '')
|
||||
->setPlace($bloc['place'] ?? 'prepend')
|
||||
;
|
||||
}
|
||||
$targets->export();
|
||||
|
||||
dcCore::app()->blog->triggerBlog();
|
||||
dcPage::addSuccessNotice(__('Configuration successfully updated'));
|
||||
dcCore::app()->adminurl->redirect('admin.plugin.noodles');
|
||||
} catch (Exception $e) {
|
||||
dcCore::app()->error->add($e->getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
echo '<html><head><title>' . __('Noodles') . '</title></head><body>' .
|
||||
dcPage::breadcrumb([
|
||||
html::escapeHTML(dcCore::app()->blog->name) => '',
|
||||
__('Noodles') => '',
|
||||
__('Plugin configuration') => '',
|
||||
]) .
|
||||
dcPage::notices() . '
|
||||
|
||||
<form id="module_config" action="' .
|
||||
dcCore::app()->adminurl->get('admin.plugin.noodles') .
|
||||
'" method="post" enctype="multipart/form-data">
|
||||
<h3>' . sprintf(__('Configure "%s"'), __('Noodles')) . '</h3>
|
||||
<div class="fieldset"><h4>' . __('Activation') . '</h4>
|
||||
<p><label for="noodles_active">' .
|
||||
form::checkbox('noodles_active', 1, $s->noodles_active) .
|
||||
__('Enable plugin noodles on this blog') . '</label></p>
|
||||
<p><label for="noodles_api" class="classic">' . __('API:') . ' </label>' .
|
||||
form::combo('noodles_api', $combo_api, $s->noodles_api) . '</p>
|
||||
</div>
|
||||
<div class="fieldset"><h4>' . __('Avatar') . '</h4>
|
||||
<p>' . __('Select default avatar to display on unknown users.') . '</p>';
|
||||
|
||||
if (!empty($public_path)) {
|
||||
echo '<div class="one-box">';
|
||||
sort($default_images);
|
||||
$i = 0;
|
||||
foreach ($default_images as $f) {
|
||||
if (!preg_match('/gravatar-[0-9]+.png/', $f)) {
|
||||
continue;
|
||||
public static function render(): void
|
||||
{
|
||||
if (!static::$init) {
|
||||
return;
|
||||
}
|
||||
$i++;
|
||||
$sz = getimagesize(dirname(__FILE__) . '/default-templates/img/' . $f);
|
||||
$sz[2] = files::size(filesize(dirname(__FILE__) . '/default-templates/img/' . $f));
|
||||
|
||||
// nullsafe check
|
||||
if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$targets = Targets::instance();
|
||||
$path = Image::getPath();
|
||||
if (is_null($path)) {
|
||||
$note = __('Local default avatar is not reachable!');
|
||||
} else {
|
||||
$note = '<a href="' . Image::getURL() . '">' . __('See local default avatar.') . '</a>';
|
||||
}
|
||||
|
||||
dcPage::openModule(My::name());
|
||||
|
||||
echo
|
||||
dcPage::breadcrumb([
|
||||
__('Plugin') => '',
|
||||
My::name() => '',
|
||||
]) .
|
||||
dcPage::notices() . '
|
||||
|
||||
<form id="module_config" action="' .
|
||||
dcCore::app()->adminurl->get('admin.plugin.' . My::id()) .
|
||||
'" method="post" enctype="multipart/form-data">
|
||||
<h3>' . sprintf(__('Configure "%s"'), __('Noodles')) . '</h3>
|
||||
<div class="fieldset"><h4>' . __('Settings') . '</h4>
|
||||
<p><label for="noodles_active">' .
|
||||
form::checkbox('noodles_active', 1, $targets->active) .
|
||||
__('Enable plugin noodles on this blog') . '</label></p>
|
||||
<p class="field"><label for="noodles_api" class="classic">' . __('Image API:') . ' </label>' .
|
||||
form::combo('noodles_api', Combo::api(), $targets->api) . '</p>
|
||||
<p class="field"><label for="noodles_local" class="classic">' . __('Default image:') . ' </label>' .
|
||||
form::combo('noodles_local', Combo::local(), $targets->local) . '</p>
|
||||
<p class="form-note">' . $note . '</p>
|
||||
<p class="form-note">' . sprintf(__('You can add your own default avatar by adding file "%s" in media manager.'), 'img/' . My::IMAGE) . '</p>
|
||||
</div>
|
||||
|
||||
<div class="fieldset"><h4>' . __('Behaviors') . '</h4>
|
||||
<div class="table-outer">
|
||||
<table><caption class="hidden">' . __('Behaviors list') . '</caption><tbody><tr>
|
||||
<th colspan="2" class="first">' . __('Search area') . '</th>
|
||||
<th scope="col">' . __('Size') . '</th>
|
||||
<th scope="col">' . __('Rating') . '</th>
|
||||
<th scope="col">' . __('PHP') . '</th>
|
||||
<th scope="col">' . __('JS') . '</th>
|
||||
<th scope="col">' . __('Target') . '</th>
|
||||
<th scope="col">' . __('Place') . '</th>
|
||||
<th colspan="2" scope="col">' . __('Adjust avatar CSS') . '</th>
|
||||
</tr>';
|
||||
|
||||
foreach ($targets->dump() as $target) {
|
||||
echo '
|
||||
<tr class="line">
|
||||
<td>' . form::checkbox(['noodle[' . $target->id . '][active]', 'ck_' . $target->id], 1, $target->active()) . '</td>
|
||||
<td class="nowrap" scope="row"><label for="ck_' . $target->id . '">' . $target->name . '</label></td>
|
||||
<td>' . form::combo(['noodle[' . $target->id . '][size]'], Combo::size(), $target->size()) . '</td>
|
||||
<td>' . form::combo(['noodle[' . $target->id . '][rating]'], Combo::rating(), $target->rating()) . '</td>
|
||||
<td>' . (
|
||||
$target->hasPhpCallback() ?
|
||||
'<img alt="ok" src="images/check-on.png" />' :
|
||||
'<img alt="nok" src="images/check-off.png" />'
|
||||
) . '</td>
|
||||
<td><img alt="ok" src="images/check-on.png" /></td>
|
||||
<td>' . form::field(['noodle[' . $target->id . '][target]'], 20, 255, $target->target()) . '</td>
|
||||
<td>' . form::combo(['noodle[' . $target->id . '][place]'], Combo::place(), $target->place()) . '</td>
|
||||
<td>' . form::field(['noodle[' . $target->id . '][css]'], 50, 255, $target->css()) . '</td>
|
||||
<td> .noodles-' . $target->id . '{}</td>
|
||||
</tr>';
|
||||
}
|
||||
echo '
|
||||
<div class="fieldset box">
|
||||
<p>' . form::radio(['noodles_image', 'noodles_image_' . $i], $f) . '
|
||||
<label class="classic" for="noodles_image_' . $i . '">' . basename($f) . '</label></p>
|
||||
<div class="two-box"><div class="box">
|
||||
<p><img src="' . dcPage::getPF('noodles/default-templates/img/' . $f) . '" alt="" /></p>
|
||||
</div><div class="box">
|
||||
<p>' . $sz[0] . 'x' . $sz[1] . '<br />' . $sz[2] . '</p>
|
||||
</div></div>
|
||||
</div>';
|
||||
</tbody></table></div>
|
||||
<p class="form-note">' . __('Target and Place are for javascript.') . '</p>
|
||||
</div>
|
||||
|
||||
<p class="clear">
|
||||
<input type="submit" value="' . __('Save') . ' (s)" accesskey="s" name="save" /> ' .
|
||||
dcCore::app()->formNonce() . '</p>
|
||||
</form>';
|
||||
|
||||
dcPage::closeModule();
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '<div class="one-box">';
|
||||
|
||||
if (null !== ($default_image_path = noodlesLibImagePath::getPath('noodles'))) {
|
||||
$sz = getimagesize($default_image_path);
|
||||
$sz[2] = files::size(filesize($default_image_path));
|
||||
|
||||
echo '
|
||||
<div class="fieldset box">
|
||||
<p>' . form::radio(['noodles_image', 'public_image'], 'existing', !empty($default_image)) . '
|
||||
<label class="classic" for="public_image">' . __('Blog default image') . '</label></p>
|
||||
<div class="two-box"><div class="box">
|
||||
<p><img src="' . noodlesLibImagePath::getUrl('noodles') . '?' . rand() . '" alt="" /></p>
|
||||
</div><div class="box">
|
||||
<p>' . $sz[0] . 'x' . $sz[1] . '<br />' . $sz[2] . '</p>
|
||||
</div></div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
if (!empty($public_path)) {
|
||||
echo '
|
||||
<div class="fieldset box">
|
||||
<p>' . form::radio(['noodles_image', 'upload_image'], 'user') . '
|
||||
<label class="classic" for="upload_image">' . __('Upload a new avatar') . '</label></p>
|
||||
<p>' . form::hidden(['MAX_FILE_SIZE'], 30000) . '
|
||||
<input type="file" name="noodlesuserfile" />
|
||||
<p class="form-note">' . __('Image must be in "png" format and have a maximum file size of 30Ko') . '</p>
|
||||
</div>';
|
||||
}
|
||||
echo '
|
||||
<div class="fieldset box">
|
||||
<p>' . form::radio(['noodles_image', 'com_image'], 'gravatar.com', empty($default_image)) . '
|
||||
<label class="classic">' . __('API default image') . '</label></p>
|
||||
</div>';
|
||||
|
||||
if (empty($public_path)) {
|
||||
echo '<p class="info">' . __('Public directory is not writable, you can not use custom gravatar.') . '</p>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</div></div>
|
||||
<div class="fieldset"><h4>' . __('Behaviors') . '</h4>
|
||||
<div class="table-outer">
|
||||
<table><caption class="hidden">' . __('Behaviors list') . '</caption><tbody><tr>
|
||||
<th colspan="2" class="first">' . __('Search area') . '</th>
|
||||
<th scope="col">' . __('Size') . '</th>
|
||||
<th scope="col">' . __('Rating') . '</th>
|
||||
<th scope="col">' . __('PHP') . '</th>
|
||||
<th scope="col">' . __('JS') . '</th>
|
||||
<th scope="col">' . __('Target') . '</th>
|
||||
<th scope="col">' . __('Place') . '</th>
|
||||
<th colspan="2" scope="col">' . __('Adjust avatar CSS') . '</th>
|
||||
</tr>';
|
||||
|
||||
foreach ($__noodles->noodles() as $noodle) {
|
||||
echo '
|
||||
<tr class="line">
|
||||
<td>' . form::checkbox(['noodle[' . $noodle->id() . '][active]', 'ck_' . $noodle->id()], 1, $noodle->active) . '</td>
|
||||
<td class="nowrap" scope="row"><label for="ck_' . $noodle->id() . '">' . $noodle->name() . '</label></td>
|
||||
<td>' . form::combo(['noodle[' . $noodle->id() . '][size]'], $combo_size, $noodle->size) . '</td>
|
||||
<td>' . form::combo(['noodle[' . $noodle->id() . '][rating]'], $combo_rating, $noodle->rating) . '</td>
|
||||
<td>' . (
|
||||
$noodle->hasPhpCallback() ?
|
||||
'<img alt="ok" src="images/check-on.png" />' :
|
||||
'<img alt="nok" src="images/check-off.png" />'
|
||||
) . '</td>
|
||||
<td><img alt="ok" src="images/check-on.png" /></td>
|
||||
<td>' . form::field(['noodle[' . $noodle->id() . '][target]'], 20, 255, $noodle->target) . '</td>
|
||||
<td>' . form::combo(['noodle[' . $noodle->id() . '][place]'], $combo_place, $noodle->place) . '</td>
|
||||
<td>' . form::field(['noodle[' . $noodle->id() . '][css]'], 50, 255, $noodle->css) . '</td>
|
||||
<td> .noodles-' . $noodle->id() . '{}</td>
|
||||
</tr>';
|
||||
}
|
||||
echo '
|
||||
</tbody></table></div>
|
||||
<p class="form-note">' . __('Target and Place are for javascript.') . '</p>
|
||||
</div>
|
||||
|
||||
<p class="clear">
|
||||
<input type="submit" value="' . __('Save') . ' (s)" accesskey="s" name="save" /> ' .
|
||||
dcCore::app()->formNonce() . '</p>
|
||||
</form>
|
||||
|
||||
</body></html>';
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
|
||||
/**
|
||||
* Plugin definitions
|
||||
*/
|
||||
class My
|
||||
{
|
||||
/** @var string Required php version */
|
||||
public const PHP_MIN = '8.1';
|
||||
|
||||
/** @var string Default image name */
|
||||
public const IMAGE = 'default-avatar.png';
|
||||
|
||||
/**
|
||||
* This module id
|
||||
*/
|
||||
public static function id(): string
|
||||
{
|
||||
return basename(dirname(__DIR__));
|
||||
}
|
||||
|
||||
/**
|
||||
* This module name
|
||||
*/
|
||||
public static function name(): string
|
||||
{
|
||||
$name = dcCore::app()->plugins->moduleInfo(self::id(), 'name');
|
||||
|
||||
return __(is_string($name) ? $name : self::id());
|
||||
}
|
||||
|
||||
/**
|
||||
* This module path
|
||||
*/
|
||||
public static function path(): string
|
||||
{
|
||||
return dirname(__DIR__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check php version
|
||||
*/
|
||||
public static function phpCompliant(): bool
|
||||
{
|
||||
return version_compare(phpversion(), self::PHP_MIN, '>=');
|
||||
}
|
||||
}
|
|
@ -10,38 +10,57 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
|
||||
class Prepend extends dcNsProcess
|
||||
{
|
||||
public static function init(): bool
|
||||
{
|
||||
static::$init = My::phpCompliant();
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// public URL for noodles files
|
||||
dcCore::app()->url->register(
|
||||
'noodles_file',
|
||||
'noodles',
|
||||
'^noodles/(.+)$',
|
||||
[UrlHandler::class, 'file']
|
||||
);
|
||||
// public URL for noodles service
|
||||
dcCore::app()->url->register(
|
||||
'noodles_service',
|
||||
'noodle',
|
||||
'^noodle/$',
|
||||
[UrlHandler::class, 'service']
|
||||
);
|
||||
// public URL for targets CSS contents
|
||||
dcCore::app()->url->register(
|
||||
'noodles_css',
|
||||
'noodles.css',
|
||||
'^noodles\.css',
|
||||
[UrlHandler::class, 'css']
|
||||
);
|
||||
// public URL for targets JS contents
|
||||
dcCore::app()->url->register(
|
||||
'noodles_js',
|
||||
'noodles.js',
|
||||
'^noodles\.js',
|
||||
[UrlHandler::class, 'js']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Clearbricks::lib()->autoload([
|
||||
'noodlesImg' => __DIR__ . '/inc/lib.noodles.img.php',
|
||||
'noodlesLibImagePath' => __DIR__ . '/inc/lib.image.path.php',
|
||||
]);
|
||||
|
||||
dcCore::app()->blog->settings->addNamespace('noodles');
|
||||
|
||||
dcCore::app()->url->register(
|
||||
'noodlesmodule',
|
||||
'noodles',
|
||||
'^noodles/(.+)$',
|
||||
['urlNoodles', 'noodles']
|
||||
);
|
||||
dcCore::app()->url->register(
|
||||
'noodlesservice',
|
||||
'noodle',
|
||||
'^noodle/$',
|
||||
['urlNoodles', 'service']
|
||||
);
|
||||
dcCore::app()->url->register(
|
||||
'noodlescss',
|
||||
'noodles.css',
|
||||
'^noodles\.css',
|
||||
['urlNoodles', 'css']
|
||||
);
|
||||
dcCore::app()->url->register(
|
||||
'noodlesjs',
|
||||
'noodles.js',
|
||||
'^noodles\.js',
|
||||
['urlNoodles', 'js']
|
||||
);
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
/**
|
||||
* Target definition.
|
||||
*/
|
||||
class Target
|
||||
{
|
||||
/** @var bool The noodle activation */
|
||||
private bool $active = false;
|
||||
|
||||
/** @var string The noodle rating */
|
||||
private string $rating = 'g';
|
||||
|
||||
/** @var int The noodle size */
|
||||
private int $size = 16;
|
||||
|
||||
/** @var string The noodle css */
|
||||
private string $css = '';
|
||||
|
||||
/** @var string The noodle target */
|
||||
private string $target = '';
|
||||
|
||||
/** @var string The noodle place */
|
||||
private string $place = 'prepend';
|
||||
|
||||
/**
|
||||
* Constructor sets main properties.
|
||||
*
|
||||
* @param string $id The noodle ID
|
||||
* @param string $name The noodle name
|
||||
* @param mixed $js_callback The js callback
|
||||
* @param mixed $php_callback The php callback
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $id,
|
||||
public readonly string $name,
|
||||
public readonly mixed $js_callback = null,
|
||||
public readonly mixed $php_callback = null
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Export settings in order to save it to blog settings.
|
||||
*
|
||||
* @return array<string,mixed> The settings
|
||||
*/
|
||||
public function exportSettings(): array
|
||||
{
|
||||
return get_object_vars($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import noodle settings from blog settings.
|
||||
*
|
||||
* @param array<string,mixed> $settings The settings
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function importSettings(array $settings): bool
|
||||
{
|
||||
if ($this->id !== ($settings['id'] ?? null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setActive($settings['active'] ?? $this->active());
|
||||
$this->setRating($settings['rating'] ?? $this->rating());
|
||||
$this->setSize($settings['size'] ?? $this->size());
|
||||
$this->setCss($settings['css'] ?? $this->css());
|
||||
$this->settarget($settings['target'] ?? $this->target());
|
||||
$this->setPlace($settings['place'] ?? $this->place());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function jsCallback(string $content = ''): string
|
||||
{
|
||||
if (is_callable($this->js_callback)) {
|
||||
$res = call_user_func($this->js_callback, $this, $content);
|
||||
|
||||
return is_string($res) ? $res : '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function hasJsCallback(): bool
|
||||
{
|
||||
return !empty($this->js_callback);
|
||||
}
|
||||
|
||||
public function phpCallback(): void
|
||||
{
|
||||
if (is_callable($this->php_callback)) {
|
||||
call_user_func($this->php_callback, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function hasPhpCallback(): bool
|
||||
{
|
||||
return !empty($this->php_callback);
|
||||
}
|
||||
|
||||
public function active(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(mixed $value): Target
|
||||
{
|
||||
$this->active = !empty($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rating(): string
|
||||
{
|
||||
return $this->rating;
|
||||
}
|
||||
|
||||
public function setRating(mixed $value): Target
|
||||
{
|
||||
if (is_string($value) && in_array($value, ['g', 'pg', 'r', 'x'])) {
|
||||
$this->rating = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function size(): int
|
||||
{
|
||||
return (int) $this->size;
|
||||
}
|
||||
|
||||
public function setSize(mixed $value): Target
|
||||
{
|
||||
if (is_numeric($value) && in_array((int) $value, [16, 24, 32, 48, 56, 64, 92, 128, 256])) {
|
||||
$this->size = (int) $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function css(): string
|
||||
{
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
public function setCss(mixed $value): Target
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$this->css = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function target(): string
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
public function setTarget(mixed $value): Target
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$this->target = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function place(): string
|
||||
{
|
||||
return $this->place;
|
||||
}
|
||||
|
||||
public function setPlace(mixed $value): Target
|
||||
{
|
||||
if (is_string($value) && in_array($value, ['append', 'prepend', 'before', 'after'])) {
|
||||
$this->place = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles\Target;
|
||||
|
||||
use dcCore;
|
||||
use Dotclear\Database\MetaRecord;
|
||||
use Dotclear\Plugin\noodles\{
|
||||
Image,
|
||||
My,
|
||||
Targets,
|
||||
Target
|
||||
};
|
||||
|
||||
/**
|
||||
* Target rendering adapt to plugin authorMode.
|
||||
*/
|
||||
class AuthorMode
|
||||
{
|
||||
public static function authors(Target $target, string $content = ''): string
|
||||
{
|
||||
$ok = preg_match('@\/([^\/]*?)$@', $content, $m);
|
||||
if (!$ok || !$m[1]) {
|
||||
return '';
|
||||
}
|
||||
$rs = dcCore::app()->getUser($m[1]);
|
||||
if ($rs->isEmpty()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$res = $rs->f('user_email');
|
||||
|
||||
return is_string($res) ? $res : '';
|
||||
}
|
||||
|
||||
public static function author(Target $target): void
|
||||
{
|
||||
if ($target->active()) {
|
||||
dcCore::app()->addBehavior('publicHeadContent', [self::class, 'publicHeadContent']);
|
||||
}
|
||||
}
|
||||
|
||||
public static function publicHeadContent(): void
|
||||
{
|
||||
$targets = Targets::instance();
|
||||
$target = $targets->get('author');
|
||||
|
||||
if (is_null($target)
|
||||
|| is_null(dcCore::app()->ctx)
|
||||
|| is_null(dcCore::app()->blog)
|
||||
|| dcCore::app()->ctx->__get('current_tpl') != 'author.html'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$u = dcCore::app()->ctx->__get('users');
|
||||
if (!($u instanceof MetaRecord)) {
|
||||
return;
|
||||
}
|
||||
$u = $u->f('user_id');
|
||||
if (!is_string($u)) {
|
||||
return;
|
||||
}
|
||||
$u = dcCore::app()->getUser($u)->f('user_email');
|
||||
if (!is_string($u)) {
|
||||
$u = '';
|
||||
}
|
||||
$d = $targets->local ? urlencode((string) Image::getUrl()) : '';
|
||||
|
||||
echo
|
||||
'<script type="text/javascript">' . "\n" .
|
||||
"//<![CDATA[\n" .
|
||||
"$(function(){if(!document.getElementById){return;}\n" .
|
||||
"$('" . $target->target() . "')." . $target->place() . "('" .
|
||||
'<img class="noodles-comments" style="width:' . $target->size() . 'px;height:' . $target->size() . 'px;' . $target->css() . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($u) .
|
||||
'?s=' . $target->size() . '&r=' . $target->rating() . '&d=' . $d . '" alt="" />' .
|
||||
"');});" .
|
||||
"\n//]]>\n" .
|
||||
"</script>\n";
|
||||
}
|
||||
}
|
|
@ -10,14 +10,23 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
class genericNoodles
|
||||
namespace Dotclear\Plugin\noodles\Target;
|
||||
|
||||
use dcCore;
|
||||
use Dotclear\Plugin\noodles\Target;
|
||||
|
||||
/**
|
||||
* Target generic rendering.
|
||||
*/
|
||||
class Generic
|
||||
{
|
||||
public static function postURL($noodle, $content = '')
|
||||
public static function postURL(Target $target, string $content = ''): string
|
||||
{
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
return '';
|
||||
}
|
||||
$types = dcCore::app()->getPostTypes();
|
||||
$reg = '@^' . str_replace('%s', '(.*?)', preg_quote(dcCore::app()->blog->url . $types['post']['public_url'])) . '$@';
|
||||
$ok = preg_match($reg, $content, $m);
|
||||
|
@ -29,140 +38,8 @@ class genericNoodles
|
|||
return '';
|
||||
}
|
||||
|
||||
return $rs->user_email;
|
||||
}
|
||||
}
|
||||
|
||||
# Miscellaneous
|
||||
class othersNoodles
|
||||
{
|
||||
public static function publicPosts($noodle)
|
||||
{
|
||||
if (!$noodle->active) {
|
||||
return null;
|
||||
}
|
||||
$bhv = $noodle->place == 'prepend' || $noodle->place == 'before' ?
|
||||
'publicEntryBeforeContent' : 'publicEntryAfterContent';
|
||||
|
||||
dcCore::app()->addBehavior($bhv, ['othersNoodles', 'publicEntryContent']);
|
||||
}
|
||||
|
||||
public static function publicEntryContent()
|
||||
{
|
||||
global $__noodles;
|
||||
|
||||
$m = dcCore::app()->ctx->posts->getAuthorEmail(false);
|
||||
$c = $__noodles->posts->css;
|
||||
$s = $__noodles->posts->size;
|
||||
$r = $__noodles->posts->rating;
|
||||
$d = dcCore::app()->blog->settings->noodles->noodles_image ?
|
||||
urlencode(noodlesLibImagePath::getUrl('noodles')) : '';
|
||||
|
||||
echo
|
||||
'<img class="noodles-posts" style="width:' . $s . 'px;height:' . $s . 'px;' . $c . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($m) .
|
||||
'?s=' . $s . '&r=' . $r . '&d=' . $d . '" alt="" />';
|
||||
}
|
||||
|
||||
public static function publicComments($noodle)
|
||||
{
|
||||
if (!$noodle->active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bhv = $noodle->place == 'prepend' || $noodle->place == 'before' ?
|
||||
'publicCommentBeforeContent' : 'publicCommentAfterContent';
|
||||
|
||||
dcCore::app()->addBehavior($bhv, ['othersNoodles', 'publicCommentContent']);
|
||||
}
|
||||
|
||||
public static function publicCommentContent()
|
||||
{
|
||||
global $__noodles;
|
||||
|
||||
$m = dcCore::app()->ctx->comments->getEmail(false);
|
||||
$c = $__noodles->comments->css;
|
||||
$s = $__noodles->comments->size;
|
||||
$r = $__noodles->comments->rating;
|
||||
$d = dcCore::app()->blog->settings->noodles->noodles_image ?
|
||||
urlencode(noodlesLibImagePath::getUrl('noodles')) : '';
|
||||
|
||||
echo
|
||||
'<img class="noodles-comments" style="width:' . $s . 'px;height:' . $s . 'px;' . $c . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($m) .
|
||||
'?s=' . $s . '&r=' . $r . '&d=' . $d . '" alt="" />';
|
||||
}
|
||||
}
|
||||
|
||||
# Plugin Widgets
|
||||
class widgetsNoodles
|
||||
{
|
||||
public static function lastcomments($noodle, $content = '')
|
||||
{
|
||||
$ok = preg_match('@\#c([0-9]+)$@', urldecode($content), $m);
|
||||
if (!$ok || !$m[1]) {
|
||||
return '';
|
||||
}
|
||||
$rs = dcCore::app()->blog->getComments(['no_content' => 1, 'comment_id' => $m[1], 'limit' => 1]);
|
||||
if (!$rs->isEmpty()) {
|
||||
return $rs->comment_email;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
# Plugin authorMode
|
||||
class authormodeNoodles
|
||||
{
|
||||
public static function authors($noodle, $content = '')
|
||||
{
|
||||
$ok = preg_match('@\/([^\/]*?)$@', $content, $m);
|
||||
if (!$ok || !$m[1]) {
|
||||
return '';
|
||||
}
|
||||
$rs = dcCore::app()->getUser($m[1]);
|
||||
if ($rs->isEmpty()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $rs->user_email;
|
||||
}
|
||||
|
||||
public static function author($noodle)
|
||||
{
|
||||
if ($noodle->active) {
|
||||
dcCore::app()->addBehavior('publicHeadContent', ['authormodeNoodles', 'publicHeadContent']);
|
||||
}
|
||||
}
|
||||
|
||||
public static function publicHeadContent()
|
||||
{
|
||||
global $__noodles;
|
||||
|
||||
if (dcCore::app()->ctx->current_tpl != 'author.html') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$id = dcCore::app()->ctx->users->user_id;
|
||||
$u = dcCore::app()->getUser($id);
|
||||
$m = $u->user_email;
|
||||
$c = $__noodles->author->css;
|
||||
$s = $__noodles->author->size;
|
||||
$r = $__noodles->author->rating;
|
||||
$d = dcCore::app()->blog->settings->noodles->noodles_image ?
|
||||
urlencode(noodlesLibImagePath::getUrl('noodles')) : '';
|
||||
|
||||
echo
|
||||
'<script type="text/javascript">' . "\n" .
|
||||
"//<![CDATA[\n" .
|
||||
"$(function(){if(!document.getElementById){return;}\n" .
|
||||
"$('" . $__noodles->author->target . "')." . $__noodles->author->place . "('" .
|
||||
'<img class="noodles-comments" style="width:' . $s . 'px;height:' . $s . 'px;' . $c . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($m) .
|
||||
'?s=' . $s . '&r=' . $r . '&d=' . $d . '" alt="" />' .
|
||||
"');});" .
|
||||
"\n//]]>\n" .
|
||||
"</script>\n";
|
||||
$res = $rs->f('user_email');
|
||||
|
||||
return is_string($res) ? $res : '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles\Target;
|
||||
|
||||
use dcCore;
|
||||
use Dotclear\Database\MetaRecord;
|
||||
use Dotclear\Plugin\noodles\{
|
||||
Image,
|
||||
My,
|
||||
Targets,
|
||||
Target
|
||||
};
|
||||
|
||||
/**
|
||||
* Target complete rendering.
|
||||
*/
|
||||
class Other
|
||||
{
|
||||
public static function publicPosts(Target $target): void
|
||||
{
|
||||
if (!$target->active()) {
|
||||
return;
|
||||
}
|
||||
$bhv = $target->place() == 'prepend' || $target->place() == 'before' ?
|
||||
'publicEntryBeforeContent' : 'publicEntryAfterContent';
|
||||
|
||||
dcCore::app()->addBehavior($bhv, [self::class, 'publicEntryContent']);
|
||||
}
|
||||
|
||||
public static function publicEntryContent(): void
|
||||
{
|
||||
$targets = Targets::instance();
|
||||
$target = $targets->get('posts');
|
||||
|
||||
if (is_null($target)
|
||||
|| is_null(dcCore::app()->ctx)
|
||||
|| is_null(dcCore::app()->blog)
|
||||
|| dcCore::app()->ctx->__get('current_tpl') != 'post.html'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$m = dcCore::app()->ctx->__get('posts');
|
||||
if (!($m instanceof MetaRecord)) {
|
||||
return;
|
||||
}
|
||||
$m = $m->__call('getAuthorEmail', [false]);
|
||||
if (!is_string($m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo
|
||||
'<img class="noodles-posts" style="width:' . $target->size() . 'px;height:' . $target->size() . 'px;' . $target->css() . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($m) .
|
||||
'?s=' . $target->size() . '&r=' . $target->rating() . '&d=' . ($targets->local ? urlencode((string) Image::getUrl()) : '') . '" alt="" />';
|
||||
}
|
||||
|
||||
public static function publicComments(Target $target): void
|
||||
{
|
||||
if (!$target->active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$bhv = $target->place() == 'prepend' || $target->place() == 'before' ?
|
||||
'publicCommentBeforeContent' : 'publicCommentAfterContent';
|
||||
|
||||
dcCore::app()->addBehavior($bhv, [self::class, 'publicCommentContent']);
|
||||
}
|
||||
|
||||
public static function publicCommentContent(): void
|
||||
{
|
||||
$targets = Targets::instance();
|
||||
$target = $targets->get('comments');
|
||||
|
||||
if (is_null($target)
|
||||
|| is_null(dcCore::app()->ctx)
|
||||
|| is_null(dcCore::app()->blog)
|
||||
|| dcCore::app()->ctx->__get('current_tpl') != 'post.html'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$m = dcCore::app()->ctx->__get('comments');
|
||||
if (!($m instanceof MetaRecord)) {
|
||||
return;
|
||||
}
|
||||
$m = $m->__call('getEmail', [false]);
|
||||
if (!is_string($m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo
|
||||
'<img class="noodles-comments" style="width:' . $target->size() . 'px;height:' . $target->size() . 'px;' . $target->css() . '"' .
|
||||
'src="http://www.gravatar.com/avatar/' . md5($m) .
|
||||
'?s=' . $target->size() . '&r=' . $target->rating() . '&d=' . ($targets->local ? urlencode((string) Image::getUrl()) : '') . '" alt="" />';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles\Target;
|
||||
|
||||
use dcCore;
|
||||
use Dotclear\Plugin\noodles\Target;
|
||||
|
||||
/**
|
||||
* Target rendering adapt to plugin Widgets.
|
||||
*/
|
||||
class Widgets
|
||||
{
|
||||
public static function lastcomments(Target $target, string $content = ''): string
|
||||
{
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
return '';
|
||||
}
|
||||
$ok = preg_match('@\#c([0-9]+)$@', urldecode($content), $m);
|
||||
if (!$ok || !$m[1]) {
|
||||
return '';
|
||||
}
|
||||
$rs = dcCore::app()->blog->getComments(['no_content' => 1, 'comment_id' => $m[1], 'limit' => 1]);
|
||||
if ($rs->isEmpty()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$res = $rs->f('comment_email');
|
||||
|
||||
return is_string($res) ? $res : '';
|
||||
}
|
||||
}
|
434
src/Targets.php
|
@ -10,211 +10,313 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_RC_PATH')) {
|
||||
return null;
|
||||
}
|
||||
declare(strict_types=1);
|
||||
|
||||
class noodles
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Targets stack.
|
||||
*/
|
||||
final class Targets
|
||||
{
|
||||
private $noodles = [];
|
||||
/** @var Targets The noodles instance */
|
||||
private static $instance;
|
||||
|
||||
public static function decode($s)
|
||||
/** @ var bool The activation */
|
||||
public readonly bool $active;
|
||||
|
||||
/** @ var string The API URL */
|
||||
public readonly string $api;
|
||||
|
||||
/** @ var bool Use local image */
|
||||
public readonly bool $local;
|
||||
|
||||
/** @var array<string,Target> The noodles stack */
|
||||
private array $targets = [];
|
||||
|
||||
/**
|
||||
* Constructor load noodles from behaviors.
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
$o = @unserialize(base64_decode($s));
|
||||
if ($o instanceof noodles) {
|
||||
return $o;
|
||||
// try to read main settings
|
||||
$active = $api = $local = null;
|
||||
if (!is_null(dcCore::app()->blog)) {
|
||||
$s = dcCore::app()->blog->settings->get(My::id());
|
||||
$active = $s->get('active');
|
||||
$api = $s->get('api');
|
||||
$local = $s->get('local');
|
||||
}
|
||||
|
||||
return new self();
|
||||
// set main settings
|
||||
$this->active = is_bool($active) ? $active : false;
|
||||
$this->api = is_string($api) ? $api : 'http://www.gravatar.com/';
|
||||
$this->local = is_bool($local) ? $local : false;
|
||||
|
||||
// add noodles
|
||||
dcCore::app()->callBehavior('TargetsConstruct', $this);
|
||||
|
||||
// add default noodles
|
||||
$this->registerDefault();
|
||||
|
||||
// set noodles settings
|
||||
$this->import();
|
||||
}
|
||||
|
||||
public function encode()
|
||||
protected function __clone()
|
||||
{
|
||||
return base64_encode(serialize($this));
|
||||
throw new Exception('nope');
|
||||
}
|
||||
|
||||
public function add($id, $name, $js_callback, $php_callback = null)
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->noodles[$id] = new noodle($id, $name, $js_callback, $php_callback);
|
||||
|
||||
return $this->noodles[$id];
|
||||
throw new Exception('nope');
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
/**
|
||||
* Get singleton instance.
|
||||
*
|
||||
* @return Targets Targets instance
|
||||
*/
|
||||
public static function instance(): Targets
|
||||
{
|
||||
return $this->noodles[$id] ?? null;
|
||||
}
|
||||
|
||||
public function __get($id)
|
||||
{
|
||||
return $this->get($id);
|
||||
}
|
||||
|
||||
public function set($id, $noodle)
|
||||
{
|
||||
return $this->noodles[$id] = $noodle;
|
||||
}
|
||||
|
||||
public function __set($id, $noodle)
|
||||
{
|
||||
return $this->set($id, $noodle);
|
||||
}
|
||||
|
||||
public function exists($id)
|
||||
{
|
||||
return isset($this->noodles[$id]);
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return !count($this->noodles);
|
||||
}
|
||||
|
||||
public function noodles()
|
||||
{
|
||||
return $this->noodles;
|
||||
}
|
||||
}
|
||||
|
||||
class noodle
|
||||
{
|
||||
private $id;
|
||||
private $name;
|
||||
private $js_callback;
|
||||
private $php_callback;
|
||||
private $settings = [
|
||||
'active' => 0,
|
||||
'rating' => 'g',
|
||||
'size' => 16,
|
||||
'target' => '',
|
||||
'place' => 'prepend',
|
||||
];
|
||||
|
||||
public function __construct($id, $name, $js_callback, $php_callback = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->js_callback = $js_callback;
|
||||
$this->php_callback = $php_callback;
|
||||
}
|
||||
|
||||
public function id()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function jsCallback($g, $content = '')
|
||||
{
|
||||
if (!is_callable($this->js_callback)) {
|
||||
return null;
|
||||
if (!is_a(self::$instance, Targets::class)) {
|
||||
self::$instance = new Targets();
|
||||
}
|
||||
|
||||
return call_user_func($this->js_callback, $g, $content);
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function hasJsCallback()
|
||||
/**
|
||||
* Import noodles settings from blog settings.
|
||||
*/
|
||||
public function import(): void
|
||||
{
|
||||
return !empty($this->js_callback);
|
||||
}
|
||||
|
||||
public function phpCallback()
|
||||
{
|
||||
if (!is_callable($this->php_callback)) {
|
||||
return null;
|
||||
$s = dcCore::app()->blog?->settings->get(My::id())->get('settings');
|
||||
if (!is_string($s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return call_user_func($this->php_callback, $this);
|
||||
}
|
||||
|
||||
public function hasPhpCallback()
|
||||
{
|
||||
return !empty($this->php_callback);
|
||||
}
|
||||
|
||||
public function set($type, $value)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'active':
|
||||
$this->settings['active'] = abs((int) $value);
|
||||
|
||||
break;
|
||||
|
||||
case 'rating':
|
||||
$this->settings['rating'] = in_array($value, ['g', 'pg', 'r', 'x']) ? $value : 'g';
|
||||
|
||||
break;
|
||||
|
||||
case 'size':
|
||||
$this->settings['size'] = in_array($value, [16, 24, 32, 48, 56, 64, 92, 128, 256]) ? $value : 16;
|
||||
|
||||
break;
|
||||
|
||||
case 'css':
|
||||
$this->settings['css'] = (string) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'target':
|
||||
$this->settings['target'] = (string) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'place':
|
||||
$this->settings['place'] = in_array($value, ['append', 'prepend', 'before', 'after']) ? $value : 'prepend';
|
||||
|
||||
break;
|
||||
$targets = json_decode($s, true);
|
||||
if (!is_array($targets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($targets as $id => $settings) {
|
||||
if (is_array($settings) && isset($this->targets[$id])) {
|
||||
$this->targets[$id]->importSettings($settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export noodles settings to blog settings.
|
||||
*/
|
||||
public function export(): void
|
||||
{
|
||||
$targets = [];
|
||||
foreach ($this->targets as $target) {
|
||||
$targets[$target->id] = $target->exportSettings();
|
||||
}
|
||||
|
||||
dcCore::app()->blog?->settings->get(My::id())->put('settings', json_encode($targets), 'string');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a noodle.
|
||||
*
|
||||
* @param string $id The noodle ID
|
||||
*
|
||||
* @return null|Target The noodle instance
|
||||
*/
|
||||
public function get(string $id): ?Target
|
||||
{
|
||||
return $this->targets[$id] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a noodle to the stack.
|
||||
*
|
||||
* @param Target $target The noodle instance
|
||||
*
|
||||
* @return Targets The noodles stack
|
||||
*/
|
||||
public function set(Target $target): Targets
|
||||
{
|
||||
$this->targets[$target->id] = $target;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function active($value)
|
||||
/**
|
||||
* Check if a noodle exists.
|
||||
*
|
||||
* @param string $id The noodle ID
|
||||
*
|
||||
* @return bool True on exists
|
||||
*/
|
||||
public function exists(string $id): bool
|
||||
{
|
||||
return $this->set('active', $value);
|
||||
return isset($this->targets[$id]);
|
||||
}
|
||||
|
||||
public function rating($value)
|
||||
/**
|
||||
* Get all noodles.
|
||||
*
|
||||
* @return array<string,Target> The noodles stack
|
||||
*/
|
||||
public function dump(): array
|
||||
{
|
||||
return $this->set('rating', $value);
|
||||
return $this->targets;
|
||||
}
|
||||
|
||||
public function size($value)
|
||||
/**
|
||||
* Add default noodles to the stack.
|
||||
*/
|
||||
private function registerDefault(): void
|
||||
{
|
||||
return $this->set('size', $value);
|
||||
}
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function css($value)
|
||||
{
|
||||
return $this->set('css', $value);
|
||||
}
|
||||
# Posts (by public behavior)
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'posts',
|
||||
name: __('Entries'),
|
||||
php_callback: [Target\Other::class, 'publicPosts']
|
||||
))
|
||||
->setSize(48)
|
||||
->setCss('float:right;margin:4px;')
|
||||
);
|
||||
|
||||
public function target($value)
|
||||
{
|
||||
return $this->set('target', $value);
|
||||
}
|
||||
# Comments (by public behavior)
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'comments',
|
||||
name: __('Comments'),
|
||||
php_callback: [Target\Other::class, 'publicComments']
|
||||
))
|
||||
->setActive(true)
|
||||
->setSize(48)
|
||||
->setCss('float:left;margin:4px;')
|
||||
);
|
||||
|
||||
public function place($value)
|
||||
{
|
||||
return $this->set('place', $value);
|
||||
}
|
||||
# Block with post title link (like homepage posts)
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'titlesposts',
|
||||
name: __('Entries titles'),
|
||||
js_callback: [Target\Generic::class, 'postURL']
|
||||
))
|
||||
->setTarget('.post-title a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
|
||||
public function __set($type, $value)
|
||||
{
|
||||
$this->set($type, $value);
|
||||
}
|
||||
if (dcCore::app()->plugins->moduleExists('widgets')) {
|
||||
# Widget Selected entries
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'bestof',
|
||||
name: __('Selected entries'),
|
||||
js_callback: [Target\Generic::class, 'postURL']
|
||||
))
|
||||
->setTarget('.selected li a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
|
||||
public function get($type)
|
||||
{
|
||||
return $this->settings[$type] ?? null;
|
||||
}
|
||||
# Widget Last entries
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'lastposts',
|
||||
name: __('Last entries'),
|
||||
js_callback: [Target\Generic::class, 'postURL']
|
||||
))
|
||||
->setTarget('.lastposts li a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
|
||||
public function __get($type)
|
||||
{
|
||||
return $this->get($type);
|
||||
# Widget Last comments
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'lastcomments',
|
||||
name: __('Last comments'),
|
||||
js_callback: [Target\Widgets::class, 'lastcomments']
|
||||
))
|
||||
->setActive(true)
|
||||
->setTarget('.lastcomments li a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
}
|
||||
|
||||
# Plugin auhtorMode
|
||||
if (dcCore::app()->plugins->moduleExists('authorMode')
|
||||
&& dcCore::app()->blog->settings->get('authormode')->get('authormode_active')
|
||||
) {
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'authorswidget',
|
||||
name: __('Authors widget'),
|
||||
js_callback: [Target\AuthorMode::class, 'authors']
|
||||
))
|
||||
->setTarget('#authors ul li a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'author',
|
||||
name: __('Author'),
|
||||
php_callback: [Target\AuthorMode::class, 'author']
|
||||
))
|
||||
->setActive(true)
|
||||
->setSize(48)
|
||||
->setTarget('.dc-author #content-info h2')
|
||||
->setCss('clear:left; float:left;margin-right:2px;')
|
||||
);
|
||||
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'authors',
|
||||
name: __('Authors'),
|
||||
js_callback: [Target\AuthorMode::class, 'authors']
|
||||
))
|
||||
->setActive(true)
|
||||
->setSize(32)
|
||||
->setTarget('.dc-authors .author-info h2 a')
|
||||
->setCss('clear:left; float:left; margin:4px;')
|
||||
);
|
||||
}
|
||||
|
||||
# Plugin rateIt
|
||||
if (dcCore::app()->plugins->moduleExists('rateIt')
|
||||
&& dcCore::app()->blog->settings->get('rateit')->get('rateit_active')
|
||||
) {
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'rateitpostsrank',
|
||||
name: __('Top rated entries'),
|
||||
js_callback: [Target\Generic::class, 'postURL']
|
||||
))
|
||||
->setTarget('.rateitpostsrank.rateittypepost ul li a') // Only "post" type
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
}
|
||||
|
||||
# Plugin lastpostsExtend
|
||||
if (dcCore::app()->plugins->moduleExists('lastpostsExtend')) {
|
||||
$this->set(
|
||||
(new Target(
|
||||
id: 'lastpostsextend',
|
||||
name: __('Last entries (extend)'),
|
||||
js_callback: [Target\Generic::class, 'postURL']
|
||||
))
|
||||
->setTarget('.lastpostsextend ul li a')
|
||||
->setCss('margin-right:2px;')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,50 +10,63 @@
|
|||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
if (!defined('DC_CONTEXT_ADMIN')) {
|
||||
return null;
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
use Dotclear\Plugin\Uninstaller\Uninstaller;
|
||||
|
||||
class Uninstall extends dcNsProcess
|
||||
{
|
||||
public static function init(): bool
|
||||
{
|
||||
static::$init = defined('DC_CONTEXT_ADMIN');
|
||||
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!static::$init || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Uninstaller::instance()
|
||||
->addUserAction(
|
||||
'settings',
|
||||
'delete_all',
|
||||
My::id()
|
||||
)
|
||||
->addUserAction(
|
||||
'plugins',
|
||||
'delete',
|
||||
My::id()
|
||||
)
|
||||
->addUserAction(
|
||||
'versions',
|
||||
'delete',
|
||||
My::id()
|
||||
)
|
||||
->addDirectAction(
|
||||
'settings',
|
||||
'delete_all',
|
||||
My::id()
|
||||
)
|
||||
->addDirectAction(
|
||||
'plugins',
|
||||
'delete',
|
||||
My::id()
|
||||
)
|
||||
->addDirectAction(
|
||||
'versions',
|
||||
'delete',
|
||||
My::id()
|
||||
)
|
||||
;
|
||||
|
||||
// no custom action
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addUserAction(
|
||||
/* type */
|
||||
'settings',
|
||||
/* action */
|
||||
'delete_all',
|
||||
/* ns */
|
||||
'noodles',
|
||||
/* description */
|
||||
__('delete all settings')
|
||||
);
|
||||
|
||||
$this->addUserAction(
|
||||
/* type */
|
||||
'plugins',
|
||||
/* action */
|
||||
'delete',
|
||||
/* ns */
|
||||
'noodles',
|
||||
/* description */
|
||||
__('delete plugin files')
|
||||
);
|
||||
|
||||
$this->addDirectAction(
|
||||
/* type */
|
||||
'settings',
|
||||
/* action */
|
||||
'delete_all',
|
||||
/* ns */
|
||||
'noodles',
|
||||
/* description */
|
||||
sprintf(__('delete all %s settings'), 'noodles')
|
||||
);
|
||||
|
||||
$this->addDirectAction(
|
||||
/* type */
|
||||
'plugins',
|
||||
/* action */
|
||||
'delete',
|
||||
/* ns */
|
||||
'noodles',
|
||||
/* description */
|
||||
sprintf(__('delete %s plugin files'), 'noodles')
|
||||
);
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief noodles, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\noodles;
|
||||
|
||||
use dcCore;
|
||||
use dcUrlHandlers;
|
||||
use Dotclear\Helper\File\Files;
|
||||
use Dotclear\Helper\File\Path;
|
||||
use Dotclear\Helper\Html\Html;
|
||||
use Dotclear\Helper\Html\XmlTag;
|
||||
use Exception;
|
||||
|
||||
class UrlHandler extends dcUrlHandlers
|
||||
{
|
||||
public static function css(?string $args): void
|
||||
{
|
||||
$css = '';
|
||||
foreach (Targets::instance()->dump() as $target) {
|
||||
if (!$target->active() || !$target->hasJsCallback()) {
|
||||
continue;
|
||||
}
|
||||
$css .= '.noodles-' . $target->id . '{' . $target->css() . '}' . "\n";
|
||||
}
|
||||
|
||||
header('Content-Type: text/css; charset=UTF-8');
|
||||
|
||||
echo $css;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function js(?string $args): void
|
||||
{
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
self::p404();
|
||||
}
|
||||
|
||||
$targets = [];
|
||||
foreach (Targets::instance()->dump() as $target) {
|
||||
if (!$target->active() || !$target->hasJsCallback()) {
|
||||
continue;
|
||||
}
|
||||
$targets[] = '$(\'' . Html::escapeJS($target->target()) . '\').noodles({' .
|
||||
' imgId:\'' . Html::escapeJS($target->id) . '\',' .
|
||||
' imgPlace:\'' . Html::escapeJS($target->place()) . '\'' .
|
||||
'});';
|
||||
}
|
||||
|
||||
header('Content-Type: text/javascript; charset=UTF-8');
|
||||
|
||||
echo
|
||||
"\$(function(){if(!document.getElementById){return;} \n" .
|
||||
"\$.fn.noodles.defaults.service_url = '" . Html::escapeJS(dcCore::app()->blog->url . dcCore::app()->url->getBase('noodles_service') . '/') . "'; \n" .
|
||||
"\$.fn.noodles.defaults.service_func = '" . Html::escapeJS('getNoodle') . "'; \n" .
|
||||
implode("\n", $targets) .
|
||||
"})\n";
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function service(string $args): void
|
||||
{
|
||||
if (is_null(dcCore::app()->blog)) {
|
||||
self::p404();
|
||||
}
|
||||
|
||||
header('Content-Type: text/xml; charset=UTF-8');
|
||||
|
||||
$targets = Targets::instance();
|
||||
$rsp = new XmlTag('rsp');
|
||||
|
||||
$i = !empty($_POST['noodleId']) ? $_POST['noodleId'] : null;
|
||||
$c = !empty($_POST['noodleContent']) ? $_POST['noodleContent'] : null;
|
||||
|
||||
if (!$targets->active) {
|
||||
$rsp->insertAttr('status', 'failed');
|
||||
$rsp->insertNode(new XmlTag('message', __('noodles is disabled on this blog')));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return;
|
||||
}
|
||||
if ($i === null || $c === null) {
|
||||
$rsp->insertAttr('status', 'failed');
|
||||
$rsp->insertNode(new XmlTag('message', __('noodles failed because of missing informations')));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$target = $targets->get($i);
|
||||
} catch (Exception $e) {
|
||||
$rsp->insertAttr('status', 'failed');
|
||||
$rsp->insertNode(new XmlTag('message', __('Failed to load default noodles')));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($target)) {
|
||||
$rsp->insertAttr('status', 'failed');
|
||||
$rsp->insertNode(new XmlTag('message', __('Failed to load noodle')));
|
||||
echo $rsp->toXML(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$m = $target->jsCallback($c);
|
||||
$s = $target->size();
|
||||
$r = $target->rating();
|
||||
$d = $targets->local ? urlencode((string) Image::getUrl()) : '';
|
||||
$u = $targets->api;
|
||||
|
||||
if (!$m) {
|
||||
$m = 'nobody@nowhere.tld';
|
||||
}
|
||||
if (!$s) {
|
||||
$s = 32;
|
||||
}
|
||||
if (!$r) {
|
||||
$r = 'g';
|
||||
}
|
||||
|
||||
$m = (string) md5(strtolower(trim($m)));
|
||||
$im = new XmlTag('noodle');
|
||||
$im->insertAttr('size', $s);
|
||||
$im->insertAttr('src', sprintf('%savatar/%s?s=%s&r=%s&d=%s', $u, $m, $s, $r, $d));
|
||||
|
||||
$rsp->insertNode($im);
|
||||
$rsp->insertAttr('status', 'ok');
|
||||
|
||||
echo $rsp->toXML(true);
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function file(string $args): void
|
||||
{
|
||||
if (is_null(dcCore::app()->blog)
|
||||
|| !Targets::instance()->active
|
||||
|| str_contains('..', $args)
|
||||
|| !preg_match('#^([^\?]*)#', $args, $m)
|
||||
) {
|
||||
self::p404();
|
||||
}
|
||||
|
||||
$f = self::searchTplFiles($m[1]);
|
||||
if (empty($f)) {
|
||||
self::p404();
|
||||
}
|
||||
|
||||
$allowed_types = ['png', 'jpg', 'jpeg', 'gif', 'css', 'js', 'swf'];
|
||||
if (!in_array(Files::getExtension($f), $allowed_types)) {
|
||||
self::p404();
|
||||
}
|
||||
$type = Files::getMimeType($f);
|
||||
|
||||
header('Content-Type: ' . $type . '; charset=UTF-8');
|
||||
header('Content-Length: ' . filesize($f));
|
||||
|
||||
if ($type != 'text/css' || dcCore::app()->blog->settings->get('system')->get('url_scan') == 'path_info') {
|
||||
readfile($f);
|
||||
} else {
|
||||
echo preg_replace(
|
||||
'#url\((?!(http:)|/)#',
|
||||
'url(' . dcCore::app()->blog->url . dcCore::app()->url->getBase('noodles_file') . '/',
|
||||
(string) file_get_contents($f)
|
||||
);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
# Search noodles files like JS, CSS in default-templates subdirectories
|
||||
private static function searchTplFiles(string $file): string
|
||||
{
|
||||
if (str_contains($file, '..')) {
|
||||
return '';
|
||||
}
|
||||
$paths = dcCore::app()->tpl->getPath();
|
||||
|
||||
foreach ($paths as $path) {
|
||||
if (preg_match('/tpl(\/|)$/', $path)) {
|
||||
$path = Path::real($path . '/..');
|
||||
}
|
||||
if (file_exists($path . '/' . $file)) {
|
||||
return $path . '/' . $file;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|