X-Git-Url: https://git.mdrn.pl/wl-mobile.git/blobdiff_plain/bff5852b5ee1320a6eaf4256570784bbc024496f..b9acd6c8b2300a76624900cd19f9e40e59ff3f7b:/www/js/catalogue.js diff --git a/www/js/catalogue.js b/www/js/catalogue.js new file mode 100644 index 0000000..40cd0bd --- /dev/null +++ b/www/js/catalogue.js @@ -0,0 +1,408 @@ +/* + * This file is part of WolneLektury-Mobile, licensed under GNU Affero GPLv3 or later. + * Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. + */ + +var DB_VER = '0.9.17'; + +var WL_INITIAL = WL + '/media/api/mobile/initial/initial.db'; +var WL_UPDATE = WL + '/api/changes/SINCE.json?book_fields=author,html,parent,parent_number,sort_key,title' + + '&tag_fields=books,category,name,sort_key' + + '&tag_categories=author,epoch,genre,kind'; + + + +var categories = {'author': 'autor', + 'epoch': 'epoka', + 'genre': 'gatunek', + 'kind': 'rodzaj', + 'theme': 'motyw' + } + +// FIXME: htmlescape strings! + + +// for preparing sql statements +// use like: +// var s = new Sql("INSERT ... '{0}', '{1}' ..."; +// s.prepare("abc", ...) +var Sql = function(scheme) { + var self = this; + self.text = scheme; + + self.sql_escape = function(term) { + return term.toString().replace("'", "''"); + }; + + self.prepare = function() { + var args = arguments; + return self.text.replace(/{(\d+)}/g, function(match, number) { + return self.sql_escape(args[parseInt(number)]); + }); + } +}; + + +var Catalogue = new function() { + /* API for database */ + + var self = this; + self.db = null; + + this.init = function(success, error) { + debug('Catalogue.init'); + + self.updateDB(function() { + if (!self.db) + self.db = window.openDatabase("wolnelektury", "1.0", "WL Catalogue", 1000000); + if (self.db) { + /*var regexp = { + onFunctionCall: function(val) { + var re = new RegExp(val.getString(0)); + if (val.getString(1).match(re)) + return 1; + else + return 0; + } + }; + self.db.createFunction("REGEXP", 2, regexp);*/ + + success && success(); + } else { + error && error('Nie mogę otworzyć bazy danych: ' + err); + } + + }, function(err) { + error && error('Błąd migracji: ' + err); + }); + }; + + self.sqlSanitize = function(term) { + return term.toString().replace("'", "''"); + }; + + + /* check if DB needs updating and upload a fresh copy, if so */ + this.updateDB = function(success, error) { + var has_ver = window.localStorage.getItem('db_ver'); + if (has_ver == DB_VER) { + debug('db ok, skipping') + success && success(); + return; + } + + var done = function() { + FileRepo.clear(); + window.localStorage.setItem('db_ver', DB_VER); + debug('db updated'); + success && success(); + }; + + // db initialize + // this is Android-specific for now + self.createdb(done, error); + }; + + + this.createdb = function(success, error) { + debug('create db'); + + var dbname = "wolnelektury"; + var db = window.openDatabase(dbname, "1.0", "WL Catalogue", 1000000); + if (db) { + debug('db created successfully'); + self.db = db; + var sqls = []; + sqls.push('CREATE TABLE IF NOT EXISTS book (\ + id INTEGER PRIMARY KEY,\ + title VARCHAR,\ + html_file VARCHAR,\ + html_file_size INTEGER,\ + parent INTEGER,\ + parent_number INTEGER,\ + sort_key VARCHAR,\ + pretty_size VARCHAR,\ + authors VARCHAR,\ + _local BOOLEAN\ + );'); + sqls.push('CREATE INDEX IF NOT EXISTS book_title_index ON book (title);'); + sqls.push('CREATE INDEX IF NOT EXISTS book_sort_key_index ON book (sort_key);'); + sqls.push('CREATE INDEX IF NOT EXISTS book_parent_index ON book (parent);'); + sqls.push('CREATE TABLE IF NOT EXISTS tag (\ + id INTEGER PRIMARY KEY,\ + name VARCHAR,\ + category VARCHAR,\ + sort_key VARCHAR,\ + books VARCHAR\ + );'); + sqls.push('CREATE INDEX IF NOT EXISTS tag_name_index ON tag (name);'); + sqls.push('CREATE INDEX IF NOT EXISTS tag_category_index ON tag (category);'); + sqls.push('CREATE INDEX IF NOT EXISTS tag_sort_key_index ON tag (name);'); + sqls.push('CREATE TABLE IF NOT EXISTS state (last_checked INTEGER);'); + sqls.push('DELETE FROM state;'); + sqls.push('INSERT INTO state (last_checked) VALUES(0);'); + self.chainSqls(sqls, success, error); + /*DBPut.fetch(WL_INITIAL, function(data) { + debug('db fetch successful'); + success && success(); + }, function(data) { + error && error('Błąd podczas pobierania bazy danych: ' + data); + });*/ + } else { + error && error('Błąd podczas inicjowania bazy danych: ' + data); + } + }; + + + this.withState = function(callback) { + self.db.transaction(function(tx) { + tx.executeSql("SELECT * FROM state", [], + function(tx, results) { + if (results.rows.length) { + callback(results.rows.item(0)); + } + else { + callback({last_checked: 0}); + } + }); + }); + }; + + + this.withBook = function(id, callback, error) { + debug('withBook '+id) + self.db.transaction(function(tx) { + tx.executeSql("SELECT * FROM book WHERE id="+id, [], + function(tx, results) { + if (results.rows.length) { + callback(results.rows.item(0)); + } + else { + error && error(); + } + }); + }); + }; + + this.withBooks = function(ids, callback) { + debug('withBooks ' + ids) + self.db.transaction(function(tx) { + tx.executeSql("SELECT * FROM book WHERE id IN ("+ids+") ORDER BY sort_key", [], + function(tx, results) { + var items = []; + var count = results.rows.length; + for (var i=0; i