mirror of https://github.com/YGGverse/Yoda.git
yggverse
6 months ago
19 changed files with 664 additions and 884 deletions
@ -1,56 +1,99 @@ |
|||||||
{ |
{ |
||||||
"homepage":"yoda://welcome", |
"window": |
||||||
"interface": |
|
||||||
{ |
{ |
||||||
|
"title":"Yoda", |
||||||
"theme":"Default", |
"theme":"Default", |
||||||
"window": |
"header": |
||||||
{ |
{ |
||||||
"header": |
"enabled":true, |
||||||
|
"button": |
||||||
{ |
{ |
||||||
"enabled":true, |
"close":true |
||||||
"button": |
} |
||||||
{ |
|
||||||
"close":true |
|
||||||
} |
|
||||||
}, |
|
||||||
"navigation": |
|
||||||
{ |
|
||||||
"button": |
|
||||||
{ |
|
||||||
"home":true, |
|
||||||
"back":true, |
|
||||||
"forward":true, |
|
||||||
"reload":true, |
|
||||||
"go":true |
|
||||||
} |
|
||||||
}, |
|
||||||
"width":640, |
|
||||||
"height":480 |
|
||||||
} |
|
||||||
}, |
|
||||||
"resolver": |
|
||||||
{ |
|
||||||
"enabled":true, |
|
||||||
"request": |
|
||||||
{ |
|
||||||
"timeout":1, |
|
||||||
"host": |
|
||||||
[ |
|
||||||
"1.1.1.1", |
|
||||||
"8.8.8.8" |
|
||||||
], |
|
||||||
"record": |
|
||||||
[ |
|
||||||
"A", |
|
||||||
"AAAA" |
|
||||||
] |
|
||||||
}, |
}, |
||||||
"result": |
"width":640, |
||||||
|
"height":480, |
||||||
|
"tab": |
||||||
{ |
{ |
||||||
"shuffle":false, |
"page": |
||||||
"cache": |
|
||||||
{ |
{ |
||||||
"timeout":3600 |
"resolver": |
||||||
|
{ |
||||||
|
"enabled":true, |
||||||
|
"request": |
||||||
|
{ |
||||||
|
"timeout":1, |
||||||
|
"host": |
||||||
|
[ |
||||||
|
"1.1.1.1", |
||||||
|
"8.8.8.8" |
||||||
|
], |
||||||
|
"record": |
||||||
|
[ |
||||||
|
"A", |
||||||
|
"AAAA" |
||||||
|
] |
||||||
|
}, |
||||||
|
"result": |
||||||
|
{ |
||||||
|
"shuffle":false, |
||||||
|
"cache": |
||||||
|
{ |
||||||
|
"timeout":3600 |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"header": |
||||||
|
{ |
||||||
|
"margin":8, |
||||||
|
"button": |
||||||
|
{ |
||||||
|
"home": |
||||||
|
{ |
||||||
|
"visible":true, |
||||||
|
"label":"Home", |
||||||
|
"url":"yoda://welcome" |
||||||
|
}, |
||||||
|
"back": |
||||||
|
{ |
||||||
|
"visible":true, |
||||||
|
"label":"Back" |
||||||
|
}, |
||||||
|
"forward": |
||||||
|
{ |
||||||
|
"visible":true, |
||||||
|
"label":"Forward" |
||||||
|
}, |
||||||
|
"go": |
||||||
|
{ |
||||||
|
"visible":true, |
||||||
|
"label":"Go" |
||||||
|
} |
||||||
|
}, |
||||||
|
"address": |
||||||
|
{ |
||||||
|
"placeholder":"URL or any search term...", |
||||||
|
"length": |
||||||
|
{ |
||||||
|
"max":1024 |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"body": |
||||||
|
{ |
||||||
|
"margin":8 |
||||||
|
}, |
||||||
|
"footer": |
||||||
|
{ |
||||||
|
"margin":8, |
||||||
|
"status": |
||||||
|
{ |
||||||
|
"open": |
||||||
|
{ |
||||||
|
"complete":"{TIME_C} | {RESPONSE_META} | {RESPONSE_LENGTH} bytes | {RESPONSE_SECONDS} seconds" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,70 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Abstract; |
|
||||||
|
|
||||||
abstract class Window |
|
||||||
{ |
|
||||||
public \GtkWindow $window; |
|
||||||
public \GtkCssProvider $css; |
|
||||||
public \GtkStyleContext $style; |
|
||||||
|
|
||||||
public object $config; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
object $config |
|
||||||
) { |
|
||||||
$this->config = $config; |
|
||||||
|
|
||||||
$this->window = new \GtkWindow(); |
|
||||||
|
|
||||||
$this->window->set_size_request( |
|
||||||
$this->config->interface->window->width, |
|
||||||
$this->config->interface->window->height |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->header->enabled) |
|
||||||
{ |
|
||||||
$header = new \GtkHeaderBar(); |
|
||||||
|
|
||||||
$header->set_show_close_button( |
|
||||||
$this->config->interface->window->header->button->close |
|
||||||
); |
|
||||||
|
|
||||||
$this->window->set_titlebar( |
|
||||||
$header |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
$this->window->set_title( |
|
||||||
'Yoda' |
|
||||||
); |
|
||||||
|
|
||||||
$this->window->connect( |
|
||||||
'destroy', |
|
||||||
function() |
|
||||||
{ |
|
||||||
\Gtk::main_quit(); |
|
||||||
} |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public function setTheme( |
|
||||||
string $css |
|
||||||
): void |
|
||||||
{ |
|
||||||
$this->css = new \GtkCssProvider(); |
|
||||||
|
|
||||||
$this->css->load_from_data( |
|
||||||
$css |
|
||||||
); |
|
||||||
|
|
||||||
$this->style = new \GtkStyleContext(); |
|
||||||
|
|
||||||
$this->style->add_provider_for_screen( |
|
||||||
$this->css, |
|
||||||
600 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,273 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Controller; |
|
||||||
|
|
||||||
class Browser extends \Yggverse\Yoda\Abstract\Window |
|
||||||
{ |
|
||||||
public \Yggverse\Yoda\Entity\Box\Tab $tab; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Model\Memory $memory; |
|
||||||
|
|
||||||
public function __construct() |
|
||||||
{ |
|
||||||
parent::__construct( |
|
||||||
\Yggverse\Yoda\Model\File::getConfig() |
|
||||||
); |
|
||||||
|
|
||||||
$this->memory = new \Yggverse\Yoda\Model\Memory(); |
|
||||||
|
|
||||||
$this->tab = new \Yggverse\Yoda\Entity\Box\Tab(); |
|
||||||
|
|
||||||
$this->tab->navigation->address->entry->connect( |
|
||||||
'activate', |
|
||||||
function ($entry) |
|
||||||
{ |
|
||||||
$this->navigate( |
|
||||||
$entry->get_text() |
|
||||||
); |
|
||||||
} |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->go) |
|
||||||
{ |
|
||||||
$this->tab->navigation->go->button->connect( |
|
||||||
'released', |
|
||||||
function ($entry) |
|
||||||
{ |
|
||||||
$this->navigate( |
|
||||||
$this->tab->navigation->address->entry->get_text() |
|
||||||
); |
|
||||||
} |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->reload) |
|
||||||
{ |
|
||||||
$this->tab->navigation->reload->button->connect( |
|
||||||
'released', |
|
||||||
function ($entry) |
|
||||||
{ |
|
||||||
$this->navigate( |
|
||||||
$this->tab->navigation->address->entry->get_text() |
|
||||||
); |
|
||||||
} |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->home && $this->config->homepage) |
|
||||||
{ |
|
||||||
$this->tab->navigation->home->button->connect( |
|
||||||
'released', |
|
||||||
function ($entry) |
|
||||||
{ |
|
||||||
$this->tab->navigation->address->entry->set_text( |
|
||||||
$this->config->homepage |
|
||||||
); |
|
||||||
|
|
||||||
$this->navigate( |
|
||||||
$this->config->homepage |
|
||||||
); |
|
||||||
} |
|
||||||
); |
|
||||||
|
|
||||||
$this->tab->navigation->home->button->set_sensitive( |
|
||||||
!($this->tab->navigation->address->entry->get_text() == $this->config->homepage) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
$this->navigate( |
|
||||||
$this->tab->navigation->address->entry->get_text() |
|
||||||
); |
|
||||||
|
|
||||||
$this->window->add( |
|
||||||
$this->tab->box |
|
||||||
); |
|
||||||
|
|
||||||
$this->window->show_all(); |
|
||||||
} |
|
||||||
|
|
||||||
public function navigate(string $url): void |
|
||||||
{ |
|
||||||
switch (true) |
|
||||||
{ |
|
||||||
case str_starts_with($url, 'gemini://'): |
|
||||||
|
|
||||||
$this->_gemini( |
|
||||||
$url |
|
||||||
); |
|
||||||
|
|
||||||
break; |
|
||||||
|
|
||||||
case str_starts_with($url, 'yoda://'): |
|
||||||
|
|
||||||
$this->_yoda( |
|
||||||
$url |
|
||||||
); |
|
||||||
|
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
|
|
||||||
$this->_yoda( |
|
||||||
'yoda://oops' |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private function _yoda(string $url): void |
|
||||||
{ |
|
||||||
if ($data = \Yggverse\Yoda\Model\Page::get(str_replace('yoda://', '', $url))) |
|
||||||
{ |
|
||||||
$response = new \Yggverse\Gemini\Client\Response( |
|
||||||
$data |
|
||||||
); |
|
||||||
|
|
||||||
$this->tab->content->label->set_text( |
|
||||||
$data |
|
||||||
); |
|
||||||
|
|
||||||
$body = new \Yggverse\Gemini\Gemtext\Body( |
|
||||||
$data |
|
||||||
); |
|
||||||
|
|
||||||
if ($h1 = $body->getH1()) |
|
||||||
{ |
|
||||||
$this->window->set_title( |
|
||||||
$h1[0] |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
else |
|
||||||
{ |
|
||||||
$data = \Yggverse\Yoda\Model\Page::get('Oops'); |
|
||||||
|
|
||||||
$this->tab->content->label->set_text( |
|
||||||
$data |
|
||||||
); |
|
||||||
|
|
||||||
$body = new \Yggverse\Gemini\Gemtext\Body( |
|
||||||
$data |
|
||||||
); |
|
||||||
|
|
||||||
if ($h1 = $body->getH1()) |
|
||||||
{ |
|
||||||
$this->window->set_title( |
|
||||||
$h1[0] |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->home && $this->config->homepage) |
|
||||||
{ |
|
||||||
$this->tab->navigation->home->button->set_sensitive( |
|
||||||
!($url == $this->config->homepage) |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private function _gemini(string $url): void |
|
||||||
{ |
|
||||||
$this->tab->tray->label->set_text( |
|
||||||
sprintf( |
|
||||||
'Open %s...', |
|
||||||
urldecode( |
|
||||||
$url |
|
||||||
) |
|
||||||
) |
|
||||||
); |
|
||||||
|
|
||||||
$start = microtime(true); |
|
||||||
|
|
||||||
$host = null; |
|
||||||
|
|
||||||
if ($this->config->resolver->enabled) |
|
||||||
{ |
|
||||||
$address = new \Yggverse\Net\Address( |
|
||||||
$url |
|
||||||
); |
|
||||||
|
|
||||||
$name = $address->getHost(); |
|
||||||
|
|
||||||
if (!$host = $this->memory->get($name)) |
|
||||||
{ |
|
||||||
$resolve = new \Yggverse\Net\Resolve( |
|
||||||
$this->config->resolver->request->record, |
|
||||||
$this->config->resolver->request->host, |
|
||||||
$this->config->resolver->request->timeout, |
|
||||||
$this->config->resolver->result->shuffle |
|
||||||
); |
|
||||||
|
|
||||||
$resolved = $resolve->address( |
|
||||||
$address |
|
||||||
); |
|
||||||
|
|
||||||
if ($resolved) |
|
||||||
{ |
|
||||||
$host = $resolved->getHost(); |
|
||||||
|
|
||||||
$this->memory->set( |
|
||||||
$name, |
|
||||||
$host |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
$request = new \Yggverse\Gemini\Client\Request( |
|
||||||
$url, |
|
||||||
$host |
|
||||||
); |
|
||||||
|
|
||||||
$raw = $request->getResponse(); |
|
||||||
|
|
||||||
$end = microtime(true); |
|
||||||
|
|
||||||
$response = new \Yggverse\Gemini\Client\Response( |
|
||||||
$raw |
|
||||||
); |
|
||||||
|
|
||||||
$this->tab->content->label->set_text( |
|
||||||
$response->getBody() |
|
||||||
); |
|
||||||
|
|
||||||
$body = new \Yggverse\Gemini\Gemtext\Body( |
|
||||||
$response->getBody() |
|
||||||
); |
|
||||||
|
|
||||||
if ($h1 = $body->getH1()) |
|
||||||
{ |
|
||||||
$this->window->set_title( |
|
||||||
sprintf( |
|
||||||
'%s - Yoda', |
|
||||||
empty($h1[0]) ? $address->getHost() : $h1[0] |
|
||||||
) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
$this->tab->tray->label->set_text( |
|
||||||
sprintf( |
|
||||||
'%s | %s | %d bytes | %s seconds', |
|
||||||
date('c'), |
|
||||||
$response->getMeta() ? $response->getMeta() : $response->getCode(), |
|
||||||
number_format( |
|
||||||
mb_strlen( |
|
||||||
$raw |
|
||||||
) |
|
||||||
), |
|
||||||
round( |
|
||||||
$end - $start, 2 |
|
||||||
) |
|
||||||
) |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->home && $this->config->homepage) |
|
||||||
{ |
|
||||||
$this->tab->navigation->home->button->set_sensitive( |
|
||||||
!($url == $this->config->homepage) |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Box; |
|
||||||
|
|
||||||
class Menu |
|
||||||
{ |
|
||||||
public \GtkBox $box; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Entity\Menu\Bar\Main $main; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
string $name = 'boxMenu' |
|
||||||
) { |
|
||||||
$this->box = new \GtkBox( |
|
||||||
\GtkOrientation::VERTICAL |
|
||||||
); |
|
||||||
|
|
||||||
$this->box->set_name( |
|
||||||
$name |
|
||||||
); |
|
||||||
|
|
||||||
$this->main = new \Yggverse\Yoda\Entity\Menu\Bar\Main(); |
|
||||||
|
|
||||||
$this->box->add( |
|
||||||
$this->main->bar |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,123 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Box; |
|
||||||
|
|
||||||
class Navigation |
|
||||||
{ |
|
||||||
public \GtkBox $box; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Entity\Entry\Address $address; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Entity\Button\Home $home; |
|
||||||
public \Yggverse\Yoda\Entity\Button\Back $back; |
|
||||||
public \Yggverse\Yoda\Entity\Button\Forward $forward; |
|
||||||
public \Yggverse\Yoda\Entity\Button\Reload $reload; |
|
||||||
public \Yggverse\Yoda\Entity\Button\Go $go; |
|
||||||
|
|
||||||
public object $config; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
string $name = 'boxNavigation' |
|
||||||
) { |
|
||||||
$this->config = \Yggverse\Yoda\Model\File::getConfig(); |
|
||||||
|
|
||||||
$this->box = new \GtkBox( |
|
||||||
\GtkOrientation::HORIZONTAL |
|
||||||
); |
|
||||||
|
|
||||||
$this->box->set_name( |
|
||||||
$name |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->home && $this->config->homepage) |
|
||||||
{ |
|
||||||
$this->home = new \Yggverse\Yoda\Entity\Button\Home(); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->home->button, |
|
||||||
false, |
|
||||||
false, |
|
||||||
8 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->back || $this->config->interface->window->navigation->button->forward) |
|
||||||
{ |
|
||||||
$boxBackForward = new \GtkButtonBox( |
|
||||||
\GtkOrientation::HORIZONTAL |
|
||||||
); |
|
||||||
|
|
||||||
$boxBackForward->set_layout( |
|
||||||
\GtkButtonBoxStyle::EXPAND |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->back) |
|
||||||
{ |
|
||||||
$this->back = new \Yggverse\Yoda\Entity\Button\Back(); |
|
||||||
|
|
||||||
$boxBackForward->pack_start( |
|
||||||
$this->back->button, |
|
||||||
false, |
|
||||||
true, |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->forward) |
|
||||||
{ |
|
||||||
$this->forward = new \Yggverse\Yoda\Entity\Button\Forward(); |
|
||||||
|
|
||||||
$boxBackForward->pack_end( |
|
||||||
$this->forward->button, |
|
||||||
false, |
|
||||||
true, |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$boxBackForward, |
|
||||||
false, |
|
||||||
false, |
|
||||||
8 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->reload) |
|
||||||
{ |
|
||||||
$this->reload = new \Yggverse\Yoda\Entity\Button\Reload(); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->reload->button, |
|
||||||
false, |
|
||||||
false, |
|
||||||
8 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
$this->address = new \Yggverse\Yoda\Entity\Entry\Address( |
|
||||||
$this->config->homepage |
|
||||||
); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->address->entry, |
|
||||||
true, |
|
||||||
true, |
|
||||||
8 |
|
||||||
); |
|
||||||
|
|
||||||
if ($this->config->interface->window->navigation->button->go) |
|
||||||
{ |
|
||||||
$this->go = new \Yggverse\Yoda\Entity\Button\Go(); |
|
||||||
|
|
||||||
$this->box->pack_end( |
|
||||||
$this->go->button, |
|
||||||
false, |
|
||||||
false, |
|
||||||
8 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Box; |
|
||||||
|
|
||||||
class Tab |
|
||||||
{ |
|
||||||
public \GtkBox $box; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Entity\Box\Menu $menu; |
|
||||||
public \Yggverse\Yoda\Entity\Box\Navigation $navigation; |
|
||||||
public \Yggverse\Yoda\Entity\Label\Content $content; |
|
||||||
public \Yggverse\Yoda\Entity\Label\Tray $tray; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
string $name = 'boxTab' |
|
||||||
) { |
|
||||||
// Init container |
|
||||||
$this->box = new \GtkBox( |
|
||||||
\GtkOrientation::VERTICAL |
|
||||||
); |
|
||||||
|
|
||||||
$this->box->set_name( |
|
||||||
$name |
|
||||||
); |
|
||||||
|
|
||||||
// Init dependencies |
|
||||||
$this->menu = new \Yggverse\Yoda\Entity\Box\Menu(); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->menu->box, |
|
||||||
false, |
|
||||||
true, |
|
||||||
0 |
|
||||||
); |
|
||||||
|
|
||||||
$this->navigation = new \Yggverse\Yoda\Entity\Box\Navigation(); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->navigation->box, |
|
||||||
false, |
|
||||||
true, |
|
||||||
8 |
|
||||||
); |
|
||||||
|
|
||||||
$this->content = new \Yggverse\Yoda\Entity\Label\Content(); |
|
||||||
|
|
||||||
$scroll = new \GtkScrolledWindow(); |
|
||||||
|
|
||||||
$scroll->add( |
|
||||||
$this->content->label |
|
||||||
); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$scroll, |
|
||||||
true, |
|
||||||
true, |
|
||||||
0 |
|
||||||
); |
|
||||||
|
|
||||||
$this->tray = new \Yggverse\Yoda\Entity\Label\Tray(); |
|
||||||
|
|
||||||
$this->box->pack_start( |
|
||||||
$this->tray->label, |
|
||||||
false, |
|
||||||
true, |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Button; |
|
||||||
|
|
||||||
class Back |
|
||||||
{ |
|
||||||
public \GtkButton $button; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $label = 'Back' |
|
||||||
) { |
|
||||||
$this->button = \GtkButton::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Button; |
|
||||||
|
|
||||||
class Forward |
|
||||||
{ |
|
||||||
public \GtkButton $button; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $label = 'Forward' |
|
||||||
) { |
|
||||||
$this->button = \GtkButton::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Button; |
|
||||||
|
|
||||||
class Go |
|
||||||
{ |
|
||||||
public \GtkButton $button; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $label = 'Go' |
|
||||||
) { |
|
||||||
$this->button = \GtkButton::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Button; |
|
||||||
|
|
||||||
class Home |
|
||||||
{ |
|
||||||
public \GtkButton $button; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $label = 'Home' |
|
||||||
) { |
|
||||||
$this->button = \GtkButton::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Button; |
|
||||||
|
|
||||||
class Reload |
|
||||||
{ |
|
||||||
public \GtkButton $button; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $label = 'Reload' |
|
||||||
) { |
|
||||||
$this->button = \GtkButton::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Entry; |
|
||||||
|
|
||||||
class Address |
|
||||||
{ |
|
||||||
public \GtkEntry $entry; |
|
||||||
|
|
||||||
public function __construct( |
|
||||||
?string $text = null, |
|
||||||
?string $placeholder = 'URL or any search term...' |
|
||||||
) { |
|
||||||
$this->entry = new \GtkEntry(); |
|
||||||
|
|
||||||
$this->entry->set_text( |
|
||||||
$text |
|
||||||
); |
|
||||||
|
|
||||||
$this->entry->set_placeholder_text( |
|
||||||
$placeholder |
|
||||||
); |
|
||||||
|
|
||||||
$this->entry->set_max_length( |
|
||||||
1024 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,37 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Label; |
|
||||||
|
|
||||||
class Content |
|
||||||
{ |
|
||||||
public \GtkLabel $label; |
|
||||||
|
|
||||||
public function __construct(string $value = '') |
|
||||||
{ |
|
||||||
$this->label = new \GtkLabel( |
|
||||||
$value |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_use_markup( |
|
||||||
true |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_selectable( |
|
||||||
true |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_line_wrap( |
|
||||||
true |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_xalign( |
|
||||||
0 |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_yalign( |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Label; |
|
||||||
|
|
||||||
class Tray |
|
||||||
{ |
|
||||||
public \GtkLabel $label; |
|
||||||
|
|
||||||
public function __construct(string $value = '') |
|
||||||
{ |
|
||||||
$this->label = new \GtkLabel( |
|
||||||
$value |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_use_markup( |
|
||||||
true |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_selectable( |
|
||||||
false |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_xalign( |
|
||||||
0 |
|
||||||
); |
|
||||||
|
|
||||||
$this->label->set_yalign( |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Menu\Bar; |
|
||||||
|
|
||||||
class Main |
|
||||||
{ |
|
||||||
public \GtkMenuBar $bar; |
|
||||||
|
|
||||||
public \Yggverse\Yoda\Entity\Menu\Item\Yoda $yoda; |
|
||||||
|
|
||||||
public function __construct() |
|
||||||
{ |
|
||||||
$this->bar = new \GtkMenuBar(); |
|
||||||
|
|
||||||
$this->yoda = new \Yggverse\Yoda\Entity\Menu\Item\Yoda(); |
|
||||||
|
|
||||||
$this->bar->append( |
|
||||||
$this->yoda->item |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Menu\Item; |
|
||||||
|
|
||||||
class Quit |
|
||||||
{ |
|
||||||
public \GtkMenuItem $item; |
|
||||||
|
|
||||||
public function __construct(string $label = 'Quit') |
|
||||||
{ |
|
||||||
$this->item = \GtkMenuItem::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
|
|
||||||
$this->activate(); |
|
||||||
} |
|
||||||
|
|
||||||
public function activate(): void |
|
||||||
{ |
|
||||||
$this->item->connect( |
|
||||||
'activate', |
|
||||||
function () |
|
||||||
{ |
|
||||||
\Gtk::main_quit(); |
|
||||||
} |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
declare(strict_types=1); |
|
||||||
|
|
||||||
namespace Yggverse\Yoda\Entity\Menu\Item; |
|
||||||
|
|
||||||
class Yoda |
|
||||||
{ |
|
||||||
public \GtkMenuItem $item; |
|
||||||
|
|
||||||
public function __construct(string $label = 'Yoda') |
|
||||||
{ |
|
||||||
$this->item = \GtkMenuItem::new_with_label( |
|
||||||
$label |
|
||||||
); |
|
||||||
|
|
||||||
$children = new \GtkMenu(); |
|
||||||
|
|
||||||
$quit = new \Yggverse\Yoda\Entity\Menu\Item\Quit(); |
|
||||||
|
|
||||||
$children->append( |
|
||||||
$quit->item |
|
||||||
); |
|
||||||
|
|
||||||
$this->item->set_submenu( |
|
||||||
$children |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,525 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Tab; |
||||||
|
|
||||||
|
class Page |
||||||
|
{ |
||||||
|
public \Yggverse\Yoda\Model\Memory $memory; |
||||||
|
|
||||||
|
public \GtkBox $box, |
||||||
|
$header, |
||||||
|
$body, |
||||||
|
$footer; |
||||||
|
|
||||||
|
public \GtkButton $home, |
||||||
|
$back, |
||||||
|
$forward, |
||||||
|
$go; |
||||||
|
|
||||||
|
public \GtkEntry $address; |
||||||
|
|
||||||
|
public \GtkLabel $content, |
||||||
|
$status; |
||||||
|
|
||||||
|
public \GtkScrolledWindow $container; |
||||||
|
|
||||||
|
public object $config; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
?string $url = null |
||||||
|
) { |
||||||
|
// Init config |
||||||
|
$this->config = \Yggverse\Yoda\Model\File::getConfig()->window->tab->page; |
||||||
|
|
||||||
|
// Init memory |
||||||
|
$this->memory = new \Yggverse\Yoda\Model\Memory(); |
||||||
|
|
||||||
|
// Compose header |
||||||
|
$this->header = new \GtkBox( |
||||||
|
\GtkOrientation::HORIZONTAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->set_margin_top( |
||||||
|
$this->config->header->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->set_margin_bottom( |
||||||
|
$this->config->header->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->set_margin_start( |
||||||
|
$this->config->header->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->set_margin_end( |
||||||
|
$this->config->header->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->set_spacing( |
||||||
|
$this->config->header->margin |
||||||
|
); |
||||||
|
|
||||||
|
// Home button |
||||||
|
$this->home = \GtkButton::new_with_label( |
||||||
|
$this->config->header->button->home->label |
||||||
|
); |
||||||
|
|
||||||
|
$this->home->set_sensitive( |
||||||
|
!($url == $this->config->header->button->home->url) |
||||||
|
); |
||||||
|
|
||||||
|
$this->home->connect( |
||||||
|
'released', |
||||||
|
function ($entry) |
||||||
|
{ |
||||||
|
$this->open( |
||||||
|
$this->config->header->button->home->url |
||||||
|
); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
if ($this->config->header->button->home->visible) |
||||||
|
{ |
||||||
|
$this->header->add( |
||||||
|
$this->home |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Back button |
||||||
|
$this->back = \GtkButton::new_with_label( |
||||||
|
$this->config->header->button->back->label |
||||||
|
); |
||||||
|
|
||||||
|
// Forward button |
||||||
|
$this->forward = \GtkButton::new_with_label( |
||||||
|
$this->config->header->button->forward->label |
||||||
|
); |
||||||
|
|
||||||
|
/// Group buttons |
||||||
|
if ($this->config->header->button->back->visible || $this->config->header->button->forward->visible) |
||||||
|
{ |
||||||
|
$buttonGroup = new \GtkButtonBox( |
||||||
|
\GtkOrientation::HORIZONTAL |
||||||
|
); |
||||||
|
|
||||||
|
$buttonGroup->set_layout( |
||||||
|
\GtkButtonBoxStyle::EXPAND |
||||||
|
); |
||||||
|
|
||||||
|
if ($this->config->header->button->back->visible) |
||||||
|
{ |
||||||
|
$buttonGroup->add( |
||||||
|
$this->back |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->config->header->button->forward->visible) |
||||||
|
{ |
||||||
|
$buttonGroup->add( |
||||||
|
$this->forward |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
$this->header->add( |
||||||
|
$buttonGroup |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Address field |
||||||
|
$this->address = new \GtkEntry(); |
||||||
|
|
||||||
|
if ($url) |
||||||
|
{ |
||||||
|
$this->address->set_text( |
||||||
|
$url |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
$this->address->set_placeholder_text( |
||||||
|
$this->config->header->address->placeholder |
||||||
|
); |
||||||
|
|
||||||
|
$this->address->set_max_length( |
||||||
|
$this->config->header->address->length->max |
||||||
|
); |
||||||
|
|
||||||
|
$this->address->connect( |
||||||
|
'activate', |
||||||
|
function ($entry) |
||||||
|
{ |
||||||
|
$this->open( |
||||||
|
$entry->get_text() |
||||||
|
); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
$this->header->pack_start( |
||||||
|
$this->address, |
||||||
|
true, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
// Go button |
||||||
|
$this->go = \GtkButton::new_with_label( |
||||||
|
$this->config->header->button->go->label |
||||||
|
); |
||||||
|
|
||||||
|
$this->go->connect( |
||||||
|
'released', |
||||||
|
function ($entry) |
||||||
|
{ |
||||||
|
$this->open( |
||||||
|
$this->address->get_text() |
||||||
|
); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
if ($this->config->header->button->go->visible) |
||||||
|
{ |
||||||
|
$this->header->add( |
||||||
|
$this->go |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Compose body |
||||||
|
$this->content = new \GtkLabel(); |
||||||
|
|
||||||
|
$this->content->set_use_markup( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->set_selectable( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->set_line_wrap( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->set_xalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->set_yalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
// Init scrolled container |
||||||
|
$this->container = new \GtkScrolledWindow(); |
||||||
|
|
||||||
|
$this->container->add( |
||||||
|
$this->content |
||||||
|
); |
||||||
|
|
||||||
|
$this->body = new \GtkBox( |
||||||
|
\GtkOrientation::VERTICAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->body->set_margin_start( |
||||||
|
$this->config->body->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->body->pack_start( |
||||||
|
$this->container, |
||||||
|
true, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
// Compose footer |
||||||
|
$this->footer = new \GtkBox( |
||||||
|
\GtkOrientation::HORIZONTAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->footer->set_margin_top( |
||||||
|
$this->config->footer->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->footer->set_margin_bottom( |
||||||
|
$this->config->footer->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->footer->set_margin_start( |
||||||
|
$this->config->footer->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->footer->set_margin_end( |
||||||
|
$this->config->footer->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->footer->set_spacing( |
||||||
|
$this->config->footer->margin |
||||||
|
); |
||||||
|
|
||||||
|
$this->status = new \GtkLabel(); |
||||||
|
|
||||||
|
$this->footer->add( |
||||||
|
$this->status |
||||||
|
); |
||||||
|
|
||||||
|
// Compose page |
||||||
|
$this->box = new \GtkBox( |
||||||
|
\GtkOrientation::VERTICAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->add( |
||||||
|
$this->header |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->pack_start( |
||||||
|
$this->body, |
||||||
|
true, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->add( |
||||||
|
$this->footer |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public function open( |
||||||
|
string $url |
||||||
|
): void |
||||||
|
{ |
||||||
|
// Update address field by requested |
||||||
|
$this->address->set_text( |
||||||
|
$url |
||||||
|
); |
||||||
|
|
||||||
|
// Update home button sensitivity on match requested |
||||||
|
$this->home->set_sensitive( |
||||||
|
!($url == $this->config->header->button->home->url) |
||||||
|
); |
||||||
|
|
||||||
|
// Open current address |
||||||
|
switch (true) |
||||||
|
{ |
||||||
|
case str_starts_with($url, 'gemini://'): |
||||||
|
|
||||||
|
$this->_gemini( |
||||||
|
$url |
||||||
|
); |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
|
||||||
|
$this->_yoda( |
||||||
|
$url |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private function _gemini(string $url): void |
||||||
|
{ |
||||||
|
// Track response time |
||||||
|
$start = microtime(true); |
||||||
|
|
||||||
|
// Init custom resolver |
||||||
|
$host = null; |
||||||
|
|
||||||
|
if ($this->config->resolver->enabled) |
||||||
|
{ |
||||||
|
$address = new \Yggverse\Net\Address( |
||||||
|
$url |
||||||
|
); |
||||||
|
|
||||||
|
$name = $address->getHost(); |
||||||
|
|
||||||
|
if (!$host = $this->memory->get($name)) |
||||||
|
{ |
||||||
|
$resolve = new \Yggverse\Net\Resolve( |
||||||
|
$this->config->resolver->request->record, |
||||||
|
$this->config->resolver->request->host, |
||||||
|
$this->config->resolver->request->timeout, |
||||||
|
$this->config->resolver->result->shuffle |
||||||
|
); |
||||||
|
|
||||||
|
$resolved = $resolve->address( |
||||||
|
$address |
||||||
|
); |
||||||
|
|
||||||
|
if ($resolved) |
||||||
|
{ |
||||||
|
$host = $resolved->getHost(); |
||||||
|
|
||||||
|
$this->memory->set( |
||||||
|
$name, |
||||||
|
$host |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$request = new \Yggverse\Gemini\Client\Request( |
||||||
|
$url, |
||||||
|
$host |
||||||
|
); |
||||||
|
|
||||||
|
$raw = $request->getResponse(); |
||||||
|
|
||||||
|
$end = microtime(true); |
||||||
|
|
||||||
|
$response = new \Yggverse\Gemini\Client\Response( |
||||||
|
$raw |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->set_markup( |
||||||
|
$this->_gemtext( |
||||||
|
$response->getBody() |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
/* @TODO |
||||||
|
$body = new \Yggverse\Gemini\Gemtext\Body( |
||||||
|
$response->getBody() |
||||||
|
); |
||||||
|
|
||||||
|
if ($h1 = $body->getH1()) |
||||||
|
{ |
||||||
|
$this->window->set_title( |
||||||
|
sprintf( |
||||||
|
'%s - Yoda', |
||||||
|
empty($h1[0]) ? $address->getHost() : $h1[0] |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
$this->status->set_text( |
||||||
|
str_replace( // Custom macros mask from config.json |
||||||
|
[ |
||||||
|
'{NAVIGATION_ADDRESS}', |
||||||
|
'{TIME_C}', |
||||||
|
'{RESPONSE_META}', |
||||||
|
'{RESPONSE_LENGTH}', |
||||||
|
'{RESPONSE_SECONDS}' |
||||||
|
], |
||||||
|
[ |
||||||
|
urlencode( |
||||||
|
$url |
||||||
|
), |
||||||
|
date( |
||||||
|
'c' |
||||||
|
), |
||||||
|
$response->getMeta() ? $response->getMeta() : $response->getCode(), |
||||||
|
number_format( |
||||||
|
mb_strlen( |
||||||
|
$raw |
||||||
|
) |
||||||
|
), |
||||||
|
round( |
||||||
|
$end - $start, 2 |
||||||
|
) |
||||||
|
], |
||||||
|
$this->config->footer->status->open->complete |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
private function _yoda( |
||||||
|
string $url |
||||||
|
): void |
||||||
|
{ |
||||||
|
// Load local page |
||||||
|
if (!$data = \Yggverse\Yoda\Model\Page::get(str_replace('yoda://', '', $url))) |
||||||
|
{ |
||||||
|
$data = \Yggverse\Yoda\Model\Page::get('Oops'); |
||||||
|
} |
||||||
|
|
||||||
|
$this->content->set_markup( |
||||||
|
$this->_gemtext( |
||||||
|
$data |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
// Parse gemtext |
||||||
|
/* @TODO |
||||||
|
$body = new \Yggverse\Gemini\Gemtext\Body( |
||||||
|
$data |
||||||
|
); |
||||||
|
|
||||||
|
if ($h1 = $body->getH1()) |
||||||
|
{ |
||||||
|
$this->window->set_title( |
||||||
|
$h1[0] |
||||||
|
); |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
private function _gemtext( |
||||||
|
string $gemtext |
||||||
|
): string |
||||||
|
{ |
||||||
|
// Format body |
||||||
|
$body = new \Yggverse\Gemini\Gemtext\Body( |
||||||
|
$gemtext |
||||||
|
); |
||||||
|
|
||||||
|
$lines = $body->getLines(); |
||||||
|
|
||||||
|
$escaped = []; |
||||||
|
|
||||||
|
/// Format H1 |
||||||
|
foreach ($body->getH1() as $index => $h1) |
||||||
|
{ |
||||||
|
$lines[$index] = sprintf( |
||||||
|
'<span size="xx-large">%s</span>', |
||||||
|
htmlentities( |
||||||
|
$h1 |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
$escaped[] = $index; |
||||||
|
} |
||||||
|
|
||||||
|
/// Format H2 |
||||||
|
foreach ($body->getH2() as $index => $h2) |
||||||
|
{ |
||||||
|
$lines[$index] = sprintf( |
||||||
|
'<span size="x-large">%s</span>', |
||||||
|
htmlentities( |
||||||
|
$h2 |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
$escaped[] = $index; |
||||||
|
} |
||||||
|
|
||||||
|
/// Format H3 |
||||||
|
foreach ($body->getH3() as $index => $h3) |
||||||
|
{ |
||||||
|
$lines[$index] = sprintf( |
||||||
|
'<span size="large">%s</span>', |
||||||
|
htmlentities( |
||||||
|
$h3 |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
$escaped[] = $index; |
||||||
|
} |
||||||
|
|
||||||
|
/// Escape entities |
||||||
|
foreach ($lines as $index => $line) |
||||||
|
{ |
||||||
|
if (!in_array($index, $escaped)) |
||||||
|
{ |
||||||
|
$lines[$index] = htmlentities( |
||||||
|
$line |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// @TODO links, code, escape entities |
||||||
|
|
||||||
|
return implode( |
||||||
|
PHP_EOL, |
||||||
|
$lines |
||||||
|
); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue