myk%mozilla.org 73d8d37869 Fix for bug 302121: Implements feedview feature for better display of RSS and Atom feed files. r=mconnor, approval1.8b4+=mconnor
git-svn-id: svn://10.0.0.236/trunk@176953 18797224-902f-48f8-a5cc-f745e15eee43
2005-08-02 03:29:11 +00:00

201 lines
8.0 KiB
JavaScript

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Feedview for Firefox.
*
* The Initial Developer of the Original Code is
* Tom Germeau <tom.germeau@epigoon.com>.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var gFeedviewPrefs;
// The values to which these variables are initialized are just backups
// in case we can't get the actual values from the prefs service.
var gFeedviewPrefArticleLength = 50;
var gFeedviewPrefShowBar = true;
var gFeedviewPrefShowImage = true;
var gFeedviewPrefTimerInterval = 0;
var gFeedviewPrefExternalCSS = "";
var gFeedviewProcessor;
var gFeedviewStylesheet;
function initFeedview() {
try {
gFeedviewPrefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch("browser.feedview.");
gFeedviewPrefArticleLength = gFeedviewPrefs.getIntPref("articleLength");
gFeedviewPrefShowBar = gFeedviewPrefs.getBoolPref("showBar");
gFeedviewPrefShowImage = gFeedviewPrefs.getBoolPref("showImage");
gFeedviewPrefTimerInterval = gFeedviewPrefs.getIntPref("timerInterval");
gFeedviewPrefExternalCSS = gFeedviewPrefs.getCharPref("externalCSS");
}
catch (ex) {}
gFeedviewProcessor = new XSLTProcessor();
gFeedviewStylesheet = document.implementation.createDocument("", "", null);
gFeedviewStylesheet.addEventListener("load", onLoadFeedviewStylesheet, false);
gFeedviewStylesheet.load("chrome://browser/content/feedview/feedview.xsl");
window.addEventListener("load", maybeLoadFeedview, true);
}
function onLoadFeedviewStylesheet() {
gFeedviewProcessor.importStylesheet(gFeedviewStylesheet);
}
function feedviewIsFeed(doc) {
const ATOM_10_NS = "http://www.w3.org/2005/Atom";
const ATOM_03_NS = "http://purl.org/atom/ns#";
const RSS_10_NS = "http://purl.org/rss/1.0/";
const RSS_09_NS = "http://my.netscape.com/rdf/simple/0.9/";
const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
var rootName = doc.localName;
var rootNS = doc.namespaceURI;
var channel;
// Atom feeds have a root "feed" element in one of two namespaces.
if (rootName == "feed" && (rootNS == ATOM_10_NS || rootNS == ATOM_03_NS))
return true;
// RSS 2.0, 0.92, and 0.91 feeds have a non-namespaced root "rss" element
// containing a non-namespaced "channel" child.
else if (rootName == "rss" && rootNS == null) {
channel = doc.getElementsByTagName('channel')[0];
if (channel && channel.parentNode == doc)
return true;
}
// RSS 1.0 and 0.9 feeds have a root "RDF" element in the RDF namespace
// and a "channel" child in the RSS 1.0 or 0.9 namespaces.
else if (rootName == "RDF" && rootNS == RDF_NS) {
channel = doc.getElementsByTagNameNS(RSS_10_NS, 'channel')[0]
|| doc.getElementsByTagNameNS(RSS_09_NS, 'channel')[0];
if (channel && channel.parentNode == doc)
return true;
}
// If it didn't match any criteria yet, it's probably not a feed,
// or perhaps it's a nonconformist feed. If you see a number of those
// and they match some pattern, add a check for that pattern here,
// making sure to specify the strictest check that matches that pattern
// to minimize false positives.
return false;
}
// Checks every document to see if it's a feed file, and transforms it if so.
function maybeLoadFeedview(evnt) {
// See if the document is XML. If not, it's definitely not a feed.
if (!(evnt.originalTarget instanceof XMLDocument))
return;
var dataXML = evnt.originalTarget;
// Make sure the document is loaded into one of the browser tabs.
// Otherwise, it might have been loaded as data by some application
// that expects it not to change, and we shouldn't break the app
// by changing the document.
var browser;
var browsers = document.getElementById('content').browsers;
for (var i = 0; i < browsers.length; i++) {
if (dataXML == browsers[i].contentDocument) {
browser = browsers[i];
break;
}
}
if (!browser)
return;
// See if the document we're dealing with is actually a feed.
if (!feedviewIsFeed(dataXML.documentElement))
return;
var ownerDocument = document.implementation.createDocument("", "", null);
var strbundle=document.getElementById("bundle_feedview");
gFeedviewProcessor.setParameter(null, "feedUrl", evnt.originalTarget.documentURI);
gFeedviewProcessor.setParameter(null, "feedTitle", strbundle.getString("title") );
// XXX This should be in a DTD.
gFeedviewProcessor.setParameter(null, "lengthSliderLabel", strbundle.getString("lengthSliderLabel"));
// XXX These are static values. Can I set them once and have the processor
// apply them every time I use it to transform a document?
gFeedviewProcessor.setParameter(null, "articleLength", gFeedviewPrefArticleLength);
gFeedviewProcessor.setParameter(null, "showBar", gFeedviewPrefShowBar);
gFeedviewProcessor.setParameter(null, "showImage", gFeedviewPrefShowImage);
gFeedviewProcessor.setParameter(null, "timerInterval", gFeedviewPrefTimerInterval);
gFeedviewProcessor.setParameter(null, "externalCSS", gFeedviewPrefExternalCSS );
// Get the length and give it to the description thingie.
var len = dataXML.getElementsByTagName("item").length;
if (len == 0)
len = dataXML.getElementsByTagName("entry").length;
gFeedviewProcessor.setParameter(null, "feedDescription", strbundle.getFormattedString("description", [len] ) );
var newFragment = gFeedviewProcessor.transformToFragment(dataXML, ownerDocument);
var oldLink = dataXML.documentElement.firstChild;
// XXX: it would be better if we could replace the documentElement..
// now the rdf/rss/feed tag remains , NOT good
dataXML.documentElement.replaceChild(newFragment, oldLink);
oldLink = dataXML.documentElement.firstChild.nextSibling;
// Kill all other child elements of the document element
// so only our transformed feed remains.
while (oldLink != null) {
oldLinkX = oldLink.nextSibling;
if (oldLinkX != null)
dataXML.documentElement.removeChild(oldLink);
oldLink = oldLinkX;
}
// Watch the article length slider so we can update the corresponding pref
// when it changes.
var slider = dataXML.getElementById('lengthSlider');
slider.addEventListener("mouseclick", updateFeedviewPrefArticleLength, false);
slider.addEventListener("mouseup", updateFeedviewPrefArticleLength, false);
}
function updateFeedviewPrefArticleLength(event) {
if (gFeedviewPrefArticleLength != event.target.getAttribute("curpos")) {
gFeedviewPrefArticleLength = event.target.getAttribute("curpos");
gFeedviewPrefs.setIntPref("articleLength", gFeedviewPrefArticleLength);
}
}