diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a677d0..5f36909 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+1.6.0 / 2024-??-??
+
+- Добавлена возможность задавать префикс "%" для поискового значения. Данный префикс позволяет вести поиск по группе подстрок, разделенных пробелами
+
1.5.7 / 2024-04-04
- В параметр bookReadLink конфига добавлен вариант замены DOWNLOAD_URI на uri из ссылки для скачивания книги (#29)
diff --git a/client/components/Search/BaseList.js b/client/components/Search/BaseList.js
index f8f7a34..71c1b25 100644
--- a/client/components/Search/BaseList.js
+++ b/client/components/Search/BaseList.js
@@ -387,21 +387,34 @@ export default class BaseList {
searchValue = searchValue.toLowerCase();
//особая обработка префиксов
- if (searchValue[0] == '=') {
+ if (searchValue[0] === '=') {
searchValue = searchValue.substring(1);
return bookValue.localeCompare(searchValue) == 0;
- } else if (searchValue[0] == '*') {
+ } else if (searchValue[0] === '%') {
+
+ searchValue = searchValue.substring(1);
+
+ const words = searchValue.split(' ').filter(a => a);
+ if (!words.length)
+ words.push('');
+
+ for (const w of words)
+ if (bookValue !== emptyFieldValue && bookValue.indexOf(w) >= 0)
+ return true;
+
+ return false;
+ } else if (searchValue[0] === '*') {
searchValue = searchValue.substring(1);
return bookValue !== emptyFieldValue && bookValue.indexOf(searchValue) >= 0;
- } else if (searchValue[0] == '#') {
+ } else if (searchValue[0] === '#') {
searchValue = searchValue.substring(1);
if (!bookValue)
return false;
return bookValue !== emptyFieldValue && !enru.has(bookValue[0]) && bookValue.indexOf(searchValue) >= 0;
- } else if (searchValue[0] == '~') {//RegExp
+ } else if (searchValue[0] === '~') {//RegExp
searchValue = searchValue.substring(1);
const re = new RegExp(searchValue, 'i');
diff --git a/client/components/Search/Search.vue b/client/components/Search/Search.vue
index 3d09034..b940592 100644
--- a/client/components/Search/Search.vue
+++ b/client/components/Search/Search.vue
@@ -846,8 +846,13 @@ class Search {
- "*" поиск подстроки в строке. Например, для "*Александр" в поле автора, будут найдены
- все авторы, имя которых содержит "Александр"
+ "%" поиск по группе подстрок, разделенных пробелами. Например, для "%Александр Пушкин" в поле автора, будут найдены
+ все авторы, имя которых содержит и "Александр", и "Пушкин" одновременно
+
+
+
+ "*" поиск подстроки в строке вместе с пробелами. Например, для "*Александр Сергеевич" в поле автора, будут найдены
+ все авторы, имя которых содержит "Александр Сергеевич"
diff --git a/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue b/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue
index f4d5a8d..c24fa33 100644
--- a/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue
+++ b/client/components/Search/SelectExtSearchDialog/SelectExtSearchDialog.vue
@@ -155,7 +155,10 @@ class SelectExtSearchDialog {
префикс "=": поиск по точному совпадению
- префикс "*": поиск подстроки в строке
+ префикс "%": поиск по группе подстрок, разделенных пробелами
+
+
+ префикс "*": поиск подстроки в строке (вместе с пробелами)
префикс "#": поиск подстроки в строке, но только среди начинающихся не с латинского или кириллического символа
diff --git a/server/core/DbSearcher.js b/server/core/DbSearcher.js
index 0b2d7a5..d18c7de 100644
--- a/server/core/DbSearcher.js
+++ b/server/core/DbSearcher.js
@@ -54,13 +54,24 @@ class DbSearcher {
let where;
//особая обработка префиксов
- if (a[0] == '=') {
+ if (a[0] === '=') {
a = a.substring(1);
where = `@dirtyIndexLR('value', ${db.esc(a)}, ${db.esc(a)})`;
- } else if (a[0] == '*') {
+ } else if (a[0] === '%') {
+ a = a.substring(1);
+ const ands = [];
+ const words = a.split(' ').filter(a => a);
+ if (!words.length)
+ words.push('');
+
+ for (const w of words)
+ ands.push(`v.indexOf(${db.esc(w)}) >= 0`);
+
+ where = `@indexIter('value', (v) => (v !== ${db.esc(emptyFieldValue)} && (${ands.join('&&')})) )`;
+ } else if (a[0] === '*') {
a = a.substring(1);
where = `@indexIter('value', (v) => (v !== ${db.esc(emptyFieldValue)} && v.indexOf(${db.esc(a)}) >= 0) )`;
- } else if (a[0] == '#') {
+ } else if (a[0] === '#') {
a = a.substring(1);
where = `@indexIter('value', (v) => {
const enru = new Set(${db.esc(enruArr)});
@@ -68,7 +79,7 @@ class DbSearcher {
return false;
return v !== ${db.esc(emptyFieldValue)} && !enru.has(v[0]) && v.indexOf(${db.esc(a)}) >= 0;
})`;
- } else if (a[0] == '~') {//RegExp
+ } else if (a[0] === '~') {//RegExp
a = a.substring(1);
where = `
await (async() => {
@@ -595,21 +606,32 @@ class DbSearcher {
const filterBySearch = (bookField, searchValue) => {
searchValue = searchValue.toLowerCase();
//особая обработка префиксов
- if (searchValue == emptyFieldValue) {
+ if (searchValue === emptyFieldValue) {
return `(row.${bookField} === '' || row.${bookField}.indexOf(${db.esc(emptyFieldValue)}) === 0)`;
- } else if (searchValue[0] == '=') {
+ } else if (searchValue[0] === '=') {
searchValue = searchValue.substring(1);
return `(row.${bookField}.toLowerCase().localeCompare(${db.esc(searchValue)}) === 0)`;
- } else if (searchValue[0] == '*') {
+ } else if (searchValue[0] === '%') {
+ searchValue = searchValue.substring(1);
+ const ands = [];
+ const words = searchValue.split(' ').filter(a => a);
+ if (!words.length)
+ words.push('');
+
+ for (const w of words)
+ ands.push(`row.${bookField}.toLowerCase().indexOf(${db.esc(w)}) >= 0`);
+
+ return `(row.${bookField} && (${ands.join('&&')}))`;
+ } else if (searchValue[0] === '*') {
searchValue = searchValue.substring(1);
return `(row.${bookField} && row.${bookField}.toLowerCase().indexOf(${db.esc(searchValue)}) >= 0)`;
- } else if (searchValue[0] == '#') {
+ } else if (searchValue[0] === '#') {
searchValue = searchValue.substring(1);
return `(row.${bookField} === '' || (!enru.has(row.${bookField}.toLowerCase()[0]) && row.${bookField}.toLowerCase().indexOf(${db.esc(searchValue)}) >= 0))`;
- } else if (searchValue[0] == '~') {//RegExp
+ } else if (searchValue[0] === '~') {//RegExp
searchValue = searchValue.substring(1);
return `
diff --git a/server/core/opds/BasePage.js b/server/core/opds/BasePage.js
index 83695a9..9003efa 100644
--- a/server/core/opds/BasePage.js
+++ b/server/core/opds/BasePage.js
@@ -247,21 +247,34 @@ class BasePage {
searchValue = searchValue.toLowerCase();
//особая обработка префиксов
- if (searchValue[0] == '=') {
+ if (searchValue[0] === '=') {
searchValue = searchValue.substring(1);
return bookValue.localeCompare(searchValue) == 0;
- } else if (searchValue[0] == '*') {
+ } else if (searchValue[0] === '%') {
+
+ searchValue = searchValue.substring(1);
+
+ const words = searchValue.split(' ').filter(a => a);
+ if (!words.length)
+ words.push('');
+
+ for (const w of words)
+ if (bookValue !== emptyFieldValue && bookValue.indexOf(w) >= 0)
+ return true;
+
+ return false;
+ } else if (searchValue[0] === '*') {
searchValue = searchValue.substring(1);
return bookValue !== emptyFieldValue && bookValue.indexOf(searchValue) >= 0;
- } else if (searchValue[0] == '#') {
+ } else if (searchValue[0] === '#') {
searchValue = searchValue.substring(1);
if (!bookValue)
return false;
return bookValue !== emptyFieldValue && !enru.has(bookValue[0]) && bookValue.indexOf(searchValue) >= 0;
- } else if (searchValue[0] == '~') {//RegExp
+ } else if (searchValue[0] === '~') {//RegExp
searchValue = searchValue.substring(1);
const re = new RegExp(searchValue, 'i');
diff --git a/server/core/opds/SearchHelpPage.js b/server/core/opds/SearchHelpPage.js
index 246f499..23c3c31 100644
--- a/server/core/opds/SearchHelpPage.js
+++ b/server/core/opds/SearchHelpPage.js
@@ -24,7 +24,10 @@ class SearchHelpPage extends BasePage {
префикс "=": поиск по точному совпадению
- префикс "*": поиск подстроки в строке
+ префикс "%": поиск по группе подстрок, разделенных пробелами
+
+
+ префикс "*": поиск подстроки в строке (вместе с пробелами)
префикс "#": поиск подстроки в строке, но только среди значений, начинающихся не с латинского или кириллического символа