Author page, load js

This commit is contained in:
Meutel 2017-08-04 18:57:15 +02:00
parent 3ab0198f21
commit cfdd62f125
7 changed files with 101 additions and 142 deletions

View File

@ -1,83 +1,9 @@
var app = new Vue({
el: '#app',
var author = new Vue({
el: '#author',
data: {
urlParams: {},
author: {},
tab: "books"
},
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);
},
authorSuccess: function(resp) {
this.author = resp;
document.title = this.author.name +' | Bouquins';
this.author.series=[];
this.author.authors=[];
if (this.author.books) {
var series = [];
var authors = [];
for (var i=0;i<this.author.books.length;i++) {
var book = this.author.books[i];
if (book.series)
series.push(book.series);
if (book.authors)
authors.push.apply(authors, book.authors);
}
if (series.length > 0) {
series.sort();
this.author.series = [series[0]];
for (var i=1;i<series.length;i++) {
if (series[i-1].id !== series[i].id)
this.author.series.push(series[i]);
}
}
if (authors.length > 0) {
authors.sort();
for (var i=0;i<authors.length;i++) {
if ((this.author.authors.length == 0
|| this.author.authors[this.author.authors.length] != authors[i])
&& authors[i].id != this.author.id)
this.author.authors.push(authors[i]);
}
}
}
},
showBooks: function() {
this.tab = "books";
},
@ -86,16 +12,6 @@ var app = new Vue({
},
showSeries: function() {
this.tab = "series";
},
loadAuthor: function() {
if (this.urlParams.id)
this.sendQuery('cgi-bin/bouquins/authors/' + this.urlParams.id, this.stdError, this.authorSuccess);
}
},
created: function() {
this.urlParse();
},
mounted: function() {
this.loadAuthor();
}
})

View File

