summaryrefslogtreecommitdiff
path: root/webhelper
diff options
context:
space:
mode:
authorWill Greenberg <ifnspifn@gmail.com>2013-09-24 16:17:32 -0700
committerWill Greenberg <ifnspifn@gmail.com>2013-09-24 16:17:32 -0700
commit8ceb8ac14c85c812308b9d93e29f76e985e7b688 (patch)
tree249a07deff03112680498c6942e6a6fd74a8b065 /webhelper
parentf6df19cad1581dc29f62c6a7d136fc77ecb997b9 (diff)
parent4cbd3c6c4620797c65b3e9507529907122e1f306 (diff)
Merge pull request #312 from endlessm/issues/310
Issues/310
Diffstat (limited to 'webhelper')
-rw-r--r--webhelper/webhelper.js133
1 files changed, 108 insertions, 25 deletions
diff --git a/webhelper/webhelper.js b/webhelper/webhelper.js
index 1992973..32ad4ec 100644
--- a/webhelper/webhelper.js
+++ b/webhelper/webhelper.js
@@ -1,8 +1,12 @@
const Endless = imports.gi.Endless;
+const Format = imports.format;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
const WebKit = imports.gi.WebKit;
+String.prototype.format = Format.format;
+
const EOS_URI_SCHEME = 'endless://';
/**
@@ -17,8 +21,8 @@ const EOS_URI_SCHEME = 'endless://';
*
* WebHelper solves that problem by detecting when the web page navigates to a
* custom action URI.
- * The custom URI corresponds to a function that you define in
- * <Application._webActions>, and you can pass parameters to the
+ * The custom URI corresponds to a function that you define using
+ * <Application.define_web_action()>, and you can pass parameters to the
* function.
*
* Another often-encountered problem is localizing text through the same API as
@@ -42,18 +46,70 @@ const Application = new Lang.Class({
Name: 'WebApplication',
Extends: Endless.Application,
+ _init: function(props) {
+ this._webActions = {};
+ this._translationFunction = null;
+ this.parent(props);
+ },
+
+ /**
+ * Method: define_web_action
+ * Define an action that may be invoked from a WebView
+ *
+ * Parameters:
+ * name - a string, which must be a valid URI location.
+ * implementation - a function (see Callback Parameters below.)
+ *
+ * Callback Parameters:
+ * dict - object containing properties corresponding to the query
+ * parameters that the web action was called with
+ *
+ * Sets up an action that may be invoked from an HTML document inside a
+ * WebView, or from the in-browser Javascript environment inside a WebView.
+ * If you set up an action "setVolume" as follows:
+ * > app.define_web_action('setVolume', function(dict) { ... });
+ * Then you can invoke the action inside the HTML document, e.g. as the
+ * target of a link, as follows:
+ * > <a href="endless://setVolume?volume=11">This one goes to 11</a>
+ * Or from the in-browser Javascript, by navigating to the action URI, as
+ * follows:
+ * > window.location.href = 'endless://setVolume?volume=11';
+ *
+ * In both cases, the function would then be called with the _dict_
+ * parameter equal to
+ * > { "volume": "11" }
+ *
+ * If an action called _name_ is already defined, the new _implementation_
+ * replaces the old one.
+ */
+ define_web_action: function(name, implementation) {
+ if(typeof implementation != 'function') {
+ throw new Error('The implementation of a web action must be a ' +
+ 'function.');
+ }
+ this._webActions[name] = implementation;
+ },
+
/**
- * Property: _webActions
- * Set of actions that may be invoked from a WebView
+ * Method: define_web_actions
+ * Define several web actions at once
*
- * Declare them as a function that takes a dict as a parameter, and use
- * links with the format "endless://actionName?parameter=value"
+ * Parameters:
+ * dict - an object, with web action names as property names, and their
+ * implementations as values
+ *
+ * Convenience method to define more than one web action at once.
+ * Calls <define_web_action()> on each property of _dict_.
*
- * *Note* This API will likely disappear and be replaced by a method
- * add_web_action().
- * That is the reason for the underscore starting the name.
+ * *Note* This API is Javascript-only. It will not be implemented in C.
*/
- _webActions: { },
+ define_web_actions: function(dict) {
+ for(let key in dict) {
+ if(dict.hasOwnProperty(key)) {
+ this.define_web_action(key, dict[key]);
+ }
+ }
+ },
/**
* Callback: web_actions_handler
@@ -80,7 +136,7 @@ const Application = new Lang.Class({
// get the name and parameters for the desired function
let f_call = uri.substring(EOS_URI_SCHEME.length, uri.length).split('?');
- var function_name = f_call[0];
+ var function_name = decodeURI(f_call[0]);
var parameters = {};
if(f_call[1]) {
@@ -101,14 +157,15 @@ const Application = new Lang.Class({
if(this._webActions[function_name])
Lang.bind(this, this._webActions[function_name])(parameters);
else
- throw new Error("Undefined WebHelper action '%s'. Did you add it " +
- "to your app's _webActions object?".format(function_name));
+ throw new Error("Undefined WebHelper action '%s'. Did you define " +
+ "it with WebHelper.Application.define_web_action()?".format(
+ function_name));
policy_decision.ignore();
return true;
},
-// convenience functions
+ // convenience function
_getElementById: function(webview, id) {
// WebKit.DOMDocument
@@ -119,18 +176,43 @@ const Application = new Lang.Class({
},
/**
- * Property: _translationFunction
- * Function which transforms all translatable text
+ * Method: set_translation_function
+ * Define function which transforms all translatable text
+ *
+ * Parameters:
+ * translation_function - a function, or null
*
* When you plan to use the <translate_html()> function to translate text in
* your web application, set this property to the translation function.
* The function must take one parameter, a string, and also return a
- * string -- for example, gettext().
+ * string.
+ * The canonical example is gettext().
+ *
+ * Pass null for _translation_function_ to unset the translation function.
*
- * *Note* This API will likely disappear and be replaced by a read-write
- * translation_function property.
- * That is the reason for the underscore starting the name.
+ * If this function has not been called, or has most recently been called
+ * with null, then it is illegal to call <translate_html()>.
*/
+ set_translation_function: function(translation_function) {
+ if(translation_function !== null
+ && typeof translation_function !== 'function') {
+ throw new Error('The translation function must be a function, or ' +
+ 'null.');
+ }
+ this._translationFunction = translation_function;
+ },
+
+ /**
+ * Method: get_translation_function
+ * Retrieve the currently set translation function
+ *
+ * Returns:
+ * the translation function previously set with
+ * <set_translation_function()>, or null if none is currently set.
+ */
+ get_translation_function: function() {
+ return this._translationFunction;
+ },
/**
* Method: translate_html
@@ -152,12 +234,12 @@ const Application = new Lang.Class({
*
* Then after the web view has finished loading, call <translate_html()> on
* it, and each of the marked strings will be passed to the function that
- * you specify using the <_translationFunction> property.
- * The return value from <_translationFunction> will be substituted into the
- * HTML instead of the original string.
+ * you specify using <set_translation_function()> property.
+ * The return value from the translation function will be substituted into
+ * the HTML instead of the original string.
*
* Example:
- * > app._translationFunction = _;
+ * > app.set_translation_function(_);
* > webview.connect('notify::load-status',
* > Lang.bind(app, function(webview) {
* > if(webview.load_status == WebKit.LoadStatus.FINISHED)
@@ -177,7 +259,8 @@ const Application = new Lang.Class({
// Translate the text
if(typeof this._translationFunction !== 'function')
throw new Error("No suitable translation function was found. " +
- "Did you forget to set '_translationFunction' on your app?");
+ "Did you forget to call 'set_translation_function()' on " +
+ "your app?");
element.inner_html = this._translationFunction(element.inner_text);
}
}