зеркало из https://github.com/mozilla/snowl.git
292 строки
9.9 KiB
JavaScript
292 строки
9.9 KiB
JavaScript
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Snowl.
|
|
*
|
|
* The Initial Developer of the Original Code is Mozilla.
|
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Myk Melez <myk@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 Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const Cr = Components.results;
|
|
const Cu = Components.utils;
|
|
|
|
// modules that come with Firefox
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
// modules that are generic
|
|
Cu.import("resource://snowl/modules/log4moz.js");
|
|
Cu.import("resource://snowl/modules/Observers.js");
|
|
Cu.import("resource://snowl/modules/URI.js");
|
|
|
|
// Snowl-specific modules
|
|
Cu.import("resource://snowl/modules/service.js");
|
|
Cu.import("resource://snowl/modules/datastore.js");
|
|
Cu.import("resource://snowl/modules/feed.js");
|
|
Cu.import("resource://snowl/modules/twitter.js");
|
|
|
|
window.addEventListener("load", function() { Subscriber.init() }, false);
|
|
|
|
function SubscriptionListener(subject, topic, data) {
|
|
// FIXME: figure out why the SubscriptionListener hangs around and gets called
|
|
// sometimes after the page has been unloaded and Subscriber is not defined.
|
|
if (typeof Subscriber == "undefined") {
|
|
Log4Moz.Service.getLogger("Snowl.SubscriptionListener").warn(
|
|
"called without Subscriber; subject: " + subject + "; topic: " + topic +
|
|
"; data: " + data);
|
|
return;
|
|
}
|
|
|
|
let source = Subscriber.feed;
|
|
|
|
// Don't track the status of subscriptions happening in other windows/tabs.
|
|
if (subject != source)
|
|
return;
|
|
|
|
let statusBox = document.getElementById("statusBox");
|
|
let statusMessage = document.getElementById("statusMessage");
|
|
|
|
function setStatus(code, message) {
|
|
statusBox.setAttribute("status", code);
|
|
|
|
while (statusMessage.hasChildNodes())
|
|
statusMessage.removeChild(statusMessage.firstChild);
|
|
|
|
// Append a child node so it wraps if it's too long to fit on one line.
|
|
// XXX Is there something we can do so the UI doesn't resize midstream?
|
|
statusMessage.appendChild(document.createTextNode(message));
|
|
}
|
|
|
|
let identity = source.name ||
|
|
(source.humanURI ? source.humanURI.spec : null) ||
|
|
(source.machineURI ? source.machineURI.spec : null) ||
|
|
"unnamed source";
|
|
|
|
switch(topic) {
|
|
case "snowl:subscribe:connect:start":
|
|
setStatus("active", "Connecting to " + identity);
|
|
break;
|
|
case "snowl:subscribe:connect:end":
|
|
let code, message;
|
|
|
|
if (data == "duplicate") {
|
|
code = "error";
|
|
message = "Already subscribed to " + identity;
|
|
}
|
|
else if (data < 200 || data > 299) {
|
|
code = "error";
|
|
message = "Error connecting to " + identity;
|
|
if (data == 401) {
|
|
message += ": your credentials were not accepted. Please check " +
|
|
"your username and password and try again.";
|
|
}
|
|
}
|
|
else {
|
|
// Under most circumstances, this message will be replaced immediately
|
|
// by the "getting messages" message.
|
|
code = "complete";
|
|
message = "Connected to " + identity;
|
|
}
|
|
|
|
setStatus(code, message);
|
|
break;
|
|
case "snowl:subscribe:get:start":
|
|
setStatus("active", "Getting messages for " + identity);
|
|
break;
|
|
case "snowl:subscribe:get:progress":
|
|
break;
|
|
case "snowl:subscribe:get:end":
|
|
setStatus("complete", "You have subscribed to " + identity);
|
|
break;
|
|
}
|
|
}
|
|
|
|
let Subscriber = {
|
|
_log: Log4Moz.Service.getLogger("Snowl.Subscriber"),
|
|
|
|
|
|
//**************************************************************************//
|
|
// Initialization & Destruction
|
|
|
|
init: function() {
|
|
Observers.add(SubscriptionListener, "snowl:subscribe:connect:start");
|
|
Observers.add(SubscriptionListener, "snowl:subscribe:connect:end");
|
|
Observers.add(SubscriptionListener, "snowl:subscribe:get:start");
|
|
Observers.add(SubscriptionListener, "snowl:subscribe:get:progress");
|
|
Observers.add(SubscriptionListener, "snowl:subscribe:get:end");
|
|
|
|
// Parse URL parameters
|
|
let paramString = window.location.search.substr(1);
|
|
let params = {};
|
|
for each (let param in paramString.split("&")) {
|
|
let [name, value] = param.split("=");
|
|
if (value)
|
|
params[name] = decodeURIComponent(value);
|
|
else
|
|
params[name] = value;
|
|
}
|
|
|
|
if (params.feed) {
|
|
document.getElementById("locationTextbox").value = params.feed;
|
|
this.subscribeFeed();
|
|
}
|
|
else if (params.tab) {
|
|
let tabbox = document.getElementById("tabbox");
|
|
switch (params.tab) {
|
|
// The feed tab is selected by default.
|
|
case "twitter":
|
|
tabbox.selectedTab = document.getElementById("twitterTab");
|
|
break;
|
|
case "opml":
|
|
tabbox.selectedTab = document.getElementById("opmlTab");
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
destroy: function() {
|
|
Observers.remove(SubscriptionListener, "snowl:subscribe:connect:start");
|
|
Observers.remove(SubscriptionListener, "snowl:subscribe:connect:end");
|
|
Observers.remove(SubscriptionListener, "snowl:subscribe:get:start");
|
|
Observers.remove(SubscriptionListener, "snowl:subscribe:get:progress");
|
|
Observers.remove(SubscriptionListener, "snowl:subscribe:get:end");
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// Event Handlers
|
|
|
|
subscribeFeed: function() {
|
|
let uri = URI.get(document.getElementById("locationTextbox").value);
|
|
let feed = new SnowlFeed(null, null, null, uri);
|
|
this._subscribe(feed);
|
|
},
|
|
|
|
importOPML: function() {
|
|
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
|
fp.init(window, "Import OPML", Ci.nsIFilePicker.modeOpen);
|
|
fp.appendFilter("OPML Files", "*.opml");
|
|
fp.appendFilters(Ci.nsIFilePicker.filterXML);
|
|
fp.appendFilters(Ci.nsIFilePicker.filterAll);
|
|
|
|
let rv = fp.show();
|
|
if (rv != Ci.nsIFilePicker.returnOK)
|
|
return;
|
|
|
|
// FIXME: use a file utility to open the file instead of XMLHttpRequest.
|
|
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
|
createInstance(Ci.nsIXMLHttpRequest);
|
|
request.open("GET", fp.fileURL.spec, false);
|
|
// Since the file probably ends in .opml, we have to force XHR to treat it
|
|
// as XML by overriding the MIME type it would otherwise select.
|
|
request.overrideMimeType("text/xml");
|
|
request.send(null);
|
|
let xmlDocument = request.responseXML;
|
|
|
|
let outline = xmlDocument.getElementsByTagName("body")[0];
|
|
|
|
this._importOutline(outline);
|
|
},
|
|
|
|
showTwitterPassword: function() {
|
|
if (document.getElementById("showTwitterPassword").checked)
|
|
document.getElementById("twitterPassword").removeAttribute("type");
|
|
else
|
|
document.getElementById("twitterPassword").setAttribute("type", "password");
|
|
},
|
|
|
|
subscribeTwitter: function() {
|
|
let credentials = {
|
|
username: document.getElementById("twitterUsername").value,
|
|
password: document.getElementById("twitterPassword").value,
|
|
remember: document.getElementById("rememberTwitterPassword").checked
|
|
};
|
|
|
|
let twitter = new SnowlTwitter();
|
|
|
|
// FIXME: call this "source" instead of "feed".
|
|
this.feed = twitter;
|
|
|
|
twitter.subscribe(credentials);
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// OPML Import
|
|
|
|
_importOutline: strand(function(aOutline) {
|
|
// If this outline represents a feed, subscribe the user to the feed.
|
|
let uri = URI.get(aOutline.getAttribute("xmlUrl"));
|
|
if (uri) {
|
|
let name = aOutline.getAttribute("title") || aOutline.getAttribute("text");
|
|
let feed = new SnowlFeed(null, name || "untitled", uri);
|
|
|
|
let future = new Future();
|
|
this._subscribe(feed, future.fulfill);
|
|
yield future.result();
|
|
}
|
|
|
|
if (aOutline.hasChildNodes()) {
|
|
let children = aOutline.childNodes;
|
|
for (let i = 0; i < children.length; i++) {
|
|
let child = children[i];
|
|
|
|
// Only deal with "outline" elements; ignore text, etc. nodes.
|
|
if (child.nodeName != "outline")
|
|
continue;
|
|
|
|
yield this._importOutline(child);
|
|
}
|
|
}
|
|
}),
|
|
|
|
_subscribe: strand(function(feed, callback) {
|
|
// Store a reference to the feed to which we are currently subscribing
|
|
// so the progress listener can filter out events for some other feed.
|
|
this.feed = feed;
|
|
|
|
if (SnowlService.hasSource(feed.machineURI.spec)) {
|
|
Observers.notify(this.feed, "snowl:subscribe:connect:end", "duplicate");
|
|
return;
|
|
}
|
|
|
|
let future = new Future();
|
|
feed.subscribe(future.fulfill);
|
|
yield future.result();
|
|
|
|
this.feed = null;
|
|
|
|
if (callback)
|
|
callback();
|
|
})
|
|
|
|
};
|