You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by Sam Ruby <ru...@apache.org> on 2015/12/26 13:58:34 UTC

[whimsy.git] [1/1] Commit eb408dd: switch to Promises

Commit eb408dd28bf2727c00c0b71c9a9cdef69ac01bf2:
    switch to Promises


Branch: refs/heads/secmail
Author: Sam Ruby <ru...@intertwingly.net>
Committer: Sam Ruby <ru...@intertwingly.net>
Pusher: rubys <ru...@apache.org>

------------------------------------------------------------
www/secmail/Gemfile                                          | + -
www/secmail/views/http.js.rb                                 | +++++++ ------
www/secmail/views/index.js.rb                                | +++++++ ----
www/secmail/views/parts.js.rb                                | ++++++++ ---
------------------------------------------------------------
291 changes: 167 additions, 124 deletions.
------------------------------------------------------------


diff --git a/www/secmail/Gemfile b/www/secmail/Gemfile
index 75bdfd5..25f19b5 100644
--- a/www/secmail/Gemfile
+++ b/www/secmail/Gemfile
@@ -7,7 +7,7 @@ gem 'whimsy-asf'
 gem 'sinatra'
 gem 'sanitize'
 gem 'wunderbar', '~> 1.0.11'
-gem 'ruby2js', '~> 2.0.11'
+gem 'ruby2js', '~> 2.0.12'
 gem 'execjs'
 
 group :demo do
diff --git a/www/secmail/views/http.js.rb b/www/secmail/views/http.js.rb
index d7442ff..f52d337 100644
--- a/www/secmail/views/http.js.rb
+++ b/www/secmail/views/http.js.rb
@@ -7,137 +7,150 @@
 
 class HTTP
   # "AJAX" style post request to the server, with a callback
-  def self.post(target, data, &block)
-    xhr = XMLHttpRequest.new()
-    xhr.open('POST', target, true)
-    xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
-    xhr.responseType = 'text'
-
-    def xhr.onreadystatechange()
-      if xhr.readyState == 4
-        data = nil
-
-        begin
-          if xhr.status == 200
-            data = JSON.parse(xhr.responseText) 
-            alert "Exception\n#{data.exception}" if data.exception
-          else
-            HTTP._log(xhr)
+  def self.post(target, data)
+    return Promise.new do |resolve, reject|
+      xhr = XMLHttpRequest.new()
+      xhr.open('POST', target, true)
+      xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
+      xhr.responseType = 'text'
+
+      def xhr.onreadystatechange()
+        if xhr.readyState == 4
+          begin
+            if xhr.status == 200
+              data = JSON.parse(xhr.responseText) 
+              if data.exception
+                reject(data.exception)
+              else
+                resolve(data)
+              end
+            else
+              HTTP._reject(xhr, reject)
+            end
+          rescue => e
+            reject(e)
           end
-        rescue => e
-          console.log(e)
         end
-
-        block(data)
       end
-    end
 
-    xhr.send(JSON.stringify(data))
+      xhr.send(JSON.stringify(data))
+    end
   end
 
   # "AJAX" style patch request to the server, with a callback
-  def self.patch(target, data, &block)
-    xhr = XMLHttpRequest.new()
-    xhr.open('PATCH', target, true)
-    xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
-    xhr.responseType = 'text'
-
-    def xhr.onreadystatechange()
-      if xhr.readyState == 4
-        data = nil
-
-        begin
-          if xhr.status == 200
-            data = JSON.parse(xhr.responseText) 
-            alert "Exception\n#{data.exception}" if data.exception
-          else
-            HTTP._log(xhr)
+  def self.patch(target, data)
+    return Promise.new do |resolve, reject|
+      xhr = XMLHttpRequest.new()
+      xhr.open('PATCH', target, true)
+      xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
+
+      def xhr.onreadystatechange()
+        if xhr.readyState == 4
+          begin
+            if xhr.status == 200
+              data = JSON.parse(xhr.responseText) 
+              if data.exception
+                reject(data.exception)
+              else
+                resolve(data)
+              end
+            elsif xhr.status == 204
+              resolve()
+            else
+              HTTP._reject(xhr, reject)
+            end
+          rescue => e
+            reject(e)
           end
