summaryrefslogtreecommitdiff
path: root/public/assets/js/lib
diff options
context:
space:
mode:
Diffstat (limited to 'public/assets/js/lib')
-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
5 files changed, 165 insertions, 46 deletions
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)