merge branch pdledit_gui into dev - many widgets still miss their description and requirements (this is work in progress)

This commit is contained in:
Mario
2022-02-20 20:18:24 +00:00
parent 2ddff785e5
commit 2a60f1cc6e
26 changed files with 1049 additions and 41 deletions

View File

@@ -0,0 +1,553 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Render\Comanche;
use Zotlabs\Lib\Libsync;
class Pdledit_gui extends Controller {
function post() {
if (!local_channel()) {
return;
}
if (!$_REQUEST['module']) {
return;
}
$module = $_REQUEST['module'];
$ret = [
'success' => false,
'module' => $module
];
if ($_REQUEST['reset']) {
del_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl');
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save']) {
if (!$_REQUEST['data']) {
return $ret;
}
$data = json_decode($_REQUEST['data'],true);
$stored_pdl_result = self::get_pdl($module);
$pdl = $stored_pdl_result['pdl'];
foreach ($data as $region => $entries) {
$region_pdl = '';
foreach ($entries as $entry) {
$region_pdl .= base64_decode($entry) . "\r\n";
}
$pdl = preg_replace('/\[region=' . $region . '\](.*?)\[\/region\]/ism', '[region=' . $region . ']' . "\r\n" . $region_pdl . "\r\n" . '[/region]', $pdl);
}
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save_src']) {
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($_REQUEST['src']));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save_template']) {
if (!$_REQUEST['data']) {
return $ret;
}
$template = $_REQUEST['data'][0]['value'];
$pdl_result = self::get_pdl($module);
$stored_template = self::get_template($pdl_result['pdl']);
if ($template === $stored_template) {
$ret['success'] = true;
return $ret;
}
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl_result['pdl'], $matches);
if ($cnt) {
$pdl = str_replace('[template]' . $stored_template . '[/template]', '[template]' . $template . '[/template]', $pdl_result['pdl']);
}
else {
$pdl = '[template]' . $template . '[/template]' . "\r\n";
$pdl .= $pdl_result['pdl'];
}
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
}
function get() {
if(! local_channel()) {
return EMPTY_STR;
}
$module = argv(1);
if (!$module) {
goaway(z_root() . '/pdledit_gui/hq');
}
$pdl_result = self::get_pdl($module);
$pdl = $pdl_result['pdl'];
$modified = $pdl_result['modified'];
if(!$pdl) {
return t('Layout not found');
}
$template = self::get_template($pdl);
$template_info = self::get_template_info($template);
if(empty($template_info['contentregion'])) {
return t('This template does not support pdledi_gui (no content regions defined)');
}
App::$page['template'] = $template;
$regions = self::get_regions($pdl);
foreach ($regions as $k => $v) {
$region_str = '';
if (is_array($v)) {
ksort($v);
foreach ($v as $entry) {
// Get the info from the file and replace entry if we get anything useful
$widget_info = get_widget_info($entry['name']);
$entry['name'] = (($widget_info['name']) ? $widget_info['name'] : $entry['name']);
$entry['desc'] = (($widget_info['description']) ? $widget_info['description'] : $entry['desc']);
$region_str .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry
]);
}
}
App::$layout['region_' . $k] = $region_str;
}
$templates = self::get_templates();
$templates_html = replace_macros(get_markup_template('pdledit_gui_templates.tpl'), [
'$templates' => $templates,
'$active' => $template
]);
$items_html = '';
//$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
//'$entry' => [
//'type' => 'content',
//'name' => t('Main page content'),
//'src' => base64_encode('$content')
//],
//'$disable_controls' => true
//]);
foreach (self::get_widgets($module) as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
foreach (self::get_menus() as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
foreach (self::get_blocks() as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
App::$layout['region_content'] .= replace_macros(get_markup_template('pdledit_gui.tpl'), [
'$content_regions' => $template_info['contentregion'],
'$page_src' => base64_encode($pdl),
'$templates' => base64_encode($templates_html),
'$modules' => base64_encode(self::get_modules()),
'$items' => base64_encode($items_html),
'$module_modified' => $modified,
'$module' => $module
]);
}
function get_templates() {
$ret = [];
$files = glob('view/php/*.php');
if($files) {
foreach($files as $f) {
$name = basename($f, '.php');
$x = get_template_info($name);
if(!empty($x['contentregion'])) {
$ret[] = [
'name' => $name,
'desc' => $x['description']
];
}
}
}
return $ret;
}
function get_modules() {
$ret = '';
$files = glob('Zotlabs/Module/*.php');
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f,'.php'));
if ($name === 'admin' && !is_site_admin()) {
continue;
}
$x = theme_include('mod_' . $name . '.pdl');
if($x) {
$ret .= '<div class="mb-2"><a href="pdledit_gui/' . $name . '">' . $name . '</a></div>';
}
}
}
return $ret;
}
function get_widgets($module) {
$ret = [];
$checkpaths = [
'Zotlabs/Widget/*.php'
];
foreach ($checkpaths as $path) {
$files = glob($path);
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f, '.php'));
$widget_info = get_widget_info($name);
if ($widget_info['requires'] && strpos($widget_info['requires'], 'admin') !== false && !is_site_admin()) {
continue;
}
if ($widget_info['requires'] && strpos($widget_info['requires'], $module) === false) {
continue;
}
$ret[] = [
'type' => 'widget',
'name' => $widget_info['name'] ?? $name,
'desc' => $widget_info['description'] ?? '',
'src' => base64_encode('[widget=' . $name . '][/widget]')
];
}
}
}
return $ret;
}
function get_menus() {
$ret = [];
$r = q("select * from menu where menu_channel_id = %d and menu_flags = 0",
intval(local_channel())
);
foreach ($r as $rr) {
$name = $rr['menu_name'];
$desc = $rr['menu_desc'];
$ret[] = [
'type' => 'menu',
'name' => $name,
'desc' => $desc,
'src' => base64_encode('[menu]' . $name . '[/menu]')
];
}
return $ret;
}
function get_blocks() {
$ret = [];
$r = q("select v, title, summary from item join iconfig on iconfig.iid = item.id and item.uid = %d
and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'",
intval(local_channel())
);
foreach ($r as $rr) {
$name = $rr['v'];
$desc = (($rr['title']) ? $rr['title'] : $rr['summary']);
$ret[] = [
'type' => 'block',
'name' => $name,
'desc' => $desc,
'src' => base64_encode('[block]' . $name . '[/block]')
];
}
return $ret;
}
function get_template($pdl) {
$ret = 'default';
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl, $matches);
if($cnt && isset($matches[1])) {
$ret = trim($matches[1]);
}
return $ret;
}
function get_regions($pdl) {
$ret = [];
$supported_regions = ['aside', 'content', 'right_aside'];
$cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $pdl, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
if (!in_array($mtch[1], $supported_regions)) {
continue;
}
$ret[$mtch[1]] = self::parse_region($mtch[2]);
}
}
return $ret;
}
function parse_region($pdl) {
$ret = [];
$cnt = preg_match_all('/\$content\b/ism', $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[0][1]);
$name = trim($mtch[0][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'content',
'name' => t('Main page content'),
'desc' => t('The main page content can not be edited!'),
'src' => $src
];
}
}
$cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'menu',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
// menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu]
// allows different menu renderings to be applied
//$cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->menu(trim($mtch[2]),$mtch[1]),$s);
//}
//}
$cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'block',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
//$cnt = preg_match_all("/\[block=(.*?)\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->block(trim($mtch[2]),trim($mtch[1])),$s);
//}
//}
//$cnt = preg_match_all("/\[js\](.*?)\[\/js\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->js(trim($mtch[1])),$s);
//}
//}
//$cnt = preg_match_all("/\[css\](.*?)\[\/css\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->css(trim($mtch[1])),$s);
//}
//}
// need to modify this to accept parameters
$cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'widget',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
return $ret;
}
/**
* @brief Parse template comment in search of template info.
*
* like
* \code
* * Name: MyWidget
* * Description: A widget
* * Version: 1.2.3
* * Author: John <profile url>
* * Author: Jane <email>
* * ContentRegionID: some_id
* * ContentRegionID: some_other_id
* *
*\endcode
* @param string $template the name of the template
* @return array with the information
*/
function get_template_info($template){
$m = [];
$info = [
'name' => $template,
'description' => '',
'author' => [],
'maintainer' => [],
'version' => '',
'contentregion' => []
];
$checkpaths = [
'view/php/' . $template . '.php',
];
$template_found = false;
foreach ($checkpaths as $path) {
if (is_file($path)) {
$template_found = true;
$f = file_get_contents($path);
break;
}
}
if(!($template_found && $f))
return $info;
$f = escape_tags($f);
$r = preg_match('|/\*.*\*/|msU', $f, $m);
if ($r) {
$ll = explode("\n", $m[0]);
foreach($ll as $l) {
$l = trim($l, "\t\n\r */");
if ($l != ''){
list($k, $v) = array_map('trim', explode(':', $l, 2));
$k = strtolower($k);
if (in_array($k, ['author', 'maintainer'])){
$r = preg_match('|([^<]+)<([^>]+)>|', $v, $m);
if ($r) {
$info[$k][] = array('name' => $m[1], 'link' => $m[2]);
} else {
$info[$k][] = array('name' => $v);
}
}
elseif (in_array($k, ['contentregion'])){
$info[$k][] = array_map('trim', explode(',', $v));
}
else {
$info[$k] = $v;
}
}
}
}
return $info;
}
function get_pdl($module) {
$ret = [
'pdl' => null,
'modified' => true
];
$pdl_path = 'mod_' . $module . '.pdl';
$ret['pdl'] = get_pconfig(local_channel(), 'system', $pdl_path);
if(!$ret['pdl']) {
$pdl_path = theme_include($pdl_path);
if ($pdl_path) {
$ret['pdl'] = file_get_contents($pdl_path);
$ret['modified'] = false;
}
}
return $ret;
}
}

