* fox.form.Select: add several properties allowing it to better
imitate other controls like DropDownButton, etc. * rework several main toolbar items to use fox.form.Select instead of other controls * replace HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM with HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2 because of markup change (option instead of menuitem) * PluginHost: add some explicit typecasts to make intellephense shut up
This commit is contained in:
parent
8a645892a6
commit
720b318796
|
@ -133,7 +133,7 @@ class Feeds extends Handler_Protected {
|
||||||
$reply['vfeed_group_enabled'] = $vfeed_group_enabled;
|
$reply['vfeed_group_enabled'] = $vfeed_group_enabled;
|
||||||
|
|
||||||
$plugin_menu_items = "";
|
$plugin_menu_items = "";
|
||||||
PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM,
|
PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2,
|
||||||
function ($result) use (&$plugin_menu_items) {
|
function ($result) use (&$plugin_menu_items) {
|
||||||
$plugin_menu_items .= $result;
|
$plugin_menu_items .= $result;
|
||||||
},
|
},
|
||||||
|
|
|
@ -647,6 +647,7 @@ abstract class Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allows adding custom elements to headlines Select... dropdown
|
/** Allows adding custom elements to headlines Select... dropdown
|
||||||
|
* @deprecated removed, see Plugin::hook_headline_toolbar_select_menu_item2()
|
||||||
* @param int $feed_id
|
* @param int $feed_id
|
||||||
* @param int $is_cat
|
* @param int $is_cat
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -658,6 +659,18 @@ abstract class Plugin {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allows adding custom elements to headlines Select... select dropdown (<option> format)
|
||||||
|
* @param int $feed_id
|
||||||
|
* @param int $is_cat
|
||||||
|
* @return string
|
||||||
|
* @see PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2
|
||||||
|
*/
|
||||||
|
function hook_headline_toolbar_select_menu_item2($feed_id, $is_cat) {
|
||||||
|
user_error("Dummy method invoked.", E_USER_ERROR);
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
/** Invoked when user tries to subscribe to feed, may override information (i.e. feed URL) used afterwards
|
/** Invoked when user tries to subscribe to feed, may override information (i.e. feed URL) used afterwards
|
||||||
* @param string $url
|
* @param string $url
|
||||||
* @param string $auth_login
|
* @param string $auth_login
|
||||||
|
|
|
@ -189,9 +189,14 @@ class PluginHost {
|
||||||
/** @see Plugin::hook_headlines_custom_sort_override() */
|
/** @see Plugin::hook_headlines_custom_sort_override() */
|
||||||
const HOOK_HEADLINES_CUSTOM_SORT_OVERRIDE = "hook_headlines_custom_sort_override";
|
const HOOK_HEADLINES_CUSTOM_SORT_OVERRIDE = "hook_headlines_custom_sort_override";
|
||||||
|
|
||||||
/** @see Plugin::hook_headline_toolbar_select_menu_item() */
|
/** @see Plugin::hook_headline_toolbar_select_menu_item()
|
||||||
|
* @deprecated removed, see PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2
|
||||||
|
*/
|
||||||
const HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM = "hook_headline_toolbar_select_menu_item";
|
const HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM = "hook_headline_toolbar_select_menu_item";
|
||||||
|
|
||||||
|
/** @see Plugin::hook_headline_toolbar_select_menu_item() */
|
||||||
|
const HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2 = "hook_headline_toolbar_select_menu_item2";
|
||||||
|
|
||||||
/** @see Plugin::hook_pre_subscribe() */
|
/** @see Plugin::hook_pre_subscribe() */
|
||||||
const HOOK_PRE_SUBSCRIBE = "hook_pre_subscribe";
|
const HOOK_PRE_SUBSCRIBE = "hook_pre_subscribe";
|
||||||
|
|
||||||
|
@ -270,9 +275,10 @@ class PluginHost {
|
||||||
* @param mixed $args
|
* @param mixed $args
|
||||||
*/
|
*/
|
||||||
function run_hooks(string $hook, ...$args): void {
|
function run_hooks(string $hook, ...$args): void {
|
||||||
$method = strtolower($hook);
|
|
||||||
|
|
||||||
foreach ($this->get_hooks($hook) as $plugin) {
|
$method = strtolower((string)$hook);
|
||||||
|
|
||||||
|
foreach ($this->get_hooks((string)$hook) as $plugin) {
|
||||||
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -291,9 +297,9 @@ class PluginHost {
|
||||||
* @param mixed $check
|
* @param mixed $check
|
||||||
*/
|
*/
|
||||||
function run_hooks_until(string $hook, $check, ...$args): bool {
|
function run_hooks_until(string $hook, $check, ...$args): bool {
|
||||||
$method = strtolower($hook);
|
$method = strtolower((string)$hook);
|
||||||
|
|
||||||
foreach ($this->get_hooks($hook) as $plugin) {
|
foreach ($this->get_hooks((string)$hook) as $plugin) {
|
||||||
try {
|
try {
|
||||||
$result = $plugin->$method(...$args);
|
$result = $plugin->$method(...$args);
|
||||||
|
|
||||||
|
@ -315,9 +321,9 @@ class PluginHost {
|
||||||
* @param mixed $args
|
* @param mixed $args
|
||||||
*/
|
*/
|
||||||
function run_hooks_callback(string $hook, Closure $callback, ...$args): void {
|
function run_hooks_callback(string $hook, Closure $callback, ...$args): void {
|
||||||
$method = strtolower($hook);
|
$method = strtolower((string)$hook);
|
||||||
|
|
||||||
foreach ($this->get_hooks($hook) as $plugin) {
|
foreach ($this->get_hooks((string)$hook) as $plugin) {
|
||||||
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -336,9 +342,9 @@ class PluginHost {
|
||||||
* @param mixed $args
|
* @param mixed $args
|
||||||
*/
|
*/
|
||||||
function chain_hooks_callback(string $hook, Closure $callback, &...$args): void {
|
function chain_hooks_callback(string $hook, Closure $callback, &...$args): void {
|
||||||
$method = strtolower($hook);
|
$method = strtolower((string)$hook);
|
||||||
|
|
||||||
foreach ($this->get_hooks($hook) as $plugin) {
|
foreach ($this->get_hooks((string)$hook) as $plugin) {
|
||||||
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -358,7 +364,7 @@ class PluginHost {
|
||||||
function add_hook(string $type, Plugin $sender, int $priority = 50): void {
|
function add_hook(string $type, Plugin $sender, int $priority = 50): void {
|
||||||
$priority = (int) $priority;
|
$priority = (int) $priority;
|
||||||
|
|
||||||
if (!method_exists($sender, strtolower($type))) {
|
if (!method_exists($sender, strtolower((string)$type))) {
|
||||||
user_error(
|
user_error(
|
||||||
sprintf("Plugin %s tried to register a hook without implementation: %s",
|
sprintf("Plugin %s tried to register a hook without implementation: %s",
|
||||||
get_class($sender), $type),
|
get_class($sender), $type),
|
||||||
|
@ -422,7 +428,7 @@ class PluginHost {
|
||||||
|
|
||||||
asort($plugins);
|
asort($plugins);
|
||||||
|
|
||||||
$this->load(join(",", $plugins), $kind, $owner_uid, $skip_init);
|
$this->load(join(",", $plugins), (int)$kind, $owner_uid, $skip_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
21
index.php
21
index.php
|
@ -215,20 +215,13 @@
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div class="catchup-button" dojoType="fox.form.ComboButton" onclick="Feeds.catchupCurrent()">
|
<select class="catchup-button" id="main-catchup-dropdown" dojoType="fox.form.Select"
|
||||||
<span><?= __('Mark as read') ?></span>
|
data-prevent-value-change="true">
|
||||||
<div dojoType="dijit.DropDownMenu">
|
<option value=""><?= __('Mark as read') ?></option>
|
||||||
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrent('1day')">
|
<option value="1day"><?= __('Older than one day') ?></option>
|
||||||
<?= __('Older than one day') ?>
|
<option value="1week"><?= __('Older than one week') ?></option>
|
||||||
</div>
|
<option value="2week"><?= __('Older than two weeks') ?></option>
|
||||||
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrent('1week')">
|
</select>
|
||||||
<?= __('Older than one week') ?>
|
|
||||||
</div>
|
|
||||||
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrent('2week')">
|
|
||||||
<?= __('Older than two weeks') ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -282,6 +282,10 @@ const Feeds = {
|
||||||
CommonDialogs.safeModeWarning();
|
CommonDialogs.safeModeWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dojo.connect(dijit.byId("main-catchup-dropdown"), 'onItemClick',
|
||||||
|
(item) => Feeds.catchupCurrent(item.option.value)
|
||||||
|
);
|
||||||
|
|
||||||
// bw_limit disables timeout() so we request initial counters separately
|
// bw_limit disables timeout() so we request initial counters separately
|
||||||
if (App.getInitParam("bw_limit")) {
|
if (App.getInitParam("bw_limit")) {
|
||||||
this.requestCounters();
|
this.requestCounters();
|
||||||
|
|
|
@ -626,6 +626,12 @@ const Headlines = {
|
||||||
const search_query = Feeds._search_query ? Feeds._search_query.query : "";
|
const search_query = Feeds._search_query ? Feeds._search_query.query : "";
|
||||||
const target = dijit.byId('toolbar-headlines');
|
const target = dijit.byId('toolbar-headlines');
|
||||||
|
|
||||||
|
// TODO: is this needed? destroyDescendants() below might take care of it (?)
|
||||||
|
if (this._headlinesSelectClickHandle)
|
||||||
|
dojo.disconnect(this._headlinesSelectClickHandle);
|
||||||
|
|
||||||
|
target.destroyDescendants();
|
||||||
|
|
||||||
if (tb && typeof tb == 'object') {
|
if (tb && typeof tb == 'object') {
|
||||||
target.attr('innerHTML',
|
target.attr('innerHTML',
|
||||||
`
|
`
|
||||||
|
@ -646,27 +652,37 @@ const Headlines = {
|
||||||
</span>
|
</span>
|
||||||
<span class='right'>
|
<span class='right'>
|
||||||
<span id='selected_prompt'></span>
|
<span id='selected_prompt'></span>
|
||||||
<div class='select-articles-dropdown' dojoType='fox.form.DropDownButton' title='"${__('Select articles')}'>
|
|
||||||
<span>${__("Select...")}</span>
|
<select class='select-articles-dropdown'
|
||||||
<div dojoType='dijit.Menu' style='display: none;'>
|
id='headlines-select-articles-dropdown'
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.select("all")'>${__('All')}</div>
|
data-prevent-value-change="true"
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.select("unread")'>${__('Unread')}</div>
|
data-dropdown-skip-first="true"
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.select("invert")'>${__('Invert')}</div>
|
dojoType="fox.form.Select"
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.select("none")'>${__('None')}</div>
|
title="${__('Show articles')}">
|
||||||
<div dojoType='dijit.MenuSeparator'></div>
|
<option value='' selected="selected">${__("Select...")}</option>
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.selectionToggleUnread()'>${__('Toggle unread')}</div>
|
<option value='headlines_select_all'>${__('All')}</option>
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.selectionToggleMarked()'>${__('Toggle starred')}</div>
|
<option value='headlines_select_unread'>${__('Unread')}</option>
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.selectionTogglePublished()'>${__('Toggle published')}</div>
|
<option value='headlines_select_invert'>${__('Invert')}</option>
|
||||||
<div dojoType='dijit.MenuSeparator'></div>
|
<option value='headlines_select_none'>${__('None')}</option>
|
||||||
<div dojoType='dijit.MenuItem' onclick='Headlines.catchupSelection()'>${__('Mark as read')}</div>
|
<option></option>
|
||||||
<div dojoType='dijit.MenuItem' onclick='Article.selectionSetScore()'>${__('Set score')}</div>
|
<option value='headlines_selectionToggleUnread'>${__('Toggle unread')}</option>
|
||||||
|
<option value='headlines_selectionToggleMarked'>${__('Toggle starred')}</option>
|
||||||
|
<option value='headlines_selectionTogglePublished'>${__('Toggle published')}</option>
|
||||||
|
<option></option>
|
||||||
|
<option value='headlines_catchupSelection'>${__('Mark as read')}</option>
|
||||||
|
<option value='article_selectionSetScore'>${__('Set score')}</option>
|
||||||
|
${tb.plugin_menu_items != '' ?
|
||||||
|
`
|
||||||
|
<option></option>
|
||||||
${tb.plugin_menu_items}
|
${tb.plugin_menu_items}
|
||||||
|
` : ''}
|
||||||
${headlines.id === 0 && !headlines.is_cat ?
|
${headlines.id === 0 && !headlines.is_cat ?
|
||||||
`
|
`
|
||||||
<div dojoType='dijit.MenuSeparator'></div>
|
<option></option>
|
||||||
<div dojoType='dijit.MenuItem' class='text-error' onclick='Headlines.deleteSelection()'>${__('Delete permanently')}</div>
|
<option class='text-error' value='headlines_deleteSelection'>${__('Delete permanently')}</option>
|
||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</select>
|
||||||
|
|
||||||
${tb.plugin_buttons}
|
${tb.plugin_buttons}
|
||||||
</span>
|
</span>
|
||||||
`);
|
`);
|
||||||
|
@ -675,6 +691,48 @@ const Headlines = {
|
||||||
}
|
}
|
||||||
|
|
||||||
dojo.parser.parse(target.domNode);
|
dojo.parser.parse(target.domNode);
|
||||||
|
|
||||||
|
this._headlinesSelectClickHandle = dojo.connect(dijit.byId("headlines-select-articles-dropdown"), 'onItemClick',
|
||||||
|
(item) => {
|
||||||
|
const action = item.option.value;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'headlines_select_all':
|
||||||
|
Headlines.select('all');
|
||||||
|
break;
|
||||||
|
case 'headlines_select_unread':
|
||||||
|
Headlines.select('unread');
|
||||||
|
break;
|
||||||
|
case 'headlines_select_invert':
|
||||||
|
Headlines.select('invert');
|
||||||
|
break;
|
||||||
|
case 'headlines_select_none':
|
||||||
|
Headlines.select('none');
|
||||||
|
break;
|
||||||
|
case 'headlines_selectionToggleUnread':
|
||||||
|
Headlines.selectionToggleUnread();
|
||||||
|
break;
|
||||||
|
case 'headlines_selectionToggleMarked':
|
||||||
|
Headlines.selectionToggleMarked();
|
||||||
|
break;
|
||||||
|
case 'headlines_selectionTogglePublished':
|
||||||
|
Headlines.selectionTogglePublished();
|
||||||
|
break;
|
||||||
|
case 'headlines_catchupSelection':
|
||||||
|
Headlines.catchupSelection();
|
||||||
|
break;
|
||||||
|
case 'article_selectionSetScore':
|
||||||
|
Article.selectionSetScore();
|
||||||
|
break;
|
||||||
|
case 'headlines_deleteSelection':
|
||||||
|
Headlines.deleteSelection();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!PluginHost.run_until(PluginHost.HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2, true, action))
|
||||||
|
console.warn('unknown headlines action', action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onLoaded: function (reply, offset, append) {
|
onLoaded: function (reply, offset, append) {
|
||||||
console.log("Headlines.onLoaded: offset=", offset, "append=", append);
|
console.log("Headlines.onLoaded: offset=", offset, "append=", append);
|
||||||
|
|
|
@ -1,8 +1,66 @@
|
||||||
/* global dijit, define */
|
/* eslint-disable prefer-rest-params */
|
||||||
define(["dojo/_base/declare", "dijit/form/Select"], function (declare) {
|
/* global define */
|
||||||
return declare("fox.form.Select", dijit.form.Select, {
|
// FIXME: there probably is a better, more dojo-like notation for custom data- properties
|
||||||
|
define(["dojo/_base/declare",
|
||||||
|
"dijit/form/Select",
|
||||||
|
"dojo/_base/lang", // lang.hitch
|
||||||
|
"dijit/MenuItem",
|
||||||
|
"dijit/MenuSeparator",
|
||||||
|
"dojo/aspect",
|
||||||
|
], function (declare, select, lang, MenuItem, MenuSeparator, aspect) {
|
||||||
|
return declare("fox.form.Select", select, {
|
||||||
focus: function() {
|
focus: function() {
|
||||||
return; // Stop dijit.form.Select from keeping focus after closing the menu
|
return; // Stop dijit.form.Select from keeping focus after closing the menu
|
||||||
|
},
|
||||||
|
startup: function() {
|
||||||
|
this.inherited(arguments);
|
||||||
|
|
||||||
|
if (this.attr('data-dropdown-skip-first') == 'true') {
|
||||||
|
aspect.before(this, "_loadChildren", () => {
|
||||||
|
this.options = this.options.splice(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// hook invoked when dropdown MenuItem is clicked
|
||||||
|
onItemClick: function(/*item, menu*/) {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
_setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
|
||||||
|
if (this.attr('data-prevent-value-change') == 'true' && newValue != '')
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.inherited(arguments);
|
||||||
|
},
|
||||||
|
// the only difference from dijit/form/Select is _onItemClicked() handler
|
||||||
|
_getMenuItemForOption: function(/*_FormSelectWidget.__SelectOption*/ option){
|
||||||
|
// summary:
|
||||||
|
// For the given option, return the menu item that should be
|
||||||
|
// used to display it. This can be overridden as needed
|
||||||
|
if (!option.value && !option.label){
|
||||||
|
// We are a separator (no label set for it)
|
||||||
|
return new MenuSeparator({ownerDocument: this.ownerDocument});
|
||||||
|
} else {
|
||||||
|
// Just a regular menu option
|
||||||
|
const click = lang.hitch(this, "_setValueAttr", option);
|
||||||
|
const item = new MenuItem({
|
||||||
|
option: option,
|
||||||
|
label: (this.labelType === 'text' ? (option.label || '').toString()
|
||||||
|
.replace(/&/g, '&').replace(/</g, '<') :
|
||||||
|
option.label) || this.emptyLabel,
|
||||||
|
onClick: () => {
|
||||||
|
this.onItemClick(item, this.dropDown);
|
||||||
|
|
||||||
|
click();
|
||||||
|
},
|
||||||
|
ownerDocument: this.ownerDocument,
|
||||||
|
dir: this.dir,
|
||||||
|
textDir: this.textDir,
|
||||||
|
disabled: option.disabled || false
|
||||||
|
});
|
||||||
|
item.focusNode.setAttribute("role", "option");
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue