Author page, load js
This commit is contained in:
parent
3ab0198f21
commit
cfdd62f125
@ -1,83 +1,9 @@
|
|||||||
var app = new Vue({
|
var author = new Vue({
|
||||||
el: '#app',
|
el: '#author',
|
||||||
data: {
|
data: {
|
||||||
urlParams: {},
|
|
||||||
author: {},
|
|
||||||
tab: "books"
|
tab: "books"
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
showBooks: function() {
|
||||||
this.tab = "books";
|
this.tab = "books";
|
||||||
},
|
},
|
||||||
@ -86,16 +12,6 @@ var app = new Vue({
|
|||||||
},
|
},
|
||||||
showSeries: function() {
|
showSeries: function() {
|
||||||
this.tab = "series";
|
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 {
|
type AuthorFull struct {
|
||||||
Author
|
Author
|
||||||
Books []*BookAdv `json:"books,omitempty"`
|
Books []*Book `json:"books,omitempty"`
|
||||||
|
Series []*Series `json:"series,omitempty"`
|
||||||
|
CoAuthors []*Author `json:"coauthors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookFull struct {
|
type BookFull struct {
|
||||||
@ -123,13 +125,18 @@ type SeriesFull struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BouquinsModel struct {
|
type BouquinsModel struct {
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
|
PageJs string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor BouquinsModel
|
// Constructor BouquinsModel
|
||||||
func NewBouquinsModel(title string) *BouquinsModel {
|
func NewBouquinsModel(title string) *BouquinsModel {
|
||||||
|
return NewBouquinsModelJs(title, "")
|
||||||
|
}
|
||||||
|
func NewBouquinsModelJs(title, js string) *BouquinsModel {
|
||||||
return &BouquinsModel{
|
return &BouquinsModel{
|
||||||
title,
|
title,
|
||||||
|
js,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +270,7 @@ func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
app.render(res, TPL_AUTHORS, &AuthorModel{
|
app.render(res, TPL_AUTHORS, &AuthorModel{
|
||||||
*NewBouquinsModel(author.Name),
|
*NewBouquinsModelJs(author.Name, "author.js"),
|
||||||
author,
|
author,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -95,52 +95,55 @@ const (
|
|||||||
LEFT OUTER JOIN series ON series.id = books_series_link.series
|
LEFT OUTER JOIN series ON series.id = books_series_link.series
|
||||||
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
|
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
|
||||||
WHERE books_authors_link.author = ? ORDER BY id`
|
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
|
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
|
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 = ?"
|
STMT_AUTHOR = "SELECT name FROM authors WHERE id = ?"
|
||||||
|
|
||||||
DEF_LIM = 10
|
DEF_LIM = 10
|
||||||
|
|
||||||
BOOKS QueryType = iota
|
BOOKS QueryType = iota
|
||||||
BOOKS_TAGS QueryType = iota
|
BOOKS_TAGS QueryType = iota
|
||||||
BOOKS_AUTHORS QueryType = iota
|
BOOKS_AUTHORS QueryType = iota
|
||||||
BOOK QueryType = iota
|
BOOK QueryType = iota
|
||||||
BOOK_TAGS QueryType = iota
|
BOOK_TAGS QueryType = iota
|
||||||
BOOK_DATA QueryType = iota
|
BOOK_DATA QueryType = iota
|
||||||
BOOK_AUTHORS QueryType = iota
|
BOOK_AUTHORS QueryType = iota
|
||||||
BOOKS_COUNT QueryType = iota
|
BOOKS_COUNT QueryType = iota
|
||||||
SERIES QueryType = iota
|
SERIES QueryType = iota
|
||||||
SERIES_AUTHORS QueryType = iota
|
SERIES_AUTHORS QueryType = iota
|
||||||
SERIES_BOOKS QueryType = iota
|
SERIES_BOOKS QueryType = iota
|
||||||
AUTHOR QueryType = iota
|
AUTHOR QueryType = iota
|
||||||
AUTHOR_BOOKS QueryType = iota
|
AUTHOR_BOOKS QueryType = iota
|
||||||
|
AUTHOR_COAUTHORS QueryType = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
var QUERIES = map[Query]string{
|
var QUERIES = map[Query]string{
|
||||||
Query{BOOKS, true, true}: STMT_BOOKS_TITLE_DESC,
|
Query{BOOKS, true, true}: STMT_BOOKS_TITLE_DESC,
|
||||||
Query{BOOKS, true, false}: STMT_BOOKS_TITLE_ASC,
|
Query{BOOKS, true, false}: STMT_BOOKS_TITLE_ASC,
|
||||||
Query{BOOKS, false, true}: STMT_BOOKS_ID_DESC,
|
Query{BOOKS, false, true}: STMT_BOOKS_ID_DESC,
|
||||||
Query{BOOKS, false, false}: STMT_BOOKS_ID_ASC,
|
Query{BOOKS, false, false}: STMT_BOOKS_ID_ASC,
|
||||||
Query{BOOKS_TAGS, true, true}: STMT_BOOKS_TAGS_TITLE_DESC,
|
Query{BOOKS_TAGS, true, true}: STMT_BOOKS_TAGS_TITLE_DESC,
|
||||||
Query{BOOKS_TAGS, true, false}: STMT_BOOKS_TAGS_TITLE_ASC,
|
Query{BOOKS_TAGS, true, false}: STMT_BOOKS_TAGS_TITLE_ASC,
|
||||||
Query{BOOKS_TAGS, false, true}: STMT_BOOKS_TAGS_ID_DESC,
|
Query{BOOKS_TAGS, false, true}: STMT_BOOKS_TAGS_ID_DESC,
|
||||||
Query{BOOKS_TAGS, false, false}: STMT_BOOKS_TAGS_ID_ASC,
|
Query{BOOKS_TAGS, false, false}: STMT_BOOKS_TAGS_ID_ASC,
|
||||||
Query{BOOKS_AUTHORS, true, true}: STMT_BOOKS_AUTHORS_TITLE_DESC,
|
Query{BOOKS_AUTHORS, true, true}: STMT_BOOKS_AUTHORS_TITLE_DESC,
|
||||||
Query{BOOKS_AUTHORS, true, false}: STMT_BOOKS_AUTHORS_TITLE_ASC,
|
Query{BOOKS_AUTHORS, true, false}: STMT_BOOKS_AUTHORS_TITLE_ASC,
|
||||||
Query{BOOKS_AUTHORS, false, true}: STMT_BOOKS_AUTHORS_ID_DESC,
|
Query{BOOKS_AUTHORS, false, true}: STMT_BOOKS_AUTHORS_ID_DESC,
|
||||||
Query{BOOKS_AUTHORS, false, false}: STMT_BOOKS_AUTHORS_ID_ASC,
|
Query{BOOKS_AUTHORS, false, false}: STMT_BOOKS_AUTHORS_ID_ASC,
|
||||||
Query{BOOK, false, false}: STMT_BOOK,
|
Query{BOOK, false, false}: STMT_BOOK,
|
||||||
Query{BOOK_TAGS, false, false}: STMT_BOOK_TAGS,
|
Query{BOOK_TAGS, false, false}: STMT_BOOK_TAGS,
|
||||||
Query{BOOK_DATA, false, false}: STMT_BOOK_DATA,
|
Query{BOOK_DATA, false, false}: STMT_BOOK_DATA,
|
||||||
Query{BOOK_AUTHORS, false, false}: STMT_BOOK_AUTHORS,
|
Query{BOOK_AUTHORS, false, false}: STMT_BOOK_AUTHORS,
|
||||||
Query{BOOKS_COUNT, false, false}: STMT_BOOKS_COUNT,
|
Query{BOOKS_COUNT, false, false}: STMT_BOOKS_COUNT,
|
||||||
Query{SERIES, false, false}: STMT_SERIE,
|
Query{SERIES, false, false}: STMT_SERIE,
|
||||||
Query{SERIES_AUTHORS, false, false}: STMT_SERIE_AUTHORS,
|
Query{SERIES_AUTHORS, false, false}: STMT_SERIE_AUTHORS,
|
||||||
Query{SERIES_BOOKS, false, false}: STMT_SERIE_BOOKS,
|
Query{SERIES_BOOKS, false, false}: STMT_SERIE_BOOKS,
|
||||||
Query{AUTHOR, false, false}: STMT_AUTHOR,
|
Query{AUTHOR, false, false}: STMT_AUTHOR,
|
||||||
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
|
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
|
||||||
|
Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS,
|
||||||
}
|
}
|
||||||
var STMTS = make(map[Query]*sql.Stmt)
|
var STMTS = make(map[Query]*sql.Stmt)
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package bouquins
|
package bouquins
|
||||||
|
|
||||||
import "database/sql"
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
// SUB QUERIES //
|
// SUB QUERIES //
|
||||||
|
|
||||||
@ -14,15 +16,16 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
series := make(map[int64]*Series, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
book := new(BookAdv)
|
book := new(Book)
|
||||||
var seriesId sql.NullInt64
|
var seriesId sql.NullInt64
|
||||||
var seriesName sql.NullString
|
var seriesName sql.NullString
|
||||||
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &seriesName, &seriesId); err != nil {
|
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &seriesName, &seriesId); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if seriesId.Valid && seriesName.Valid {
|
if seriesId.Valid && seriesName.Valid {
|
||||||
book.Series = &Series{
|
series[seriesId.Int64] = &Series{
|
||||||
seriesId.Int64,
|
seriesId.Int64,
|
||||||
seriesName.String,
|
seriesName.String,
|
||||||
}
|
}
|
||||||
@ -32,11 +35,33 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
|||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
author.Series = make([]*Series, 0, len(series))
|
||||||
|
for _, s := range series {
|
||||||
|
author.Series = append(author.Series, s)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
<div class="container" id="app">
|
<div class="container" id="author">
|
||||||
{{ if .Id }}
|
{{ if .Id }}
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>
|
<h1>
|
||||||
@ -9,12 +9,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li role="presentation" :class="{ active: tab == 'books' }"><a href="#" @click="showBooks">Livres</a></li>
|
<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>
|
<li role="presentation" :class="{ active: tab == 'series' }"><a href="#" @click="showSeries">Series</a></li>
|
||||||
{{/* end */}}
|
{{ end }}
|
||||||
{{/* if gt (len .Authors) 0 */}}
|
{{ if gt (len .CoAuthors) 0 }}
|
||||||
<li role="presentation" :class="{ active: tab == 'authors' }"><a href="#" @click="showAuthors">Co-auteurs</a></li>
|
<li role="presentation" :class="{ active: tab == 'authors' }"><a href="#" @click="showAuthors">Co-auteurs</a></li>
|
||||||
{{/* end */}}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="panel panel-default" :class="{ hidden: tab != 'books' }">
|
<div class="panel panel-default" :class="{ hidden: tab != 'books' }">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@ -27,33 +27,32 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ if gt (len .Series) 0 }}
|
||||||
<div class="panel panel-default" :class="{ hidden: tab != 'series' }">
|
<div class="panel panel-default" :class="{ hidden: tab != 'series' }">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{{ range .Books }}
|
{{ range .Series }}
|
||||||
{{/* FIXME unicity */}}
|
|
||||||
{{ with .Series }}
|
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><span class="glyphicon glyphicon-list"></span>
|
<li><span class="glyphicon glyphicon-list"></span>
|
||||||
<a href="/series/{{ .Id }}">{{ .Name }}</a>
|
<a href="/series/{{ .Id }}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ if gt (len .CoAuthors) 0 }}
|
||||||
<div class="panel panel-default" :class="{ hidden: tab != 'authors' }">
|
<div class="panel panel-default" :class="{ hidden: tab != 'authors' }">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{{ range .Books }}
|
{{ range .CoAuthors }}
|
||||||
{{ range .Authors }}
|
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li> <span class="glyphicon glyphicon-user"></span>
|
<li> <span class="glyphicon glyphicon-user"></span>
|
||||||
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<div class="alert alert-danger" role="alert">Aucun auteur sélectionné</div>
|
<div class="alert alert-danger" role="alert">Aucun auteur sélectionné</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
<script src="/js/vue.min.js"></script>
|
<script src="/js/vue.min.js"></script>
|
||||||
|
{{ if .PageJs }}
|
||||||
|
<script src="/js/{{ .PageJs }}"></script>
|
||||||
|
{{ end }}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-inverse" id="nav">
|
<nav class="navbar navbar-inverse" id="nav">
|
||||||
|
Loading…
Reference in New Issue
Block a user