Start merging cytube3 account management

This commit is contained in:
calzoneman 2013-12-12 14:48:23 -06:00
parent 8d2587cebd
commit b889f7b4c8
34 changed files with 20908 additions and 1 deletions

View file

@ -0,0 +1,60 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/account/channels")
+navloginlogout("/account/channels")
section#mainpage
.container
if !loggedIn
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-danger.messagebox.center
strong Authorization Required
p You must be <a href="/login">logged in</a> to view this page.
else
.col-lg-6.col-md-6
h3 My Channels
if deleteChannelError
.alert.alert-danger.center.messagebox
strong Channel Deletion Failed
p= deleteChannelError
if channels.length == 0
.center
strong You haven't registered any channels
else
table.table.table-bordered
thead
tr
th Channel
tbody
for c in channels
tr
th
form.form-inline.pull-right(action="/account/channels", method="post", onsubmit="return confirm('Are you sure you want to delete #{c.name}? This cannot be undone');")
input(type="hidden", name="action", value="delete_channel")
button.btn.btn-xs.btn-danger(type="submit") Delete
span.glyphicon.glyphicon-trash
a(href="/r/#{c.name}", style="margin-left: 5px")= c.name
.col-lg-6.col-md-6
h3 Register a new channel
if newChannelError
.alert.alert-danger.messagebox.center
strong Channel Registration Failed
p= newChannelError
form(action="/account/channels", method="post")
input(type="hidden", name="action", value="new_channel")
.form-group
label.control-label(for="channelname") Channel Name
input#channelname.form-control(type="text", name="name")
button.btn.btn-primary.btn-block(type="submit") Register
include footer
+footer()

View file

@ -0,0 +1,94 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/account/edit")
+navloginlogout("/account/edit")
section#mainpage
.container
if !loggedIn
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-danger.messagebox.center
strong Authorization Required
p You must be <a href="/login">logged in</a> to view this page.
else
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
if successMessage
.alert.alert-success.center
p= successMessage
else if errorMessage
.alert.alert-danger.center
p= errorMessage
h3 Change Password
form(action="/account/edit", method="post", onsubmit="return validatePasswordChange()")
input(type="hidden", name="action", value="change_password")
.form-group
label.control-label(for="username") Username
input#username.form-control(type="text", name="name", value=loginName, disabled=true)
.form-group
label.control-label(for="oldpassword") Current Password
input#oldpassword.form-control(type="password", name="oldpassword")
.form-group
label.control-label(for="newpassword") New Password
input#newpassword.form-control(type="password", name="newpassword")
.form-group
label.control-label(for="newpassword_confirm") Confirm New Password
input#newpassword_confirm.form-control(type="password", name="newpassword_confirm")
button#changepassbtn.btn.btn-danger.btn-block(type="submit") Change Password
hr
h3 Change Email
form(action="/account/edit", method="post", onsubmit="return submitEmail()")
input(type="hidden", name="action", value="change_email")
.form-group
label.control-label(for="username2") Username
input#username2.form-control(type="text", name="name", value=loginName, disabled=true)
.form-group
label.control-label(for="password2") Password
input#password2.form-control(type="password", name="password")
.form-group
label.control-label(for="email") New Email
input#email.form-control(type="email", name="email")
button#changeemailbtn.btn.btn-danger.btn-block(type="submit") Change Email
include footer
+footer()
script(type="text/javascript").
function validatePasswordChange() {
var pw = $("#newpassword").val();
var pwc = $("#newpassword_confirm").val();
$("#passwordempty").remove();
$("#passwordmismatch").remove();
if (pw === '') {
$("#newpassword").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "passwordempty")
.text("Password must not be empty")
.insertAfter($("#newpassword"));
return false;
} else {
if (pw !== pwc) {
$("#newpassword_confirm").parent().addClass("has-error");
$("#newpassword").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "passwordmismatch")
.text("Passwords do not match")
.insertAfter($("#newpassword_confirm"));
return false;
} else {
$("#username").attr("disabled", false);
return true;
}
}
}
function submitEmail() {
$("#username2").attr("disabled", false);
return true;
}

108
templates/channel-hd.jade Normal file
View file

