changeset 359:57bbbcb76b0b

initial implementationi of writing; stream view only, still pretty hacky
author Myk Melez <myk@mozilla.org>
date Tue, 04 Nov 2008 12:24:08 -0800
parents c00b3db58dcf
children 926940f1559a
files content/icons/email_add.png content/stream.js content/stream.xul content/toolbar.js content/toolbar.xul locale/en-US/toolbar.dtd modules/opml.js modules/twitter.js
diffstat 8 files changed, 126 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
Binary file content/icons/email_add.png has changed
--- a/content/stream.js	Tue Nov 04 12:11:07 2008 -0800
+++ b/content/stream.js	Tue Nov 04 12:24:08 2008 -0800
@@ -51,6 +51,8 @@
 Cu.import("resource://snowl/modules/datastore.js");
 Cu.import("resource://snowl/modules/collection.js");
 Cu.import("resource://snowl/modules/utils.js");
+Cu.import("resource://snowl/modules/twitter.js");
+Cu.import("resource://snowl/modules/service.js");
 
 const XML_NS = "http://www.w3.org/XML/1998/namespace"
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
@@ -162,10 +164,19 @@
     this._setMidnightTimout();
 
     gBrowserWindow.Snowl._initSnowlToolbar();
+
+    // For some reason setting hidden="true" in the XUL file prevents us
+    // from showing the box later via writeBox.hidden = false.
+    // FIXME: file a bug on this abnormality.
+    let writeBox = document.getElementById("writeBox");
+    writeBox.hidden = true;
+
+    this._updateWriteButton();
   },
 
   onunLoad: function() {
     Observers.remove(this, "snowl:message:added");
+    Observers.remove(this, "snowl:sources:changed");
   },
 
   _setMidnightTimout: function() {
@@ -176,6 +187,13 @@
     window.setTimeout(function() { t.onMidnight() }, msUntilMidnight);
   },
 
+  // Selectively show/hide the button for writing a message depending on
+  // whether or not the user has an account that supports writing.
+  _updateWriteButton: function() {
+    document.getElementById("snowlWriteMessageButton").disabled =
+      (SnowlService.targets.length == 0);
+  },
+
 
   //**************************************************************************//
   // Event & Notification Handlers
@@ -226,6 +244,7 @@
   },
 
   _onSourcesChanged: function() {
+    this._updateWriteButton();
     this._rebuildView();
   },
 
@@ -233,6 +252,18 @@
     event.target.nextSibling.style.display = event.target.checked ? "block" : "none";
   },
 
+  onWriteMessage: function(event) {
+    let writeBox = document.getElementById("writeBox");
+    writeBox.hidden = !event.target.checked;
+  },
+
+  onSendMessage: function() {
+    let writeTextbox = document.getElementById("writeTextbox");
+    let content = writeTextbox.value;
+    let twitter = new SnowlTwitter();
+    twitter.send(content);
+  },
+
 
   //**************************************************************************//
   // Safe DOM Manipulation
--- a/content/stream.xul	Tue Nov 04 12:11:07 2008 -0800
+++ b/content/stream.xul	Tue Nov 04 12:24:08 2008 -0800
@@ -53,8 +53,16 @@
   <script type="application/javascript" src="chrome://snowl/content/strands.js"/>
   <script type="application/javascript" src="chrome://snowl/content/stream.js"/>
 
+  <toolbar id="snowlToolbar"/>
+
+  <vbox id="writeBox">
+    <textbox id="writeTextbox" multiline="true" rows="3"/>
+    <hbox>
+      <spacer flex="1"/>
+      <button label="Send" oncommand="SnowlMessageView.onSendMessage()"/>
+    </hbox>
+  </vbox>
+
   <vbox id="contentBox"/>
 
-  <toolbar id="snowlToolbar"/>
-
 </page>
--- a/content/toolbar.js	Tue Nov 04 12:11:07 2008 -0800
+++ b/content/toolbar.js	Tue Nov 04 12:24:08 2008 -0800
@@ -57,6 +57,9 @@
 
   onExportOPML: function() {
     SnowlOPML.export(window);
-  }
+  },
 
+  onWriteMessage: function(event) {
+    SnowlMessageView.onWriteMessage(event);
+  }
 };
--- a/content/toolbar.xul	Tue Nov 04 12:11:07 2008 -0800
+++ b/content/toolbar.xul	Tue Nov 04 12:24:08 2008 -0800
@@ -44,8 +44,7 @@
 
   <script type="application/x-javascript" src="chrome://snowl/content/toolbar.js"/>
 
