Merge and fix external forms

This commit is contained in:
James Allen 2014-06-17 16:19:40 +01:00
commit aa8969c652
14 changed files with 157 additions and 1114 deletions

View file

@ -102,14 +102,25 @@ module.exports = ProjectController =
projects = ProjectController._buildProjectList results.projects[0], results.projects[1], results.projects[2]
ProjectController._injectProjectOwners projects, (error, projects) ->
return next(error) if error?
res.render 'project/list', {
viewModel = {
title:'Your Projects'
priority_title: true
projects: projects
tags: tags
}
if Settings?.algolia?.institutions?.app_id? and Settings?.algolia?.institutions?.api_key?
viewModel.showUserDetailsArea = true
viewModel.algolia_api_key = Settings.algolia.institutions.api_key
viewModel.algolia_app_id = Settings.algolia.institutions.app_id
else
viewModel.showUserDetailsArea = false
res.render 'project/list', viewModel
timer.done()
loadEditor: (req, res, next)->
timer = new metrics.Timer("load-editor")
if !Settings.editorIsOpen

View file

@ -31,8 +31,10 @@ html(itemscope, itemtype='http://schema.org/Product')
script(type="text/javascript").
window.csrfToken = "#{csrfToken}";
script(src=jsPath+'libs/jquery.js')
script(src=jsPath+'libs/angular-1.2.17.js')
script(src=jsPath+'libs/moment-2.4.0.js')
script(src=jsPath+'libs/underscore-1.3.3.js')
block scripts
- if (typeof(bodyClasses) == "undefined")

View file

@ -6,12 +6,18 @@ block scripts
projects: !{JSON.stringify(projects)},
tags: !{JSON.stringify(tags)}
};
window.algolia = {
institutions: {
app_id: '#{algolia_app_id}',
api_key: '#{algolia_api_key}'
}
};
block content
.content.content-alt(ng-controller="ProjectPageController")
.container
.row
.col-md-2
.col-md-3
#newProject.dropdown
a.btn.btn-primary.dropdown-toggle(
href="#",
@ -80,7 +86,66 @@ block content
.row-spaced
a(href="/user/bonus").btn.btn-info Upgrade Account
.col-md-10
- if (showUserDetailsArea)
.row-spaced#userProfileInformation(ng-cloak)
div(ng-controller="UpdateForm").userProfileInformationArea
div(ng-hide="hidePersonalInfoSection").alert.alert-info
div(ng-show="percentComplete >= 100")
h4 100% complete, well done!
div(ng-hide="percentComplete >= 100")
h4 Your profile is
strong {{percentComplete}}%
| complete
.progress
.bar.bar-success(ng-style="{'width' : (percentComplete+'%')}")
button#completeUserProfileInformation.btn.btn-primary(
ng-hide="formVisable",
ng-click="showForm()"
) Complete now
div(ng-show="formVisable")
form(enctype='multipart/form-data', method='post')
.form-group
input.form-control(
type='text',
name='first_name',
ng-model="userInfoForm.first_name",
ng-blur="sendUpdate()",
placeholder="First Name",
focus-input="formVisable"
)
.form-group
input.form-control(
type='text',
name='last_name',
ng-model="userInfoForm.last_name",
ng-blur="sendUpdate()",
placeholder='Last Name'
)
.form-group#institution_auto_complete
autocomplete(
ng-model="userInfoForm.institution",
data="institutions",
ng-blur="sendUpdate()",
on-type="updateInstitutionsList",
attr-placeholder="Institution",
attr-inputclass="form-control"
)
.form-group
input.form-control(
type='text',
name='role',
ng-model="userInfoForm.role",
placeholder='Role',
ng-blur="sendUpdate()",
list="_roles"
)
datalist#_roles
option(ng-repeat='role in roles') {{role}}
.col-md-9
.container-fluid
.row
.col-md-12

View file

@ -8,14 +8,22 @@ block content
.card
.page-header
h1 Login
.messageArea
form.validate#loginForm(enctype='multipart/form-data', method='post')
form(async-form="login", action='/login')
input(name='_csrf', type='hidden', value=csrfToken)
input(name='redir', type='hidden', value=redir)
form-messages
.form-group
input#email.email.required.form-control(type='email', autofocus="autofocus", name='email', placeholder='email@example.com')
input.form-control(
type='email',
name='email',
placeholder='email@example.com'
)
.form-group
input#password.required.form-control(type='password', name='password', placeholder='********')
input.form-control(
type='password',
name='password',
placeholder='********'
)
.actions
button.btn-primary.btn#login(type='submit') Login
a#passwordReset.pull-right(href='/user/password/reset') Forgot your password?
button.btn-primary.btn(type='submit') Login
a.pull-right(href='/user/password/reset') Forgot your password?

View file

@ -9,10 +9,20 @@ block content
.page-header
h1 Password Reset
.messageArea
form.validate#passwordReset(method='post')
form(
async-form="password-reset-request",
action="/user/password/reset"
)
input(type="hidden", name="_csrf", value=csrfToken)
form-messages
.alert.alert-success(ng-show="success")
| You have been sent an email to complete your password reset.
.form-group
label(for='email') Please enter your email address
input.email.required.form-control(type='email', name='email', placeholder='email@example.com')
input.form-control(
type='email',
name='email',
placeholder='email@example.com'
)
.actions
button.btn.btn-primary.btn.btn-large(type='submit') Request password reset
button.btn.btn-primary(type='submit') Request password reset

View file

@ -18,16 +18,16 @@ block content
.card
.page-header
h1 Register
.messageArea
form#registerFormShort(method="post")
form(async-form="register", action="/register")
input(name='_csrf', type='hidden', value=csrfToken)
input(name='redir', type='hidden', value=redir)
form-messages
.form-group
label(for='email') Email
input#email.email.required.form-control(type='email', name='email', value='#{new_email}')
input.form-control(type='email', name='email', value='#{new_email}')
.form-group
label(for='password') Password
input#password.required.form-control(type='password', name='password')
input.form-control(type='password', name='password')
.actions
button#registerButton.btn-primary.btn(type='submit') Register
button.btn-primary.btn(type='submit') Register

View file

@ -8,11 +8,26 @@ block content
.card
.page-header
h1 Reset your password
.messageArea
form.validate#setPasswordReset(method='post')
form(
async-form="password-reset",
action="/user/password/set"
)
input(type="hidden", name="_csrf", value=csrfToken)
form-messages
.alert.alert-success(ng-show="success")
| Your password has been reset.
a(href='/login') Login here
.form-group
input.password.required.form-control(type='password', name='password', placeholder='new password')
input(type="hidden", name="passwordResetToken", value=passwordResetToken)
input.form-control(
type='password',
name='password',
placeholder='new password'
)
input(
type="hidden",
name="passwordResetToken",
value=passwordResetToken
)
.actions
button.btn.btn-primary.btn.btn-large(type='submit') Set new password
button.btn.btn-primary(type='submit') Set new password

View file

@ -1,5 +1,6 @@
define [
"project-list"
"user-details"
"directives/asyncForm"
], () ->
angular.bootstrap(document.body, ["SharelatexApp"])

View file

@ -2,8 +2,8 @@ define [
"base"
"../libs/algolia"
], (App, algolia)->
App.factory "Institutions", ->
new AlgoliaSearch("SK53GL4JLY", "1606ccef5b70ac44680b61e6b0285126").initIndex("institutions")
app.factory "Institutions", ->
new AlgoliaSearch(window.algolia.institutions.app_id, window.algolia.institutions.api_key).initIndex("institutions")
App.directive "focusInput", ($timeout) ->
return (scope, element, attr) ->

View file

@ -1,16 +0,0 @@
require [
"libs/jquery.storage"
"libs/bootstrap"
], ()->
$('tr.clickable').click (event)->
window.location = $(event.target).closest('tr').attr("href")
$('.dropdown-toggle').dropdown()
# $('.tabs').tab('show')
$(".carousel").carousel()
$("#scribtexModal").modal()
return

View file

@ -1,5 +0,0 @@
define [
"libs/bootstrap"
"forms"
], ()->
$(document).ready ()->

File diff suppressed because it is too large Load diff

View file

@ -296,6 +296,16 @@ input[type="checkbox"],
.form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);
}
// .form-control.ng-invalid {
// border-color: @state-danger-text;
// .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
// &:focus {
// border-color: darken(@state-danger-text, 10%);
// @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@state-danger-text, 20%);
// .box-shadow(@shadow);
// }
// }
// Static form control text
//

View file

@ -18,10 +18,14 @@ describe "UserInfoController", ->
updatePersonalInfo: sinon.stub()
@sanitizer = escape:(v)->v
sinon.spy @sanitizer, "escape"
@UserGetter = {}
@UserInfoController = SandboxedModule.require modulePath, requires:
"./UserGetter": @UserGetter = {}
"./UserGetter": @UserGetter
"./UserUpdater": @UserUpdater
"./UserDeleter": @UserDeleter
"logger-sharelatex": log:->
"sanitizer":@sanitizer
@req = new MockRequest()
@ -33,7 +37,9 @@ describe "UserInfoController", ->
@user =
_id: ObjectId()
@req.user = @user
@req.session.user = @user
@UserInfoController.sendFormattedPersonalInfo = sinon.stub()
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, @user)
@UserInfoController.getLoggedInUsersPersonalInfo(@req, @res, @next)
it "should call sendFormattedPersonalInfo", ->
@ -105,6 +111,8 @@ describe "UserInfoController", ->
email: "doug@sharelatex.com"
password: "should-not-get-included"
signUpDate: new Date()
role:"student"
institution:"sheffield"
@UserInfoController._formatPersonalInfo @user, (error, info) =>
expect(info).to.deep.equal {
id: @user._id.toString()
@ -112,6 +120,8 @@ describe "UserInfoController", ->
last_name: @user.last_name
email: @user.email
signUpDate: @user.signUpDate
role: @user.role
institution: @user.institution
}
describe "setPersonalInfo", ->