@ -0,0 +1,108 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
- var cname = "/r/" + channelName
ul.nav.navbar-nav
+navdefaultlinks(cname)
li: a(href="javascript:showUserOptions()") Options
+navloginlogout(cname)
section#mainpage
.container
#motdwrap.col-lg-12.col-md-12
#motd
#announcements.col-lg-12.col-md-12
.alert.alert-info Demo announcement
#drinkbar.col-lg-12.col-md-12
#drinkcount
#videowrap.hd-video-wrap.col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2
#videoopts.col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2
button#voteskip.btn.btn-sm.btn-default Voteskip
.vertical-spacer.col-lg-8.col-md-8
#playlistwrap.col-lg-6.col-md-6
#playlistheader
button#showimport.btn.btn-default.btn-xs.btn-block(data-toggle="collapse", data-target="#playlistcontrols") Playlist Controls
#playlistcontrols.collapse
strong Add from URL
#fromurl.input-group
input#urlinput.form-control(type="text")
.input-group-btn
button#queuenext.btn.btn-default(type="button") Next
button#queueend.btn.btn-default(type="button") End
hr
#customembed
strong Custom Embed
br
| Acceptable embed codes are <code>&lt;iframe&gt;</code> and <code>&lt;object&gt;</code> tags)
textarea#customembedcode.form-control.input-block-level(rows="3")
.input-group
input#customembedtitle.form-control.input-block-level(placeholder="(Optional) Title")
.input-group-btn
button#customqueuenext.btn.btn-default(type="button") Next
button#customqueueend.btn.btn-default(type="button") End
hr
#misccontrols
strong Additional Controls
button#clearplaylist.btn.btn-xs.btn-default.btn-block(type="button") Clear Playlist
button#shuffleplaylist.btn.btn-xs.btn-default.btn-block(type="button") Shuffle Playlist
hr
button#showsearch.btn.btn-default.btn-xs.btn-block(data-toggle="collapse", data-target="#fromsearch") Search Library/YouTube
#fromsearch.collapse
.input-group
input#ytsearchtext.form-control(type="text")
.input-group-btn
button#libsearchbtn.btn.btn-default(type="button") Library
button#ytsearchbtn.btn.btn-default(type="button") YouTube
hr
#searchresultswrap(style="display: none")
#searchresults
hr
ul#playlist
li
.btn-group.video-buttons
button.btn.btn-xs.btn-default
span.glyphicon.glyphicon-play
button.btn.btn-xs.btn-default
span.glyphicon.glyphicon-share-alt
button.btn.btn-xs.btn-default
span.glyphicon.glyphicon-flag
button.btn.btn-xs.btn-default
span.glyphicon.glyphicon-trash
a.video-title(href="#") Some Video Thing
span.video-time 02:00
span.clear
li
a.video-title(href="#") Some Video Thing
span.video-time 02:00
span.clear
li
a.video-title(href="#") Some Video Thing
span.video-time 02:00
span.clear
#chatwrap.col-lg-6.col-md-6
#chatheader
span Not connected
ul#chatlist.pull-right
li Test
li Test 2
#chatbuffer.linewrap.
sdfngjksdfngjnsdjkgfnjklsdngjksdngfsnjdfg
sdgfsdjifgjksdfngjksdngfjksdfnjgfknsdjkgfnsdgsdbfasdhbfhjbasdhjfbsdhjbghjsdfbghjsdbhjgbsdhjfbghjdsfbghj
fsdfgfnjksdgjnsdjgnfjksngjksngjnksjgnsjnfgsd
gfsnjgfjsnjkg
input#chatline.form-control.input-block-level(type="text")
include footer
+footer()
script(src="#{ioUrl}/socket.io/socket.io.js")
script(type="text/javascript").
var IOSERVER = "#{ioUrl}";
var SOCKET = io.connect(IOSERVER);
script(src="/js/functions.js")

183
templates/channel.jade Normal file
View file