View File

@@ -107,7 +107,8 @@ class WebServer {
$Router->Dispatch();
$this->set_homebase();
// TODO: this is not used for anything atm and messes up comanche templates by adding some javascript
//$this->set_homebase();
// now that we've been through the module content, see if the page reported
// a permission problem and if so, a 403 response would seem to be in order.

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: Activity filters
* * Description: Filters for the network stream
* * Requires: network
*/
namespace Zotlabs\Widget;
use App;

View File

@@ -2,6 +2,12 @@
namespace Zotlabs\Widget;
/**
* * Name: Activity order
* * Description: Order the network stream by posted date, last commented or by date unthreaded
* * Requires: network
*/
class Activity_order {
function widget($arr) {
@@ -22,7 +28,7 @@ class Activity_order {
switch($_GET['order']){
case 'post':
$postord_active = 'active';
set_pconfig(local_channel(), 'mod_network', 'order', 1);
set_pconfig(local_channel(), 'mod_network', 'order', 1);
break;
case 'comment':
$commentord_active = 'active';

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Admin menu
* * Requires: admin
*/
namespace Zotlabs\Widget;
class Admin {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Affinity Tool
* * Description: Filter the network stream by affinity, requires the Affinity Tool App
* * Requires: network
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;
@@ -13,7 +19,7 @@ class Affinity {
if(! Apps::system_app_installed(local_channel(),'Affinity Tool'))
return;
$default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0);
$default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99);
@@ -54,7 +60,7 @@ class Affinity {
'$refresh' => t('Refresh'),
'$labels' => $label_str,
));
$arr = array('html' => $x);
call_hooks('main_slider',$arr);
@@ -63,4 +69,4 @@ class Affinity {
}
}

View File

@@ -10,7 +10,6 @@ class Filer {
if(! local_channel())
return '';
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: HQ Controls
* * Description: Control buttons for the HQ module
* * Author: Mario Vavti
* * Requires: hq
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;

View File

@@ -1,5 +1,13 @@
<?php
/**
* * Name: HQ Messages
* * Description: Quick access to messages, direct messages, starred messages (if enabled) and notifications
* * Author: Mario Vavti
* * Requires: hq
*/
namespace Zotlabs\Widget;
use App;

View File

@@ -1,5 +1,13 @@
<?php
/**
* * Name: Notes
* * Description: A simple notes widget, requires the Notes App
* * Author: Mike Macgirvin
* * Author: Mario Vavti
* * Maintainer: Mario Vavti
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;
@@ -33,9 +41,6 @@ class Notes {
]
));
return $o;
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Notifications
* * Description: Shows all kind of notifications
* * Author: Mario Vavti
*/
namespace Zotlabs\Widget;
class Notifications {

View File

@@ -1,5 +1,5 @@
version: 3
url: $baseurl/pdledit
version: 1
url: $baseurl/pdledit_gui
requires: local_channel
name: PDL Editor
photo: icon:object-group

View File

@@ -793,6 +793,79 @@ function get_theme_info($theme){
return $info;
}
/**
* @brief Parse template comment in search of template info.
*
* like
* \code
* * Name: MyWidget
* * Description: A widget
* * Version: 1.2.3
* * Author: John <profile url>
* * Author: Jane <email>
* * ContentRegionID: some_id
* * ContentRegionID: some_other_id
* *
*\endcode
* @param string $widget the name of the widget
* @return array with the information
*/
function get_template_info($template){
$m = array();
$info = array(
'name' => $template,
'description' => '',
'author' => array(),
'maintainer' => array(),
'version' => '',
'content_regions' => []
);
$checkpaths = [
"view/php/$template.php",
];
$template_found = false;
foreach ($checkpaths as $path) {
if (is_file($path)) {
$template_found = true;
$f = file_get_contents($path);
break;
}
}
if(! ($template_found && $f))
return $info;
$f = escape_tags($f);
$r = preg_match("|/\*.*\*/|msU", $f, $m);
if ($r) {
$ll = explode("\n", $m[0]);
foreach( $ll as $l ) {
$l = trim($l, "\t\n\r */");
if ($l != ""){
list($k, $v) = array_map("trim", explode(":", $l, 2));
$k = strtolower($k);
if ($k == 'author' || $k == 'maintainer'){
$r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
if ($r) {
$info[$k][] = array('name' => $m[1], 'link' => $m[2]);
} else {
$info[$k][] = array('name' => $v);
}
}
else {
$info[$k] = $v;
}
}
}
}
return $info;
}
/**
* @brief Returns the theme's screenshot.
*

View File

@@ -7,7 +7,6 @@ header #banner {
}
section {
display: block;
min-height: 112px;
margin: 50px 10px;
height: 100vh;
padding: 4.5rem 7px 200px 7px;
}

3
view/css/minimal.css Normal file
View File

@@ -0,0 +1,3 @@
section {
height: 100vh;
}

View File

@@ -0,0 +1,3 @@
.aside_wrapper {
min-height: 70vh;
}

View File

@@ -0,0 +1 @@
[template]none[/template]

View File

@@ -1,3 +1,15 @@
<?php
/**
* * Name: default
* * Description: Hubzilla default 3-column layout
* * Version: 1
* * Author: Mario Vavti
* * Maintainer: Mario Vavti
* * ContentRegion: aside, left_aside_wrapper
* * ContentRegion: content, region_2
* * ContentRegion: right_aside, right_aside_wrapper
*/
?>
<!DOCTYPE html >
<html prefix="og: http://ogp.me/ns#">
<head>
@@ -8,7 +20,7 @@
<body <?php if($page['direction']) echo 'dir="rtl"' ?> >
<?php if(x($page,'banner')) echo $page['banner']; ?>
<header><?php if(x($page,'header')) echo $page['header']; ?></header>
<?php if(x($page,'nav')) echo $page['nav']; ?></nav>
<?php if(x($page,'nav')) echo $page['nav']; ?>
<main>
<div class="content">
<div class="columns">

View File

@@ -1,3 +1,13 @@
<?php
/**
* * Name: full
* * Description: A single column full width layout with the hubzilla navbar
* * Version: 1
* * Author: None
* * Maintainer: None
* * ContentRegion: content, region_1
*/
?>
<!DOCTYPE html >
<html prefix="og: http://ogp.me/ns#">
<head>
@@ -8,8 +18,9 @@
<body <?php if($page['direction']) echo 'dir="rtl"' ?> >
<?php if(x($page,'banner')) echo $page['banner']; ?>
<header><?php if(x($page,'header')) echo $page['header']; ?></header>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark"><?php if(x($page,'nav')) echo $page['nav']; ?></nav>
<section id="region_2"><?php if(x($page,'content')) echo $page['content']; ?>
<?php if(x($page,'nav')) echo $page['nav']; ?>
<section id="region_1">
<?php if(x($page,'content')) echo $page['content']; ?>
<div id="page-footer"></div>
</section>
</body>

View File

@@ -1,14 +1,25 @@
<!DOCTYPE html >
<html prefix="og: http://ogp.me/ns#">
<head>
<title><?php if(x($page,'title')) echo $page['title'] ?></title>
<script>var baseurl="<?php echo z_root() ?>";</script>
<?php if(x($page,'htmlhead')) echo $page['htmlhead'] ?>
</head>
<body>
<section style="margin:0px!important; padding:0px!important; float:none!important;display:block!important;"><?php if(x($page,'content')) echo $page['content']; ?>
<div id="page-footer"></div>
</section>
</body>
</html>
<?php
/**
* * Name: full
* * Description: A single column full width layout without a navbar
* * Version: 1
* * Author: None
* * Maintainer: None
* * ContentRegion: content, region_1
*/
?>
<!DOCTYPE html >
<html prefix="og: http://ogp.me/ns#">
<head>
<title><?php if(x($page,'title')) echo $page['title'] ?></title>
<script>var baseurl="<?php echo z_root() ?>";</script>
<?php if(x($page,'htmlhead')) echo $page['htmlhead'] ?>
</head>
<body>
<section id="region_1">
<?php if(x($page,'content')) echo $page['content']; ?>
<div id="page-footer"></div>
</section>
</body>
</html>

View File

@@ -1 +1,10 @@
<?php
/**
* * Name: none
* * Description: A barebones empty single page template
* * Version: 1
* * Author: None
* * Maintainer: None
*/
?>
<?php if(x($page,'content')) echo $page['content']; ?>

View File

@@ -1,11 +1,11 @@
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
<title><?php if(x($page,'title')) echo $page['title'] ?></title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<?php if(x($page,'htmlhead')) echo $page['htmlhead'] ?>
</head>
<body>
<?php if(x($page,'content')) echo $page['content']; ?>
</body>
<head>
<title><?php if(x($page,'title')) echo $page['title'] ?></title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<?php if(x($page,'htmlhead')) echo $page['htmlhead'] ?>
</head>
<body>
<?php if(x($page,'content')) echo $page['content']; ?>
</body>
</html>

View File

@@ -17,8 +17,13 @@ $(document).ready(function() {
}
$('#css3-calc').remove(); // Remove the test element
stickyScroll('.aside_spacer_left', '.aside_spacer_top_left', '.content', parseFloat(window.getComputedStyle(document.querySelector('#region_1')).getPropertyValue('padding-top')), 0);
stickyScroll('.aside_spacer_right', '.aside_spacer_top_right', '.content', parseFloat(window.getComputedStyle(document.querySelector('#region_3')).getPropertyValue('padding-top')), 20);
if (document.querySelector('#region_1')) {
stickyScroll('.aside_spacer_left', '.aside_spacer_top_left', '.content', parseFloat(window.getComputedStyle(document.querySelector('#region_1')).getPropertyValue('padding-top')), 0);
}
if (document.querySelector('#region_3')) {
stickyScroll('.aside_spacer_right', '.aside_spacer_top_right', '.content', parseFloat(window.getComputedStyle(document.querySelector('#region_3')).getPropertyValue('padding-top')), 20);
}
$('#expand-aside').on('click', function() {
if($('main').hasClass('region_1-on')){
@@ -121,8 +126,14 @@ function setStyle(element, cssProperty) {
}
function stickyScroll(sticky, stickyTop, container, topOffset, bottomOffset) {
var lastScrollTop = 0;
var sticky = document.querySelector(sticky);
if (!sticky) {
return;
}
var stickyHeight = sticky.getBoundingClientRect().height;
var stickyTop = document.querySelector(stickyTop);
var content = document.querySelector(container);

243
view/tpl/pdledit_gui.tpl Normal file
View File

@@ -0,0 +1,243 @@
<div id="pdledit_gui_offcanvas" class="offcanvas offcanvas-lg offcanvas-bottom shadow border rounded-top start-50 translate-middle-x" tabindex="-1" data-bs-backdrop="false" data-bs-scroll="true" style="min-width: 300px">
<div id="pdledit_gui_offcanvas_body" class="offcanvas-body"></div>
<div class="offcanvas-header">
<div class="offcanvas-title h3"></div>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
</div>
<div id="pdledit_gui_offcanvas_edit" class="offcanvas offcanvas-lg offcanvas-bottom shadow border rounded-top start-50 translate-middle-x" tabindex="-1" data-bs-backdrop="false" data-bs-scroll="true" style="min-width: 300px">
<div id="pdledit_gui_offcanvas_edit_body" class="offcanvas-body">
<textarea id="pdledit_gui_offcanvas_edit_textarea" class="form-control font-monospace h-100"></textarea>
</div>
<div class="offcanvas-header">
<button id="pdledit_gui_offcanvas_edit_submit" type="button" class="btn btn-primary">Submit</button>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
</div>
<div id="pdledit_gui_offcanvas_submit" class="offcanvas offcanvas-lg offcanvas-bottom shadow border rounded-top start-50 translate-middle-x" tabindex="-1" data-bs-backdrop="false" data-bs-scroll="true" style="min-width: 300px">
<div id="pdledit_gui_offcanvas_submit_body" class="offcanvas-body"></div>
<div class="offcanvas-header">
<button id="pdledit_gui_offcanvas_submit_submit" type="button" class="btn btn-primary">Submit</button>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
</div>
<ul class="nav position-fixed bottom-0 start-50 bg-light translate-middle-x text-uppercase" style="min-width: 300px">
<li class="nav-item">
<a id="pdledit_gui_modules" class="nav-link" href="#">Modules</a>
</li>
<li class="nav-item">
<a id="pdledit_gui_templates" class="nav-link" href="#">Templates</a>
</li>
<li class="nav-item">
<a id="pdledit_gui_items" class="nav-link" href="#">Items</a>
</li>
<li class="nav-item">
<a id="pdledit_gui_src" class="nav-link" href="#">Source</a>
</li>
{{if $module_modified}}
<li class="nav-item">
<a id="pdledit_gui_reset" class="nav-link" href="#">Reset</a>
</li>
{{/if}}
<li class="nav-item">
<a id="pdledit_gui_save" class="nav-link" href="#">Apply</a>
</li>
</ul>
<script>
$(document).ready(function() {
let poi;
let regions = [];
let content_regions = [];
let page_src = atob('{{$page_src}}');
let offcanvas = new bootstrap.Offcanvas(document.getElementById('pdledit_gui_offcanvas'));
let edit_offcanvas = new bootstrap.Offcanvas(document.getElementById('pdledit_gui_offcanvas_edit'));
let submit_offcanvas = new bootstrap.Offcanvas(document.getElementById('pdledit_gui_offcanvas_submit'));
{{foreach $content_regions as $content_region}}
regions.push('{{$content_region.0}}');
content_regions.push('{{$content_region.1}}');
let sortable_{{$content_region.1}} = document.getElementById('{{$content_region.1}}');
new Sortable(sortable_{{$content_region.1}}, {
group: 'shared',
handle: '.pdledit_gui_item_handle',
animation: 150
});
{{/foreach}}
let sortable_items = document.getElementById('pdledit_gui_offcanvas_body');
new Sortable(sortable_items, {
group: {
name: 'shared',
pull: 'clone',
put: false
},
sort: false,
handle: '.pdledit_gui_item_handle',
animation: 150,
onEnd: function (e) {
$(e.item).find('button').removeClass('disabled');
}
});
$(document).on('click', '.pdledit_gui_item_src', function(e) {
poi = this.closest('.pdledit_gui_item');
let src = atob(poi.dataset.src);
$('#pdledit_gui_offcanvas_edit_textarea').val(src);
$('#pdledit_gui_offcanvas_edit_textarea').bbco_autocomplete('comanche');
edit_offcanvas.show();
});
$(document).on('click', '.pdledit_gui_item_remove', function(e) {
poi = this.closest('.pdledit_gui_item');
$(poi).remove();
});
$(document).on('click', '#pdledit_gui_offcanvas_edit_submit', function(e) {
let src = $('#pdledit_gui_offcanvas_edit_textarea').val();
if (poi) {
poi.dataset.src = btoa(src);
}
else {
$.post(
'pdledit_gui',
{
'save_src': 1,
'module': '{{$module}}',
'src': $('#pdledit_gui_offcanvas_edit_textarea').val()
}
)
.done(function(data) {
if (data.success) {
window.location.href = 'pdledit_gui/' + data.module;
}
});
}
edit_offcanvas.hide();
});
$(document).on('click', '#pdledit_gui_offcanvas_submit_submit', function(e) {
if ($('#pdledit_gui_templates_form').length) {
$.post(
'pdledit_gui',
{
'save_template': 1,
'module': '{{$module}}',
'data': $('#pdledit_gui_templates_form').serializeArray()
}
)
.done(function(data) {
if (data.success) {
window.location.href = 'pdledit_gui/' + data.module;
}
});
}
submit_offcanvas.hide();
});
$(document).on('click', '#pdledit_gui_src', function(e) {
e.preventDefault();
poi = null; // this is important!
let obj = {};
content_regions.forEach(function (content_region, i) {
let data_src = [];
$('#' + content_region + ' > .card').each(function () {
data_src.push(atob(this.dataset.src));
});
obj[regions[i]] = data_src;
});
for (let [region, entries] of Object.entries(obj)) {
let region_pdl = '';
entries.forEach(function (entry) {
region_pdl = region_pdl.concat(entry + "\r\n");
});
let regex_str = '\\[region=' + region + '\\](.*?)\\[\\/region\\]';
let replace_str = '[region=' + region + ']' + "\r\n" + region_pdl + "\r\n" + '[/region]'
let regex = new RegExp(regex_str, 'ism');
page_src = page_src.replace(regex, replace_str);
}
$('#pdledit_gui_offcanvas_edit_textarea').val(page_src);
$('#pdledit_gui_offcanvas_edit_textarea').bbco_autocomplete('comanche');
edit_offcanvas.show();
});
$(document).on('click', '#pdledit_gui_items', function(e) {
e.preventDefault();
$('#pdledit_gui_offcanvas_body').html(atob('{{$items}}'));
offcanvas.show();
});
$(document).on('click', '#pdledit_gui_templates', function(e) {
e.preventDefault();
$('#pdledit_gui_offcanvas_submit_body').html(atob('{{$templates}}'));
submit_offcanvas.show();
});
$(document).on('click', '#pdledit_gui_modules', function(e) {
e.preventDefault();
$('#pdledit_gui_offcanvas_body').html(atob('{{$modules}}'));
offcanvas.show();
});
$(document).on('click', '#pdledit_gui_save', function(e) {
e.preventDefault();
let obj = {};
content_regions.forEach(function (content_region, i) {
let data_src = [];
$('#' + content_region + ' > .card').each(function () {
data_src.push(this.dataset.src);
});
obj[regions[i]] = data_src;
});
$.post(
'pdledit_gui',
{
'save': 1,
'module': '{{$module}}',
'data': JSON.stringify(obj)
}
)
.done(function(data) {
if (data.success) {
window.location.href = 'pdledit_gui/' + data.module;
}
});
});
$(document).on('click', '#pdledit_gui_reset', function(e) {
e.preventDefault();
$.post(
'pdledit_gui',
{
'reset': 1,
'module': '{{$module}}'
}
)
.done(function(data) {
if (data.success) {
window.location.href = 'pdledit_gui/' + data.module;
}
});
});
});
</script>

View File

@@ -0,0 +1,18 @@
<div class="pdledit_gui_item card mb-3" data-src="{{$entry.src}}">
<div class="card-header d-flex justify-content-between">
<span class="text-uppercase">{{$entry.name}}</span>
<div class="badge rounded-pill{{if $entry.type === 'widget'}} bg-info text-dark{{/if}}{{if $entry.type === 'content'}} bg-primary{{/if}}{{if $entry.type === 'menu'}} bg-secondary{{/if}}{{if $entry.type === 'block'}} bg-warning text-dark{{/if}}">
{{$entry.type}}
</div>
</div>
<div class="card-body">
{{if $entry.desc}}
<div class="mb-3 text-muted">{{$entry.desc}}</div>
{{/if}}
{{if $entry.type !== 'content'}}
<button type="button" class="btn btn-sm btn-outline-primary pdledit_gui_item_src{{if $disable_controls}} disabled{{/if}}">Edit</button>
<button type="button" class="btn btn-sm btn-outline-danger pdledit_gui_item_remove{{if $disable_controls}} disabled{{/if}}">Remove</button>
<i class="fa fa-fw fa-arrows-alt m-2 float-end cursor-pointer pdledit_gui_item_handle"></i>
{{/if}}
</div>
</div>

View File

@@ -0,0 +1,11 @@
<form id="pdledit_gui_templates_form">
{{foreach $templates as $template}}
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="template" id="id_template_{{$template.name}}" value="{{$template.name}}" {{if $template.name == $active}} checked{{/if}}>
<label class="form-check-label" for="id_template_{{$template.name}}">
{{$template.name}}
</label>
<small class="text-muted">{{$template.desc}}</small>
</div>
{{/foreach}}
</form>