303848 - integrate feedview better with firefox browser code/live bookmarking system.

this is an initial stab at implementing a design I'm working on with Mike Beltzner
here: http://wiki.mozilla.org/Firefox:1.1_RSS_Pretty_Print


git-svn-id: svn://10.0.0.236/trunk@177609 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ben%bengoodger.com 2005-08-12 00:34:19 +00:00
parent 0e71db2146
commit 73c66a13c6
29 changed files with 1095 additions and 1392 deletions

View File

@ -47,7 +47,7 @@ static const nsXREAppData kAppData = {
sizeof(nsXREAppData),
nsnull,
"Mozilla",
"Firefox",
"Firefox RSS",
NS_STRINGIFY(APP_VERSION),
NS_STRINGIFY(BUILD_ID),
"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",

View File

@ -34,6 +34,7 @@
# Jason Barnabe <jason_barnabe@fastmail.fm>
# Peter Parente <parente@cs.unc.edu>
# Giorgio Maone <g.maone@informaction.com>
# Tom Germeau <tom.germeau@epigoon.com>
#
# 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
@ -71,7 +72,6 @@ var gRDF = null;
var gGlobalHistory = null;
var gURIFixup = null;
var gPageStyleButton = null;
var gLivemarksButton = null;
var gCharsetMenu = null;
var gLastBrowserCharset = null;
var gPrevCharset = null;
@ -123,7 +123,7 @@ function pageShowEventHandlers(event)
#ifdef ALTSS_ICON
updatePageStyles();
#endif
updatePageLivemarks();
FeedHandler.updateFeeds();
}
// some event handlers want to be told what the original browser/listener is
@ -198,6 +198,36 @@ const gSessionHistoryObserver = {
}
};
/**
* Given a starting docshell and a URI to look up, find the docshell the URI
* is loaded in.
* @param aDocument
* A document to find instead of using just a URI - this is more specific.
* @param aDocShell
* The doc shell to start at
* @param aSoughtURI
* The URI that we're looking for
* @returns The doc shell that the sought URI is loaded in. Can be in
* subframes.
*/
function findChildShell(aDocument, aDocShell, aSoughtURI) {
aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation);
aDocShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var doc = aDocShell.getInterface(Components.interfaces.nsIDOMDocument);
if ((aDocument && doc == aDocument) &&
aDocShell.currentURI.spec == aSoughtURI.spec)
return aDocShell;
var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
for (var i = 0; i < node.childCount; ++i) {
var docShell = node.getChildAt(i);
docShell = findChildShell(aDocument, docShell, aSoughtURI);
if (docShell)
return docShell;
}
return null;
}
const gPopupBlockerObserver = {
_reportButton: null,
_kIPM: Components.interfaces.nsIPermissionManager,
@ -322,22 +352,6 @@ const gPopupBlockerObserver = {
blockedPopupDontShowMessage.setAttribute("label", bundle_browser.getString("popupWarningDontShowFromStatusbar"));
},
_findChildShell: function (aDocShell, aSoughtURI)
{
var webNav = aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation);
if (webNav.currentURI.spec == aSoughtURI.spec)
return aDocShell;
var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
for (var i = 0; i < node.childCount; ++i) {
var docShell = node.getChildAt(i);
docShell = this._findChildShell(docShell, aSoughtURI);
if (docShell)
return docShell;
}
return null;
},
showBlockedPopup: function (aEvent)
{
var requestingWindow = aEvent.target.getAttribute("requestingWindowURI");
@ -349,8 +363,8 @@ const gPopupBlockerObserver = {
var popupWindowURI = aEvent.target.getAttribute("popupWindowURI");
var features = aEvent.target.getAttribute("popupWindowFeatures");
var shell = this._findChildShell(gBrowser.selectedBrowser.docShell,
requestingWindowURI);
var shell = findChildShell(null, gBrowser.selectedBrowser.docShell,
requestingWindowURI);
if (shell) {
var ifr = shell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var dwi = ifr.getInterface(Components.interfaces.nsIDOMWindowInternal);
@ -412,28 +426,13 @@ const gPopupBlockerObserver = {
};
const gXPInstallObserver = {
_findChildShell: function (aDocShell, aSoughtShell)
{
if (aDocShell == aSoughtShell)
return aDocShell;
var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
for (var i = 0; i < node.childCount; ++i) {
var docShell = node.getChildAt(i);
docShell = this._findChildShell(docShell, aSoughtShell);
if (docShell == aSoughtShell)
return docShell;
}
return null;
},
_getBrowser: function (aDocShell)
{
var tabbrowser = getBrowser();
for (var i = 0; i < tabbrowser.browsers.length; ++i) {
var browser = tabbrowser.getBrowserAtIndex(i);
var soughtShell = aDocShell;
var shell = this._findChildShell(browser.docShell, soughtShell);
var shell = findChildShell(null, browser.docShell, soughtShell);
if (shell)
return browser;
}
@ -661,7 +660,6 @@ function prepareForStartup()
gNavigatorBundle = document.getElementById("bundle_browser");
gProgressMeterPanel = document.getElementById("statusbar-progresspanel");
gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
gBrowser.addEventListener("DOMLinkAdded", livemarkOnLinkAdded, false);
gBrowser.addEventListener("PluginNotFound", gMissingPluginInstaller.newMissingPlugin, false);
gBrowser.addEventListener("NewTab", BrowserOpenTab, false);
@ -886,8 +884,7 @@ function delayedStartup()
document.getElementById("textfieldDirection-swap").hidden = false;
}
// Prepare to load feedview for feed files.
initFeedview();
FeedHandler.init();
}
function BrowserShutdown()
@ -933,6 +930,7 @@ function BrowserShutdown()
gSanitizeListener.shutdown();
BrowserOffline.uninit();
FeedHandler.uninit();
uninitFindBar();
@ -3443,7 +3441,7 @@ nsBrowserStatusHandler.prototype =
//fix bug 271359 - reset mFavIconURL
getBrowser().selectedBrowser.mFavIconURL = null;
setTimeout(function () { updatePageLivemarks(); }, 0);
setTimeout(function () { FeedHandler.updateFeeds(); }, 0);
#ifdef ALTSS_ICON
setTimeout(function () { updatePageStyles(); }, 0);
#endif
@ -3507,8 +3505,8 @@ nsBrowserStatusHandler.prototype =
// (so we keep it while switching tabs after failed load
getBrowser().userTypedClear = true;
// clear out livemark data
gBrowser.mCurrentBrowser.livemarkLinks = null;
// clear out feed data
gBrowser.mCurrentBrowser.feeds = null;
const nsIChannel = Components.interfaces.nsIChannel;
var urlStr = aRequest.QueryInterface(nsIChannel).URI.spec;
@ -5692,137 +5690,8 @@ function AddKeywordForSearchField()
BROWSER_ADD_BM_FEATURES, dialogArgs);
}
/////////////// livemark handling
// XXX this event listener can/should probably be combined with the onLinkAdded
// listener in tabbrowser.xml, which only listens for favicons and then passes
// them to onLinkIconAvailable in the ProgressListener. We could extend the
// progress listener to have a generic onLinkAvailable and have tabbrowser pass
// along all events. It should give us the browser for the tab, as well as
// the actual event.
function livemarkOnLinkAdded(event)
{
if (!gLivemarksButton)
gLivemarksButton = document.getElementById("livemark-button");
// from tabbrowser.xml
// mechanism for reading properties of the underlying XPCOM object
// (ignoring potential getters/setters added by malicious content)
var safeGetProperty = function(obj, propname) {
return obj[propname];
}
var erel = event.target.rel;
var etype = event.target.type;
var etitle = event.target.title;
// this is a blogger post service URL; so skip it
if (erel && erel == "service.post")
return;
if (etype == "application/rss+xml" ||
etype == "application/atom+xml" ||
etype == "application/x.atom+xml" ||
etitle.indexOf("RSS") != -1 ||
etitle.indexOf("Atom") != -1 ||
etitle.indexOf("rss") != -1)
{
const targetDoc = safeGetProperty(event.target, "ownerDocument");
// find which tab this is for, and set the attribute on the browser
// should there be a getTabForDocument method on tabbedbrowser?
var browserForLink = null;
if (gBrowser.mTabbedMode) {
var browserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
if (browserIndex == -1)
return;
browserForLink = gBrowser.getBrowserAtIndex(browserIndex);
} else if (gBrowser.mCurrentBrowser.contentDocument == targetDoc) {
browserForLink = gBrowser.mCurrentBrowser;
}
if (!browserForLink) {
// ??? this really shouldn't happen..
return;
}
var livemarkLinks = [];
if (browserForLink.livemarkLinks != null) {
livemarkLinks = browserForLink.livemarkLinks;
}
var wrapper = event.target;
livemarkLinks.push({ href: wrapper.href,
type: wrapper.type,
title: wrapper.title});
browserForLink.livemarkLinks = livemarkLinks;
if (browserForLink == gBrowser || browserForLink == gBrowser.mCurrentBrowser)
gLivemarksButton.setAttribute("livemarks", "true");
}
}
// this is called both from onload and also whenever the user
// switches tabs; we update whether we show or hide the livemark
// button based on whether the window has livemarks set.
function updatePageLivemarks()
{
if (!gLivemarksButton)
gLivemarksButton = document.getElementById("livemark-button");
var livemarkLinks = gBrowser.mCurrentBrowser.livemarkLinks;
if (!livemarkLinks || livemarkLinks.length == 0) {
gLivemarksButton.removeAttribute("livemarks");
gLivemarksButton.setAttribute("tooltiptext", gNavigatorBundle.getString("livemarkNoLivemarksTooltip"));
} else {
gLivemarksButton.setAttribute("livemarks", "true");
gLivemarksButton.setAttribute("tooltiptext", gNavigatorBundle.getString("livemarkHasLivemarksTooltip"));
}
}
function livemarkFillPopup(menuPopup)
{
var livemarkLinks = gBrowser.mCurrentBrowser.livemarkLinks;
if (livemarkLinks == null) {
// XXX hack -- menu opening depends on setting of an "open"
// attribute, and the menu refuses to open if that attribute is
// set (because it thinks it's already open). onpopupshowing gets
// called after the attribute is unset, and it doesn't get unset
// if we return false. so we unset it here; otherwise, the menu
// refuses to work past this point.
menuPopup.parentNode.removeAttribute("open");
return false;
}
while (menuPopup.firstChild) {
menuPopup.removeChild(menuPopup.firstChild);
}
for (var i = 0; i < livemarkLinks.length; i++) {
var markinfo = livemarkLinks[i];
var menuItem = document.createElement("menuitem");
var baseTitle = markinfo.title || markinfo.href;
var labelStr = gNavigatorBundle.getFormattedString("livemarkSubscribeTo", [baseTitle]);
menuItem.setAttribute("label", labelStr);
menuItem.setAttribute("data", markinfo.href);
menuItem.setAttribute("tooltiptext", markinfo.href);
menuPopup.appendChild(menuItem);
}
return true;
}
function livemarkAddMark(wincontent, data) {
var title = wincontent.document.title;
var description = BookmarksUtils.getDescriptionFromDocument(wincontent.document);
BookmarksUtils.addLivemark(wincontent.document.baseURI, data, title, description);
}
function SwitchDocumentDirection(aWindow) {
aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
for (var run = 0; run < aWindow.frames.length; run++)
SwitchDocumentDirection(aWindow.frames[run]);
}
@ -5931,7 +5800,7 @@ missingPluginInstaller.prototype.observe = function(aSubject, aTopic, aData){
}
}
var gMissingPluginInstaller = new missingPluginInstaller();
function convertFromUnicode(charset, str)
{
try {
@ -5945,3 +5814,449 @@ function convertFromUnicode(charset, str)
return null;
}
}
/**
* The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
* and shows UI when they are discovered. It is also responsible for
* transforming XML feeds into a human-readable form when they are loaded.
*/
const kFeedHandler_Stylesheet =
"chrome://browser/content/feedview.xsl";
var FeedHandler = {
/**
* The Feed icon in the location bar
*/
_feedButton: null,
/**
* The XSLT Processor used to do feed transformation
*/
_processor: null,
/**
* The XSLT Stylesheet used to transform feeds
*/
_stylesheet: null,
/**
* Initialize the Pretty Print mode, adding page load event listeners to
* check for and load the pretty print view if a feed is loaded.
*/
init: function() {
var self = this;
function onPageLoad(event) {
self._checkForFeed(event);
}
addEventListener("load", onPageLoad, true);
gBrowser.addEventListener("DOMLinkAdded",
function (event) { FeedHandler.onLinkAdded(event); },
false);
},
/**
* Release held objects to prevent leaks.
*/
uninit: function() {
this._processor = null;
this._stylesheet = null;
},
/**
* Called when the user clicks on the Feed icon in the location bar.
* Builds a menu of unique feeds associated with the page, and if there
* is only one, shows the feed inline in the browser window.
* @param event
* The popupshowing event from the feed list menupopup
* @returns true if the menu should be shown, false if there was only
* one feed and the feed should be shown inline in the browser
* window (do not show the menupopup).
*/
buildFeedList: function(event) {
var menuPopup = event.target;
var feeds = gBrowser.selectedBrowser.feeds;
if (feeds == null) {
// XXX hack -- menu opening depends on setting of an "open"
// attribute, and the menu refuses to open if that attribute is
// set (because it thinks it's already open). onpopupshowing gets
// called after the attribute is unset, and it doesn't get unset
// if we return false. so we unset it here; otherwise, the menu
// refuses to work past this point.
menuPopup.parentNode.removeAttribute("open");
return false;
}
while (menuPopup.firstChild)
menuPopup.removeChild(menuPopup.firstChild);
/**
* Attempt to generate a list of unique feeds from the list of feeds
* supplied by the web page. It is fairly common for a site to supply
* feeds in multiple formats but with divergent |title| attributes so
* we need to make a rough pass at trying to not show a menu when there
* is in fact only one feed
* @param feeds
* An array of Feed info JS Objects representing the list of
* feeds advertised by the web page
* @returns An array of what should be mostly unique feeds.
*
* Note: we should consider extending HTML in some way here to allow
* pages to give "names" to <link> tags so that multiple tags can
* be identified as pointing to the same content.
*/
function harvestFeeds(feeds) {
var feedHash = { };
for (var i = 0; i < feeds.length; ++i) {
var feed = feeds[i];
if (!(feed.type in feedHash))
feedHash[feed.type] = [];
feedHash[feed.type].push(feed);
}
var mismatch = false;
var count = 0;
var defaultType = null;
for (var type in feedHash) {
// The default type is whichever is listed first on the web page.
// Nothing fancy, just something that works.
if (!defaultType) {
defaultType = type;
count = feedHash[type].length;
}
if (feedHash[type].length != count) {
mismatch = true;
break;
}
count = feedHash[type].length;
}
// There are more feeds of one type than another - this implies the
// content developer is supplying multiple channels, let's not do
// anything fancier than this and just return the full set.
if (mismatch)
return feeds;
// Return all the feeds for the selected type.
return feedHash[defaultType];
}
// Get the list of unique feeds, and if there's only one unique entry,
// show the feed in the browser rather than displaying a menu.
var feeds = harvestFeeds(feeds);
if (feeds.length == 1) {
this.showFeed(feeds[0].href);
return false;
}
// Build the menu showing the available feed choices for viewing.
for (var i = 0; i < feeds.length; ++i) {
var feedInfo = feeds[i];
var menuItem = document.createElement("menuitem");
var baseTitle = feedInfo.title || feedInfo.href;
var labelStr = gNavigatorBundle.getFormattedString("feedShowFeed", [baseTitle]);
menuItem.setAttribute("label", labelStr);
menuItem.setAttribute("feed", feedInfo.href);
menuItem.setAttribute("tooltiptext", feedInfo.href);
menuPopup.appendChild(menuItem);
}
return true;
},
/**
* Adds a Live Bookmark to a feed
* @param event
* The click/command event handler fired by a piece of UI that
* contains metadata about the feed to add a Live Bookmark to.
*/
addLiveBookmark: function(event) {
var a = event.target;
var title = a.ownerDocument.title;
var description = BookmarksUtils.getDescriptionFromDocument(a.ownerDocument);
BookmarksUtils.addLivemark(a.ownerDocument.baseURI, a.getAttribute("feed"),
title, description);
},
/**
* Shows a feed in the content area, pretty printed with the stylesheet.
* @param url
* The URL to the RSS feed
*/
showFeed: function(url) {
// If there's only one feed, load it and don't show the popup.
getWebNavigation().loadURI(url, nsIWebNavigation.LOAD_FLAGS_NONE,
null, null, null);
setTimeout(function () { gBrowser.selectedBrowser.focus(); }, 100);
},
/**
* Update the browser UI to show whether or not feeds are available when
* a page is loaded or the user switches tabs to a page that has feeds.
*/
updateFeeds: function() {
if (!this._feedButton)
this._feedButton = document.getElementById("feed-button");
var feeds = gBrowser.mCurrentBrowser.feeds;
if (!feeds || feeds.length == 0) {
this._feedButton.removeAttribute("feeds");
this._feedButton.setAttribute("tooltiptext",
gNavigatorBundle.getString("feedNoFeeds"));
} else {
this._feedButton.setAttribute("feeds", "true");
this._feedButton.setAttribute("tooltiptext",
gNavigatorBundle.getString("feedHasFeeds"));
}
},
/**
* A new <link> tag has been discovered - check to see if it advertises
* an RSS feed.
*/
onLinkAdded: function(event) {
// XXX this event listener can/should probably be combined with the onLinkAdded
// listener in tabbrowser.xml, which only listens for favicons and then passes
// them to onLinkIconAvailable in the ProgressListener. We could extend the
// progress listener to have a generic onLinkAvailable and have tabbrowser pass
// along all events. It should give us the browser for the tab, as well as
// the actual event.
if (!this._feedButton)
this._feedButton = document.getElementById("feed-button");
// from tabbrowser.xml
// mechanism for reading properties of the underlying XPCOM object
// (ignoring potential getters/setters added by malicious content)
var safeGetProperty = function(obj, propname) {
return obj[propname];
}
var erel = event.target.rel;
var etype = event.target.type;
var etitle = event.target.title;
// this is a blogger post service URL; so skip it
if (erel && erel == "service.post")
return;
if (etype == "application/rss+xml" ||
etype == "application/atom+xml" ||
etype == "application/x.atom+xml" ||
(etitle &&
(etitle.indexOf("RSS") != -1 ||
etitle.indexOf("Atom") != -1 ||
etitle.indexOf("rss") != -1)))
{
const targetDoc = safeGetProperty(event.target, "ownerDocument");
// find which tab this is for, and set the attribute on the browser
// should there be a getTabForDocument method on tabbedbrowser?
var feedURI =
Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService).
newURI(targetDoc.location.href, null, null);
var shellInfo = this._getContentShell(targetDoc, feedURI);
var browserForLink = shellInfo.browser;
if (!browserForLink) {
// ??? this really shouldn't happen..
return;
}
var feeds = [];
if (browserForLink.feeds != null)
feeds = browserForLink.feeds;
var wrapper = event.target;
feeds.push({ href: wrapper.href,
type: wrapper.type,
title: wrapper.title});
browserForLink.feeds = feeds;
if (browserForLink == gBrowser || browserForLink == gBrowser.mCurrentBrowser)
this._feedButton.setAttribute("feeds", "true");
}
},
/**
* Locate the shell that has a specified URI loaded in it.
* @param doc
* The document that contains the feed
* @param feedURI
* The URI to locate a shell for
* @returns The doc shell that contains the specified URI
*/
_getContentShell: function(doc, feedURI) {
var browsers = getBrowser().browsers;
for (var i = 0; i < browsers.length; i++) {
var shell = findChildShell(doc, browsers[i].docShell, feedURI);
if (shell)
return { shell: shell, browser: browsers[i] };
}
return null;
},
/**
* Validate the document to see if it is a feed we should pretty print or
* not.
* @param doc
* The document to inspect
* @returns true if this is an RSS feed we should pretty print, false
* otherwise.
*/
_validate: function(doc) {
// See if the document is XML. If not, it's definitely not a feed.
if (!(doc instanceof XMLDocument))
return false;
// See if the document we're dealing with is actually a feed.
if (!this._isDocumentFeed(doc.documentElement))
return false;
// 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 feedURI =
Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService).
newURI(doc.location.href, null, null);
if (!this._getContentShell(doc, feedURI))
return false;
return true;
},
/**
* Loads the Pretty Print if necessary for the current document.
* @param event
* The "load" DOM event
*/
_checkForFeed: function(event) {
var doc = event.originalTarget;
if (!this._validate(doc))
return;
var self = this;
/**
* Called back once we're guaranteed that an XSLT Processor has been
* created and the transformation stylesheet loaded and ready for use.
* Does the work of translating the RSS feed into the output document.
* @param processor
* The XSLT Processor, initialized with the pretty print
* stylesheet
*/
function transformFeed(processor) {
var strings = document.getElementById("bundle_browser");
processor.setParameter(null, "url", doc.documentURI);
processor.setParameter(null, "title",
strings.getFormattedString("feedTitle", [""]));
/**
* @returns the number of articles in the feed
*/
function getArticleCount() {
var len = doc.getElementsByTagName("item").length;
if (len == 0)
len = doc.getElementsByTagName("entry").length;
return len;
}
processor.setParameter(null, "articleCount",
strings.getFormattedString("feedDescription",
[getArticleCount()]));
processor.setParameter(null, "showMenu", true);
processor.setParameter(null, "reloadInterval", 30);
processor.setParameter(null, "addLiveBookmarkLink",
strings.getString("feedAddLiveBookmarkLink"));
var regionStrings = document.getElementById("bundle_browser_region");
processor.setParameter(null, "liveBookmarkInfoURL",
regionStrings.getString("feedLiveBookmarkInfoURL"));
processor.setParameter(null, "liveBookmarkInfoText",
strings.getString("feedLiveBookmarkInfoText"));
var ownerDocument = document.implementation.createDocument("", "", null);
var newFragment = processor.transformToFragment(doc, ownerDocument);
var de = doc.documentElement;
while (de.hasChildNodes())
de.removeChild(de.firstChild);
de.appendChild(newFragment);
// Update the title bar with the title of the feed.
var h1s = doc.getElementsByTagName("h1");
if (h1s.length)
doc.title = strings.getFormattedString("feedTitle", [h1s[0].textContent]);
doc.getElementById("addLiveBookmarkLink").addEventListener("click",
function (event) { self.addLiveBookmark(event); }, false);
}
this._process(transformFeed);
},
/**
* Invoke the tranformation routine on the specified callback, once we've
* lazily instantiated and loaded the XSLTProcessor and stylesheet.
* @param callback
* A function to be called when the processor and stylesheet are
* ready for use.
*/
_process: function(callback) {
var async = false;
if (!this._processor) {
this._processor = new XSLTProcessor();
}
if (!this._stylesheet) {
this._stylesheet = document.implementation.createDocument("", "", null);
var processor = this._processor;
var stylesheet = this._stylesheet;
function onStyleSheetLoaded() {
processor.importStylesheet(stylesheet);
callback(processor);
}
this._stylesheet.addEventListener("load", onStyleSheetLoaded, false);
this._stylesheet.load(kFeedHandler_Stylesheet);
async = true;
}
if (!async)
callback(this._processor);
},
/**
* Determines if a DOM document is an RSS/ATOM feed or not.
* @param doc
* The DOM document to test
* @returns true if the document is a feed, false otherwise.
*/
_isDocumentFeed: function(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;
},
};

View File

@ -71,14 +71,11 @@
#include global-scripts.inc
<script type="application/x-javascript" src="chrome://global/content/contentAreaUtils.js"/>
<script type="application/x-javascript" src="chrome://browser/content/feedview/feedviewOverlay.js"/>
# All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
# browser-sets.inc file for sharing with hiddenWindow.xul.
#include browser-sets.inc
<stringbundle id="bundle_feedview" src="chrome://browser/locale/feedview.properties"/>
<popupset id="mainPopupSet">
<popup id="backMenu"
position="after_start"
@ -210,8 +207,7 @@
ontextreverted="return handleURLBarRevert();"
onfocus="URLBarFocusHandler(event, this);"
onmousedown="URLBarMouseDownHandler(event, this);"
onclick="URLBarClickHandler(event, this);"
oninfoclick="displaySecurityInfo();">
onclick="URLBarClickHandler(event, this);">
<deck id="page-proxy-deck" onclick="PageProxyClickHandler(event);">
<image id="page-proxy-button"
ondraggesture="PageProxyDragGesture(event);"
@ -226,6 +222,13 @@
this.parentNode.selectedIndex = 0;"
tooltiptext="&proxyIcon.tooltip;"/>
</deck>
<hbox>
<button type="menu" class="plain" id="feed-button" chromedir="&locale.dir;">
<menupopup onpopupshowing="return FeedHandler.buildFeedList(event);" position="after_end"
oncommand="FeedHandler.showFeed(event.target.getAttribute('feed'));" />
</button>
<image id="lock-icon" onclick="displaySecurityInfo()"/>
</hbox>
</textbox>
</toolbaritem>
@ -465,10 +468,6 @@
</menupopup>
</statusbarpanel>
#endif
<statusbarpanel id="livemark-button" type="menu" class="statusbarpanel-menu-iconic" chromedir="&locale.dir;">
<menupopup onpopupshowing="return livemarkFillPopup(this);"
oncommand="livemarkAddMark(window.content, event.target.getAttribute('data'));" />
</statusbarpanel>
</statusbar>
</window>

View File

@ -0,0 +1,127 @@
/* ***** 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):
* Ben Goodger <ben@mozilla.org>
*
* 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 FeedView = {
/**
* Attempt to get a JavaScript Date object from a string
* @param str
* A string that may contain a formatted date
* @returns A JavaScript Date object representing the date
*/
_xmlDate: function(str) {
str = str.replace("Z", "+00:00");
var d = str.replace(/^(\d{4})-(\d\d)-(\d\d)T([0-9:]*)([.0-9]*)(.)(\d\d):(\d\d)$/, '$1/$2/$3 $4 $6$7$8');
d = Date.parse(d);
d += 1000 * RegExp.$5;
return new Date(d);
},
/**
* Normalizes date strings embedded in the feed into a common format.
*/
_initializeDates: function() {
// Normalize date formatting for all feed entries
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
var d = divs[i].getAttribute("date");
dump("*** D = " + d + "\n");
if (d) {
// If it is an RFC... date -> first parse it...
// otherwise try the Date() constructor.
d = d.indexOf("T") ? xmlDate(d) : new Date(d);
// If the date could be parsed...
if (d instanceof Date) {
// XXX It would be nicer to say day = "Today" or "Yesterday".
var day = d.toGMTString();
day = day.substring(0, 11);
function padZeros(num) {
return num < 10 ? "0" + num : num;
}
divs[i].getElementsByTagName("span")[0].textContent =
day + " @ " + padZeros(d.getHours()) + ":" + padZeros(d.getMinutes());
}
}
}
},
/**
* Returns the value of a boolean preference
* @param name
* The name of the preference
* @returns The value of the preference
*/
_getBooleanPref: function(name) {
return document.getElementById("data").getAttribute(name) == "true";
},
/**
* Returns the value of an integer preference
* @param name
* The name of the preference
* @returns The value of the preference
*/
_getIntegerPref: function(name) {
return parseInt(document.getElementById("data").getAttribute(name));
},
/**
* Reload the page after an interval
*/
reload: function() {
location.reload();
},
/**
* Initialize the feed view
*/
init: function() {
// Hide the menu if the user chose to have it closed
if (!this._getBooleanPref("showMenu"))
document.getElementById("menubox").style.display = "none";
// Normalize the date formats
this._initializeDates();
// Set up the auto-reload timer
setTimeout("RSSPrettyPrint.refresh()",
this._getIntegerPref("reloadInterval") * 1000);
},
};

View File

@ -1,292 +1,222 @@
<?xml version="1.0"?>
<!-- ***** 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) 2004
- 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 LGPL or the GPL. 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 ***** -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:date="http://www.jclark.com/xt/java/java.util.Date"
xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.0"
xmlns:atom03="http://purl.org/atom/ns#"
xmlns:atom10="http://www.w3.org/2005/Atom"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<!--
These parameters are filled in by the overlay.js with processor.setParameter
The parameters are used in '<options id="options" ' so they can be accessed in the DOM from JS
- there should be an easier way getting the settings
-->
<xsl:param name="feedUrl"/>
<xsl:param name="feedDescription"/>
<xsl:param name="feedTitle"/>
<xsl:param name="lengthSliderLabel"/>
<xsl:param name="articleLength"/>
<xsl:param name="showBar"/>
<xsl:param name="showImage"/>
<xsl:param name="timerInterval"/>
<xsl:param name="externalCSS"/>
<xsl:output method="html" media-type="text/html"/>
<xsl:template match="/">
<html>
<head>
<link rel="alternate" type="application/rss+xml" title="Current Feed" href=""/>
<title>
<xsl:value-of select="$feedTitle"/>
</title>
<link rel="stylesheet" href="chrome://browser/skin/feedview/feedview.css"/>
<!-- The custom stylesheet from the settings-->
<link rel="stylesheet">
<xsl:attribute name="href">
<xsl:value-of select="$externalCSS"/>
</xsl:attribute>
</link>
<script type="application/x-javascript" src="chrome://browser/content/feedview/feedview.js"/>
</head>
<body>
<!-- Menu box -->
<div id="menubox">
<xsl:value-of select="$lengthSliderLabel"/>
<br/>
<table>
<tr id="lengthSwitcher">
<td>
<a onclick="javascript:updateArticleLength(100);">
<div style="height: 10px;"/>
</a>
</td>
<td>
<a onclick="javascript:updateArticleLength(300);">
<div style="margin-left: 8px; margin-right: 8px; height: 15px; "/>
</a>
</td>
<td>
<a onclick="javascript:updateArticleLength(900);">
<div style="height: 20px; "/>
</a>
</td>
</tr>
</table>
<xul:slider id="lengthSlider" style="width: 110px; " flex="1"
pageincrement="10" maxpos="100"
onmousemove="updateArticleLength(this.getAttribute('curpos'))"
onclick="updateArticleLength(this.getAttribute('curpos'))"
onmouseup="updateArticleLength(this.getAttribute('curpos'))">
<xsl:attribute name="curpos">
<xsl:value-of select="$articleLength"/>
</xsl:attribute>
<xul:thumb/>
</xul:slider>
<br/>
<br/>
<span id="number">
<xsl:value-of select="$feedDescription"/>
</span>
<br/>
<br/>
<span id="timerspan">Refresh in <span id="timevalue">
<xsl:value-of select="$timerInterval"/>
</span> seconds</span>
</div>
<!-- The options place holder -->
<options id="options" style="display:none">
<xsl:attribute name="showbar">
<xsl:value-of select="$showBar"/>
</xsl:attribute>
<xsl:attribute name="showimage">
<xsl:value-of select="$showImage"/>
</xsl:attribute>
<xsl:attribute name="timerinterval">
<xsl:value-of select="$timerInterval"/>
</xsl:attribute>
</options>
<xsl:apply-templates/>
<!-- Dynamic stuff -->
<script><![CDATA[
if (document.getElementById("options").getAttribute("showbar") != "true")
document.getElementById("menubox").style.display = "none";
var showImage = true;
if (document.getElementById("options").getAttribute("showimage") != "true")
showImage = false;
setDate();
updateArticleLength(document.getElementById("lengthSlider").getAttribute("curpos"), showImage);
setFeed();
var interval = document.getElementById("options").getAttribute("timerinterval");
// only needed for automatic refresh
function refresh() {
interval -= 1;
if (interval <= 0)
window.location.href = window.location.href;
else
document.getElementById("timevalue").textContent = interval;
setTimeout("refresh()", 1000);
}
// if there is no interval hide the ticker
if (interval > 0)
setTimeout("refresh()", 1000);
else
document.getElementById("timerspan").style.display = "none";
]]></script>
</body>
</html>
</xsl:template>
<!-- RSS RDF Support-->
<xsl:template name="a-element">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:apply-templates select="*[local-name()='link']"/>
</xsl:attribute>
<xsl:value-of select="*[local-name()='title']"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[local-name()='channel']">
<h1>
<xsl:call-template name="a-element"/>
</h1>
<!-- Following line for RSS .091 -->
<div id="articles">
<xsl:apply-templates select="*[local-name()='item']"/>
</div>
</xsl:template>
<xsl:template match="*[local-name()='image']"></xsl:template>
<xsl:template match="*[local-name()='textinput']"></xsl:template>
<xsl:template match="*[local-name()='item']">
<div class="article">
<xsl:attribute name="description">
<xsl:value-of select="*[local-name()='description']" />
</xsl:attribute>
<xsl:if test="dc:date">
<xsl:attribute name="date">
<xsl:value-of select="dc:date" />
</xsl:attribute>
</xsl:if>
<xsl:if test="*[local-name()='pubDate']">
<xsl:attribute name="date">
<xsl:value-of select="*[local-name()='pubDate']" />
</xsl:attribute>
</xsl:if>
<xsl:call-template name="a-element"/>
<span class="date"></span>
<p></p>
</div>
</xsl:template>
<!-- ATOM 0.3 SUPPORT-->
<xsl:template match="atom03:feed">
<h1>
<a href="{atom03:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom03:title"/>
</a>
</h1>
<div id="articles">
<xsl:apply-templates select="atom03:entry"/>
</div>
</xsl:template>
<xsl:template match="atom03:entry">
<div class="article">
<xsl:if test="atom03:issued">
<xsl:attribute name="date">
<xsl:value-of select="atom03:issued"/>
</xsl:attribute>
</xsl:if>
<xsl:attribute name="description">
<xsl:choose>
<xsl:when test="atom03:content">
<xsl:value-of select="atom03:content"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="atom03:summary"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<a href="{atom03:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom03:title"/>
</a>
<span class="date"/>
<p/>
</div>
</xsl:template>
<!-- ATOM 1.0 SUPPORT-->
<xsl:template match="atom10:feed">
<h1>
<a href="{atom10:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom10:title"/>
</a>
</h1>
<div id="articles">
<xsl:apply-templates select="atom10:entry"/>
</div>
</xsl:template>
<xsl:template match="atom10:entry">
<div class="article">
<xsl:if test="atom10:updated">
<xsl:attribute name="date">
<xsl:value-of select="atom10:updated"/>
</xsl:attribute>
</xsl:if>
<xsl:attribute name="description">
<xsl:choose>
<xsl:when test="atom10:content">
<xsl:value-of select="atom10:content"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="atom10:summary"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<a href="{atom10:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom10:title"/>
</a>
<span class="date"/>
<p/>
</div>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0"?>
<!-- ***** 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) 2004
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Ben Goodger <ben@mozilla.org>
-
- 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 LGPL or the GPL. 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 ***** -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:date="http://www.jclark.com/xt/java/java.util.Date"
xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.0"
xmlns:atom03="http://purl.org/atom/ns#"
xmlns:atom10="http://www.w3.org/2005/Atom"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<xsl:param name="url"/>
<xsl:param name="articleCount"/>
<xsl:param name="title"/>
<xsl:param name="addLiveBookmarkLink"/>
<xsl:param name="liveBookmarkInfoURL"/>
<xsl:param name="liveBookmarkInfoText"/>
<!-- these parameters are read from the Firefox preferences system and are stored
as attributes on the <options> element in this page. -->
<xsl:param name="showMenu"/>
<xsl:param name="reloadInterval"/>
<xsl:output method="html" media-type="text/html"/>
<xsl:template match="/">
<html>
<head>
<title>
<xsl:value-of select="$title"/>
</title>
<link rel="stylesheet" href="chrome://browser/skin/feedview.css"/>
<script type="application/x-javascript" src="chrome://browser/content/feedview.js"/>
</head>
<body>
<!-- Menu box -->
<div id="menubox">
<span id="number">
<xsl:value-of select="$articleCount"/>
</span>
<br/>
<br/>
<a href="javascript:void(0);" id="addLiveBookmarkLink">
<xsl:attribute name="feed">
<xsl:value-of select="$url"/>
</xsl:attribute>
<xsl:value-of select="$addLiveBookmarkLink"/>
</a>
<br/>
<br/>
<a id="liveBookmarkInfoLink">
<xsl:attribute name="href">
<xsl:value-of select="$liveBookmarkInfoURL"/>
</xsl:attribute>
<xsl:value-of select="$liveBookmarkInfoText"/>
</a>
</div>
<!-- The options place holder -->
<div id="data" style="display: none;">
<xsl:attribute name="showMenu">
<xsl:value-of select="$showMenu"/>
</xsl:attribute>
<xsl:attribute name="reloadInterval">
<xsl:value-of select="$reloadInterval"/>
</xsl:attribute>
<xsl:attribute name="url">
<xsl:value-of select="$url"/>
</xsl:attribute>
</div>
<xsl:apply-templates/>
<script type="application/x-javascript"><!--
// Initialize the view
FeedView.init();
//--></script>
</body>
</html>
</xsl:template>
<!-- RSS RDF Support-->
<xsl:template name="a-element">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:apply-templates select="*[local-name()='link']"/>
</xsl:attribute>
<xsl:value-of select="*[local-name()='title']"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[local-name()='channel']">
<h1>
<xsl:call-template name="a-element"/>
</h1>
<!-- Following line for RSS .091 -->
<div id="articles">
<xsl:apply-templates select="*[local-name()='item']"/>
</div>
</xsl:template>
<xsl:template match="*[local-name()='image']"></xsl:template>
<xsl:template match="*[local-name()='textinput']"></xsl:template>
<xsl:template match="*[local-name()='item']">
<div class="article">
<xsl:if test="dc:date">
<xsl:attribute name="date">
<xsl:value-of select="dc:date" />
</xsl:attribute>
</xsl:if>
<xsl:if test="*[local-name()='pubDate']">
<xsl:attribute name="date">
<xsl:value-of select="*[local-name()='pubDate']" />
</xsl:attribute>
</xsl:if>
<h2><xsl:call-template name="a-element"/></h2>
<span class="date"></span>
<xsl:value-of select="*[local-name()='description']" />
<p></p>
</div>
</xsl:template>
<!-- ATOM 0.3 SUPPORT-->
<xsl:template match="atom03:feed">
<h1>
<a href="{atom03:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom03:title"/>
</a>
</h1>
<div id="articles">
<xsl:apply-templates select="atom03:entry"/>
</div>
</xsl:template>
<xsl:template match="atom03:entry">
<div class="article">
<xsl:if test="atom03:issued">
<xsl:attribute name="date">
<xsl:value-of select="atom03:issued"/>
</xsl:attribute>
</xsl:if>
<a href="{atom03:link[substring(@rel, 1, 8)!='service.']/@href}">
<h2><xsl:value-of select="atom03:title"/></h2>
</a>
<span class="date"/>
<xsl:choose>
<xsl:when test="atom03:content">
<xsl:value-of select="atom03:content"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="atom03:summary"/>
</xsl:otherwise>
</xsl:choose>
<p/>
</div>
</xsl:template>
<!-- ATOM 1.0 SUPPORT-->
<xsl:template match="atom10:feed">
<h1>
<a href="{atom10:link[substring(@rel, 1, 8)!='service.']/@href}">
<xsl:value-of select="atom10:title"/>
</a>
</h1>
<div id="articles">
<xsl:apply-templates select="atom10:entry"/>
</div>
</xsl:template>
<xsl:template match="atom10:entry">
<div class="article">
<xsl:if test="atom10:updated">
<xsl:attribute name="date">
<xsl:value-of select="atom10:updated"/>
</xsl:attribute>
</xsl:if>
<a href="{atom10:link[substring(@rel, 1, 8)!='service.']/@href}">
<h2><xsl:value-of select="atom10:title"/></h2>
</a>
<span class="date"/>
<xsl:choose>
<xsl:when test="atom10:content">
<xsl:value-of select="atom10:content"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="atom10:summary"/>
</xsl:otherwise>
</xsl:choose>
<p/>
</div>
</xsl:template>
</xsl:stylesheet>

View File

@ -16,6 +16,8 @@ browser.jar:
* content/browser/browser.js (content/browser.js)
* content/browser/browser.xul (content/browser.xul)
* content/browser/credits.xhtml (content/credits.xhtml)
* content/browser/feedview.xsl (content/feedview.xsl)
* content/browser/feedview.js (content/feedview.js)
* content/browser/metaData.js (content/metaData.js)
* content/browser/metaData.xul (content/metaData.xul)
content/browser/monitor.png (content/monitor.png)

View File

@ -62,7 +62,6 @@ DIRS = \
shell \
sidebar \
build \
feedview \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -134,6 +134,11 @@ function Startup()
gSelectedFolder = RDF.GetResource(gMenulist.selectedItem.id);
gExpander.setAttribute("tooltiptext", gExpander.getAttribute("tooltiptextdown"));
gPostData = gArg.postData;
if ("feedURL" in gArg) {
var strings = document.getElementById("bookmarksBundle");
document.title = strings.getString("addLiveBookmarkTitle");
}
# read the persisted attribute. If it is not present, set a default height.
WSucks = parseInt(gBookmarksTree.getAttribute("height"));
@ -153,6 +158,16 @@ function Startup()
localStore.Unassert(rDialog, rPersist, rElement, true);
gExpander.setAttribute("class", "down");
}
// Select the specified folder after the window is made visible
function initMenulist() {
if ("folderURI" in gArg) {
var folderItem = document.getElementById(gArg.folderURI);
if (folderItem)
gMenulist.selectedItem = folderItem;
}
}
setTimeout(initMenulist, 0);
}
function onFieldInput()

View File

@ -70,6 +70,9 @@
<script type="application/x-javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="application/x-javascript" src="chrome://browser/content/bookmarks/bookmarks.js"/>
<script type="application/x-javascript" src="chrome://browser/content/bookmarks/addBookmark2.js"/>
<stringbundle id="bookmarksBundle"
src="chrome://browser/locale/bookmarks/bookmarks.properties"/>
<separator id="nameseparator" class="thin"/>
@ -96,6 +99,9 @@
<menuitem class="menuitem-iconic folder-icon"
label="&bookmarksRoot.label;"
id="NC:BookmarksRoot"/>
<menuitem class="menuitem-iconic folder-icon"
label="&bookmarksToolbar.label;"
id="NC:PersonalToolbarFolder"/>
<menuseparator/>
<template>
<!-- this parent="menupopup" here seems to prevent the template builder from recursing. -->

View File

@ -1819,7 +1819,8 @@ var BookmarksUtils = {
url: aURL,
bWebPanel: false,
feedURL: aFeedURL,
description: aDescription
description: aDescription,
folderURI: "NC:PersonalToolbarFolder"
}
openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
ADD_BM_DIALOG_FEATURES, dArgs);

View File

@ -1,46 +0,0 @@
#
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1998
# 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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

View File

@ -1,216 +0,0 @@
/* ***** 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 curLength;
var number ;
// Add the name of the feed to the title.
function setFeed() {
var title = document.getElementsByTagName("h1")[0].textContent;
document.title = document.getElementsByTagName("title")[0].textContent + " " + title;
}
// Try to get a Date() from a date string.
function xmlDate(In) {
In = In.replace('Z', '+00:00')
var D = In.replace(/^(\d{4})-(\d\d)-(\d\d)T([0-9:]*)([.0-9]*)(.)(\d\d):(\d\d)$/, '$1/$2/$3 $4 $6$7$8');
D = Date.parse(D);
D += 1000*RegExp.$5;
return new Date(D);
}
function setDate() {
// Find all items (div) in the htmlfeed.
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
// If the current div element has a date...
var d = divs[i].getAttribute("date");
if (d) {
// If it is an RFC... date -> first parse it...
// otherwise try the Date() constructor.
if (d.indexOf("T"))
d = xmlDate( d );
else
d = new Date( d );
// If the date could be parsed...
if (d instanceof Date) {
// XXX It would be nicer to say day = "Today" or "Yesterday".
var day = d.toGMTString();
day = day.substring(0, 11);
divs[i].getElementsByTagName("span")[0].textContent =
day + " @ " + lead(d.getHours()) + ":" + lead(d.getMinutes());
}
}
} // end of the divs loop
}
// XXX This function should not exist.
// It tries to fix as many special characters as posible.
function fixchars(txt) {
txt = txt.replace(/&nbsp;/g, " ");
txt = txt.replace(/&amp;/g, "&");
txt = txt.replace(/&gt;/g, ">");
txt = txt.replace(/&lt;/g, "<");
txt = txt.replace(/&quot;/g, "'");
txt = txt.replace(/&#8217;/g, "'");
txt = txt.replace(/&#8216;/g, "'");
txt = txt.replace(/&#8212;/g, "—");
txt = txt.replace(/&#33;/g, "!");
txt = txt.replace(/&#38;/g, "&");
txt = txt.replace(/&#39;/g, "'");
return txt;
}
// This function is called when the page is loaded and when the feeds are resized.
// maxLength: maximum length (in words) of the article, which can be set by the slider
// init: is this onload or not
function updateArticleLength(maxLength, init) {
// regex to get all the img tags
var img = /<img([^>]*)>/g;
var imgArr;
var im;
// sl: the slider element
var sl = document.getElementById("lengthSlider");
sl.setAttribute("curpos", maxLength);
// performance trick, don't know if it actually speeds up
if (maxLength == curLength) return;
curLength = maxLength;
var divs = document.getElementsByTagName("div");
// for each feed item (div) in the feedhtml
for (var i = 0; i < divs.length; i++) {
// if this is onload, set the title (the <a>) of each feed item
if (init) {
var title = divs[i].getElementsByTagName("a");
if (title.length > 0) { // just being safe
title = title[0];
title.textContent = fixchars(title.textContent);
// ...and remove all html tags from the title.
title.textContent = title.textContent.replace(/<([^>]*)>/g, "");
}
}
var txt = divs[i].getAttribute("description");
// If the item contains a description attribute, fill the <p> with it.
if (txt != null) {
txt = fixchars(txt);
// Replace all <br> and <p> by real breaks.
txt = txt.replace(/<br[^\>]*>/g, "\n");
txt = txt.replace(/<p[^\>]*>/g, "\n");
// If we have a description AND we are in onload
// find all images in the description and put them in an array
// before they are stripped as common html tags.
if (init) {
imgArr = new Array();
img.lastIndex = 0;
while ((im = img.exec(txt)) != null) {
var src = /\< *[img][^\>]*[src] *= *[\"\']{0,1}([^\"\'\ >]*)/i;
im[0] = im[0].replace('border=', ''); // fix somtin?
im[0] = im[0].replace('class=', ''); // fix somtin?
var imgsrc = src.exec(im[0]);
imgArr.push(imgsrc[1]);
}
// For each found image in the description create a new <img> tag
// and append it after the <p> with the description.
var o; // will be our new <img> tag
for (im=0; im < imgArr.length; im++) {
a = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
a.setAttribute("href", imgArr[im]);
o = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
a.setAttribute("class", "image");
o.setAttribute("src", imgArr[im]);
a.appendChild(o);
divs[i].appendChild(a);
}
} // end:if (init)
// Kill all html.
txt = txt.replace(/<([^>]*)>/g, "");
/* split the description in words*/
var ar = txt.split(" ");
// performance... :)
if (maxLength == 0) txt = "";
if (maxLength < 100 && maxLength != 0) {
if (ar.length > maxLength) {
txt = "";
// append the number of words (maxLength)
for (var x = 0; x < maxLength ; x++) {
txt += ar[x] + " ";
}
txt += " ..." ;
}
}
// the <p> of the feeditem we are working with
var currentP = divs[i].getElementsByTagName("p")[0];
if (currentP != null) {
// Remove all previous elements from the parent <p>,
// which fill in the next lines of code.
for (var pc = currentP.childNodes.length; pc > 0; pc--)
currentP.removeChild(currentP.childNodes[0]);
// Split our description and for each line (which were
// actually <br> or <p>) of the description add a new <p>.
var p = txt.split("\n");
for (im = 0; im < p.length; im++) {
if (p != "") {
var a = document.createElementNS("http://www.w3.org/1999/xhtml", "p");
a.textContent = p[im];
currentP.appendChild(a);
}
}
} // end if (currentP != null)
} // end if (txt != null)
} // end for (i=0; i<divs.length; i++)
}
// leading zero function
function lead(In) {
if (In < 10)
return "0" + In;
else
return In;
}