@ -0,0 +1,183 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
- var cname = "/r/" + channelName
ul.nav.navbar-nav
+navdefaultlinks(cname)
li: a(href="javascript:showUserOptions()") Options
li: a(href="javascript:$('#channeloptions').modal()") Channel Settings
+navloginlogout(cname)
section#mainpage
.container
.row
.col-lg-12.col-md-12
#motdwrap.well
button#togglemotd.close.pull-right(type="button")
span.glyphicon.glyphicon-minus
#motd
.clear
#announcements.row
#drinkbarwrap.col-lg-12.col-md-12.row
#drinkbar
h1#drinkcount
#main.row
#chatwrap.col-lg-5.col-md-5
#chatheader
i#userlisttoggle.glyphicon.glyphicon-chevron-up.pull-left.pointer(title="Show/Hide Userlist")
span#usercount.pointer Not Connected
span#modflair.label.label-default.pull-right.pointer M
span#adminflair.label.label-default.pull-right.pointer A
#userlist
#messagebuffer
input#chatline.form-control(type="text", maxlength="240", style="display: none")
#guestlogin.input-group
span.input-group-addon Guest login
input#guestname.form-control(type="text", placeholder="Name")
#videowrap.col-lg-7.col-md-7
p#currenttitle Nothing Playling
#ytapiplayer
.row
#leftcontrols.col-lg-5.col-md-5
button#newpollbtn.btn.btn-sm.btn-default New Poll
#rightcontrols.col-lg-7.col-md-7
#qualitywrap.dropdown.btn-group
button#qdrop.btn.btn-sm.btn-default.dropdown-toggle(data-toggle="dropdown") Quality
b.caret
mixin quality_item(id, text)
li(role="presentation")
a(id="#{id}", role="menuitem", href="javascript:void(0)") #{text}
ul.dropdown-menu(role="menu", aria-labelledby="qdrop")
+quality_item("quality_auto", "Quality: Auto")
+quality_item("quality_240p", "240p")
+quality_item("quality_360p", "360p")
+quality_item("quality_480p", "480p")
+quality_item("quality_720p", "720p")
+quality_item("quality_1080p", "1080p")
button#mediarefresh.btn.btn-sm.btn-default Refresh Media
#playlistrow.row
#leftpane.col-lg-5.col-md-5
#leftpane-inner.row
#pollwrap.col-lg-12.col-md-12
#searchwrap.col-lg-12.col-md-12
button#showsearch.btn.btn-default.btn-block(data-toggle="collapse", data-target="#searchcontrol") Search Library/YouTube
#searchcontrol.collapse
.row.vertical-spacer
#querywrap.col-lg-12.col-md-12
.input-group
input#library_query.form-control(type="text")
span.input-group-btn
button#library_search.btn.btn-default Library
span.input-group-btn
button#youtube_search.btn.btn-default YouTube
ul#library.videolist.col-lg-12.col-md-12
#playlistmanagerwrap.col-lg-12.col-md-12
button#showplaylistmanager.btn.btn-default.btn-block(data-toggle="collapse", data-target="#playlistmanager") Playlist Manager
#playlistmanager.collapse
.row.vertical-spacer
.col-lg-12.col-md-12
.input-group
input#userpl_name.form-control(type="text", placeholder="Playlist Name")
span.input-group-btn
button#userpl_save.btn.btn-default Save
ul#userpl_list.col-lg-12.col-md-12
#rightpane.col-lg-7.col-md-7
#rightpane-inner.row
#playlistcontrolswrap.col-lg-12.col-md-12
button#showplaylistcontrols.btn.btn-default.btn-block(data-toggle="collapse", data-target="#playlistcontrols") Playlist Controls
#playlistcontrols.collapse
.row.vertical-spacer
.col-lg-12.col-md-12
.input-group
input#mediaurl.form-control.input-block-level(type="text", placeholder="Media URL")
span.input-group-btn
button#queue_next.btn.btn-default Next
span.input-group-btn
button#queue_end.btn.btn-default At End
hr
.row
#customembedwrap.col-lg-12.col-md-12
button#showcustomembed.btn.btn-default.btn-block(data-toggle="collapse", data-target="#customembed") Custom Embed
#customembed.collapse
| Paste the embed code below and click Next or At End.
| Acceptable embed codes are <code>&lt;iframe&gt;</code> and <code>&lt;object&gt;</code> tags.
textarea#customembed_code.input-block-level.form-control(rows="3")
hr
.row
#extended_controls.col-lg-12.col-md-12
button#clearplaylist.btn.btn-default.btn-block Clear Playlist
button#shuffleplaylist.btn.btn-default.btn-block Shuffle Playlist
#voteskipwrap.col-lg-12.col-md-12.col-sm-12.col-xs-12.btn-group
button#voteskip.btn.btn-default Voteskip
button#getplaylist.btn.btn-default Get Playlist URLs
button#qlockbtn.btn.btn-danger(title="Playlist Locked")
i.glyphicon.glyphicon-lock
.col-lg-12.col-md-12
#queue.videolist
li.queue_entry
a.qe_title(href="#") Derp
span.qe_time 00:00
div.qe_clear
li.queue_entry.queue_active.queue_temp
a.qe_title(href="#") Derp
span.qe_time 00:00
div.qe_clear
#plmeta
span#plcount 0 items
span#pllength 00:00:00
#resizewrap.row
.col-lg-5.col-md-5
#videowidth.col-lg-7.col-md-7
#sitefooter
#channeloptions.modal.fade(tabindex="-1", role="dialog", aria-hidden="true")
.modal-dialog
.modal-content
.modal-header
button.close(data-dismiss="modal", aria-hidden="true")&times;
h4 Channel Settings
ul.nav.nav-tabs
li: a(href="#cs-miscoptions" data-toggle="tab") General Settings
li: a(href="#cs-adminoptions" data-toggle="tab") Admin Settings
li.dropdown
a#cs-edit-dd-toggle(href="#", data-toggle="dropdown") Edit
span.caret
ul.dropdown-menu
li: a(href="#cs-motdeditor", data-toggle="tab", tabindex="-1") Edit MOTD
li: a(href="#cs-csseditor", data-toggle="tab", tabindex="-1") Edit CSS
li: a(href="#cs-jseditor", data-toggle="tab", tabindex="-1") Edit Javascript
li: a(href="#cs-chanranks", data-toggle="tab", tabindex="-1") Edit user ranks
li: a(href="#cs-banlist", data-toggle="tab", tabindex="-1") Ban list
.modal-body
.tab-content
include channeloptions
+miscoptions()
+adminoptions()
+motdeditor()
+csseditor()
+jseditor()
+banlist()
+recentjoins()
+chanranks()
.modal-footer
button.btn.btn-default(type="button", data-dismiss="modal") Close
include footer
+footer()
script(src="/assets/js/iourl.js")
//script(src="#{ioUrl}/socket.io/socket.io.js")
//script(type="text/javascript").
// var IOSERVER = "#{ioUrl}";
// var SOCKET = io.connect(IOSERVER);
// $('#channeloptions').modal();
// $('#channeloptions a[href="#cs-miscoptions"]').tab('show');
script(src="/assets/js/data.js")
script(src="/assets/js/util.js")
script(src="/assets/js/ui.js")
script(src="/assets/js/callbacks.js")

