servicepane.js
Go to the documentation of this file.
1 /* servicepane.js
2  * This will be loaded into the main window, and manage Service Pane
3  * integration of playlist folders.
4  */
5 // Make a namespace.
6 if (typeof playlistfolders == 'undefined') {
7  var playlistfolders = {};
8 };
9 
10 /* Service Pane controller
11  * Controller for playlist folder node handling in service pane
12  * Things that are only related to the nodes (Drag'n'drop, etc.) are done
13  * in pfServicePane XPCOM. This controller handles its connection to the
14  * preference controller.
15  */
16 playlistfolders.servicepane={
17  /* Ensure the node has dndacceptnear set so it accepts our folder drops
18  * n (node): the node to check
19  */
20  _ensureDND: function(n){
21  var dndacc = n.dndAcceptNear.split(",");
22  var found = false;
23  for each (var e in dndacc)
24  if (e == "application/x-pf-transfer-folder")
25  found = true;
26  if (!found){
27  dndacc.push("application/x-pf-transfer-folder");
28  n.dndAcceptNear = dndacc.join(",");
29  // if DND missed, the playlist might need to be included:
30  if (n.id.split("urn:item:").length > 1)
31  this._ensureAvailable(n.id.split("urn:item:")[1]);
32  }
33  },
34 
35  /* Ensure the playlist's guid is registered somewhere in our sort
36  * guid (string): the playlist's guid to check
37  */
38  _ensureAvailable: function(guid){
39  var found = false;
40  var folders = playlistfolders.preferences.getFolders();
41  for each (var f in folders)
42  for each (var e in f.content)
43  if (e == guid)
44  found = true;
45  if (!found)
46  playlistfolders.preferences.getFolderByGUID("{root}").content.push(guid);
47  },
48 
49  // Inject our Playlist Folder Service Pane Module into service pane
50  _inject: function(){
51  // Ensure our Service Pane Module is registered and running
52  var Cr = Components.manager.QueryInterface(Components.interfaces.
53  nsIComponentRegistrar);
54  if (!Cr.isContractIDRegistered("@rsjtdrjgfuzkfg.com/servicepane/" +
55  "folders;1")){
56  playlistfolders.central.logEvent("servicepane",
57  "Register Service Pane Module.", 4);
58  var emgr = Components.classes['@mozilla.org/extensions/manager;1'].
59  getService(Ci.nsIExtensionManager);
60  var moduleFile = emgr.getInstallLocation("playlistfolders@" +
61  "rsjtdrjgfuzkfg.com").
62  getItemLocation("playlistfolders@" +
63  "rsjtdrjgfuzkfg.com");
64  moduleFile.append("components");
65  moduleFile.append("pfServicePane.js");
66  Cr.autoRegister(moduleFile);
67  }
68 
69  var SPS = Cc["@songbirdnest.com/servicepane/service;1"].
70  getService(Ci.sbIServicePaneService);
71  var nodes = SPS.getNode("SB:Playlists").childNodes;
72  while (nodes.hasMoreElements()){
73  this._ensureDND(nodes.getNext());
74  }
75 
76  },
77 
78  /* Returns the node for a folder
79  * folder(folder): the folder object for the node
80  */
81  _getFolderNode: function(folder){
82  var SPS = Cc["@songbirdnest.com/servicepane/service;1"].
83  getService(Ci.sbIServicePaneService);
84  var dtSP_NS = 'http://songbirdnest.com/rdf/servicepane#';
85  var node = SPS.getNode("urn:folder:" + folder.GUID);
86  if (!node){
87  node = SPS.createNode();
88  node.id = "urn:folder:" + folder.GUID;
89  node.url = "chrome://playlistfolders/content/folder.xul?guid=" +
90  folder.GUID;
91  node.name = folder.name;
92  node.contractid = "@rsjtdrjgfuzkfg.com/servicepane/folders;1";
93  node.editable = true;
94  node.setAttributeNS(dtSP_NS, "addonID",
95  "playlistfolders@rsjtdrjgfuzkfg.com");
96  if (folder.closed){
97  node.setAttribute("isOpen", "false");
98  node.image = "chrome://playlistfolders/skin/" +
99  "icon-folder-closed.png";
100  } else {
101  node.image = "chrome://playlistfolders/skin/icon-folder.png";
102  }
103  node.className = "playlistfolder";
104  } else
105  playlistfolders.central.logEvent("servicepane", "Node urn:folder:" +
106  folder.GUID + " exists already, " +
107  "won't create a new one.", 3,
108  "chrome://playlistfolders/content" +
109  "/servicepane.js");
110  return node;
111  },
112 
113  // Loads folders from preference controller into service pane
114  onLoad: function(e) {
115  playlistfolders.central.logEvent("servicepane",
116  "Service Pane initialisation started", 5);
117  try {
118  // Inject our custom management code
119  this._inject();
120  // Get the ServicePaneService
121  var SPS = Cc["@songbirdnest.com/servicepane/service;1"].
122  getService(Ci.sbIServicePaneService);
123 
124  // Fill service pane
125  var fillFolder = function (node, folder){
126  for each (var e in folder.content){
127  var snode = null;
128  if (playlistfolders.preferences.isFolder(e)){
129  var f = playlistfolders.preferences.getFolderByGUID(e);
130  snode = playlistfolders.servicepane._getFolderNode(f);
131  fillFolder(snode, f);
132  } else if (playlistfolders.preferences.isPlaylist(e)){
133  snode = SPS.getNode("urn:item:" + e);
134  }
135  if (snode)
136  node.appendChild(snode);
137  }
138  }
139  var rootFolder = playlistfolders.preferences.getFolderByGUID("{root}");
140  fillFolder(SPS.getNode("SB:Playlists"), rootFolder);
141  // Register us as listener
142  SPS.getNode("SB:Playlists").addMutationListener(this);
143  // We're done!
144  playlistfolders.central.logEvent("servicepane", "Service Pane " +
145  "controller started.", 4);
146  } catch (e){
147  playlistfolders.central.logEvent("servicepane", "Startup of Service " +
148  "Pane controller failed:\n\n" + e, 1,
149  "chrome://playlistfolders/content/" +
150  "servicepane.js", e.lineNumber);
151  }
152  },
153 
154  // Save order, unregister listener, etc.
155  onUnload: function(e){
156  playlistfolders.central.logEvent("servicepane", "Servicepane controller " +
157  "shutdown started.", 5);
158  // Unregister service pane listener
159  var SPS = Cc["@songbirdnest.com/servicepane/service;1"].
160  getService(Ci.sbIServicePaneService);
161  SPS.getNode("SB:Playlists").removeMutationListener(this);
162  // We're done!
163  playlistfolders.central.logEvent("servicepane",
164  "Servicepane controller stopped.", 4);
165  },
166 
167  // Called by UI, create a new Folder
168  newFolder: function(){
169  playlistfolders.central.logEvent("servicepane", "Create new Folder", 5);
170  // Generate a new folder
171  var bstrings = document.getElementById("playlistfolders-bookmark-strings");
172  var fname = bstrings.getString("newFolderDefault");
173  var folder = playlistfolders.preferences.createFolder(fname);
174  var node = this._getFolderNode(folder);
175  // Append it to the Playlist section in service pane, as last folder
176  var SPS = Cc["@songbirdnest.com/servicepane/service;1"]
177  .getService(Ci.sbIServicePaneService);
178  var fPlist = null;
179  var nodes = SPS.getNode("SB:Playlists").childNodes;
180  while (nodes.hasMoreElements()){
181  var n = nodes.getNext();
182  if ((!fPlist) && n.id && (n.id.split("urn:item:").length > 1))
183  fPlist = n;
184  }
185  SPS.getNode("SB:Playlists").insertBefore(node, fPlist);
186  // Start a renaming
187  gServicePane.startEditingNode(node);
188  },
189 
190  /* Called by UI, delete a given folder
191  * id (string): the folder's node's id
192  */
193  deleteFolder: function(id){
194  playlistfolders.central.logEvent("servicepane", "Delete Folder with " +
195  "Node " + id, 5);
196  // Parse folder object from node's id
197  var GUID = id.split('urn:folder:')[1];
198  var folder = playlistfolders.preferences.getFolderByGUID(GUID);
199 
200  // Ensure the user wants to delete
201  if (!playlistfolders.preferences.isDeleteBypass()) {
202  var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"]
203  .getService(Ci.nsIPromptService);
204  var check = { value: false };
205 
206  var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
207  .getService(Ci.nsIStringBundleService);
208 
209  var songbirdStrings = sbs.createBundle("chrome://songbird/locale/" +
210  "songbird.properties");
211  var pfoldersStrings = sbs.createBundle("chrome://playlistfolders/locale/" +
212  "playlistfolders.properties");
213  var strTitle = pfoldersStrings.GetStringFromName("delete.title");
214  var strMsg = pfoldersStrings.formatStringFromName("delete.msg",
215  [folder.name], 1);
216 
217  var strCheck = SBString("playlist.deletewarning.check");
218 
219  var r = promptService.confirmEx(window,
220  strTitle,
221  strMsg,
222  Ci.nsIPromptService.STD_YES_NO_BUTTONS,
223  null,
224  null,
225  null,
226  strCheck,
227  check);
228  if (check.value == true) {
229  playlistfolders.preferences.doDeleteBypass()
230  }
231  if (r == 1) { // 0 = yes, 1 = no
232  return;
233  }
234  }
235 
236  // Delete the folder, and if that succeeded delete the node
237  if (playlistfolders.preferences.removeFolder(folder, true))
238  document.getElementById(id).parentNode.
239  removeChild(document.getElementById(id));
240  },
241 
242  /* Called by UI, rename a given folder
243  * node (node): the folder's node
244  * name (string): the new name
245  */
246  renameFolder: function(node, name){
247  playlistfolders.central.logEvent("servicepane", "Rename Folder with " +
248  "Node " + node.id + " to " + name, 5);
249  // Parse folder object from node's id
250  var GUID = node.id.split('urn:folder:')[1];
251  var folder = playlistfolders.preferences.getFolderByGUID(GUID);
252  // Rename the folder
253  playlistfolders.preferences.renameFolder(folder, name);
254  node.name = name;
255  },
256 
257  /* Called by UI, move a given folder to a given place
258  * node (string): the id of the node of the folder to move
259  * targetFolder (node): the target folder's node or SB:Playlists for root
260  * insertBefore (node): the subfolder or playlist after target pos, or null
261  */
262  moveFolder: function(node, targetFolder, insertBefore){
263  playlistfolders.central.logEvent("servicepane", "Move Folder with " +
264  "Node " + node + " to " +
265  targetFolder.id + ", before " +
266  (insertBefore ? insertBefore.id : ""), 5);
267  // Move the node(s) only, we'll keep track in preferences via listener
268  var SPS = Cc["@songbirdnest.com/servicepane/service;1"]
269  .getService(Ci.sbIServicePaneService);
270  targetFolder.insertBefore(SPS.getNode(node), insertBefore);
271  },
272 
273  /* Called by UI, move a given playlist to a given place
274  * pguid (string): the id of the playlist to move
275  * targetFolder (node): the target folder's node or SB:Playlists for root
276  * insertBefore (node): the playlist after target pos, or null
277  */
278  movePlaylist: function(pguid, targetFolder, insertBefore){
279  playlistfolders.central.logEvent("servicepane", "Move Playlist " +
280  pguid + " to " +
281  targetFolder.id + ", before " +
282  (insertBefore ? insertBefore.id : ""), 5);
283  // Move the node(s) only, we'll keep track in preferences via listener
284  var SPS = Cc["@songbirdnest.com/servicepane/service;1"]
285  .getService(Ci.sbIServicePaneService);
286  targetFolder.insertBefore(SPS.getNode('urn:item:' + pguid), insertBefore);
287  },
288 
290  // sbIServicePaneMutationListener //
292 
293  attrModified: function(aNode, aAttrName, aNamespace, aOldVal, aNewVal){
294  // Check for opening / closing Nodes
295  if ((aNode.id.split("urn:folder").length > 1)&&(aAttrName == "isOpen")){
296  playlistfolders.central.logEvent("servicepane",
297  "Open/Closes State change: " +
298  aNode.id, 5);
299  var guid = aNode.id.split('urn:folder:')[1];
300  var folder = playlistfolders.preferences.getFolderByGUID(guid);
301  folder.closed = aNewVal == "false";
302  aNode.image = folder.closed ? "chrome://playlistfolders/skin/" +
303  "icon-folder-closed.png"
304  : "chrome://playlistfolders/skin/" +
305  "icon-folder.png";
306  }
307  },
308  nodeInserted: function(aNode, aParent, aInsertBefores){
309  // We're interested in new / moved Playlist nodes, to update our sort
310  if ((aNode.id.split("urn:item:").length > 1)){
311  playlistfolders.central.logEvent("servicepane",
312  "Moved Playlist node " + aNode.id, 5);
313  // Ensure the node accepts folders, if this is a new created node
314  this._ensureDND(aNode);
315  // Track movement in preference controller
316  var pguid = aNode.id.split("urn:item:")[1];
317  var tfolder = null;
318  if (aParent.id != "SB:Playlists"){
319  var tGUID = aParent.id.split('urn:folder:')[1];
320  tfolder = playlistfolders.preferences.getFolderByGUID(tGUID);
321  }
322  var bGUID = null;
323  if (aInsertBefores && (aInsertBefores.id.split('urn:item:').length > 1))
324  bGUID = aInsertBefores.id.split('urn:item:')[1];
325  if (aInsertBefores && (aInsertBefores.id.split('urn:folder:').length > 1))
326  bGUID = aInsertBefores.id.split('urn:folder:')[1];
327  playlistfolders.preferences.movePlaylist(pguid, tfolder, bGUID);
328  }
329  // We're interested in moved Folders, to update our sort
330  if ((aNode.id.split("urn:folder:").length > 1)){
331  playlistfolders.central.logEvent("servicepane",
332  "Moved Folder node " + aNode.id, 5);
333  // Track movement in preference controller
334  var fguid = aNode.id.split("urn:folder:")[1];
335  var tfolder = null;
336  if (aParent.id != "SB:Playlists"){
337  var tGUID = aParent.id.split('urn:folder:')[1];
338  tfolder = playlistfolders.preferences.getFolderByGUID(tGUID);
339  }
340  var bGUID = null;
341  if (aInsertBefores && (aInsertBefores.id.split('urn:item:').length > 1))
342  bGUID = aInsertBefores.id.split('urn:item:')[1];
343  if (aInsertBefores && (aInsertBefores.id.split('urn:folder:').length > 1))
344  bGUID = aInsertBefores.id.split('urn:folder:')[1];
345  var folder = playlistfolders.preferences.getFolderByGUID(fguid);
346  //alert("bGUID: " + bGUID + "\nID: " + aInsertBefores ? aInsertBefores.id : "(missing)");
347  playlistfolders.preferences.moveFolder(folder, tfolder, bGUID);
348  }
349  },
350  nodeRemoved: function(aNode, aParent){
351  // The only case we're interested for removed nodes is removing playlists
352  if (aNode.id.split("urn:item:").length <= 1)
353  return;
354  // We're interested in playlists inside folders only
355  if (aParent.id.split("urn:folder:").length <= 1)
356  return;
357  // Remove the playlist from the folder WITHOUT any central-delete stuff
358  var pGUID = aNode.id.split("urn:item:")[1];
359  var fGUID = aParent.id.split("urn:folder:")[1];
360  playlistfolders.preferences.removePlaylist(pGUID, fGUID);
361  },
362 };
const Cc
menuItem id
Definition: FeedWriter.js:971
getService(Ci.sbIFaceplateManager)
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
let window
Lastfm onLoad
Definition: mini.js:36
imageContainer removeChild(oldImage)
return null
Definition: FeedWriter.js:1143
function check(ch, cx)
let node
countRef value
Definition: FeedWriter.js:1423
const Cr
let promptService
const Ci
var gServicePane
Definition: mainWinInit.js:39
function onUnload()
onUnload - called when the cover preview window unloads.
Definition: coverPreview.js:36
sbDeviceServicePane prototype nodeInserted
sbDeviceServicePane prototype nodeRemoved