View File

@ -1,202 +0,0 @@
/* ***** 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) &&
// bandaid for bug 256084
!(evnt.originalTarget instanceof XULDocument))
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);
}
}

View File

@ -1,4 +0,0 @@
browser.jar:
content/browser/feedview/feedviewOverlay.js (content/feedviewOverlay.js)
content/browser/feedview/feedview.xsl (content/feedview.xsl)
content/browser/feedview/feedview.js (content/feedview.js)

View File

@ -24,4 +24,4 @@ browser.search.defaultenginename=Google
update_notifications.provider.0.datasource=
searchEnginesURL=http://www.mozilla.org/products/firefox/add-engines.html
feedLiveBookmarkInfoURL=http://www.mozilla.org/products/firefox/live-bookmarks

View File

@ -25,3 +25,4 @@
<!ENTITY addGroup.label "Bookmark all tabs in a folder">
<!ENTITY addGroup.accesskey "B">
<!ENTITY acceptButton.label "Add">
<!ENTITY bookmarksToolbar.label "Bookmarks Toolbar">

View File

@ -172,6 +172,7 @@ emptyFolder = (Empty)
addBookmarkPromptTitle=Add Bookmark?
addBookmarkPromptMessage=Add Bookmark to "%S" (%S)?
addBookmarkPromptButton=Add Bookmark
addLiveBookmarkTitle=Add Live Bookmark
BookmarksLivemarkLoading=Live Bookmark loading...
BookmarksLivemarkFailed=Live Bookmark feed failed to load.

View File

@ -83,10 +83,6 @@ popupWarningDontShowFromMessage=Don't show this message when popups are blocked
popupWarningDontShowFromStatusbar=Don't show info message when popups are blocked
popupShowPopupPrefix=Show '%S'
livemarkHasLivemarksTooltip=Add Live Bookmark for this page's feed
livemarkNoLivemarksTooltip=Page has no feeds for Live Bookmark
livemarkSubscribeTo=Subscribe to '%S'...
saveFormInformationMessage=%S can save information that you enter in web forms to make filling them out faster in the future. Would you like to save form information from now on?
saveFormInformationYes=Save Form Information
saveFormInformationNo=Don't Save
@ -109,3 +105,12 @@ updatesItem_resume=Resume Downloading %S...
updatesItem_resumeFallback=Resume Downloading Update...
updatesItem_pending=Apply Downloaded Update Now...
updatesItem_pendingFallback=Apply Downloaded Update Now...
# RSS Pretty Print
feedTitle=Feed: %S
feedDescription=This feed contains %S articles.
feedAddLiveBookmarkLink=Add Live Bookmark...
feedLiveBookmarkInfoText=What are Live Bookmarks?
feedShowFeed=Show '%S'
feedHasFeeds=View this page's feeds
feedNoFeeds=Page has no feeds

View File

@ -1,39 +0,0 @@
# ***** 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 (www.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 *****
title=Feed:
description=This feed contains %S articles.
lengthSliderLabel=Article length:

View File

@ -7,7 +7,6 @@
* locale/browser/browser.dtd (%chrome/browser/browser.dtd)
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/feedview.properties (%chrome/browser/feedview.properties)
locale/browser/metaData.dtd (%chrome/browser/metaData.dtd)
locale/browser/metaData.properties (%chrome/browser/metaData.properties)
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)

View File

@ -820,21 +820,6 @@ statusbarpanel#statusbar-display {
display: -moz-box;
}
#livemark-button {
list-style-image: none;
width: 20px;
display: none;
}
#livemark-button[livemarks] {
list-style-image: url("chrome://browser/skin/page-livemarks.png");
display: -moz-box;
}
#livemark-button[livemarks][chromedir="rtl"] {
list-style-image: url("chrome://browser/skin/page-livemarks-rtl.png");
}
/* ::::: throbber ::::: */
#navigator-throbber {
@ -936,16 +921,43 @@ toolbar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
color: #000000;
}
#urlbar[level="high"] > .autocomplete-textbox-container > .info-icon {
#urlbar[level="high"] #lock-icon {
list-style-image: url("chrome://browser/skin/Secure.png");
}
#urlbar[level="low"] > .autocomplete-textbox-container > .info-icon {
#urlbar[level="low"] #lock-icon {
list-style-image: url("chrome://browser/skin/Secure.png");
}
#urlbar[level="broken"] > .autocomplete-textbox-container > .info-icon {
#urlbar[level="broken"] #lock-icon {
list-style-image: url("chrome://browser/skin/Security-broken.png");
}
#feed-button, #feed-button > .button-box,
#feed-button:hover:active > .button-box {
padding: 0px;
margin: 0px;
border: 0px;
background-color: transparent;
}
#feed-button .button-menu-dropmarker,
#feed-button .button-text {
display: none;
}
#feed-button {
-moz-binding: url("chrome://global/content/bindings/button.xml#menu");
-moz-appearance: none;
min-width: 0px;
margin-right: 1px !important;
}
#feed-button[feeds] {
list-style-image: url("chrome://browser/skin/page-livemarks.png");
}
#feed-button[chromedir="rtl"][feeds] {
list-style-image: url("chrome://browser/skin/page-livemarks-rtl.png");
}
/* ::::: About Popup Blocking dialog ::::: */
#pageReportFirstTime statusbarpanel.statusbar-resizerpanel {
visibility: collapse;

View File

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 243 B

View File

