mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-04-02 09:35:28 +00:00
move Page entity out of Tab namespace
This commit is contained in:
parent
46adc640e9
commit
63bc991bda
21 changed files with 111 additions and 111 deletions
416
src/Entity/Browser/Container/Page/Content.php
Normal file
416
src/Entity/Browser/Container/Page/Content.php
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page;
|
||||
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Content\Data;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Content\Viewport;
|
||||
|
||||
class Content
|
||||
{
|
||||
public \GtkScrolledWindow $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page $page;
|
||||
|
||||
// Requirements
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Content\Data $data;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Content\Viewport $viewport;
|
||||
|
||||
// Defaults
|
||||
private int $_margin = 8;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page $page
|
||||
) {
|
||||
$this->page = $page;
|
||||
|
||||
// Init container
|
||||
$this->gtk = new \GtkScrolledWindow;
|
||||
|
||||
$this->gtk->set_margin_start(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_end(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_bottom(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
// Init viewport
|
||||
// to integrate scrolled window features for data label
|
||||
$this->viewport = new Viewport(
|
||||
$this
|
||||
);
|
||||
|
||||
// Init data label
|
||||
$this->data = new Data(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->viewport->gtk->add(
|
||||
$this->data->gtk
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->viewport->gtk
|
||||
);
|
||||
|
||||
// Render
|
||||
$this->gtk->show();
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
// @TODO
|
||||
}
|
||||
|
||||
public function update(
|
||||
bool $history = true
|
||||
): void
|
||||
{
|
||||
// Parse address
|
||||
$address = new \Yggverse\Net\Address(
|
||||
$this->page->navbar->request->getValue()
|
||||
);
|
||||
|
||||
// Init new title
|
||||
$this->page->title->setValue(
|
||||
$address->getHost(),
|
||||
'loading...'
|
||||
);
|
||||
|
||||
if ($history)
|
||||
{
|
||||
// Remember address in the navigation memory
|
||||
$this->page->navbar->history->add(
|
||||
$address->get()
|
||||
);
|
||||
|
||||
// Update history in database
|
||||
$this->page->container->browser->database->renewHistory(
|
||||
$address->get(),
|
||||
// @TODO title
|
||||
);
|
||||
}
|
||||
|
||||
// Detect protocol
|
||||
switch ($address->getScheme())
|
||||
{
|
||||
case 'file':
|
||||
|
||||
if (file_exists($address->getPath()) && is_readable($address->getPath()))
|
||||
{
|
||||
switch ($address->getPath())
|
||||
{
|
||||
case is_dir($address->getPath()):
|
||||
|
||||
// @TODO build fs listing
|
||||
|
||||
break;
|
||||
|
||||
case str_ends_with($address->getPath(), '.gmi'):
|
||||
|
||||
$title = null;
|
||||
|
||||
$this->data->setGemtext(
|
||||
file_get_contents( // @TODO format relative links
|
||||
$address->getPath()
|
||||
),
|
||||
$title
|
||||
);
|
||||
|
||||
if ($title) // detect title by document h1
|
||||
{
|
||||
$this->page->title->setValue(
|
||||
$title,
|
||||
$this->page->title->subtitle
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$this->page->title->setValue(
|
||||
'Oops!',
|
||||
'file extension not supported'
|
||||
);
|
||||
|
||||
$this->data->setPlain(
|
||||
'File extension not supported'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$this->page->title->setValue(
|
||||
'Failure',
|
||||
'resource not found or not readable'
|
||||
);
|
||||
|
||||
$this->data->setPlain(
|
||||
'Could not open file'
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'nex':
|
||||
|
||||
$client = new \Yggverse\Nex\Client;
|
||||
|
||||
if ($response = $client->request($address->get()))
|
||||
{
|
||||
// Detect content type
|
||||
switch (true)
|
||||
{
|
||||
case in_array(
|
||||
pathinfo(
|
||||
strval(
|
||||
$address->getPath()
|
||||
),
|
||||
PATHINFO_EXTENSION
|
||||
),
|
||||
[
|
||||
'gmi',
|
||||
'gemini'
|
||||
]
|
||||
):
|
||||
|
||||
$title = null;
|
||||
|
||||
$this->data->setGemtext(
|
||||
$response,
|
||||
$title
|
||||
);
|
||||
|
||||
$this->page->title->setValue(
|
||||
$title ? sprintf(
|
||||
'%s - %s',
|
||||
$title,
|
||||
$address->getHost()
|
||||
) : $address->getHost()
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$this->data->setMono(
|
||||
$response
|
||||
);
|
||||
|
||||
$this->page->title->setValue(
|
||||
$address->getHost()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$this->page->title->setValue(
|
||||
'Failure',
|
||||
'could not open resource'
|
||||
);
|
||||
|
||||
$this->data->setPlain(
|
||||
'Requested resource not available!'
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'gemini':
|
||||
|
||||
$request = new \Yggverse\Gemini\Client\Request(
|
||||
$address->get()
|
||||
);
|
||||
|
||||
$response = new \Yggverse\Gemini\Client\Response(
|
||||
$request->getResponse()
|
||||
);
|
||||
|
||||
// Route status code
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-codes
|
||||
switch ($response->getCode())
|
||||
{
|
||||
case 10: // response expected
|
||||
case 11: // sensitive input
|
||||
|
||||
$this->page->title->setValue(
|
||||
$address->getHost(),
|
||||
$response->getMeta() ? $response->getMeta() : 'response expected'
|
||||
);
|
||||
|
||||
$this->page->response->show(
|
||||
$response->getMeta(), // placeholder
|
||||
boolval(11 !== $response->getCode()) // input visibility
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 20: // ok
|
||||
|
||||
// Detect content type
|
||||
switch (true)
|
||||
{
|
||||
case str_contains(
|
||||
$response->getMeta(),
|
||||
'text/gemini'
|
||||
):
|
||||
|
||||
case in_array(
|
||||
pathinfo(
|
||||
strval(
|
||||
$address->getPath()
|
||||
),
|
||||
PATHINFO_EXTENSION
|
||||
),
|
||||
[
|
||||
'gmi',
|
||||
'gemini'
|
||||
]
|
||||
):
|
||||
|
||||
$title = null;
|
||||
|
||||
$this->data->setGemtext(
|
||||
$response->getBody(),
|
||||
$title
|
||||
);
|
||||
|
||||
$this->page->title->setValue(
|
||||
$title ? sprintf(
|
||||
'%s - %s',
|
||||
$title,
|
||||
$address->getHost()
|
||||
) : $address->getHost(), // detect title by document h1
|
||||
$response->getMeta()
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$this->data->setPlain(
|
||||
$response->getBody()
|
||||
);
|
||||
|
||||
$this->page->title->setValue(
|
||||
$address->getHost()
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 31: // redirect @TODO
|
||||
|
||||
$this->data->setGemtext(
|
||||
sprintf(
|
||||
'=> %s',
|
||||
$response->getMeta()
|
||||
)
|
||||
);
|
||||
|
||||
$this->page->title->setValue(
|
||||
$address->getHost(),
|
||||
sprintf(
|
||||
'redirect (code %d)',
|
||||
intval(
|
||||
$response->getCode()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$this->page->title->setValue(
|
||||
'Failure',
|
||||
sprintf(
|
||||
'%s (code %d)',
|
||||
$response->getMeta() ? $response->getMeta() : 'could not open resource',
|
||||
intval(
|
||||
$response->getCode()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->data->setPlain(
|
||||
'Requested resource not available!'
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case null:
|
||||
|
||||
// Try gemini protocol
|
||||
$address = new \Yggverse\Net\Address(
|
||||
sprintf(
|
||||
'gemini://%s',
|
||||
$this->page->navbar->request->getValue()
|
||||
)
|
||||
);
|
||||
|
||||
// Is hostname request
|
||||
if (filter_var(
|
||||
$address->getHost(),
|
||||
FILTER_VALIDATE_DOMAIN,
|
||||
FILTER_FLAG_HOSTNAME
|
||||
)
|
||||
) {
|
||||
$this->page->navbar->request->setValue(
|
||||
$address->get()
|
||||
);
|
||||
}
|
||||
|
||||
// Is search request
|
||||
else
|
||||
{
|
||||
$this->page->navbar->request->setValue(
|
||||
sprintf(
|
||||
'gemini://tlgs.one/search?%s', // @TODO custom provider
|
||||
urlencode(
|
||||
$this->page->navbar->request->getValue()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->update();
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
|
||||
$this->page->title->setValue(
|
||||
'Oops!',
|
||||
'protocol not supported!'
|
||||
);
|
||||
|
||||
$this->data->setPlain(
|
||||
'Protocol not supported!'
|
||||
);
|
||||
}
|
||||
|
||||
// Render content
|
||||
$this->gtk->show_all();
|
||||
|
||||
// Refresh page components
|
||||
$this->page->refresh();
|
||||
|
||||
// Update window header
|
||||
$this->page->container->browser->header->setTitle(
|
||||
$this->page->title->getValue(),
|
||||
$this->page->title->getSubtitle(),
|
||||
);
|
||||
}
|
||||
}
|
||||
268
src/Entity/Browser/Container/Page/Content/Data.php
Normal file
268
src/Entity/Browser/Container/Page/Content/Data.php
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Content;
|
||||
|
||||
use \Yggverse\Gemtext\Document;
|
||||
use \Yggverse\Net\Address;
|
||||
|
||||
class Data
|
||||
{
|
||||
public \GtkLabel $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Content $content;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page\Content $content
|
||||
) {
|
||||
// Init dependency
|
||||
$this->content = $content;
|
||||
|
||||
// Init markup label
|
||||
$this->gtk = new \GtkLabel;
|
||||
|
||||
$this->gtk->set_use_markup(
|
||||
true
|
||||
);
|
||||
|
||||
$this->gtk->set_selectable(
|
||||
true
|
||||
);
|
||||
|
||||
/*
|
||||
$this->gtk->set_line_wrap(
|
||||
true
|
||||
);
|
||||
|
||||
$this->gtk->set_line_wrap_mode(
|
||||
@TODO #114
|
||||
\GtkWrapMode::WORD
|
||||
);
|
||||
*/
|
||||
|
||||
$this->gtk->set_track_visited_links(
|
||||
true
|
||||
);
|
||||
|
||||
$this->gtk->set_xalign(
|
||||
0
|
||||
);
|
||||
|
||||
$this->gtk->set_yalign(
|
||||
0
|
||||
);
|
||||
|
||||
// Render
|
||||
$this->gtk->show();
|
||||
|
||||
// Init events
|
||||
$this->gtk->connect(
|
||||
'activate-link',
|
||||
function(
|
||||
\GtkLabel $label,
|
||||
string $href
|
||||
) {
|
||||
$this->content->page->navbar->request->setValue(
|
||||
$this->_url(
|
||||
$href
|
||||
)
|
||||
);
|
||||
|
||||
$this->content->page->update();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function setPlain(
|
||||
string $value
|
||||
): void
|
||||
{
|
||||
$this->gtk->set_text(
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
public function setMono(
|
||||
string $value
|
||||
): void
|
||||
{
|
||||
$this->gtk->set_markup(
|
||||
sprintf(
|
||||
'<tt>%s</tt>',
|
||||
htmlspecialchars(
|
||||
$value
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function setGemtext(
|
||||
string $value,
|
||||
string | null &$title = null,
|
||||
bool $preformatted = false
|
||||
): void
|
||||
{
|
||||
$document = new Document(
|
||||
$value
|
||||
);
|
||||
|
||||
$line = [];
|
||||
|
||||
foreach ($document->getEntities() as $entity)
|
||||
{
|
||||
switch (true)
|
||||
{
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Code:
|
||||
|
||||
if ($entity->isInline())
|
||||
{
|
||||
$line[] = sprintf(
|
||||
'<tt>%s</tt>',
|
||||
htmlspecialchars(
|
||||
$entity->getAlt()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$line[] = $preformatted ? '</tt>' : '<tt>';
|
||||
|
||||
$preformatted = !($preformatted); // toggle
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Header:
|
||||
|
||||
switch ($entity->getLevel())
|
||||
{
|
||||
case 1: // #
|
||||
|
||||
$line[] = sprintf(
|
||||
'<span size="xx-large">%s</span>',
|
||||
htmlspecialchars(
|
||||
$entity->getText()
|
||||
)
|
||||
);
|
||||
|
||||
// Find and return document title by first # tag
|
||||
if (empty($title))
|
||||
{
|
||||
$title = $entity->getText();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2: // ##
|
||||
|
||||
$line[] = sprintf(
|
||||
'<span size="x-large">%s</span>',
|
||||
htmlspecialchars(
|
||||
$entity->getText()
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 3: // ###
|
||||
|
||||
$line[] = sprintf(
|
||||
'<span size="large">%s</span>',
|
||||
htmlspecialchars(
|
||||
$entity->getText()
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Link:
|
||||
|
||||
$line[] = sprintf(
|
||||
'<a href="%s" title="%s">%s</a>',
|
||||
$this->_url(
|
||||
$entity->getAddress()
|
||||
),
|
||||
htmlspecialchars(
|
||||
$entity->getAddress()
|
||||
),
|
||||
htmlspecialchars(
|
||||
$entity->getAlt() ? $entity->getAlt()
|
||||
: $entity->getAddress() // @TODO date
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Listing:
|
||||
|
||||
$line[] = sprintf(
|
||||
'* %s',
|
||||
htmlspecialchars(
|
||||
$entity->getItem()
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Quote:
|
||||
|
||||
$line[] = sprintf(
|
||||
'<i>%s</i>',
|
||||
htmlspecialchars(
|
||||
$entity->getText()
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case $entity instanceof \Yggverse\Gemtext\Entity\Text:
|
||||
|
||||
$line[] = htmlspecialchars(
|
||||
$entity->getData()
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
|
||||
$this->gtk->set_markup(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$line
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function _url(
|
||||
string $link
|
||||
): ?string
|
||||
{
|
||||
$address = new Address(
|
||||
$link
|
||||
);
|
||||
|
||||
if ($address->isRelative())
|
||||
{
|
||||
$address->toAbsolute(
|
||||
new Address(
|
||||
$this->content->page->navbar->request->getValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $address->get();
|
||||
}
|
||||
}
|
||||
26
src/Entity/Browser/Container/Page/Content/Viewport.php
Normal file
26
src/Entity/Browser/Container/Page/Content/Viewport.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Content;
|
||||
|
||||
class Viewport
|
||||
{
|
||||
public \GtkViewport $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Content $content;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page\Content $content
|
||||
) {
|
||||
// Init dependencies
|
||||
$this->content = $content;
|
||||
|
||||
// Init viewport
|
||||
$this->gtk = new \GtkViewport;
|
||||
|
||||
// Render
|
||||
$this->gtk->show();
|
||||
}
|
||||
}
|
||||
108
src/Entity/Browser/Container/Page/Navbar.php
Normal file
108
src/Entity/Browser/Container/Page/Navbar.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page;
|
||||
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Base;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Go;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Request;
|
||||
|
||||
class Navbar
|
||||
{
|
||||
public \GtkBox $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page $page;
|
||||
|
||||
// Requirements
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Base $base;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Go $go;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History $history;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\Request $request;
|
||||
|
||||
// Defaults
|
||||
private int $_margin = 8;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page $page
|
||||
) {
|
||||
// Init dependencies
|
||||
$this->page = $page;
|
||||
|
||||
// Init navbar
|
||||
$this->gtk = new \GtkBox(
|
||||
\GtkOrientation::HORIZONTAL
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_top(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_bottom(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_start(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_end(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_spacing(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
// Append base button
|
||||
$this->base = new Base(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->base->gtk
|
||||
);
|
||||
|
||||
// Append history buttons group
|
||||
$this->history = new History(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->history->gtk
|
||||
);
|
||||
|
||||
// Append request entry, fill empty space
|
||||
$this->request = new Request(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->pack_start(
|
||||
$this->request->gtk,
|
||||
true,
|
||||
true,
|
||||
0
|
||||
);
|
||||
|
||||
// Append go button
|
||||
$this->go = new Go(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->go->gtk
|
||||
);
|
||||
|
||||
// Render
|
||||
$this->gtk->show();
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
$this->base->refresh();
|
||||
$this->go->refresh();
|
||||
$this->history->refresh();
|
||||
}
|
||||
}
|
||||
55
src/Entity/Browser/Container/Page/Navbar/Base.php
Normal file
55
src/Entity/Browser/Container/Page/Navbar/Base.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar;
|
||||
|
||||
class Base extends \Yggverse\Yoda\Abstract\Entity\Browser\Container\Page\Navbar\Button
|
||||
{
|
||||
protected string $_label = 'Base';
|
||||
|
||||
protected function _onCLick(
|
||||
\GtkButton $entity
|
||||
): void
|
||||
{
|
||||
$address = new \Yggverse\Net\Address(
|
||||
$this->navbar->request->getValue()
|
||||
);
|
||||
|
||||
if ($address->getHost())
|
||||
{
|
||||
$this->navbar->request->setValue(
|
||||
$address->get( // build base
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
$this->navbar->page->update();
|
||||
}
|
||||
|
||||
$this->refresh();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$address = new \Yggverse\Net\Address(
|
||||
rtrim(
|
||||
$this->navbar->request->getValue(),
|
||||
'/'
|
||||
)
|
||||
);
|
||||
|
||||
$this->gtk->set_sensitive(
|
||||
$address->getHost() && (
|
||||
$address->getPath() || $address->getQuery()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
26
src/Entity/Browser/Container/Page/Navbar/Go.php
Normal file
26
src/Entity/Browser/Container/Page/Navbar/Go.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar;
|
||||
|
||||
class Go extends \Yggverse\Yoda\Abstract\Entity\Browser\Container\Page\Navbar\Button
|
||||
{
|
||||
protected string $_label = 'Go';
|
||||
|
||||
protected function _onCLick(
|
||||
\GtkButton $entity
|
||||
): void
|
||||
{
|
||||
$this->navbar->page->update();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->gtk->set_sensitive(
|
||||
!empty(
|
||||
$this->navbar->request->getValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
82
src/Entity/Browser/Container/Page/Navbar/History.php
Normal file
82
src/Entity/Browser/Container/Page/Navbar/History.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar;
|
||||
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History\Back;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History\Forward;
|
||||
|
||||
class History
|
||||
{
|
||||
public \GtkButtonBox $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Model\History $memory;
|
||||
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar $navbar;
|
||||
|
||||
// Requirements
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History\Back $back;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History\Forward $forward;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page\Navbar $navbar
|
||||
) {
|
||||
$this->memory = new \Yggverse\Yoda\Model\History();
|
||||
|
||||
$this->navbar = $navbar;
|
||||
|
||||
$this->gtk = new \GtkButtonBox(
|
||||
\GtkOrientation::HORIZONTAL
|
||||
);
|
||||
|
||||
$this->gtk->set_layout(
|
||||
\GtkButtonBoxStyle::EXPAND
|
||||
);
|
||||
|
||||
$this->back = new Back(
|
||||
$this->navbar
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->back->gtk
|
||||
);
|
||||
|
||||
$this->forward = new Forward(
|
||||
$this->navbar
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->forward->gtk
|
||||
);
|
||||
|
||||
// Render
|
||||
$this->gtk->show();
|
||||
}
|
||||
|
||||
public function add(
|
||||
string $value
|
||||
): void
|
||||
{
|
||||
if (empty($value))
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
if ($value != $this->memory->getCurrent())
|
||||
{
|
||||
$this->memory->add(
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
$this->refresh();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->back->refresh();
|
||||
$this->forward->refresh();
|
||||
}
|
||||
}
|
||||
37
src/Entity/Browser/Container/Page/Navbar/History/Back.php
Normal file
37
src/Entity/Browser/Container/Page/Navbar/History/Back.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History;
|
||||
|
||||
class Back extends \Yggverse\Yoda\Abstract\Entity\Browser\Container\Page\Navbar\Button
|
||||
{
|
||||
protected string $_label = 'Back';
|
||||
|
||||
protected function _onCLick(
|
||||
\GtkButton $entity
|
||||
): void
|
||||
{
|
||||
if ($this->navbar->history->memory->getBack())
|
||||
{
|
||||
$this->navbar->request->setValue(
|
||||
$this->navbar->history->memory->goBack()
|
||||
);
|
||||
|
||||
$this->navbar->page->update(
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
$this->navbar->history->refresh();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->gtk->set_sensitive(
|
||||
boolval(
|
||||
$this->navbar->history->memory->getBack()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
37
src/Entity/Browser/Container/Page/Navbar/History/Forward.php
Normal file
37
src/Entity/Browser/Container/Page/Navbar/History/Forward.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar\History;
|
||||
|
||||
class Forward extends \Yggverse\Yoda\Abstract\Entity\Browser\Container\Page\Navbar\Button
|
||||
{
|
||||
protected string $_label = 'Forward';
|
||||
|
||||
protected function _onCLick(
|
||||
\GtkButton $entity
|
||||
): void
|
||||
{
|
||||
if ($this->navbar->history->memory->getForward())
|
||||
{
|
||||
$this->navbar->request->setValue(
|
||||
$this->navbar->history->memory->goForward()
|
||||
);
|
||||
|
||||
$this->navbar->page->update(
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
$this->navbar->history->refresh();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->gtk->set_sensitive(
|
||||
boolval(
|
||||
$this->navbar->history->memory->getForward()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
25
src/Entity/Browser/Container/Page/Navbar/Request.php
Normal file
25
src/Entity/Browser/Container/Page/Navbar/Request.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Navbar;
|
||||
|
||||
class Request extends \Yggverse\Yoda\Abstract\Entity\Browser\Container\Page\Navbar\Entry
|
||||
{
|
||||
protected string $_placeholder = 'URL or search term...';
|
||||
|
||||
protected function _onActivate(
|
||||
\GtkEntry $entry
|
||||
): void
|
||||
{
|
||||
$this->navbar->page->content->update();
|
||||
}
|
||||
|
||||
protected function _onKeyRelease(
|
||||
\GtkEntry $entry,
|
||||
\GdkEvent $event
|
||||
): void
|
||||
{
|
||||
$this->navbar->refresh();
|
||||
}
|
||||
}
|
||||
152
src/Entity/Browser/Container/Page/Response.php
Normal file
152
src/Entity/Browser/Container/Page/Response.php
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page;
|
||||
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Response\Query;
|
||||
use \Yggverse\Yoda\Entity\Browser\Container\Page\Response\Send;
|
||||
|
||||
use \Yggverse\Net\Address;
|
||||
|
||||
class Response
|
||||
{
|
||||
public \GtkBox $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page $page;
|
||||
|
||||
// Requirements
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Response\Query $query;
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Response\Send $send;
|
||||
|
||||
// Defaults
|
||||
private int $_margin = 8;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page $page
|
||||
) {
|
||||
// Init dependencies
|
||||
$this->page = $page;
|
||||
|
||||
// Init container
|
||||
$this->gtk = new \GtkBox(
|
||||
\GtkOrientation::HORIZONTAL
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_top(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_bottom(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_start(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_margin_end(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
$this->gtk->set_spacing(
|
||||
$this->_margin
|
||||
);
|
||||
|
||||
// Init query field
|
||||
$this->query = new Query(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->pack_start(
|
||||
$this->query->gtk,
|
||||
true,
|
||||
true,
|
||||
0
|
||||
);
|
||||
|
||||
// Init send button
|
||||
$this->send = new Send(
|
||||
$this
|
||||
);
|
||||
|
||||
$this->gtk->add(
|
||||
$this->send->gtk
|
||||
);
|
||||
|
||||
// Hide widget by default
|
||||
$this->hide();
|
||||
}
|
||||
|
||||
public function show(
|
||||
?string $placeholder = null,
|
||||
?bool $visible = null,
|
||||
bool $focus = true
|
||||
): void
|
||||
{
|
||||
if ($focus)
|
||||
{
|
||||
$this->query->focus();
|
||||
}
|
||||
|
||||
if (!is_null($placeholder))
|
||||
{
|
||||
$this->query->setPlaceholder(
|
||||
$placeholder
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_null($visible))
|
||||
{
|
||||
$this->query->setVisible(
|
||||
$visible
|
||||
);
|
||||
}
|
||||
|
||||
$this->gtk->show();
|
||||
}
|
||||
|
||||
public function hide(): void
|
||||
{
|
||||
$this->query->setPlaceholder(
|
||||
null
|
||||
);
|
||||
|
||||
$this->query->setVisible(
|
||||
null
|
||||
);
|
||||
|
||||
$this->gtk->hide();
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
$this->query->refresh();
|
||||
$this->send->refresh();
|
||||
}
|
||||
|
||||
public function send(): void
|
||||
{
|
||||
$address = new Address(
|
||||
$this->page->navbar->request->getValue()
|
||||
);
|
||||
|
||||
$address->setQuery(
|
||||
urlencode(
|
||||
trim(
|
||||
strval(
|
||||
$this->query->getValue()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->page->open(
|
||||
$address->get(),
|
||||
false // disable history recording
|
||||
);
|
||||
|
||||
$this->hide();
|
||||
}
|
||||
}
|
||||
43
src/Entity/Browser/Container/Page/Response/Query.php
Normal file
43
src/Entity/Browser/Container/Page/Response/Query.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Response;
|
||||
|
||||
class Query extends \Yggverse\Yoda\Abstract\Entity\Entry
|
||||
{
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Response $response;
|
||||
|
||||
// Defaults
|
||||
protected string $_placeholder = 'Enter response...';
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page\Response $response
|
||||
) {
|
||||
// Use parent features
|
||||
parent::__construct();
|
||||
|
||||
// Init dependency
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
protected function _onActivate(
|
||||
\GtkEntry $entry
|
||||
): void
|
||||
{
|
||||
$this->response->send();
|
||||
}
|
||||
|
||||
protected function _onKeyRelease(
|
||||
\GtkEntry $entry,
|
||||
\GdkEvent $event
|
||||
): void
|
||||
{
|
||||
$this->response->refresh();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
// @TODO
|
||||
}
|
||||
}
|
||||
38
src/Entity/Browser/Container/Page/Response/Send.php
Normal file
38
src/Entity/Browser/Container/Page/Response/Send.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page\Response;
|
||||
|
||||
class Send extends \Yggverse\Yoda\Abstract\Entity\Button
|
||||
{
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page\Response $response;
|
||||
|
||||
// Defaults
|
||||
protected string $_label = 'Send';
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page\Response $response
|
||||
) {
|
||||
// Use parent features
|
||||
parent::__construct();
|
||||
|
||||
// Init dependency
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
protected function _onCLick(
|
||||
\GtkButton $entity
|
||||
): void
|
||||
{
|
||||
$this->response->send();
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->gtk->set_sensitive(
|
||||
!empty($this->response->query->getValue())
|
||||
);
|
||||
}
|
||||
}
|
||||
80
src/Entity/Browser/Container/Page/Title.php
Normal file
80
src/Entity/Browser/Container/Page/Title.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Yoda\Entity\Browser\Container\Page;
|
||||
|
||||
use \Yggverse\Yoda\Gtk\Browser\Container\Page\Title\Label;
|
||||
|
||||
class Title
|
||||
{
|
||||
public Label $gtk;
|
||||
|
||||
// Dependencies
|
||||
public \Yggverse\Yoda\Entity\Browser\Container\Page $page;
|
||||
|
||||
// Defaults
|
||||
private int $_ellipsize = 3;
|
||||
private int $_length = 16;
|
||||
private ?string $_value = 'New page';
|
||||
private ?string $_subtitle = null;
|
||||
|
||||
public function __construct(
|
||||
\Yggverse\Yoda\Entity\Browser\Container\Page $page,
|
||||
) {
|
||||
// Init dependencies
|
||||
$this->page = $page;
|
||||
|
||||
// Init container
|
||||
$this->gtk = new Label(
|
||||
$this->_value
|
||||
);
|
||||
|
||||
$this->gtk->set_width_chars(
|
||||
$this->_length
|
||||
);
|
||||
|
||||
$this->gtk->set_ellipsize(
|
||||
$this->_ellipsize
|
||||
);
|
||||
}
|
||||
|
||||
public function setValue(
|
||||
?string $value = null,
|
||||
?string $subtitle = null
|
||||
): void
|
||||
{
|
||||
$this->gtk->set_text(
|
||||
is_null($value) ? $this->_value : trim(
|
||||
$value
|
||||
)
|
||||
);
|
||||
|
||||
$this->setSubtitle(
|
||||
$subtitle
|
||||
);
|
||||
}
|
||||
|
||||
public function setSubtitle(
|
||||
?string $subtitle = null
|
||||
): void
|
||||
{
|
||||
$this->gtk->set_subtitle(
|
||||
is_null($subtitle) ? $this->_subtitle : strtolower(
|
||||
trim(
|
||||
$subtitle
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function getValue(): ?string
|
||||
{
|
||||
return $this->gtk->get_text();
|
||||
}
|
||||
|
||||
public function getSubtitle(): ?string
|
||||
{
|
||||
return $this->gtk->get_subtitle();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue