Index table books
This commit is contained in:
parent
14764d931f
commit
634d10c63e
@ -1,90 +1,50 @@
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
// TODO ref components tables
|
||||
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: {
|
||||
books: [],
|
||||
authors: [],
|
||||
series: [],
|
||||
booksCount: 0,
|
||||
page: 1,
|
||||
perpage: 20,
|
||||
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: {
|
||||
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);
|
||||
sortBy: function(sort) {
|
||||
console.log("Sort by" + sort);
|
||||
},
|
||||
stdError: function(code, resp) {
|
||||
console.log('ERROR ' + code + ': ' + resp);
|
||||
},
|
||||
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;
|
||||
loadBooks: function() {
|
||||
this.sendQuery(this.params('/books/'), this.stdError, this.booksSuccess);
|
||||
},
|
||||
booksSuccess: function(resp) {
|
||||
this.books = resp;
|
||||
},
|
||||
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();
|
||||
this.books = resp.books;
|
||||
},
|
||||
order: function(query) {
|
||||
if (this.order_desc)
|
||||
@ -102,44 +62,35 @@ var app = new Vue({
|
||||
params: function(url) {
|
||||
return this.order(this.sort(this.paginate(url)));
|
||||
},
|
||||
loadAuthors: function() {
|
||||
this.sendQuery(this.params('cgi-bin/bouquins/authors'), this.stdError, this.authorsSuccess);
|
||||
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);
|
||||
},
|
||||
loadBooks: function() {
|
||||
this.sendQuery(this.params('cgi-bin/bouquins/books'), this.stdError, this.booksSuccess);
|
||||
},
|
||||
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();
|
||||
stdError: function(code, resp) {
|
||||
console.log('ERROR ' + code + ': ' + resp);
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
this.loadIndex();
|
||||
this.loadBooks();
|
||||
}
|
||||
})
|
||||
|
@ -154,9 +154,9 @@ type IndexModel struct {
|
||||
}
|
||||
|
||||
// Constructor IndexModel
|
||||
func NewIndexModel(title string, count int64) *IndexModel {
|
||||
func NewIndexModel(title, js string, count int64) *IndexModel {
|
||||
return &IndexModel{
|
||||
*NewBouquinsModel(title),
|
||||
*NewBouquinsModelJs(title, js),
|
||||
count,
|
||||
nil,
|
||||
nil,
|
||||
@ -206,7 +206,7 @@ func paramInt(name string, req *http.Request) int {
|
||||
val := req.URL.Query().Get(name)
|
||||
valInt, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Print("Invalid value for", name, ":", val)
|
||||
log.Println("Invalid value for", name, ":", val)
|
||||
return 0
|
||||
}
|
||||
return valInt
|
||||
@ -226,7 +226,7 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
model := NewIndexModel("", count)
|
||||
model := NewIndexModel("", "index.js", count)
|
||||
order, sort := paramOrder(req), req.URL.Query().Get(PARAM_SORT)
|
||||
limit, offset := paramInt(PARAM_LIMIT, req), paramInt(PARAM_OFFSET, req)
|
||||
switch req.URL.Query().Get(PARAM_LIST) {
|
||||
@ -259,7 +259,24 @@ func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
|
||||
// FIXME 404
|
||||
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 {
|
||||
// FIXME 404
|
||||
log.Fatalln(err)
|
||||
@ -275,6 +292,7 @@ func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
app.render(res, TPL_BOOKS, model)
|
||||
}
|
||||
}
|
||||
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
|
||||
if !strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
|
||||
// FIXME 404
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script src="/js/vue.min.js"></script>
|
||||
<script src="/js/vue.js"></script>
|
||||
{{ if .PageJs }}
|
||||
<script src="/js/{{ .PageJs }}"></script>
|
||||
{{ end }}
|
||||
|
@ -5,8 +5,8 @@
|
||||
<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">
|
||||
<link rel="preload" href="/js/vue.js" as="script">
|
||||
<link rel="prefetch" href="/js/vue.js">
|
||||
{{ if .PageJs }}
|
||||
<link rel="preload" href="/js/{{ .PageJs }}" as="script">
|
||||
<link rel="prefetch" href="/js/{{ .PageJs }}">
|
||||
|
@ -1,6 +1,6 @@
|
||||
{{ template "header.html" . }}
|
||||
<div class="container" id="app">
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<div class="jumbotron" id="index">
|
||||
<h1>Bouquins</h1>
|
||||
<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>
|
||||
@ -8,31 +8,11 @@
|
||||
<button class="btn btn-primary" type="button" @click="showSeries">Series</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
{{ 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 }}
|
||||
{{ 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 }}
|
||||
{{ template "index_paginate.html" }}
|
||||
{{/* template "index_series.html" */}}
|
||||
{{/* template "index_authors.html" */}}
|
||||
{{ template "index_books.html" }}
|
||||
{{ template "index_paginate.html" }}
|
||||
</div>
|
||||
</div>
|
||||
{{ 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>
|
||||
<th>
|
||||
<a href="#" @click="sortBy('title')">Nom</a>
|
||||
@ -7,23 +7,21 @@
|
||||
<th>Auteur(s)</th>
|
||||
<th>Serie</th>
|
||||
</tr>
|
||||
{{ range . }}
|
||||
<tr>
|
||||
<tr v-for="book in books">
|
||||
<td><span class="glyphicon glyphicon-book"></span>
|
||||
<a href="/books/{{ .Id }}">{{ .Title }}</a></td>
|
||||
<a :href="'/books/'+book.id">{{ "{{" }} book.title {{ "}}" }}</a></td>
|
||||
<td>
|
||||
{{ range .Authors }}
|
||||
<template v-for="author in book.authors">
|
||||
<span class="glyphicon glyphicon-user"></span>
|
||||
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
<a :href="'/authors/'+author.id">{{ "{{" }} author.name {{ "}}" }}</a>
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
{{ if .Series }}
|
||||
<template v-if="book.series">
|
||||
<span class="glyphicon glyphicon-list"></span>
|
||||
<a href="/series/{{ .Series.Id }}">{{ .Series.Name }}</a>
|
||||
<span class="badge">{{ .Book.SeriesIndex }}</span>
|
||||
{{ end }}
|
||||
<a :href="'/series/'+book.series.id">{{ "{{" }} book.series.name {{ "}}" }}</a>
|
||||
<span class="badge">{{ "{{" }} book.series ? book.series.idx : '' {{ "}}" }}</span>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</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