Refactor FacebookHandler and GPlusHandler

* Move api loading to FacebookHandler
* Use success callbacks
* Use same, properly named events
* Use same functions and property names
* Refactor related social button, out of use rendering system
* Remove the now unnecessary form split from CreateAccountModal
This commit is contained in:
Scott Erickson 2016-03-15 13:50:33 -07:00
parent 93c7072d8d
commit e6593dea8d
13 changed files with 364 additions and 429 deletions

View file

@ -5,7 +5,6 @@ module.exports = class CocoRouter extends Backbone.Router
initialize: ->
# http://nerds.airbnb.com/how-to-add-google-analytics-page-tracking-to-57536
@bind 'route', @_trackPageView
Backbone.Mediator.subscribe 'auth:gplus-api-loaded', @onGPlusAPILoaded, @
Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
@initializeSocialMediaServices = _.once @initializeSocialMediaServices
@ -170,7 +169,6 @@ module.exports = class CocoRouter extends Backbone.Router
$('#page-container').empty().append view.el
window.currentView = view
@activateTab()
@renderLoginButtons() if view.usesSocialMedia
view.afterInsert()
view.didReappear()
@ -187,21 +185,19 @@ module.exports = class CocoRouter extends Backbone.Router
$('body')[0].scrollTop = 0
), 10
onGPlusAPILoaded: =>
@renderLoginButtons()
initializeSocialMediaServices: ->
return if application.testing or application.demoing
require('core/services/facebook')()
application.facebookHandler.loadAPI()
application.gplusHandler.loadAPI()
require('core/services/twitter')()
renderLoginButtons: =>
renderSocialButtons: =>
# TODO: Refactor remaining services to Handlers, use loadAPI success callback
@initializeSocialMediaServices()
$('.share-buttons, .partner-badges').addClass('fade-in').delay(10000).removeClass('fade-in', 5000)
setTimeout(FB.XFBML.parse, 10) if FB?.XFBML?.parse # Handles FB login and Like
application.facebookHandler.renderButtons()
application.gplusHandler.renderButtons()
twttr?.widgets?.load?()
application.gplusHandler.renderLoginButtons()
activateTab: ->
base = _.string.words(document.location.pathname[1..], '/')[0]

View file

@ -1,41 +0,0 @@
module.exports = initializeFacebook = ->
# Additional JS functions here
window.fbAsyncInit = ->
FB.init
appId: (if document.location.origin is 'http://localhost:3000' then '607435142676437' else '148832601965463') # App ID
channelUrl: document.location.origin + '/channel.html' # Channel File
status: true # check login status
cookie: true # enable cookies to allow the server to access the session
xfbml: true # parse XFBML
Backbone.Mediator.publish 'auth:facebook-api-loaded', {}
# This is fired for any auth related change, such as login, logout or session refresh.
FB.Event.subscribe 'auth.authResponseChange', (response) ->
# Here we specify what we do with the response anytime this event occurs.
if response.status is 'connected'
# They have logged in to the app.
Backbone.Mediator.publish 'auth:logged-in-with-facebook', response: response
#else if response.status is 'not_authorized'
# #
#else
# #
# Load the SDK asynchronously
((d) ->
js = undefined
id = 'facebook-jssdk'
ref = d.getElementsByTagName('script')[0]
return if d.getElementById(id)
js = d.createElement('script')
js.id = id
js.async = true
js.src = '//connect.facebook.net/en_US/all.js'
#js.src = '//connect.facebook.net/en_US/all/debug.js'
ref.parentNode.insertBefore js, ref
return
) document

View file

