Bug #281237 --> start landing the new RSS subscription manager UI.

This commit is contained in:
scott%scott-macgregor.org 2005-02-08 22:20:04 +00:00
Родитель c6ed0e4d26
Коммит 28af173c29
24 изменённых файлов: 1331 добавлений и 253 удалений

Просмотреть файл

@ -73,9 +73,10 @@ var FeedCache =
}
};
function Feed(aResource)
function Feed(aResource, aRSSServer)
{
this.resource = aResource.QueryInterface(Components.interfaces.nsIRDFResource);
this.server = aRSSServer;
}
Feed.prototype =
@ -347,15 +348,15 @@ Feed.prototype =
cleanupParsingState: function(aFeed)
{
// now that we are done parsing the feed, remove the feed from our feed cache
FeedCache.removeFeed(feed.url);
FeedCache.removeFeed(aFeed.url);
aFeed.removeInvalidItems();
// let's be sure to flush any feed item changes back to disk
var ds = getItemsDS(feed.server);
var ds = getItemsDS(aFeed.server);
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes
if (aFeed.downloadCallback)
aFeed.downloadCallback.downloaded(feed, kNewsBlogSuccess);
aFeed.downloadCallback.downloaded(aFeed, kNewsBlogSuccess);
this.request = null; // force the xml http request to go away. This helps reduce some nasty assertions on shut down.
this.itemsToStore = "";

Просмотреть файл

@ -45,6 +45,7 @@ function onLoad()
document.getElementById('selectFolder').setAttribute('ref', window.arguments[0].serverURI);
SetFolderPicker(window.arguments[0].folderURI ? window.arguments[0].folderURI : window.arguments[0].serverURI, 'selectFolder');
document.getElementById('selectFolder').setInitialSelection();
document.getElementById('rssAccountMenuItem').label = window.arguments[0].serverPrettyName;
document.getElementById('rssAccountMenuItem').value = window.arguments[0].serverURI;
@ -53,7 +54,7 @@ function onLoad()
document.getElementById('quickMode').checked = window.arguments[0].quickMode;
// if we are editing an existing feed, disable the top level account
if (window.arguments[0].folderURI)
if (!window.arguments[0].newFeed)
document.getElementById('rssAccountMenuItem').setAttribute('disabled', 'true');
}

Просмотреть файл

@ -1,40 +1,41 @@
<?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 News and Blogs Feed Properties UI.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2004
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Scott MacGregor <mscott@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 ***** -->
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Feed Properties UI
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
<?xml-stylesheet href="chrome://messenger/skin/" type="text/css"?>

Просмотреть файл

@ -0,0 +1,733 @@
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Subscription Manager
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
const MSG_FOLDER_FLAG_TRASH = 0x0100;
const IPS = Components.interfaces.nsIPromptService;
var gFeedSubscriptionsWindow = {
mFeedContainers : [],
mTree : null,
mBundle : null,
mRSSServer : null,
init: function ()
{
// extract the server argument
if (window.arguments[0].server)
this.mRSSServer = window.arguments[0].server;
var docshell = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell);
docshell.allowAuth = true;
this.mTree = document.getElementById("rssSubscriptionsList");
this.mBundle = document.getElementById("bundle_newsblog");
this.loadSubscriptions();
this.mTree.treeBoxObject.view = this.mView;
if (this.mView.rowCount > 0)
this.mTree.view.selection.select(0);
},
uninit: function ()
{
var dismissDialog = true;
// if we are in the middle of subscribing to a feed, inform the user that
// dismissing the dialog right now will abort the feed subscription.
// cheat and look at the disabled state of the add button to determine if we are in the middle of a new subscription
if (document.getElementById('addFeed').getAttribute('disabled'))
{
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(IPS);
var newsBlogBundle = document.getElementById("bundle_newsblog");
dismissDialog = !(promptService.confirmEx(window, newsBlogBundle.getString('subscribe-cancelSubscriptionTitle'),
newsBlogBundle.getString('subscribe-cancelSubscription'),
(IPS.BUTTON_TITLE_YES * IPS.BUTTON_POS_0) + (IPS.BUTTON_TITLE_NO * IPS.BUTTON_POS_1),
null, null, null, null, { }));
}
return dismissDialog;
},
mView:
{
mRowCount : 0,
get rowCount()
{
return this.mRowCount;
},
getItemAtIndex: function (aIndex)
{
return gFeedSubscriptionsWindow.mFeedContainers[aIndex];
},
removeItemAtIndex: function (aIndex, aCount)
{
var itemToRemove = this.getItemAtIndex(aIndex);
if (!itemToRemove)
return;
var parentIndex = this.getParentIndex(aIndex);
if (parentIndex != -1)
{
var parent = this.getItemAtIndex(parentIndex);
if (parent)
{
for (var index = 0; index < parent.children.length; index++)
if (parent.children[index] == itemToRemove)
{
parent.children.splice(index, 1);
break;
}
}
}
// now remove it from our view
gFeedSubscriptionsWindow.mFeedContainers.splice(aIndex, 1);
// now invalidate the correct tree rows
var tbo = gFeedSubscriptionsWindow.mTree.treeBoxObject;
this.mRowCount--;
tbo.rowCountChanged(aIndex, -1);
tbo.invalidateRow(aIndex);
// now update the selection position
if (aIndex < gFeedSubscriptionsWindow.mFeedContainers.length)
this.selection.select(aIndex);
else
this.selection.clearSelection();
// now refocus the tree
gFeedSubscriptionsWindow.mTree.focus();
},
getCellText: function (aIndex, aColumn)
{
var item = this.getItemAtIndex(aIndex);
if (!item)
return "";
else if (aColumn.id == "folderNameCol")
return item.name;
},
_selection: null,
get selection () { return this._selection; },
set selection (val) { this._selection = val; return val; },
getRowProperties: function (aIndex, aProperties) {},
getCellProperties: function (aIndex, aColumn, aProperties) {},
getColumnProperties: function (aColumn, aProperties) {},
isContainer: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
return item ? item.container : false;
},
isContainerOpen: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
return item ? item.open : false;
},
isContainerEmpty: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (!item)
return false;
return item.children.length == 0;
},
isSeparator: function (aIndex) { return false; },
isSorted: function (aIndex) { return false; },
canDrop: function (aIndex, aOrientation)
{
var dropResult = this.extractURLAndVerifyFlavour();
return (aOrientation == Components.interfaces.nsITreeView.DROP_ON) && dropResult.canDrop && dropResult.url;
},
mDropUrl: "",
mDropFolderUrl: "",
drop: function (aIndex, aOrientation)
{
var results = this.extractURLAndVerifyFlavour();
if (results.canDrop && results.url)
{
var folderItem = this.getItemAtIndex(aIndex);
// don't freeze the app that initiaed the drop just because we are in a loop waiting for the user
// to dimisss the add feed dialog....
this.mDropUrl = results.url;
this.mDropFolderUrl = folderItem.url;
setTimeout(processDrop, 0);
}
},
// helper function for drag and drop
extractURLAndVerifyFlavour: function()
{
var canDrop = false;
var urlToDrop;
var dragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService);
var dragSession = dragService.getCurrentSession();
var transfer = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
transfer.addDataFlavor("text/x-moz-url");
dragSession.getData (transfer, 0);
var dataObj = new Object();
var flavor = new Object();
var len = new Object();
try {
transfer.getAnyTransferData(flavor, dataObj, len);
} catch (ex) { return { canDrop: false, url: "" }; }
if (dataObj.value)
{
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
sourceUri = dataObj.data.substring(0, len.value); // pull the URL out of the data object
if (sourceUri)
{
var uri = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURI);
uri.spec = sourceUri.split("\n")[0];
if (uri.schemeIs("http") || uri.schemeIs("https"))
{
urlToDrop = uri.spec;
canDrop = true;
}
} // if sourceUri
} // if dataObj.value
return { canDrop: canDrop, url: urlToDrop };
},
getParentIndex: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (item)
{
for (var index = aIndex; index >= 0; index--)
if (gFeedSubscriptionsWindow.mFeedContainers[index].level < item.level)
return index;
}
return -1;
},
hasNextSibling: function (aParentIndex, aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (item)
{
// if the next node in the view has the same level as us, then we must have a next sibling...
if (aIndex + 1 < gFeedSubscriptionsWindow.mFeedContainers.length )
return this.getItemAtIndex(aIndex + 1).level == item.level;
}
return false;
},
hasPreviousSibling: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (item && aIndex)
return this.getItemAtIndex(aIndex - 1).level == item.level;
else
return false;
},
getLevel: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (!item)
return 0;
return item.level;
},
getImageSrc: function (aIndex, aColumn) {},
getProgressMode: function (aIndex, aColumn) {},
getCellValue: function (aIndex, aColumn) {},
setTree: function (aTree) {},
toggleOpenState: function (aIndex)
{
var item = this.getItemAtIndex(aIndex);
if (!item) return;
var multiplier = item.open ? -1 : 1;
var delta = multiplier * item.children.length;
this.mRowCount += delta;
if (multiplier < 0)
gFeedSubscriptionsWindow.mFeedContainers.splice(aIndex + 1, item.children.length);
else
for (var i = 0; i < item.children.length; i++)
gFeedSubscriptionsWindow.mFeedContainers.splice(aIndex + 1, 0, item.children[i]);
// add or remove the children from our view
item.open = !item.open;
gFeedSubscriptionsWindow.mTree.treeBoxObject.rowCountChanged(aIndex + 1, delta);
gFeedSubscriptionsWindow.mTree.treeBoxObject.invalidateRow(aIndex);
},
cycleHeader: function (aColumn) {},
selectionChanged: function () {},
cycleCell: function (aIndex, aColumn) {},
isEditable: function (aIndex, aColumn)
{
return false;
},
setCellValue: function (aIndex, aColumn, aValue) {},
setCellText: function (aIndex, aColumn, aValue) {},
performAction: function (aAction) {},
performActionOnRow: function (aAction, aIndex) {},
performActionOnCell: function (aAction, aindex, aColumn) {}
},
makeFolderObject: function (aFolder, aCurrentLevel)
{
var folderObject = { children : [],
name : aFolder.prettiestName,
level : aCurrentLevel,
url : aFolder.QueryInterface(Components.interfaces.nsIRDFResource).Value,
open : false,
container: true };
// if a feed has any sub folders, we should add them to the list of children
if (aFolder.hasSubFolders)
{
var folderEnumerator = aFolder.GetSubFolders();
var done = false;
while (!done)
{
var folder = folderEnumerator.currentItem().QueryInterface(Components.interfaces.nsIMsgFolder);
folderObject.children.push(this.makeFolderObject(folder, aCurrentLevel + 1));
try {
folderEnumerator.next();
}
catch (ex)
{
done = true;
}
}
}
var msgdb = aFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null);
var folderInfo = msgdb.dBFolderInfo;
var feedurls = folderInfo.getCharPtrProperty("feedUrl");
var feedUrlArray = feedurls.split("|");
for (url in feedUrlArray)
{
if (!feedUrlArray[url])
continue;
var feedResource = rdf.GetResource(feedUrlArray[url]);
var feed = new Feed(feedResource, this.mRSSServer);
// Special case, if a folder only has a single feed associated with it, then just use the feed
// in the view and don't show the folder at all.
// if (feedUrlArray.length <= 2 && !aFolder.hasSubFolders) // Note: split always adds an empty element to the array...
// this.mFeedContainers[aCurrentLength] = this.makeFeedObject(feed, aCurrentLevel);
// else // now add any feed urls for the folder
folderObject.children.push(this.makeFeedObject(feed, aCurrentLevel + 1));
}
return folderObject;
},
makeFeedObject: function (aFeed, aLevel)
{
// look inside the data source for the feed properties
var feed = { children : [],
name : aFeed.title,
url : aFeed.url,
level : aLevel,
open : false,
container : false };
return feed;
},
loadSubscriptions: function ()
{
// put together an array of folders
var numFolders = 0;
this.mFeedContainers = [];
if (this.mRSSServer.rootFolder.hasSubFolders)
{
var folderEnumerator = this.mRSSServer.rootFolder.GetSubFolders();
var done = false;
while (!done)
{
var folder = folderEnumerator.currentItem().QueryInterface(Components.interfaces.nsIMsgFolder);
if (folder && !folder.getFlag(MSG_FOLDER_FLAG_TRASH))
{
this.mFeedContainers.push(this.makeFolderObject(folder, 0));
numFolders++;
}
try {
folderEnumerator.next();
}
catch (ex)
{
done = true;
}
}
}
this.mView.mRowCount = numFolders;
},
updateFeedData: function (aItem)
{
var ids = ['nameLabel', 'nameValue', 'locationLabel', 'locationValue'];
if (aItem && !aItem.container)
{
// set the feed location and title info
document.getElementById('nameValue').value = aItem.name;
document.getElementById('locationValue').value = aItem.url;
}
else
{
var noneSelected = this.mBundle.getString("subscribe-noFeedSelected");
document.getElementById('nameValue').value = noneSelected;
document.getElementById('locationValue').value = "";
}
for (i = 0; i < ids.length; ++i)
document.getElementById(ids[i]).disabled = !aItem || aItem.container;
},
onRSSFeedSelected: function ()
{
var properties, item;
var seln = this.mTree.view.selection;
item = this.mView.getItemAtIndex(seln.currentIndex);
this.updateFeedData(item);
document.getElementById("removeFeed").disabled = !item || item.container;
},
removeFeed: function ()
{
var seln = this.mView.selection;
if (seln.count != 1) return;
var itemToRemove = this.mView.getItemAtIndex(seln.currentIndex);
if (!itemToRemove)
return;
// ask the user if he really wants to unsubscribe from the feed
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(IPS);
var abortRemoval = promptService.confirmEx(window, this.mBundle.getString('subsribe-confirmFeedDeletionTitle'),
this.mBundle.getFormattedString('subsribe-confirmFeedDeletion', [itemToRemove.name], 1),
(IPS.BUTTON_TITLE_YES * IPS.BUTTON_POS_0) + (IPS.BUTTON_TITLE_NO * IPS.BUTTON_POS_1),
null, null, null, null, { });
if (abortRemoval)
return;
var resource = rdf.GetResource(itemToRemove.url);
var feed = new Feed(resource);
var ds = getSubscriptionsDS(this.mRSSServer);
if (feed && ds)
{
// remove the feed from the subscriptions ds
var feeds = getSubscriptionsList(this.mRSSServer);
var index = feeds.IndexOf(resource);
if (index != -1)
feeds.RemoveElementAt(index, false);
// remove the feed property string from the folder data base
var currentFolder = ds.GetTarget(resource, FZ_DESTFOLDER, true);
if (currentFolder)
{
var currentFolderURI = currentFolder.QueryInterface(Components.interfaces.nsIRDFResource).Value;
currentFolder = rdf.GetResource(currentFolderURI).QueryInterface(Components.interfaces.nsIMsgFolder);
var feedUrl = ds.GetTarget(resource, DC_IDENTIFIER, true);
ds.Unassert(resource, DC_IDENTIFIER, feedUrl, true);
feedUrl = feedUrl ? feedUrl.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : "";
updateFolderFeedUrl(currentFolder, feedUrl, true); // remove the old url
}
// Remove all assertions about the feed from the subscriptions database.
removeAssertions(ds, resource);
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes
// Remove all assertions about items in the feed from the items database.
var itemds = getItemsDS(this.mRSSServer);
feed.invalidateItems();
feed.removeInvalidItems();
itemds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes
}
// Now that we have removed the feed from the datasource, it is time to update our
// view layer. Start by removing the child from its parent folder object
this.mView.removeItemAtIndex(seln.currentIndex);
// If we don't have any more subscriptions pointing into
// this folder, then I think we should offer to delete it...
// Cheat and look at the feed url property to see if anyone else is still using the feed...
// you could also accomplish this by looking at some properties in the data source...
// var msgdb = currentFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null);
// var folderInfo = msgdb.dBFolderInfo;
// var oldFeedUrl = folderInfo.getCharPtrProperty("feedUrl");
// if (!oldFeedUrl) // no more feeds pointing to the folder?
// {
// try {
// var openerResource = this.mRSSServer.rootMsgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
// var folderResource = currentFolder.QueryInterface(Components.interfaces.nsIRDFResource);
// window.opener.messenger.DeleteFolders(window.opener.GetFolderDatasource(), openerResource, folderResource);
// } catch (e) { }
// }
},
// aRootFolderURI --> optional argument. The folder to initially create the new feed under.
addFeed: function(aFeedLocation, aRootFolderURI)
{
var userAddedFeed = false;
var defaultQuickMode = this.mRSSServer.getBoolAttribute('quickMode');
var feedProperties = { feedName: "", feedLocation: aFeedLocation,
serverURI: this.mRSSServer.serverURI,
serverPrettyName: this.mRSSServer.prettyName,
folderURI: aRootFolderURI,
quickMode: this.mRSSServer.getBoolAttribute('quickMode'),
newFeed: true,
result: userAddedFeed};
feedProperties = openFeedEditor(feedProperties);
// if the user hit cancel, exit without doing anything
if (!feedProperties.result)
return;
if (!feedProperties.feedLocation)
return;
// before we go any further, make sure the user is not already subscribed to this feed.
if (feedAlreadyExists(feedProperties.feedLocation, this.mRSSServer))
{
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(IPS);
promptService.alert(window, null, this.mBundle.getString("subscribe-feedAlreadySubscribed"));
return;
}
var itemResource = rdf.GetResource(feedProperties.feedLocation);
feed = new Feed(itemResource);
// if the user specified a specific folder to add the feed too, then set it here
if (feedProperties.folderURI)
{
var folderResource = rdf.GetResource(feedProperties.folderURI);
if (folderResource)
{
var folder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
if (folder && !folder.isServer)
feed.folder = folder;
}
}
// set the server for the feed
feed.server = this.mRSSServer;
feed.quickMode = feedProperties.quickMode;
// update status text
updateStatusItem('statusText', document.getElementById("bundle_newsblog").getString('subscribe-validating'));
updateStatusItem('progressMeter', 0);
// validate the feed and download the articles
// we used to pass false which caused us to skip parsing then we'd
// turn around and download the feed again so we could actually parse the items...
// But now that this operation is asynch, just kick it off once...if we change this back
// modify feedDownloadCallback.downloaded to parse the feed...
// Also, disable the Add button while we are subscribing.
document.getElementById('addFeed').setAttribute('disabled', 'true');
feed.download(true, this.mFeedDownloadCallback);
},
mFeedDownloadCallback:
{
downloaded: function(feed, aErrorCode)
{
// feed is null if our attempt to parse the feed failed
if (aErrorCode == kNewsBlogSuccess)
{
updateStatusItem('progressMeter', 100);
// if we get here...we should always have a folder by now...either
// in feed.folder or FeedItems created the folder for us....
var folder = feed.folder ? feed.folder : gFeedSubscriptionsWindow.mRSSServer.rootMsgFolder.getChildNamed(feed.name);
updateFolderFeedUrl(folder, feed.url, false);
// add feed just adds the feed we have validated and downloaded to our datasource
// it also flushes the subscription datasource
addFeed(feed.url, feed.name, folder);
// now add the feed to our view
gFeedSubscriptionsWindow.loadSubscriptions();
gFeedSubscriptionsWindow.mTree.treeBoxObject.invalidate();
if (gFeedSubscriptionsWindow.mView.rowCount > 0)
gFeedSubscriptionsWindow.mTree.view.selection.select(0);
}
else if (aErrorCode == kNewsBlogInvalidFeed) // the feed was bad...
window.alert(gFeedSubscriptionsWindow.mBundle.getFormattedString('newsblog-invalidFeed', [feed.url]));
else if (aErrorCode == kNewsBlogRequestFailure)
window.alert(gFeedSubscriptionsWindow.mBundle.getFormattedString('newsblog-networkError', [feed.url]));
// re-enable the add button now that we are done subscribing
document.getElementById('addFeed').removeAttribute('disabled');
// our operation is done...clear out the status text and progressmeter
setTimeout(clearStatusInfo, 1000);
},
// this gets called after the RSS parser finishes storing a feed item to disk
// aCurrentFeedItems is an integer corresponding to how many feed items have been downloaded so far
// aMaxFeedItems is an integer corresponding to the total number of feed items to download
onFeedItemStored: function (feed, aCurrentFeedItems, aMaxFeedItems)
{
updateStatusItem('statusText', gFeedSubscriptionsWindow.mBundle.getFormattedString("subscribe-fetchingFeedItems",
[aCurrentFeedItems, aMaxFeedItems]));
this.onProgress(feed, aCurrentFeedItems, aMaxFeedItems);
},
onProgress: function(feed, aProgress, aProgressMax)
{
updateStatusItem('progressMeter', (aProgress * 100) / aProgressMax);
},
}
};
// opens the feed properties dialog
function openFeedEditor(aFeedProperties)
{
window.openDialog('chrome://messenger-newsblog/content/feed-properties.xul', 'feedproperties', 'modal,titlebar,chrome,center', aFeedProperties);
return aFeedProperties;
}
function processDrop()
{
gFeedSubscriptionsWindow.addFeed(gFeedSubscriptionsWindow.mView.mDropUrl, gFeedSubscriptionsWindow.mView.mDropFolderUrl);
}
// status helper routines
function updateStatusItem(aID, aValue)
{
var el = document.getElementById(aID);
if (el.getAttribute('collapsed'))
el.removeAttribute('collapsed');
el.value = aValue;
}
function clearStatusInfo()
{
document.getElementById('statusText').value = "";
document.getElementById('progressMeter').collapsed = true;
}
function doEdit() {
// XXX There should be some way of correlating feed RDF resources
// with their corresponding Feed objects. Perhaps in the end much
// of this code could hang off methods of the Feed object.
var ds = getSubscriptionsDS(this.mRSSServer);
var tree = document.getElementById('subscriptions');
var item = tree.view.getItemAtIndex(tree.view.selection.currentIndex);
var resource = rdf.GetResource(item.id);
var old_url = ds.GetTarget(resource, DC_IDENTIFIER, true);
old_url = old_url ? old_url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : "";
var feed = new Feed(resource);
var currentFolder = ds.GetTarget(resource, FZ_DESTFOLDER, true);
var currentFolderURI = currentFolder.QueryInterface(Components.interfaces.nsIRDFResource).Value;
currentFolder = rdf.GetResource(currentFolderURI).QueryInterface(Components.interfaces.nsIMsgFolder);
var userModifiedFeed = false;
var feedProperties = { feedLocation: old_url, serverURI: this.mRSSServer.serverURI,
serverPrettyName: this.mRSSServer.prettyName, folderURI: currentFolderURI,
quickMode: feed.quickMode, result: userModifiedFeed};
feedProperties = openFeedEditor(feedProperties);
if (!feedProperties.result) // did the user cancel?
return;
// did the user change the folder URI for storing the feed?
if (feedProperties.folderURI && feedProperties.folderURI != currentFolderURI)
{
// unassert the older URI, add an assertion for the new URI...
ds.Change(resource, FZ_DESTFOLDER, currentFolder, rdf.GetResource(feedProperties.folderURI));
// we need to update the feed url attributes on the databases for each folder
var folderResource = rdf.GetResource(feedProperties.folderURI);
var newFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
currentFolder = rdf.GetResource(currentFolderURI).QueryInterface(Components.interfaces.nsIMsgFolder);
updateFolderFeedUrl(currentFolder, old_url, true); // remove our feed url property from the current folder
updateFolderFeedUrl(newFolder, feedProperties.feedLocation, false); // add our feed url property to the new folder
currentFolder = newFolder; // the folder has changed
}
// check to see if the location changed
if (feedProperties.feedLocation && feedProperties.feedLocation != old_url)
{
ds.Change(resource, DC_IDENTIFIER, rdf.GetLiteral(old_url), rdf.GetLiteral(feedProperties.feedLocation));
// now update our feed url property on the destination folder
updateFolderFeedUrl(currentFolder, old_url, false); // remove the old url
updateFolderFeedUrl(currentFolder, feedProperties.feedLocation, true); // add the new one
}
// check to see if the quickMode value changed
if (feed.quickMode != feedProperties.quickMode)
feed.quickMode = feedProperties.quickMode;
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes
}