-        rescue => e
-          console.log(e)
         end
-
-        block(data)
       end
-    end
 
-    xhr.send(JSON.stringify(data))
+      xhr.send(JSON.stringify(data))
+    end
   end
 
   # "AJAX" style delete request to the server, with a callback
-  def self.delete(target, &block)
-    xhr = XMLHttpRequest.new()
-    xhr.open('DELETE', target, true)
-
-    def xhr.onreadystatechange()
-      if xhr.readyState == 4
-
-        begin
-          if xhr.status == 404
-            alert "Not Found: #{target}"
+  def self.delete(target)
+    return Promise.new do |resolve, reject|
+      xhr = XMLHttpRequest.new()
+      xhr.open('DELETE', target, true)
+      xhr.responseType = 'text'
+
+      def xhr.onreadystatechange()
+        if xhr.readyState == 4
+          console.log xhr.status
+          if xhr.status == 200
+            resolve()
           else
-            HTTP._log(xhr)
+            HTTP._reject(xhr, reject)
           end
-        rescue => e
-          console.log(e)
         end
-
-        block()
       end
-    end
 
-    xhr.send()
+      xhr.send()
+    end
   end
 
   # "AJAX" style get request to the server, with a callback
-  def self.get(target, type, &block)
-    xhr = XMLHttpRequest.new()
-
-    def xhr.onreadystatechange()
-      if xhr.readyState == 4
-        data = nil
-
-        begin
-          if xhr.status == 200
-            if type == :json
-              data = xhr.response || JSON.parse(xhr.responseText) 
+  def self.get(target, type)
+    return Promise.new do |resolve, reject|
+      xhr = XMLHttpRequest.new()
+
+      def xhr.onreadystatechange()
+        if xhr.readyState == 4
+          begin
+            if xhr.status == 200
+              if type == :json
+                data = xhr.response || JSON.parse(xhr.responseText) 
+              else
+                data = xhr.responseText
+              end
+
+              resolve data
             else
-              data = xhr.responseText
+              HTTP._reject(xhr, reject)
             end
-          else
-            HTTP._log(xhr)
+          rescue => e
+            reject e
           end
-        rescue => e
-          console.log(e)
         end
+      end
 
-        block(data)
+      if target =~ /^https?:/
+        xhr.open('GET', target, true)
+        xhr.setRequestHeader("Accept", "application/json") if type == :json
+      else
+        xhr.open('GET', target, true)
       end
-    end
 
-    if target =~ /^https?:/
-      xhr.open('GET', target, true)
-      xhr.setRequestHeader("Accept", "application/json") if type == :json
-    else
-      xhr.open('GET', target, true)
+      xhr.responseType = type
+      xhr.send()
     end
-    xhr.responseType = type
-    xhr.send()
   end
 
-  # common logging
-  def self._log(xhr)
-    if xhr.status == 404
-      alert "Not Found: #{target}"
-    elsif xhr.status >= 400
-      console.log(xhr.response)
+  # common rejection logic
+  def self._reject(xhr, reject)
+    if not xhr.status
+      reject "Server unavailable"
+    elsif xhr.status == 404
+      reject "Not found"
+    else
+      console.log xhr.response
       if not xhr.response
-        alert "Exception - #{xhr.statusText}"
+        reject "Exception - #{xhr.statusText}"
       elsif xhr.response.exception
-        alert "Exception\n#{xhr.response.exception}"
+        reject "Exception\n#{xhr.response.exception}"
       else
-        alert "Exception\n#{JSON.parse(xhr.responseText).exception}"
+        text = xhr.responseText
+        begin
+          json = JSON.parse(text)
+          text = "Exception: #{json.exception}" if json.exception
+        rescue => e
+        end
+        reject text
       end
     end
+  rescue => e
+    reject e
   end
 end
diff --git a/www/secmail/views/index.js.rb b/www/secmail/views/index.js.rb
index 3756e5d..aa9170e 100644
--- a/www/secmail/views/index.js.rb
+++ b/www/secmail/views/index.js.rb
@@ -83,7 +83,7 @@ def componentDidUpdate()
 
   # fetch a month's worth of messages
   def fetch_month()
-    HTTP.get("/#{@nextmbox}", :json) do |response|
+    HTTP.get("/#{@nextmbox}", :json).then {|response|
       # update latest mbox
       @nextmbox = response.mbox
 
@@ -92,7 +92,10 @@ def fetch_month()
 
       # select oldest message
       self.selectRow Status.selected || @messages.last unless @selected
-    end
+    }.catch {|error|
+      console.log error
+      alert error
+    }
   end
 
   # update @selected, given either a DOM event or a message
@@ -110,9 +113,9 @@ def selectRow(object)
     end
 
     # ensure selected message is not deleted
-    index = @messages.findIndex {|m| return m.href == href}
+    index = @messages.find_index {|m| m.href == href}
     index -= 1 while index >= 0 and @messages[index].status == :deleted
-    index = @messages.findIndex {|m| return m.status != :deleted} if index == -1
+    index = @messages.find_index {|m| m.status != :deleted} if index == -1
 
     @selected = Status.selected = @messages[index].href
   end
@@ -127,36 +130,41 @@ def nav(event)
 
   def undo(event)
     message = Status.popStack()
-    selected = @messages.find {|m| return m.href == message}
+    selected = @messages.find {|m| m.href == message}
     if selected
       self.selectRow selected
       selected.status = :deletePending
 
       # send request to server to remove delete status
-      HTTP.patch(selected.href, status: nil) do
+      HTTP.patch(selected.href, status: nil).then {
         delete selected.status
         self.forceUpdate()
         self.selectRow message
-      end
+      }.catch {|error|
+        alert error
+      }
     end
   end
 
   def refresh(event)
     @checking = true
-    HTTP.post "actions/check-mail", mbox: @@mbox do |response|
+    HTTP.post("actions/check-mail", mbox: @@mbox).then {
       location.reload()
-    end
+    }.catch {|error|
+      alert error
+      @checking = false
+    }
   end
 
   # handle keyboard events
   def keydown(event)
     if event.keyCode == 38 # up
-      index = @messages.findIndex {|m| return m.href == @selected}
+      index = @messages.find_index {|m| m.href == @selected}
       self.selectRow @messages[index-1] if index > 0
       event.preventDefault()
 
     elsif event.keyCode == 40 # down
-      index = @messages.findIndex {|m| return m.href == @selected} + 1
+      index = @messages.find_index {|m| m.href == @selected} + 1
       while index < @messages.length and @messages[index].status == :deleted
         index += 1
       end
@@ -164,7 +172,7 @@ def keydown(event)
       event.preventDefault()
 
     elsif event.keyCode == 13 or event.keyCode == 39 # enter/return or right
-      selected = @messages.find {|m| return m.href == @selected}
+      selected = @messages.find {|m| m.href == @selected}
       window.location.href = selected.href if selected
 
     elsif event.keyCode == 8 or event.keyCode == 46 # backspace or delete
@@ -173,7 +181,7 @@ def keydown(event)
 
         # mark item as delete pending
         selected = @selected
-        index = @messages.findIndex {|m| return m.href == selected}
+        index = @messages.find_index {|m| m.href == selected}
         @messages[index].status = :deletePending if index >= 0
 
         # move selected pointer
@@ -186,13 +194,15 @@ def keydown(event)
         end
 
         # send request to server to perform delete
-        HTTP.delete(selected) do
-          index = @messages.findIndex {|m| return m.href == selected}
+        HTTP.delete(selected).then {
+          index = @messages.find_index {|m| m.href == selected}
           @messages[index].status = :deleted if index >= 0
           Status.pushDeleted selected
           self.selectRow selected if @selected == selected
           self.forceUpdate()
-        end
+        }.catch {|error|
+          alert error
+        }
       end
 
     elsif event.keyCode == 'Z'.ord
diff --git a/www/secmail/views/parts.js.rb b/www/secmail/views/parts.js.rb
index 1578957..3fb5881 100644
--- a/www/secmail/views/parts.js.rb
+++ b/www/secmail/views/parts.js.rb
@@ -147,10 +147,13 @@ def submit(event)
     end
 
     @busy = true
-    HTTP.post form.action, data do |response|
+    HTTP(post form.action, data).then {|response|
       @busy = false
       alert response.result
-    end
+    }.catch {|error|
+      alert error
+      @busy = false
+    }
   end
 
   # hide context menu whenever a click is received outside the menu
@@ -163,10 +166,12 @@ def window_click(event)
     document.querySelector('.contextMenu').style.display = :none
   end
 
+  # clicking on an attachment selects it
   def select(event)
     @selected = event.currentTarget.querySelector('a').getAttribute('href')
   end
 
+  # handle keyboard events
   def keydown(event)
     if event.keyCode == 8 or event.keyCode == 46 # backspace or delete
       if event.metaKey or event.ctrlKey
@@ -174,10 +179,13 @@ def keydown(event)
         event.stopPropagation()
 
         pathname = window.parent.location.pathname
-        HTTP.delete(pathname) do
+        HTTP.delete(pathname).then {
           Status.pushDeleted pathname
           window.parent.location.href = '../..'
-        end
+        }.catch {|error|
+          alert error
+          @busy = false
+        }
       end
     end
   end
@@ -190,12 +198,15 @@ def burst(event)
     }
 
     @busy = true
-    HTTP.post '../../actions/burst', data do |response|
+    HTTP.post('../../actions/burst', data).then {|response|
       @attachments = response.attachments
       @selected = response.selected
       @busy = false
       window.parent.frames.content.location.href=response.selected
-    end
+    }.catch {|error|
+      alert error
+      @busy = false
+    }
   end
 
   # burst a PDF into individual pages
@@ -206,7 +217,7 @@ def delete_attachment(event)
     }
 
     @busy = true
-    HTTP.post '../../actions/delete-attachment', data do |response|
+    HTTP.post('../../actions/delete-attachment', data).then {|response|
       if response.attachments and not response.attachments.empty?
         @attachments = response.attachments
         @busy = false
@@ -214,7 +225,10 @@ def delete_attachment(event)
       else
         window.parent.location.href = '../..'
       end
-    end
+    }.catch {|error|
+      alert error
+      @busy = false
+    }
   end
 
   # rotate an attachment
@@ -228,14 +242,17 @@ def rotate_attachment(event)
     }
 
     @busy = true
-    HTTP.post '../../actions/rotate-attachment', data do |response|
+    HTTP.post('../../actions/rotate-attachment', data).then {|response|
       @attachments = response.attachments
       @selected = response.selected
       @busy = false
 
       # reload attachment in content pane
       window.parent.frames.content.location.href = response.selected
-    end
+    }.catch {|error|
+      alert error
+      @busy = false
+    }
   end
 
   #
@@ -290,13 +307,16 @@ def drop(event)
 
     @busy = true
     @drag = nil
-    HTTP.post '../../actions/drop', data do |response| 
+    HTTP.post('../../actions/drop', data).then {|response| 
       @attachments = response.attachments
       @selected = response.selected
       @busy = false
       target.classList.remove 'drop-target'
       window.parent.frames.content.location.href=response.selected
-    end
+    }.catch {|error|
+      alert error
+      @busy = false
+    }
   end
 
   # cancel drag operation