Commit 4c35e5bd authored by Cédric Bellegarde's avatar Cédric Bellegarde

Initial support for OpenSearch. Fix #286

parent 46d4a194
......@@ -9,6 +9,7 @@
<file compressed="true">application.css</file>
<file compressed="true">error.css</file>
<file compressed="true">Readability.js</file>
<file compressed="true">Extensions.js</file>
<file compressed="true" preprocess="xml-stripblanks">ActionsMenu.ui</file>
<file compressed="true" preprocess="xml-stripblanks">Appmenu.ui</file>
<file compressed="true" preprocess="xml-stripblanks">BookmarkEdit.ui</file>
......
......@@ -10,14 +10,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk, GLib, GObject, Gio
from gi.repository import Gtk, GLib, GObject
from gettext import gettext as _
from urllib.parse import urlparse
import json
from eolie.search import Search
from eolie.define import El, EOLIE_DATA_PATH
from eolie.define import El
class Item(GObject.GObject):
......@@ -133,19 +132,9 @@ class SearchEngineDialog:
bang = child.item.get_property("bang")
if name and search:
engines[name] = [uri, search, keyword, encoding, bang]
try:
content = json.dumps(engines)
f = Gio.File.new_for_path(EOLIE_DATA_PATH + "/search_engines.json")
f.replace_contents(content.encode("utf-8"),
None,
False,
Gio.FileCreateFlags.REPLACE_DESTINATION,
None)
except Exception as e:
print("SearchEngineDialog::run():", e)
El().search.save_engines(engines)
El().search.update_default_engine()
self.__dialog.destroy()
# Update application search engines
El().search = Search()
#######################
# PROTECTED #
......
......@@ -19,11 +19,12 @@ class MessagePopover(Gtk.Popover):
@warning: will block current execution
"""
def __init__(self, message, window):
def __init__(self, message, window, callback=None, *args):
"""
Init popover
@param message as str
@param window as window
@param callback as function
"""
Gtk.Popover.__init__(self)
self.set_modal(False)
......@@ -39,6 +40,14 @@ class MessagePopover(Gtk.Popover):
self.add(widget)
self.__loop = GLib.MainLoop.new(None, False)
self.connect("closed", self.__on_closed)
if callback is not None:
self.__callback = callback
self.__args = args
ok_button = builder.get_object("ok_button")
cancel_button = builder.get_object("cancel_button")
ok_button.show()
cancel_button.show()
builder.connect_signals(self)
def popup(self):
"""
......@@ -50,6 +59,20 @@ class MessagePopover(Gtk.Popover):
#######################
# PROTECTED #
#######################
def _on_ok_button_clicked(self, button):
"""
Pass ok to js
@param button as Gtk.Button
"""
self.__callback(*self.__args)
self.hide()
def _on_cancel_button_clicked(self, button):
"""
Pass ok to js
@param button as Gtk.Button
"""
self.hide()
#######################
# PRIVATE #
......
......@@ -13,6 +13,7 @@
from gi.repository import Gio, GLib
from gettext import gettext as _
from urllib.parse import urlparse
import json
from eolie.helper_task import TaskHelper
......@@ -73,10 +74,26 @@ class Search:
self.__uri = ""
self.__search = ""
self.__keyword = ""
self.__suggest = ""
self.__encoding = ""
self.update_default_engine()
def save_engines(self, engines):
"""
Save engines
@param engines as {}
"""
try:
content = json.dumps(engines)
f = Gio.File.new_for_path(EOLIE_DATA_PATH + "/search_engines.json")
f.replace_contents(content.encode("utf-8"),
None,
False,
Gio.FileCreateFlags.REPLACE_DESTINATION,
None)
except Exception as e:
print("Search::save_engines():", e)
def update_default_engine(self):
"""
Update default engine based on user settings
......@@ -86,7 +103,7 @@ class Search:
if engine == wanted:
self.__uri = self.engines[engine][0]
self.__search = self.engines[engine][1]
self.__keyword = self.engines[engine][2]
self.__suggest = self.engines[engine][2]
self.__encoding = self.engines[engine][3]
break
......@@ -115,7 +132,7 @@ class Search:
try:
if not value.strip(" "):
return
uri = self.__keyword % GLib.uri_escape_string(value,
uri = self.__suggest % GLib.uri_escape_string(value,
None,
True)
task_helper = TaskHelper()
......@@ -124,6 +141,14 @@ class Search:
except Exception as e:
print("Search::search_suggestions():", e)
def install_engine(self, uri, window):
"""
Install new search engine
@param uri as str
@param window as Window
"""
self.__install_engine(uri, window)
def is_search(self, string):
"""
Return True is string is a search string
......@@ -170,3 +195,78 @@ class Search:
#######################
# PRIVATE #
#######################
def __install_engine(self, uri, window):
"""
Install engine from uri
@param uri as str
@param window as Window
"""
task_helper = TaskHelper()
task_helper.load_uri_content(uri, None,
self.__on_engine_loaded,
window)
def __on_engine_loaded(self, uri, status, content, window):
"""
Ask user to add engine
@param uri as str
@param content as bytes
@param window as Window
"""
SHORTNAME = "{http://a9.com/-/spec/opensearch/1.1/}ShortName"
URL = "{http://a9.com/-/spec/opensearch/1.1/}Url"
ENCODING = "{http://a9.com/-/spec/opensearch/1.1/}InputEncoding"
HTML = "text/html"
JSON = "application/x-suggestions+json"
try:
import xml.etree.ElementTree as xml
root = xml.fromstring(content)
name = None
search = None
suggest = None
encoding = "utf-8"
for child in root.iter():
if child.tag == SHORTNAME:
name = child.text
elif child.tag == URL:
if child.attrib["type"] == HTML:
search = child.attrib["template"]
elif child.attrib["type"] == JSON:
suggest = child.attrib["template"]
elif child.tag == ENCODING:
encoding = child.text
if name is not None and\
search is not None and\
suggest is not None:
from eolie.popover_message import MessagePopover
message = _("Do you want to install\n"
"%s search engine?" % name)
popover = MessagePopover(message, window,
self.__on_message_popover_ok,
name,
search,
suggest,
encoding)
popover.set_relative_to(window.toolbar.title)
popover.popup()
except Exception as e:
print("Search::__on_engine_loaded()", e)
def __on_message_popover_ok(self, name, search, suggest, encoding):
"""
Save engine
@param name as str
@param uri as str
@param suggest_uri as str
@param encoding as str
"""
# Save engines
engines = El().search.engines
parsed = urlparse(search)
uri = "%s://%s" % (parsed.scheme, parsed.netloc)
engines[name] = [uri,
search.replace("{searchTerms}", "%s"),
suggest.replace("{searchTerms}", "%s"),
encoding,
""]
El().search.save_engines(engines)
......@@ -405,6 +405,8 @@ class WebViewNavigation:
self.run_javascript(js, None, None)
break
elif event == WebKit2.LoadEvent.FINISHED:
self.run_javascript_from_gresource(
"/org/gnome/Eolie/Extensions.js", None, None)
self.set_favicon(False)
if parsed.scheme != "populars":
self.set_snapshot()
......
......@@ -69,6 +69,10 @@ class WebViewJsSignals:
if message.startswith("@EOLIE_READER@"):
self._readable_content = message.replace("@EOLIE_READER@", "")
self.emit("readable")
# OpenSearch message
elif message.startswith("@EOLIE_OPENSEARCH@"):
uri = message.replace("@EOLIE_OPENSEARCH@", "")
El().search.install_engine(uri, self._window)
# Populars view message
elif message.startswith("@EOLIE_HIDE_BOOKMARK_POPULARS@"):
uri = message.replace("@EOLIE_HIDE_BOOKMARK_POPULARS@", "")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment