Merge lp:~mpdeimos/nuvola-player/bug-1212167 into lp:nuvola-player/2.5.x

Proposed by Martin Pöhlmann
Status: Merged
Merged at revision: 814
Proposed branch: lp:~mpdeimos/nuvola-player/bug-1212167
Merge into: lp:nuvola-player/2.5.x
Diff against target: 386 lines (+216/-50)
4 files modified
data/nuvolaplayer/js/main.js (+129/-42)
data/nuvolaplayer/services/googleplay/integration.js (+74/-7)
data/nuvolaplayer/services/googleplay/settings.js (+11/-0)
src/nuvola/core/jsapi.vala (+2/-1)
To merge this branch: bzr merge lp:~mpdeimos/nuvola-player/bug-1212167
Reviewer Review Type Date Requested Status
Jiří Janoušek Approve
Martin Pöhlmann (community) Needs Resubmitting
Review via email: mp+200249@code.launchpad.net

Description of the change

Implements Bug #1212167: Back/forward buttons in UI (default off) for Google Play

To post a comment you must log in.
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

=== modified file 'data/nuvolaplayer/services/googleplay/integration.js'
35 + navigateBack.addEventListener('click', function() {window.history.back();});
45 + navigateFwd.addEventListener('click', function() {window.history.forward();});

Use Nuvola.triggerAction("back") and Nuvola.triggerAction("forward").

=== modified file 'data/nuvolaplayer/services/googleplay/settings.js'
98 + Nuvola.saveConfig();
99 + form.showReloadNotice();

Could it be possible to apply this setting live without form.showReloadNotice()? Nuvola.saveConfig() emits signal cmd="config-changed" in Integration.prototype.messageHandler. You can check for it to add/remove buttons instantly.

=== modified file 'data/nuvolaplayer/services/googleplay/integration.js'
48 + var navigationStack = [];

Could you rework your code to use the new actions API (see bug LP:1265290) and fall back to your navigationStack if(Nuvola.Action === undefined) for Nuvola Player <= 2.3?

- var back = new Nuvola.Action("back");
- var forward = new Nuvola.Action("forward");
- in Integration.prototype.messageHandler(cmd, param1, param2) check for signal ("action-changed", back.name/forward.name, "sensitive")

review: Needs Fixing
786. By Martin Pöhlmann

Merged 2.3.0 and JS API release

787. By Martin Pöhlmann

Bug #1212167:
* Usage of new nuvola player APIs instead of navigation stack
* Dynamic activation of preferences

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Incorporated your ideas.

Some comments:

* The feature is disabled on pre 2.4 versions. I the navigation stack is a hack and I do not like to keep it even as compatibility code. Especially if the buttons are added to other services.

* I'm directly assigning this.naviagteBack.disabled again. The reason for not using the makeElement shorthand is, that this uses dom attributes and this means it will always be disabled (according to html spec, <button disable="anything"/> will disable the button).

* I'm exposing Nuvola.ACTION_CHANGED instead of using "action-changed"

* The JS API version should be bumped to 2.3 (have not done this)

* I think the other Google Play Service options can also be dynamically activated. I may add a ticket for this later.

review: Needs Resubmitting
Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Forget the last two comments, just saw that this is already in trunk. Will update code according to latest trunk.

788. By Martin Pöhlmann

Merged latest trunk

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Updated code to your latest trunk changes.

review: Needs Resubmitting
Revision history for this message
Jiří Janoušek (fenryxo) wrote :
Download full text (4.0 KiB)

> I'm directly assigning this.naviagteBack.disabled again. The reason for not using the makeElement shorthand is, that this uses dom attributes and this means it will always be disabled (according to html spec, <button disable="anything"/> will disable the button).

It is possible to use elm.removeAttribute(), but you can keep it your way.

> I'm exposing Nuvola.ACTION_CHANGED instead of using "action-changed"

In that case you have to define it for older versions.

integration.js:
/* Monkey patching */
if (Nuvola.ACTION_CHANGED === undefined) // @since JS API 2.3
    Nuvola.ACTION_CHANGED = "action-changed";

> The feature is disabled on pre 2.4 versions.

In that case it would be better to move as much code as possible to shared file /data/nuvolaplayer/js/main.js. What do you think about it?

main.js
-------

