From 6cbe53c9f5e9c369977b737f897a621f00fba90b Mon Sep 17 00:00:00 2001
From: Andrew Dolgov <fox@fakecake.org>
Date: Sun, 23 Dec 2012 23:36:07 +0400
Subject: [PATCH] add instances plugin

---
 classes/pluginhost.php                        |  13 +-
 js/prefs.js                                   | 165 -----------------
 plugins/example_routing/example_routing.php   |   3 +-
 plugins/instances/README.txt                  |   1 +
 plugins/instances/instances.js                | 169 ++++++++++++++++++
 .../pref => plugins/instances}/instances.php  |  33 +++-
 prefs.php                                     |  10 +-
 7 files changed, 216 insertions(+), 178 deletions(-)
 create mode 100644 plugins/instances/README.txt
 create mode 100644 plugins/instances/instances.js
 rename {classes/pref => plugins/instances}/instances.php (91%)

diff --git a/classes/pluginhost.php b/classes/pluginhost.php
index b28d2511d..46415bd21 100644
--- a/classes/pluginhost.php
+++ b/classes/pluginhost.php
@@ -9,6 +9,7 @@ class PluginHost {
 	const HOOK_ARTICLE_FILTER = 2;
 	const HOOK_PREFS_TAB = 3;
 	const HOOK_PREFS_SECTION = 4;
+	const HOOK_PREFS_TABS = 5;
 
 	function __construct($link) {
 		$this->link = $link;
@@ -77,7 +78,7 @@ class PluginHost {
 	}
 
 	function add_handler($handler, $method, $sender) {
-		$handler = strtolower($handler);
+		$handler = str_replace("-", "_", strtolower($handler));
 		$method = strtolower($method);
 
 		if (!is_array($this->handlers[$handler])) {
@@ -88,18 +89,22 @@ class PluginHost {
 	}
 
 	function del_handler($handler, $method) {
-		$handler = strtolower($handler);
+		$handler = str_replace("-", "_", strtolower($handler));
 		$method = strtolower($method);
 
 		unset($this->handlers[$handler][$method]);
 	}
 
 	function lookup_handler($handler, $method) {
-		$handler = strtolower($handler);
+		$handler = str_replace("-", "_", strtolower($handler));
 		$method = strtolower($method);
 
 		if (is_array($this->handlers[$handler])) {
-			return $this->handlers[$handler][$method];
+			if (isset($this->handlers[$handler]["*"])) {
+				return $this->handlers[$handler]["*"];
+			} else {
+				return $this->handlers[$handler][$method];
+			}
 		}
 
 		return false;
diff --git a/js/prefs.js b/js/prefs.js
index 51d8412fc..4687c60bb 100644
--- a/js/prefs.js
+++ b/js/prefs.js
@@ -24,15 +24,6 @@ function updateFeedList(sort_key) {
 		} });
 }
 
-function updateInstanceList(sort_key) {
-	new Ajax.Request("backend.php", {
-		parameters: "?op=pref-instances&sort=" + param_escape(sort_key),
-		onComplete: function(transport) {
-			dijit.byId('instanceConfigTab').attr('content', transport.responseText);
-			selectTab("instanceConfig", true);
-			notify("");
-		} });
-}
 
 function updateUsersList(sort_key) {
 	try {
@@ -1891,162 +1882,6 @@ function insertSSLserial(value) {
 	}
 }
 
-function getSelectedInstances() {
-	return getSelectedTableRowIds("prefInstanceList");
-}
-
-function addInstance() {
-	try {
-		var query = "backend.php?op=dlg&method=addInstance";
-
-		if (dijit.byId("instanceAddDlg"))
-			dijit.byId("instanceAddDlg").destroyRecursive();
-
-		dialog = new dijit.Dialog({
-			id: "instanceAddDlg",
-			title: __("Link Instance"),
-			style: "width: 600px",
-			regenKey: function() {
-				new Ajax.Request("backend.php", {
-					parameters: "?op=rpc&method=genHash",
-					onComplete: function(transport) {
-						var reply = JSON.parse(transport.responseText);
-						if (reply)
-							dijit.byId('instance_add_key').attr('value', reply.hash);
-
-					} });
-			},
-			execute: function() {
-				if (this.validate()) {
-					console.warn(dojo.objectToQuery(this.attr('value')));
-
-					notify_progress('Saving data...', true);
-					new Ajax.Request("backend.php", {
-						parameters: dojo.objectToQuery(this.attr('value')),
-						onComplete: function(transport) {
-							dialog.hide();
-							notify('');
-							updateInstanceList();
-					} });
-				}
-			},
-			href: query,
-		});
-
-		dialog.show();
-
-	} catch (e) {
-		exception_error("addInstance", e);
-	}
-}
-
-function editInstance(id, event) {
-	try {
-		if (!event || !event.ctrlKey) {
-
-		selectTableRows('prefInstanceList', 'none');
-		selectTableRowById('LIRR-'+id, 'LICHK-'+id, true);
-
-		var query = "backend.php?op=pref-instances&method=edit&id=" +
-			param_escape(id);
-
-		if (dijit.byId("instanceEditDlg"))
-			dijit.byId("instanceEditDlg").destroyRecursive();
-
-		dialog = new dijit.Dialog({
-			id: "instanceEditDlg",
-			title: __("Edit Instance"),
-			style: "width: 600px",
-			regenKey: function() {
-				new Ajax.Request("backend.php", {
-					parameters: "?op=rpc&method=genHash",
-					onComplete: function(transport) {
-						var reply = JSON.parse(transport.responseText);
-						if (reply)
-							dijit.byId('instance_edit_key').attr('value', reply.hash);
-
-					} });
-			},
-			execute: function() {
-				if (this.validate()) {
-//					console.warn(dojo.objectToQuery(this.attr('value')));
-
-					notify_progress('Saving data...', true);
-					new Ajax.Request("backend.php", {
-						parameters: dojo.objectToQuery(this.attr('value')),
-						onComplete: function(transport) {
-							dialog.hide();
-							notify('');
-							updateInstanceList();
-					} });
-				}
-			},
-			href: query,
-		});
-
-		dialog.show();
-
-		} else if (event.ctrlKey) {
-			var cb = $('LICHK-' + id);
-			cb.checked = !cb.checked;
-			toggleSelectRow(cb);
-		}
-
-
-	} catch (e) {
-		exception_error("editInstance", e);
-	}
-}
-
-function removeSelectedInstances() {
-	try {
-		var sel_rows = getSelectedInstances();
-
-		if (sel_rows.length > 0) {
-
-			var ok = confirm(__("Remove selected instances?"));
-
-			if (ok) {
-				notify_progress("Removing selected instances...");
-
-				var query = "?op=pref-instances&method=remove&ids="+
-					param_escape(sel_rows.toString());
-
-				new Ajax.Request("backend.php", {
-					parameters: query,
-					onComplete: function(transport) {
-						notify('');
-						updateInstanceList();
-					} });
-			}
-
-		} else {
-			alert(__("No instances are selected."));
-		}
-
-	} catch (e) {
-		exception_error("removeInstance", e);
-	}
-}
-
-function editSelectedInstance() {
-	var rows = getSelectedInstances();
-
-	if (rows.length == 0) {
-		alert(__("No instances are selected."));
-		return;
-	}
-
-	if (rows.length > 1) {
-		alert(__("Please select only one instance."));
-		return;
-	}
-
-	notify("");
-
-	editInstance(rows[0]);
-}
-
 function showHelp() {
 	try {
 		new Ajax.Request("backend.php", {
diff --git a/plugins/example_routing/example_routing.php b/plugins/example_routing/example_routing.php
index a5c4e6139..c8d352ac8 100644
--- a/plugins/example_routing/example_routing.php
+++ b/plugins/example_routing/example_routing.php
@@ -9,7 +9,8 @@ class Example_Routing extends Plugin implements IHandler {
 	// Plugin class must implelement IHandler interface and has
 	// a public method of same name as being registered.
 	//
-	// Any system method may be masked by plugins.
+	// Any system method may be masked by plugins. You can mask
+	// entire handler by supplying "*" instead of a method name.
 
 	private $link;
 	private $host;
diff --git a/plugins/instances/README.txt b/plugins/instances/README.txt
new file mode 100644
index 000000000..d4e403929
--- /dev/null
+++ b/plugins/instances/README.txt
@@ -0,0 +1 @@
+Adds support for linking other tt-rss instances
diff --git a/plugins/instances/instances.js b/plugins/instances/instances.js
new file mode 100644
index 000000000..83213896d
--- /dev/null
+++ b/plugins/instances/instances.js
@@ -0,0 +1,169 @@
+function addInstance() {
+	try {
+		var query = "backend.php?op=dlg&method=addInstance";
+
+		if (dijit.byId("instanceAddDlg"))
+			dijit.byId("instanceAddDlg").destroyRecursive();
+
+		dialog = new dijit.Dialog({
+			id: "instanceAddDlg",
+			title: __("Link Instance"),
+			style: "width: 600px",
+			regenKey: function() {
+				new Ajax.Request("backend.php", {
+					parameters: "?op=rpc&method=genHash",
+					onComplete: function(transport) {
+						var reply = JSON.parse(transport.responseText);
+						if (reply)
+							dijit.byId('instance_add_key').attr('value', reply.hash);
+
+					} });
+			},
+			execute: function() {
+				if (this.validate()) {
+					console.warn(dojo.objectToQuery(this.attr('value')));
+
+					notify_progress('Saving data...', true);
+					new Ajax.Request("backend.php", {
+						parameters: dojo.objectToQuery(this.attr('value')),
+						onComplete: function(transport) {
+							dialog.hide();
+							notify('');
+							updateInstanceList();
+					} });
+				}
+			},
+			href: query,
+		});
+
+		dialog.show();
+
+	} catch (e) {
+		exception_error("addInstance", e);
+	}
+}
+
+// *** INS ***
+
+function updateInstanceList(sort_key) {
+	new Ajax.Request("backend.php", {
+		parameters: "?op=pref-instances&sort=" + param_escape(sort_key),
+		onComplete: function(transport) {
+			dijit.byId('instanceConfigTab').attr('content', transport.responseText);
+			selectTab("instanceConfig", true);
+			notify("");
+		} });
+}
+
+function editInstance(id, event) {
+	try {
+		if (!event || !event.ctrlKey) {
+
+		selectTableRows('prefInstanceList', 'none');
+		selectTableRowById('LIRR-'+id, 'LICHK-'+id, true);
+
+		var query = "backend.php?op=pref-instances&method=edit&id=" +
+			param_escape(id);
+
+		if (dijit.byId("instanceEditDlg"))
+			dijit.byId("instanceEditDlg").destroyRecursive();
+
+		dialog = new dijit.Dialog({
+			id: "instanceEditDlg",
+			title: __("Edit Instance"),
+			style: "width: 600px",
+			regenKey: function() {
+				new Ajax.Request("backend.php", {
+					parameters: "?op=rpc&method=genHash",
+					onComplete: function(transport) {
+						var reply = JSON.parse(transport.responseText);
+						if (reply)
+							dijit.byId('instance_edit_key').attr('value', reply.hash);
+
+					} });
+			},
+			execute: function() {
+				if (this.validate()) {
+//					console.warn(dojo.objectToQuery(this.attr('value')));
+
+					notify_progress('Saving data...', true);
+					new Ajax.Request("backend.php", {
+						parameters: dojo.objectToQuery(this.attr('value')),
+						onComplete: function(transport) {
+							dialog.hide();
+							notify('');
+							updateInstanceList();
+					} });
+				}
+			},
+			href: query,
+		});
+
+		dialog.show();
+
+		} else if (event.ctrlKey) {
+			var cb = $('LICHK-' + id);
+			cb.checked = !cb.checked;
+			toggleSelectRow(cb);
+		}
+
+
+	} catch (e) {
+		exception_error("editInstance", e);
+	}
+}
+
+function removeSelectedInstances() {
+	try {
+		var sel_rows = getSelectedInstances();
+
+		if (sel_rows.length > 0) {
+
+			var ok = confirm(__("Remove selected instances?"));
+
+			if (ok) {
+				notify_progress("Removing selected instances...");
+
+				var query = "?op=pref-instances&method=remove&ids="+
+					param_escape(sel_rows.toString());
+
+				new Ajax.Request("backend.php", {
+					parameters: query,
+					onComplete: function(transport) {
+						notify('');
+						updateInstanceList();
+					} });
+			}
+
+		} else {
+			alert(__("No instances are selected."));
+		}
+
+	} catch (e) {
+		exception_error("removeInstance", e);
+	}
+}
+
+function editSelectedInstance() {
+	var rows = getSelectedInstances();
+
+	if (rows.length == 0) {
+		alert(__("No instances are selected."));
+		return;
+	}
+
+	if (rows.length > 1) {
+		alert(__("Please select only one instance."));
+		return;
+	}
+
+	notify("");
+
+	editInstance(rows[0]);
+}
+
+function getSelectedInstances() {
+	return getSelectedTableRowIds("prefInstanceList");
+}
+
+
diff --git a/classes/pref/instances.php b/plugins/instances/instances.php
similarity index 91%
rename from classes/pref/instances.php
rename to plugins/instances/instances.php
index 763bb49fa..c5d8067af 100644
--- a/classes/pref/instances.php
+++ b/plugins/instances/instances.php
@@ -1,5 +1,8 @@
 <?php
-class Pref_Instances extends Handler_Protected {
+class Instances extends Plugin implements IHandler {
+
+	private $link;
+	private $host;
 
 	private $status_codes = array(
 		0 	=> "Connection failed",
@@ -7,6 +10,26 @@ class Pref_Instances extends Handler_Protected {
 		2 	=> "Invalid object received",
 		16	=> "Access denied" );
 
+	function __construct($host) {
+		$this->link = $host->get_link();
+		$this->host = $host;
+
+		$host->add_hook($host::HOOK_PREFS_TABS, $this);
+		$host->add_handler("pref-instances", "*", $this);
+	}
+
+	function get_prefs_js() {
+		return file_get_contents(dirname(__FILE__) . "/instances.js");
+	}
+
+	function hook_prefs_tabs($args) {
+		if ($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) {
+			?><div id="instanceConfigTab" dojoType="dijit.layout.ContentPane"
+			href="backend.php?op=pref-instances"
+			title="<?php echo __('Linked') ?>"></div><?php
+		}
+	}
+
 	function csrf_ignore($method) {
 		$csrf_ignored = array("index", "edit");
 
@@ -14,7 +37,7 @@ class Pref_Instances extends Handler_Protected {
 	}
 
 	function before($method) {
-		if (parent::before($method)) {
+		if ($_SESSION["uid"]) {
 			if ($_SESSION["access_level"] < 10) {
 				print __("Your access level is insufficient to open this tab.");
 				return false;
@@ -24,6 +47,10 @@ class Pref_Instances extends Handler_Protected {
 		return false;
 	}
 
+	function after() {
+		return true;
+	}
+
 	function remove() {
 		$ids = db_escape_string($_REQUEST['ids']);
 
@@ -219,5 +246,7 @@ class Pref_Instances extends Handler_Protected {
 		print "</div>"; #container
 
 	}
+
 }
 ?>
+
diff --git a/prefs.php b/prefs.php
index 74bcd4cc1..8b5541673 100644
--- a/prefs.php
+++ b/prefs.php
@@ -120,12 +120,10 @@
 		href="backend.php?op=pref-users"
 		title="<?php echo __('Users') ?>"></div>
 <?php } ?>
-<?php if ($_SESSION["access_level"] >= 10 || SINGLE_USER_MODE) { ?>
-	<div id="instanceConfigTab" dojoType="dijit.layout.ContentPane"
-		href="backend.php?op=pref-instances"
-		title="<?php echo __('Linked') ?>"></div>
-<?php } ?>
-
+<?php
+	$pluginhost->run_hooks($pluginhost::HOOK_PREFS_TABS,
+		"hook_prefs_tabs", false);
+?>
 </div>
 
 <div id="footer" dojoType="dijit.layout.ContentPane" region="bottom">
-- 
GitLab