Просмотреть файл

@ -0,0 +1,130 @@
<?xml version="1.0"?>
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Subscription Manager
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
<?xml-stylesheet href="chrome://messenger/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://messenger-newsblog/skin/feed-subscriptions.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger-newsblog/locale/feed-subscriptions.dtd">
<window id="subscriptionsDialog"
title="&newsBlogSubscriptions.label;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
style="width: 30em; height: 25em;"
persist="width height"
onload="gFeedSubscriptionsWindow.init();"
onunload="return gFeedSubscriptionsWindow.uninit();"
windowtype="Mail:News-BlogSubscriptions"
flex="1">
<script type="application/x-javascript" src="utils.js"/>
<script type="application/x-javascript" src="file-utils.js"/>
<script type="application/x-javascript" src="debug-utils.js"/>
<script type="application/x-javascript" src="feed-subscriptions.js"/>
<script type="application/x-javascript" src="Feed.js"/>
<script type="application/x-javascript" src="FeedItem.js"/>
<script type="application/x-javascript" src="feed-parser.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsDragAndDrop.js"/>
<script type="application/x-javascript" src="chrome://global/content/nsTransferable.js"/>
<keyset id="extensionsKeys">
<key id="key_close" key="&cmd.close.commandKey;" modifiers="accel" oncommand="window.close();"/>
<key id="key_close2" keycode="VK_ESCAPE" oncommand="window.close();"/>
</keyset>
<stringbundle id="bundle_newsblog" src="chrome://messenger-newsblog/locale/newsblog.properties"/>
<description>&subscriptionDesc.label;</description>
<separator class="thin"/>
<tree id="rssSubscriptionsList" flex="1" style="height: 10em;"
hidecolumnpicker="true"
onselect="gFeedSubscriptionsWindow.onRSSFeedSelected();"
seltype="single">
<treecols>
<treecol id="folderNameCol" flex="2" primary="true" hideheader="true"/>
# <splitter class="tree-splitter"/>
# <treecol id="nameCol" label="&cookiename.label;" flex="1" persist="width"/>
</treecols>
<treechildren id="subscriptionChildren"/>
</tree>
<hbox id="rssFeedInfoBox">
<stack flex="1">
<hbox id="backgroundBox" flex="1"/>
<grid flex="1">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox pack="end"><label id="nameLabel" value="&feedTitle.label;"/></hbox>
<textbox id="nameValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="locationLabel" value="&location.label;"/></hbox>
<textbox id="locationValue" readonly="true" class="plain"/>
</row>
</rows>
</grid>
</stack>
</hbox>
<hbox id="statusContainerBox" align="center">
<label id="statusText" class="statusbarpanel-text" crop="right" flex="1"/>
<progressmeter id="progressMeter" collapsed="true" class="progressmeter-statusbar" style="margin-right: 5px;" mode="normal" value="0"/>
</hbox>
<hbox align="end">
<hbox class="actionButtons" flex="1">
<button id="addFeed"
label="&button.addFeed.label;" accesskey="&button.addFeed.accesskey;"
oncommand="gFeedSubscriptionsWindow.addFeed();"/>
<button id="removeFeed" disabled="true"
label="&button.removeFeed.label;" accesskey="&button.removeFeed.accesskey;"
oncommand="gFeedSubscriptionsWindow.removeFeed();"/>
</hbox>
<resizer dir="bottomright"/>
</hbox>
</window>

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -17,8 +17,8 @@
if (lastSubscriptionWindow)
lastSubscriptionWindow.focus();
else
window.openDialog("chrome://messenger-newsblog/content/subscriptions.xul", "",
"centerscreen,resizable=yes", { server: aRSSServer});
window.openDialog("chrome://messenger-newsblog/content/feed-subscriptions.xul", "",
"centerscreen,chrome,dialog=no,resizable", { server: aRSSServer});
}
function openSubscriptionsDialogFromFolderPane()

