summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2017-12-15 05:36:50 +0100
committerJules Laplace <julescarbon@gmail.com>2017-12-15 05:36:50 +0100
commit7ad469291c015b33a2d20587db26b9621ed82d00 (patch)
tree83e2a56822033a638d03ff7ddf4bfee3181631e6
parentcc585396a85e3107bb7b4298098b84b738919c8f (diff)
sort file list by name or date, updates audio player
-rw-r--r--bucky/app/bucky.js59
-rw-r--r--bucky/app/router.js29
-rw-r--r--bucky/db/index.js15
-rw-r--r--public/assets/css/bucky.css31
-rw-r--r--public/assets/js/lib/views/details/audio.js42
-rw-r--r--public/assets/js/lib/views/details/files.js71
-rw-r--r--public/assets/js/lib/views/details/index.js2
-rw-r--r--public/assets/js/lib/views/details/settings.js94
-rw-r--r--public/assets/js/lib/views/index/threadbox.js2
-rw-r--r--public/assets/js/util/format.js2
-rw-r--r--public/assets/js/vendor/util.js1
-rw-r--r--views/partials/files.ejs11
-rw-r--r--views/partials/settings.ejs16
13 files changed, 281 insertions, 94 deletions
diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js
index ec0ab8c..25de991 100644
--- a/bucky/app/bucky.js
+++ b/bucky/app/bucky.js
@@ -184,6 +184,8 @@ var bucky = module.exports = {
return res.sendStatus(500)
}
var keyword = util.sanitize(req.body.keyword || "")
+ var privacy = parseInt(req.body.privacy) || 0
+ var allowed = util.sanitize(req.body.allowed || "")
var settings
if (typeof req.body.settings === 'object') {
try {
@@ -194,29 +196,48 @@ var bucky = module.exports = {
if (! settings) {
return res.sendStatus(500)
}
+console.log(privacy)
res.thread.set('title', title)
res.thread.set('keyword', keyword)
res.thread.set('color', util.sanitize(req.body.color || 'blue'))
res.thread.set('revision', res.thread.get('revision')+1)
res.thread.set('settings', settings)
- res.thread.save().then( () => next() )
- },
- ensureInterestedUsers: function(req, res, next){
- // given a thread, find people who might be interested in it
- // - other people who have been in threads with you
- // - other people who have posted on the keyword
- // for now though, just show the last 20 people who have logged in..
- db.getLastlog(21).then( (users) => {
- res.interestedUsers = users
- next()
- }).catch( () => {
- res.interestedUsers = []
+ res.thread.set('privacy', privacy)
+ res.thread.set('allowed', allowed)
+ res.thread.save()
+ .then( () => next() )
+ .catch(err => {
+ console.error(err)
next()
})
},
- ensureThreadUsers: function(req, res, next) {
- db.getThreadUsers(res.thread.get('id')).then(thread_users => {
- res.thread_users = thread_users
+// ensureInterestedUsers: function(req, res, next){
+// // given a thread, find people who might be interested in it
+// // - other people who have been in threads with you
+// // - other people who have posted on the keyword
+// // for now though, just show the last 20 people who have logged in..
+// db.getLastlog(21).then( (users) => {
+// res.interestedUsers = users
+// next()
+// }).catch( () => {
+// res.interestedUsers = []
+// next()
+// })
+// },
+// ensureThreadUsers: function(req, res, next) {
+// db.getThreadUsers(res.thread.get('id')).then(thread_users => {
+// res.thread_users = thread_users
+// next()
+// })
+// },
+ checkUsernames: function(req, res, next) {
+ if (! req.body.usernames) return res.sendStatus(500)
+ db.checkUsernames(req.body.usernames).then( (users) => {
+ res.usernames = users.map(user => user.username)
+ next()
+ }).catch((err) => {
+ console.log(err)
+ res.usernames = []
next()
})
},
@@ -370,6 +391,7 @@ var bucky = module.exports = {
reject(err)
},
success: function(url){
+ console.log("file >", url)
var data = {
thread: res.thread.get('id'),
username: req.user.get('username'),
@@ -436,7 +458,7 @@ var bucky = module.exports = {
res.sendStatus({ error: 'Problem uploading avatar.' })
},
success: function(url){
- console.log(">", url)
+ console.log("avatar >", url)
res.user.set('avatar', url)
next()
}
@@ -461,7 +483,7 @@ var bucky = module.exports = {
next()
},
checkThreadPrivacy: function(req, res, next) {
- if (res.thread.checkPrivacy(req.user)) {
+ if (! res.thread.checkPrivacy(req.user)) {
return res.sendStatus(500)
}
next()
@@ -479,10 +501,11 @@ var bucky = module.exports = {
}
next()
},
- checkThreadsPrivacy: function(req, res, next) {
+ filterPrivateThreads: function(req, res, next) {
res.threads = res.threads.filter(thread => {
return thread.checkPrivacy(req.user)
})
+ next()
},
/* MAIL */
diff --git a/bucky/app/router.js b/bucky/app/router.js
index 106c65e..e24253a 100644
--- a/bucky/app/router.js
+++ b/bucky/app/router.js
@@ -76,8 +76,7 @@ module.exports = function(app){
bucky.sanitizeUser,
function(req, res) {
res.json(res.user)
- }
- )
+ })
app.post("/api/user/:username",
middleware.ensureAuthenticated,
bucky.ensureUser,
@@ -90,6 +89,13 @@ module.exports = function(app){
function(req, res){
res.json(util.sanitizeUser(res.user))
})
+ app.put("/api/checkUsernames",
+ middleware.ensureAuthenticated,
+ bucky.checkUsernames,
+ function(req, res){
+ res.send({ usernames: res.usernames })
+ })
+
/* threads */
@@ -97,7 +103,7 @@ module.exports = function(app){
bucky.ensureLastlog,
middleware.ensureAuthenticated,
bucky.ensureLatestThreads,
- bucky.ensureThreadsPrivacy,
+ bucky.filterPrivateThreads,
bucky.ensureCommentCountsForThreads,
bucky.ensureFileCountsForThreads,
bucky.ensureKeywordsForThreads,
@@ -114,7 +120,7 @@ module.exports = function(app){
bucky.ensureLastlog,
middleware.ensureAuthenticated,
bucky.ensureThreadsForKeyword,
- bucky.ensureThreadsPrivacy,
+ bucky.filterPrivateThreads,
bucky.ensureCommentCountsForThreads,
bucky.ensureFileCountsForThreads,
bucky.ensureKeywordsForThreads,
@@ -127,22 +133,11 @@ module.exports = function(app){
lastlog: res.lastlog,
})
})
- // app.get("/api/thread/:id/interested",
- // middleware.ensureAuthenticated,
- // bucky.ensureThread,
- // bucky.ensureThreadPrivacy,
- // bucky.ensureInterestedUsers,
- // // bucky.ensureThreadUsers,
- // function(req, res){
- // res.json({
- // interestedUsers: res.interestedUsers,
- // })
- // })
app.get("/api/thread/:id",
middleware.ensureAuthenticated,
bucky.ensureThread,
+ bucky.checkThreadPrivacy,
bucky.bumpViewCount,
- bucky.ensureThreadPrivacy,
bucky.ensureKeywordForThread,
bucky.ensureCommentsForThread,
bucky.ensureFilesForThread,
@@ -152,7 +147,6 @@ module.exports = function(app){
function(req, res){
res.json({
thread: res.thread,
- thread_users: res.thread,
comments: res.comments,
files: res.files,
keyword: res.keyword,
@@ -261,6 +255,7 @@ module.exports = function(app){
middleware.ensureAuthenticated,
bucky.ensureKeyword,
bucky.ensureThreadsForKeyword,
+ bucky.filterPrivateThreads,
bucky.ensureCommentCountsForThreads,
bucky.ensureFileCountsForThreads,
bucky.ensureKeywordsForThreads,
diff --git a/bucky/db/index.js b/bucky/db/index.js
index 652f723..f92ba2f 100644
--- a/bucky/db/index.js
+++ b/bucky/db/index.js
@@ -18,8 +18,9 @@ var Thread = db.Thread = bookshelf.Model.extend({
if (this.get('privacy') === 0) return true
let username = user.get('username')
if (this.get('username') === username) return true
- let allowed = this.get('allowed').split(',')
- if (allowed.findIndex(username) !== -1) return true
+ let allowed = (this.get('allowed') || '').split(',')
+ if (allowed.indexOf(username) !== -1) return true
+ return false
}
})
var ThreadUser = db.ThreadUser = bookshelf.Model.extend({
@@ -65,13 +66,19 @@ db.getUsersById = function(ids){
return User.where("id", "in", ids).fetchAll()
}
db.getUsernamesById = function(ids){
- return User.column("id").column("username").where("id", "in", ids).fetchAll()
+ return knex.column("id").column("username")
+ .select().from('users').where("id", "in", ids)
+}
+db.checkUsernames = function(usernames){
+ return knex.column("username")
+ .select().distinct().from('users').where("username", "in", usernames)
}
db.getUserByUsername = function(username) {
return new User({'username': username}).fetch()
}
db.getLastlog = function(limit){
- return knex.column('id').column('username').column('lastseen').select().from('users').orderBy('lastseen', 'desc').limit(limit || 10)
+ return knex.column('id').column('username').column('lastseen')
+ .select().from('users').orderBy('lastseen', 'desc').limit(limit || 10)
}
/* THREADS */
diff --git a/public/assets/css/bucky.css b/public/assets/css/bucky.css
index 03cb81d..e915ded 100644
--- a/public/assets/css/bucky.css
+++ b/public/assets/css/bucky.css
@@ -556,6 +556,8 @@ pre br {
display: block;
}
+/* FILES */
+
#files,
#files tr {
margin: 0; padding: 0;
@@ -599,6 +601,20 @@ pre br {
#files tr.total td:first-child {
padding: 5px;
}
+.bold {
+ font-weight: bold;
+}
+.italic {
+ font-style: italic;
+}
+.total div {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+#files .total td a {
+ display: inline;
+}
#gallery {
width: 100%;
@@ -688,6 +704,21 @@ pre br {
.desktop button.thread_delete:hover {
background: #ff8288;
}
+.allowed_field_container,
+.allowed_names {
+ display: none;
+}
+#thread_controls .allowed_names div {
+ display: inline-block;
+ white-space: nowrap;
+ margin-right: 10px;
+}
+#thread_controls .allowed_names label {
+ min-width: auto;
+ padding-right: 2px;
+ width: auto;
+ display: inline-block;
+}
/* SEARCH */
diff --git a/public/assets/js/lib/views/details/audio.js b/public/assets/js/lib/views/details/audio.js
index 42f5376..e328a07 100644
--- a/public/assets/js/lib/views/details/audio.js
+++ b/public/assets/js/lib/views/details/audio.js
@@ -3,24 +3,35 @@ var audio = (function(){
var el, music = [], current_index = -1
var links, comment, parent
+ var selected = false
var playing = false
audio.init = function () {
- links = document.querySelectorAll("a")
comment = document.querySelector("#comment")
parent = document.querySelector("#audio")
-
- Array.prototype.slice.apply(links).forEach(function(url){
- if (! url.href.match(/(mp3|wav|ogg)/)) return
- url.dataset.index = music.length
- music.push(url)
- })
+
+ audio.index()
audio.build()
}
+ audio.index = function () {
+ music = []
+ var links = document.querySelectorAll("a")
+ Array.prototype.slice.apply(links).forEach(function(link){
+ if (! link.href.match(/(mp3|wav|ogg)/)) return
+ link.dataset.index = music.length
+ music.push(link)
+ if (playing && link.href === el.src) {
+ current_index = parseInt(link.dataset.index)
+ }
+ })
+ if (playing) {
+ audio.set_cursor()
+ }
+ }
audio.build = function () {
el = document.createElement("audio")
el.setAttribute("controls", true)
- el.addEventListener("loadeddata", () => { if (playing) el.play() })
+ el.addEventListener("loadeddata", () => { if (selected) el.play() })
el.addEventListener("ended", audio.next)
el.src = music[0]
parent.appendChild(el)
@@ -33,10 +44,14 @@ var audio = (function(){
document.body.removeEventListener("keydown", audio.keydown)
}
audio.play = function (index) {
+ playing = true
current_index = (parseInt(index) + music.length) % music.length
el.src = music[current_index].href
- playing = document.querySelector(".playing")
- if (playing) playing.classList.remove("playing")
+ audio.set_cursor()
+ }
+ audio.set_cursor = function () {
+ selected = document.querySelector(".playing")
+ if (selected) selected.classList.remove("playing")
music[current_index].classList.add("playing")
}
audio.prev = function (){
@@ -50,6 +65,13 @@ var audio = (function(){
else el.pause()
}
audio.keydown = function(e){
+ function element_is_text_input(el) {
+ var tagName = el.tagName.toLowerCase()
+ return (tagName == 'input' && el.type == 'text' || tagName == 'textarea')
+ }
+ if (element_is_text_input(document.activeElement)) {
+ return
+ }
if (app.typing || e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return
switch (e.keyCode) {
case 37: // left
diff --git a/public/assets/js/lib/views/details/files.js b/public/assets/js/lib/views/details/files.js
index e8832a7..b68d42c 100644
--- a/public/assets/js/lib/views/details/files.js
+++ b/public/assets/js/lib/views/details/files.js
@@ -4,6 +4,8 @@ var FilesView = FormView.extend({
events: {
"click .file": "pick",
+ "click #sortByName": "sortByName",
+ "click #sortByDate": "sortByDate",
},
initialize: function(){
@@ -17,23 +19,61 @@ var FilesView = FormView.extend({
this.$el.hide()
}
var total = 0, has_music = false
+ this.files = files
files.forEach(function(file){
if (is_image(file.filename)) {
// return
}
- this.appendFile(file)
total += file.size
has_music = has_music || file.filename.match(/(mp3|wav|ogg)/i)
}.bind(this))
- var size = hush_size(total)
- var t = this.templateTotal.replace(/{{size_class}}/g, size[0])
- .replace(/{{size}}/g, size[1])
- this.$el.append(t)
+ this.total = total
+ this.has_music = has_music
- if (has_music) {
+ if (this.has_music) {
audio.init()
}
+
+ this.sortByName()
+ },
+
+ files: [],
+ sortedFiles: [],
+ currentSort: 'name',
+ reverse: false,
+
+ sortByName: function(e){
+ e && e.preventDefault()
+ if (this.currentSort !== 'name') {
+ this.currentSort = 'name'
+ this.reverse = false
+ } else {
+ this.reverse = !this.reverse
+ }
+ this.sort((a,b) => cmp(a.filename, b.filename))
+ },
+ sortByDate: function(e){
+ e && e.preventDefault()
+ if (this.currentSort !== 'date') {
+ this.currentSort = 'date'
+ this.reverse = true
+ } else {
+ this.reverse = !this.reverse
+ }
+ this.sort((a,b) => cmp(a.date, b.date))
+ },
+
+ sort: function(f){
+ this.$el.empty()
+ this.sortedFiles = this.reverse ? this.files.sort(f) : this.files.sort(f).reverse()
+ this.sortedFiles.forEach(file => {
+ this.appendFile(file)
+ })
+ this.appendTotal()
+ if (this.has_music) {
+ audio.index()
+ }
},
parse: function(file){
@@ -64,11 +104,28 @@ var FilesView = FormView.extend({
this.$el.append($el)
},
+ appendTotal: function(){
+ var size = hush_size(this.total)
+ var nameClass = this.sort === 'name' ? 'bold' : ''
+ if (nameClass && this.reverse) {
+ nameClass += ' italic'
+ }
+ var dateClass = this.sort === 'date' ? 'bold' : ''
+ if (dateClass && this.reverse) {
+ dateClass += ' italic'
+ }
+ var t = this.templateTotal.replace(/{{size_class}}/g, size[0])
+ .replace(/{{size}}/g, size[1])
+ .replace(/{{nameClass}}/g, nameClass)
+ .replace(/{{dateClass}}/g, dateClass)
+ this.$el.append(t)
+ },
+
pick: function(e){
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return
if (! e.target.href || ! e.target.href.match(/(mp3|wav|ogg)/i)) return
e.preventDefault()
- audio.play( e.target.dataset.index )
+ audio.play( e.target.dataset.index ) // index set in audio.js
},
}) \ No newline at end of file
diff --git a/public/assets/js/lib/views/details/index.js b/public/assets/js/lib/views/details/index.js
index df2aeff..1b67b92 100644
--- a/public/assets/js/lib/views/details/index.js
+++ b/public/assets/js/lib/views/details/index.js
@@ -28,7 +28,7 @@ var DetailsView = View.extend({
populate: function(data){
this.data = data
- console.log(data)
+ // console.log(data)
set_background_color(data.thread.color || (data.keyword ? data.keyword.color : 'plain'))
$("body").removeClass('loading')
var thread = data.thread
diff --git a/public/assets/js/lib/views/details/settings.js b/public/assets/js/lib/views/details/settings.js
index 1124826..0a77774 100644
--- a/public/assets/js/lib/views/details/settings.js
+++ b/public/assets/js/lib/views/details/settings.js
@@ -8,6 +8,10 @@ var ThreadSettingsForm = FormView.extend({
"click .thread_delete": "deleteThread",
"click .close_link": "hide",
"change [name=color]": "changeColor",
+ "change [name=privacy]": "toggleAllowed",
+ "click #allowed_names [type=checkbox]": "removeAllowed",
+ "keydown [name=allowed_field]": "keydownAllowed",
+ "blur [name=allowed_field]": "updateAllowed",
},
action: "",
@@ -29,7 +33,9 @@ var ThreadSettingsForm = FormView.extend({
var settings = thread.settings
var display = thread.display
+ this.thread = thread
this.action = "/api/thread/" + thread.id
+ this.allowed = (this.thread.allowed || "").split(" ").map(s => s.trim()).filter(s => !! s)
this.$(".close_link").attr("href", "/details/" + thread.id)
this.$(".metadata").html(metadata(thread))
@@ -38,6 +44,7 @@ var ThreadSettingsForm = FormView.extend({
this.$("[name=hootbox]").prop("checked", !!thread.settings.hootbox)
this.$("[name=shorturls]").prop("checked", !!thread.settings.shorturls)
this.$("[name=noupload]").prop("checked", !!thread.settings.noupload)
+ this.$("[name=privacy]").prop("checked", !!thread.privacy)
var $color = this.$('[name=color]')
Object.keys(COLORS).forEach((color) => {
@@ -48,13 +55,13 @@ var ThreadSettingsForm = FormView.extend({
})
$color.val(thread.color || keyword ? keyword.color : "")
+ this.toggleAllowed()
this.fetchKeywords()
-// this.fetchAllowedUsers(thread)
$("body").removeClass("loading")
},
- fetchKeywords: function(){
+ fetchKeywords: function(thread){
$.get('/api/keywords', function(data){
var $keyword = this.$('[name=keyword]')
data.keywords
@@ -66,33 +73,62 @@ var ThreadSettingsForm = FormView.extend({
option.innerHTML = keyword
$keyword.append(option)
})
- $keyword.val(thread.keyword)
+ $keyword.val(this.thread.keyword)
}.bind(this))
},
-// fetchAllowedUsers: function(thread){
-// var usernameRegexp = new RegExp('{{username}}', g)
-// $.get('/api/thread/' + thread.id + '/interested', function(data){
-// var $allowed = this.$(".allowed")
-// var tmpl = this.allowedTemplate
-// // make a lookup of existing users
-// var allowed = {}
-// thread.allowed.split(" ").forEach((username) => {
-//
-// })
-// // build the ui
-// data.interestedUsers
-// .map( (a) => a.username)
-// .sort( (a,b) => a < b ? -1 : a === b ? 0 : 1 )
-// .forEach((username) => {
-// var t = tmpl.replace(usernameRegexp, "")
-// .replace('{{checked}}',
-// $keyword.append(option)
-// })
-// $keyword.val(thread.keyword)
-// }.bind(this))
-// },
-
+ toggleAllowed: function(e){
+ var checked = this.$('[name=privacy]').prop('checked')
+ this.$(".allowed_field_container").toggle(checked)
+ this.$(".allowed_names").toggle(checked)
+ if (! checked) return
+ this.$("[name=allowed_field]").focus()
+ this.displayAllowed()
+ },
+
+ displayAllowed: function(e){
+ var $allowedNames = this.$(".allowed_names").empty()
+ this.allowed.forEach(username => {
+ var t = this.allowedTemplate.replace(/{{username}}/g, username)
+ $allowedNames.append(t)
+ })
+ },
+
+ keydownAllowed: function(e){
+ if (e.keyCode === 13) { // enter
+ e.preventDefault()
+ e.stopPropagation()
+ this.updateAllowed()
+ }
+ },
+
+ updateAllowed: function(){
+ var usernames = this.$('[name=allowed_field]').val().replace(/,/g, ' ').split(' ').map(s => s.trim()).filter(s => !! s)
+ this.$('[name=allowed_field]').val('')
+ usernames = usernames.filter( (name) => this.allowed.indexOf(name) === -1 )
+ .map( (name) => sanitize(name) )
+ $.ajax({
+ method: "PUT",
+ url: "/api/checkUsernames",
+ headers: { "csrf-token": $("[name=_csrf]").attr("value") },
+ data: JSON.stringify({ csrf: csrf(), usernames: usernames }),
+ contentType: "application/json",
+ dataType: "json",
+ success: function(data){
+ if (! data.usernames || ! data.usernames.length) return
+ this.allowed = this.allowed.concat(data.usernames)
+ this.displayAllowed()
+ }.bind(this),
+ })
+ },
+
+ removeAllowed: function(){
+ this.allowed = this.$("#allowed_names input[type=checkbox]:checked").map(function(){
+ return $(this).val()
+ })
+ this.displayAllowed()
+ },
+
validate: function(){
var errors = []
var title = $("[name=title]").val()
@@ -107,11 +143,13 @@ var ThreadSettingsForm = FormView.extend({
title: $("[name=title]").val(),
keyword: $("[name=keyword]").val(),
color: $("[name=color]").val(),
+ privacy: $("[name=privacy]:checked").val() ? 1 : 0,
+ allowed: this.allowed.join(","),
settings: {
hootbox: $("[name=hootbox]:checked").val() ? true : false,
shorturls: $("[name=shorturls]:checked").val() ? true : false,
noupload: $("[name=noupload]:checked").val() ? true : false,
- }
+ },
}
return JSON.stringify(data)
},
@@ -125,6 +163,7 @@ var ThreadSettingsForm = FormView.extend({
show: function(){
this.visible = true
+ app.typing = true
this.populate()
this.$el.addClass('visible')
app.router.pushState("/details/" + this.options.parent.data.thread.id + "/settings")
@@ -133,6 +172,7 @@ var ThreadSettingsForm = FormView.extend({
hide: function(e){
e && e.preventDefault()
this.visible = false
+ app.typing = false
this.$el.removeClass('visible')
app.router.pushState("/details/" + this.options.parent.data.thread.id)
},
diff --git a/public/assets/js/lib/views/index/threadbox.js b/public/assets/js/lib/views/index/threadbox.js
index 65ad945..4ecb919 100644
--- a/public/assets/js/lib/views/index/threadbox.js
+++ b/public/assets/js/lib/views/index/threadbox.js
@@ -53,7 +53,7 @@ var ThreadBox = View.extend({
var size = hush_size(thread.size)
var comments = hush_null(thread.comment_count, "c")
var files = hush_null(thread.file_count, "f")
- var dot = privacy_dot(thread.private)
+ var dot = privacy_dot(thread.privacy)
var datetime = verbose_date(thread.lastmodified)
var age = get_age(thread.lastmodified)
var id = thread.id + get_revision(thread)
diff --git a/public/assets/js/util/format.js b/public/assets/js/util/format.js
index 339e4f6..e58928e 100644
--- a/public/assets/js/util/format.js
+++ b/public/assets/js/util/format.js
@@ -28,7 +28,7 @@ function commatize (n) {
function privacy_dot (p) {
if (! p) return "&middot;"
- else return "&middot;:"
+ else return ".:"
}
var short_months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")
diff --git a/public/assets/js/vendor/util.js b/public/assets/js/vendor/util.js
index 34ef45f..b08a914 100644
--- a/public/assets/js/vendor/util.js
+++ b/public/assets/js/vendor/util.js
@@ -71,6 +71,7 @@ function mod(n,m){ return n-(m * floor(n/m)) }
function dist(x0,y0,x1,y1){ return sqrt(pow(x1-x0,2)+pow(y1-y0,2)) }
function angle(x0,y0,x1,y1){ return atan2(y1-y0,x1-x0) }
function avg(m,n,a){ return (m*(a-1)+n)/a }
+function cmp (a,b){ return (a<b)?-1:(a===b)?0:1 }
function noop(){}
function pixel(x,y){ return 4*(mod(y,actual_h)*actual_w+mod(x,actual_w)) }
diff --git a/views/partials/files.ejs b/views/partials/files.ejs
index 5b55f4b..456fe17 100644
--- a/views/partials/files.ejs
+++ b/views/partials/files.ejs
@@ -21,7 +21,16 @@
<script class="templateTotal" type="text/html">
<tr class="total">
<td colspan="5">
- total size: <span class="{{size_class}}">{{size}}</span>
+ <div>
+ <span>
+ <i>sort by</i>
+ <a href="#" class="{{nameClass}}" id="sortByName">name</a>
+ <a href="#" class="{{dateClass}}" id="sortByDate">date</a>
+ </span>
+ <span>
+ total size: <span class="{{size_class}}">{{size}}</span>
+ </span>
+ </div>
</td>
</tr>
</script>
diff --git a/views/partials/settings.ejs b/views/partials/settings.ejs
index 3964429..d3833e1 100644
--- a/views/partials/settings.ejs
+++ b/views/partials/settings.ejs
@@ -30,28 +30,30 @@
</div>
<div>
<label for="thread_hootbox">hoot style</label>
- <input id="thread_hootbox" name="hootbox" value="0" type="hidden">
<input id="thread_hootbox" name="hootbox" value="1" type="checkbox">
</div>
<div>
<label for="thread_noupload">disable uploads</label>
- <input id="thread_noupload" name="noupload" value="0" type="hidden">
<input id="thread_noupload" name="noupload" value="1" type="checkbox">
</div>
<div>
<label for="thread_shorturls">shorten urls</label>
- <input id="thread_shorturls" name="shorturls" value="0" type="hidden">
<input id="thread_shorturls" name="shorturls" value="1" type="checkbox">
</div>
<div>
<label for="thread_privacy">private?</label>
- <input id="thread_privacy" name="privacy" value="0" type="hidden">
<input id="thread_privacy" name="privacy" value="1" type="checkbox">
</div>
- <div class="allowed">
+ <div class="allowed_field_container">
+ <label for="allowed_field">allow names:</label>
+ <input id="allowed_field" name="allowed_field" type="text" />
+ </div>
+ <div class="allowed_names">
<script type="text/html" class="allowedTemplate">
- <label for="user_{{username}}">{{username}}</label>
- <input id="user_{{username}}" name="allowed" value="{{username}}" type="checkbox">
+ <div>
+ <label for="user_{{username}}">{{username}}</label>
+ <input id="user_{{username}}" name="allowed" value="{{username}}" type="checkbox" checked>
+ </div>
</script>
</div>
<div>