main.js
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010, Pioneers of the Inevitable, Inc.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 
8  * Redistributions of source code must retain the above copyright notice,
9  this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation
12  and/or other materials provided with the distribution.
13  * Neither the name of Pioneers of the Inevitable, Songbird, nor the names
14  of its contributors may be used to endorse or promote products derived
15  from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 Cu.import("resource://app/jsmodules/DOMUtils.jsm");
30 
31 // Make a namespace.
32 if (typeof LastFm == 'undefined') {
33  var LastFm = {};
34 }
35 
36 if (typeof(gBrowser) == "undefined") {
37  var gBrowser = Cc['@mozilla.org/appshell/window-mediator;1']
38  .getService(Ci.nsIWindowMediator)
39  .getMostRecentWindow('Songbird:Main')
40  .window.gBrowser;
41 }
42 
43 LastFm.Icons = {
44  busy: 'chrome://sb-lastfm/skin/busy.png',
45  disabled: 'chrome://sb-lastfm/skin/disabled.png',
46  disabled_libre: 'chrome://sb-lastfm/skin/librefm_disabled.png',
47  logged_in_libre: 'chrome://sb-lastfm/skin/librefm.png',
48  logged_in: 'chrome://sb-lastfm/skin/as.png',
49  logged_out: 'chrome://sb-lastfm/skin/disabled.png',
50  error: 'chrome://sb-lastfm/skin/error.png',
51  login_error: 'chrome://sb-lastfm/skin/error.png'
52 };
53 
54 LastFm.URL_SIGNUP = 'http://www.last.fm/join/';
55 LastFm.URL_PASSWORD = 'http://www.last.fm/settings/lostpassword';
56 
57 
58 // Called when the window finishes loading
59 LastFm.onLoad = function() {
60  // the window has finished loading
61  this._strings = document.getElementById("lastfmStrings");
62 
63  // get the XPCOM service as a JS object
64  this._service = Components.classes['@songbirdnest.com/lastfm;1']
65  .getService().wrappedJSObject;
66  // listen to events from our Last.fm service
67  this._service.listeners.add(this);
68 
69 #ifdef METRICS_ENABLED
70  // get metrics service
71  this.metrics = Cc['@songbirdnest.com/Songbird/Metrics;1']
72  .getService(Ci.sbIMetrics);
73 #endif
74 
75  // get references to our pieces of ui
76 
77  // menu items
78  this._menuLogin = document.getElementById('lastfmMenuLogin');
79  this._menuLogout = document.getElementById('lastfmMenuLogout');
80  this._menuEnableScrobbling =
81  document.getElementById('lastfmMenuEnableScrobbling');
82 
83  // statusbar icon
84  this._statusIcon = document.getElementById('lastfmStatusIcon');
85 
86  // the panel binding
87  this._panelBinding = document.getElementById('lastfmLoginPanel');
88 
89  // the panel
90  this._panel = this._getElement(this._panelBinding, 'loginPanel');
91  this._tagPanel = document.getElementById('lastfmTagPanel');
92 
93  // the deck
94  this._deck = this._getElement(this._panelBinding, 'loginDeck');
95 
96  // login page of the deck
97  this._login = this._getElement(this._panelBinding, 'loginBox');
98  // login username field
99  this._username = this._getElement(this._panelBinding, 'username');
100  // login password field
101  this._password = this._getElement(this._panelBinding, 'password');
102  // login auto sign in checkbox
103  this._loginAutoLogin = this._getElement(this._panelBinding,
104  'loginAutoLogin');
105  // abort button
106  this._abortButton = this._getElement(this._panelBinding,
107  'abortButton');
108  // login button
109  this._loginButton = this._getElement(this._panelBinding, 'loginButton');
110  // login error description
111  this._loginError = this._getElement(this._panelBinding, 'loginError');
112  // new account groupbox
113  this._newAccountGroupbox = this._getElement(this._panelBinding,
114  'newAccountGroupbox');
115  // signup button
116  this._signupButton = this._getElement(this._panelBinding, 'signupButton');
117  // forgot password link
118  this._forgotpass = this._getElement(this._panelBinding, 'forgotpass');
119  this._forgotpass.textContent =
120  this._strings.getString('lastfm.forgotpass.label');
121 
122  // the logging-in page of the deck
123  this._loggingIn = this._getElement(this._panelBinding, 'loginProgressBox');
124 
125  // the logged-in / profile page of the deck
126  this._profile = this._getElement(this._panelBinding, 'profileBox');
127  // profile image
128  this._image = this._getElement(this._panelBinding, 'image');
129  // profile real name
130  this._realname = this._getElement(this._panelBinding, 'realname');
131  // profile tracks
132  this._tracks = this._getElement(this._panelBinding, 'profileDescription');
133  // enable-scrobbling checkbox
134  this._scrobble = this._getElement(this._panelBinding, 'profileCheckbox');
135  // profile auto sign in checkbox
136  this._profileAutoLogin = this._getElement(this._panelBinding,
137  'profileAutoLogin');
138 
139  // Create a DOM event listener set.
140  this._domEventListenerSet = new DOMEventListenerSet();
141 
142  var self = this;
143  // wire up UI events for the menu items
144  var onMenuLogin = function(event) {
145 #ifdef METRICS_ENABLED
146  self.metrics.metricsInc('lastfm', 'menu', 'login');
147 #endif
148  self.showPanel();
149  };
150  this._domEventListenerSet.add(this._menuLogin,
151  'command',
152  onMenuLogin,
153  false,
154  false);
155 
156  var onMenuLogout = function(event) {
157 #ifdef METRICS_ENABLED
158  self.metrics.metricsInc('lastfm', 'menu', 'logout');
159 #endif
160  self.showPanel();
161  };
162  this._domEventListenerSet.add(this._menuLogout,
163  'command',
164  onMenuLogout,
165  false,
166  false);
167 
168  var onMenuEnableScrobbling = function(event) {
169  self.metrics.metricsInc('lastfm', 'menu', 'scrobble');
170  self.toggleShouldScrobble();
171  };
172  this._domEventListenerSet.add(this._menuEnableScrobbling,
173  'command',
174  onMenuEnableScrobbling,
175  false,
176  false);
177 
178  // wire up click event for the status icon
179  var onStatusIconClicked = function(event) {
180  // only the left button
181  if (event.button != 0) return;
182 
183 #ifdef METRICS_ENABLED
184  self.metrics.metricsInc('lastfm', 'icon', 'click');
185 #endif
186 
187  if (self._service.loggedIn) {
188  // if we're logged in, toggle the scrobble state
189  self.toggleShouldScrobble();
190  } else {
191  // otherwise show the panel
192  self.showPanel();
193  }
194  };
195  this._domEventListenerSet.add(this._statusIcon,
196  'click',
197  onStatusIconClicked,
198  false,
199  false);
200 
201  // and the contextmenu event
202  var onStatusIconContextMenu = function(event) {
203 #ifdef METRICS_ENABLED
204  self.metrics.metricsInc('lastfm', 'icon', 'context');
205 #endif
206 
207  self.showPanel();
208  };
209  this._domEventListenerSet.add(this._statusIcon,
210  'contextmenu',
211  onStatusIconContextMenu,
212  false,
213  false);
214 
215  // wire up the abort login link
216  var onAbortButtonClicked = function(event) { self._panel.hidePopup(); };
217  this._domEventListenerSet.add(this._abortButton,
218  'click',
219  onAbortButtonClicked,
220  false,
221  false);
222 
223 
224  // wire up the signup link
225  var onSignupButtonClicked = function(event) {
226  self.loadURI(self.URL_SIGNUP, event);
227  };
228  this._domEventListenerSet.add(this._signupButton,
229  'click',
230  onSignupButtonClicked,
231  false,
232  false);
233 
234  // wire up the forgot password link
235  var onForgotpass = function(event) {
236  self.loadURI(self.URL_PASSWORD, event);
237  };
238  this._domEventListenerSet.add(this._forgotpass,
239  'click',
240  onForgotpass,
241  false,
242  false);
243 
244  // wire up UI events for the profile links
245  var onProfileUrlClicked = function(event) {
246  self.loadURI(self._service.profileurl, event);
247  };
248  this._domEventListenerSet.add(this._image,
249  'click',
250  onProfileUrlClicked,
251  false,
252  false);
253  this._domEventListenerSet.add(this._realname,
254  'click',
255  onProfileUrlClicked,
256  false,
257  false);
258 
259  var onTracksUrlClicked = function(event) {
260  self.loadURI('http://www.last.fm/user/' +
261  self._service.username + '/charts/', event);
262  };
263  this._domEventListenerSet.add(this._tracks,
264  'click',
265  onTracksUrlClicked,
266  false,
267  false);
268 
269  // ui events for the auto sign in checkbox
270  var onAutoLoginToggled = function(event) { self.toggleAutoLogin(); };
271  this._domEventListenerSet.add(this._loginAutoLogin,
272  'command',
273  onAutoLoginToggled,
274  false,
275  false);
276  this._domEventListenerSet.add(this._profileAutoLogin,
277  'command',
278  onAutoLoginToggled,
279  false,
280  false);
281 
282  // ui event for the should-scrobble checkbox
283  var onScrobbleToggled = function(event) { self.toggleShouldScrobble(); };
284  this._domEventListenerSet.add(this._scrobble,
285  'command',
286  onScrobbleToggled,
287  false,
288  false);
289 
290  var onButtonClicked = function(event) { self._handleUIEvents(event); };
291  this._domEventListenerSet.add(this._panelBinding,
292  'login-button-clicked',
293  onButtonClicked,
294  false,
295  false);
296  this._domEventListenerSet.add(this._panelBinding,
297  'cancel-button-clicked',
298  onButtonClicked,
299  false,
300  false);
301  this._domEventListenerSet.add(this._panelBinding,
302  'logout-button-clicked',
303  onButtonClicked,
304  false,
305  false);
306 
307  // copy the username & password out of the service into the UI
308  this._username.value = this._service.username;
309  this._password.value = this._service.password;
310 
311  // Initially disable the login button if no username or password value
312  if (!this._username.value || !this._password.value) {
313  this._loginButton.disabled = true;
314  }
315 
316  // create elements for the faceplate
317  var faceplateParent = document.getElementById('faceplate-tool-bar');
318  if (faceplateParent) {
319  this._faceplate = document.createElement('hbox');
320  this._faceplate.setAttribute('id', 'lastfmFaceplate');
321  faceplateParent.insertBefore(this._faceplate, faceplateParent.firstChild);
322  this._faceplateLove = document.createElement('image');
323  this._faceplateLove.setAttribute('id', 'lastfmFaceplateLove');
324  this._faceplateLove.setAttribute('mousethrough', 'never');
325  this._faceplateLove.setAttribute('tooltiptext',
326  this._strings.getString('lastfm.faceplate.love.tooltip'));
327 
328  var onFaceplateLoveClicked = function(event) {
329 #ifdef METRICS_ENABLED
330  self.metrics.metricsInc('lastfm', 'faceplate', 'love');
331 #endif
332 
333  if (self._service.loveTrack && self._service.love) {
334  /* if we have a loved track, then unlove */
335  self._service.loveBan(null, false);
336  } else {
337  /* otherwise, love */
338  self._service.loveBan(gMM.sequencer.currentItem, true);
339  }
340  };
341  this._domEventListenerSet.add(this._faceplateLove,
342  'click',
343  onFaceplateLoveClicked,
344  false,
345  false);
346  this._faceplate.appendChild(this._faceplateLove);
347 
348  this._faceplateBan = document.createElement('image');
349  this._faceplateBan.setAttribute('id', 'lastfmFaceplateBan');
350  this._faceplateBan.setAttribute('mousethrough', 'never');
351  this._faceplateBan.setAttribute('tooltiptext',
352  this._strings.getString('lastfm.faceplate.ban.tooltip'));
353 
354  var onFaceplateBanClicked = function(event) {
355 #ifdef METRICS_ENABLED
356  self.metrics.metricsInc('lastfm', 'faceplate', 'ban');
357 #endif
358 
359  if (self._service.loveTrack && !self._service.love) {
360  /* if we have a banned track, then unban */
361  self._service.loveBan(null, false);
362  } else {
363  /* otherwise, ban */
364  self._service.loveBan(gMM.sequencer.currentItem, false);
365  gMM.sequencer.next();
366  }
367  };
368  this._domEventListenerSet.add(this._faceplateBan,
369  'click',
370  onFaceplateBanClicked,
371  false,
372  false);
373  this._faceplate.appendChild(this._faceplateBan);
374 
375  this._faceplateTag = document.createElement('image');
376  this._faceplateTag.setAttribute('id', 'lastfmFaceplateTag');
377  this._faceplateTag.setAttribute('mousethrough', 'never');
378  this._faceplateTag.setAttribute('tooltiptext',
379  this._strings.getString('lastfm.faceplate.tag.tooltip'));
380 
381  var onFaceplateTagClicked = function(event) {
382 #ifdef METRICS_ENABLED
383  self.metrics.metricsInc('lastfm', 'faceplate', 'tag');
384 #endif
385 
386  self._tagPanel.openPopup(event.target);
387  var globalTags = document.getElementById("global-tags");
388  var userTags = document.getElementById("user-tags");
389  // clear out the tag boxes
390  while (userTags.firstChild)
391  userTags.removeChild(userTags.firstChild);
392  while (globalTags.firstChild)
393  globalTags.removeChild(globalTags.firstChild);
394 
395  // grab the tags from the service
396  for (var tag in self._service.userTags) {
397  var removable = self._service.userTags[tag];
398  var hbox = self.showOneMoreTag(tag, removable);
399  userTags.appendChild(hbox);
400  }
401  for (var tag in self._service.globalTags) {
402  var removable = self._service.globalTags[tag];
403  var hbox = self.showOneMoreTag(tag, removable);
404  globalTags.appendChild(hbox);
405  }
406 
407  if (!userTags.firstChild) {
408  document.getElementById("label-user-tags")
409  .style.visibility = "collapse";
410  }
411  if (!globalTags.firstChild) {
412  document.getElementById("label-global-tags")
413  .style.visibility = "collapse";
414  }
415  };
416  this._domEventListenerSet.add(this._faceplateTag,
417  'click',
418  onFaceplateTagClicked,
419  false,
420  false);
421  this._faceplate.appendChild(this._faceplateTag);
422 
423  // Add a preferences observer
424  this.prefs = Cc["@mozilla.org/preferences-service;1"]
425  .getService(Ci.nsIPrefService)
426  .getBranch("extensions.lastfm.")
427  .QueryInterface(Ci.nsIPrefBranch2);
428  this.prefs.addObserver("", this.prefObserver, false);
429  }
430 
431  // Add a listener to toggle visibility of the love/ban faceplate toolbar
432  Cc['@songbirdnest.com/Songbird/Mediacore/Manager;1']
433  .getService(Ci.sbIMediacoreManager)
434  .addListener(this);
435 
436  // clear the login error message
437  this.setLoginError(null);
438  // update the ui with the should-auto-login state
439  this.onAutoLoginChanged(this._service.autoLogin);
440  // update the ui with the should-scrobble state
441  this.onShouldScrobbleChanged(this._service.shouldScrobble);
442  // update the ui with the logged-in state
443  this.onLoggedInStateChanged();
444  // update the ui with the love/ban state
445  this.onLoveBan();
446 
447  // if we have a username & password then try to log in
448  if (this._service.shouldAutoLogin()) {
449  this._service.login();
450  }
451 
452  // Attach our listener to the ShowCurrentTrack event issue by the faceplate
453  this._domEventListenerSet.add(window,
454  'ShowCurrentTrack',
455  this.showCurrentTrack,
456  true,
457  false);
458 }
459 
460 LastFm._getElement = function(aWidget, aElementID) {
461  return document.getAnonymousElementByAttribute(aWidget, "sbid", aElementID);
462 }
463 
464 LastFm.onMediacoreEvent = function(aEvent) {
465  switch(aEvent.type) {
466  case Ci.sbIMediacoreEvent.TRACK_CHANGE:
467  // Hide the faceplate controls for love/ban/tag if it's not audio
468  var mediaItem = aEvent.data;
469  if (mediaItem.getProperty(SBProperties.contentType) != "audio") {
470  document.getElementById("lastfmFaceplate").hidden = true;
471  } else {
472  document.getElementById("lastfmFaceplate").hidden = false;
473  }
474  break;
475  }
476 }
477 
478 LastFm.showOneMoreTag = function(tagName, removable) {
479  var hbox = document.createElement('hbox');
480  hbox.setAttribute("align", "center");
481  var delTag = document.createElement('image');
482  delTag.setAttribute("mousethrough", "never");
483  delTag.setAttribute('id', tagName);
484  hbox.appendChild(delTag);
485  var onDelTagClicked = null;
486  if (removable) {
487  onDelTagClicked = function(event) {
488  var tagName = event.target.id;
489  dump("removing tag: " + tagName + "\n");
490  self._service.removeTag(gMM.sequencer.currentItem, tagName);
491  this.parentNode.parentNode.removeChild(this.parentNode);
492  if (!this.parentNode.parentNode.firstChild) {
493  document.getElementById("label-user-tags")
494  .style.visibility = "collapse";
495  }
496  };
497 
498  this._domEventListenerSet.add(delTag,
499  'click',
500  onDelTagClicked,
501  false,
502  false);
503  delTag.setAttribute('class', 'tag-remove');
504  } else {
505  onDelTagClicked = function(event) {
506  var tagName = event.target.id;
507  dump("adding tag: " + tagName + "\n");
508  self.addThisTag(gMM.sequencer.currentItem, tagName);
509  };
510  this._domEventListenerSet.add(delTag,
511  'click',
512  onDelTagClicked,
513  false,
514  false);
515  delTag.setAttribute('class', 'tag-add');
516  }
517 
518  var label = document.createElement('label');
519  label.setAttribute('value', tagName);
520  label.setAttribute('class', 'tag-link');
521  if (removable) {
522  label.setAttribute('href', '/user/' + LastFm._service.username +
523  '/tags/' + tagName);
524  } else {
525  label.setAttribute('href', '/tag/' + tagName);
526  }
527 
528  var onLabelClicked = function(event) {
529  dump("loading: " + this.getAttribute('href'));
530  gBrowser.loadOneTab("http://www.last.fm"+this.getAttribute('href'));
531  };
532  this._domEventListenerSet.add(label,
533  'click',
534  onLabelClicked,
535  false,
536  false);
537 
538  hbox.appendChild(label);
539  return hbox;
540 }
541 
542 LastFm.addTags = function(event) {
543  // call the API to add the tags
544  var textbox = event.target;
545  var tagString = textbox.value;
546  LastFm.addThisTag(gMM.sequencer.currentItem, tagString, function() {
547  textbox.value = "";
548  }, function() {});
549 }
550 
551 LastFm.addThisTag = function(mediaItem, tagString, success, failure) {
552  // need to handle adding a global tag that already exists as a user tag
553  this._service.addTags(mediaItem, tagString, function() {
554  // add them to the tag panel
555  var tagBox = document.getElementById("user-tags");
556  var tags = tagString.split(",");
557  for (var i in tags) {
558  var tag = tags[i].replace(/^\s*/, "").replace(/\s*$/, "");
559  var hbox = LastFm.showOneMoreTag(tag, true);
560  tagBox.appendChild(hbox);
561  LastFm._service.userTags[tag] = true;
562  }
563 
564  if (tagBox.firstChild) {
565  document.getElementById("label-user-tags").style.visibility = "visible";
566  }
567  if (typeof(success) == "function")
568  success();
569  }, function() {
570  alert(LastFm._strings.getString('lastfm.tags.add_fail'));
571  if (typeof(failure) == "function")
572  failure();
573  });
574 }
575 
576 LastFm.onUnload = function() {
577  // the window is about to close
578  this._service.listeners.remove(this);
579  this.prefs.removeObserver("", this.prefObserver, false);
580 
581  // Remove DOM event listeners.
582  if (this._domEventListenerSet) {
583  this._domEventListenerSet.removeAll();
584  this._domEventListenerSet = null;
585  }
586 
587  // Add a listener to toggle visibility of the love/ban faceplate toolbar
588  Cc['@songbirdnest.com/Songbird/Mediacore/Manager;1']
589  .getService(Ci.sbIMediacoreManager)
590  .removeListener(this);
591 }
592 
593 LastFm.showCurrentTrack = function(e) {
594  var gMM = Cc['@songbirdnest.com/Songbird/Mediacore/Manager;1']
595  .getService(Ci.sbIMediacoreManager);
596  var item = gMM.sequencer.currentItem;
597  var artistPage =
598  item.getProperty("http://www.songbirdnest.com/lastfm#artistPage");
599  if (artistPage) {
600  dump("artist page: " + artistPage + "\n");
601  var mainWin =
602  Components.classes['@mozilla.org/appshell/window-mediator;1']
603  .getService(Components.interfaces.nsIWindowMediator)
604  .getMostRecentWindow('Songbird:Main');
605  if (mainWin && mainWin.gBrowser)
606  mainWin.gBrowser.loadOneTab(artistPage);
607  e.preventDefault();
608  e.stopPropagation();
609  }
610 }
611 
612 LastFm.showPanel = function LastFm_showPanel() {
613  this._panel.openPopup(this._statusIcon);
614 }
615 
616 
617 // UI event handlers
618 LastFm._handleUIEvents = function(aEvent) {
619  switch (aEvent.type) {
620  case "login-button-clicked":
621  this._service.userLoggedOut = false;
622  this._service.username = this._username.value;
623  this._service.password = this._password.value;
624  // call login, telling the service to ignore any saved sessions
625  this._service.login(true);
626  break;
627  case "cancel-button-clicked":
628  this._service.cancelLogin();
629  this._service.userLoggedOut = true;
630  break;
631  case "logout-button-clicked":
632  this.onLogoutClick(aEvent);
633  break;
634  default:
635  break;
636  }
637 
638  if (this._service.userLoggedOut) {
639  this._newAccountGroupbox.removeAttribute('loggedOut');
640  } else {
641  this._newAccountGroupbox.setAttribute('loggedOut', 'false');
642  }
643 }
644 
645 LastFm.onLogoutClick = function(event) {
646  this._service.userLoggedOut = true;
647  this._service.logout();
648  this.setLoginError(null);
649  this.updateStatus();
650 }
651 
652 // load an URL from an event in the panel
653 LastFm.loadURI = function(uri, event) {
654  gBrowser.loadURI(uri, null, null, event, '_blank');
655  this._panel.hidePopup();
656 }
657 
658 LastFm.toggleAutoLogin = function() {
659  this._service.autoLogin = !this._service.autoLogin;
660 }
661 
662 LastFm.toggleShouldScrobble = function() {
663  this._service.shouldScrobble = !this._service.shouldScrobble;
664 }
665 
666 // last.fm event handlers for login events
667 LastFm.onLoggedInStateChanged = function LastFm_onLoggedInStateChanged() {
668  if (this._service.loggedIn) {
669  // logged in
670 
671  // insert the "log out" menu item
672  this._menuEnableScrobbling.parentNode.insertBefore(this._menuLogout,
673  this._menuEnableScrobbling);
674  // remove the "log in" menu item
675  if (this._menuLogin.parentNode) {
676  this._menuLogin.parentNode.removeChild(this._menuLogin);
677  }
678  // enable the "enable scrobbling" menu item
679  this._menuEnableScrobbling.disabled = false;
680 
681  // main screen turn on
682  this._deck.selectedPanel = this._profile;
683 
684  // show the last.fm faceplate if we're logged in
685  document.getElementById("lastfmFaceplate").hidden = false;
686  } else {
687  // logged out
688  if (this._service.userLoggedOut) {
689  // remove the "log out" menu item
690  this._menuLogout.parentNode.removeChild(this._menuLogout);
691  // insert the "log in" menu item
692  this._menuEnableScrobbling.parentNode.insertBefore(this._menuLogin,
693  this._menuEnableScrobbling);
694  // disable the "enable scrobbling" menu item
695  this._menuEnableScrobbling.disabled = true;
696 
697  // don't show the last.fm faceplate if we're logged out
698  document.getElementById("lastfmFaceplate").hidden = true;
699  }
700 
701  // switch back to the login panel
702  this._deck.selectedPanel = this._login;
703  }
704 
705  this.updateStatus();
706 }
707 LastFm.onLoginBegins = function LastFm_onLoginBegins() {
708  this._deck.selectedPanel = this._loggingIn;
709  this.setStatusIcon(this.Icons.busy);
710  this.setStatusTextId('lastfm.state.logging_in');
711 }
712 LastFm.onLoginCancelled = function LastFm_onLoginCancelled() {
713  // clear the login error
714  this.setLoginError(null);
715 
716 }
717 LastFm.onLoginFailed = function LastFm_onLoginFailed() {
718  // set the login error message
719  this.setLoginError(this._strings.getString('lastfm.error.login_failed'));
720 
721  // set the status icon
722  this.updateStatus();
723 }
724 LastFm.onLoginSucceeded = function LastFm_onLoginSucceeded() {
725  // clear the login error
726  this.setLoginError(null);
727 }
728 
729 // last.fm profile changed
730 LastFm.onProfileUpdated = function LastFm_onProfileUpdated() {
731  var avatar = 'chrome://sb-lastfm/skin/default-avatar.png';
732  if (this._service.avatar) {
733  avatar = this._service.avatar;
734  }
735  this._image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', avatar);
736  if (this._service.realname && this._service.realname.length) {
737  this._realname.textContent = this._service.realname;
738  } else {
739  this._realname.textContent = this._service.username;
740  }
741  this._tracks.textContent =
742  this._strings.getFormattedString('lastfm.profile.numtracks',
743  [this._service.playcount]);
744 }
745 
746 // autoLogin changed
747 LastFm.onAutoLoginChanged = function LastFm_onAutoLoginChanged(val) {
748  if (val) {
749  this._loginAutoLogin.setAttribute('checked', 'true');
750  this._profileAutoLogin.setAttribute('checked', 'true');
751  } else {
752  this._loginAutoLogin.removeAttribute('checked');
753  this._profileAutoLogin.removeAttribute('checked');
754  }
755 }
756 
757 // shouldScrobble changed
758 LastFm.onShouldScrobbleChanged = function LastFm_onShouldScrobbleChanged(val) {
759  if (val) {
760  this._menuEnableScrobbling.setAttribute('checked', 'true');
761  this._scrobble.setAttribute('checked', 'true');
762  } else {
763  this._menuEnableScrobbling.removeAttribute('checked');
764  this._scrobble.removeAttribute('checked');
765  }
766  this.updateStatus();
767 }
768 
769 // userLoggedOut changed
770 LastFm.onUserLoggedOutChanged = function LastFm_onUserLoggedOutChanged(val) {
771  // we don't care
772 }
773 
774 // update the status icon's icon
775 LastFm.setStatusIcon = function LastFm_setStatusIcon(aIcon) {
776  this._statusIcon.setAttribute('src', aIcon);
777 }
778 
779 // update the status icon based on the current service state
780 LastFm.updateStatus = function LastFm_updateStatus() {
781  var stateName = '';
782  if (this._service.error) {
783  if (this._service.loggedIn) {
784  stateName = 'error';
785  } else {
786  stateName = 'login_error';
787  }
788  } else {
789  if (this._service.loggedIn) {
790  if (this._service.shouldScrobble) {
791  if (Application.prefs.getValue("extensions.lastfm.auth_url", "")
792  .indexOf("libre.fm") >= 0)
793  {
794  stateName = 'logged_in_libre'
795  } else {
796  stateName = 'logged_in';
797  }
798  } else {
799  if (Application.prefs.getValue("extensions.lastfm.auth_url", "")
800  .indexOf("libre.fm") >= 0)
801  {
802  stateName = 'disabled_libre';
803  } else {
804  stateName = 'disabled';
805  }
806  }
807  } else {
808  stateName = 'logged_out';
809  }
810  }
811  this.setStatusIcon(this.Icons[stateName]);
812  this.setStatusTextId('lastfm.state.'+stateName.replace("_libre", ""));
813 
814  if (stateName == 'logged_in') {
815  this._faceplate.removeAttribute('hidden');
816  } else {
817  this._faceplate.setAttribute('hidden', 'true');
818  }
819 }
820 
821 // update the status icon's text
822 LastFm.setStatusText = function LastFm_setStatusText(aText) {
823  this._statusIcon.setAttribute('tooltiptext', aText);
824 }
825 
826 // update the status icon's text from the properties file by id
827 LastFm.setStatusTextId = function LastFm_setStatusTextId(aId) {
828  this.setStatusText(this._strings.getString(aId));
829 }
830 
831 // update the login error - pass null to clear the error message
832 LastFm.setLoginError = function LastFm_setLoginError(aText) {
833  if (aText) {
834  this._loginError.textContent = aText;
835  this._loginError.style.visibility = 'visible';
836  } else {
837  this._loginError.textContent = '';
838  this._loginError.style.visibility = 'collapse';
839  }
840 }
841 
842 LastFm.onErrorChanged = function LastFm_onErrorChanged(aError) {
843  this.setLoginError(aError);
844 
845  this.updateStatus();
846 }
847 
848 // Love & Ban support
849 LastFm.onLoveBan = function LastFm_onLoveBan(aItem, love) {
850  if (this._service.loveTrack) {
851  // the current track is loved or banned
852  this._faceplate.setAttribute('loveban', this._service.love?'love':'ban');
853  } else {
854  this._faceplate.removeAttribute('loveban');
855  }
856 }
857 
858 LastFm.onAuthorisationSuccess = function LastFm_onAuthorisationSuccess() { }
859 
860 LastFm.prefObserver = {
861  observe: function(subject, topic, data) {
862  if (subject instanceof Components.interfaces.nsIPrefBranch &&
863  data == "show_radio_node")
864  {
865  var lastFmNode =
866  Cc['@songbirdnest.com/servicepane/service;1']
867  .getService(Ci.sbIServicePaneService)
868  .getNodeForURL("chrome://sb-lastfm/content/tuner2.xhtml");
869 
870  if (lastFmNode != null) {
871  lastFmNode.hidden = !Application.prefs.getValue(
872  "extensions.lastfm.show_radio_node", true);
873 
874  // Hide the "Radio" node if it's empty
875  var radioNode = lastFmNode.parentNode;
876  var enum = radioNode.childNodes;
877  var visibleFlag = false;
878 
879  // Iterate through elements and check if one is visible
880  while (enum.hasMoreElements()) {
881  var node = enum.getNext();
882  if (!node.hidden) {
883  visibleFlag = true;
884  break;
885  }
886  }
887 
888  radioNode.hidden = !visibleFlag;
889  }
890  }
891  }
892 }
893 
894 window.addEventListener("load", function(e) { LastFm.onLoad(e); }, false);
895 window.addEventListener("unload", function(e) { LastFm.onUnload(e); }, false);
const Cu
const Cc
var gMM
Definition: windowUtils.js:62
var Application
Definition: sbAboutDRM.js:37
var event
function DOMEventListenerSet()
Definition: DOMUtils.jsm:766
let window
this _contentSandbox label
Definition: FeedWriter.js:814
LastFm Icons
Definition: main.js:43
this _dialogInput val(dateText)
return null
Definition: FeedWriter.js:1143
let node
LastFm URL_SIGNUP
Definition: main.js:54
SimpleArrayEnumerator prototype hasMoreElements
var uri
Definition: FeedWriter.js:1135
var prefs
Definition: FeedWriter.js:1169
return aWindow document documentElement getAttribute(aAttribute)||dimension
observe topic
Definition: FeedWriter.js:1326
const Ci
dataSBGenres SBProperties tag
Definition: tuner2.js:871
observe data
Definition: FeedWriter.js:1329
_getSelectedPageStyle s i
sbDeviceFirmwareAutoCheckForUpdate prototype observe