Index table books
This commit is contained in:
parent
14764d931f
commit
634d10c63e
@ -1,90 +1,50 @@
|
|||||||
var app = new Vue({
|
// TODO ref components tables
|
||||||
el: '#app',
|
var index = new Vue({
|
||||||
|
el: '#index',
|
||||||
|
data: {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showSeries: function() {
|
||||||
|
console.log("Series");
|
||||||
|
},
|
||||||
|
showAuthors: function() {
|
||||||
|
console.log("Authors");
|
||||||
|
},
|
||||||
|
showBooks: function() {
|
||||||
|
console.log("Books");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var books = new Vue({
|
||||||
|
el: '#books',
|
||||||
data: {
|
data: {
|
||||||
books: [],
|
|
||||||
authors: [],
|
|
||||||
series: [],
|
|
||||||
booksCount: 0,
|
|
||||||
page: 1,
|
page: 1,
|
||||||
perpage: 20,
|
perpage: 20,
|
||||||
sort_by: null,
|
sort_by: null,
|
||||||
order_desc: false
|
order_desc: false,
|
||||||
|
books: [ {
|
||||||
|
id: 456,
|
||||||
|
title: "Test title",
|
||||||
|
authors: [ {
|
||||||
|
id: 123,
|
||||||
|
name: "Test author"
|
||||||
|
} ],
|
||||||
|
series: {
|
||||||
|
id: 789,
|
||||||
|
name: "Test series",
|
||||||
|
idx: 1
|
||||||
|
}
|
||||||
|
} ]
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sendQuery: function(url, error, success) {
|
sortBy: function(sort) {
|
||||||
var xmh = new XMLHttpRequest();
|
console.log("Sort by" + sort);
|
||||||
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) {
|
loadBooks: function() {
|
||||||
console.log('ERROR ' + code + ': ' + resp);
|
this.sendQuery(this.params('/books/'), this.stdError, this.booksSuccess);
|
||||||
},
|
|
||||||
indexSuccess: function(resp) {
|
|
||||||
this.booksCount = resp.count;
|
|
||||||
},
|
|
||||||
loadIndex: function() {
|
|
||||||
this.sendQuery('cgi-bin/bouquins/index', this.stdError, this.indexSuccess);
|
|
||||||
},
|
|
||||||
authorsSuccess: function(resp) {
|
|
||||||
this.authors = resp;
|
|
||||||
},
|
},
|
||||||
booksSuccess: function(resp) {
|
booksSuccess: function(resp) {
|
||||||
this.books = resp;
|
this.books = resp.books;
|
||||||
},
|
|
||||||
seriesSuccess: function(resp) {
|
|
||||||
this.series = resp;
|
|
||||||
},
|
|
||||||
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.reload();
|
|
||||||
},
|
|
||||||
reload: function() {
|
|
||||||
if (this.books.length > 0)
|
|
||||||
this.loadBooks();
|
|
||||||
if (this.authors.length > 0)
|
|
||||||
this.loadAuthors();
|
|
||||||
if (this.series.length > 0)
|
|
||||||
this.loadSeries();
|
|
||||||
},
|
|
||||||
prevPage: function() {
|
|
||||||
if (this.page > 1) {
|
|
||||||
this.page--;
|
|
||||||
this.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nextPage: function() {
|
|
||||||
this.page++;
|
|
||||||
this.reload();
|
|
||||||
},
|
},
|
||||||
order: function(query) {
|
order: function(query) {
|
||||||
if (this.order_desc)
|
if (this.order_desc)
|
||||||
@ -102,44 +62,35 @@ var app = new Vue({
|
|||||||
params: function(url) {
|
params: function(url) {
|
||||||
return this.order(this.sort(this.paginate(url)));
|
return this.order(this.sort(this.paginate(url)));
|
||||||
},
|
},
|
||||||
loadAuthors: function() {
|
sendQuery: function(url, error, success) {
|
||||||
this.sendQuery(this.params('cgi-bin/bouquins/authors'), this.stdError, this.authorsSuccess);
|
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);
|
||||||
},
|
},
|
||||||
loadBooks: function() {
|
stdError: function(code, resp) {
|
||||||
this.sendQuery(this.params('cgi-bin/bouquins/books'), this.stdError, this.booksSuccess);
|
console.log('ERROR ' + code + ': ' + resp);
|
||||||
},
|
|
||||||
loadSeries: function() {
|
|
||||||
this.sendQuery(this.params('cgi-bin/bouquins/series'), this.stdError, this.seriesSuccess);
|
|
||||||
},
|
|
||||||
showSeries: function() {
|
|
||||||
this.books = [];
|
|
||||||
this.authors = [];
|
|
||||||
this.page = 1;
|
|
||||||
this.perpage = 20;
|
|
||||||
this.order_desc = false;
|
|
||||||
this.sort_by = null;
|
|
||||||
this.loadSeries();
|
|
||||||
},
|
|
||||||
showAuthors: function() {
|
|
||||||
this.books = [];
|
|
||||||
this.series = [];
|
|
||||||
this.page = 1;
|
|
||||||
this.perpage = 20;
|
|
||||||
this.order_desc = false;
|
|
||||||
this.sort_by = null;
|
|
||||||
this.loadAuthors();
|
|
||||||
},
|
|
||||||
showBooks: function() {
|
|
||||||
this.authors = [];
|
|
||||||
this.series = [];
|
|
||||||
this.page = 1;
|
|
||||||
this.perpage = 20;
|
|
||||||
this.order_desc = false;
|
|
||||||
this.sort_by = null;
|
|
||||||
this.loadBooks();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
this.loadIndex();
|
this.loadBooks();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -154,9 +154,9 @@ type IndexModel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructor IndexModel
|
// Constructor IndexModel
|
||||||
func NewIndexModel(title string, count int64) *IndexModel {
|
func NewIndexModel(title, js string, count int64) *IndexModel {
|
||||||
return &IndexModel{
|
return &IndexModel{
|
||||||
*NewBouquinsModel(title),
|
*NewBouquinsModelJs(title, js),
|
||||||
count,
|
count,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -206,7 +206,7 @@ func paramInt(name string, req *http.Request) int {
|
|||||||
val := req.URL.Query().Get(name)
|
val := req.URL.Query().Get(name)
|
||||||
valInt, err := strconv.Atoi(val)
|
valInt, err := strconv.Atoi(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("Invalid value for", name, ":", val)
|
log.Println("Invalid value for", name, ":", val)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return valInt
|
return valInt
|
||||||
@ -226,7 +226,7 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
model := NewIndexModel("", count)
|
model := NewIndexModel("", "index.js", count)
|
||||||
order, sort := paramOrder(req), req.URL.Query().Get(PARAM_SORT)
|
order, sort := paramOrder(req), req.URL.Query().Get(PARAM_SORT)
|
||||||
limit, offset := paramInt(PARAM_LIMIT, req), paramInt(PARAM_OFFSET, req)
|
limit, offset := paramInt(PARAM_LIMIT, req), paramInt(PARAM_OFFSET, req)
|
||||||
switch req.URL.Query().Get(PARAM_LIST) {
|
switch req.URL.Query().Get(PARAM_LIST) {
|
||||||
@ -259,7 +259,24 @@ func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
|
|||||||
// FIXME 404
|
// FIXME 404
|
||||||
log.Fatalln("Invalid URL")
|
log.Fatalln("Invalid URL")
|
||||||
}
|
}
|
||||||
id, err := strconv.Atoi(req.URL.Path[len(URL_BOOKS):])
|
idParam := req.URL.Path[len(URL_BOOKS):]
|
||||||
|
if len(idParam) == 0 {
|
||||||
|
// books list
|
||||||
|
if req.Header.Get("Accept") == "application/json" {
|
||||||
|
model := NewIndexModel("", "", 0) // FIXME model books/paginate
|
||||||
|
var err error
|
||||||
|
model.Books, err = app.BooksAdv(10, 0, "", "") // FIXME params
|
||||||
|
res.Header().Set("Content-Type", "application/json")
|
||||||
|
enc := json.NewEncoder(res)
|
||||||
|
err = enc.Encode(model)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
http.Error(res, err.Error(), 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// book page
|
||||||
|
id, err := strconv.Atoi(idParam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// FIXME 404
|
// FIXME 404
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
@ -275,6 +292,7 @@ func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
app.render(res, TPL_BOOKS, model)
|
app.render(res, TPL_BOOKS, model)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
|
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
|
||||||
if !strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
|
if !strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
|
||||||
// FIXME 404
|
// FIXME 404
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<script src="/js/vue.min.js"></script>
|
<script src="/js/vue.js"></script>
|
||||||
{{ if .PageJs }}
|
{{ if .PageJs }}
|
||||||
<script src="/js/{{ .PageJs }}"></script>
|
<script src="/js/{{ .PageJs }}"></script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
<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="preload" href="/js/vue.js" as="script">
|
||||||
<link rel="prefetch" href="/js/vue.min.js">
|
<link rel="prefetch" href="/js/vue.js">
|
||||||
{{ if .PageJs }}
|
{{ if .PageJs }}
|
||||||
<link rel="preload" href="/js/{{ .PageJs }}" as="script">
|
<link rel="preload" href="/js/{{ .PageJs }}" as="script">
|
||||||
<link rel="prefetch" href="/js/{{ .PageJs }}">
|
<link rel="prefetch" href="/js/{{ .PageJs }}">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
<div class="container" id="app">
|
<div class="container">
|
||||||
<div class="jumbotron">
|
<div class="jumbotron" id="index">
|
||||||
<h1>Bouquins</h1>
|
<h1>Bouquins</h1>
|
||||||
<p>Cette bibliothèque contient actuellement <strong>{{ .BooksCount }}</strong> livres et BD en format papier ou électronique.</p>
|
<p>Cette bibliothèque contient actuellement <strong>{{ .BooksCount }}</strong> livres et BD en format papier ou électronique.</p>
|
||||||
<button class="btn btn-primary" type="button" @click="showBooks">Livres</button>
|
<button class="btn btn-primary" type="button" @click="showBooks">Livres</button>
|
||||||
@ -8,31 +8,11 @@
|
|||||||
<button class="btn btn-primary" type="button" @click="showSeries">Series</button>
|
<button class="btn btn-primary" type="button" @click="showSeries">Series</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
{{ if (ne (len .Books) 0) or (ne (len .Authors) 0) or (ne (len .Series) 0) }}
|
{{ template "index_paginate.html" }}
|
||||||
<nav aria-label="Pages">
|
{{/* template "index_series.html" */}}
|
||||||
<ul class="pager">
|
{{/* template "index_authors.html" */}}
|
||||||
<li class="previous" v-bind:class="{ disabled: page <= 1 }"><a href="#" @click="prevPage"><span aria-hidden="true">←</span> Précédents</a></li>
|
{{ template "index_books.html" }}
|
||||||
<li class="next"><a href="#" @click="nextPage">Suivants <span aria-hidden="true">→</span></a></li>
|
{{ template "index_paginate.html" }}
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{{ end }}
|
|
||||||
{{ if ne (len .Series) 0 }}
|
|
||||||
{{ template "index_series.html" .Series }}
|
|
||||||
{{ end }}
|
|
||||||
{{ if ne (len .Authors) 0 }}
|
|
||||||
{{ template "index_authors.html" .Authors }}
|
|
||||||
{{ end }}
|
|
||||||
{{ if ne (len .Books) 0 }}
|
|
||||||
{{ template "index_books.html" .Books }}
|
|
||||||
{{ end }}
|
|
||||||
{{ if (ne (len .Books) 0) or (ne (len .Authors) 0) or (ne (len .Series) 0) }}
|
|
||||||
<nav aria-label="Pages">
|
|
||||||
<ul class="pager">
|
|
||||||
<li class="previous" v-bind:class="{ disabled: page <= 1 }"><a href="#" @click="prevPage"><span aria-hidden="true">←</span> Précédents</a></li>
|
|
||||||
<li class="next"><a href="#" @click="nextPage">Suivants <span aria-hidden="true">→</span></a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ template "footer.html" . }}
|
{{ template "footer.html" . }}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<table class="table table-striped">
|
<table id="books" class="table table-striped" v-if="books.length > 0">
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<a href="#" @click="sortBy('title')">Nom</a>
|
<a href="#" @click="sortBy('title')">Nom</a>
|
||||||
@ -7,23 +7,21 @@
|
|||||||
<th>Auteur(s)</th>
|
<th>Auteur(s)</th>
|
||||||
<th>Serie</th>
|
<th>Serie</th>
|
||||||
</tr>
|
</tr>
|
||||||
{{ range . }}
|
<tr v-for="book in books">
|
||||||
<tr>
|
|
||||||
<td><span class="glyphicon glyphicon-book"></span>
|
<td><span class="glyphicon glyphicon-book"></span>
|
||||||
<a href="/books/{{ .Id }}">{{ .Title }}</a></td>
|
<a :href="'/books/'+book.id">{{ "{{" }} book.title {{ "}}" }}</a></td>
|
||||||
<td>
|
<td>
|
||||||
{{ range .Authors }}
|
<template v-for="author in book.authors">
|
||||||
<span class="glyphicon glyphicon-user"></span>
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
<a :href="'/authors/'+author.id">{{ "{{" }} author.name {{ "}}" }}</a>
|
||||||
{{ end }}
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ if .Series }}
|
<template v-if="book.series">
|
||||||
<span class="glyphicon glyphicon-list"></span>
|
<span class="glyphicon glyphicon-list"></span>
|
||||||
<a href="/series/{{ .Series.Id }}">{{ .Series.Name }}</a>
|
<a :href="'/series/'+book.series.id">{{ "{{" }} book.series.name {{ "}}" }}</a>
|
||||||
<span class="badge">{{ .Book.SeriesIndex }}</span>
|
<span class="badge">{{ "{{" }} book.series ? book.series.idx : '' {{ "}}" }}</span>
|
||||||
{{ end }}
|
</template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
|
||||||
</table>
|
</table>
|
||||||
|
6
templates/index_paginate.html
Normal file
6
templates/index_paginate.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<nav aria-label="Pages">
|
||||||
|
<ul class="pager">
|
||||||
|
<li class="previous" v-bind:class="{ disabled: page <= 1 }"><a href="#" @click="prevPage"><span aria-hidden="true">←</span> Précédents</a></li>
|
||||||
|
<li class="next"><a href="#" @click="nextPage">Suivants <span aria-hidden="true">→</span></a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
Loading…
Reference in New Issue
Block a user