@ -1,187 +1,179 @@
/* ***** 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 ***** */
feed, rss, rdf {
margin: 0;
padding: 0;
}
body {
padding: 30px;
margin: 0;
}
* {
font-family: arial;
}
p {
width: 70%;
color: #666;
font-size: 13px;
margin-bottom: 20px;
margin-top: 5px;
}
p > p {
width: 100%;
}
select {
color: #666;
font-size: 13px;
}
h1 {
font-weight: normal;
font-size: 27px;
margin: -30px;
margin-bottom: 30px;
padding: 12px;
padding-left: 28px;
background-image: url("chrome://browser/skin/feedview/itemSelected.png") !important;
}
div.article a {
color: #444;
text-decoration: none;
font-size: 16px;
font-weight: bold;
padding-right: 25px;
}
div.article a:visited {
-moz-opacity: 1;
background: url(chrome://browser/skin/feedview/check.png) no-repeat right;
}
.image:visited {
background: transparent !important;
}
h1 a {
text-decoration: none;
color: white;
}
span.date {
margin-left:30px;
font-size:14px ;
color: #ccc;
font-weight: bold;
}
span#number {
margin-left:0px;
display:inline;
font-size:13px;
}
#addLivemark {
display:none;
font-size: 12px;
font-weight: normal;
background: url(chrome://browser/skin/page-livemarks.png) no-repeat;
padding-left: 25px;
}
#lengthSwitcher {
display: none;
}
#lengthSwitcher td {
vertical-align:top;
}
#lengthSwitcher div {
width: 20px;
background: #bbb;
-moz-border-radius: 3px;
cursor: pointer;
-moz-opacity: 0.6;
}
#lengthSwitcher div:hover {
-moz-opacity: 1;
}
#switchdate {
cursor: pointer;
}
#lengthSlider {
background: #fff;
-moz-border-radius: 6px;
}
#menubox {
width:125px;
-moz-border-radius:4px;
float: right;
margin-top: 50px;
background: #eee; /*#f5f5f5; */
border: 1px solid #ddd;
padding: 10px 30px 15px 30px;
font-size: 12px; color: #aaa;
border-width: 0 1px 1px 0;
}
.image img {
max-height: 80px ;
border: 1px solid #ddd;
padding: 4px;
background: #fff;
margin: -13px 5px 18px 0px;
-moz-border-radius: 4px;
vertical-align: top;
}
thumb {
height: 15px ;
min-height: 15px ;
}
thumb * {
display:none;
}
item, entry, channel {
display: none;
}
p > p {
margin: 0;
}
/* ***** 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 ***** */
feed, rss, rdf {
margin: 0;
padding: 0;
}
body {
padding: 30px;
margin: 0;
}
* {
font-family: arial;
}
p {
width: 70%;
color: #666;
font-size: 13px;
margin-bottom: 20px;
margin-top: 5px;
}
p > p {
width: 100%;
}
select {
color: #666;
font-size: 13px;
}
h1 {
font-weight: normal;
font-size: 27px;
margin: -30px;
margin-bottom: 30px;
padding: 12px;
padding-left: 28px;
background-image: url("chrome://browser/skin/itemSelected.png") !important;
}
div.article a {
color: #444;
text-decoration: none;
font-size: 16px;
font-weight: bold;
padding-right: 25px;
}
div.article a:visited {
-moz-opacity: 1;
background: url(chrome://browser/skin/check.png) no-repeat right;
}
.image:visited {
background: transparent !important;
}
h1 a {
text-decoration: none;
color: white;
}
span.date {
margin-left:30px;
font-size:14px ;
color: #ccc;
font-weight: bold;
}
span#number {
margin-left:0px;
display:inline;
font-size:13px;
}
#addLivemark {
display:none;
font-size: 12px;
font-weight: normal;
background: url(chrome://browser/skin/page-livemarks.png) no-repeat;
padding-left: 25px;
}
#switchdate {
cursor: pointer;
}
#menubox {
width: 15em;
-moz-border-radius: 4px;
float: right;
margin: 50px 10px 25px 10px;
background: #eee; /*#f5f5f5; */
border: 1px solid #ddd;
padding: 15px;
font-size: 12px;
color: #aaa;
border-width: 0 1px 1px 0;
}
#menubox a {
padding-left: 20px;
color: #aaa !important;
text-decoration: none;
font-weight: bold;
}
#menubox a:hover {
text-decoration: underline;
}
#addLiveBookmarkLink {
background: url("chrome://browser/skin/page-livemarks.png") no-repeat left;
}
.image img {
max-height: 80px ;
border: 1px solid #ddd;
padding: 4px;
background: #fff;
margin: -13px 5px 18px 0px;
-moz-border-radius: 4px;
vertical-align: top;
}
thumb {
height: 15px ;
min-height: 15px ;
}
thumb * {
display:none;
}
item, entry, channel {
display: none;
}
p > p {
margin: 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

View File

@ -1,187 +0,0 @@
/* ***** 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 ***** */
feed, rss, rdf {
margin: 0;
padding: 0;
}
body {
padding: 30px;
margin: 0;
}
* {
font-family: arial;
}
p {
width: 70%;
color: #666;
font-size: 13px;
margin-bottom: 20px;
margin-top: 5px;
}
p > p {
width: 100%;
}
select {
color: #666;
font-size: 13px;
}
h1 {
font-weight: normal;
font-size: 27px;
margin: -30px;
margin-bottom: 30px;
padding: 12px;
padding-left: 28px;
background-image: url("chrome://browser/skin/feedview/itemSelected.png") !important;
}
div.article a {
color: #444;
text-decoration: none;
font-size: 16px;
font-weight: bold;
padding-right: 25px;
}
div.article a:visited {
-moz-opacity: 1;
background: url(chrome://browser/skin/feedview/check.png) no-repeat right;
}
.image:visited {
background: transparent !important;
}
h1 a {
text-decoration: none;
color: white;
}
span.date {
margin-left:30px;
font-size:14px ;
color: #ccc;
font-weight: bold;
}
span#number {
margin-left:0px;
display:inline;
font-size:13px;
}
#addLivemark {
display:none;
font-size: 12px;
font-weight: normal;
background: url(chrome://browser/skin/page-livemarks.png) no-repeat;
padding-left: 25px;
}
#lengthSwitcher {
display: none;
}
#lengthSwitcher td {
vertical-align:top;
}
#lengthSwitcher div {
width: 20px;
background: #bbb;
-moz-border-radius: 3px;
cursor: pointer;
-moz-opacity: 0.6;
}
#lengthSwitcher div:hover {
-moz-opacity: 1;
}
#switchdate {
cursor: pointer;
}
#lengthSlider {
background: #fff;
-moz-border-radius: 6px;
}
#menubox {
width:125px;
-moz-border-radius:4px;
float: right;
margin-top: 50px;
background: #eee; /*#f5f5f5; */
border: 1px solid #ddd;
padding: 10px 30px 15px 30px;
font-size: 12px; color: #aaa;
border-width: 0 1px 1px 0;
}
.image img {
max-height: 80px ;
border: 1px solid #ddd;
padding: 4px;
background: #fff;
margin: -13px 5px 18px 0px;
-moz-border-radius: 4px;
vertical-align: top;
}
thumb {
height: 15px ;
min-height: 15px ;
}
thumb * {
display:none;
}
item, entry, channel {
display: none;
}
p > p {
margin: 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

View File

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 459 B

View File

@ -24,9 +24,9 @@ classic.jar:
skin/classic/browser/bookmarks/addBookmark.css (bookmarks/addBookmark.css)
skin/classic/browser/bookmarks/bookmarksManager.css (bookmarks/bookmarksManager.css)
skin/classic/browser/bookmarks/Bookmarks-toolbar.png (bookmarks/Bookmarks-toolbar.png)
skin/classic/browser/feedview/feedview.css (feedview/feedview.css)
skin/classic/browser/feedview/check.png (feedview/check.png)
skin/classic/browser/feedview/itemSelected.png (feedview/itemSelected.png)
skin/classic/browser/feedview.css (feedview.css)
skin/classic/browser/check.png (check.png)
skin/classic/browser/itemSelected.png (itemSelected.png)
skin/classic/browser/preferences/Options.png (preferences/Options.png)
skin/classic/browser/preferences/preferences.css (preferences/preferences.css)
icon.png

View File

@ -63,7 +63,7 @@
flex="1" allowevents="true"
xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,userAction"/>
</xul:hbox>
<xul:image class="info-icon" xbl:inherits="src=infoicon,tooltiptext=infotext"/>
<children includes="hbox"/>
</xul:hbox>
<xul:dropmarker anonid="historydropmarker" class="autocomplete-history-dropmarker"
@ -469,13 +469,6 @@
<handler event="blur" phase="capturing"
action="this.detachController();"/>
<handler event="dblclick">
<![CDATA[
if (event.originalTarget.className == "info-icon" && event.button == 0)
return this.fireEvent("infoclick");
return true;
]]>
</handler>
</handlers>
</binding>