// FIXME: documentation; backClass, backStyles, forwardClass, forwardStyles optional
Nuvola.NavigationButtons = function(backClass, backStyles, forwardClass, forwardStyles)
{
    this.backAction = Nuvola.Action(Nuvola.NavigationButtons.BACK);
    this.forwardAction = Nuvola.Action(Nuvola.NavigationButtons.FORWARD);
    this.backButton = Nuvola.makeElement("button", null, "<");
    this.forwardButton = Nuvola.makeElement("button", null, ">");
    if (backClass)
        this.backButton.className = backClass;
    if (backStyles)
        Nuvola.css(this.backButton, backStyles);
    if (backClass)
        this.forwardButton.className = forwardClass;
    if (forwardStyles)
        Nuvola.css(this.forwardButton, forwardStyles);
}

Nuvola.NavigationButtons.BACK = "back";
Nuvola.NavigationButtons.FORWARD = "forward";

// FIXME: documentation
Nuvola.NavigationButtons.prototype.update = function(name)
{
    var button = this[name + "Button"];
    var action = this[name + "Action"];
    if (button && action)
        button.disabled = !action.sensitive;
}

// FIXME: documentation
Nuvola.NavigationButtons.prototype.prepend = function(parent)
{
    if (!parent)
        return false;
    return this.insert(parent, parent.firstChild)
}

// FIXME: documentation
Nuvola.NavigationButtons.prototype.insert = function(parent, nextChild)
{

    if (!parent || !nextChild || this.parent)
        return false;

    var firstChild = parent.firstChild;
    parent.insertBefore(this.forwardButton, nextChild);
    parent.insertBefore(this.backButton, nextChild);
    this.parent = parent;
    return true;
}

// FIXME: documentation
Nuvola.NavigationButtons.prototype.append = function(parent)
{
    if (!parent || this.parent)
        return false;

    var firstChild = parent.firstChild;
    parent.appendChild(this.forwardButton);
    parent.appendChild(this.backButton);
    this.parent = parent;
    return true;
}

// FIXME: documentation
Nuvola.NavigationButtons.prototype.remove = function()
{
    if (!this.parent)
        return false;

    this.parent.removeChild(this.forwardButton);
    this.parent.removeChild(this.backButton);
    this.parent = undefined;
    return true;
}

// FIXME: documentation
Nuvola.css = function(elm, styles)
{
    for (var style in styles)
        elm.style[style] = styles[style];
}

integration.js
--------------

/* ...

Read more...

review: Needs Fixing
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

Also, add yourself to the list of copyright holders at the top of integration.js.

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Resubmited. Some thoughts:

I know about removeElement, but this requires to 1) create the attributes object conditionally 2) use addElement/removeElement on update. This way it is much simpler.

The whole navigation bar integration is now a separate object in main.js as you suggested. This keeps code much simpler and reusable across services (I might also have a look at amazon and bandcamp integration). In the end I decided against taking your proposal as-is:
 * Creating the element will be handled by the service integration. There are lots of corner cases where you might wish to add some extra stuff. So just pass the back/forward button elements to the constructor.
 * I did not like feeding the integration object with message handler callbacks. Hence I've completely rewritten message handling for JS API 2.3 onwards. main.js defines a default message handler Nuvola.onMessageReceived that dispatches messages to handlers registered with Nuvola.onMessageReceived.addHandler(). Now the service integration as well the navigation button can register separate handlers. Pre JS API 2.3 will just override Nuvola.onMessageReceived as before, so this shouldn't be a problem (and navigation buttons are not available there anyways). I alo had to disable throwing exceptions in the message handler of the service integration, but using logging instead. Should yield the same result anyways.
 * The integration can be disabled either by calling deconstruct or setEnabled(false). The latter will just manipulate the element style to be hidden (used for google).
* Integration for navigation buttons is enabled by default.

Minor:
* Nuvola.Action and Nuvola.NavigationMuttonIntegration are wrapped in additional curly brackets to indicate that they are separate objects and support readability.
* I'm not sure if my integration code somehow messes with hide googleplus controls (searchbar is not stretched 100%). Hence I've adjusted the CSS there. Related: I'm not sure if the code below /* Fix bar dimensions */ is actually doing something and whether it can be removed.

review: Needs Resubmitting
789. By Martin Pöhlmann

Bug #1212167:
* Moved navigation button to main.js
* Rewritten messageHandler
* Fixed search bar style