@ -13,44 +13,94 @@ userPropsToSave =
module.exports = FacebookHandler = class FacebookHandler extends CocoClass
subscriptions:
'auth:logged-in-with-facebook': 'onFacebookLoggedIn'
loggedIn: false
token: -> @authResponse?.accessToken
fakeFacebookLogin: ->
@onFacebookLoggedIn({
response:
authResponse: { accessToken: '1234' }
})
startedLoading: false
apiLoaded: false
connected: false
person: null
fakeAPI: ->
window.FB =
login: (cb, options) ->
cb({status: 'connected', authResponse: { accessToken: '1234' }})
api: (url, options, cb) ->
cb({
first_name: 'Mr'
last_name: 'Bean'
id: 'abcd'
email: 'some@email.com'
})
onFacebookLoggedIn: (e) ->
# user is logged in also when the page first loads, so check to see
# if we really need to do the lookup
@loggedIn = false
@authResponse = e.response.authResponse
for fbProp, userProp of userPropsToSave
unless me.get(userProp)
@loggedIn = true
break
@startedLoading = true
@apiLoaded = true
@trigger 'logged-into-facebook'
loginThroughFacebook: ->
if @loggedIn
return true
loadAPI: (options={}) ->
options.success ?= _.noop
options.context ?= options
if @apiLoaded
options.success.bind(options.context)()
else
FB.login ((response) ->
console.log 'Received FB login response:', response
), scope: 'email'
@once 'load-api', options.success, options.context
if not @startedLoading
# Load the SDK asynchronously
@startedLoading = true
((d) ->
js = undefined
id = 'facebook-jssdk'
ref = d.getElementsByTagName('script')[0]
return if d.getElementById(id)
js = d.createElement('script')
js.id = id
js.async = true
js.src = '//connect.facebook.net/en_US/all.js'
#js.src = '//connect.facebook.net/en_US/all/debug.js'
ref.parentNode.insertBefore js, ref
return
)(document)
loadPerson: ->
window.fbAsyncInit = =>
FB.init
appId: (if document.location.origin is 'http://localhost:3000' then '607435142676437' else '148832601965463') # App ID
channelUrl: document.location.origin + '/channel.html' # Channel File
cookie: true # enable cookies to allow the server to access the session
xfbml: true # parse XFBML
FB.getLoginStatus (response) =>
if response.status is 'connected'
@connected = true
@authResponse = response.authResponse
@trigger 'connect', { response: response }
@apiLoaded = true
@trigger 'load-api'
connect: (options={}) ->
options.success ?= _.noop
options.context ?= options
FB.login ((response) =>
if response.status is 'connected'
@connected = true
@authResponse = response.authResponse
@trigger 'connect', { response: response }
options.success.bind(options.context)()
), scope: 'email'
loadPerson: (options={}) ->
options.success ?= _.noop
options.context ?= options
FB.api '/me', {fields: 'email,last_name,first_name,gender'}, (person) =>
attrs = {}
for fbProp, userProp of userPropsToSave
value = person[fbProp]
if value
attrs[userProp] = value
@trigger 'person-loaded', attrs
@trigger 'load-person', attrs
options.success.bind(options.context)(attrs)
renderButtons: ->
setTimeout(FB.XFBML.parse, 10) if FB?.XFBML?.parse # Handles FB login and Like

View file

@ -20,109 +20,122 @@ scope = 'https://www.googleapis.com/auth/plus.login email'
module.exports = GPlusHandler = class GPlusHandler extends CocoClass
constructor: ->
@accessToken = storage.load GPLUS_TOKEN_KEY, false
window.onGPlusLogin = _.bind(@onGPlusLogin, @)
super()
token: -> @accessToken?.access_token
startedLoading: false
apiLoaded: false
connected: false
person: null
loadAPI: ->
return if @loadedAPI
@loadedAPI = true
(=>
fakeAPI: ->
window.gapi =
client:
load: (api, version, cb) -> cb()
plus:
people:
get: -> {
execute: (cb) ->
cb({
name: {
givenName: 'Mr'
familyName: 'Bean'
}
id: 'abcd'
emails: [{value: 'some@email.com'}]
})
}
auth:
authorize: (opts, cb) ->
cb({access_token: '1234'})
@startedLoading = true
@apiLoaded = true
fakeConnect: ->
@accessToken = {access_token: '1234'}
@trigger 'connect'
loadAPI: (options={}) ->
options.success ?= _.noop
options.context ?= options
if @apiLoaded
options.success.bind(options.context)()
else
@once 'load-api', options.success, options.context
if not @startedLoading
po = document.createElement('script')
po.type = 'text/javascript'
po.async = true
po.src = 'https://apis.google.com/js/client:platform.js?onload=onGPlusLoaded'
s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore po, s
window.onGPlusLoaded = _.bind(@onLoadAPI, @)
return
)()
@startedLoading = true
window.onGPlusLoaded = =>
@apiLoaded = true
if @accessToken and me.get('gplusID')
# We need to check the current state, given our access token
gapi.auth.setToken 'token', @accessToken
session_state = @accessToken.session_state
gapi.auth.checkSessionState {client_id: clientID, session_state: session_state}, (connected) =>
@connected = connected
@trigger 'load-api'
else
@connected = false
@trigger 'load-api'
onLoadAPI: ->
Backbone.Mediator.publish 'auth:gplus-api-loaded', {}
session_state = null
if @accessToken and me.get('gplusID')
# We need to check the current state, given our access token
gapi.auth.setToken 'token', @accessToken
session_state = @accessToken.session_state
gapi.auth.checkSessionState({client_id: clientID, session_state: session_state}, @onCheckedSessionState)
else
# If we ran checkSessionState, it might return true, that the user is logged into Google, but has not authorized us
@loggedIn = false
func = => @trigger 'checked-state'
setTimeout func, 1
renderLoginButtons: ->
return false unless gapi?.plusone?
gapi.plusone.go?() # Handles +1 button
if not gapi.signin?.render
console.warn 'Didn\'t have gapi.signin to render G+ login button. (DoNotTrackMe extension?)'
return
for gplusButton in $('.gplus-login-button')
params = {
callback: 'onGPlusLogin',
clientid: clientID,
cookiepolicy: 'single_host_origin',
scope: 'https://www.googleapis.com/auth/plus.login email',
height: 'short',
}
if gapi.signin?.render
gapi.signin.render(gplusButton, params)
@trigger 'render-login-buttons'
onCheckedSessionState: (@loggedIn) =>
@trigger 'checked-state'
reauthorize: ->
params =
'client_id' : clientID
'scope' : scope
gapi.auth.authorize params, @onGPlusLogin
fakeGPlusLogin: ->
@onGPlusLogin({
access_token: '1234'
})
onGPlusLogin: (e) ->
return unless e.access_token
@loggedIn = true
Backbone.Mediator.publish 'auth:logged-in-with-gplus', e
try
connect: (options={}) ->
options.success ?= _.noop
options.context ?= options
authOptions = {
client_id: clientID
scope: 'https://www.googleapis.com/auth/plus.login email'
}
gapi.auth.authorize authOptions, (e) =>
return unless e.access_token
@connected = true
try
# Without removing this, we sometimes get a cross-domain error
d = _.omit(e, 'g-oauth-window')
storage.save(GPLUS_TOKEN_KEY, d, 0)
catch e
console.error 'Unable to save G+ token key', e
@accessToken = e
@trigger 'logged-in'
@trigger 'logged-into-google'
d = _.omit(e, 'g-oauth-window')
storage.save(GPLUS_TOKEN_KEY, d, 0)
catch e
console.error 'Unable to save G+ token key', e
@accessToken = e
@trigger 'connect'
options.success.bind(options.context)()
loadPerson: (options={}) ->
@reloadOnLogin = options.reloadOnLogin
options.success ?= _.noop
options.context ?= options
# email and profile data loaded separately
gapi.client.load('plus', 'v1', =>
gapi.client.plus.people.get({userId: 'me'}).execute(@onPersonReceived))
gapi.client.load 'plus', 'v1', =>
gapi.client.plus.people.get({userId: 'me'}).execute (r) =>
attrs = {}
for gpProp, userProp of userPropsToSave
keys = gpProp.split('.')
value = r
for key in keys
value = value[key]
if value
attrs[userProp] = value
if r.emails?.length
attrs.email = r.emails[0].value
@trigger 'load-person', attrs
options.success.bind(options.context)(attrs)
onPersonReceived: (r) =>
attrs = {}
for gpProp, userProp of userPropsToSave
keys = gpProp.split('.')
value = r
for key in keys
value = value[key]
if value
attrs[userProp] = value
newEmail = r.emails?.length and r.emails[0] isnt me.get('email')
return unless newEmail or me.get('anonymous', true)
if r.emails?.length
attrs.email = r.emails[0].value
@trigger 'person-loaded', attrs
renderButtons: ->
return false unless gapi?.plusone?
gapi.plusone.go?() # Handles +1 button
# Friends logic, not in use
loadFriends: (friendsCallback) ->
return friendsCallback() unless @loggedIn
expiresIn = if @accessToken then parseInt(@accessToken.expires_at) - new Date().getTime()/1000 else -1
@ -133,3 +146,9 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
@listenToOnce(@, 'logged-in', onReauthorized)
else
onReauthorized()
reauthorize: ->
params =
'client_id' : clientID
'scope' : scope
gapi.auth.authorize params, @onGPlusLogin

View file

@ -4,40 +4,10 @@ module.exports =
'auth:me-synced': c.object {required: ['me']},
me: {type: 'object'}
'auth:facebook-api-loaded': c.object {}
'auth:logging-in-with-facebook': c.object {}
'auth:signed-up': c.object {}
'auth:logging-out': c.object {}
'auth:logged-in-with-facebook': c.object {title: 'Facebook logged in', description: 'Published when you successfully logged in with Facebook', required: ['response']},
response:
type: 'object'
properties:
status: {type: 'string'}
authResponse:
type: 'object'
properties:
accessToken: {type: 'string'}
expiresIn: {type: 'number'}
signedRequest: {type: 'string'}
userID: {type: 'string'}
'auth:linkedin-api-loaded': c.object {}
'auth:gplus-api-loaded': c.object {}
'auth:logging-in-with-gplus': c.object {}
'auth:logged-in-with-gplus':
title: 'G+ logged in'
description: 'Published when you successfully logged in with G+'
type: 'object'
required: ['access_token']
properties:
access_token: {type: 'string'}
# Could be some other stuff
'auth:log-in-with-github': c.object {}

View file

