move subscribe function into Options, various glue to support this, localize subscribe status messages. only feed subscriptions (via rss icon/link click feed preview handler) displayed in a page now.

This commit is contained in:
alta88 2008-11-15 18:29:31 -07:00
Родитель d048b55d5d
Коммит 8df73548c8
14 изменённых файлов: 371 добавлений и 299 удалений

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

@ -251,13 +251,11 @@ let Snowl = {
},
onSubscribe: function() {
gBrowser.selectedTab =
gBrowser.addTab("chrome://snowl/content/subscribe.xul");
openPreferences("paneSnowl", { "snowlTab" : "snowlPrefsTabSubscribe" });
},
onImportOPML: function() {
gBrowser.selectedTab =
gBrowser.addTab("chrome://snowl/content/subscribe.xul?tab=opml");
Subscriber.importOPML();
},
onExportOPML: function() {

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

@ -45,6 +45,9 @@
id="snowlBrowserOverlay">
<script type="application/javascript" src="chrome://snowl/content/browser.js"/>
<!-- Include strands.js and subscribe.js for onImportOPML -->
<script type="application/javascript" src="chrome://snowl/content/strands.js"/>
<script type="application/javascript" src="chrome://snowl/content/subscribe.js"/>
<menupopup id="viewSidebarMenu">
<menuitem observes="viewSnowlList" label="&listViewSidebarMenuItem.label;"

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

@ -38,11 +38,13 @@
- ***** END LICENSE BLOCK ***** -->
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript"><![CDATA[
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
<script type="application/x-javascript"><![CDATA[
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
try {
win.openPreferences("paneSnowl");
window.close();
]]></script>
} catch (e) {};
window.close();
]]></script>
</dialog>

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

@ -60,3 +60,38 @@ radio[pane="paneSnowl"]:active {
padding-bottom: 10px;
}
/******************************************************************************/
/* Subscribe tab */
#statusIcon[status="active"] {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}
#statusIcon[status="complete"] {
list-style-image: url("chrome://snowl/content/icons/tick.png");
}
#statusIcon[status="error"] {
list-style-image: url("chrome://global/skin/icons/error-16.png");
}
/******************************************************************************/
/* Subscribe page */
content {
border: 1px solid threedshadow;
padding: 1em;
-moz-border-radius: 10px;
background-color: -moz-field;
color: -moz-fieldtext;
width: 44em;
}
#title {
font-size: 2em;
margin-top: 0;
margin-bottom: 0.5em;
border-bottom: 1px solid threedlightshadow;
}

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

@ -38,3 +38,52 @@ 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");
let SnowlPreferences = {
// Logger
get _log() {
delete this._log;
return this._log = Log4Moz.Service.getLogger("Snowl.Preferences");
},
onPaneLoad: function() {
// Select passed tab
let snowlPrefs = document.getElementById("snowlPrefs");
let extraArgs = window.arguments[1];
if (extraArgs && extraArgs["snowlTab"])
snowlPrefs.selectedTab = document.getElementById(extraArgs["snowlTab"]);
Subscriber.addObservers();
window.addEventListener("unload", function() { Subscriber.removeObservers(); }, false);
},
selectSubcribeDeck: function() {
let index = document.getElementById("subscribeRadio").selectedIndex;
let deck = document.getElementById("subscribeDeck");
deck.setAttribute("selectedIndex", index);
this.clearFields();
},
clearFields: function() {
document.getElementById("locationTextbox").value = "";
document.getElementById("nameTextbox").value = "";
document.getElementById("twitterUsername").value = "";
document.getElementById("twitterPassword").value = "";
Subscriber.setStatus("none", "");
},
}

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

