aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2022-02-20 20:18:24 +0000
committerMario <mario@mariovavti.com>2022-02-20 20:18:24 +0000
commit2a60f1cc6ed49ab559090c831788308fe3df0706 (patch)
tree1a5a0a28cbf4aaeb38dc0b08f03c874833500e78
parent2ddff785e55745045bc9a742b2287a500e5370a6 (diff)
downloadvolse-hubzilla-2a60f1cc6ed49ab559090c831788308fe3df0706.tar.gz
volse-hubzilla-2a60f1cc6ed49ab559090c831788308fe3df0706.tar.bz2
volse-hubzilla-2a60f1cc6ed49ab559090c831788308fe3df0706.zip
merge branch pdledit_gui into dev - many widgets still miss their description and requirements (this is work in progress)
-rw-r--r--Zotlabs/Module/Pdledit_gui.php553
-rw-r--r--Zotlabs/Web/WebServer.php3
-rw-r--r--Zotlabs/Widget/Activity_filter.php7
-rw-r--r--Zotlabs/Widget/Activity_order.php8
-rw-r--r--Zotlabs/Widget/Admin.php5
-rw-r--r--Zotlabs/Widget/Affinity.php12
-rw-r--r--Zotlabs/Widget/Filer.php1
-rw-r--r--Zotlabs/Widget/Hq_controls.php7
-rw-r--r--Zotlabs/Widget/Messages.php8
-rw-r--r--Zotlabs/Widget/Notes.php11
-rw-r--r--Zotlabs/Widget/Notifications.php6
-rw-r--r--app/pdledit_gui.apd (renamed from app/pdledit.apd)4
-rw-r--r--include/plugin.php73
-rw-r--r--view/css/full.css5
-rw-r--r--view/css/minimal.css3
-rw-r--r--view/css/mod_pdledit_gui.css3
-rw-r--r--view/pdl/mod_pdledit_gui.pdl1
-rw-r--r--view/php/default.php14
-rw-r--r--view/php/full.php15
-rw-r--r--view/php/minimal.php39
-rw-r--r--view/php/none.php9
-rw-r--r--view/php/zen.php16
-rw-r--r--view/theme/redbasic/js/redbasic.js15
-rw-r--r--view/tpl/pdledit_gui.tpl243
-rw-r--r--view/tpl/pdledit_gui_item.tpl18
-rw-r--r--view/tpl/pdledit_gui_templates.tpl11
26 files changed, 1049 insertions, 41 deletions
diff --git a/Zotlabs/Module/Pdledit_gui.php b/Zotlabs/Module/Pdledit_gui.php
new file mode 100644
index 000000000..b550b92d3
--- /dev/null
+++ b/Zotlabs/Module/Pdledit_gui.php
@@ -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;
+ }
+}
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
index de0d5a883..70c6eb9b8 100644
--- a/Zotlabs/Web/WebServer.php
+++ b/Zotlabs/Web/WebServer.php
@@ -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.
diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php
index b7a69752e..daaf5fb67 100644
--- a/Zotlabs/Widget/Activity_filter.php
+++ b/Zotlabs/Widget/Activity_filter.php
@@ -1,5 +1,12 @@
<?php
+/**
+ * * Name: Activity filters
+ * * Description: Filters for the network stream
+ * * Requires: network
+ */
+
+
namespace Zotlabs\Widget;
use App;
diff --git a/Zotlabs/Widget/Activity_order.php b/Zotlabs/Widget/Activity_order.php
index d3fe2a30f..e8ee11508 100644
--- a/Zotlabs/Widget/Activity_order.php
+++ b/Zotlabs/Widget/Activity_order.php
@@ -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';
diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php
index f349377a0..0a7a6925f 100644
--- a/Zotlabs/Widget/Admin.php
+++ b/Zotlabs/Widget/Admin.php
@@ -1,5 +1,10 @@
<?php
+/**
+ * * Name: Admin menu
+ * * Requires: admin
+ */
+
namespace Zotlabs\Widget;
class Admin {
diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php
index 572af0503..e083e576c 100644
--- a/Zotlabs/Widget/Affinity.php
+++ b/Zotlabs/Widget/Affinity.php
@@ -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 {
}
}
-
+
diff --git a/Zotlabs/Widget/Filer.php b/Zotlabs/Widget/Filer.php
index 5d6f96a87..bac1c339e 100644
--- a/Zotlabs/Widget/Filer.php
+++ b/Zotlabs/Widget/Filer.php
@@ -10,7 +10,6 @@ class Filer {
if(! local_channel())
return '';
-
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();
diff --git a/Zotlabs/Widget/Hq_controls.php b/Zotlabs/Widget/Hq_controls.php
index 91335fd76..7b1fe817d 100644
--- a/Zotlabs/Widget/Hq_controls.php
+++ b/Zotlabs/Widget/Hq_controls.php
@@ -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;
diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php
index 86ce2fa29..d045ae85b 100644
--- a/Zotlabs/Widget/Messages.php
+++ b/Zotlabs/Widget/Messages.php
@@ -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;
diff --git a/Zotlabs/Widget/Notes.php b/Zotlabs/Widget/Notes.php
index 659b62390..2e8e04e93 100644
--- a/Zotlabs/Widget/Notes.php
+++ b/Zotlabs/Widget/Notes.php
@@ -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;
}
}
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
index a818ae40a..0e02d5cc1 100644
--- a/Zotlabs/Widget/Notifications.php
+++ b/Zotlabs/Widget/Notifications.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * * Name: Notifications
+ * * Description: Shows all kind of notifications
+ * * Author: Mario Vavti
+ */
+
namespace Zotlabs\Widget;
class Notifications {
diff --git a/app/pdledit.apd b/app/pdledit_gui.apd
index e13c04cb5..85a95a067 100644
--- a/app/pdledit.apd
+++ b/app/pdledit_gui.apd
@@ -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
diff --git a/include/plugin.php b/include/plugin.php
index 95c9882d0..25fa22e10 100644
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -794,6 +794,79 @@ function get_theme_info($theme){
}
/**
+ * @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.
*
* The screenshot is expected as view/theme/$theme/img/screenshot.[png|jpg].
diff --git a/view/css/full.css b/view/css/full.css
index 3f9a01d24..1a36c9b08 100644
--- a/view/css/full.css
+++ b/view/css/full.css
@@ -7,7 +7,6 @@ header #banner {
}
section {
- display: block;
- min-height: 112px;
- margin: 50px 10px;
+ height: 100vh;
+ padding: 4.5rem 7px 200px 7px;
}
diff --git a/view/css/minimal.css b/view/css/minimal.css
new file mode 100644
index 000000000..3bd04a5df
--- /dev/null
+++ b/view/css/minimal.css
@@ -0,0 +1,3 @@
+section {
+ height: 100vh;
+}
diff --git a/view/css/mod_pdledit_gui.css b/view/css/mod_pdledit_gui.css
new file mode 100644
index 000000000..dcda842dc
--- /dev/null
+++ b/view/css/mod_pdledit_gui.css
@@ -0,0 +1,3 @@
+.aside_wrapper {
+ min-height: 70vh;
+}
diff --git a/view/pdl/mod_pdledit_gui.pdl b/view/pdl/mod_pdledit_gui.pdl
new file mode 100644
index 000000000..7590b7fa0
--- /dev/null
+++ b/view/pdl/mod_pdledit_gui.pdl
@@ -0,0 +1 @@
+[template]none[/template]
diff --git a/view/php/default.php b/view/php/default.php
index 64d58a0c1..10e150906 100644
--- a/view/php/default.php
+++ b/view/php/default.php
@@ -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">
diff --git a/view/php/full.php b/view/php/full.php
index 1a9cd9a84..d855fb650 100644
--- a/view/php/full.php
+++ b/view/php/full.php
@@ -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>
diff --git a/view/php/minimal.php b/view/php/minimal.php
index 3572f3b5c..3fab0c5f9 100644
--- a/view/php/minimal.php
+++ b/view/php/minimal.php
@@ -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>
+
diff --git a/view/php/none.php b/view/php/none.php
index 51d0e83dc..5e92310b7 100644
--- a/view/php/none.php
+++ b/view/php/none.php
@@ -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']; ?>
diff --git a/view/php/zen.php b/view/php/zen.php
index a96cf722f..24aae951b 100644
--- a/view/php/zen.php
+++ b/view/php/zen.php
@@ -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>
diff --git a/view/theme/redbasic/js/redbasic.js b/view/theme/redbasic/js/redbasic.js
index c0c03d4f8..04469cb85 100644
--- a/view/theme/redbasic/js/redbasic.js
+++ b/view/theme/redbasic/js/redbasic.js
@@ -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);
diff --git a/view/tpl/pdledit_gui.tpl b/view/tpl/pdledit_gui.tpl
new file mode 100644
index 000000000..8c4ca3e50
--- /dev/null
+++ b/view/tpl/pdledit_gui.tpl
@@ -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>
diff --git a/view/tpl/pdledit_gui_item.tpl b/view/tpl/pdledit_gui_item.tpl
new file mode 100644
index 000000000..9d0095ed4
--- /dev/null
+++ b/view/tpl/pdledit_gui_item.tpl
@@ -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>
diff --git a/view/tpl/pdledit_gui_templates.tpl b/view/tpl/pdledit_gui_templates.tpl
new file mode 100644
index 000000000..0f3d8a7b6
--- /dev/null
+++ b/view/tpl/pdledit_gui_templates.tpl
@@ -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>