@ -94,7 +94,9 @@ type BookAdv struct {
type AuthorFull struct {
Author
Books []*BookAdv `json:"books,omitempty"`
Books []*Book `json:"books,omitempty"`
Series []*Series `json:"series,omitempty"`
CoAuthors []*Author `json:"coauthors,omitempty"`
}
type BookFull struct {
@ -124,12 +126,17 @@ type SeriesFull struct {
type BouquinsModel struct {
Title string `json:"title,omitempty"`
PageJs string `json:"-"`
}
// Constructor BouquinsModel
func NewBouquinsModel(title string) *BouquinsModel {
return NewBouquinsModelJs(title, "")
}
func NewBouquinsModelJs(title, js string) *BouquinsModel {
return &BouquinsModel{
title,
js,
}
}
@ -263,7 +270,7 @@ func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
log.Fatalln(err)
}
app.render(res, TPL_AUTHORS, &AuthorModel{
*NewBouquinsModel(author.Name),
*NewBouquinsModelJs(author.Name, "author.js"),
author,
})
}

View File

@ -95,10 +95,11 @@ const (
LEFT OUTER JOIN series ON series.id = books_series_link.series
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
WHERE books_authors_link.author = ? ORDER BY id`
STMT_AUTHORS_AUTHORS = `SELECT authors.id, authors.name, books_authors_link.book as book
STMT_AUTHOR_AUTHORS = `SELECT DISTINCT authors.id, authors.name
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
AND books_authors_link.book IN ( SELECT books.id FROM books LEFT OUTER JOIN books_authors_link
ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)`
ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)
AND authors.id != ? ORDER BY authors.id`
STMT_AUTHOR = "SELECT name FROM authors WHERE id = ?"
DEF_LIM = 10
@ -116,6 +117,7 @@ const (
SERIES_BOOKS QueryType = iota
AUTHOR QueryType = iota
AUTHOR_BOOKS QueryType = iota
AUTHOR_COAUTHORS QueryType = iota
)
var QUERIES = map[Query]string{
@ -141,6 +143,7 @@ var QUERIES = map[Query]string{
Query{SERIES_BOOKS, false, false}: STMT_SERIE_BOOKS,
Query{AUTHOR, false, false}: STMT_AUTHOR,
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS,
}
var STMTS = make(map[Query]*sql.Stmt)

View File

@ -1,6 +1,8 @@
package bouquins
import "database/sql"
import (
"database/sql"
)
// SUB QUERIES //
@ -14,15 +16,16 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
return err
}
defer rows.Close()
series := make(map[int64]*Series, 0)
for rows.Next() {
book := new(BookAdv)
book := new(Book)
var seriesId sql.NullInt64
var seriesName sql.NullString
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &seriesName, &seriesId); err != nil {
return err
}
if seriesId.Valid && seriesName.Valid {
book.Series = &Series{
series[seriesId.Int64] = &Series{
seriesId.Int64,
seriesName.String,
}
@ -32,11 +35,33 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
if err := rows.Err(); err != nil {
return err
}
author.Series = make([]*Series, 0, len(series))
for _, s := range series {
author.Series = append(author.Series, s)
}
return nil
}
func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
// TODO
stmt, err := app.ps(AUTHOR_COAUTHORS)
if err != nil {
return err
}
rows, err := stmt.Query(author.Id, author.Id)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
coauthor := new(Author)
if err = rows.Scan(&coauthor.Id, &coauthor.Name); err != nil {
return err
}
author.CoAuthors = append(author.CoAuthors, coauthor)
}
if err := rows.Err(); err != nil {
return err
}
return nil
}

View File

@ -1,5 +1,5 @@
{{ template "header.html" . }}
<div class="container" id="app">
<div class="container" id="author">
{{ if .Id }}
<div class="page-header">
<h1>
@ -9,12 +9,12 @@
</div>
<ul class="nav nav-pills">
<li role="presentation" :class="{ active: tab == 'books' }"><a href="#" @click="showBooks">Livres</a></li>
{{/* if gt (len .Series) 0 */}}
{{ if gt (len .Series) 0 }}
<li role="presentation" :class="{ active: tab == 'series' }"><a href="#" @click="showSeries">Series</a></li>
{{/* end */}}
{{/* if gt (len .Authors) 0 */}}
{{ end }}
{{ if gt (len .CoAuthors) 0 }}
<li role="presentation" :class="{ active: tab == 'authors' }"><a href="#" @click="showAuthors">Co-auteurs</a></li>
{{/* end */}}
{{ end }}
</ul>
<div class="panel panel-default" :class="{ hidden: tab != 'books' }">
<div class="panel-body">
@ -27,33 +27,32 @@
{{ end }}
</div>
</div>
{{ if gt (len .Series) 0 }}
<div class="panel panel-default" :class="{ hidden: tab != 'series' }">
<div class="panel-body">
{{ range .Books }}
{{/* FIXME unicity */}}
{{ with .Series }}
{{ range .Series }}
<ul class="list-unstyled">
<li><span class="glyphicon glyphicon-list"></span>
<a href="/series/{{ .Id }}">{{ .Name }}</a>
</li>
</ul>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
{{ if gt (len .CoAuthors) 0 }}
<div class="panel panel-default" :class="{ hidden: tab != 'authors' }">
<div class="panel-body">
{{ range .Books }}
{{ range .Authors }}
{{ range .CoAuthors }}
<ul class="list-unstyled">
<li> <span class="glyphicon glyphicon-user"></span>
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
</li>
</ul>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
{{ else }}
<div class="alert alert-danger" role="alert">Aucun auteur sélectionné</div>
{{ end }}

View File

@ -1,3 +1,6 @@
<script src="/js/vue.min.js"></script>
{{ if .PageJs }}
<script src="/js/{{ .PageJs }}"></script>
{{ end }}
</body>
</html>

View File

@ -5,6 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="preload" href="/js/vue.min.js" as="script">
<link rel="prefetch" href="/js/vue.min.js">
{{ if .PageJs }}
<link rel="preload" href="/js/{{ .PageJs }}" as="script">
<link rel="prefetch" href="/js/{{ .PageJs }}">
{{ end }}
</head>
<body>
<nav class="navbar navbar-inverse" id="nav">