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 f9b3217c9..c00e52bde 100755 --- a/classes/pref/filters.php +++ b/classes/pref/filters.php @@ -319,162 +319,90 @@ class Pref_Filters extends Handler_Protected { $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" => [], + "action_types" => [], + "plugin_actions" => [], + "labels" => Labels::get_all($_SESSION["uid"]) + ]; - $enabled = $row["enabled"] ?? true; - $match_any_rule = $row["match_any_rule"] ?? false; - $inverse = $row["inverse"] ?? false; - $title = htmlspecialchars($row["title"] ?? ""); + $res = $this->pdo->query("SELECT id,description + FROM ttrss_filter_types WHERE id != 5 ORDER BY description"); - 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"); + while ($line = $res->fetch()) { + $rv["filter_types"][$line["id"]] = __($line["description"]); } - print \Controls\hidden_tag("csrf_token", $_SESSION['csrf_token']); + $res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions + ORDER BY name"); - print "
".__("Caption")."
-
- -
-
".__("Match")."
-
-
-
- " . __('Select')." -
- -
".__('All')."
-
".__('None')."
-
-
- - -
"; + while ($line = $res->fetch()) { + $rv["action_types"][$line["id"]] = __($line["description"]); + } - print " -
"; - - print "
".__("Apply actions")."
-
-
-
- ".__('Select')." -
-
".__('All')."
-
".__('None')."
-
-
- - -
"; - - print ""; - - print "
"; - - print "
".__("Options")."
-
"; - - print "
-
"; - - print "
- -
"; - - print "
-
"; - - print "
-
"; + print json_encode($rv); } } @@ -592,8 +520,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 +597,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,176 +691,12 @@ class Pref_Filters extends Handler_Protected { "; - - $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 ""; - $this->feed_multi_select("feed_id", - $feed_id, - 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"'); - 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 json_encode([ + "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'style="width : 540px; height : 300px" dojoType="dijit.form.MultiSelect"') + ]); } private function _get_name($id) { @@ -1067,106 +830,110 @@ 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) { - $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/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 0fc8f87ae..5874170b8 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -5,358 +5,559 @@ /* global __, App, Article, Lists, fox */ /* global xhr, dojo, dijit, Notify, Feeds */ +/* exported Filters */ const Filters = { - filterDlgCheckAction: function(sender) { - const action = sender.value; - - const action_param = App.byId("filterDlg_paramBox"); - - if (!action_param) { - console.log("filterDlgCheckAction: 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 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) { + edit: function(filter_id = null) { // if no id, new filter dialog 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; + id: "filterEditDlg", + 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", + 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 && dialog && dialog.open) { - 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", 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 + " " + 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; - } + App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; + } - if (dialog.results < 30 && offset < dialog.max_offset) { + if (test_dialog.results < 30 && offset < test_dialog.max_offset) { - // get the next batch - window.setTimeout(function () { - dialog.getTestResults(params, offset + dialog.limit); - }, 0); + // get the next batch + window.setTimeout(function () { + test_dialog.getTestResults(params, offset + test_dialog.limit); + }, 0); - } else { - // all done + } else { + // all done - Element.hide("prefFilterLoadingIndicator"); + 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:"; + 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 { - App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") - .replace("%d", dialog.results); + console.log("getTestResults: dialog closed, bailing out."); } - + } catch (e) { + App.Error.report(e); } + }); + }, + content: ` +
+   + Looking for articles... +
- } else if (!result) { - console.log("getTestResults: can't parse results object"); - Element.hide("prefFilterLoadingIndicator"); - Notify.error("Error while trying to get filter test results."); + + + + ` + }); + + const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) { + dojo.disconnect(tmph); + + test_dialog.getTestResults(dialog.attr('value'), 0); + }); + + test_dialog.show(); + }, + 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 = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})} + ${reply} + ${App.FormFields.hidden_tag("rule[]", rule)}`; + + dojo.parser.parse(li); + + if (replaceNode) { + parentNode.replaceChild(li, replaceNode); } else { - console.log("getTestResults: dialog closed, bailing out."); + parentNode.appendChild(li); } } catch (e) { App.Error.report(e); } }); }, - content: ` -
-   - Looking for articles... -
+ insertAction: 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.addClassName("action"); + + li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})} + ${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 = null) { + const edit_rule_dialog = new fox.SingleUseDialog({ + id: "filterNewRuleDlg", + title: ruleStr ? __("Edit rule") : __("Add rule"), + execute: function () { + if (this.validate()) { + dialog.insertRule(App.byId("filterDlg_Matches"), replaceNode); + this.hide(); + } + }, + content: __('Loading, please wait...'), + }); + + const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function () { + dojo.disconnect(tmph); + + 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} + +
+
+ + + +
+ `); + }); + + }); + + edit_rule_dialog.show(); + }, + editAction: function(replaceNode, actionStr) { + const edit_action_dialog = new fox.SingleUseDialog({ + title: actionStr ? __("Edit action") : __("Add action"), + 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(); + 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.insertAction(App.byId("filterDlg_Actions"), replaceNode); + this.hide(); + } + }, + content: __("Loading, please wait...") + }); + + const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () { + dojo.disconnect(tmph); + + 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")} +
+ +
+ `); + + 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); + }, + selectActions: function (select) { + Lists.select("filterDlg_Actions", select); + }, + onRuleClicked: function (elem) { + + const li = elem.closest('li'); + const rule = li.querySelector('input[name="rule[]"]').value; + + this.editRule(li, rule); + }, + onActionClicked: function (elem) { + + const li = elem.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: __("Loading, please wait...") }); - dojo.connect(dialog, "onShow", null, function (/* e */) { - dialog.getTestResults(params, 0); + const tmph = dojo.connect(dialog, 'onShow', function () { + dojo.disconnect(tmph); + + xhr.json("backend.php", {op: "pref-filters", method: "edit", id: filter_id}, 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("")} +
+ + +
+ `); + + 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(); }, - 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}; - } - - 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')); - }, - selectRules: function (select) { - Lists.select("filterDlg_Matches", select); - }, - selectActions: function (select) { - Lists.select("filterDlg_Actions", select); - }, - editRule: function (e) { - const li = e.closest('li'); - const rule = li.querySelector('input[name="rule[]"]').value - - Filters.addFilterRule(li, rule); - }, - editAction: function (e) { - const li = e.closest('li'); - const action = li.querySelector('input[name="action[]"]').value - - Filters.addFilterAction(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 () { - Filters.addFilterAction(); - }, - addRule: function () { - Filters.addFilterRule(); - }, - 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 lh = dojo.connect(dialog, "onShow", function () { - dojo.disconnect(lh); - - 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}; - - Filters.addFilterRule(null, dojo.toJson(rule)); - - } 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}; - - Filters.addFilterRule(null, dojo.toJson(rule)); - } - }); - } - }); - } - dialog.show(); - - } catch (e) { - App.Error.report(e); - } - }); - }, }; diff --git a/js/common.js b/js/common.js index e85862990..df1bf8690 100755 --- a/js/common.js +++ b/js/common.js @@ -400,25 +400,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(); -} 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 {