User Tools

Site Tools


developer_center:creating_media_views

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

developer_center:creating_media_views [2015/05/11 16:00] (current)
zjays created
Line 1: Line 1:
 +====== Creating Media Views ======
  
 +===== Introduction =====
 +
 +As of this writing, Nightingale ships with two default views: a simple traditional playlist view, and a second playlist view incorporating three filter panes across the top for choosing a subset of your music. ​ Views can be extended via extensions that implement Media Pages. ​ Developers can easily create new views as HTML pages or XUL pages which provide custom visual interfaces to Nightingale libraries, and playlists.
 +
 +===== How It Works =====
 +
 +When a media page is loaded, it is passed the current [[developer_center:​components:​media_library|MediaListView]]. This object is controlled by the page. Media pages are registered in an install.rdf file to work with media lists that have certain properties. For example, a media page can be set to support all media lists (the default), to target only media lists with a certain customtype (for example, "​download"​),​ or even to target a media list with a given GUID.
 +
 +Certain other operations will call methods on the sbIMediaPage interface, such as dropping a selection onto a media page, attempting to highlight the current track, or initiating playback. Most media pages will include a <​sb-playlist/>​ object which should be passed any calls you do not handle specially. ​ The default media page created by the extension wizard will do this by default.
 +
 +===== Creating Media Pages =====
 +
 +As usual, the [[:​add-ons#​nightingale_developer_tools|Nightingale Developer Tools Add-on]] greatly simplifies the process for developers. ​ Using the Extension Wizard (accessed via the Tools menu under //Create Extension...//​),​ you can create the skeleton/​framework for your media page quickly and easily. ​ The Extension Wizard takes care of setting up your install.rdf media page registration,​ and creating the basic "Hello World" media page.
 +
 +===== Registering A Media Page =====
 +
 +When creating a new media page, you must add a ''<​mediaPage>''​ block to the install.rdf for that extension. It must include a ''<​contentTitle/>''​ and a ''<​contentUrl/>''​ which define the title shown in the menu and the document to load. It may optionally also include any number of ''<​match/>''​ elements.
 +
 +==== Rules for Matching ====
 +
 +Because some media pages may be specific to certain kinds of playlists, you may provide any number of ''<​match/>''​ elements to target particular kinds of lists. You can target "​type",​ "​customtype"​ or any SBProperty of the MediaList within the view.
 +
 +=== Examples ===
 +
 +Match any "​simple"​ media list:
 +<code xml>
 +<​match>​type:​simple</​match>  ​
 +</​code>​
 +
 +Match only the downloads list:
 +<code xml>
 +<​match>​customtype:​downloads</​match>  ​
 +</​code>​
 +
 +Match simple media lists which have a custom property added by your extension:
 +<code xml>
 +<​match>​type:​simple myExtensionProperty:​someValue
 +</​code>  ​
 +
 +==== Opting Out ====
 +
 +Because media pages can come from many sources, we have provided a mechanism to allow extension developers to specify that a particular MediaList would like to "opt out" of the generic media lists and only support custom media lists specially targetting them.
 +
 +We have specified that any ''<​mediaPage>''​ rule which has no match rules, or any match rule which only targets the "​type"​ property of a media list can be excluded by setting the "​onlyCustomMediaPages"​ property of the list to true.
 +
 +=== Examples ===
 +
 +The example uses a mediaList with these properties:
 +mediaList.type == "​simple"​ && mediaList.customtype == "​downloads"​
 +
 +^ <​match/>​ rule ^ SBProperties.onlyCustomMediaPages ^ result ^ reason ^
 +| (none provided) | false | matches | matches all |
 +| (none provided) | true | does not match (opt-outable rule) | opted out |
 +| type:simple | false | matches | same type |
 +| type:simple | true | does not match (opt-outable rule) | opted out |
 +| customtype:​download | false | matches | same customtype |
 +| customtype:​download | true | matches (not opt-outable) | same customtype |
 +| type:simple ; customtype:​other | true/false | no match | does not match customtype |
 +
 +=== Multiple Match Rules ===
 +
 +If there are multiple ''<​match/>''​ rules, any rule which completely matches the list will cause the page to appear in the menu for that item.
 +
 +===== Implementing Media Pages =====
 +
 +Media pages can be implemented in either XUL or HTML.  The easier method, and the one covered here, is implementing them via XUL.  At its core, a media page is as simple as the following (as excerpted from the standard media-page.xul generated by the Extension Wizard)
 +
 +<code xml>
 +    <​page  ​
 +      id="​mymediapage-media-page"  ​
 +      title="​My Media Page"  ​
 +      xmlns:​html="​http://​www.w3.org/​1999/​xhtml"  ​
 +      xmlns:​rdf="​http://​www.w3.org/​TR/​WD-rdf-syntax#"  ​
 +      xmlns="​http://​www.mozilla.org/​keymaster/​gatekeeper/​there.is.only.xul"  ​
 +      onload="​window.mediaPage.onLoad();"  ​
 +      onunload="​window.mediaPage.onUnload();"  ​
 +      windowtype="​Songbird:​MediaPage"  ​
 +    >  ​
 +      <​sb-playlist id="​playlist" ​  
 +          flex="​1"  ​
 +          enableColumnDrag="​true"  ​
 +          persist="​column-list column-widths"  ​
 +          editable="​true"  ​
 +          hidefilters="​true"  ​
 +      />  ​
 +      ​
 +      ​
 +      <!-- Page Controller.  ​
 +           ​Registers a window.mediaPage object implementing the   
 +           ​sbIMediaPage interface.  ​
 +        -->  ​
 +      <script type="​application/​x-javascript"​ src="​media-page.js"​ />  ​
 +      ​
 +    </​page>  ​
 +</​code>​
 +
 +The above media page is a simple recreation of the standard playlist view.  You can see it defines a ''<​page/>''​ element of windowtype ''​Songbird:​MediaPage'',​ and adds onload & onunload handlers to call the media page registration. ​
 +
 +The media page should also define a ''​window.mediaPage''​ object which implements the [[http://​developer.getnightingale.com/​d8/​d8a/​interfacesb_i_media_page.html|sbIMediaPage interface]]. The above XUL implements this in the ''​media-page.js''​ file.  The three methods the media page should implement are ''​highlightItem()'',​ ''​canDrop()'',​ and ''​onDrop()''​ which implement the behaviour the media page should take when items are highlighted or dropped. ​
 +
 +''​highlightItem()''​ is called when the item should be highlighted,​ e.g. when the user clicks on the playing track in the faceplate to jump the playlist to the currently playing track.
 +
 +''​canDrop()''​ is called when something is dragged on top of the tabbrowser tab (note this is the tab selector underneath the web navigation bar)
 +
 +''​onDrop()''​ is called when something is actually dropped onto the tabbrowser tab.
 +
 +The following code is the media-page.js file referenced above:
 +
 +<code javascript>​
 +    // Shorthand  ​
 +    if (typeof(Cc) == "​undefined"​)  ​
 +      var Cc = Components.classes;  ​
 +    if (typeof(Ci) == "​undefined"​)  ​
 +      var Ci = Components.interfaces;  ​
 +    if (typeof(Cu) == "​undefined"​)  ​
 +      var Cu = Components.utils;  ​
 +    if (typeof(Cr) == "​undefined"​)  ​
 +      var Cr = Components.results;  ​
 +      ​
 +      ​
 +    /** 
 +     * Media Page Controller ​
 +     ​* ​
 +     * In order to display the contents of a library or list, pages 
 +     * must provide a "​window.mediaPage"​ object implementing ​
 +     * the Nightingale sbIMediaPage interface. This interface allows ​
 +     * the rest of Nightingale to talk to the page without knowledge  ​
 +     * of what the page looks like. 
 +     ​* ​
 +     * In this particular page most functionality is simply  ​
 +     * delegated to the sb-playlist widget. ​
 +     ​*/  ​
 +    window.mediaPage = {  ​
 +          ​
 +        // The sbIMediaListView that this page is to display  ​
 +      _mediaListView:​ null,  ​
 +          ​
 +        // The sb-playlist XBL binding  ​
 +      _playlist: null,   
 +          ​
 +        ​
 +      /​**  ​
 +       * Gets the sbIMediaListView that this page is displaying ​
 +       ​*/  ​
 +      get mediaListView() ​ {  ​
 +        return this._mediaListView;  ​
 +      },  ​
 +        ​
 +        ​
 +      /​**  ​
 +       * Set the sbIMediaListView that this page is to display. ​
 +       * Called in the capturing phase of window load by the Nightingale browser. ​
 +       * Note that to simplify page creation mediaListView may only be set once. 
 +       ​*/  ​
 +      set mediaListView(value) ​ {  ​
 +          ​
 +        if (!this._mediaListView) {  ​
 +          this._mediaListView = value;  ​
 +        } else {  ​
 +          throw new Error("​mediaListView may only be set once.  Please reload the page"​);  ​
 +        }  ​
 +      },  ​
 +          ​
 +          ​
 +      /​**  ​
 +       * Called when the page finishes loading. ​  
 +       * By this time window.mediaPage.mediaListView should have  ​
 +       * been externally set.   
 +       ​*/  ​
 +      onLoad: ​ function(e) {  ​
 +          ​
 +        // Make sure we have the javascript modules we&​apos;​re going to use  ​
 +        if (!window.SBProperties) ​  
 +          Cu.import("​resource://​app/​jsmodules/​sbProperties.jsm"​);  ​
 +        if (!window.LibraryUtils) ​  
 +          Cu.import("​resource://​app/​jsmodules/​sbLibraryUtils.jsm"​);  ​
 +        if (!window.kPlaylistCommands) ​  
 +          Cu.import("​resource://​app/​jsmodules/​kPlaylistCommands.jsm"​);  ​
 +          ​
 +        if (!this._mediaListView) {  ​
 +          Components.utils.reportError("​Media Page did not receive ​ " +   
 +                                       "​a mediaListView before the onload event!"​);  ​
 +          return;  ​
 +        }   
 +          ​
 +        this._playlist = document.getElementById("​playlist"​);  ​
 +          ​
 +        //  ​
 +        // TODO: Do something interesting here!  ​
 +        //  ​
 +          ​
 +        // Get playlist commands (context menu, keyboard shortcuts, toolbar)  ​
 +        // Note: playlist commands currently depend on the playlist widget.  ​
 +        var mgr =  ​
 +          Components.classes["​@songbirdnest.com/​Songbird/​PlaylistCommandsManager;​1"​]  ​
 +                    .createInstance(Components.interfaces.sbIPlaylistCommandsManager);  ​
 +        var cmds = mgr.request(kPlaylistCommands.MEDIAITEM_DEFAULT);  ​
 +          ​
 +        // Set up the playlist widget  ​
 +        this._playlist.bind(this._mediaListView,​ cmds);  ​
 +      },  ​
 +          ​
 +          ​
 +      /​**  ​
 +       * Called as the window is about to unload ​
 +       ​*/  ​
 +      onUnload: ​ function(e) {  ​
 +        if (this._playlist) {  ​
 +          this._playlist.destroy();  ​
 +          this._playlist = null;  ​
 +        }  ​
 +      },  ​
 +          ​
 +        ​
 +      /​**  ​
 +       * Show/​highlight the MediaItem at the given MediaListView index. ​
 +       * Called by the Find Current Track button. ​
 +       ​*/  ​
 +      highlightItem:​ function(aIndex) {  ​
 +        this._playlist.highlightItem(aIndex);  ​
 +      },  ​
 +          ​
 +        ​
 +      /​**  ​
 +       * Called when something is dragged over the tabbrowser tab for this window ​
 +       ​*/  ​
 +      canDrop: function(aEvent,​ aSession) {  ​
 +        return this._playlist.canDrop(aEvent,​ aSession);  ​
 +      },  ​
 +          ​
 +        ​
 +      /​**  ​
 +       * Called when something is dropped on the tabbrowser tab for this window ​
 +       ​*/  ​
 +      onDrop: function(aEvent,​ aSession) {  ​
 +        return this._playlist.  ​
 +            _dropOnTree(this._playlist.mediaListView.length,  ​
 +                    Ci.sbIMediaListViewTreeViewObserver.DROP_AFTER);  ​
 +      }  ​
 +          ​
 +            ​
 +    } // End window.mediaPage ​
 +</​code>​
developer_center/creating_media_views.txt ยท Last modified: 2015/05/11 16:00 by zjays