diff --git a/README.md b/README.md index 74eb720..fddde4d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Bouquins in Go * tests * UI book: cover in background * auth downloads -* clean unused js * version string in js url (cache) * csrf * vue.js dev/prod diff --git a/assets/js/author.js b/assets/js/author.js deleted file mode 100644 index bcf899c..0000000 --- a/assets/js/author.js +++ /dev/null @@ -1,17 +0,0 @@ -var author = new Vue({ - el: '#author', - data: { - tab: "books" - }, - methods: { - showBooks: function() { - this.tab = "books"; - }, - showAuthors: function() { - this.tab = "authors"; - }, - showSeries: function() { - this.tab = "series"; - } - } -}) diff --git a/assets/js/book.js b/assets/js/book.js deleted file mode 100644 index af5f033..0000000 --- a/assets/js/book.js +++ /dev/null @@ -1,73 +0,0 @@ -var app = new Vue({ - el: '#app', - data: { - urlParams: {}, - book: {} - }, - methods: { - urlParse: function() { - var match, - pl = /\+/g, // Regex for replacing addition symbol with a space - search = /([^&=]+)=?([^&]*)/g, - decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, - query = window.location.search.substring(1); - while (match = search.exec(query)) - this.urlParams[decode(match[1])] = decode(match[2]); - }, - sendQuery: function(url, error, success) { - var xmh = new XMLHttpRequest(); - var v; - - xmh.onreadystatechange = function() { - v = xmh.responseText; - if (xmh.readyState === 4 && xmh.status === 200) { - var res; - try { - res = JSON.parse(v); - } catch (err) { - if (null !== error) - error(err.name, err.message); - } - if (null !== success) - success(res); - } else if (xmh.readyState === 4) { - if (null !== error) - error(xmh.status, v); - } - }; - - xmh.open('GET', url, true); - xmh.send(null); - }, - stdError: function(code, resp) { - console.log('ERROR ' + code + ': ' + resp); - }, - formatBytes: function(bytes) { - if(bytes == 0) return '0'; - var k = 1024; // or 1024 for binary - var sizes = ['Octets', 'Ko', 'Mo', 'Go', 'To', 'Po', 'Eo', 'Zo', 'Yo']; - var i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; - }, - bookCover: function(book) { - return '/calibre/' + encodeURI(book.path) + '/cover.jpg'; - }, - bookLink: function(book, data) { - return '/calibre/' + encodeURI(book.path) + '/' + encodeURI(data.name) + '.' + data.format.toLowerCase(); - }, - bookSuccess: function(resp) { - this.book = resp; - document.title = this.book.title +' | Bouquins'; - }, - loadBook: function() { - if (this.urlParams.id) - this.sendQuery('cgi-bin/bouquins/books/' + this.urlParams.id, this.stdError, this.bookSuccess); - } - }, - created: function() { - this.urlParse(); - }, - mounted: function() { - this.loadBook(); - } -}) diff --git a/assets/js/bouquins.js b/assets/js/bouquins.js new file mode 100644 index 0000000..b2ead4e --- /dev/null +++ b/assets/js/bouquins.js @@ -0,0 +1,408 @@ +var bus = new Vue(); + +// COMPONENTS // + +Vue.component('results-list', { + template: '#results-list-template', + props: ['results', 'count', 'type'], + methods: { + url: function(item) { + return '/'+this.type+'/'+item.id; + }, + label: function(item) { + switch (this.type) { + case 'books': + return item.title; + case 'authors': + case 'series': + return item.name; + default: + return ''; + } + }, + iconClass: function() { + return 'glyphicon glyphicon-' + this.icon(); + }, + icon: function() { + switch (this.type) { + case 'books': + return 'icon'; + case 'authors': + return 'user'; + case 'series': + return 'list'; + default: + return ''; + } + }, + countlabel: function() { + switch (this.type) { + case 'books': + return this.count > 1 ? 'livres' : 'livre'; + case 'authors': + return this.count > 1 ? 'auteurs' : 'auteur'; + case 'series': + return this.count > 1 ? 'series' : 'serie'; + default: + return ''; + } + } + } +}); +Vue.component('results', { + template: '#results-template', + props: ['results', 'cols','sort_by','order_desc'], + methods: { + sortBy: function(col) { + bus.$emit('sort-on', col); + } + } +}); +Vue.component('result-cell', { + render: function(h) { + return h('td', this.cellContent(h)); + }, + props: ['item', 'col'], + methods: { + bookUrl: function(id) { + return '/books/' + id; + }, + authorUrl: function(id) { + return '/authors/' + id; + }, + seriesUrl: function(id) { + return '/series/' + id; + }, + link: function(h, icon, text, url) { + return [ + h('span',{ attrs: { class: 'glyphicon glyphicon-'+icon } },''), + ' ', + h('a', { attrs: { href: url } }, text) + ]; + }, + badge: function(h, num) { + return h('span', { attrs: { class: 'badge' } }, num); + }, + cellContent: function(h) { + switch (this.col.id) { + case 'author_name': + return this.link(h, 'user', this.item.name, this.authorUrl(this.item.id)); + case 'serie_name': + return this.link(h, 'list', this.item.name, this.authorUrl(this.item.id)); + case 'count': + return this.item.count; + case 'title': + return this.link(h, 'book', this.item.title, this.bookUrl(this.item.id)); + case 'authors': + var elts = []; + var authors = this.item.authors; + if (authors) { + for (i=0;i 1) bus.$emit('update-page', -1); + }, + nextPage: function() { + if (this.more) bus.$emit('update-page', 1); + } + } +}); + +// PAGES // + +if (document.getElementById("index")) { + new Vue({ + el: '#index', + data: { + url: '', + page: 0, + perpage: 20, + more: false, + sort_by: null, + order_desc: false, + cols: [], + results: [] + }, + methods: { + sortBy: function(col) { + if (this.sort_by == col) { + if (this.order_desc) { + this.order_desc = false; + this.sort_by = null; + } else { + this.order_desc = true; + } + } else { + this.order_desc = false; + this.sort_by = col; + } + this.updateResults(); + }, + updatePage: function(p) { + this.page += p; + this.updateResults(); + }, + order: function(query) { + if (this.order_desc) + return query + '&order=desc'; + return query; + }, + sort: function(query) { + if (this.sort_by) + return query + '&sort=' + this.sort_by; + return query; + }, + paginate: function(query) { + return query + '?page=' + this.page + '&perpage=' + this.perpage; + }, + params: function(url) { + return this.order(this.sort(this.paginate(url))); + }, + updateResults: function() { + this.sendQuery(this.params(this.url), this.stdError, this.loadResults); + }, + showSeries: function() { + this.url = '/series/'; + this.updateResults(); + }, + showAuthors: function() { + this.url = '/authors/'; + this.updateResults(); + }, + showBooks: function() { + this.url = '/books/'; + this.updateResults(); + }, + loadCols: function(type) { + switch (type) { + case 'books': + this.cols = [ + { id: 'title', name: 'Titre', sort: 'title' }, + { id: 'authors', name: 'Auteur(s)' }, + { id: 'series', name: 'Serie' } + ]; + break; + case 'series': + this.cols = [ + { id: 'serie_name', name: 'Nom', sort: 'name' }, + { id: 'count', name: 'Livre(s)' }, + { id: 'authors', name: 'Auteur(s)' } + ]; + break; + case 'authors': + this.cols = [ + { id: 'author_name', name: 'Nom', sort: 'name' }, + { id: 'count', name: 'Livre(s)' } + ]; + break; + } + }, + loadResults(resp) { + this.results = []; + this.more = resp.more; + this.loadCols(resp.type); + if (resp.results) { + this.results = resp.results; + if (this.page == 0) this.page = 1; + } else { + this.page = 0; + } + }, + sendQuery: function(url, error, success) { + var xmh = new XMLHttpRequest(); + var v; + xmh.onreadystatechange = function() { + v = xmh.responseText; + if (xmh.readyState === 4 && xmh.status === 200) { + var res; + try { + res = JSON.parse(v); + } catch (err) { + if (null !== error) + error(err.name, err.message); + } + if (null !== success) + success(res); + } else if (xmh.readyState === 4) { + if (null !== error) + error(xmh.status, v); + } + }; + xmh.open('GET', url, true); + xmh.setRequestHeader('Accept','application/json'); + xmh.send(null); + }, + stdError: function(code, resp) { + console.log('ERROR ' + code + ': ' + resp); + } + }, + mounted: function() { + bus.$on('sort-on', this.sortBy); + bus.$on('update-page', this.updatePage); + } + }); +} +if (document.getElementById("author")) { + new Vue({ + el: '#author', + data: { + tab: "books" + }, + methods: { + showBooks: function() { + this.tab = "books"; + }, + showAuthors: function() { + this.tab = "authors"; + }, + showSeries: function() { + this.tab = "series"; + } + } + }); +} + +if (document.getElementById("search")) { + new Vue({ + el: '#search', + data: { + authors: [], + books: [], + series: [], + authorsCount: 0, + booksCount: 0, + seriesCount: 0, + q: '', + which: 'all', + all: false, + perpage: 10 + }, + methods: { + searchParams: function(url) { + var res = url; + res += '?perpage=' + this.perpage; + for (var i=0; i 1) bus.$emit('update-page', -1); - }, - nextPage: function() { - if (this.more) bus.$emit('update-page', 1); - } - } -}); -var index = new Vue({ - el: '#index', - data: { - url: '', - page: 0, - perpage: 20, - more: false, - sort_by: null, - order_desc: false, - cols: [], - results: [] - }, - methods: { - sortBy: function(col) { - if (this.sort_by == col) { - if (this.order_desc) { - this.order_desc = false; - this.sort_by = null; - } else { - this.order_desc = true; - } - } else { - this.order_desc = false; - this.sort_by = col; - } - this.updateResults(); - }, - updatePage: function(p) { - this.page += p; - this.updateResults(); - }, - order: function(query) { - if (this.order_desc) - return query + '&order=desc'; - return query; - }, - sort: function(query) { - if (this.sort_by) - return query + '&sort=' + this.sort_by; - return query; - }, - paginate: function(query) { - return query + '?page=' + this.page + '&perpage=' + this.perpage; - }, - params: function(url) { - return this.order(this.sort(this.paginate(url))); - }, - updateResults: function() { - this.sendQuery(this.params(this.url), this.stdError, this.loadResults); - }, - showSeries: function() { - this.url = '/series/'; - this.updateResults(); - }, - showAuthors: function() { - this.url = '/authors/'; - this.updateResults(); - }, - showBooks: function() { - this.url = '/books/'; - this.updateResults(); - }, - loadCols: function(type) { - switch (type) { - case 'books': - this.cols = [ - { id: 'title', name: 'Titre', sort: 'title' }, - { id: 'authors', name: 'Auteur(s)' }, - { id: 'series', name: 'Serie' } - ]; - break; - case 'series': - this.cols = [ - { id: 'serie_name', name: 'Nom', sort: 'name' }, - { id: 'count', name: 'Livre(s)' }, - { id: 'authors', name: 'Auteur(s)' } - ]; - break; - case 'authors': - this.cols = [ - { id: 'author_name', name: 'Nom', sort: 'name' }, - { id: 'count', name: 'Livre(s)' } - ]; - break; - } - }, - loadResults(resp) { - this.results = []; - this.more = resp.more; - this.loadCols(resp.type); - if (resp.results) { - this.results = resp.results; - if (this.page == 0) this.page = 1; - } else { - this.page = 0; - } - }, - sendQuery: function(url, error, success) { - var xmh = new XMLHttpRequest(); - var v; - xmh.onreadystatechange = function() { - v = xmh.responseText; - if (xmh.readyState === 4 && xmh.status === 200) { - var res; - try { - res = JSON.parse(v); - } catch (err) { - if (null !== error) - error(err.name, err.message); - } - if (null !== success) - success(res); - } else if (xmh.readyState === 4) { - if (null !== error) - error(xmh.status, v); - } - }; - xmh.open('GET', url, true); - xmh.setRequestHeader('Accept','application/json'); - xmh.send(null); - }, - stdError: function(code, resp) { - console.log('ERROR ' + code + ': ' + resp); - } - }, - mounted: function() { - bus.$on('sort-on', this.sortBy); - bus.$on('update-page', this.updatePage); - } -}); diff --git a/assets/js/search.js b/assets/js/search.js deleted file mode 100644 index ee1c8cb..0000000 --- a/assets/js/search.js +++ /dev/null @@ -1,166 +0,0 @@ -Vue.component('results-list', { - template: '#results-list-template', - props: ['results', 'count', 'type'], - methods: { - url: function(item) { - return '/'+this.type+'/'+item.id; - }, - label: function(item) { - switch (this.type) { - case 'books': - return item.title; - case 'authors': - case 'series': - return item.name; - default: - return ''; - } - }, - iconClass: function() { - return 'glyphicon glyphicon-' + this.icon(); - }, - icon: function() { - switch (this.type) { - case 'books': - return 'icon'; - case 'authors': - return 'user'; - case 'series': - return 'list'; - default: - return ''; - } - }, - countlabel: function() { - switch (this.type) { - case 'books': - return this.count > 1 ? 'livres' : 'livre'; - case 'authors': - return this.count > 1 ? 'auteurs' : 'auteur'; - case 'series': - return this.count > 1 ? 'series' : 'serie'; - default: - return ''; - } - } - } -}); -var search = new Vue({ - el: '#search', - data: { - authors: [], - books: [], - series: [], - authorsCount: 0, - booksCount: 0, - seriesCount: 0, - q: '', - which: 'all', - all: false, - perpage: 10 - }, - methods: { - searchParams: function(url) { - var res = url; - res += '?perpage=' + this.perpage; - for (var i=0; i - {{ if .PageJs }} - - {{ end }} + diff --git a/templates/header.html b/templates/header.html index 90bab5a..96f5f3c 100644 --- a/templates/header.html +++ b/templates/header.html @@ -7,10 +7,8 @@ - {{ if .PageJs }} - - - {{ end }} + +