Revision history for this message
Jiří Janoušek (fenryxo) wrote :

FYI, I was in hospital last seven days. I'll take a look at your changes ASAP.

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Take the time to recover. This thingy can wait.

Revision history for this message
Jiří Janoušek (fenryxo) wrote :

> Creating the element will be handled by the service integration.

Ok.

> Hence I've completely rewritten message handling for JS API 2.3 onwards.

So significant change is not acceptable for minor update of JavaScript API. However, I will take it into account during designing of JS API 3.0.

> Nuvola.Action and Nuvola.NavigationMuttonIntegration are wrapped in additional curly brackets to indicate that they are separate objects and support readability.

Nice :-)

> I'm not sure if my integration code somehow messes with hide googleplus controls

Yes, your changes broke the fix bar dimensions code. However, the feature has been just removed from trunk.

278 + * Copyright 2014 Martin Pöhlmann <http://mpdeimos.com>

Please use your contact e-mail instead of a website.

381 + // Otherwise, if not yet integrated and disabled, do nothing.
382 + if (Nuvola.config.navigationButtons !== true)
383 + {
384 + return;
385 + }

The button should be enabled by default, so condition Nuvola.config.navigationButtons === false has to be used to allow Nuvola.config.navigationButtons to be undefined (the default value).

review: Needs Fixing
Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Thanks for the review, here are few comments/questions before I start to rework.

> > Hence I've completely rewritten message handling for JS API 2.3 onwards.
>
> So significant change is not acceptable for minor update of JavaScript API.

As I've said, the modification should be fully backwards compatible and not break existing services. Just in case a service wants to use the button integration, it has to register a handler instead of overriding it.
However, I can understand your concerns. Depending on your plans for 3.0 I would opt for the following:

* Wait with the whole implementation till 3.0 (I'm also ok with that)
* Move implementation back to gMusic (assuming that there will no other services to follow till 3.0 release?)
* Doing a mixture with keeping the implementation in main.js and passing the callbacks from the service integration side. However, I am not sure if it is worth if 3.0 contains JS API changes (see next question).

> However, I will take it into account during designing of JS API 3.0.

Is 3.0 planned to be JS-backwards compatible?
I haven't found code for 3.0 yet, when do you plan to push the branch to LP?

> > Nuvola.Action and Nuvola.NavigationMuttonIntegration are wrapped in
> additional curly brackets to indicate that they are separate objects and
> support readability.
>
> Nice :-)
>
> > I'm not sure if my integration code somehow messes with hide googleplus
> controls
>
> Yes, your changes broke the fix bar dimensions code. However, the feature has
> been just removed from trunk.

I'll merge trunk when starting to rework, so will see what happened to this.

> 278 + * Copyright 2014 Martin Pöhlmann <http://mpdeimos.com>
>
> Please use your contact e-mail instead of a website.

I was a bit picky about adding my gmail addy, because of spam :)

>
> 381 + // Otherwise, if not yet integrated and disabled, do nothing.
> 382 + if (Nuvola.config.navigationButtons !== true)
> 383 + {
> 384 + return;
> 385 + }
>
> The button should be enabled by default, so condition
> Nuvola.config.navigationButtons === false has to be used to allow
> Nuvola.config.navigationButtons to be undefined (the default value).

True, good catch. Dealing with undefined (besides null) is a bit strange for a Java/C# guy like me :)

Revision history for this message
Jiří Janoušek (fenryxo) wrote :

> Is 3.0 planned to be JS-backwards compatible? I haven't found code for 3.0 yet, when do you plan to push the branch to LP?

JS API 3.0 won't be backward compatible. It will be part of Nuvola Player 3.0 - a new codebase written from scratch on top of WebKit2Gtk (the second generation of WebKitGtk). There is no code yet of NP 3.0, I'm starting with a utility library first. Meanwhile, series 2.x is still open for new not so intrusive features like your in-page buttons.

790. By Martin Pöhlmann

Merged trunk

791. By Martin Pöhlmann

Resolved minor comments from review

792. By Martin Pöhlmann

Removed generic message handler implementation from main.js

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Applied your review comments. Most of the changes result from removing the message handler code from main.js

review: Needs Resubmitting
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

Great :-) There is only one issue left: the search button covers the +Name text https://db.tt/fPWCl4K2

