OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
38
app/Core/Events/Htmx/HtmxEvent.php
Normal file
38
app/Core/Events/Htmx/HtmxEvent.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Core\Events\Htmx;
|
||||
|
||||
/**
|
||||
* Contract for client (HTMX) event enums.
|
||||
*
|
||||
* Client events travel from the server to the browser on the `HX-Trigger` response header and are
|
||||
* consumed either declaratively (`hx-trigger="<event> from:body"`) for data events, or by a JS
|
||||
* listener for UI command events. Implementations are string-backed enums whose backing value IS
|
||||
* the wire name, following the convention:
|
||||
*
|
||||
* - data events: lt:{domain}:{entity}.{verb} e.g. lt:tickets:ticket.updated
|
||||
* - UI commands: lt:ui:{command} e.g. lt:ui:modal.close
|
||||
*
|
||||
* Use the {@see InteractsWithHtmxEvents} trait to satisfy this interface. Note: PHP enums cannot
|
||||
* implement Stringable / __toString, so use {@see event()} (or `->value`) to get the wire name in
|
||||
* PHP. In Blade, `{{ MyEvents::Case }}` renders the value (Laravel's e() unwraps backed enums).
|
||||
*/
|
||||
interface HtmxEvent
|
||||
{
|
||||
/**
|
||||
* The wire name (the enum's backing value), e.g. "lt:tickets:ticket.updated".
|
||||
*/
|
||||
public function event(): string;
|
||||
|
||||
/**
|
||||
* Wire name scoped to a single entity, e.g. "lt:reactions:sentiment.updated#42".
|
||||
* Lets a specific component listen for changes to one entity while broad listeners use the
|
||||
* unscoped name.
|
||||
*/
|
||||
public function scoped(int|string $id): string;
|
||||
|
||||
/**
|
||||
* The value formatted for an `hx-trigger` attribute, e.g. "lt:tickets:ticket.updated from:body".
|
||||
*/
|
||||
public function trigger(string $from = 'body'): string;
|
||||
}
|
||||
68
app/Core/Events/Htmx/HtmxEvents.php
Normal file
68
app/Core/Events/Htmx/HtmxEvents.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Core\Events\Htmx;
|
||||
|
||||
/**
|
||||
* Helpers for building the `HX-Trigger` response header from client event names.
|
||||
*
|
||||
* MIGRATION WINDOW: while emitters and listeners move to the lt:{domain}:{entity}.{verb} convention
|
||||
* we dual-emit legacy names alongside their canonical replacement so existing declarative listeners
|
||||
* (hx-trigger="<name> from:body") and (phar) plugins keep working without coordinated releases. Each
|
||||
* group is bidirectional — emitting ANY member puts the whole group on the wire, so old and new
|
||||
* listeners both fire regardless of which name the emitter used. Delete LEGACY_ALIASES once every
|
||||
* emitter and listener has been migrated.
|
||||
*
|
||||
* Only DOMAIN data events are aliased here. UI command events (lt:ui:*) are intentionally NOT
|
||||
* aliased: they're consumed by JS addEventListener handlers that listen for each name directly, so
|
||||
* dual-emitting them would fire the same handler once per alias (double growl, multiple modal-close
|
||||
* callbacks) for a single response.
|
||||
*/
|
||||
final class HtmxEvents
|
||||
{
|
||||
/**
|
||||
* Bidirectional alias groups. The first entry of each group is the canonical lt:* name.
|
||||
*
|
||||
* @var array<int, array<int, string>>
|
||||
*/
|
||||
private const LEGACY_ALIASES = [
|
||||
['lt:tickets:ticket.updated', 'ticket_update'],
|
||||
['lt:tickets:subtask.updated', 'subtasks_update', 'subtasksUpdated'],
|
||||
['lt:projects:project.updated', 'HTMX.updateProjectList'],
|
||||
['lt:timesheets:timer.updated', 'timerUpdate'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Expand event names to include their legacy/canonical aliases, de-duplicated and order-stable.
|
||||
* Scoped names (e.g. "lt:reactions:sentiment.updated#42") pass through unchanged.
|
||||
*
|
||||
* @param array<int, string|HtmxEvent> $names
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function expand(array $names): array
|
||||
{
|
||||
$expanded = [];
|
||||
|
||||
foreach ($names as $name) {
|
||||
$name = $name instanceof HtmxEvent ? $name->event() : (string) $name;
|
||||
$expanded[] = $name;
|
||||
|
||||
foreach (self::LEGACY_ALIASES as $group) {
|
||||
if (in_array($name, $group, true)) {
|
||||
array_push($expanded, ...$group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($expanded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the comma-separated `HX-Trigger` header value from queued event names.
|
||||
*
|
||||
* @param array<int, string|HtmxEvent> $names
|
||||
*/
|
||||
public static function triggerHeader(array $names): string
|
||||
{
|
||||
return implode(',', self::expand($names));
|
||||
}
|
||||
}
|
||||
31
app/Core/Events/Htmx/HtmxUiEvents.php
Normal file
31
app/Core/Events/Htmx/HtmxUiEvents.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Core\Events\Htmx;
|
||||
|
||||
/**
|
||||
* Canonical client UI command events (the `lt:ui:*` plane).
|
||||
*
|
||||
* These are imperative commands to the JS layer (show a toast, close the modal, refresh the page),
|
||||
* as opposed to domain data events ("entity X changed") which live in per-domain Htmx{Domain}Events
|
||||
* enums. There is exactly one home for UI commands so casing/naming never drifts again — plugins
|
||||
* reuse these cases rather than minting their own `lt:ui:*` strings.
|
||||
*
|
||||
* Legacy string equivalents (e.g. HTMX.ShowNotification, closeModal) are dual-emitted during the
|
||||
* migration window via {@see HtmxEvents::expand()} so existing listeners keep working.
|
||||
*/
|
||||
enum HtmxUiEvents: string implements HtmxEvent
|
||||
{
|
||||
use InteractsWithHtmxEvents;
|
||||
|
||||
/** Fetch + show the latest growl notification. Replaces 'HTMX.ShowNotification'. */
|
||||
case Notify = 'lt:ui:notify';
|
||||
|
||||
/** Close the top-most modal. Replaces 'closeModal' / 'HTMX.closemodal' / 'Htmx.CloseModal'. */
|
||||
case ModalClose = 'lt:ui:modal.close';
|
||||
|
||||
/** Open a modal for the current url hash. */
|
||||
case ModalOpen = 'lt:ui:modal.open';
|
||||
|
||||
/** Refresh the main page url in the background. */
|
||||
case UrlRefresh = 'lt:ui:url.refresh';
|
||||
}
|
||||
37
app/Core/Events/Htmx/InteractsWithHtmxEvents.php
Normal file
37
app/Core/Events/Htmx/InteractsWithHtmxEvents.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Core\Events\Htmx;
|
||||
|
||||
/**
|
||||
* Shared behavior for string-backed client (HTMX) event enums.
|
||||
*
|
||||
* The backing value of each case is the wire name. PHP enums cannot define __toString, so use
|
||||
* {@see event()} to obtain the wire name in PHP code; Blade's `{{ }}` renders the value directly
|
||||
* because Laravel's e() helper unwraps backed enums.
|
||||
*/
|
||||
trait InteractsWithHtmxEvents
|
||||
{
|
||||
/**
|
||||
* The wire name (the enum's backing value).
|
||||
*/
|
||||
public function event(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire name scoped to a single entity id, e.g. "lt:reactions:sentiment.updated#42".
|
||||
*/
|
||||
public function scoped(int|string $id): string
|
||||
{
|
||||
return $this->value.'#'.$id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format for an `hx-trigger` attribute, e.g. "lt:tickets:ticket.updated from:body".
|
||||
*/
|
||||
public function trigger(string $from = 'body'): string
|
||||
{
|
||||
return $this->value.($from !== '' ? ' from:'.$from : '');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user