View file

@ -0,0 +1,100 @@
mixin lcheckbox(id, label)
.form-group
label.control-label.col-sm-4(for=id)= label
.col-sm-8
.checkbox
input(type="checkbox", id=id)
mixin rcheckbox(id, label)
.form-group
.col-sm-8.col-sm-offset-4
.checkbox
label.control-label(for=id)= label
input(type="checkbox", id=id)
mixin textbox(id, label, placeholder)
.form-group
label.control-label.col-sm-4(for=id)= label
.col-sm-8
if placeholder
input.form-control(id=id, type="text", placeholder=placeholder)
else
input.form-control(id=id, type="text")
mixin miscoptions
#cs-miscoptions.tab-pane
h4 General Settings
form.form-horizontal(action="javascript:void(0)")
+rcheckbox("opt_enable_link_regex", "Convert URLs in chat to links")
+rcheckbox("opt_allow_voteskip", "Allow voteskip")
+textbox("opt_voteskip_ratio", "Voteskip ratio", "0.5")
+textbox("opt_maxlength", "Max video length", "HH:MM:SS")
+textbox("opt_afktimeout", "Auto-AFK Delay", "0 (disabled)")
.form-group
.col-sm-8.col-sm-offset-4
button.btn.btn-default#cs-miscoptionssubmit Save
mixin adminoptions
#cs-adminoptions.tab-pane
h4 Admin-Only Settings
form.form-horizontal(action="javascript:void(0)")
- var defname = "CyTube - /r/" + channelName
+textbox("opt_pagetitle", "Page title", defname)
+textbox("opt_password", "Password", "leave blank to disable")
+textbox("opt_externalcss", "External CSS", "Stylesheet URL")
+textbox("opt_externaljs", "External Javascript", "Script URL")
+rcheckbox("opt_show_public", "List channel publicly")
.form-group
.col-sm-8.col-sm-offset-4
button.btn.btn-default#cs-adminoptionssubmit Save
mixin motdeditor
#cs-motdeditor.tab-pane
h4 MOTD editor
p The MOTD can be formatted using a subset of HTML. Tags which attempt to execute Javascript will be removed.
textarea.form-control#cs-motdtext(rows="10")
button.btn.btn-default#cs-motdsubmit Save MOTD
mixin csseditor
#cs-csseditor.tab-pane
h4 CSS editor
p Maximum size 20KB. If more space is required, use the External CSS option under General Settings to link to an externally hosted stylesheet.
textarea.form-control#cs-csstext(rows="10")
button.btn.btn-default#cs-csssubmit Save CSS
mixin jseditor
#cs-jseditor.tab-pane
h4 JS editor
p Maximum size 20KB. If more space is required, use the External JS option under General Settings to link to an externally hosted stylesheet.
textarea.form-control#cs-jstext(rows="10")
button.btn.btn-default#cs-jssubmit Save JS
mixin banlist
#cs-banlist.tab-pane
h4 Ban list
table.table.table-striped
thead
tr
th Unban
th IP
th Name
th Aliases
th Banned by
mixin recentjoins
#cs-recentjoins.tab-pane
h4 Recent connections
table.table.table-striped
thead
tr
th Name
th Aliases
th Time
mixin chanranks
#cs-chanranks.tab-pane
table.table.table-striped
thead
tr
th Name
th Rank

