Skip to content

Commit 9c07550

Browse files
committed
Page autocomplete: new option 'filter' instead of old 'namespace' and 'postfix'
1 parent c0f1a2d commit 9c07550

File tree

2 files changed

+111
-72
lines changed

2 files changed

+111
-72
lines changed

_test/types/PageTest.php

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -296,62 +296,74 @@ public function test_ajax_postfix()
296296

297297
$INPUT->set('search', 'oku');
298298
$this->assertEquals([['label' => 'dokuwiki (wiki)', 'value' => 'wiki:dokuwiki']], $page->handleAjax());
299+
300+
$page = new Page(
301+
[
302+
'autocomplete' => [
303+
'mininput' => 2,
304+
'maxresult' => 5,
305+
'namespace' => 'wiki',
306+
'postfix' => 'iki',
307+
],
308+
]
309+
);
310+
311+
$INPUT->set('search', 'oku');
312+
$this->assertEquals([['label' => 'dokuwiki (wiki)', 'value' => 'wiki:dokuwiki']], $page->handleAjax());
299313
}
300314

301315
/**
302-
* Test simple namespace matching in autocompletion
316+
* Test simple filter matching in autocompletion
303317
*
304318
* @return void
305319
*/
306-
public function test_namespace_matching_simple()
320+
public function test_filter_matching_simple()
307321
{
308322
$page = new Page();
309323

310-
$this->assertTrue($page->nsMatch('foo:start', 'foo'));
311-
$this->assertFalse($page->nsMatch('start#foo', 'foo'));
312-
$this->assertFalse($page->nsMatch('ns:foo', ':foo'));
313-
$this->assertTrue($page->nsMatch('ns:foo:start', 'foo'));
314-
$this->assertTrue($page->nsMatch('ns:foo:start#headline', 'foo'));
315-
$this->assertTrue($page->nsMatch('foo-bar:start', 'foo-bar'));
316-
$this->assertTrue($page->nsMatch('foo-bar:start-with_special.chars', 'foo-bar'));
317-
$this->assertTrue($page->nsMatch('foo.bar:start', 'foo.bar'));
318-
$this->assertFalse($page->nsMatch('ns:foo.bar', 'foo.bar'));
319-
$this->assertTrue($page->nsMatch('ns:foo.bar:start', 'foo.bar'));
320-
$this->assertFalse($page->nsMatch('ns:foo_bar:start', ':foo_bar'));
321-
$this->assertTrue($page->nsMatch('8bar:start', '8bar'));
322-
$this->assertTrue($page->nsMatch('ns:8bar:start', '8bar'));
323-
$this->assertFalse($page->nsMatch('ns:98bar:start', '8bar'));
324+
$this->assertTrue($page->filterMatch('foo:start', 'foo'));
325+
$this->assertTrue($page->filterMatch('start#foo', 'foo'));
326+
$this->assertFalse($page->filterMatch('ns:foo', ':foo'));
327+
$this->assertTrue($page->filterMatch('foo-bar:start', 'foo-bar'));
328+
$this->assertTrue($page->filterMatch('foo-bar:start-with_special.chars', 'foo-bar'));
329+
$this->assertTrue($page->filterMatch('foo.bar:start', 'foo.bar'));
330+
$this->assertTrue($page->filterMatch('ns:foo.bar', 'foo.bar'));
331+
$this->assertTrue($page->filterMatch('ns:foo.bar:start', 'foo.bar'));
332+
$this->assertFalse($page->filterMatch('ns:foo_bar:start', ':foo_bar'));
333+
$this->assertTrue($page->filterMatch('8bar:start', '8bar'));
334+
$this->assertTrue($page->filterMatch('ns:8bar:start', '8bar'));
335+
$this->assertTrue($page->filterMatch('ns:98bar:start', '8bar'));
324336
}
325337