@ -40,7 +40,9 @@
<!DOCTYPE overlay [
<!ENTITY % snowlPreferencesDTD SYSTEM "chrome://snowl/locale/preferences.dtd">
<!ENTITY % snowlLoginDTD SYSTEM "chrome://snowl/locale/login.dtd">
%snowlPreferencesDTD;
%snowlLoginDTD;
]>
<overlay id="snowlPreferencesPaneOverlay"
@ -49,15 +51,22 @@
<prefwindow id="BrowserPreferences">
<script type="application/x-javascript" src="chrome://snowl/content/preferences.js"/>
<script type="application/x-javascript" src="chrome://snowl/content/strands.js"/>
<script type="application/x-javascript" src="chrome://snowl/content/subscribe.js"/>
<stringbundleset id="stringbundleset">
<stringbundle id="snowlStringBundle"
src="chrome://snowl/locale/preferences.properties"/>
</stringbundleset>
<prefpane id="paneSnowl"
label="&paneSnowl.title;"
onpaneload=""
onpaneload="SnowlPreferences.onPaneLoad();"
insertbefore="paneAdvanced">
<preferences id="snowlPreferences">
<preference id="browser.preferences.snowl.selectedTabIndex"
name="browser.preferences.snowl.selectedTabIndex"
<preference id="extensions.snowl.preferences.selectedTabIndex"
name="extensions.snowl.preferences.selectedTabIndex"
type="int"/>
</preferences>
@ -87,39 +96,32 @@
gAdvancedPane.updateAutoItems();
gAdvancedPane.updateModeItems();"/>
</preferences>
<stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
<stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
-->
<script type="application/x-javascript" src="chrome://browser/content/preferences/advanced.js"/>
<tabbox id="snowlPrefs" flex="1"
onselect="SnowPreferencesPane.tabSelectionChanged();">
persist="selectedIndex">
<tabs id="snowlTabsElement">
<tab id="snowlTab1"
<tabs id="snowlPrefsTabs">
<tab id="snowlPrefsTabGeneral"
label="&generalTab.label;"
helpTopic="prefs-advanced-general"/>
<tab id="snowlTab2"
XXXhelpTopic="prefs-snowl-general"/>
<tab id="snowlPrefsTabSubscribe"
label="&subscribeTab.label;"
disabled="true"
helpTopic="prefs-advanced-network"/>
<tab id="snowlTab3"
XXXhelpTopic="prefs-snowl-subscribe"/>
<tab id="snowlPrefsTabOrganize"
label="&organizeTab.label;"
disabled="true"
helpTopic="prefs-advanced-network"/>
XXXhelpTopic="prefs-snowl-organize"/>
</tabs>
<tabpanels flex="1">
<tabpanels id="snowlPrefsPanels" flex="1">
<!-- General -->
<tabpanel id="snowlPanel1" orient="vertical">
<tabpanel id="snowlPrefsGeneralPanel" orient="vertical">
<!-- Layouts -->
<groupbox id="snowlPanel1a" align="start">
<caption label="Layouts"/>
</groupbox>
<!-- Browsing -->
<groupbox id="snowlPanel1b" align="start">
<caption label="Other"/>
@ -127,35 +129,122 @@
</tabpanel>
<!-- Subscribe -->
<tabpanel id="snowlPanel2" orient="vertical">
<tabpanel id="snowlPrefsSubscribePanel" orient="vertical">
<!-- New Source -->
<groupbox>
<!-- -->
<groupbox id="snowlPanel2a">
<caption label="snowlPanel2a"/>
<caption label="&source.label;"/>
<radiogroup id="subscribeRadio"
orient="horizontal"
oncommand="SnowlPreferences.selectSubcribeDeck()">
<radio label="&feeds.label;"
accesskey="&feeds.accesskey;"/>
<radio label="&twitter.label;"
accesskey="&twitter.accesskey;"/>
<radio label="&mail.label;" disabled="true"
accesskey="&mail.accesskey;"/>
<radio label="&newsgroup.label;" disabled="true"
accesskey="&newsgroup.accesskey;"/>
</radiogroup>
<separator class="groove-thin"/>
</groupbox>
<deck id="subscribeDeck">
<grid id="feedSubscribe">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox flex="1" pack="end">
<label control="locationTextbox" value="&location.label;"/>
</hbox>
<textbox id="locationTextbox" clickSelectsAll="true"/>
</row>
<row align="center">
<hbox flex="1" pack="end">
<label control="nameTextbox" value="&name.label;"/>
</hbox>
<textbox id="nameTextbox" readonly="true" clickSelectsAll="true"/>
</row>
<row>
<box/>
<hbox pack="start">
<button label="&subscribeButton.label;" default="true"
oncommand="Subscriber.subscribeFeed()"/>
<spacer flex="1"/>
<button label="&clearButton.label;"
oncommand="SnowlPreferences.clearFields()"/>
</hbox>
</row>
</rows>
</grid>
<grid id="twitterSubscribe">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox flex="1" pack="end">
<label control="twitterUsername" value="&username.label;"/>
</hbox>
<textbox id="twitterUsername"/>
</row>
<row align="center">
<hbox flex="1" pack="end">
<label control="twitterPassword" value="&password.label;"/>
</hbox>
<textbox id="twitterPassword" type="password"/>
</row>
<row align="center">
<box/>
<checkbox id="showTwitterPassword" label="&showPassword.label;"
oncommand="Subscriber.showTwitterPassword()"/>
</row>
<row align="center">
<box/>
<checkbox id="rememberTwitterPassword" label="&rememberPassword.label;"/>
</row>
<row>
<box/>
<hbox >
<button label="&subscribeButton.label;" default="true"
oncommand="Subscriber.subscribeTwitter()"/>
<spacer flex="1"/>
<button label="&clearButton.label;"
oncommand="SnowlPreferences.clearFields()"/>
</hbox>
</row>
</rows>
</grid>
</deck>
</groupbox>
<hbox id="statusBox">
<vbox pack="center">
<image id="statusIcon" />
</vbox>
<description id="statusMessage" flex="1"/>
</hbox>
<!-- -->
<groupbox id="snowlPanel2b">
<caption label="snowlPanel2b"/>
</groupbox>
</tabpanel>
<!-- Organize -->
<tabpanel id="snowlPanel3" orient="vertical">
<tabpanel id="snowlPrefsOrganizePanel" orient="vertical">
<!-- -->
<groupbox id="snowlPanel3a">
<caption label="snowlPanel3a"/>
</groupbox>
<!-- -->
<groupbox id="snowlPanel3b">
<caption label="snowlPanel3b"/>
</groupbox>
</tabpanel>
</tabpanel>
</tabpanels>
</tabbox>

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