7
templates/footer.jade Normal file
View file

@ -0,0 +1,7 @@
mixin footer
footer#footer
.container
p.text-muted.credit.
Copyright &copy; 2013 Calvin Montgomery
script(src="/js/jquery.js")
script(src="/js/bootstrap.js")

15
templates/head.jade Normal file
View file

@ -0,0 +1,15 @@
mixin head()
meta(charset="utf-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
meta(name="description", content="#{siteDescription}")
meta(name="author", content="#{siteAuthor}")
title= siteTitle
link(href="/css/bootstrap.css", rel="stylesheet")
//link(href="/css/bootstrap-theme.min.css", rel="stylesheet")
link(href="/css/sticky-footer-navbar.css", rel="stylesheet")
link(href="/css/cytube.css", rel="stylesheet")
//[if lt IE 9]
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
//[endif]

16
templates/index.jade Normal file
View file

@ -0,0 +1,16 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/")
+navloginlogout("/")
include footer
+footer()

46
templates/login.jade Normal file
View file

@ -0,0 +1,46 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/login")
if loggedIn
+navlogoutform("/login")
section#mainpage.container
if wasAlreadyLoggedIn
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-info.messagebox.center
h3(style="margin: 5px auto") Logged in as #{loginName}
// TODO Link to My Account page
else if !loggedIn
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
if loginError
.alert.alert-danger.messagebox.center
strong Login Failed
p= loginError
h2 Login
form(role="form", action="/login", method="post")
.form-group
label(for="username") Username
input#username.form-control(type="text", name="name")
.form-group
label(for="password") Password
input#password.form-control(type="password", name="password")
button.btn.btn-success.btn-block(type="submit") Login
else
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-success.messagebox.center
strong Login Successful
p Logged in as #{loginName}
if redirect
br
a(href=redirect) Return to previous page
include footer
+footer()

23
templates/logout.jade Normal file
View file

@ -0,0 +1,23 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/logout")
+navloginform()
section#mainpage.container
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-info.center.messagebox
strong Logged out
p
if redirect
a(href=redirect) Return to previous page
include footer
+footer()

64
templates/nav.jade Normal file
View file

@ -0,0 +1,64 @@
- var links = { "/": "Home" }
mixin navlink(page, title, active)
if active
li.active
a(href=page)= title
else
li
a(href=page)= title
mixin navheader()
.navbar-header
button.navbar-toggle(type="button", data-toggle="collapse", data-target="#nav-collapsible")
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href="/")= siteTitle
mixin navdefaultlinks(page)
each t, p in links
if p == page
+navlink(p, t, true)
else
+navlink(p, t, false)
li.dropdown
a.dropdown-toggle(href="#", data-toggle="dropdown") Account
b.caret
ul.dropdown-menu
if loggedIn
li: a(href="/logout?redirect=#{page}") Logout
li.divider
li: a(href="/account/channels") My Channels
li: a(href="/account/profile") Profile
li: a(href="/account/edit") Change Password/Email
else
li: a(href="/login") Login
li: a(href="/register") Register
mixin navloginlogout(redirect)
if loggedIn
+navlogoutform(redirect)
else
+navloginform(redirect)
mixin navloginform(redirect)
.visible-md.visible-lg
form#loginform.navbar-form.navbar-right(action="/login", method="post")
input(type="hidden", name="redirect", value=redirect)
.form-group
input#username.form-control(type="text", name="name", placeholder="Username")
.form-group
input#password.form-control(type="password", name="password", placeholder="Password")
button#login.btn.btn-default(type="submit") Login
mixin navlogoutform(redirect)
if redirect
- url = "/logout?redirect=#{redirect}"
else
- url = "/logout"
p#logoutform.navbar-text.pull-right
span#welcome Welcome, #{loginName}
span &nbsp;&middot;&nbsp;
a#logout.navbar-link(href=url) Logout

110
templates/register.jade Normal file
View file

@ -0,0 +1,110 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/register")
if loggedIn
+navlogoutform("/register")
section#mainpage.container
if loggedIn
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-danger.messagebox.center
strong Already logged in
p.
You are already logged in. If you intend to register a new account, please <a href="/logout?redirect=/register">Logout</a> first.
// TODO Link to My Account page
else if !registered
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
if registerError
.alert.alert-danger.messagebox.center
strong Registration Failed
p= registerError
h2 Register
form(role="form", action="/register", method="post", onsubmit="return verify()")
.form-group
label.control-label(for="username") Username
input#username.form-control(type="text", name="name")
.form-group
label.control-label(for="password") Password
input#password.form-control(type="password", name="password", onkeyup="checkPasswords()")
.form-group
label.control-label(for="password_confirm") Confirm Password
input#password_confirm.form-control(type="password", onkeyup="checkPasswords()")
.form-group
label.control-label(for="email") Email (optional)
input#email.form-control(type="email", name="email")
p Providing an email address is optional and will allow you to recover your account via email if you forget your password. Your address will not be shared with anyone.
button#registerbtn.btn.btn-success.btn-block(type="submit") Register
else
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
.alert.alert-success.messagebox.center
strong Registration Successful
p Thanks for registering, #{registerName}! Now you can <a href="/login">Login</a> to use your account.
include footer
+footer()
script(src="/js/jquery.js")
script(type="text/javascript").
function verify() {
var valid = checkUsername();
valid = checkPasswords() && valid;
return valid;
}
function checkUsername() {
var name = $("#username").val();
$("#usernameerror").remove();
if (name === "") {
$("#username").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "usernameerror")
.text("Username must not be empty")
.insertAfter($("#username"));
return false;
} else if (!(/^[-\w\u00c0-\u00ff]{1,20}$/).test(name)) {
$("#username").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "usernameerror")
.text("Username must consist of 1-20 characters a-Z, A-Z, 0-9 " +
", -, _, and accented letters.")
.insertAfter($("#username"));
return false;
} else {
$("#username").parent().removeClass("has-error")
.addClass("has-success");
}
}
function checkPasswords() {
var pw = $("#password").val();
var pwc = $("#password_confirm").val();
$("#passwordempty").remove();
$("#passwordmismatch").remove();
if (pw === "") {
$("#password").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "passwordempty")
.text("Password must not be empty")
.insertAfter($("#password"));
return false;
} else {
$("#password").parent().removeClass("has-error")
.addClass("has-success");
if (pw !== pwc) {
$("#password_confirm").parent().addClass("has-error");
$("<p/>").addClass("text-danger")
.attr("id", "passwordmismatch")
.text("Passwords do not match")
.insertAfter($("#password_confirm"));
return false;
} else {
$("#password_confirm").parent().removeClass("has-error")
.addClass("has-success");
}
}
}

17
templates/test.jade Normal file
View file

@ -0,0 +1,17 @@
doctype 5
html(lang="en")
head
include head
+head()
body
#wrap
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
include nav
+navheader()
#nav-collapsible.collapse.navbar-collapse
ul.nav.navbar-nav
+navdefaultlinks("/test")
+navloginform("/test")
include footer
+footer()