Просмотреть файл

@ -1,4 +1,41 @@
// XXX Rename this to global.js
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Utils
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Myk Melez <myk@mozilla.org>
# Scott MacGregor <mscott@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 ******
// Whether or not to dump debugging messages to the console.
const DEBUG = false;
@ -8,10 +45,7 @@ if (DEBUG)
else
debug = function() {}
var rdf =
Components
.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
const RDF_TYPE = rdf.GetResource(RDF_NS + "type");
@ -47,40 +81,44 @@ const RDF_LITERAL_TRUE = rdf.GetLiteral("true");
const RDF_LITERAL_FALSE = rdf.GetLiteral("false");
// XXX There's a containerutils in forumzilla.js that this should be merged with.
var containerUtils =
Components
.classes["@mozilla.org/rdf/container-utils;1"]
.getService(Components.interfaces.nsIRDFContainerUtils);
var containerUtils = Components.classes["@mozilla.org/rdf/container-utils;1"]
.getService(Components.interfaces.nsIRDFContainerUtils);
var fileHandler =
Components
.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.getProtocolHandler("file")
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
var fileHandler = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService)
.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
function addFeed(url, title, destFolder) {
var ds = getSubscriptionsDS(destFolder.server);
var feeds = getSubscriptionsList(destFolder.server);
// helper routine that checks our subscriptions list array and returns true if the url
// is already in our list. This is used to prevent the user from subscribing to the same
// feed multiple times for the same server...
function feedAlreadyExists(aUrl, aServer)
{
var feeds = getSubscriptionsList(aServer);
return feeds.IndexOf(rdf.GetResource(aUrl)) != -1;
}
// Generate a unique ID for the feed.
var id = url;
var i = 1;
while (feeds.IndexOf(rdf.GetResource(id)) != -1 && ++i < 1000)
id = url + i;
if (id == 1000)
throw("couldn't generate a unique ID for feed " + url);
function addFeed(url, title, destFolder)
{
var ds = getSubscriptionsDS(destFolder.server);
var feeds = getSubscriptionsList(destFolder.server);
// Add the feed to the list.
id = rdf.GetResource(id);
feeds.AppendElement(id);
ds.Assert(id, RDF_TYPE, FZ_FEED, true);
ds.Assert(id, DC_IDENTIFIER, rdf.GetLiteral(url), true);
if (title)
ds.Assert(id, DC_TITLE, rdf.GetLiteral(title), true);
ds.Assert(id, FZ_DESTFOLDER, destFolder, true);
ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
ds.Flush();
// Generate a unique ID for the feed.
var id = url;
var i = 1;
while (feeds.IndexOf(rdf.GetResource(id)) != -1 && ++i < 1000)
id = url + i;
if (id == 1000)
throw("couldn't generate a unique ID for feed " + url);
// Add the feed to the list.
id = rdf.GetResource(id);
feeds.AppendElement(id);
ds.Assert(id, RDF_TYPE, FZ_FEED, true);
ds.Assert(id, DC_IDENTIFIER, rdf.GetLiteral(url), true);
if (title)
ds.Assert(id, DC_TITLE, rdf.GetLiteral(title), true);
ds.Assert(id, FZ_DESTFOLDER, destFolder, true);
ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
ds.Flush();
}
// updates the "feedUrl" property in the message database for the folder in question.
@ -106,12 +144,15 @@ function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl)
msgdb.Close(true);
}
function getNodeValue(node) {
function getNodeValue(node)
{
if (node && node.textContent)
return node.textContent;
else if (node && node.firstChild) {
else if (node && node.firstChild)
{
var ret = "";
for (var child = node.firstChild; child; child = child.nextSibling) {
for (var child = node.firstChild; child; child = child.nextSibling)
{
var value = getNodeValue(child);
if (value)
ret += value;
@ -124,9 +165,11 @@ function getNodeValue(node) {
return null;
}
function getRDFTargetValue(ds, source, property) {
function getRDFTargetValue(ds, source, property)
{
var node = ds.GetTarget(source, property, true);
if (node) {
if (node)
{
node = node.QueryInterface(Components.interfaces.nsIRDFLiteral);
if (node)
return node.Value;
@ -135,31 +178,34 @@ function getRDFTargetValue(ds, source, property) {
}
var gFzSubscriptionsDS; // cache
function getSubscriptionsDS(server) {
if (gFzSubscriptionsDS)
return gFzSubscriptionsDS;
var file = getSubscriptionsFile(server);
var url = fileHandler.getURLSpecFromFile(file);
gFzSubscriptionsDS = rdf.GetDataSourceBlocking(url);
if (!gFzSubscriptionsDS)
throw("can't get subscriptions data source");
function getSubscriptionsDS(server)
{
if (gFzSubscriptionsDS)
return gFzSubscriptionsDS;
var file = getSubscriptionsFile(server);
var url = fileHandler.getURLSpecFromFile(file);
gFzSubscriptionsDS = rdf.GetDataSourceBlocking(url);
if (!gFzSubscriptionsDS)
throw("can't get subscriptions data source");
return gFzSubscriptionsDS;
}
function getSubscriptionsList(server) {
var ds = getSubscriptionsDS(server);
var list = ds.GetTarget(FZ_ROOT, FZ_FEEDS, true);
//list = feeds.QueryInterface(Components.interfaces.nsIRDFContainer);
list = list.QueryInterface(Components.interfaces.nsIRDFResource);
list = containerUtils.MakeSeq(ds, list);
return list;
function getSubscriptionsList(server)
{
var ds = getSubscriptionsDS(server);
var list = ds.GetTarget(FZ_ROOT, FZ_FEEDS, true);
//list = feeds.QueryInterface(Components.interfaces.nsIRDFContainer);
list = list.QueryInterface(Components.interfaces.nsIRDFResource);
list = containerUtils.MakeSeq(ds, list);
return list;
}
function getSubscriptionsFile(server) {
function getSubscriptionsFile(server)
{
server.QueryInterface(Components.interfaces.nsIRssIncomingServer);
var file = server.subscriptionsDataSourcePath;
@ -170,7 +216,8 @@ function getSubscriptionsFile(server) {
return file;
}
function createSubscriptionsFile(file) {
function createSubscriptionsFile(file)
{
file = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
file.write('\
<?xml version="1.0"?>\n\
@ -189,31 +236,32 @@ function createSubscriptionsFile(file) {
}
var gFzItemsDS; // cache
function getItemsDS(server) {
if (gFzItemsDS)
return gFzItemsDS;
var file = getItemsFile(server);
var url = fileHandler.getURLSpecFromFile(file);
gFzItemsDS = rdf.GetDataSourceBlocking(url);
if (!gFzItemsDS)
throw("can't get subscriptions data source");
// Note that it this point the datasource may not be loaded yet.
// You have to QueryInterface it to nsIRDFRemoteDataSource and check
// its "loaded" property to be sure. You can also attach an observer
// which will get notified when the load is complete.
function getItemsDS(server)
{
if (gFzItemsDS)
return gFzItemsDS;
var file = getItemsFile(server);
var url = fileHandler.getURLSpecFromFile(file);
gFzItemsDS = rdf.GetDataSourceBlocking(url);
if (!gFzItemsDS)
throw("can't get subscriptions data source");
// Note that it this point the datasource may not be loaded yet.
// You have to QueryInterface it to nsIRDFRemoteDataSource and check
// its "loaded" property to be sure. You can also attach an observer
// which will get notified when the load is complete.
return gFzItemsDS;
}
function getItemsFile(server) {
function getItemsFile(server)
{
server.QueryInterface(Components.interfaces.nsIRssIncomingServer);
var file = server.feedItemsDataSourcePath;
// If the file doesn't exist, create it.
if (!file.exists()) {
if (!file.exists())
{
var newfile = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
newfile.write('\
<?xml version="1.0"?>\n\
@ -227,51 +275,57 @@ function getItemsFile(server) {
return file;
}
function removeAssertions(ds, resource) {
var properties = ds.ArcLabelsOut(resource);
var property;
while (properties.hasMoreElements()) {
property = properties.getNext();
var values = ds.GetTargets(resource, property, true);
var value;
while (values.hasMoreElements()) {
value = values.getNext();
ds.Unassert(resource, property, value, true);
}
function removeAssertions(ds, resource)
{
var properties = ds.ArcLabelsOut(resource);
var property;
while (properties.hasMoreElements())
{
property = properties.getNext();
var values = ds.GetTargets(resource, property, true);
var value;
while (values.hasMoreElements())
{
value = values.getNext();
ds.Unassert(resource, property, value, true);
}
}
}
// Date validator for RSS feeds
const FZ_RFC822_RE = "^(((Mon)|(Tue)|(Wed)|(Thu)|(Fri)|(Sat)|(Sun)), *)?\\d\\d?"
+ " +((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))"
+ " +\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? +(([+-]?\\d\\d\\d\\d)|(UT)|(GMT)"
+ "|(EST)|(EDT)|(CST)|(CDT)|(MST)|(MDT)|(PST)|(PDT)|\\w)$";
function isValidRFC822Date(pubDate){
var regex = new RegExp(FZ_RFC822_RE);
return regex.test(pubDate);
function isValidRFC822Date(pubDate)
{
var regex = new RegExp(FZ_RFC822_RE);
return regex.test(pubDate);
}
function dateRescue(dateString){
function dateRescue(dateString)
{
// Deal with various kinds of invalid dates
// Just timestamps for now.
if(!isNaN(parseInt(dateString))) {//It's an integer, so maybe it's a timestamp
if(!isNaN(parseInt(dateString)))
{ //It's an integer, so maybe it's a timestamp
var d = new Date(parseInt(dateString)*1000);
var now = new Date();
var yeardiff = now.getFullYear()-d.getFullYear();
debug("Rescue Timestamp date: " + d.toString() + "\nYear diff:" + yeardiff + "\n");
if((yeardiff >= 0) && (yeardiff<3)){
if((yeardiff >= 0) && (yeardiff<3))
{
//it's quite likely the correct date
return d.toString();
}
}
// Can't help. Set to current time.
return (new Date()).toString();
}
}
// Could be a prototype on String, but I don't know the policy on that
function trimString(s){
return(s.replace(/^\s+/,'').replace(/\s+$/,''));
function trimString(s)
{
return(s.replace(/^\s+/,'').replace(/\s+$/,''));
}

Просмотреть файл

@ -1,16 +1,16 @@
newsblog.jar:
* content/messenger-newsblog/toolbar-icon.xul (content/toolbar-icon.xul)
* content/messenger-newsblog/subscriptions.xul (content/subscriptions.xul)
* content/messenger-newsblog/edittree.xml (content/edittree.xml)
* content/messenger-newsblog/debug-utils.js (content/debug-utils.js)
* content/messenger-newsblog/Feed.js (content/Feed.js)
* content/messenger-newsblog/FeedItem.js (content/FeedItem.js)
* content/messenger-newsblog/feed-parser.js (content/feed-parser.js)
* content/messenger-newsblog/file-utils.js (content/file-utils.js)
* content/messenger-newsblog/subscriptions.js (content/subscriptions.js)
* content/messenger-newsblog/utils.js (content/utils.js)
* content/messenger-newsblog/feed-properties.xul (content/feed-properties.xul)
* content/messenger-newsblog/feed-properties.js (content/feed-properties.js)
* content/messenger-newsblog/feed-subscriptions.js (content/feed-subscriptions.js)
* content/messenger-newsblog/feed-subscriptions.xul (content/feed-subscriptions.xul)
* content/messenger-newsblog/am-newsblog.xul (content/am-newsblog.xul)
* content/messenger-newsblog/am-newsblog.js (content/am-newsblog.js)
* content/messenger-newsblog/contents.rdf (content/contents.rdf)

Просмотреть файл

@ -95,9 +95,8 @@ var nsNewsBlogFeedDownloader =
if (feedUrlArray[url])
{
id = rdf.GetResource(feedUrlArray[url]);
feed = new Feed(id);
feed = new Feed(id, aFolder.server);
feed.folder = aFolder;
feed.server = aFolder.server;
gNumPendingFeedDownloads++; // bump our pending feed download count
feed.download(true, progressNotifier);
}
@ -109,21 +108,27 @@ var nsNewsBlogFeedDownloader =
if (!gExternalScriptsLoaded)
loadScripts();
// we don't support the ability to subscribe to several feeds at once yet...
// for now, abort the subscription if we are already in the middle of subscribing to a feed
// via drag and drop.
if (gNumPendingFeedDownloads)
{
debug('Aborting RSS subscription. Feed downloads already in progress\n');
return;
}
// we don't support the ability to subscribe to several feeds at once yet...
// for now, abort the subscription if we are already in the middle of subscribing to a feed
// via drag and drop.
if (gNumPendingFeedDownloads)
{
debug('Aborting RSS subscription. Feed downloads already in progress\n');
return;
}
// make sure we aren't already subscribed to this feed before we attempt to subscribe to it.
if (feedAlreadyExists(aUrl, aFolder.server))
{
aMsgWindow.statusFeedback.showStatusString(GetNewsBlogStringBundle().GetStringFromName('subscribe-feedAlreadySubscribed'));
return;
}
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var itemResource = rdf.GetResource(aUrl);
var feed = new Feed(itemResource);
feed.server = aFolder.server;
var feed = new Feed(itemResource, aFolder.server);
feed.quickMode = feed.server.getBoolAttribute('quickMode');
if (!aFolder.isServer) // if the root server, create a new folder for the feed

Просмотреть файл

@ -0,0 +1,72 @@
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Subscription CSS
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
/* ::::: Feed Subscription UI icons :::::: */
#subscriptionsDialog {
padding: 8px 10px 10px 8px;
}
#subscriptionChildren::-moz-tree-image(folderNameCol) {
margin-right: 2px;
list-style-image: url("chrome://messenger-newsblog/skin/icons/rss-feed.png");
}
#subscriptionChildren::-moz-tree-image(folderNameCol, container) {
list-style-image: url("chrome://messenger/skin/icons/folder-closed.png");
}
#subscriptionChildren::-moz-tree-image(folderNameCol, container, open) {
list-style-image: url("chrome://messenger/skin/icons/folder-open.png");
}
#rssFeedInfoBox {
border: 1px solid ThreeDShadow;
-moz-border-radius: 0px;
margin: 4px;
padding: 0px;
}
#rssFeedInfoBox textbox {
background-color: transparent;
}
#backgroundBox {
background-color: #FFFFFF;
opacity: 0.5;
}

Просмотреть файл

@ -1,6 +1,6 @@
classic.jar:
skin/classic/messenger-newsblog/subscriptions.css (subscriptions.css)
skin/classic/messenger-newsblog/newsBlogOverlay.css (newsBlogOverlay.css)
* skin/classic/messenger-newsblog/feed-subscriptions.css (feed-subscriptions.css)
* skin/classic/messenger-newsblog/newsBlogOverlay.css (newsBlogOverlay.css)
skin/classic/messenger-newsblog/icons/rss-feed.png (rss-feed.png )
skin/classic/messenger-newsblog/icons/rss-feed-new.png (rss-feed-new.png)
skin/classic/messenger-newsblog/icons/server-rss.png (server-rss.png)

Просмотреть файл

@ -0,0 +1,72 @@
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Subscription CSS
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
/* ::::: Feed Subscription UI icons :::::: */
#subscriptionsDialog {
padding: 14px;
}
#subscriptionChildren::-moz-tree-image(folderNameCol) {
margin-right: 2px;
list-style-image: url("chrome://messenger/skin/icons/folder-newsgroup.png");
}
#subscriptionChildren::-moz-tree-image(folderNameCol, container) {
list-style-image: url("chrome://messenger/skin/icons/folder-closed.png");
}
#subscriptionChildren::-moz-tree-image(folderNameCol, container, open) {
list-style-image: url("chrome://messenger/skin/icons/folder-open.png");
}
#rssFeedInfoBox {
border: 1px solid ThreeDShadow;
-moz-border-radius: 0px;
margin: 4px;
padding: 0px;
}
#rssFeedInfoBox textbox {
background-color: transparent;
}
#backgroundBox {
background-color: #FFFFFF;
opacity: 0.5;
}

Просмотреть файл

@ -1,5 +1,5 @@
classic.jar:
skin/classic/messenger-newsblog/subscriptions.css (subscriptions.css)
skin/classic/messenger-newsblog/newsBlogOverlay.css (newsBlogOverlay.css)
* skin/classic/messenger-newsblog/feed-subscriptions.css (feed-subscriptions.css)
* skin/classic/messenger-newsblog/newsBlogOverlay.css (newsBlogOverlay.css)
skin/classic/messenger-newsblog/icons/folder-search-rss.png (folder-search-rss.png)
skin/classic/messenger-newsblog/contents.rdf

Просмотреть файл

@ -1,40 +1,40 @@
/* ***** 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 RSS News & Blogs CSS Overlay style rules.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Myk Melez <myk@melez.com>
* Scott MacGregor <mscott@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 ***** */
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS Subscription CSS
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Scott MacGregor <mscott@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 ******
/* ::::: Folder Pane icons :::::: */

Просмотреть файл

Просмотреть файл

@ -1,40 +1,41 @@
/* ***** 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 RSS News & Blogs CSS Overlay style rules.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Myk Melez <myk@melez.com>
* Scott MacGregor <mscott@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 ***** */
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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 Thunderbird RSS News & Blogs CSS Overlay style rules.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Myk Melez <myk@melez.com>
# Scott MacGregor <mscott@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 ******
/* ::::: Folder Pane icons :::::: */

Просмотреть файл

Просмотреть файл

@ -1,14 +1,14 @@
<!-- Feed Properties Dialog -->
<!ENTITY window.title "News Feed Properties">
<!ENTITY window.title "Feed Properties">
<!ENTITY feedFolder.label "Store Feed Articles in: ">
<!ENTITY feedFolder.label "Store Articles in: ">
<!ENTITY feedFolder.accesskey "S">
<!ENTITY choosethisfolder.label "choose this folder">
<!ENTITY feedLocation.label "Feed URL: ">
<!ENTITY feedLocation.accesskey "F">
<!ENTITY choosethisfolder.label "choose this folder">
<!ENTITY quickMode.label "Show the article summary instead of loading the web page">
<!ENTITY quickMode.accesskey "h">

Просмотреть файл

@ -0,0 +1,14 @@
<!-- Subscription Dialog -->
<!ENTITY newsBlogSubscriptions.label "RSS Subscriptions">
<!ENTITY subscriptionDesc.label "Note: Removing or changing the folder for a feed will not effect previously downloaded articles.">
<!ENTITY feedTitle.label "Title:">
<!ENTITY location.label "Location:">
<!ENTITY button.addFeed.label "Add Feed">
<!ENTITY button.addFeed.accesskey "A">
<!ENTITY editButton.label "Edit">
<!ENTITY editButton.accesskey "E">
<!ENTITY button.removeFeed.label "Remove Feed">
<!ENTITY button.removeFeed.accesskey "R">
<!ENTITY cmd.close.commandKey "w">

Просмотреть файл

@ -2,17 +2,4 @@
<!ENTITY folderContextRSSSubscribe.label "Manage Subscriptions...">
<!ENTITY folderContextRSSSubscribe.accesskey "M">
<!-- Subscription Dialog -->
<!ENTITY newsBlogSubscriptions.label "RSS Subscriptions">
<!ENTITY subscriptionDesc.label "Manage your RSS Subscriptions.">
<!ENTITY feedNameTreeCol.label "Name">
<!ENTITY locationTreeCol.label "Location">
<!ENTITY addButton.label "Add">
<!ENTITY addButton.accesskey "A">
<!ENTITY editButton.label "Edit">
<!ENTITY editButton.accesskey "E">
<!ENTITY deleteButton.label "Delete">
<!ENTITY deleteButton.accesskey "D">
<!ENTITY feedNameTreeCol.label "Name">

Просмотреть файл

@ -3,6 +3,12 @@
subscribe-validating=Verifying the RSS feed...
subscribe-cancelSubscription=Are you sure you wish to cancel subscribing to the current feed?
subscribe-cancelSubscriptionTitle=Subscribing to a Feed...
subscribe-noFeedSelected=<no RSS feed selected>
subscribe-feedAlreadySubscribed=You already have a subscription for this feed.
#LOCALIZATION NOTE: %S is the name of the feed the user wants to unsubscribe from.
subsribe-confirmFeedDeletionTitle=Remove Feed
subsribe-confirmFeedDeletion=Are you sure you want to unsubscribe from the feed: \n %S?
# when downloading new feed items from the subscribe dialog.
# LOCALIZATION NOTE: Do not translate %d in the following line.

Просмотреть файл

@ -131,6 +131,7 @@
* locale/@AB_CD@/messenger-newsblog/contents.rdf (generic/chrome/messenger-newsblog/contents.rdf)
locale/@AB_CD@/messenger-newsblog/newsblog.dtd (@AB_CD@/chrome/messenger-newsblog/newsblog.dtd)
locale/@AB_CD@/messenger-newsblog/newsblog.properties (@AB_CD@/chrome/messenger-newsblog/newsblog.properties)
locale/@AB_CD@/messenger-newsblog/feed-subscriptions.dtd (@AB_CD@/chrome/messenger-newsblog/feed-subscriptions.dtd)
locale/@AB_CD@/messenger-newsblog/feed-properties.dtd (@AB_CD@/chrome/messenger-newsblog/feed-properties.dtd)
locale/@AB_CD@/messenger-newsblog/am-newsblog.properties (@AB_CD@/chrome/messenger-newsblog/am-newsblog.properties)
locale/@AB_CD@/messenger-newsblog/am-newsblog.dtd (@AB_CD@/chrome/messenger-newsblog/am-newsblog.dtd)