@ -42,7 +42,7 @@
#facebook-login-btn.btn.btn-primary.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_facebook.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_facebook")
#gplus-login-btn.btn.btn-danger.btn-lg.btn-illustrated.network-login(disabled=true)
#gplus-login-btn.btn.btn-danger.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_g+.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_gplus")
.gplus-login-wrapper

View file

@ -6,7 +6,7 @@
div#close-modal
span.glyphicon.glyphicon-remove
.auth-form-content
form.auth-form-content
if view.options.showRequiredError
#required-error-alert.alert.alert-success
span(data-i18n="signup.required")
@ -16,20 +16,19 @@
#email-password-row.row
.col-md-6
form
.form-group
label.control-label(for="email")
span(data-i18n="general.email")
| :
.input-border
input#email.input-large.form-control(name="email", type="email", value=view.previousFormInputs.email, tabindex=1)
.form-group
label.control-label(for="password")
span(data-i18n="general.password")
| :
.input-border
input#password.input-large.form-control(name="password", type="password", value=view.previousFormInputs.password, tabindex=2)
.form-group
label.control-label(for="email")
span(data-i18n="general.email")
| :
.input-border
input#email.input-large.form-control(name="email", type="email", value=view.previousFormInputs.email, tabindex=1)
.form-group
label.control-label(for="password")
span(data-i18n="general.password")
| :
.input-border
input#password.input-large.form-control(name="password", type="password", value=view.previousFormInputs.password, tabindex=2)
.col-md-6
.auth-network-logins.text-center
@ -37,7 +36,7 @@
#facebook-signup-btn.btn.btn-primary.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_facebook.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_facebook")
#gplus-signup-btn.btn.btn-danger.btn-lg.btn-illustrated.network-login(disabled=true)
#gplus-signup-btn.btn.btn-danger.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_g+.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_gplus")
.gplus-login-wrapper
@ -59,52 +58,51 @@
h2(data-i18n="signup.facebook_exists")
a.btn.btn-primary#facebook-login-btn(data-i18n="login.log_in")
form
.row
.col-md-6
.form-group
label.control-label(for="name")
span(data-i18n="general.name") Name
| :
.input-border
if me.get('name')
input#name.input-large.form-control(name="name", type="text", value=me.get('name'), tabindex=3)
else
input#name.input-large.form-control(name="name", type="text", value="", placeholder="e.g. Alex W the Skater", tabindex=3)
.form-group
label.control-label(for="school-input")
span.spr(data-i18n="signup.school_name")
em.optional-note
| (
span(data-i18n="signup.optional")
| ):
.input-border
input#school-input.input-large.form-control(name="schoolName", data-i18n="[placeholder]signup.school_name_placeholder", value=view.previousFormInputs.schoolName || '', tabindex=4)
.form-group
label.control-label(for="school-input")
span.spr(data-i18n="courses.class_code")
em.optional-note
| (
span(data-i18n="signup.optional")
| ):
.input-border
input#class-code-input.input-large.form-control(name="classCode", value=view.previousFormInputs.classCode || '', tabindex=5)
.row
.col-md-6
.form-group
label.control-label(for="name")
span(data-i18n="general.name") Name
| :
.input-border
if me.get('name')
input#name.input-large.form-control(name="name", type="text", value=me.get('name'), tabindex=3)
else
input#name.input-large.form-control(name="name", type="text", value="", placeholder="e.g. Alex W the Skater", tabindex=3)
.col-md-6
.form-group.checkbox
label.control-label(for="subscribe")
.input-border
input#subscribe(type="checkbox", checked='checked')
span.custom-checkbox
.glyphicon.glyphicon-ok
span(data-i18n="signup.email_announcements")
.form-group
label.control-label(for="school-input")
span.spr(data-i18n="signup.school_name")
em.optional-note
| (
span(data-i18n="signup.optional")
| ):
.input-border
input#school-input.input-large.form-control(name="schoolName", data-i18n="[placeholder]signup.school_name_placeholder", value=view.previousFormInputs.schoolName || '', tabindex=4)
.form-group
label.control-label(for="school-input")
span.spr(data-i18n="courses.class_code")
em.optional-note
| (
span(data-i18n="signup.optional")
| ):
.input-border
input#class-code-input.input-large.form-control(name="classCode", value=view.previousFormInputs.classCode || '', tabindex=5)
.col-md-6
.form-group.checkbox
label.control-label(for="subscribe")
.input-border
input#subscribe(type="checkbox", checked='checked')
span.custom-checkbox
.glyphicon.glyphicon-ok
span(data-i18n="signup.email_announcements")
.well(data-i18n="signup.hey_students")
.well(data-i18n="signup.hey_students")
input#signup-button.btn.btn-lg.btn-illustrated.btn-block.btn-success(value=translate("signup.sign_up"), type="submit")
input#signup-button.btn.btn-lg.btn-illustrated.btn-block.btn-success(value=translate("signup.sign_up"), type="submit")
.extra-pane
.switch-explanation(data-i18n="signup.login_switch")