326338
/**
327-
* Test regex namespace matching in autocompletion
339+
* Test pattern matching in autocompletion
328340
*
329341
* @return void
330342
*/
331-
public function test_namespace_matching_regex()
343+
public function test_filter_matching_regex()
332344
{
333345
$page = new Page();
334346

335-
$namespace = '/(foo:|^:foo:|(?::|^)bar:|foo:bar|foo-bar:|^:foo_bar:|foo\.bar:|(?::|^)8bar:)/';
336-
337-
$this->assertTrue($page->nsMatch('foo:start', $namespace));
338-
$this->assertFalse($page->nsMatch('start#foo', $namespace));
339-
$this->assertFalse($page->nsMatch('ns:foo', $namespace));
340-
$this->assertTrue($page->nsMatch('bar:foo', $namespace));
341-
$this->assertTrue($page->nsMatch('ns:foo:start', $namespace));
342-
$this->assertTrue($page->nsMatch('ns:foo:start#headline', $namespace));
343-
$this->assertTrue($page->nsMatch('foo-bar:start', $namespace));
344-
$this->assertTrue($page->nsMatch('foo-bar:start-with_special.chars', $namespace));
345-
$this->assertTrue($page->nsMatch('foo.bar:start', $namespace));
346-
$this->assertFalse($page->nsMatch('ns:foo.bar', $namespace));
347-
$this->assertTrue($page->nsMatch('ns:foo.bar:start', $namespace));
348-
$this->assertFalse($page->nsMatch('ns:foo_bar:start', $namespace));
349-
$this->assertTrue($page->nsMatch('8bar:start', $namespace));
350-
$this->assertTrue($page->nsMatch('ns:8bar:start', $namespace));
351-
$this->assertFalse($page->nsMatch('ns:98bar:start', $namespace));
352-
353-
$namespace = '/^:systems:[^:]+:components:([^:]+:){1,2}$/';
354-
$this->assertTrue($page->nsMatch('systems:system1:components:sub1:sub2:start', $namespace));
355-
$this->assertFalse($page->nsMatch('systems:system1:components:sub1:sub2:sub3:start', $namespace));
347+
$filter = '(foo:|^:foo:|(?::|^)bar:|foo:bar|foo-bar:|^:foo_bar:|foo\.bar:|(?::|^)8bar:)';
348+
349+
$this->assertTrue($page->filterMatch('foo:start', $filter));
350+
$this->assertFalse($page->filterMatch('start#foo', $filter));
351+
$this->assertFalse($page->filterMatch('ns:foo', $filter));
352+
$this->assertTrue($page->filterMatch('bar:foo', $filter));
353+
$this->assertTrue($page->filterMatch('ns:foo:start', $filter));
354+
$this->assertTrue($page->filterMatch('ns:foo:start#headline', $filter));
355+
$this->assertTrue($page->filterMatch('foo-bar:start', $filter));
356+
$this->assertTrue($page->filterMatch('foo-bar:start-with_special.chars', $filter));
357+
$this->assertTrue($page->filterMatch('foo.bar:start', $filter));
358+
$this->assertFalse($page->filterMatch('ns:foo.bar', $filter));
359+
$this->assertTrue($page->filterMatch('ns:foo.bar:start', $filter));
360+
$this->assertFalse($page->filterMatch('ns:foo_bar:start', $filter));
361+
$this->assertTrue($page->filterMatch('8bar:start', $filter));
362+
$this->assertTrue($page->filterMatch('ns:8bar:start', $filter));
363+
$this->assertFalse($page->filterMatch('ns:98bar:start', $filter));
364+
365+
$filter = '^:systems:[^:]+:components:([^:]+:){1,2}[^:]+$';
366+
$this->assertTrue($page->filterMatch('systems:system1:components:sub1:sub2:start', $filter));
367+
$this->assertFalse($page->filterMatch('systems:system1:components:sub1:sub2:sub3:start', $filter));
356368
}
357369
}

types/Page.php

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,32 @@ class Page extends AbstractMultiBaseType
2121
'autocomplete' => [
2222
'mininput' => 2,
2323
'maxresult' => 5,
24-
'namespace' => '',
25-
'postfix' => ''
24+
'filter' => '',
2625
]
2726
];
2827

