Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promises! #8

Merged
merged 5 commits into from
Apr 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 54 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# framer-Firebase

The **Firebase module** allows your Framer prototype to **load**, **save** and **sync** data effortlessly between multiple sessions and devices.

Updated to support Promises.
<br />

## Demo Projects
Expand All @@ -27,8 +29,8 @@ These examples include access to a public demo database for the purpose of demon
## Getting started in under 5 minutes

<a href='https://open.framermodules.com/Firebase'>
<img alt='Install with Framer Modules'
src='https://www.framermodules.com/assets/[email protected]' width='160' height='40' /></a>
<img alt='Install with Framer Modules'
src='https://www.framermodules.com/assets/[email protected]' width='160' height='40' /></a>

<strong>OR</strong>

Expand Down Expand Up @@ -108,8 +110,8 @@ The required information is located at https://firebase.google.com → *Console*

```coffee
firebase = new Firebase
projectID: ___________ # 1) ... Database → first part of URL
secret: ______________ # 2) ... Project Settings → Service Accounts → Database Secrets → Show (mouse-over)
projectID: ___________ # 1) ... Database → first part of URL
secret: ______________ # 2) ... Project Settings → Service Accounts → Database Secrets → Show (mouse-over)
```


Expand All @@ -134,8 +136,8 @@ If you wish not to use and share your database *secret* in your Framer project l
```json
{
"rules": {
".read": "true",
".write": "true"
".read": "true",
".write": "true"
}
}
```
Expand Down Expand Up @@ -196,20 +198,34 @@ Retrieves data from the database.
```coffee
# Simple 1, expecting single value
firebase.get "/value", (value) ->
print value
print value

# Promise
firebase.get "/value"
.then (value) -> print value

# Simple 2, expecting dataset
firebase.get "/names", (names) ->
namesArray = _.toArray(names) # converts JSON to array
print name for name in namesArray
namesArray = _.toArray(names) # converts JSON to array
print name for name in namesArray

# Promise
firebase.get "/names"
.then (names) ->
namesArray = _.toArray(names) # converts JSON to array
print name for name in namesArray

# Advanced
response = (names) ->
namesArray = _.toArray(names)
print name for name in namesArray
namesArray = _.toArray(names)
print name for name in namesArray

firebase.get("/names",response,{orderBy: "$key", limitToFirst: 5})

# Promise
firebase.get("/names",{orderBy: "$key", limitToFirst: 5})
.then(response)

```
<br />

Expand All @@ -232,10 +248,13 @@ firebase.put("/value", true)

# Advanced
response = (confirmation) ->
print confirmation
print confirmation

firebase.put("/values", {"foo": true, "bar": false}, response)

# Promise
firebase.put("/values", {"foo": true, "bar": false})
.then(response)
```
<br />

Expand All @@ -258,19 +277,19 @@ firebase.post("/value", true)

# Advanced
firebase.post("/addressBook", { # JSON encoded:
"name" : {
"forename" : "Jane",
"surename" : "Doe"
}
"name" : {
"forename" : "Jane",
"surename" : "Doe"
}

"birthday" : {
"day" : 4,
"month": 7,
"year" : 1976
}
"birthday" : {
"day" : 4,
"month": 7,
"year" : 1976
}

"tel" : "202-555-0101"
})
"tel" : "202-555-0101"
})

```
<br />
Expand Down Expand Up @@ -313,14 +332,14 @@ Fires, when the Framer project is loaded (returns all current data of the path)

# Simple
firebase.onChange "/values", (value) ->
print value
print value

# Advanced
response = (data, method, path, breadcrumbs) ->
# method returns either `put´ or `patch´, depending on what method changed the data
# path returns the path that was changed
# breadcrumbs returns the path as segments (array)
print "received #{data} via #{method}"
# method returns either `put´ or `patch´, depending on what method changed the data
# path returns the path that was changed
# breadcrumbs returns the path as segments (array)
print "received #{data} via #{method}"

firebase.onChange("/values", response)

Expand All @@ -336,8 +355,8 @@ Fires, whenever the connection status to Firebase has changed.
```coffee

firebase.onChange "connection", (status) ->
# status is either `connected´ or `disconnected´
print "Hooray, we're connected to Firebase" if status is "connected"
# status is either `connected´ or `disconnected´
print "Hooray, we're connected to Firebase" if status is "connected"

# Or

Expand Down Expand Up @@ -376,11 +395,11 @@ For further information on how to order or limit requests please refer to [Fireb
```JSON

{
"rules": {
".read": "auth != null",
".write": "auth != null",
"routes": {".indexOn": ["distance"]}
}
"rules": {
".read": "auth != null",
".write": "auth != null",
"routes": {".indexOn": ["distance"]}
}
}

```
Expand Down
92 changes: 41 additions & 51 deletions firebase.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


# Documentation of this Module: https://github.com/marckrenn/framer-Firebase
# ------ : ------- Firebase REST API: https://firebase.google.com/docs/reference/rest/database/

Expand All @@ -23,13 +21,11 @@ class exports.Firebase extends Framer.BaseClass
console.log "Firebase: Connecting to Firebase Project '#{@projectID}' ... \n URL: 'https://#{@projectID}.firebaseio.com'" if @debug
@.onChange "connection"


request = (project, secret, path, callback, method, data, parameters, debug) ->

url = "https://#{project}.firebaseio.com#{path}.json#{secret}"


unless parameters is undefined
if parameters?
if parameters.shallow then url += "&shallow=true"
if parameters.format is "export" then url += "&format=export"

Expand All @@ -47,45 +43,40 @@ class exports.Firebase extends Framer.BaseClass
url += "&startAt=#{parameters.startAt}" if typeof parameters.startAt is "number"
url += "&endAt=#{parameters.endAt}" if typeof parameters.endAt is "number"
url += "&equalTo=#{parameters.equalTo}" if typeof parameters.equalTo is "number"

xhttp = new XMLHttpRequest

console.log "Firebase: New '#{method}'-request with data: '#{JSON.stringify(data)}' \n URL: '#{url}'" if debug
xhttp.onreadystatechange = =>

unless parameters is undefined
if parameters.print is "silent" or typeof parameters.download is "string" then return # ugh

switch xhttp.readyState
when 0 then console.log "Firebase: Request not initialized \n URL: '#{url}'" if debug
when 1 then console.log "Firebase: Server connection established \n URL: '#{url}'" if debug
when 2 then console.log "Firebase: Request received \n URL: '#{url}'" if debug
when 3 then console.log "Firebase: Processing request \n URL: '#{url}'" if debug
when 4
if xhttp.responseText?
callback(JSON.parse(xhttp.responseText)) if callback?
console.log "Firebase: Request finished, response: '#{JSON.parse(xhttp.responseText)}' \n URL: '#{url}'" if debug
else
console.log "Lost connection to Firebase." if debug


if xhttp.status is "404"
console.warn "Firebase: Invalid request, page not found \n URL: '#{url}'" if debug


xhttp.open(method, url, true)
xhttp.setRequestHeader("Content-type", "application/json; charset=utf-8")
xhttp.send(data = "#{JSON.stringify(data)}")



options = if data?
body: JSON.stringify(data)
method: method
headers:
'content-type': 'application/json; charset=utf-8'

r = fetch url, (options ? {})
.then (res) ->
if !res.ok then throw Error(res.statusText)
json = res.json()
json.then callback
return json
.catch (error) => console.warn(error)

return r

# Third argument can also accept options, rather than callback
parseArgs = (l, args..., cb) ->
if typeof args[l-1] is "object"
args[l] = args[l-1]
args[l-1] = null

return cb.apply(null, args)

# Available methods

get: (path, callback, parameters) -> request(@projectID, @secretEndPoint, path, callback, "GET", null, parameters, @debug)
put: (path, data, callback, parameters) -> request(@projectID, @secretEndPoint, path, callback, "PUT", data, parameters, @debug)
post: (path, data, callback, parameters) -> request(@projectID, @secretEndPoint, path, callback, "POST", data, parameters, @debug)
patch: (path, data, callback, parameters) -> request(@projectID, @secretEndPoint, path, callback, "PATCH", data, parameters, @debug)
delete: (path, callback, parameters) -> request(@projectID, @secretEndPoint, path, callback, "DELETE", null, parameters, @debug)

get: (args...) -> parseArgs 2, args..., (path, callback, parameters) => request(@projectID, @secretEndPoint, path, callback, "GET", null, parameters, @debug)
put: (args...) -> parseArgs 3, args..., (path, data, callback, parameters) => request(@projectID, @secretEndPoint, path, callback, "PUT", data, parameters, @debug)
post: (args...) -> parseArgs 3, args..., (path, data, callback, parameters) => request(@projectID, @secretEndPoint, path, callback, "POST", data, parameters, @debug)
patch: (args...) -> parseArgs 3, args..., (path, data, callback, parameters) => request(@projectID, @secretEndPoint, path, callback, "PATCH", data, parameters, @debug)
delete: (args...) -> parseArgs 2, args..., (path, callback, parameters) => request(@projectID, @secretEndPoint, path, callback, "DELETE", null, parameters, @debug)


onChange: (path, callback) ->
Expand All @@ -111,17 +102,16 @@ class exports.Firebase extends Framer.BaseClass
console.warn "Firebase: Connection to Firebase Project '#{@projectID}' closed" if @debug
currentStatus = "disconnected"

return

else

url = "https://#{@projectID}.firebaseio.com#{path}.json#{@secretEndPoint}"
source = new EventSource(url)
console.log "Firebase: Listening to changes made to '#{path}' \n URL: '#{url}'" if @debug
url = "https://#{@projectID}.firebaseio.com#{path}.json#{@secretEndPoint}"
source = new EventSource(url)
console.log "Firebase: Listening to changes made to '#{path}' \n URL: '#{url}'" if @debug

source.addEventListener "put", (ev) =>
callback(JSON.parse(ev.data).data, "put", JSON.parse(ev.data).path, _.tail(JSON.parse(ev.data).path.split("/"),1)) if callback?
console.log "Firebase: Received changes made to '#{path}' via 'PUT': #{JSON.parse(ev.data).data} \n URL: '#{url}'" if @debug
source.addEventListener "put", (ev) =>
callback(JSON.parse(ev.data).data, "put", JSON.parse(ev.data).path, _.tail(JSON.parse(ev.data).path.split("/"),1)) if callback?
console.log "Firebase: Received changes made to '#{path}' via 'PUT': #{JSON.parse(ev.data).data} \n URL: '#{url}'" if @debug

source.addEventListener "patch", (ev) =>
callback(JSON.parse(ev.data).data, "patch", JSON.parse(ev.data).path, _.tail(JSON.parse(ev.data).path.split("/"),1)) if callback?
console.log "Firebase: Received changes made to '#{path}' via 'PATCH': #{JSON.parse(ev.data).data} \n URL: '#{url}'" if @debug
source.addEventListener "patch", (ev) =>
callback(JSON.parse(ev.data).data, "patch", JSON.parse(ev.data).path, _.tail(JSON.parse(ev.data).path.split("/"),1)) if callback?
console.log "Firebase: Received changes made to '#{path}' via 'PATCH': #{JSON.parse(ev.data).data} \n URL: '#{url}'" if @debug