Author page, load js
This commit is contained in:
parent
3ab0198f21
commit
cfdd62f125
@ -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();
|
||||
}
|
||||
})
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 }}
|
||||
|
@ -1,3 +1,6 @@
|
||||
<script src="/js/vue.min.js"></script>
|
||||
{{ if .PageJs }}
|
||||
<script src="/js/{{ .PageJs }}"></script>
|
||||
{{ end }}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -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">
|
||||
|
Loading…
Reference in New Issue
Block a user