User Tools

Site Tools

A PCRE internal error occured. This might be caused by a faulty plugin

developer_center:creating_media_views

====== 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