From be91355c20140c797912247bfbfb45b7dbfd41c9 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sat, 20 Feb 2021 18:15:08 +0300 Subject: [PATCH 1/6] first for filter frontend overhaul --- classes/pref/filters.php | 2 +- js/CommonFilters.js | 452 +++++++++++++++++++-------------------- 2 files changed, 225 insertions(+), 229 deletions(-) diff --git a/classes/pref/filters.php b/classes/pref/filters.php index f9b3217c9..cfff383d8 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -861,7 +861,7 @@ class Pref_Filters extends Handler_Protected { print "
"; print " - ${reply} - ${App.FormFields.hidden_tag("rule[]", rule)}`; - - dojo.parser.parse(li); - - if (replaceNode) { - parentNode.replaceChild(li, replaceNode); - } else { - parentNode.appendChild(li); - } - } catch (e) { - App.Error.report(e); - } - }); - }, - createNewActionElement: function(parentNode, replaceNode) { - const form = document.forms["filter_new_action_form"]; - - if (form.action_id.value == 7) { - form.action_param.value = form.action_param_label.value; - } else if (form.action_id.value == 9) { - form.action_param.value = form.action_param_plugin.value; - } - - const action = dojo.formToJson(form); - - xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => { - try { - const li = document.createElement('li'); - - li.innerHTML = ` - ${reply} - ${App.FormFields.hidden_tag("action[]", action)}`; - - dojo.parser.parse(li); - - if (replaceNode) { - parentNode.replaceChild(li, replaceNode); - } else { - parentNode.appendChild(li); - } - - } catch (e) { - App.Error.report(e); - } - }); - }, - addFilterRule: function(replaceNode, ruleStr) { - const dialog = new fox.SingleUseDialog({ - id: "filterNewRuleDlg", - title: ruleStr ? __("Edit rule") : __("Add rule"), - execute: function () { - if (this.validate()) { - Filters.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); - this.hide(); - } - }, - content: __('Loading, please wait...'), - }); - - const tmph = dojo.connect(dialog, "onShow", null, function (/* e */) { - dojo.disconnect(tmph); - - xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { - dialog.attr('content', reply); - }); - }); - - dialog.show(); - }, - addFilterAction: function(replaceNode, actionStr) { - const dialog = new fox.SingleUseDialog({ - title: actionStr ? __("Edit action") : __("Add action"), - execute: function () { - if (this.validate()) { - Filters.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); - this.hide(); - } - } - }); - - const tmph = dojo.connect(dialog, "onShow", null, function (/* e */) { - dojo.disconnect(tmph); - - xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { - dialog.attr('content', reply); - }); - }); - - dialog.show(); - }, - test: function(params) { - - const dialog = new fox.SingleUseDialog({ - title: "Test Filter", - results: 0, - limit: 100, - max_offset: 10000, - getTestResults: function (params, offset) { - params.method = 'testFilterDo'; - params.offset = offset; - params.limit = dialog.limit; - - console.log("getTestResults:" + offset); - - xhr.json("backend.php", params, (result) => { - try { - if (result && dialog && dialog.open) { - dialog.results += result.length; - - console.log("got results:" + result.length); - - App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") - .replace("%f", dialog.results) - .replace("%d", offset); - - console.log(offset + " " + dialog.max_offset); - - for (let i = 0; i < result.length; i++) { - const tmp = dojo.create("table", { innerHTML: result[i]}); - - App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; - } - - if (dialog.results < 30 && offset < dialog.max_offset) { - - // get the next batch - window.setTimeout(function () { - dialog.getTestResults(params, offset + dialog.limit); - }, 0); - - } else { - // all done - - Element.hide("prefFilterLoadingIndicator"); - - if (dialog.results == 0) { - App.byId("prefFilterTestResultList").innerHTML = ` - ${__('No recent articles matching this filter have been found.')}`; - App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; - } else { - App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") - .replace("%d", dialog.results); - } - - } - - } else if (!result) { - console.log("getTestResults: can't parse results object"); - Element.hide("prefFilterLoadingIndicator"); - Notify.error("Error while trying to get filter test results."); - } else { - console.log("getTestResults: dialog closed, bailing out."); - } - } catch (e) { - App.Error.report(e); - } - }); - }, - content: ` -
-   - Looking for articles... -
- - - -
- -
- ` - }); - - dojo.connect(dialog, "onShow", null, function (/* e */) { - dialog.getTestResults(params, 0); - }); - - dialog.show(); - }, +const Filters = { edit: function(id) { // if no id, new filter dialog let query; @@ -235,15 +18,228 @@ const Filters = { query = {op: "pref-filters", method: "edit", id: id}; } - console.log('Filters.edit', query); - xhr.post("backend.php", query, function (reply) { try { const dialog = new fox.SingleUseDialog({ id: "filterEditDlg", title: id ? __("Edit Filter") : __("Create Filter"), - test: function () { - Filters.test(this.attr('value')); + test: function() { + const test_dialog = new fox.SingleUseDialog({ + title: "Test Filter", + results: 0, + limit: 100, + max_offset: 10000, + getTestResults: function (params, offset) { + params.method = 'testFilterDo'; + params.offset = offset; + params.limit = test_dialog.limit; + + console.log("getTestResults:" + offset); + + xhr.json("backend.php", params, (result) => { + try { + if (result && test_dialog && test_dialog.open) { + test_dialog.results += result.length; + + console.log("got results:" + result.length); + + App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") + .replace("%f", test_dialog.results) + .replace("%d", offset); + + console.log(offset + " " + test_dialog.max_offset); + + for (let i = 0; i < result.length; i++) { + const tmp = dojo.create("table", { innerHTML: result[i]}); + + App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; + } + + if (test_dialog.results < 30 && offset < test_dialog.max_offset) { + + // get the next batch + window.setTimeout(function () { + test_dialog.getTestResults(params, offset + test_dialog.limit); + }, 0); + + } else { + // all done + + Element.hide("prefFilterLoadingIndicator"); + + if (test_dialog.results == 0) { + App.byId("prefFilterTestResultList").innerHTML = ` + ${__('No recent articles matching this filter have been found.')}`; + App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; + } else { + App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") + .replace("%d", test_dialog.results); + } + + } + + } else if (!result) { + console.log("getTestResults: can't parse results object"); + Element.hide("prefFilterLoadingIndicator"); + Notify.error("Error while trying to get filter test results."); + } else { + console.log("getTestResults: dialog closed, bailing out."); + } + } catch (e) { + App.Error.report(e); + } + }); + }, + content: ` +
+   + Looking for articles... +
+ + + +
+ +
+ ` + }); + + const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + test_dialog.getTestResults(dialog.attr('value'), 0); + }); + + test_dialog.show(); + }, + hideOrShowActionParam: function(sender) { + const action = sender.value; + + const action_param = App.byId("filterDlg_paramBox"); + + if (!action_param) { + console.log("hideOrShowActionParam: can't find action param box!"); + return; + } + + // if selected action supports parameters, enable params field + if (action == 4 || action == 6 || action == 7 || action == 9) { + Element.show(action_param); + + Element.hide(dijit.byId("filterDlg_actionParam").domNode); + Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); + Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode); + + if (action == 7) { + Element.show(dijit.byId("filterDlg_actionParamLabel").domNode); + } else if (action == 9) { + Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode); + } else { + Element.show(dijit.byId("filterDlg_actionParam").domNode); + } + + } else { + Element.hide(action_param); + } + }, + createNewRuleElement: function(parentNode, replaceNode) { + const rule = dojo.formToJson("filter_new_rule_form"); + + xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => { + try { + const li = document.createElement('li'); + + li.innerHTML = ` + ${reply} + ${App.FormFields.hidden_tag("rule[]", rule)}`; + + dojo.parser.parse(li); + + if (replaceNode) { + parentNode.replaceChild(li, replaceNode); + } else { + parentNode.appendChild(li); + } + } catch (e) { + App.Error.report(e); + } + }); + }, + createNewActionElement: function(parentNode, replaceNode) { + const form = document.forms["filter_new_action_form"]; + + if (form.action_id.value == 7) { + form.action_param.value = form.action_param_label.value; + } else if (form.action_id.value == 9) { + form.action_param.value = form.action_param_plugin.value; + } + + const action = dojo.formToJson(form); + + xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => { + try { + const li = document.createElement('li'); + + li.innerHTML = ` + ${reply} + ${App.FormFields.hidden_tag("action[]", action)}`; + + dojo.parser.parse(li); + + if (replaceNode) { + parentNode.replaceChild(li, replaceNode); + } else { + parentNode.appendChild(li); + } + + } catch (e) { + App.Error.report(e); + } + }); + }, + addFilterRule: function(replaceNode, ruleStr) { + const add_dialog = new fox.SingleUseDialog({ + id: "filterNewRuleDlg", + title: ruleStr ? __("Edit rule") : __("Add rule"), + execute: function () { + if (this.validate()) { + dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); + this.hide(); + } + }, + content: __('Loading, please wait...'), + }); + + const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { + add_dialog.attr('content', reply); + }); + }); + + add_dialog.show(); + }, + addFilterAction: function(replaceNode, actionStr) { + const add_dialog = new fox.SingleUseDialog({ + title: actionStr ? __("Edit action") : __("Add action"), + execute: function () { + if (this.validate()) { + dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); + this.hide(); + } + } + }); + + const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { + add_dialog.attr('content', reply); + }); + }); + + add_dialog.show(); }, selectRules: function (select) { Lists.select("filterDlg_Matches", select); @@ -255,13 +251,13 @@ const Filters = { const li = e.closest('li'); const rule = li.querySelector('input[name="rule[]"]').value - Filters.addFilterRule(li, rule); + this.addFilterRule(li, rule); }, editAction: function (e) { const li = e.closest('li'); const action = li.querySelector('input[name="action[]"]').value - Filters.addFilterAction(li, action); + this.addFilterAction(li, action); }, removeFilter: function () { const msg = __("Remove filter?"); @@ -281,10 +277,10 @@ const Filters = { } }, addAction: function () { - Filters.addFilterAction(); + this.addFilterAction(); }, addRule: function () { - Filters.addFilterRule(); + this.addFilterRule(); }, deleteAction: function () { App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) { @@ -326,7 +322,7 @@ const Filters = { const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1}; - Filters.addFilterRule(null, dojo.toJson(rule)); + dialog.addFilterRule(null, dojo.toJson(rule)); } else { @@ -346,7 +342,7 @@ const Filters = { const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1}; - Filters.addFilterRule(null, dojo.toJson(rule)); + dialog.addFilterRule(null, dojo.toJson(rule)); } }); } From 590b1fc39e104bd41a8ab213b98b38345dba4eac Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sat, 20 Feb 2021 18:21:36 +0300 Subject: [PATCH 2/6] a few more methods shuffled around --- classes/pref/filters.php | 6 +-- js/CommonFilters.js | 104 ++++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/classes/pref/filters.php b/classes/pref/filters.php index cfff383d8..1aeaa8a3f 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -389,7 +389,7 @@ class Pref_Filters extends Handler_Protected { unset($line["match_on"]); print "
  • - ".$this->_get_rule_name($line)."". + ".$this->_get_rule_name($line)."". \Controls\hidden_tag("rule[]", (string)json_encode($line))."
  • "; } } @@ -429,7 +429,7 @@ class Pref_Filters extends Handler_Protected { unset($line["id"]); print "
  • - ".$this->_get_action_name($line)."". + ".$this->_get_action_name($line)."". \Controls\hidden_tag("action[]", (string)json_encode($line))."
  • "; } } @@ -861,7 +861,7 @@ class Pref_Filters extends Handler_Protected { print "
    "; print " - ${reply} + ${reply} ${App.FormFields.hidden_tag("rule[]", rule)}`; dojo.parser.parse(li); @@ -181,7 +152,7 @@ const Filters = { const li = document.createElement('li'); li.innerHTML = ` - ${reply} + ${reply} ${App.FormFields.hidden_tag("action[]", action)}`; dojo.parser.parse(li); @@ -197,8 +168,8 @@ const Filters = { } }); }, - addFilterRule: function(replaceNode, ruleStr) { - const add_dialog = new fox.SingleUseDialog({ + editRule: function(replaceNode, ruleStr) { + const edit_rule_dialog = new fox.SingleUseDialog({ id: "filterNewRuleDlg", title: ruleStr ? __("Edit rule") : __("Add rule"), execute: function () { @@ -210,19 +181,50 @@ const Filters = { content: __('Loading, please wait...'), }); - const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) { + const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) { dojo.disconnect(tmph); xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { - add_dialog.attr('content', reply); + edit_rule_dialog.attr('content', reply); }); }); - add_dialog.show(); + edit_rule_dialog.show(); }, - addFilterAction: function(replaceNode, actionStr) { - const add_dialog = new fox.SingleUseDialog({ + editAction: function(replaceNode, actionStr) { + const edit_action_dialog = new fox.SingleUseDialog({ title: actionStr ? __("Edit action") : __("Add action"), + hideOrShowActionParam: function(sender) { + const action = sender.value; + + const action_param = App.byId("filterDlg_paramBox"); + + if (!action_param) { + console.log("hideOrShowActionParam: can't find action param box!"); + return; + } + + // if selected action supports parameters, enable params field + if (action == 4 || action == 6 || action == 7 || action == 9) { + Element.show(action_param); + + Element.hide(dijit.byId("filterDlg_actionParam").domNode); + Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); + Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode); + + if (action == 7) { + Element.show(dijit.byId("filterDlg_actionParamLabel").domNode); + } else if (action == 9) { + Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode); + } else { + Element.show(dijit.byId("filterDlg_actionParam").domNode); + } + + } else { + Element.hide(action_param); + } + }, + execute: function () { if (this.validate()) { dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); @@ -231,15 +233,15 @@ const Filters = { } }); - const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) { + const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) { dojo.disconnect(tmph); xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { - add_dialog.attr('content', reply); + edit_action_dialog.attr('content', reply); }); }); - add_dialog.show(); + edit_action_dialog.show(); }, selectRules: function (select) { Lists.select("filterDlg_Matches", select); @@ -247,17 +249,17 @@ const Filters = { selectActions: function (select) { Lists.select("filterDlg_Actions", select); }, - editRule: function (e) { + onRuleClicked: function (e) { const li = e.closest('li'); const rule = li.querySelector('input[name="rule[]"]').value - this.addFilterRule(li, rule); + this.editRule(li, rule); }, - editAction: function (e) { + onActionClicked: function (e) { const li = e.closest('li'); const action = li.querySelector('input[name="action[]"]').value - this.addFilterAction(li, action); + this.editAction(li, action); }, removeFilter: function () { const msg = __("Remove filter?"); @@ -277,10 +279,10 @@ const Filters = { } }, addAction: function () { - this.addFilterAction(); + this.editAction(); }, addRule: function () { - this.addFilterRule(); + this.editRule(); }, deleteAction: function () { App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) { @@ -322,7 +324,7 @@ const Filters = { const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1}; - dialog.addFilterRule(null, dojo.toJson(rule)); + dialog.editRule(null, dojo.toJson(rule)); } else { @@ -342,7 +344,7 @@ const Filters = { const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1}; - dialog.addFilterRule(null, dojo.toJson(rule)); + dialog.editRule(null, dojo.toJson(rule)); } }); } From da97b29dbe7ac923fae5a0cddee141716d1da3e5 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sat, 20 Feb 2021 21:07:28 +0300 Subject: [PATCH 3/6] prevent filter selected text dialog from opening in wrong order --- js/App.js | 21 ++ js/CommonFilters.js | 594 ++++++++++++++++++++++---------------------- js/common.js | 22 -- 3 files changed, 313 insertions(+), 324 deletions(-) diff --git a/js/App.js b/js/App.js index 2041a6168..68f3740c5 100644 --- a/js/App.js +++ b/js/App.js @@ -358,6 +358,27 @@ const App = { return p; } }, + // http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac + getSelectedText: function() { + let text = ""; + + if (typeof window.getSelection != "undefined") { + const sel = window.getSelection(); + if (sel.rangeCount) { + const container = document.createElement("div"); + for (let i = 0, len = sel.rangeCount; i < len; ++i) { + container.appendChild(sel.getRangeAt(i).cloneContents()); + } + text = container.innerHTML; + } + } else if (typeof document.selection != "undefined") { + if (document.selection.type == "Text") { + text = document.selection.createRange().textText; + } + } + + return text.stripTags(); + }, displayIfChecked: function(checkbox, elemId) { if (checkbox.checked) { Element.show(elemId); diff --git a/js/CommonFilters.js b/js/CommonFilters.js index 210c63479..88f9c83f5 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -19,342 +19,332 @@ const Filters = { query = {op: "pref-filters", method: "edit", id: id}; } - xhr.post("backend.php", query, function (reply) { - try { - const dialog = new fox.SingleUseDialog({ - id: "filterEditDlg", - title: id ? __("Edit Filter") : __("Create Filter"), - test: function() { - const test_dialog = new fox.SingleUseDialog({ - title: "Test Filter", - results: 0, - limit: 100, - max_offset: 10000, - getTestResults: function (params, offset) { - params.method = 'testFilterDo'; - params.offset = offset; - params.limit = test_dialog.limit; + const dialog = new fox.SingleUseDialog({ + id: "filterEditDlg", + title: id ? __("Edit Filter") : __("Create Filter"), + test: function() { + const test_dialog = new fox.SingleUseDialog({ + title: "Test Filter", + results: 0, + limit: 100, + max_offset: 10000, + getTestResults: function (params, offset) { + params.method = 'testFilterDo'; + params.offset = offset; + params.limit = test_dialog.limit; - console.log("getTestResults:" + offset); + console.log("getTestResults:" + offset); - xhr.json("backend.php", params, (result) => { - try { - if (result && test_dialog && test_dialog.open) { - test_dialog.results += result.length; + xhr.json("backend.php", params, (result) => { + try { + if (result && test_dialog && test_dialog.open) { + test_dialog.results += result.length; - console.log("got results:" + result.length); + console.log("got results:" + result.length); - App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") - .replace("%f", test_dialog.results) - .replace("%d", offset); + App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") + .replace("%f", test_dialog.results) + .replace("%d", offset); - console.log(offset + " " + test_dialog.max_offset); + console.log(offset + " " + test_dialog.max_offset); - for (let i = 0; i < result.length; i++) { - const tmp = dojo.create("table", { innerHTML: result[i]}); + for (let i = 0; i < result.length; i++) { + const tmp = dojo.create("table", { innerHTML: result[i]}); - App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; - } - - if (test_dialog.results < 30 && offset < test_dialog.max_offset) { - - // get the next batch - window.setTimeout(function () { - test_dialog.getTestResults(params, offset + test_dialog.limit); - }, 0); - - } else { - // all done - - Element.hide("prefFilterLoadingIndicator"); - - if (test_dialog.results == 0) { - App.byId("prefFilterTestResultList").innerHTML = ` - ${__('No recent articles matching this filter have been found.')}`; - App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; - } else { - App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") - .replace("%d", test_dialog.results); - } - - } - - } else if (!result) { - console.log("getTestResults: can't parse results object"); - Element.hide("prefFilterLoadingIndicator"); - Notify.error("Error while trying to get filter test results."); - } else { - console.log("getTestResults: dialog closed, bailing out."); - } - } catch (e) { - App.Error.report(e); + App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; } - }); - }, - content: ` -
    -   - Looking for articles... -
    -
      + if (test_dialog.results < 30 && offset < test_dialog.max_offset) { -
      - -
      - ` - }); + // get the next batch + window.setTimeout(function () { + test_dialog.getTestResults(params, offset + test_dialog.limit); + }, 0); - const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) { - dojo.disconnect(tmph); - - test_dialog.getTestResults(dialog.attr('value'), 0); - }); - - test_dialog.show(); - }, - createNewRuleElement: function(parentNode, replaceNode) { - const rule = dojo.formToJson("filter_new_rule_form"); - - xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => { - try { - const li = document.createElement('li'); - - li.innerHTML = ` - ${reply} - ${App.FormFields.hidden_tag("rule[]", rule)}`; - - dojo.parser.parse(li); - - if (replaceNode) { - parentNode.replaceChild(li, replaceNode); - } else { - parentNode.appendChild(li); - } - } catch (e) { - App.Error.report(e); - } - }); - }, - createNewActionElement: function(parentNode, replaceNode) { - const form = document.forms["filter_new_action_form"]; - - if (form.action_id.value == 7) { - form.action_param.value = form.action_param_label.value; - } else if (form.action_id.value == 9) { - form.action_param.value = form.action_param_plugin.value; - } - - const action = dojo.formToJson(form); - - xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => { - try { - const li = document.createElement('li'); - - li.innerHTML = ` - ${reply} - ${App.FormFields.hidden_tag("action[]", action)}`; - - dojo.parser.parse(li); - - if (replaceNode) { - parentNode.replaceChild(li, replaceNode); - } else { - parentNode.appendChild(li); - } - - } catch (e) { - App.Error.report(e); - } - }); - }, - editRule: function(replaceNode, ruleStr) { - const edit_rule_dialog = new fox.SingleUseDialog({ - id: "filterNewRuleDlg", - title: ruleStr ? __("Edit rule") : __("Add rule"), - execute: function () { - if (this.validate()) { - dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); - this.hide(); - } - }, - content: __('Loading, please wait...'), - }); - - const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) { - dojo.disconnect(tmph); - - xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { - edit_rule_dialog.attr('content', reply); - }); - }); - - edit_rule_dialog.show(); - }, - editAction: function(replaceNode, actionStr) { - const edit_action_dialog = new fox.SingleUseDialog({ - title: actionStr ? __("Edit action") : __("Add action"), - hideOrShowActionParam: function(sender) { - const action = sender.value; - - const action_param = App.byId("filterDlg_paramBox"); - - if (!action_param) { - console.log("hideOrShowActionParam: can't find action param box!"); - return; - } - - // if selected action supports parameters, enable params field - if (action == 4 || action == 6 || action == 7 || action == 9) { - Element.show(action_param); - - Element.hide(dijit.byId("filterDlg_actionParam").domNode); - Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); - Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode); - - if (action == 7) { - Element.show(dijit.byId("filterDlg_actionParamLabel").domNode); - } else if (action == 9) { - Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode); } else { - Element.show(dijit.byId("filterDlg_actionParam").domNode); + // all done + + Element.hide("prefFilterLoadingIndicator"); + + if (test_dialog.results == 0) { + App.byId("prefFilterTestResultList").innerHTML = ` + ${__('No recent articles matching this filter have been found.')}`; + App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; + } else { + App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") + .replace("%d", test_dialog.results); + } + } + } else if (!result) { + console.log("getTestResults: can't parse results object"); + Element.hide("prefFilterLoadingIndicator"); + Notify.error("Error while trying to get filter test results."); } else { - Element.hide(action_param); - } - }, - - execute: function () { - if (this.validate()) { - dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); - this.hide(); + console.log("getTestResults: dialog closed, bailing out."); } + } catch (e) { + App.Error.report(e); } }); - - const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) { - dojo.disconnect(tmph); - - xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { - edit_action_dialog.attr('content', reply); - }); - }); - - edit_action_dialog.show(); }, - selectRules: function (select) { - Lists.select("filterDlg_Matches", select); - }, - selectActions: function (select) { - Lists.select("filterDlg_Actions", select); - }, - onRuleClicked: function (e) { - const li = e.closest('li'); - const rule = li.querySelector('input[name="rule[]"]').value + content: ` +
      +   + Looking for articles... +
      - this.editRule(li, rule); - }, - onActionClicked: function (e) { - const li = e.closest('li'); - const action = li.querySelector('input[name="action[]"]').value +
        - this.editAction(li, action); - }, - removeFilter: function () { - const msg = __("Remove filter?"); - - if (confirm(msg)) { - this.hide(); - - Notify.progress("Removing filter..."); - - const query = {op: "pref-filters", method: "remove", ids: this.attr('value').id}; - - xhr.post("backend.php", query, () => { - const tree = dijit.byId("filterTree"); - - if (tree) tree.reload(); - }); - } - }, - addAction: function () { - this.editAction(); - }, - addRule: function () { - this.editRule(); - }, - deleteAction: function () { - App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) { - e.parentNode.removeChild(e) - }); - }, - deleteRule: function () { - App.findAll("#filterDlg_Matches li[class*=Selected]").forEach(function (e) { - e.parentNode.removeChild(e) - }); - }, - execute: function () { - if (this.validate()) { - - Notify.progress("Saving data...", true); - - xhr.post("backend.php", this.attr('value'), () => { - dialog.hide(); - - const tree = dijit.byId("filterTree"); - if (tree) tree.reload(); - }); - } - }, - content: reply +
        + +
        + ` }); - if (!App.isPrefs()) { - /* global getSelectionText */ - const selectedText = getSelectionText(); + const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); - const lh = dojo.connect(dialog, "onShow", function () { - dojo.disconnect(lh); + test_dialog.getTestResults(dialog.attr('value'), 0); + }); - if (selectedText != "") { + test_dialog.show(); + }, + createNewRuleElement: function(parentNode, replaceNode) { + const rule = dojo.formToJson("filter_new_rule_form"); - const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) : - Feeds.getActive(); + xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => { + try { + const li = document.createElement('li'); - const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1}; + li.innerHTML = ` + ${reply} + ${App.FormFields.hidden_tag("rule[]", rule)}`; - dialog.editRule(null, dojo.toJson(rule)); + dojo.parser.parse(li); + + if (replaceNode) { + parentNode.replaceChild(li, replaceNode); + } else { + parentNode.appendChild(li); + } + } catch (e) { + App.Error.report(e); + } + }); + }, + createNewActionElement: function(parentNode, replaceNode) { + const form = document.forms["filter_new_action_form"]; + + if (form.action_id.value == 7) { + form.action_param.value = form.action_param_label.value; + } else if (form.action_id.value == 9) { + form.action_param.value = form.action_param_plugin.value; + } + + const action = dojo.formToJson(form); + + xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => { + try { + const li = document.createElement('li'); + + li.innerHTML = ` + ${reply} + ${App.FormFields.hidden_tag("action[]", action)}`; + + dojo.parser.parse(li); + + if (replaceNode) { + parentNode.replaceChild(li, replaceNode); + } else { + parentNode.appendChild(li); + } + + } catch (e) { + App.Error.report(e); + } + }); + }, + editRule: function(replaceNode, ruleStr) { + const edit_rule_dialog = new fox.SingleUseDialog({ + id: "filterNewRuleDlg", + title: ruleStr ? __("Edit rule") : __("Add rule"), + execute: function () { + if (this.validate()) { + dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); + this.hide(); + } + }, + content: __('Loading, please wait...'), + }); + + const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { + edit_rule_dialog.attr('content', reply); + }); + }); + + edit_rule_dialog.show(); + }, + editAction: function(replaceNode, actionStr) { + const edit_action_dialog = new fox.SingleUseDialog({ + title: actionStr ? __("Edit action") : __("Add action"), + hideOrShowActionParam: function(sender) { + const action = sender.value; + + const action_param = App.byId("filterDlg_paramBox"); + + if (!action_param) { + console.log("hideOrShowActionParam: can't find action param box!"); + return; + } + + // if selected action supports parameters, enable params field + if (action == 4 || action == 6 || action == 7 || action == 9) { + Element.show(action_param); + + Element.hide(dijit.byId("filterDlg_actionParam").domNode); + Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); + Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode); + + if (action == 7) { + Element.show(dijit.byId("filterDlg_actionParamLabel").domNode); + } else if (action == 9) { + Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode); + } else { + Element.show(dijit.byId("filterDlg_actionParam").domNode); + } } else { - - const query = {op: "article", method: "getmetadatabyid", id: Article.getActive()}; - - xhr.json("backend.php", query, (reply) => { - let title = false; - - if (reply && reply.title) title = reply.title; - - if (title || Feeds.getActive() || Feeds.activeIsCat()) { - - console.log(title + " " + Feeds.getActive()); - - const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) : - Feeds.getActive(); - - const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1}; - - dialog.editRule(null, dojo.toJson(rule)); - } - }); + Element.hide(action_param); } + }, + + execute: function () { + if (this.validate()) { + dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); + this.hide(); + } + } + }); + + const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { + edit_action_dialog.attr('content', reply); + }); + }); + + edit_action_dialog.show(); + }, + selectRules: function (select) { + Lists.select("filterDlg_Matches", select); + }, + selectActions: function (select) { + Lists.select("filterDlg_Actions", select); + }, + onRuleClicked: function (e) { + const li = e.closest('li'); + const rule = li.querySelector('input[name="rule[]"]').value + + this.editRule(li, rule); + }, + onActionClicked: function (e) { + const li = e.closest('li'); + const action = li.querySelector('input[name="action[]"]').value + + this.editAction(li, action); + }, + removeFilter: function () { + const msg = __("Remove filter?"); + + if (confirm(msg)) { + this.hide(); + + Notify.progress("Removing filter..."); + + const query = {op: "pref-filters", method: "remove", ids: this.attr('value').id}; + + xhr.post("backend.php", query, () => { + const tree = dijit.byId("filterTree"); + + if (tree) tree.reload(); }); } - dialog.show(); + }, + addAction: function () { + this.editAction(); + }, + addRule: function () { + this.editRule(); + }, + deleteAction: function () { + App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) { + e.parentNode.removeChild(e) + }); + }, + deleteRule: function () { + App.findAll("#filterDlg_Matches li[class*=Selected]").forEach(function (e) { + e.parentNode.removeChild(e) + }); + }, + execute: function () { + if (this.validate()) { - } catch (e) { - App.Error.report(e); - } + Notify.progress("Saving data...", true); + + xhr.post("backend.php", this.attr('value'), () => { + dialog.hide(); + + const tree = dijit.byId("filterTree"); + if (tree) tree.reload(); + }); + } + }, + content: __("Loading, please wait...") }); + + const tmph = dojo.connect(dialog, 'onShow', function () { + dojo.disconnect(tmph); + + xhr.post("backend.php", query, function (reply) { + dialog.attr('content', reply); + + if (!App.isPrefs()) { + const selectedText = App.getSelectedText(); + + if (selectedText != "") { + const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) : + Feeds.getActive(); + const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1}; + + dialog.editRule(null, dojo.toJson(rule)); + } else { + const query = {op: "article", method: "getmetadatabyid", id: Article.getActive()}; + + xhr.json("backend.php", query, (reply) => { + let title; + + if (reply && reply.title) title = reply.title; + + if (title || Feeds.getActive() || Feeds.activeIsCat()) { + console.log(title + " " + Feeds.getActive()); + + const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) : + Feeds.getActive(); + const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1}; + + dialog.editRule(null, dojo.toJson(rule)); + } + }); + } + } + }); + }); + dialog.show(); }, }; diff --git a/js/common.js b/js/common.js index 6e8168357..01fe321f7 100755 --- a/js/common.js +++ b/js/common.js @@ -401,25 +401,3 @@ const Notify = { } }; -// http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac -/* exported getSelectionText */ -function getSelectionText() { - let text = ""; - - if (typeof window.getSelection != "undefined") { - const sel = window.getSelection(); - if (sel.rangeCount) { - const container = document.createElement("div"); - for (let i = 0, len = sel.rangeCount; i < len; ++i) { - container.appendChild(sel.getRangeAt(i).cloneContents()); - } - text = container.innerHTML; - } - } else if (typeof document.selection != "undefined") { - if (document.selection.type == "Text") { - text = document.selection.createRange().textText; - } - } - - return text.stripTags(); -} From b4e96374bcc14b3be353f87a80f83b34615dec73 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sat, 20 Feb 2021 21:48:05 +0300 Subject: [PATCH 4/6] more filter stuff --- classes/pref/filters.php | 20 ++++++++--------- js/CommonFilters.js | 47 +++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/classes/pref/filters.php b/classes/pref/filters.php index 1aeaa8a3f..9c250be19 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -860,7 +860,7 @@ class Pref_Filters extends Handler_Protected { print "
        "; - print ""; - $param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ? - "" : "display : none"; + #$param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ? + # "" : "display : none"; - $param_hidden = ($action_id == 4 || $action_id == 6) ? - "" : "display : none"; + #$param_hidden = ($action_id == 4 || $action_id == 6) ? + # "" : "display : none"; - $label_param_hidden = ($action_id == 7) ? "" : "display : none"; - $plugin_param_hidden = ($action_id == 9) ? "" : "display : none"; + #$label_param_hidden = ($action_id == 7) ? "" : "display : none"; + #$plugin_param_hidden = ($action_id == 9) ? "" : "display : none"; - print ""; - print " "; + #print ""; + #print " "; //print " " . __("with parameters:") . " "; print " $plugin_param_hidden], $filter_plugin_disabled), "filterDlg_actionParamPlugin"); - print ""; + #print ""; print " "; // tiny layout hack diff --git a/js/CommonFilters.js b/js/CommonFilters.js index 88f9c83f5..bd6808f59 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -22,6 +22,11 @@ const Filters = { const dialog = new fox.SingleUseDialog({ id: "filterEditDlg", title: id ? __("Edit Filter") : __("Create Filter"), + ACTION_TAG: 4, + ACTION_SCORE: 6, + ACTION_LABEL: 7, + ACTION_PLUGIN: 9, + PARAM_ACTIONS: [4, 6, 7, 9], test: function() { const test_dialog = new fox.SingleUseDialog({ title: "Test Filter", @@ -193,36 +198,21 @@ const Filters = { const edit_action_dialog = new fox.SingleUseDialog({ title: actionStr ? __("Edit action") : __("Add action"), hideOrShowActionParam: function(sender) { - const action = sender.value; + const action = parseInt(sender.value); - const action_param = App.byId("filterDlg_paramBox"); - - if (!action_param) { - console.log("hideOrShowActionParam: can't find action param box!"); - return; - } + dijit.byId("filterDlg_actionParam").domNode.hide(); + dijit.byId("filterDlg_actionParamLabel").domNode.hide(); + dijit.byId("filterDlg_actionParamPlugin").domNode.hide(); // if selected action supports parameters, enable params field - if (action == 4 || action == 6 || action == 7 || action == 9) { - Element.show(action_param); - - Element.hide(dijit.byId("filterDlg_actionParam").domNode); - Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); - Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode); - - if (action == 7) { - Element.show(dijit.byId("filterDlg_actionParamLabel").domNode); - } else if (action == 9) { - Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode); - } else { - Element.show(dijit.byId("filterDlg_actionParam").domNode); - } - - } else { - Element.hide(action_param); + if (action == dialog.ACTION_LABEL) { + dijit.byId("filterDlg_actionParamLabel").domNode.show(); + } else if (action == dialog.ACTION_PLUGIN) { + dijit.byId("filterDlg_actionParamPlugin").domNode.show(); + } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) { + dijit.byId("filterDlg_actionParam").domNode.show(); } }, - execute: function () { if (this.validate()) { dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); @@ -236,6 +226,10 @@ const Filters = { xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { edit_action_dialog.attr('content', reply); + + setTimeout(() => { + edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value')); + }, 250); }); }); @@ -308,6 +302,8 @@ const Filters = { content: __("Loading, please wait...") }); + + const tmph = dojo.connect(dialog, 'onShow', function () { dojo.disconnect(tmph); @@ -345,6 +341,7 @@ const Filters = { } }); }); + dialog.show(); }, }; From 94560132ddf45a5a7c68ce520b40ecb10a6f89fe Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 21 Feb 2021 09:35:07 +0300 Subject: [PATCH 5/6] for the most part, deal with filter rules UI --- classes/labels.php | 15 +- classes/pref/filters.php | 261 ++++++++++++++++-------- classes/rpc.php | 4 +- include/controls.php | 16 +- js/CommonFilters.js | 294 ++++++++++++++++++++++++---- plugins/auto_assign_labels/init.php | 1 + themes/compact.css | 20 +- themes/compact_night.css | 20 +- themes/light.css | 20 +- themes/light/tt-rss.less | 8 +- themes/night.css | 20 +- themes/night_blue.css | 20 +- 12 files changed, 510 insertions(+), 189 deletions(-) diff --git a/classes/labels.php b/classes/labels.php index f72d7d84b..570f24f4f 100644 --- a/classes/labels.php +++ b/classes/labels.php @@ -37,7 +37,18 @@ class Labels } } - static function get_all_labels($owner_uid) { + static function get_as_hash($owner_uid) { + $rv = []; + $labels = Labels::get_all($owner_uid); + + foreach ($labels as $i => $label) { + $rv[$label["id"]] = $labels[$i]; + } + + return $rv; + } + + static function get_all($owner_uid) { $rv = array(); $pdo = Db::pdo(); @@ -46,7 +57,7 @@ class Labels WHERE owner_uid = ? ORDER BY caption"); $sth->execute([$owner_uid]); - while ($line = $sth->fetch()) { + while ($line = $sth->fetch(PDO::FETCH_ASSOC)) { array_push($rv, $line); } diff --git a/classes/pref/filters.php b/classes/pref/filters.php index 9c250be19..4e52260c9 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -318,6 +318,84 @@ class Pref_Filters extends Handler_Protected { WHERE id = ? AND owner_uid = ?"); $sth->execute([$filter_id, $_SESSION['uid']]); + if (empty($filter_id) || $row = $sth->fetch()) { + $rv = [ + "id" => $filter_id, + "enabled" => $row["enabled"] ?? true, + "match_any_rule" => $row["match_any_rule"] ?? false, + "inverse" => $row["inverse"] ?? false, + "title" => $row["title"] ?? "", + "rules" => [], + "actions" => [], + "filter_types" => [], + "filter_actions" => [], + "labels" => Labels::get_all($_SESSION["uid"]) + ]; + + $res = $this->pdo->query("SELECT id,description + FROM ttrss_filter_types WHERE id != 5 ORDER BY description"); + + while ($line = $res->fetch()) { + $rv["filter_types"][$line["id"]] = __($line["description"]); + } + + $res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions + ORDER BY name"); + + while ($line = $res->fetch()) { + $rv["filter_actions"][$line["id"]] = __($line["description"]); + } + + if ($filter_id) { + $rules_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_rules + WHERE filter_id = ? ORDER BY reg_exp, id"); + $rules_sth->execute([$filter_id]); + + while ($rrow = $rules_sth->fetch(PDO::FETCH_ASSOC)) { + if ($rrow["match_on"]) { + $rrow["feed_id"] = json_decode($rrow["match_on"], true); + } else { + if ($rrow["cat_filter"]) { + $feed_id = "CAT:" . (int)$rrow["cat_id"]; + } else { + $feed_id = (int)$rrow["feed_id"]; + } + + $rrow["feed_id"] = ["" . $feed_id]; // set item type to string for in_array() + } + + unset($rrow["cat_filter"]); + unset($rrow["cat_id"]); + unset($rrow["filter_id"]); + unset($rrow["id"]); + if (!$rrow["inverse"]) unset($rrow["inverse"]); + unset($rrow["match_on"]); + + $rrow["name"] = $this->_get_rule_name($rrow); + + array_push($rv["rules"], $rrow); + } + + $actions_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_actions + WHERE filter_id = ? ORDER BY id"); + $actions_sth->execute([$filter_id]); + + while ($arow = $actions_sth->fetch(PDO::FETCH_ASSOC)) { + $arow["action_param_label"] = $arow["action_param"]; + + unset($arow["filter_id"]); + unset($arow["id"]); + + $arow["name"] = $this->_get_action_name($arow); + + array_push($rv["actions"], $arow); + } + } + print json_encode($rv); + } + + /*return; + if (empty($filter_id) || $row = $sth->fetch()) { $enabled = $row["enabled"] ?? true; @@ -475,7 +553,7 @@ class Pref_Filters extends Handler_Protected { } print ""; - } + } */ } private function _get_rule_name($rule) { @@ -592,8 +670,7 @@ class Pref_Filters extends Handler_Protected { $sth->execute(array_merge($ids, [$_SESSION['uid']])); } - private function _save_rules_and_actions($filter_id) - { + private function _save_rules_and_actions($filter_id) { $sth = $this->pdo->prepare("DELETE FROM ttrss_filters2_rules WHERE filter_id = ?"); $sth->execute([$filter_id]); @@ -670,7 +747,7 @@ class Pref_Filters extends Handler_Protected { } } - function add() { + function add () { $enabled = checkbox_to_sql_bool(clean($_REQUEST["enabled"] ?? false)); $match_any_rule = checkbox_to_sql_bool(clean($_REQUEST["match_any_rule"] ?? false)); $title = clean($_REQUEST["title"]); @@ -764,7 +841,15 @@ class Pref_Filters extends Handler_Protected { $this->feed_multi_select("feed_id", $feed_ids, 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"') + ]); + + /*return; + $rule = json_decode(clean($_REQUEST["rule"]), true); if ($rule) { @@ -818,7 +903,7 @@ class Pref_Filters extends Handler_Protected { print "
        "; print ""; - $this->feed_multi_select("feed_id", + print $this->feed_multi_select("feed_id", $feed_id, 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"'); print ""; @@ -840,7 +925,7 @@ class Pref_Filters extends Handler_Protected { print ""; - print ""; + print "";*/ } function newaction() { @@ -1071,102 +1156,106 @@ class Pref_Filters extends Handler_Protected { $attributes = "", $include_all_feeds = true, $root_id = null, $nest_level = 0) { - $pdo = Db::pdo(); + $pdo = Db::pdo(); - // print_r(in_array("CAT:6",$default_ids)); + $rv = ""; - if (!$root_id) { - print ""; + if ($include_all_feeds) { + $is_selected = (in_array("0", $default_ids)) ? "selected=\"1\"" : ""; + $rv .= ""; + } } - } - if (get_pref('ENABLE_FEED_CATS')) { + if (get_pref('ENABLE_FEED_CATS')) { - if (!$root_id) $root_id = null; + if (!$root_id) $root_id = null; - $sth = $pdo->prepare("SELECT id,title, - (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE - c2.parent_cat = ttrss_feed_categories.id) AS num_children - FROM ttrss_feed_categories - WHERE owner_uid = :uid AND - (parent_cat = :root_id OR (:root_id IS NULL AND parent_cat IS NULL)) ORDER BY title"); + $sth = $pdo->prepare("SELECT id,title, + (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE + c2.parent_cat = ttrss_feed_categories.id) AS num_children + FROM ttrss_feed_categories + WHERE owner_uid = :uid AND + (parent_cat = :root_id OR (:root_id IS NULL AND parent_cat IS NULL)) ORDER BY title"); - $sth->execute([":uid" => $_SESSION['uid'], ":root_id" => $root_id]); + $sth->execute([":uid" => $_SESSION['uid'], ":root_id" => $root_id]); - while ($line = $sth->fetch()) { - - for ($i = 0; $i < $nest_level; $i++) - $line["title"] = " " . $line["title"]; - - $is_selected = in_array("CAT:".$line["id"], $default_ids) ? "selected=\"1\"" : ""; - - printf("", - $line["id"], htmlspecialchars($line["title"])); - - if ($line["num_children"] > 0) - $this->feed_multi_select($id, $default_ids, $attributes, - $include_all_feeds, $line["id"], $nest_level+1); - - $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds - WHERE cat_id = ? AND owner_uid = ? ORDER BY title"); - - $f_sth->execute([$line['id'], $_SESSION['uid']]); - - while ($fline = $f_sth->fetch()) { - $is_selected = (in_array($fline["id"], $default_ids)) ? "selected=\"1\"" : ""; - - $fline["title"] = " " . $fline["title"]; + while ($line = $sth->fetch()) { for ($i = 0; $i < $nest_level; $i++) + $line["title"] = " " . $line["title"]; + + $is_selected = in_array("CAT:".$line["id"], $default_ids) ? "selected=\"1\"" : ""; + + $rv .= sprintf("", + $line["id"], htmlspecialchars($line["title"])); + + if ($line["num_children"] > 0) + $rv .= $this->feed_multi_select($id, $default_ids, $attributes, + $include_all_feeds, $line["id"], $nest_level+1); + + $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds + WHERE cat_id = ? AND owner_uid = ? ORDER BY title"); + + $f_sth->execute([$line['id'], $_SESSION['uid']]); + + while ($fline = $f_sth->fetch()) { + $is_selected = (in_array($fline["id"], $default_ids)) ? "selected=\"1\"" : ""; + $fline["title"] = " " . $fline["title"]; - printf("", - $fline["id"], htmlspecialchars($fline["title"])); + for ($i = 0; $i < $nest_level; $i++) + $fline["title"] = " " . $fline["title"]; + + $rv .= sprintf("", + $fline["id"], htmlspecialchars($fline["title"])); + } + } + + if (!$root_id) { + $is_selected = in_array("CAT:0", $default_ids) ? "selected=\"1\"" : ""; + + $rv .= sprintf("", + __("Uncategorized")); + + $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds + WHERE cat_id IS NULL AND owner_uid = ? ORDER BY title"); + $f_sth->execute([$_SESSION['uid']]); + + while ($fline = $f_sth->fetch()) { + $is_selected = in_array($fline["id"], $default_ids) ? "selected=\"1\"" : ""; + + $fline["title"] = " " . $fline["title"]; + + for ($i = 0; $i < $nest_level; $i++) + $fline["title"] = " " . $fline["title"]; + + $rv .= sprintf("", + $fline["id"], htmlspecialchars($fline["title"])); + } + } + + } else { + $sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds + WHERE owner_uid = ? ORDER BY title"); + $sth->execute([$_SESSION['uid']]); + + while ($line = $sth->fetch()) { + + $is_selected = (in_array($line["id"], $default_ids)) ? "selected=\"1\"" : ""; + + $rv .= sprintf("", + $line["id"], htmlspecialchars($line["title"])); } } if (!$root_id) { - $is_selected = in_array("CAT:0", $default_ids) ? "selected=\"1\"" : ""; - - printf("", - __("Uncategorized")); - - $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds - WHERE cat_id IS NULL AND owner_uid = ? ORDER BY title"); - $f_sth->execute([$_SESSION['uid']]); - - while ($fline = $f_sth->fetch()) { - $is_selected = in_array($fline["id"], $default_ids) ? "selected=\"1\"" : ""; - - $fline["title"] = " " . $fline["title"]; - - for ($i = 0; $i < $nest_level; $i++) - $fline["title"] = " " . $fline["title"]; - - printf("", - $fline["id"], htmlspecialchars($fline["title"])); - } + $rv .= ""; } - } else { - $sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds - WHERE owner_uid = ? ORDER BY title"); - $sth->execute([$_SESSION['uid']]); - - while ($line = $sth->fetch()) { - - $is_selected = (in_array($line["id"], $default_ids)) ? "selected=\"1\"" : ""; - - printf("", - $line["id"], htmlspecialchars($line["title"])); - } - } - - if (!$root_id) { - print ""; + return $rv; } } -} diff --git a/classes/rpc.php b/classes/rpc.php index 643ad29d8..20a11b994 100755 --- a/classes/rpc.php +++ b/classes/rpc.php @@ -399,7 +399,7 @@ class RPC extends Handler_Protected { $params["icon_indicator_white"] = $this->image_to_base64("images/indicator_white.gif"); - $params["labels"] = Labels::get_all_labels($_SESSION["uid"]); + $params["labels"] = Labels::get_all($_SESSION["uid"]); return $params; } @@ -430,7 +430,7 @@ class RPC extends Handler_Protected { $data["max_feed_id"] = (int) $max_feed_id; $data["num_feeds"] = (int) $num_feeds; $data['cdm_expanded'] = get_pref('CDM_EXPANDED'); - $data["labels"] = Labels::get_all_labels($_SESSION["uid"]); + $data["labels"] = Labels::get_all($_SESSION["uid"]); if (LOG_DESTINATION == 'sql' && $_SESSION['access_level'] >= 10) { if (DB_TYPE == 'pgsql') { diff --git a/include/controls.php b/include/controls.php index ae5fba739..e3349d31b 100755 --- a/include/controls.php +++ b/include/controls.php @@ -60,21 +60,11 @@ return $rv; } - function select_labels(string $name, string $value, array $attributes = [], string $id = "") { - $pdo = \Db::pdo(); - - $sth = $pdo->prepare("SELECT caption FROM ttrss_labels2 - WHERE owner_uid = ? ORDER BY caption"); - $sth->execute([$_SESSION['uid']]); - - $values = []; - - while ($row = $sth->fetch()) { - array_push($values, $row["caption"]); - } + /*function select_labels(string $name, string $value, array $attributes = [], string $id = "") { + $values = \Labels::get_as_hash($_SESSION["uid"]); return select_tag($name, $value, $values, $attributes, $id); - } + }*/ function select_hash(string $name, $value, array $values, array $attributes = [], string $id = "") { $attributes_str = attributes_to_string($attributes); diff --git a/js/CommonFilters.js b/js/CommonFilters.js index bd6808f59..75e1fa8af 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -7,26 +7,17 @@ /* exported Filters */ const Filters = { - edit: function(id) { // if no id, new filter dialog - let query; - - if (!App.isPrefs()) { - query = { - op: "pref-filters", method: "edit", - feed: Feeds.getActive(), is_cat: Feeds.activeIsCat() - }; - } else { - query = {op: "pref-filters", method: "edit", id: id}; - } + edit: function(filter_id = null) { // if no id, new filter dialog const dialog = new fox.SingleUseDialog({ id: "filterEditDlg", - title: id ? __("Edit Filter") : __("Create Filter"), + title: filter_id ? __("Edit Filter") : __("Create Filter"), ACTION_TAG: 4, ACTION_SCORE: 6, ACTION_LABEL: 7, ACTION_PLUGIN: 9, PARAM_ACTIONS: [4, 6, 7, 9], + filter_info: {}, test: function() { const test_dialog = new fox.SingleUseDialog({ title: "Test Filter", @@ -116,16 +107,17 @@ const Filters = { test_dialog.show(); }, - createNewRuleElement: function(parentNode, replaceNode) { + insertRule: function(parentNode, replaceNode) { const rule = dojo.formToJson("filter_new_rule_form"); xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => { try { const li = document.createElement('li'); + li.addClassName("rule"); - li.innerHTML = ` - ${reply} - ${App.FormFields.hidden_tag("rule[]", rule)}`; + li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})} + ${reply} + ${App.FormFields.hidden_tag("rule[]", rule)}`; dojo.parser.parse(li); @@ -139,7 +131,7 @@ const Filters = { } }); }, - createNewActionElement: function(parentNode, replaceNode) { + insertAction: function(parentNode, replaceNode) { const form = document.forms["filter_new_action_form"]; if (form.action_id.value == 7) { @@ -153,10 +145,11 @@ const Filters = { xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => { try { const li = document.createElement('li'); + li.addClassName("action"); - li.innerHTML = ` - ${reply} - ${App.FormFields.hidden_tag("action[]", action)}`; + li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})} + ${reply} + ${App.FormFields.hidden_tag("action[]", action)}`; dojo.parser.parse(li); @@ -171,30 +164,84 @@ const Filters = { } }); }, - editRule: function(replaceNode, ruleStr) { + editRule: function(replaceNode, ruleStr = null) { const edit_rule_dialog = new fox.SingleUseDialog({ id: "filterNewRuleDlg", title: ruleStr ? __("Edit rule") : __("Add rule"), execute: function () { if (this.validate()) { - dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); + dialog.insertRule(App.byId("filterDlg_Matches"), replaceNode); this.hide(); } }, content: __('Loading, please wait...'), }); - const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) { + const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function () { dojo.disconnect(tmph); - xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => { - edit_rule_dialog.attr('content', reply); + let rule; + + if (ruleStr) { + rule = JSON.parse(ruleStr); + } else { + rule = { + reg_exp: "", + filter_type: 1, + feed_id: ["0"], + inverse: false, + }; + } + + console.log(rule, dialog.filter_info); + + xhr.json("backend.php", {op: "pref-filters", method: "editrule", ids: rule.feed_id.join(",")}, function (editrule) { + edit_rule_dialog.attr('content', + ` +
        + +
        + + +
        + +
        + +
        +
        + + ${App.FormFields.select_hash("filter_type", rule.filter_type, dialog.filter_info.filter_types)} + +
        +
        + + ${editrule.multiselect} + +
        +
        + +
        + ${App.FormFields.button_tag(App.FormFields.icon("help") + " " + __("More info"), "", {class: 'pull-left alt-info', + onclick: "window.open('https://tt-rss.org/wiki/ContentFilters')"})} + ${App.FormFields.submit_tag(__("Save rule"), {onclick: "App.dialogOf(this).execute()"})} + ${App.FormFields.cancel_dialog_tag(__("Cancel"))} +
        + +
        + `); }); + }); edit_rule_dialog.show(); }, - editAction: function(replaceNode, actionStr) { + /*editAction: function(replaceNode, actionStr) { const edit_action_dialog = new fox.SingleUseDialog({ title: actionStr ? __("Edit action") : __("Add action"), hideOrShowActionParam: function(sender) { @@ -221,7 +268,7 @@ const Filters = { } }); - const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) { + const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () { dojo.disconnect(tmph); xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { @@ -234,22 +281,65 @@ const Filters = { }); edit_action_dialog.show(); - }, + }, */ + /*editAction: function(replaceNode, actionStr) { + const edit_action_dialog = new fox.SingleUseDialog({ + title: actionStr ? __("Edit action") : __("Add action"), + hideOrShowActionParam: function(sender) { + const action = parseInt(sender.value); + + dijit.byId("filterDlg_actionParam").domNode.hide(); + dijit.byId("filterDlg_actionParamLabel").domNode.hide(); + dijit.byId("filterDlg_actionParamPlugin").domNode.hide(); + + // if selected action supports parameters, enable params field + if (action == dialog.ACTION_LABEL) { + dijit.byId("filterDlg_actionParamLabel").domNode.show(); + } else if (action == dialog.ACTION_PLUGIN) { + dijit.byId("filterDlg_actionParamPlugin").domNode.show(); + } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) { + dijit.byId("filterDlg_actionParam").domNode.show(); + } + }, + execute: function () { + if (this.validate()) { + dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); + this.hide(); + } + } + }); + + const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () { + dojo.disconnect(tmph); + + xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { + edit_action_dialog.attr('content', reply); + + setTimeout(() => { + edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value')); + }, 250); + }); + }); + + edit_action_dialog.show(); + },*/ selectRules: function (select) { Lists.select("filterDlg_Matches", select); }, selectActions: function (select) { Lists.select("filterDlg_Actions", select); }, - onRuleClicked: function (e) { - const li = e.closest('li'); - const rule = li.querySelector('input[name="rule[]"]').value + onRuleClicked: function (elem) { + + const li = elem.closest('li'); + const rule = li.querySelector('input[name="rule[]"]').value; this.editRule(li, rule); }, - onActionClicked: function (e) { - const li = e.closest('li'); - const action = li.querySelector('input[name="action[]"]').value + onActionClicked: function (elem) { + + const li = elem.closest('li'); + const action = li.querySelector('input[name="action[]"]').value; this.editAction(li, action); }, @@ -302,13 +392,141 @@ const Filters = { content: __("Loading, please wait...") }); - - const tmph = dojo.connect(dialog, 'onShow', function () { dojo.disconnect(tmph); - xhr.post("backend.php", query, function (reply) { - dialog.attr('content', reply); + const query = {op: "pref-filters", method: "edit", id: filter_id}; + + /*if (!App.isPrefs()) { + query = { + op: "pref-filters", method: "edit", + feed: Feeds.getActive(), is_cat: Feeds.activeIsCat() + }; + } else { + query = {op: "pref-filters", method: "edit", id: id}; + }*/ + + xhr.json("backend.php", query, function (filter) { + + dialog.filter_info = filter; + + const options = { + enabled: [ filter.enabled, __('Enabled') ], + match_any_rule: [ filter.match_any_rule, __('Match any rule') ], + inverse: [ filter.inverse, __('Inverse matching') ], + }; + + dialog.attr('content', + ` +
        + + ${App.FormFields.hidden_tag("op", "pref-filters")} + ${App.FormFields.hidden_tag("id", filter_id)} + ${App.FormFields.hidden_tag("method", filter_id ? "editSave" : "add")} + ${App.FormFields.hidden_tag("csrf_token", App.getInitParam('csrf_token'))} + +
        + +
        + +
        +
        +
        +
        +
        + ${__("Select")} +
        + +
        ${__("All")}
        +
        ${__("None")}
        +
        +
        + + +
        +
        +
          + ${filter.rules.map((rule) => ` +
        • + ${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})} + ${rule.name} + ${App.FormFields.hidden_tag("rule[]", JSON.stringify(rule))} +
        • + `).join("")} +
        +
        +
        +
        +
        +
        +
        +
        + ${__("Select")} +
        +
        ${__("All")}
        +
        ${__("None")}
        +
        +
        + + +
        +
        +
          + ${filter.actions.map((action) => ` +
        • + ${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})} + ${App.escapeHtml(action.name)} + ${App.FormFields.hidden_tag("action[]", JSON.stringify(action))} +
        • + `).join("")} +
        +
        +
        +
        +
        + +
        + +
        + ${Object.keys(options).map((name) => + ` +
        + +
        + `).join("")} +
        + +
        + ${filter_id ? + ` + ${App.FormFields.button_tag(__("Remove"), "", {class: "pull-left alt-danger", onclick: "App.dialogOf(this).removeFilter()"})} + ${App.FormFields.button_tag(__("Test"), "", {class: "alt-info", onclick: "App.dialogOf(this).test()"})} + ${App.FormFields.submit_tag(__("Save"), {onclick: "App.dialogOf(this).execute()"})} + ${App.FormFields.cancel_dialog_tag(__("Cancel"))} + ` : ` + ${App.FormFields.button_tag(__("Test"), "", {class: "alt-info", onclick: "App.dialogOf(this).test()"})} + ${App.FormFields.submit_tag(__("Create"), {onclick: "App.dialogOf(this).execute()"})} + ${App.FormFields.cancel_dialog_tag(__("Cancel"))} + `} +
        +
        + `); if (!App.isPrefs()) { const selectedText = App.getSelectedText(); diff --git a/plugins/auto_assign_labels/init.php b/plugins/auto_assign_labels/init.php index 3fa4ad8c0..341895cef 100755 --- a/plugins/auto_assign_labels/init.php +++ b/plugins/auto_assign_labels/init.php @@ -19,6 +19,7 @@ class Auto_Assign_Labels extends Plugin { function get_all_labels_filter_format($owner_uid) { $rv = array(); + // TODO: use Labels::get_all() $sth = $this->pdo->prepare("SELECT id, fg_color, bg_color, caption FROM ttrss_labels2 WHERE owner_uid = ?"); $sth->execute([$owner_uid]); diff --git a/themes/compact.css b/themes/compact.css index 92e9928c8..16bdcf1f0 100644 --- a/themes/compact.css +++ b/themes/compact.css @@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover { } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { - max-height: 100px; - overflow: auto; list-style-type: none; - border-style: solid; - border-color: #ddd; - border-width: 1px 1px 1px 1px; - background-color: white; - margin: 0px 0px 5px 0px; - padding: 4px; - min-height: 16px; + margin: 0; + padding: 0; + /*max-height : 100px; + overflow : auto; + border-style : solid; + border-color : @border-default; + border-width : 1px 1px 1px 1px; + background-color : @default-bg; + margin : 0px 0px 5px 0px; + padding : 4px; + min-height : 16px;*/ } body.ttrss_main ul#filterDlg_Matches li, body.ttrss_main ul#filterDlg_Actions li { diff --git a/themes/compact_night.css b/themes/compact_night.css index 29eff9cb9..37adf3fda 100644 --- a/themes/compact_night.css +++ b/themes/compact_night.css @@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover { } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { - max-height: 100px; - overflow: auto; list-style-type: none; - border-style: solid; - border-color: #222; - border-width: 1px 1px 1px 1px; - background-color: #333; - margin: 0px 0px 5px 0px; - padding: 4px; - min-height: 16px; + margin: 0; + padding: 0; + /*max-height : 100px; + overflow : auto; + border-style : solid; + border-color : @border-default; + border-width : 1px 1px 1px 1px; + background-color : @default-bg; + margin : 0px 0px 5px 0px; + padding : 4px; + min-height : 16px;*/ } body.ttrss_main ul#filterDlg_Matches li, body.ttrss_main ul#filterDlg_Actions li { diff --git a/themes/light.css b/themes/light.css index 583f9cabb..0f2ffc1b6 100644 --- a/themes/light.css +++ b/themes/light.css @@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover { } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { - max-height: 100px; - overflow: auto; list-style-type: none; - border-style: solid; - border-color: #ddd; - border-width: 1px 1px 1px 1px; - background-color: white; - margin: 0px 0px 5px 0px; - padding: 4px; - min-height: 16px; + margin: 0; + padding: 0; + /*max-height : 100px; + overflow : auto; + border-style : solid; + border-color : @border-default; + border-width : 1px 1px 1px 1px; + background-color : @default-bg; + margin : 0px 0px 5px 0px; + padding : 4px; + min-height : 16px;*/ } body.ttrss_main ul#filterDlg_Matches li, body.ttrss_main ul#filterDlg_Actions li { diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less index b1895f318..2794d8177 100644 --- a/themes/light/tt-rss.less +++ b/themes/light/tt-rss.less @@ -955,16 +955,18 @@ body.ttrss_main { } ul#filterDlg_Matches, ul#filterDlg_Actions { - max-height : 100px; - overflow : auto; list-style-type : none; + margin : 0; + padding: 0; + /*max-height : 100px; + overflow : auto; border-style : solid; border-color : @border-default; border-width : 1px 1px 1px 1px; background-color : @default-bg; margin : 0px 0px 5px 0px; padding : 4px; - min-height : 16px; + min-height : 16px;*/ } ul#filterDlg_Matches li, ul#filterDlg_Actions li { diff --git a/themes/night.css b/themes/night.css index e428d8aa7..e012c92b2 100644 --- a/themes/night.css +++ b/themes/night.css @@ -823,16 +823,18 @@ body.ttrss_main #headlines-spacer a:hover { } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { - max-height: 100px; - overflow: auto; list-style-type: none; - border-style: solid; - border-color: #222; - border-width: 1px 1px 1px 1px; - background-color: #333; - margin: 0px 0px 5px 0px; - padding: 4px; - min-height: 16px; + margin: 0; + padding: 0; + /*max-height : 100px; + overflow : auto; + border-style : solid; + border-color : @border-default; + border-width : 1px 1px 1px 1px; + background-color : @default-bg; + margin : 0px 0px 5px 0px; + padding : 4px; + min-height : 16px;*/ } body.ttrss_main ul#filterDlg_Matches li, body.ttrss_main ul#filterDlg_Actions li { diff --git a/themes/night_blue.css b/themes/night_blue.css index c9ccaf737..b49a496e3 100644 --- a/themes/night_blue.css +++ b/themes/night_blue.css @@ -823,16 +823,18 @@ body.ttrss_main #headlines-spacer a:hover { } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { - max-height: 100px; - overflow: auto; list-style-type: none; - border-style: solid; - border-color: #222; - border-width: 1px 1px 1px 1px; - background-color: #333; - margin: 0px 0px 5px 0px; - padding: 4px; - min-height: 16px; + margin: 0; + padding: 0; + /*max-height : 100px; + overflow : auto; + border-style : solid; + border-color : @border-default; + border-width : 1px 1px 1px 1px; + background-color : @default-bg; + margin : 0px 0px 5px 0px; + padding : 4px; + min-height : 16px;*/ } body.ttrss_main ul#filterDlg_Matches li, body.ttrss_main ul#filterDlg_Actions li { From 3b8d69206ccc24b41b45acd55f0c63681e749fd1 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 21 Feb 2021 10:28:59 +0300 Subject: [PATCH 6/6] deal with filter actions UI --- classes/pref/filters.php | 354 ++------------------------------------- js/CommonFilters.js | 126 +++++++------- 2 files changed, 78 insertions(+), 402 deletions(-) diff --git a/classes/pref/filters.php b/classes/pref/filters.php index 4e52260c9..c00e52bde 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -328,7 +328,8 @@ class Pref_Filters extends Handler_Protected { "rules" => [], "actions" => [], "filter_types" => [], - "filter_actions" => [], + "action_types" => [], + "plugin_actions" => [], "labels" => Labels::get_all($_SESSION["uid"]) ]; @@ -343,7 +344,17 @@ class Pref_Filters extends Handler_Protected { ORDER BY name"); while ($line = $res->fetch()) { - $rv["filter_actions"][$line["id"]] = __($line["description"]); + $rv["action_types"][$line["id"]] = __($line["description"]); + } + + $filter_actions = PluginHost::getInstance()->get_filter_actions(); + + foreach ($filter_actions as $fclass => $factions) { + foreach ($factions as $faction) { + + $rv["plugin_actions"][$fclass . ":" . $faction["action"]] = + $fclass . ": " . $faction["description"]; + } } if ($filter_id) { @@ -393,167 +404,6 @@ class Pref_Filters extends Handler_Protected { } print json_encode($rv); } - - /*return; - - if (empty($filter_id) || $row = $sth->fetch()) { - - $enabled = $row["enabled"] ?? true; - $match_any_rule = $row["match_any_rule"] ?? false; - $inverse = $row["inverse"] ?? false; - $title = htmlspecialchars($row["title"] ?? ""); - - print "
        "; - - print \Controls\hidden_tag("op", "pref-filters"); - - if ($filter_id) { - print \Controls\hidden_tag("id", "$filter_id"); - print \Controls\hidden_tag("method", "editSave"); - } else { - print \Controls\hidden_tag("method", "add"); - } - - print \Controls\hidden_tag("csrf_token", $_SESSION['csrf_token']); - - print "
        ".__("Caption")."
        -
        - -
        -
        ".__("Match")."
        -
        -
        -
        - " . __('Select')." -
        - -
        ".__('All')."
        -
        ".__('None')."
        -
        -
        - - -
        "; - - print "
          "; - - if ($filter_id) { - $rules_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_rules - WHERE filter_id = ? ORDER BY reg_exp, id"); - $rules_sth->execute([$filter_id]); - - while ($line = $rules_sth->fetch()) { - if ($line["match_on"]) { - $line["feed_id"] = json_decode($line["match_on"], true); - } else { - if ($line["cat_filter"]) { - $feed_id = "CAT:" . (int)$line["cat_id"]; - } else { - $feed_id = (int)$line["feed_id"]; - } - - $line["feed_id"] = ["" . $feed_id]; // set item type to string for in_array() - } - - unset($line["cat_filter"]); - unset($line["cat_id"]); - unset($line["filter_id"]); - unset($line["id"]); - if (!$line["inverse"]) unset($line["inverse"]); - unset($line["match_on"]); - - print "
        • - ".$this->_get_rule_name($line)."". - \Controls\hidden_tag("rule[]", (string)json_encode($line))."
        • "; - } - } - - print "
        -
        "; - - print "
        ".__("Apply actions")."
        -
        -
        -
        - ".__('Select')." -
        -
        ".__('All')."
        -
        ".__('None')."
        -
        -
        - - -
        "; - - print "
          "; - - if ($filter_id) { - $actions_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_actions - WHERE filter_id = ? ORDER BY id"); - $actions_sth->execute([$filter_id]); - - while ($line = $actions_sth->fetch()) { - $line["action_param_label"] = $line["action_param"]; - - unset($line["filter_id"]); - unset($line["id"]); - - print "
        • - ".$this->_get_action_name($line)."". - \Controls\hidden_tag("action[]", (string)json_encode($line))."
        • "; - } - } - - print "
        "; - - print "
        "; - - print "
        ".__("Options")."
        -
        "; - - print "
        -
        "; - - print "
        - -
        "; - - print "
        -
        "; - - print "
        -
        "; - - if ($filter_id) { - print "
        - -
        - - - "; - } else { - print " - - "; - } - - print "
        "; - } */ } private function _get_rule_name($rule) { @@ -845,180 +695,8 @@ class Pref_Filters extends Handler_Protected { $feed_ids = explode(",", clean($_REQUEST["ids"])); print json_encode([ - "multiselect" => $this->feed_multi_select("feed_id", $feed_ids, 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"') + "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'style="width : 540px; height : 300px" dojoType="dijit.form.MultiSelect"') ]); - - /*return; - - $rule = json_decode(clean($_REQUEST["rule"]), true); - - if ($rule) { - $reg_exp = htmlspecialchars($rule["reg_exp"]); - $filter_type = $rule["filter_type"]; - $feed_id = $rule["feed_id"]; - $inverse_checked = !empty($rule["inverse"]); - } else { - $reg_exp = ""; - $filter_type = 1; - $feed_id = ["0"]; - $inverse_checked = false; - } - - print "
        "; - - $res = $this->pdo->query("SELECT id,description - FROM ttrss_filter_types WHERE id != 5 ORDER BY description"); - - $filter_types = array(); - - while ($line = $res->fetch()) { - $filter_types[$line["id"]] = __($line["description"]); - } - - print "
        ".__("Match")."
        "; - - print "
        "; - - print ""; - - print "
        "; - - print "
        "; - print ""; - print "
        "; - - print "
        "; - print " "; - print \Controls\select_hash("filter_type", $filter_type, $filter_types); - print " "; - - print "
        "; - - print "
        "; - print ""; - print $this->feed_multi_select("feed_id", - $feed_id, - 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"'); - print ""; - - print "
        "; - - print "
        "; - - print "
        "; - - print ""; - - print " "; - - print ""; - - print "
        "; - - print "
        ";*/ - } - - function newaction() { - $action = json_decode(clean($_REQUEST["action"]), true); - - if ($action) { - $action_param = $action["action_param"]; - $action_id = (int)$action["action_id"]; - } else { - $action_param = ""; - $action_id = 0; - } - - print "
        "; - - print "
        ".__("Perform Action")."
        "; - - print "
        "; - - print ""; - - #$param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ? - # "" : "display : none"; - - #$param_hidden = ($action_id == 4 || $action_id == 6) ? - # "" : "display : none"; - - #$label_param_hidden = ($action_id == 7) ? "" : "display : none"; - #$plugin_param_hidden = ($action_id == 9) ? "" : "display : none"; - - #print ""; - #print " "; - //print " " . __("with parameters:") . " "; - print ""; - - print \Controls\select_labels("action_param_label", $action_param, - ["style" => $label_param_hidden], - "filterDlg_actionParamLabel"); - - $filter_actions = PluginHost::getInstance()->get_filter_actions(); - $filter_action_hash = array(); - - foreach ($filter_actions as $fclass => $factions) { - foreach ($factions as $faction) { - - $filter_action_hash[$fclass . ":" . $faction["action"]] = - $fclass . ": " . $faction["description"]; - } - } - - if (count($filter_action_hash) == 0) { - $filter_plugin_disabled = ["disabled" => "1"]; - - $filter_action_hash["no-data"] = __("No actions available"); - - } else { - $filter_plugin_disabled = []; - } - - print \Controls\select_hash("action_param_plugin", $action_param, $filter_action_hash, - array_merge(["style" => $plugin_param_hidden], $filter_plugin_disabled), - "filterDlg_actionParamPlugin"); - - #print ""; - - print " "; // tiny layout hack - - print "
        "; - - print "
        "; - - print " "; - - print ""; - - print "
        "; - - print "
        "; } private function _get_name($id) { @@ -1152,7 +830,7 @@ class Pref_Filters extends Handler_Protected { $this->pdo->commit(); } - private function feed_multi_select($id, $default_ids = [], + private function _feed_multi_select($id, $default_ids = [], $attributes = "", $include_all_feeds = true, $root_id = null, $nest_level = 0) { @@ -1194,7 +872,7 @@ class Pref_Filters extends Handler_Protected { $line["id"], htmlspecialchars($line["title"])); if ($line["num_children"] > 0) - $rv .= $this->feed_multi_select($id, $default_ids, $attributes, + $rv .= $this->_feed_multi_select($id, $default_ids, $attributes, $include_all_feeds, $line["id"], $nest_level+1); $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds diff --git a/js/CommonFilters.js b/js/CommonFilters.js index 75e1fa8af..5874170b8 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -209,13 +209,13 @@ const Filters = {
        -
        - + ${App.FormFields.select_hash("filter_type", rule.filter_type, dialog.filter_info.filter_types)}
        @@ -241,10 +241,14 @@ const Filters = { edit_rule_dialog.show(); }, - /*editAction: function(replaceNode, actionStr) { + editAction: function(replaceNode, actionStr) { const edit_action_dialog = new fox.SingleUseDialog({ title: actionStr ? __("Edit action") : __("Add action"), - hideOrShowActionParam: function(sender) { + select_labels: function(name, value, labels, attributes = {}, id = "") { + const values = Object.values(labels).map((label) => label.caption); + return App.FormFields.select_tag(name, value, values, attributes, id); + }, + toggleParam: function(sender) { const action = parseInt(sender.value); dijit.byId("filterDlg_actionParam").domNode.hide(); @@ -262,67 +266,72 @@ const Filters = { }, execute: function () { if (this.validate()) { - dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); + dialog.insertAction(App.byId("filterDlg_Actions"), replaceNode); this.hide(); } - } - }); - - const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () { - dojo.disconnect(tmph); - - xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { - edit_action_dialog.attr('content', reply); - - setTimeout(() => { - edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value')); - }, 250); - }); - }); - - edit_action_dialog.show(); - }, */ - /*editAction: function(replaceNode, actionStr) { - const edit_action_dialog = new fox.SingleUseDialog({ - title: actionStr ? __("Edit action") : __("Add action"), - hideOrShowActionParam: function(sender) { - const action = parseInt(sender.value); - - dijit.byId("filterDlg_actionParam").domNode.hide(); - dijit.byId("filterDlg_actionParamLabel").domNode.hide(); - dijit.byId("filterDlg_actionParamPlugin").domNode.hide(); - - // if selected action supports parameters, enable params field - if (action == dialog.ACTION_LABEL) { - dijit.byId("filterDlg_actionParamLabel").domNode.show(); - } else if (action == dialog.ACTION_PLUGIN) { - dijit.byId("filterDlg_actionParamPlugin").domNode.show(); - } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) { - dijit.byId("filterDlg_actionParam").domNode.show(); - } }, - execute: function () { - if (this.validate()) { - dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); - this.hide(); - } - } + content: __("Loading, please wait...") }); const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () { dojo.disconnect(tmph); - xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { + let action; + + if (actionStr) { + action = JSON.parse(actionStr); + } else { + action = { + action_id: 2, + action_param: "" + }; + } + + console.log(action); + + edit_action_dialog.attr('content', + ` +
        +
        + ${App.FormFields.select_hash("action_id", -1, + dialog.filter_info.action_types, + {onchange: "App.dialogOf(this).toggleParam(this)"}, + "filterDlg_actionSelect")} + + + + ${edit_action_dialog.select_labels("action_param_label", action.action_param, + dialog.filter_info.labels, + {}, + "filterDlg_actionParamLabel")} + + ${App.FormFields.select_hash("action_param_plugin", action.action_param, + dialog.filter_info.plugin_actions, + {}, + "filterDlg_actionParamPlugin")} +
        +
        + ${App.FormFields.submit_tag(__("Save action"), {onclick: "App.dialogOf(this).execute()"})} + ${App.FormFields.cancel_dialog_tag(__("Cancel"))} +
        +
        + `); + + dijit.byId("filterDlg_actionSelect").attr('value', action.action_id); + + /*xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => { edit_action_dialog.attr('content', reply); setTimeout(() => { edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value')); }, 250); - }); + });*/ }); edit_action_dialog.show(); - },*/ + }, selectRules: function (select) { Lists.select("filterDlg_Matches", select); }, @@ -395,18 +404,7 @@ const Filters = { const tmph = dojo.connect(dialog, 'onShow', function () { dojo.disconnect(tmph); - const query = {op: "pref-filters", method: "edit", id: filter_id}; - - /*if (!App.isPrefs()) { - query = { - op: "pref-filters", method: "edit", - feed: Feeds.getActive(), is_cat: Feeds.activeIsCat() - }; - } else { - query = {op: "pref-filters", method: "edit", id: id}; - }*/ - - xhr.json("backend.php", query, function (filter) { + xhr.json("backend.php", {op: "pref-filters", method: "edit", id: filter_id}, function (filter) { dialog.filter_info = filter; @@ -476,10 +474,10 @@ const Filters = { dojoType="dijit.MenuItem">${__("None")} - - @@ -488,7 +486,7 @@ const Filters = { ${filter.actions.map((action) => `
      • ${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})} - ${App.escapeHtml(action.name)} + ${App.escapeHtml(action.name)} ${App.FormFields.hidden_tag("action[]", JSON.stringify(action))}
      • `).join("")}