-  <toolbar id="snowlToolbar"
-           persist="hidden">
+  <toolbar id="snowlToolbar" persist="hidden">
     <toolbarbutton id="snowlSubscribeButton"
                    image="chrome://snowl/content/icons/add.png"
                    oncommand="SnowlToolbar.subscribe()"
@@ -62,6 +61,11 @@
                    image="chrome://snowl/content/icons/opml-icon-16x16.png"
                    oncommand="SnowlToolbar.onExportOPML()"
                    tooltiptext="&exportButton.tooltip;"/>
+    <toolbarspring/>
+    <toolbarbutton id="snowlWriteMessageButton" type="checkbox"
+                   image="chrome://snowl/content/icons/email_add.png"
+                   oncommand="SnowlToolbar.onWriteMessage(event)"
+                   tooltiptext="&writeMessageButton.tooltip;"/>
   </toolbar>
 
 </overlay>
--- a/locale/en-US/toolbar.dtd	Tue Nov 04 12:11:07 2008 -0800
+++ b/locale/en-US/toolbar.dtd	Tue Nov 04 12:24:08 2008 -0800
@@ -2,3 +2,4 @@
 <!ENTITY unsubscribeButton.tooltip    "Unsubscribe from message sources.">
 <!ENTITY refreshButton.tooltip        "Refresh message sources.">
 <!ENTITY exportButton.tooltip         "Export message sources as OPML.">
+<!ENTITY writeMessageButton.tooltip   "Write a message.">
--- a/modules/opml.js	Tue Nov 04 12:11:07 2008 -0800
+++ b/modules/opml.js	Tue Nov 04 12:24:08 2008 -0800
@@ -100,8 +100,7 @@
     root.appendChild(body);
 
     // Populate the <body> element with <outline> elements.
-    let sources = SnowlService.getSources();
-    for each (let source in sources) {
+    for each (let source in SnowlService.sources) {
       let outline = doc.createElement("outline");
       // XXX Should we specify the |type| attribute, and should we specify
       // type="atom" for Atom feeds or just type="rss" for all feeds?
--- a/modules/twitter.js	Tue Nov 04 12:11:07 2008 -0800
+++ b/modules/twitter.js	Tue Nov 04 12:24:08 2008 -0800
@@ -556,6 +556,79 @@
 
     // Now that we've saved the login, we don't need the auth info anymore.
     this._authInfo = null;
+  },
+
+
+  //**************************************************************************//
+  // Sending
+
+  send: function(content) {
+    Observers.notify(this, "snowl:send:start", null);
+
+    let data = "status=" + encodeURIComponent(content);
+    //          + "&in_reply_to_status_id=" + encodeURIComponent(inReplyToID);
+
+    let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
+
+    request.QueryInterface(Ci.nsIDOMEventTarget);
+    let (t = this) {
+      request.addEventListener("load", function(e) { t.onSendLoad(e) }, false);
+      request.addEventListener("error", function(e) { t.onSendError(e) }, false);
+    }
+
+    request.QueryInterface(Ci.nsIXMLHttpRequest);
+    request.open("POST", this.machineURI.spec + "/statuses/update.json", true);
+    request.channel.notificationCallbacks = this;
+    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+    request.send(data);
+  },
+
+  onSendLoad: function(event) {
+    let request = event.target;
+
+    // FIXME: the next three chunks of code are the same for multiple
+    // load handlers; find some way to factor them out.
+
+    // If the request failed, let the error handler handle it.
+    // XXX Do we need this?  Don't such failures call the error handler directly?
+    if (request.status < 200 || request.status > 299) {
+      this.onSendError(event);
+      return;
+    }
+
+    // If the response is empty, assume failure.
+    // XXX What's the right way to handle this?
+    if (request.responseText.length == 0) {
+      this.onSendError(event);
+      return;
+    }
+
+    // _authInfo only gets set if we prompted the user to authenticate
+    // and the user checked the "remember password" box.  Since we're here,
+    // it means the request succeeded, so we save the login.
+    if (this._authInfo)
+      this._saveLogin();
+
+    this._log.info("onSendLoad: " + request.responseText);
+    this._processSend(request.responseText);
+  },
+
+  onSendError: function(event) {
+    let request = event.target;
+
+    // Sometimes an attempt to retrieve status text throws NS_ERROR_NOT_AVAILABLE
+    let statusText = "";
+    try {
+      statusText = request.statusText;
+    }
+    catch(ex) {}
+    
+    this._log.error("onSendError: " + request.status + " (" + statusText + ")");
+  },
+
+  _processSend: function(responseText) {
+    var JSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+    let response = JSON.decode(responseText);
   }
 
 };