28+
/**
29+
* Return the current configuration.
30+
* Overwrites parent method to migrate deprecated options.
31+
*
32+
* @return array
33+
*/
34+
public function getConfig()
35+
{
36+
// migrate autocomplete options 'namespace' and 'postfix' to 'filter'
37+
if (empty($this->config['autocomplete']['filter'])) {
38+
if (!empty($this->config['autocomplete']['namespace'])) {
39+
$this->config['autocomplete']['filter'] = $this->config['autocomplete']['namespace'];
40+
unset($this->config['autocomplete']['namespace']);
41+
}
42+
if (!empty($this->config['autocomplete']['postfix'])) {
43+
$this->config['autocomplete']['filter'] .= '.+?' . $this->config['autocomplete']['postfix'] . '$';
44+
unset($this->config['autocomplete']['namespace']);
45+
}
46+
}
47+
return $this->config;
48+
}
49+
2950
/**
3051
* Output the stored data
3152
*
@@ -78,19 +99,24 @@ public function handleAjax()
7899
$max = $this->config['autocomplete']['maxresult'];
79100
if ($max <= 0) return [];
80101

81-
// apply namespace and postfix
82-
$postfix = $this->config['autocomplete']['postfix'];
83-
84102
$data = ft_pageLookup($lookup, true, $this->config['usetitles']);
85103
if ($data === []) return [];
86104

87-
$namespace = $this->config['autocomplete']['namespace'];
105+
$filter = $this->config['autocomplete']['filter'];
88106

89-
// this basically duplicates what we do in ajax_qsearch() but with ns filter
107+
// try to use deprecated options namespace and postfix as filter
108+
$namespace = $this->config['autocomplete']['namespace'] ?? '';
109+
$postfix = $this->config['autocomplete']['postfix'] ?? '';
110+
if (!$filter) {
111+
$filter = $namespace ? $namespace . ':' : '';
112+
$filter .= $postfix ? '.+?' . $postfix . '$' : '';
113+
}
114+
115+
// this basically duplicates what we do in ajax_qsearch() but with a filter
90116
$result = [];
91117
$counter = 0;
92118
foreach ($data as $id => $title) {
93-
if (!empty($namespace) && !$this->nsMatch($id, $namespace)) {
119+
if (!empty($filter) && !$this->filterMatch($id, $filter)) {
94120
continue;
95121
}
96122
if ($this->config['usetitles']) {
@@ -104,11 +130,6 @@ public function handleAjax()
104130
}
105131
}
106132

107-
// check suffix
108-
if ($postfix && substr($id, -1 * strlen($postfix)) != $postfix) {
109-
continue; // page does not end in postfix, don't suggest it
110-
}
111-
112133
$result[] = [
113134
'label' => $name,
114135
'value' => $id
@@ -222,33 +243,39 @@ public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $va
222243
}
223244

224245
/**
225-
* Check if the given id matches at configured namespace (pattern):
226-
* simple string or regex pattern with delimiter "/"
246+
* Check if the given id matches a configured filter pattern
227247
*
228248
* @param string $id
229-
* @param string $namespace
249+
* @param string $filter
230250
* @return bool
231251
*/
232-
public function nsMatch($id, $namespace)
252+
public function filterMatch($id, $filter)
233253
{
234-
$searchNS = getNS($id);
235-
if (!$searchNS) {
236-
return false; // root
237-
}
238-
239-
// prepare any namespace for preg_match()
240-
$searchNS = ':' . $searchNS . ':';
241254
// absolute namespace?
242-
if (PhpString::substr($namespace, 0, 1) === ':') {
243-
$namespace = '^' . $namespace;
244-
}
245-
// non-regex namespace?
246-
if (PhpString::substr($namespace, 0, 1) !== '/') {
247-
$namespace = '(?::|^)' . $namespace ;
248-
$namespace = '/' . $namespace . '/';
255+
if (PhpString::substr($filter, 0, 1) === ':') {
256+
$filter = '^' . $filter;
249257
}
250-
preg_match($namespace, $searchNS, $matches);
251258

252-
return !empty($matches);
259+
return (bool)preg_match('/' . $filter . '/', ':' . $id, $matches);
260+
}
261+
262+
/**
263+
* Merge the current config with the base config of the type.
264+
*
265+
* In contrast to parent, this method does not throw away unknown keys.
266+
* Required to migrate deprecated / obsolete options, no longer part of type config.
267+
*
268+
* @param array $current Current configuration
269+
* @param array $config Base Type configuration
270+
*/
271+
protected function mergeConfig($current, &$config)
272+
{
273+
foreach ($current as $key => $value) {
274+
if (isset($config[$key]) && is_array($config[$key])) {
275+
$this->mergeConfig($value, $config[$key]);
276+
} else {
277+
$config[$key] = $value;
278+
}
279+
}
253280
}
254281
}

0 commit comments

Comments
 (0)