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