It might be necessary to reintroduce queueFixBarDimensions() function removed in commit 807 to set proper searchField.style.width = bar.clientWidth - {all bar elements except for search element}.offsetWidth. Or you can propose alternate solution.

http://bazaar.launchpad.net/~fenryxo/nuvola-player/trunk/revision/807

review: Needs Fixing
Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Hm, I'm not able to get into the state you showed. Tried several times, also with chrome web application (including the nav buttons).

This screenshot shows (almost) exactly the same size as yours (I've my cache cleared)
https://copy.com/lBiQzFfRyeUjoMoi

Any ideas?

Offtopic: I can also apply the 'hide g+ stuff' simply by calling document.getElementById("gb").firstChild.firstChild.style.display="none"
and there are no further visual glitches.
If one wants to "stretch" the searchbar, it works with:
document.getElementById("gbq").parentNode.style.width="100%";
document.getElementById("gbq").parentNode.style.setProperty("margin-right", "30px", "important");

review: Needs Information
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

> Hm, I'm not able to get into the state you showed.

This issue might occur only in a specific WebKit version - I use libwebkitgtk-3.0-0 1.8.1. Could you add extra space (30px?) after the search button?

> I can also apply the 'hide g+ stuff'

I don't want to reintroduce this feature again.

793. By Martin Pöhlmann

Adjusted query bar width if webkit dows not support flexible boxes

794. By Martin Pöhlmann

merged trunk

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Seems like older webkit implementations do not support flexible boxes. The good thing is that google has already some compatibility code, so adding a margin in case flexible boxes are not avail will suffice.

Ready for review.

review: Needs Resubmitting
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

> queryBarFirstChild.style.marginRight = "85px";

I don't like that hard-coded value. Would it be possible to calculate it using offsetWidth property of the buttons?

review: Needs Information
Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

I'll have a look after the weekend.

review: Needs Fixing
795. By Martin Pöhlmann

calculating margin dynamically

Revision history for this message
Martin Pöhlmann (mpdeimos) wrote :

Fixed (internet connection on the highway was better than I thought)

review: Needs Resubmitting
Revision history for this message
Jiří Janoušek (fenryxo) wrote :

Approved. Could you subscribe to the development mailing list at https://launchpad.net/~nuvola-player-devel ? I will send there information about JS API 3.0.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/nuvolaplayer/js/main.js'
2--- data/nuvolaplayer/js/main.js 2014-01-12 10:44:36 +0000
3+++ data/nuvolaplayer/js/main.js 2014-03-14 16:57:37 +0000
4@@ -1,5 +1,6 @@
5 /*
6- * Copyright 2011-2012 Jiří Janoušek <janousek.jiri@gmail.com>
7+ * Copyright 2011-2014 Jiří Janoušek <janousek.jiri@gmail.com>
8+ * Copyright 2014 Martin Pöhlmann <martin.deimos@gmx.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12@@ -264,42 +265,6 @@
13 }
14
15 /**
16- * Creates new Action object.
17- *
18- * @param name action name [string]
19- */
20- Nuvola.Action = function(name)
21- {
22- this.name = name;
23- }
24-
25- /**
26- * Manipulates with action property
27- *
28- * @param name action name [string]
29- * @param value undefined to get the current value or a new value to set the new value
30- */
31- Nuvola.Action.prototype.prop = function(name, value)
32- {
33- if (value === undefined)
34- return Nuvola.getActionProperty(this.name, name);
35-
36- if (name != "sensitive")
37- throw new Error("Property '" + name + "' is read-only.");
38-
39- Nuvola.updateAction(this.name, value);
40- }
41-
42- /**
43- * Triggers action
44- */
45- Nuvola.Action.prototype.trigger = function()
46- {
47- return Nuvola.triggerAction(this.name);
48- }
49-
50-
51- /**
52 * Add getter/setter for object's property.
53 *
54 * @param klass class constructor
55@@ -314,11 +279,6 @@
56 }
57
58 /**
59- * @property Nuvola.Action.sensitive whether the action is enabled [bool]
60- */
61- Nuvola.addProperty(Nuvola.Action, "sensitive");
62-
63- /**
64 * Adds CSS style sheet
65 *
66 * @since Nuvola JS API 2.3
67@@ -355,6 +315,133 @@
68 }
69 return false;
70 }
71+
72+ /**
73+ * class Nuvola.Action
74+ *
75+ * Wrapper object for accessing and triggering GTKActions
76+ *
77+ * @since Nuvola JS API 2.3
78+ */
79+ {
80+ /**
81+ * Creates new Action object.
82+ *
83+ * @param name action name [string]
84+ */
85+ Nuvola.Action = function(name)
86+ {
87+ this.name = name;
88+ }
89+
90+ /**
91+ * Manipulates with action property
92+ *
93+ * @param name action name [string]
94+ * @param value undefined to get the current value or a new value to set the new value
95+ */
96+ Nuvola.Action.prototype.prop = function(name, value)
97+ {
98+ if (value === undefined)
99+ return Nuvola.getActionProperty(this.name, name);
100+
101+ if (name != "sensitive")
102+ throw new Error("Property '" + name + "' is read-only.");
103+
104+ Nuvola.updateAction(this.name, value);
105+ }
106+
107+ /**
108+ * Triggers action
109+ */
110+ Nuvola.Action.prototype.trigger = function()
111+ {
112+ return Nuvola.triggerAction(this.name);
113+ }
114+
115+ /**
116+ * @property Nuvola.Action.sensitive whether the action is enabled [bool]
117+ */
118+ Nuvola.addProperty(Nuvola.Action, "sensitive");
119+ }
120+
121+ /**
122+ * class Nuvola.NavigationButtonIntegration
123+ *
124+ * Support object for integrating and handling navigation buttons.
125+ * This class requires that Nuvola.onMessageReceived is not overridden by the service integration.
126+ *
127+ * @since Nuvola JS API 2.3
128+ */
129+ {
130+ /**
131+ * Creates a new NavigationButtonIntegration instance.
132+ *
133+ * @param backButton the back button [Element]
134+ * @param forwardButton the forward button [Element]
135+ */
136+ Nuvola.NavigationButtonIntegration = function(backButton, forwardButton)
137+ {
138+ this.backButton = backButton;
139+ this.backAction = new Nuvola.Action(Nuvola.NavigationButtonIntegration.BACK);
140+ this.backButtonDisplayEnabled = this.backButton.style.display;
141+ this.setSensitivity(this.backButton, this.backAction);
142+ this.backButton.addEventListener('click', this.backAction.trigger.bind(this.backAction));
143+
144+ this.forwardButton = forwardButton;
145+ this.forwardAction = new Nuvola.Action(Nuvola.NavigationButtonIntegration.FORWARD);
146+ this.forwardButtonDisplayEnabled = this.forwardButton.style.display;
147+ this.setSensitivity(this.forwardButton, this.forwardAction);
148+ this.forwardButton.addEventListener('click', this.forwardAction.trigger.bind(this.forwardAction));
149+ }
150+
151+ /** @private Prefix for navigation back button and back action. */
152+ Nuvola.NavigationButtonIntegration.BACK = "back";
153+
154+ /** @private Prefix for navigation forward button and action. */
155+ Nuvola.NavigationButtonIntegration.FORWARD = "forward";
156+
157+ /** Enables or disables the buttons by toggling style.display 'hidden'. */
158+ Nuvola.NavigationButtonIntegration.prototype.setEnabled = function(enabled)
159+ {
160+ if (enabled)
161+ {
162+ this.backButton.style.display = this.backButtonDisplayEnabled;
163+ this.forwardButton.style.display = this.forwardButtonDisplayEnabled;
164+ }
165+ else
166+ {
167+ this.backButton.style.display = 'none';
168+ this.forwardButton.style.display = 'none';
169+ }
170+ }
171+
172+ /** Sets the enabled state of a navigation button according to the action sensitivity. Override for custom behavior. */
173+ Nuvola.NavigationButtonIntegration.prototype.setSensitivity = function(button, action)
174+ {
175+ button.disabled = !action.sensitive;
176+ }
177+
178+ /** Handles action changes to adjust the sensitivity state of the buttons. Returns true if the message was handled. */
179+ Nuvola.NavigationButtonIntegration.prototype.onMessageReceived = function(message, action, property)
180+ {
181+ if (message !== Nuvola.ACTION_CHANGED && property !== "sensitive")
182+ {
183+ return false;
184+ }
185+
186+ var button = this[action + "Button"];
187+ var action = this[action + "Action"];
188+
189+ if (button === undefined || action === undefined)
190+ {
191+ return false;
192+ }
193+
194+ this.setSensitivity(button, action);
195+ return true;
196+ }
197+ }
198
199 // Immediately call the anonymous function with Nuvola JS API main object as an argument.
200 // Note that "this" is set to the Nuvola JS API main object.
201
202=== modified file 'data/nuvolaplayer/services/googleplay/integration.js'
203--- data/nuvolaplayer/services/googleplay/integration.js 2014-03-07 20:42:27 +0000
204+++ data/nuvolaplayer/services/googleplay/integration.js 2014-03-14 16:57:37 +0000
205@@ -1,5 +1,6 @@
206 /*
207- * Copyright 2011-2012 Jiří Janoušek <janousek.jiri@gmail.com>
208+ * Copyright 2011-2014 Jiří Janoušek <janousek.jiri@gmail.com>
209+ * Copyright 2014 Martin Pöhlmann <http://mpdeimos.com>
210 *
211 * Redistribution and use in source and binary forms, with or without
212 * modification, are permitted provided that the following conditions are met:
213@@ -25,7 +26,6 @@
214 /* Anonymous function is used not to pollute environment */
215 (function(Nuvola){
216 var ACTIVITY_INTERVAL = 15*60*1000;
217- console.debug(Nuvola);
218 if (Nuvola.libVersion && Nuvola.warn)
219 {
220 var gst = Nuvola.libVersion("gstreamer");
221@@ -208,7 +208,7 @@
222 * Command handler
223 * @param cmd command to execute
224 */
225- Integration.prototype.messageHandler = function(cmd)
226+ Integration.prototype.messageHandler = function(cmd, param1, param2)
227 {
228 if (cmd === Nuvola.CONFIG_CHANGED)
229 {
230@@ -217,6 +217,12 @@
231 return;
232 }
233
234+ // Return if navigation buttons are enabled and can handle this event.
235+ if (this.navigationButtons !== undefined && this.navigationButtons.onMessageReceived(cmd, param1, param2) === true)
236+ {
237+ return;
238+ }
239+
240 /* SJBpost is an internal Google Music JavaScript function */
241 var buttons = document.querySelector("#player .player-middle");
242 if (buttons)
243@@ -229,7 +235,7 @@
244 var prev_song = null;
245 var next_song = null;
246 }
247-
248+
249 try{
250 switch(cmd){
251 case Nuvola.ACTION_PLAY:
252@@ -261,7 +267,7 @@
253 // Other commands are not supported
254 throw {"message": "Not supported."};
255 }
256- console.log(this.name + ": comand '" + cmd + "' executed.");
257+ console.log(this.name + ": comand '" + cmd + "' handled.");
258 }
259 catch(e){
260 // API expects exception to be a string!
261@@ -284,12 +290,13 @@
262 var callback = Nuvola.bind(this, this.simulateActivity);
263 this.simulateActivityTimeout = setTimeout(callback, ACTIVITY_INTERVAL);
264 }
265-
266- if (Nuvola.config.simulateActivity !== true && this.simulateActivityTimeout !== undefined)
267+ else if (Nuvola.config.simulateActivity !== true && this.simulateActivityTimeout !== undefined)
268 {
269 window.clearTimeout(this.simulateActivityTimeout);
270 this.simulateActivityTimeout = undefined;
271 }
272+
273+ this.integrateNavigationButtons();
274 }
275
276 Integration.prototype.simulateActivity = function(){
277@@ -301,6 +308,66 @@
278 }
279 }
280
281+ Integration.prototype.integrateNavigationButtons = function(){
282+ // This feature is disabled on pre 2.4.0
283+ if (Nuvola.NavigationButtonIntegration === undefined)
284+ {
285+ return;
286+ }
287+
288+ // If the navigation buttons are already integrated, adjust enablement state.
289+ if (this.navigationButtons !== undefined)
290+ {
291+ this.navigationButtons.setEnabled(Nuvola.config.navigationButtons !== false);
292+ return;
293+ }
294+
295+ // Otherwise, if not yet integrated and disabled, do nothing.
296+ if (Nuvola.config.navigationButtons === false)
297+ {
298+ return;
299+ }
300+
301+ var queryBar = document.getElementById("gbq2");
302+ if (!queryBar)
303+ {
304+ console.log("Could not find the query bar.");
305+ return;
306+ }
307+
308+ var queryBarFirstChild = queryBar.firstChild;
309+
310+ var navigateBack = Nuvola.makeElement("button", null, "<");
311+ navigateBack.className = "button small vertical-align";
312+ navigateBack.style.float = "left";
313+ navigateBack.style.marginRight = "0px";
314+ navigateBack.style.borderTopRightRadius = "2px";
315+ navigateBack.style.borderBottomRightRadius = "2px";
316+ queryBar.insertBefore(navigateBack, queryBarFirstChild);
317+
318+ var navigateForward = Nuvola.makeElement("button", null, ">");
319+ navigateForward.className = "button small vertical-align";
320+ navigateForward.style.float = "left";
321+ navigateForward.style.marginRight = "15px";
322+ navigateForward.style.borderLeft = "none";
323+ navigateForward.style.borderTopLeftRadius = "2px";
324+ navigateForward.style.borderLeftRightRadius = "2px";
325+ queryBar.insertBefore(navigateForward, queryBarFirstChild);
326+
327+ // If webkit browser does not support flexible boxes, we have to add a right margin
328+ // to the right of the query bar with width of the buttons (incl. margin)
329+ if (!("flex" in document.body.style || "-webkit-flex" in document.body.style))
330+ {
331+ var buttonWidth = navigateBack.offsetWidth
332+ + navigateForward.offsetWidth
333+ + parseInt(navigateForward.style.marginRight);
334+ queryBarFirstChild.style.marginRight = buttonWidth + "px";
335+
336+ window.dispatchEvent(new Event('resize')); // force update in google script
337+ }
338+
339+ this.navigationButtons = new Nuvola.NavigationButtonIntegration(navigateBack, navigateForward);
340+ }
341
342 Integration.prototype.getThumbs = function()
343 {
344
345=== modified file 'data/nuvolaplayer/services/googleplay/settings.js'
346--- data/nuvolaplayer/services/googleplay/settings.js 2014-02-25 16:56:13 +0000
347+++ data/nuvolaplayer/services/googleplay/settings.js 2014-03-14 16:57:37 +0000
348@@ -28,6 +28,17 @@
349 var _ = Nuvola.gettext;
350 var form = Nuvola.getSettingsForm();
351
352+if (Nuvola.NavigationButtonIntegration !== undefined)
353+{
354+ form.append(new Nuvola.Checkbox(_("Integrate navigation buttons"),
355+ Nuvola.config.navigationButtons !== false,
356+ function(){
357+ Nuvola.config.navigationButtons = this.checked;
358+ Nuvola.saveConfig();
359+ }
360+ ));
361+}
362+
363 form.append(new Nuvola.Checkbox(_("Don't stop playback due to inactivity"),
364 Nuvola.config.simulateActivity === true,
365 function()
366
367=== modified file 'src/nuvola/core/jsapi.vala'
368--- src/nuvola/core/jsapi.vala 2014-02-03 18:20:19 +0000
369+++ src/nuvola/core/jsapi.vala 2014-03-14 16:57:37 +0000
370@@ -510,7 +510,7 @@
371 }
372
373 /**
374- * Loads service's own configuration to the main object, implementation of Nuvola.loadConfig()
375+ * Loads service's own configuration to the main object, implementation of Nuvola.reloadConfig()
376 */
377 static unowned JS.Value load_config_func(Context ctx, JS.Object function, JS.Object self, JS.Value[] args, out unowned JS.Value exception){
378 exception = null;
379@@ -870,6 +870,7 @@
380 o_set_string(ctx, object_this, "ACTION_THUMBS_DOWN", Actions.THUMBS_DOWN);
381 o_set_string(ctx, object_this, "ACTION_FAVORITE", Actions.FAVORITE);
382 o_set_string(ctx, object_this, "CONFIG_CHANGED", CONFIG_CHANGED_MESSAGE);
383+ o_set_string(ctx, object_this, "ACTION_CHANGED", ACTION_CHANGED_MESSAGE);
384 o_set_number(ctx, object_this, "API_VERSION", (double)API_VERSION);
385 o_set_number(ctx, object_this, "API_VERSION_MINOR", (double)API_VERSION_MINOR);
386 o_set_number(ctx, object_this, "VERSION_MAJOR", (double)Config.VERSION_MAJOR);

Subscribers

People subscribed via source and target branches