@ -37,7 +37,7 @@
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://global/skin/" type"text/css"?>
<?xml-stylesheet href="chrome://snowl/content/subscribe.css" type"text/css"?>
<?xml-stylesheet href="chrome://snowl/content/preferences.css" type"text/css"?>
<!DOCTYPE page [
<!ENTITY % subscribeDTD SYSTEM "chrome://snowl/locale/sources.dtd">

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

@ -1,72 +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 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 ***** */
#content {
border: 1px solid threedshadow;
padding: 3em;
-moz-border-radius: 10px;
background-color: -moz-field;
color: -moz-fieldtext;
width: 37em;
}
#title {
font-size: 2em;
margin-top: 0;
margin-bottom: 0.5em;
border-bottom: 1px solid threedlightshadow;
}
toolbarbutton {
-moz-appearance: none;
}
.toolbarbutton-icon {
-moz-margin-end: 0;
}
#statusBox[status="active"] > #statusIcon {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}
#statusBox[status="complete"] > #statusIcon {
list-style-image: url("chrome://snowl/content/icons/tick.png");
}
#statusBox[status="error"] > #statusIcon {
list-style-image: url("chrome://global/skin/icons/error-16.png");
}

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

@ -34,30 +34,10 @@
*
* ***** 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.
// XXX: onunload added to subscribe.xul and preferences.xul, should fix this
if (typeof Subscriber == "undefined") {
Log4Moz.Service.getLogger("Snowl.SubscriptionListener").warn(
"called without Subscriber; subject: " + subject + "; topic: " + topic +
@ -71,77 +51,80 @@ function SubscriptionListener(subject, topic, data) {
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";
let code, message;
// If blank, fine
let identity = source.name;
let stringBundle = document.getElementById("snowlStringBundle");
switch(topic) {
case "snowl:subscribe:connect:start":
setStatus("active", "Connecting to " + identity);
code = "active";
message = stringBundle.getString("messageConnecting");
break;
case "snowl:subscribe:connect:end":
let code, message;
if (data == "duplicate") {
if (data.split(":")[0] == "duplicate") {
code = "error";
message = "Already subscribed to " + identity;
message = stringBundle.getString("messageDuplicate");
identity = data.split(":")[1];
}
else if (data == "invalid") {
code = "error";
message = stringBundle.getString("messageInvalid");
}
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.";
}
message = stringBundle.getString("messageConnectionError");
if (data == 401)
message = stringBundle.getString("messagePassword");
}
else {
// Under most circumstances, this message will be replaced immediately
// by the "getting messages" message.
code = "complete";
message = "Connected to " + identity;
message = stringBundle.getString("messageConnected");
}
setStatus(code, message);
break;
case "snowl:subscribe:get:start":
setStatus("active", "Getting messages for " + identity);
code = "active";
message = stringBundle.getString("messageGettingMessages");
break;
case "snowl:subscribe:get:progress":
return;
break;
case "snowl:subscribe:get:end":
setStatus("complete", "You have subscribed to " + identity);
code = "complete";
message = stringBundle.getString("messageSuccess");
break;
}
Subscriber.setStatus(code, message, identity);
}
let Subscriber = {
_log: Log4Moz.Service.getLogger("Snowl.Subscriber"),
// Logger
get _log() {
delete this._log;
return this._log = Log4Moz.Service.getLogger("Snowl.Subscribe");
},
setStatus: function(code, message, identity) {
let nameBox = document.getElementById("nameTextbox");
nameBox.setAttribute("value", identity);
let statusIcon = document.getElementById("statusIcon");
let statusMessage = document.getElementById("statusMessage");
statusIcon.setAttribute("status", code);
while (statusMessage.hasChildNodes())
statusMessage.removeChild(statusMessage.firstChild);
statusMessage.appendChild(document.createTextNode(message));
},
//**************************************************************************//
// 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");
this.addObservers();
// Parse URL parameters
let paramString = window.location.search.substr(1);
@ -156,23 +139,19 @@ let Subscriber = {
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;
}
this.subscribeFeed(params.feed);
}
},
destroy: function() {
addObservers: 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");
},
removeObservers: function() {
Observers.remove(SubscriptionListener, "snowl:subscribe:connect:start");
Observers.remove(SubscriptionListener, "snowl:subscribe:connect:end");
Observers.remove(SubscriptionListener, "snowl:subscribe:get:start");
@ -184,8 +163,15 @@ let Subscriber = {
//**************************************************************************//
// Event Handlers
subscribeFeed: function() {
let uri = URI.get(document.getElementById("locationTextbox").value);
subscribeFeed: function(url) {
let uri, typedUri;
if (!url)
// Url from user input in Options
uri = URI.get(document.getElementById("locationTextbox").value);
else
// Url passed from feedparser
uri = URI.get(url);
let feed = new SnowlFeed(null, null, null, uri);
this._subscribe(feed);
},
@ -235,6 +221,14 @@ let Subscriber = {
// FIXME: call this "source" instead of "feed".
this.feed = twitter;
// XXX: Multiple twitter subsciptions allowed? How are they differentiated?
// For now disallow since the database can be filled with bad records..
// let name = SnowlService.hasSource(twitter.machineURI.spec)
// if (name) {
// Observers.notify(this.feed, "snowl:subscribe:connect:end", "duplicate:" + name);
// return;
// }
twitter.subscribe(credentials);
},
@ -273,8 +267,14 @@ let Subscriber = {
// 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");
if (!feed.machineURI) {
Observers.notify(this.feed, "snowl:subscribe:connect:end", "invalid");
return;
}
let name = SnowlService.hasSource(feed.machineURI.spec)
if (name) {
Observers.notify(this.feed, "snowl:subscribe:connect:end", "duplicate:" + name);
return;
}

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

@ -37,114 +37,59 @@
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://global/skin/" type"text/css"?>
<?xml-stylesheet href="chrome://snowl/content/subscribe.css" type"text/css"?>
<?xml-stylesheet href="chrome://snowl/content/preferences.css" type"text/css"?>
<!DOCTYPE page [
<!ENTITY % subscribeDTD SYSTEM "chrome://snowl/locale/subscribe.dtd">
<!ENTITY % subscribeDTD SYSTEM "chrome://snowl/locale/preferences.dtd">
%subscribeDTD;
<!ENTITY % loginDTD SYSTEM "chrome://snowl/locale/login.dtd">
%loginDTD;
]>
<page title="&page.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
pack="center"
align="center">
align="center"
onload="Subscriber.init()"
onunload="Subscriber.removeObservers()">
<script type="application/x-javascript" src="chrome://snowl/content/preferences.js"/>
<script type="application/x-javascript" src="chrome://snowl/content/strands.js"/>
<script type="application/x-javascript" src="chrome://snowl/content/subscribe.js"/>
<stringbundleset id="stringbundleset">
<stringbundle id="snowlStringBundle"
src="chrome://snowl/locale/preferences.properties"/>
</stringbundleset>
<vbox id="content">
<label flex="1" value="&page.title;" class="header"/>
<separator class="groove-thin"/>
<separator class="thin" orient="horizontal"/>
<tabbox id="tabbox">
<tabs>
<tab id="feedTab" label="&feedsTab.label;"/>
<tab id="twitterTab" label="&twitterTab.label;"/>
<tab id="opmlTab" label="&opmlTab.label;"/>
</tabs>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox flex="1" pack="end">
<label control="locationTextbox" value="&location.label;"/>
</hbox>
<textbox id="locationTextbox" readonly="true" clickSelectsAll="true"/>
</row>
<row align="center">
<hbox flex="1" pack="end">
<label control="nameTextbox" value="&name.label;"/>
</hbox>
<textbox id="nameTextbox" readonly="true" clickSelectsAll="true"/>
</row>
</rows>
</grid>
<separator class="groove-thin"/>
<tabpanels>
<tabpanel orient="vertical">
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox flex="1" pack="end">
<label control="locationTextbox" value="&location.label;"/>
</hbox>
<textbox id="locationTextbox"/>
</row>
<row>
<box/>
<hbox pack="start">
<button label="&subscribeButton.label;" default="true"
oncommand="Subscriber.subscribeFeed()"/>
</hbox>
</row>
</rows>
</grid>
</tabpanel>
<tabpanel orient="vertical">
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox flex="1" pack="end">
<label control="twitterUsername" value="&username.label;"/>
</hbox>
<textbox id="twitterUsername"/>
</row>
<row align="center">
<hbox flex="1" pack="end">
<label control="twitterPassword" value="&password.label;"/>
</hbox>
<textbox id="twitterPassword" type="password"/>
</row>
<row align="center">
<box/>
<checkbox id="showTwitterPassword" label="&showPassword.label;"
oncommand="Subscriber.showTwitterPassword()"/>
</row>
<row align="center">
<box/>
<checkbox id="rememberTwitterPassword" label="&rememberPassword.label;"/>
</row>
<row>
<box/>
<hbox pack="start">
<button label="&subscribeButton.label;" default="true"
oncommand="Subscriber.subscribeTwitter()"/>
</hbox>
</row>
</rows>
</grid>
</tabpanel>
<tabpanel orient="vertical" pack="center" align="center">
<button id="importOPMLButton" label="&importOPMLButton.label;"
oncommand="Subscriber.importOPML()"/>
</tabpanel>
</tabpanels>
</tabbox>
<!-- Note: the status box should be align="baseline", but that looks ugly.
- align="center" looks ugly for multi-line messages, but those are rare,
- so this is the best option (for the moment, anyway). -->
<hbox id="statusBox" align="center">
<image id="statusIcon"/>
<!-- FIXME: figure out how to allocate space in the UI for the message
- such that setting it later doesn't resize the UI. -->
<hbox id="statusBox">
<vbox pack="center">
<image id="statusIcon"/>
</vbox>
<description id="statusMessage" flex="1"/>
</hbox>

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

@ -1,5 +1,27 @@
<!-- Snowl Options -->
<!ENTITY paneSnowl.title "Snowl">
<!ENTITY noPreferences.message "Snowl does not yet have preferences.">
<!ENTITY page.title "Snowl: Subscribe to Message Sources">
<!-- General tab -->
<!ENTITY generalTab.label "General">
<!-- Subscribe tab -->
<!ENTITY subscribeTab.label "Subscribe">
<!ENTITY source.label "New Source">
<!ENTITY feeds.label "Feed">
<!ENTITY feeds.accesskey "F">
<!ENTITY twitter.label "Twitter">
<!ENTITY twitter.accesskey "T">
<!ENTITY mail.label "Mail">
<!ENTITY mail.accesskey "M">
<!ENTITY newsgroup.label "Newsgroup">
<!ENTITY newsgroup.accesskey "N">
<!ENTITY location.label "Location:">
<!ENTITY name.label "Name:">
<!ENTITY subscribeButton.label "Subscribe">
<!ENTITY closeButton.label "Close">
<!ENTITY clearButton.label "Clear">
<!-- Organize tab -->
<!ENTITY organizeTab.label "Organize">

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

@ -0,0 +1,10 @@
# Status messages when subscribing
messageConnecting=Connecting...
messageDuplicate=You have already subscribed.
messageInvalid=The location is blank or invalid.
messageConnectionError=Connection error or location cannot be found.
messagePassword=Your credentials were not accepted. Please check your username and password and try again.
messageConnected=Connected.
messageGettingMessages=Getting messages...
messageSuccess=You have successfully subscribed.

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

@ -1,11 +0,0 @@
<!ENTITY page.title "Snowl: Subscribe to Message Sources">
<!ENTITY feedsTab.label "Feeds">
<!ENTITY twitterTab.label "Twitter">
<!ENTITY opmlTab.label "OPML">
<!ENTITY location.label "Location:">
<!ENTITY subscribeButton.label "Subscribe">
<!ENTITY importOPMLButton.label "Import OPML File...">
<!ENTITY closeButton.label "Close">

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

@ -412,23 +412,25 @@ let SnowlDatastore = {
get _selectHasSourceStatement() {
let statement = this.createStatement(
"SELECT 1 FROM sources WHERE machineURI = :machineURI"
"SELECT name FROM sources WHERE machineURI = :machineURI"
);
this.__defineGetter__("_selectHasSourceStatement", function() { return statement });
return this._selectHasSourceStatement;
},
selectHasSource: function(aMachineURI) {
let name;
try {
this._selectHasSourceStatement.params.machineURI = aMachineURI;
if (this._selectHasSourceStatement.step())
return true;
name = this._selectHasSourceStatement.row["name"];
}
finally {
this._selectHasSourceStatement.reset();
}
return false;
return name;
},
get _selectHasMessageStatement() {