View file

@ -11,29 +11,19 @@ module.exports = class AuthModal extends ModalView
template: template
events:
# login buttons
'click #switch-to-signup-btn': 'onSignupInstead'
'click #github-login-button': 'onGitHubLoginClicked'
'submit form': 'onSubmitForm' # handles both submit buttons
'submit form': 'onSubmitForm'
'keyup #name': 'onNameChange'
'click #gplus-login-btn': 'onClickGPlusLogin'
'click #gplus-login-btn': 'onClickGPlusLoginButton'
'click #facebook-login-btn': 'onClickFacebookLoginButton'
'click #close-modal': 'hide'
subscriptions:
'errors:server-error': 'onServerError'
'auth:facebook-api-loaded': 'onFacebookAPILoaded'
# Initialization
initialize: (options={}) ->
@previousFormInputs = options.initialValues or {}
@listenTo application.gplusHandler, 'logged-into-google', @onGPlusHandlerLoggedIntoGoogle
@listenTo application.gplusHandler, 'person-loaded', @onGPlusPersonLoaded
@listenTo application.gplusHandler, 'render-login-buttons', @onGPlusRenderLoginButtons
@listenTo application.facebookHandler, 'logged-into-facebook', @onFacebookHandlerLoggedIntoFacebook
@listenTo application.facebookHandler, 'person-loaded', @onFacebookPersonLoaded
getRenderData: ->
c = super()
@ -47,19 +37,11 @@ module.exports = class AuthModal extends ModalView
afterRender: ->
super()
@playSound 'game-menu-open'
@$('#facebook-login-btn').attr('disabled', true) if not window.FB?
afterInsert: ->
super()
_.delay (=> application.router.renderLoginButtons()), 500
_.delay (=> $('input:visible:first', @$el).focus()), 500
onGPlusRenderLoginButtons: ->
@$('#gplus-login-btn').attr('disabled', false)
onFacebookAPILoaded: ->
@$('#facebook-login-btn').attr('disabled', false)
onSignupInstead: (e) ->
CreateAccountModal = require('./CreateAccountModal')
modal = new CreateAccountModal({initialValues: forms.formToObject @$el})
@ -81,61 +63,71 @@ module.exports = class AuthModal extends ModalView
# Google Plus
onClickGPlusLogin: ->
@clickedGPlusLogin = true
onGPlusHandlerLoggedIntoGoogle: ->
return unless @clickedGPlusLogin
application.gplusHandler.loadPerson()
onClickGPlusLoginButton: ->
btn = @$('#gplus-login-btn')
btn.find('.sign-in-blurb').text($.i18n.t('login.logging_in'))
btn.attr('disabled', true)
onGPlusPersonLoaded: (gplusAttrs) ->
existingUser = new User()
existingUser.fetchGPlusUser(gplusAttrs.gplusID, {
success: =>
me.loginGPlusUser(gplusAttrs.gplusID, {
success: -> window.location.reload()
error: @onGPlusLoginError
application.gplusHandler.loadAPI({
context: @
success: ->
btn.attr('disabled', false)
application.gplusHandler.connect({
context: @
success: ->
btn.find('.sign-in-blurb').text($.i18n.t('login.logging_in'))
btn.attr('disabled', true)
application.gplusHandler.loadPerson({
context: @
success: (gplusAttrs) ->
existingUser = new User()
existingUser.fetchGPlusUser(gplusAttrs.gplusID, {
success: =>
me.loginGPlusUser(gplusAttrs.gplusID, {
success: -> window.location.reload()
error: @onGPlusLoginError
})
error: @onGPlusLoginError
})
})
})
error: @onGPlusLoginError
})
onGPlusLoginError: =>
btn = @$('#gplus-login-btn')
btn.find('.sign-in-blurb').text($.i18n.t('login.sign_in_with_gplus'))
btn.attr('disabled', false)
errors.showNotyNetworkError(arguments...)
errors.showNotyNetworkError(arguments...)
# Facebook
onClickFacebookLoginButton: ->
@clickedFacebookLogin = true
if application.facebookHandler.loggedIn
@onFacebookHandlerLoggedIntoFacebook()
else
application.facebookHandler.loginThroughFacebook()
onFacebookHandlerLoggedIntoFacebook: ->
return unless @clickedFacebookLogin
application.facebookHandler.loadPerson()
btn = @$('#facebook-login-btn')
btn.find('.sign-in-blurb').text($.i18n.t('login.logging_in'))
btn.attr('disabled', true)
onFacebookPersonLoaded: (facebookAttrs) ->
existingUser = new User()
existingUser.fetchFacebookUser(facebookAttrs.facebookID, {
success: =>
me.loginFacebookUser(facebookAttrs.facebookID, {
success: -> window.location.reload()
error: @onFacebookLoginError
application.facebookHandler.loadAPI({
context: @
success: ->
btn.attr('disabled', false)
application.facebookHandler.connect({
context: @
success: ->
btn.find('.sign-in-blurb').text($.i18n.t('login.logging_in'))
btn.attr('disabled', true)
application.facebookHandler.loadPerson({
context: @
success: (facebookAttrs) ->
existingUser = new User()
existingUser.fetchFacebookUser(facebookAttrs.facebookID, {
success: =>
me.loginFacebookUser(facebookAttrs.facebookID, {
success: -> window.location.reload()
error: @onFacebookLoginError
})
error: @onFacebookLoginError
})
})
})
error: @onFacebookLoginError
})
onFacebookLoginError: =>
btn = @$('#facebook-login-btn')
btn.find('.sign-in-blurb').text($.i18n.t('login.sign_in_with_facebook'))

View file

@ -7,8 +7,6 @@ application = require 'core/application'
Classroom = require 'models/Classroom'
errors = require 'core/errors'
# TODO: Avoid using G+ render buttons to login, login directly instead.
# Form object is split in two in template to avoid having rendered buttons triggered on form submit.
module.exports = class CreateAccountModal extends ModalView
id: 'create-account-modal'
@ -24,37 +22,21 @@ module.exports = class CreateAccountModal extends ModalView
'click #close-modal': 'hide'
'click #switch-to-login-btn': 'onClickSwitchToLoginButton'
subscriptions:
'auth:facebook-api-loaded': 'onFacebookAPILoaded'
# Initialization
initialize: (options={}) ->
@onNameChange = _.debounce(_.bind(@checkNameExists, @), 500)
@previousFormInputs = options.initialValues or {}
@listenTo application.gplusHandler, 'logged-into-google', @onGPlusHandlerLoggedIntoGoogle
@listenTo application.gplusHandler, 'person-loaded', @onGPlusPersonLoaded
@listenTo application.gplusHandler, 'render-login-buttons', @onGPlusRenderLoginButtons
@listenTo application.facebookHandler, 'logged-into-facebook', @onFacebookHandlerLoggedIntoFacebook
@listenTo application.facebookHandler, 'person-loaded', @onFacebookPersonLoaded
afterRender: ->
super()
@playSound 'game-menu-open'
@$('#facebook-signup-btn').attr('disabled', true) if not window.FB?
afterInsert: ->
super()
_.delay (-> application.router.renderLoginButtons()), 500
_.delay (=> $('input:visible:first', @$el).focus()), 500
onGPlusRenderLoginButtons: ->
@$('#gplus-signup-btn').attr('disabled', false)
onFacebookAPILoaded: ->
@$('#facebook-signup-btn').attr('disabled', false)
# User creation
@ -151,28 +133,35 @@ module.exports = class CreateAccountModal extends ModalView
# Google Plus
onClickGPlusSignupButton: ->
@clickedGPlusLogin = true
onGPlusHandlerLoggedIntoGoogle: ->
return unless @clickedGPlusLogin
application.gplusHandler.loadPerson()
btn = @$('#gplus-signup-btn')
btn.find('.sign-in-blurb').text($.i18n.t('signup.creating'))
btn.attr('disabled', true)
onGPlusPersonLoaded: (@gplusAttrs) ->
existingUser = new User()
existingUser.fetchGPlusUser(@gplusAttrs.gplusID, {
application.gplusHandler.loadAPI({
context: @
complete: ->
@$('#email-password-row').remove()
success: =>
@$('#gplus-account-exists-row').removeClass('hide')
error: (user, jqxhr) =>
if jqxhr.status is 404
@$('#gplus-logged-in-row').toggleClass('hide')
else
errors.showNotyNetworkError(jqxhr)
success: ->
btn.attr('disabled', false)
application.gplusHandler.connect({
context: @
success: ->
btn.find('.sign-in-blurb').text($.i18n.t('signup.creating'))
btn.attr('disabled', true)
application.gplusHandler.loadPerson({
context: @
success: (@gplusAttrs) ->
existingUser = new User()
existingUser.fetchGPlusUser(@gplusAttrs.gplusID, {
context: @
complete: ->
@$('#email-password-row').remove()
success: =>
@$('#gplus-account-exists-row').removeClass('hide')
error: (user, jqxhr) =>
if jqxhr.status is 404
@$('#gplus-logged-in-row').toggleClass('hide')
else
errors.showNotyNetworkError(jqxhr)
})
})
})
})
onClickGPlusLoginButton: ->
@ -190,31 +179,35 @@ module.exports = class CreateAccountModal extends ModalView
# Facebook
onClickFacebookSignupButton: ->
@clickedFacebookLogin = true
if application.facebookHandler.loggedIn
@onFacebookHandlerLoggedIntoFacebook()
else
application.facebookHandler.loginThroughFacebook()
onFacebookHandlerLoggedIntoFacebook: ->
return unless @clickedFacebookLogin
application.facebookHandler.loadPerson()
btn = @$('#facebook-signup-btn')
btn.find('.sign-in-blurb').text($.i18n.t('signup.creating'))
btn.attr('disabled', true)
onFacebookPersonLoaded: (@facebookAttrs) ->
existingUser = new User()
existingUser.fetchFacebookUser(@facebookAttrs.facebookID, {
success: =>
@$('#email-password-row').remove()
@$('#facebook-account-exists-row').removeClass('hide')
error: (model, jqxhr) =>
@$('#email-password-row').remove()
if jqxhr.status is 404
@$('#facebook-logged-in-row').toggleClass('hide')
else
errors.showNotyNetworkError(jqxhr)
application.facebookHandler.loadAPI({
context: @
success: ->
btn.attr('disabled', false)
application.facebookHandler.connect({
context: @
success: ->
btn.find('.sign-in-blurb').text($.i18n.t('signup.creating'))
btn.attr('disabled', true)
application.facebookHandler.loadPerson({
context: @
success: (@facebookAttrs) ->
existingUser = new User()
existingUser.fetchFacebookUser(@facebookAttrs.facebookID, {
context: @
complete: ->
@$('#email-password-row').remove()
success: =>
@$('#facebook-account-exists-row').removeClass('hide')
error: (user, jqxhr) =>
if jqxhr.status is 404
@$('#facebook-logged-in-row').toggleClass('hide')
else
errors.showNotyNetworkError(jqxhr)
})
})
})
})
onClickFacebookLoginButton: ->

View file

@ -99,11 +99,6 @@ module.exports = class RootView extends CocoView
#location.hash = hash
@renderScrollbar()
getRenderData: ->
c = super()
c.usesSocialMedia = @usesSocialMedia
c
afterRender: ->
if @$el.find('#site-nav').length # hack...
@$el.addClass('site-chrome')

View file

@ -22,11 +22,12 @@ module.exports = class LadderTabView extends CocoView
'click .spectate-cell': 'onClickSpectateCell'
'click .load-more-ladder-entries': 'onLoadMoreLadderEntries'
subscriptions:
'auth:facebook-api-loaded': 'checkFriends'
'auth:gplus-api-loaded': 'checkFriends'
'auth:logged-in-with-facebook': 'onConnectedWithFacebook'
'auth:logged-in-with-gplus': 'onConnectedWithGPlus'
# Refactored, to-reimplement
# subscriptions:
# 'auth:facebook-api-loaded': 'checkFriends'
# 'auth:gplus-api-loaded': 'checkFriends'
# 'auth:logged-in-with-facebook': 'onConnectedWithFacebook'
# 'auth:logged-in-with-gplus': 'onConnectedWithGPlus'
constructor: (options, @level, @sessions) ->
super(options)

View file

@ -1,26 +0,0 @@
FacebookHandler = require 'core/social-handlers/FacebookHandler'
mockAuthEvent =
response:
authResponse:
accessToken: 'aksdhjflkqjrj245234b52k345q344le4j4k5l45j45s4dkljvdaskl'
userID: '4301938'
expiresIn: 5138
signedRequest: 'akjsdhfjkhea.3423nkfkdsejnfkd'
status: 'connected'
window.FB ?= {
api: ->
login: ->
}
describe 'lib/FacebookHandler.coffee', ->
it 'on facebook-logged-in, gets data from FB and sends a patch to the server', ->
me.clear({silent: true})
me.markToRevert()
me.set({_id: '12345'})
facebookHandler = new FacebookHandler()
facebookHandler.loginThroughFacebook()
Backbone.Mediator.publish 'auth:logged-in-with-facebook', mockAuthEvent

View file

@ -6,16 +6,12 @@ describe 'CreateAccountModal', ->
modal = null
initModal = (options) ->
application.facebookHandler.fakeAPI()
application.gplusHandler.fakeAPI()
modal = new CreateAccountModal(options)
modal.render()
modal.render = _.noop
jasmine.demoModal(modal)
window.gapi =
client:
load: _.noop
window.FB =
login: _.noop
api: _.noop
afterEach ->
modal.stopListening()
@ -37,21 +33,21 @@ describe 'CreateAccountModal', ->
it 'fails if nothing is in the form, showing errors for email and password', ->
modal.$('form').each (i, el) -> el.reset()
modal.$('form:first').submit()
modal.$('form').submit()
expect(jasmine.Ajax.requests.all().length).toBe(0)
expect(modal.$('.has-error').length).toBe(2)
it 'fails if email is missing', ->
modal.$('form').each (i, el) -> el.reset()
forms.objectToForm(modal.$el, { name: 'Name', password: 'xyzzy' })
modal.$('form:first').submit()
modal.$('form').submit()
expect(jasmine.Ajax.requests.all().length).toBe(0)
expect(modal.$('.has-error').length).toBeTruthy()
it 'signs up if only email and password is provided', ->
modal.$('form').each (i, el) -> el.reset()
forms.objectToForm(modal.$el, { email: 'some@email.com', password: 'xyzzy' })
modal.$('form:first').submit()
modal.$('form').submit()
requests = jasmine.Ajax.requests.all()
expect(requests.length).toBe(1)
expect(modal.$el.has('.has-warning').length).toBeFalsy()
@ -62,7 +58,7 @@ describe 'CreateAccountModal', ->
beforeEach ->
modal.$('form').each (i, el) -> el.reset()
forms.objectToForm(modal.$el, { email: 'some@email.com', password: 'xyzzy', classCode: 'qwerty' })
modal.$('form:first').submit()
modal.$('form').submit()
expect(jasmine.Ajax.requests.all().length).toBe(1)
it 'checks for Classroom existence if a class code was entered', ->
@ -84,11 +80,9 @@ describe 'CreateAccountModal', ->
describe 'the Classroom does not exist', ->
it 'shows an error and clears the field', ->
request = jasmine.Ajax.requests.mostRecent()
console.log 'school input?', modal.$('#class-code-input').val()
request.respondWith({status: 404, responseText: JSON.stringify({})})
expect(jasmine.Ajax.requests.all().length).toBe(1)
expect(modal.$el.has('.has-error').length).toBeTruthy()
console.log 'school input?', modal.$('#class-code-input').val()
expect(modal.$('#class-code-input').val()).toBe('')
@ -98,12 +92,9 @@ describe 'CreateAccountModal', ->
beforeEach ->
initModal()
application.gplusHandler.trigger 'render-login-buttons'
signupButton = modal.$('#gplus-signup-btn')
expect(signupButton.attr('disabled')).toBeFalsy()
signupButton.click()
application.gplusHandler.fakeGPlusLogin()
application.gplusHandler.trigger 'person-loaded', { firstName: 'Mr', lastName: 'Bean', gplusID: 'abcd', email: 'some@email.com' }
it 'checks to see if the user already exists in our system', ->
requests = jasmine.Ajax.requests.all()
@ -131,7 +122,7 @@ describe 'CreateAccountModal', ->
describe 'and the user finishes signup anyway with new info', ->
beforeEach ->
forms.objectToForm(modal.$el, { email: 'some@email.com', schoolName: 'Hogwarts' })
modal.$('form:first').submit()
modal.$('form').submit()
it 'upserts the values to the new user', ->
request = jasmine.Ajax.requests.mostRecent()
@ -151,7 +142,7 @@ describe 'CreateAccountModal', ->
describe 'and the user finishes signup', ->
beforeEach ->
modal.$('form:first').submit()
modal.$('form').submit()
it 'creates the user with the gplus attributes', ->
request = jasmine.Ajax.requests.mostRecent()
@ -167,12 +158,9 @@ describe 'CreateAccountModal', ->
beforeEach ->
initModal()
Backbone.Mediator.publish 'auth:facebook-api-loaded', {}
signupButton = modal.$('#facebook-signup-btn')
expect(signupButton.attr('disabled')).toBeFalsy()
signupButton.click()
application.facebookHandler.fakeFacebookLogin()
application.facebookHandler.trigger 'person-loaded', { firstName: 'Mr', lastName: 'Bean', facebookID: 'abcd', email: 'some@email.com' }
it 'checks to see if the user already exists in our system', ->
requests = jasmine.Ajax.requests.all()
@ -200,7 +188,7 @@ describe 'CreateAccountModal', ->
describe 'and the user finishes signup anyway with new info', ->
beforeEach ->
forms.objectToForm(modal.$el, { email: 'some@email.com', schoolName: 'Hogwarts' })
modal.$('form:first').submit()
modal.$('form').submit()
it 'upserts the values to the new user', ->
request = jasmine.Ajax.requests.mostRecent()
@ -220,7 +208,7 @@ describe 'CreateAccountModal', ->
describe 'and the user finishes signup', ->
beforeEach ->
modal.$('form:first').submit()
modal.$('form').submit()
it 'creates the user with the facebook attributes', ->
request = jasmine.Ajax.requests.mostRecent()