From 152bc934ecac41676482a89aabd257eda728e575 Mon Sep 17 00:00:00 2001 From: Erik Brommers <1458944+eb1@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:41:34 -0700 Subject: [PATCH] Under the hood refactoring - Update to featherlight lib - New / updates to model classes (not connected / json for web service proof of concept) --- www/js/Application.js | 8 +- www/js/main.js | 9 +- www/js/models/json/book.js | 43 ++-- www/js/models/json/chapter.js | 34 +-- www/js/models/json/font.js | 4 +- www/js/models/json/project.js | 282 +++++++++++++++++++++++- www/js/models/json/sourcephrase.js | 46 ++-- www/js/models/json/targetunit.js | 41 ++-- www/js/models/json/user.js | 70 ++++++ www/js/models/sql/user.js | 322 ++++++++++++++++++++++++++++ www/lib/featherlight.gallery.min.js | 6 +- www/lib/featherlight.min.js | 6 +- 12 files changed, 797 insertions(+), 74 deletions(-) create mode 100644 www/js/models/json/user.js create mode 100644 www/js/models/sql/user.js mode change 100755 => 100644 www/lib/featherlight.gallery.min.js mode change 100755 => 100644 www/lib/featherlight.min.js diff --git a/www/js/Application.js b/www/js/Application.js index 14bd711b..624e92ad 100755 --- a/www/js/Application.js +++ b/www/js/Application.js @@ -335,6 +335,7 @@ define(function (require) { // new project wizard. These objects with no id defined are only in memory; // once the source and target language are defined, an id is set and // the project is saved in the device's localStorage. + // $.when(this.ProjectList.fetch()).done(function () { $.when(this.ProjectList.fetch({reset: true, data: {name: ""}})).done(function () { window.Application.ProjectList.each(function (model, index) { if (model.get('projectid') === "") { @@ -347,10 +348,15 @@ define(function (require) { window.Application.ProjectList.remove(models); } if (window.Application.currentProject === null) { + console.log("Home() - No current project set"); // check to see if we saved a current project if (localStorage.getItem("CurrentProjectID")) { + console.log("Attempting to use CurrentProjectID from local storage"); window.Application.currentProject = window.Application.ProjectList.where({projectid: localStorage.getItem("CurrentProjectID")})[0]; - } else { + } + if (window.Application.currentProject === null) { + // project list was a dud. Set to the first item in the list if we can + console.log("No localStorage, or attempt to set failed. Trying the first item in the project list (if there is one)"); // pick the first project in the list, if there is one if (window.Application.ProjectList.length > 0) { window.Application.currentProject = window.Application.ProjectList.at(0); diff --git a/www/js/main.js b/www/js/main.js index c2bc3284..195cc020 100755 --- a/www/js/main.js +++ b/www/js/main.js @@ -8,8 +8,8 @@ require.config({ // backbone.babysitter 0.1.12 // backbone.wreqr 1.4.0 // circular-progress-bar 1.0.6 - // featherlight 1.7.6 - // featherlight.gallery 1.7.6 + // featherlight 1.7.14 + // featherlight.gallery 1.7.14 // hammer 2.0.8 // handlebars 4.7.8 // hopscotch 0.3.1+ ** NOTE: if upgrading, fold in the hack in hopscotch.js (search for EDB HACK) - @@ -50,11 +50,12 @@ require.config({ map: { '*': { 'app/models': 'app/models/sql' // Use sqlite model persistence + // 'app/models': 'app/models/json' // Use json model persistence } }, shim: { 'featherlightGallery': { - deps: ['featherlight', 'jquery'], + deps: ['jquery-hammerjs', 'featherlight', 'jquery'], exports: 'featherlightGallery' }, 'handlebars': { @@ -78,7 +79,7 @@ require.config({ }, 'backbone': { // deps: ['underscore', 'jquery'], - deps: ['jquery-hammerjs', 'underscore-min'], + deps: ['jquery-hammerjs', 'underscore-min', 'jquery'], exports: 'Backbone' }, 'underscore': { diff --git a/www/js/models/json/book.js b/www/js/models/json/book.js index baa7b4f0..18753eca 100755 --- a/www/js/models/json/book.js +++ b/www/js/models/json/book.js @@ -7,19 +7,36 @@ define(function (require) { var Backbone = require('backbone'), - Book = Backbone.Model.extend({ - - urlRoot: "/book" - - }), - - BookCollection = Backbone.Collection.extend({ - - model: Book, - - url: "/books" - - }); + Book = Backbone.Model.extend({ + // default values + defaults: { + bookid: "", + projectid: "", + scrid: "", + name: "", + filename: "", + chapters: [] + }, + + }), + + BookCollection = Backbone.Collection.extend({ + model: Book, + url: function() { + // TODO: global function to prepend server:port to url path + // return this.document.url() + '/books'; + return "http://localhost:3042/books"; + }, + // sync: function (method, model, options) { + // if (method === "read") { + // // special case for sql - remove the blank name property for json + // if (options.data.hasOwnProperty('name') && options.data.name === "") { + // delete options.data.name; + // } + // } + // } + + }); return { Book: Book, diff --git a/www/js/models/json/chapter.js b/www/js/models/json/chapter.js index c871570c..762a0f3b 100755 --- a/www/js/models/json/chapter.js +++ b/www/js/models/json/chapter.js @@ -7,19 +7,27 @@ define(function (require) { var Backbone = require('backbone'), - Chapter = Backbone.Model.extend({ - - urlRoot: "/chapter" - - }), - - ChapterCollection = Backbone.Collection.extend({ - - model: Chapter, - - url: "/chapters" - - }); + Chapter = Backbone.Model.extend({ + // default values + defaults: { + chapterid: "", + bookid: "", + projectid: "", + name: "", + lastadapted: 0, + versecount: 0 + }, + + }), + + ChapterCollection = Backbone.Collection.extend({ + model: Chapter, + url: function() { + // TODO: global function to prepend server:port to url path + // return this.document.url() + '/chapters'; + return "http://localhost:3042/chapters"; + } + }); return { Chapter: Chapter, diff --git a/www/js/models/json/font.js b/www/js/models/json/font.js index 07d8f2a5..3d28e679 100644 --- a/www/js/models/json/font.js +++ b/www/js/models/json/font.js @@ -9,15 +9,13 @@ define(function (require) { Font = Backbone.Model.extend({ - urlRoot: "http://localhost:3000/font" - }), FontCollection = Backbone.Collection.extend({ model: Font, - url: "http://localhost:3000/fonts" + url: "/fonts" }); diff --git a/www/js/models/json/project.js b/www/js/models/json/project.js index 54217c08..fddaf535 100755 --- a/www/js/models/json/project.js +++ b/www/js/models/json/project.js @@ -5,23 +5,289 @@ define(function (require) { "use strict"; - var Backbone = require('backbone'), + var Backbone = require('backbone'), - Project = Backbone.Model.extend({ + // in Json-land, checkSchema is a promise that always returns success + checkSchema = function () { + var deferred = $.Deferred(); + console.log("checkSchema: entry"); + deferred.resolve(); + return deferred.promise(); + }, - urlRoot: "/project" + Project = Backbone.Model.extend({ + // default values + defaults: { + projectid: "", + SourceFont: "Source Sans", + SourceFontSize: "16", + SourceColor: "#0000aa", + TargetFont: "Source Sans", + TargetFontSize: "16", + TargetColor: "#000000", + NavigationFont: "Source Sans", + NavigationFontSize: "16", + NavigationColor: "#00cc00", + SpecialTextColor: "#aa0000", + RetranslationColor: "#996633", + TextDifferencesColor: "rgb(40, 100, 40)", + SourceLanguageName: "", + TargetLanguageName: "", + SourceLanguageCode: "", + TargetLanguageCode: "", + SourceVariant: "", + TargetVariant: "", + CopyPunctuation: "true", + PunctPairs: [ + { + s: "?", + t: "?" + }, + { + s: ".", + t: "." + }, + { + s: ",", + t: "," + }, + { + s: ";", + t: ";" + }, + { + s: ":", + t: ":" + }, + { + s: "\"", + t: "\"" + }, + { + s: "!", + t: "!" + }, + { + s: "(", + t: "(" + }, + { + s: ")", + t: ")" + }, + { + s: "<", + t: "<" + }, + { + s: ">", + t: ">" + }, + { + s: "{", + t: "{" + }, + { + s: "}", + t: "}" + }, + { + s: "“", + t: "“" + }, + { + s: "”", + t: "”" + }, + { + s: "‘", + t: "‘" + }, + { + s: "’", + t: "’" + }, + { + s: "'", + t: "'" + }, + { + s: "«", + t: "«" + }, + { + s: "»", + t: "»" + }, + { + s: "¿", + t: "¿" + }, + { + s: "¡", + t: "¡" + }, + { + s: "—", + t: "—" + } + ], + AutoCapitalization: "false", + SourceHasUpperCase: "false", + CasePairs: [ + { + s: "aA", + t: "aA" + }, + { + s: "bB", + t: "bB" + }, + { + s: "cC", + t: "cC" + }, + { + s: "dD", + t: "dD" + }, + { + s: "eE", + t: "eE" + }, + { + s: "fF", + t: "fF" + }, + { + s: "gG", + t: "gG" + }, + { + s: "hH", + t: "hH" + }, + { + s: "iI", + t: "iI" + }, + { + s: "jJ", + t: "jJ" + }, + { + s: "kK", + t: "kK" + }, + { + s: "lL", + t: "lL" + }, + { + s: "mM", + t: "mM" + }, + { + s: "nN", + t: "nN" + }, + { + s: "oO", + t: "oO" + }, + { + s: "pP", + t: "pP" + }, + { + s: "qQ", + t: "qQ" + }, + { + s: "rR", + t: "rR" + }, + { + s: "sS", + t: "sS" + }, + { + s: "tT", + t: "tT" + }, + { + s: "uU", + t: "uU" + }, + { + s: "vV", + t: "vV" + }, + { + s: "wW", + t: "wW" + }, + { + s: "xX", + t: "xX" + }, + { + s: "yY", + t: "yY" + }, + { + s: "zZ", + t: "zZ" + } + ], + SourceDir: "", + TargetDir: "", + NavDir: "", + name: "", + CustomFilters: "false", + FilterMarkers: "\\lit \\_table_grid \\_header \\_intro_base \\x \\r \\cp \\_horiz_rule \\ie \\rem \\_unknown_para_style \\_normal_table \\note \\_heading_base \\_hidden_note \\_footnote_caller \\_dft_para_font \\va \\_small_para_break \\_footer \\_vernacular_base \\pro \\xt \\_notes_base \\__normal \\xdc \\ide \\mr \\xq \\_annotation_ref \\_annotation_text \\_peripherals_base \\_gls_lang_interlinear \\free \\rq \\_nav_lang_interlinear \\_body_text \\cl \\xot \\efm \\bt \\_unknown_char_style \\_double_boxed_para \\_hdr_ftr_interlinear \\xk \\_list_base \\ib \\xnt \\fig \\restore \\_src_lang_interlinear \\vp \\_tgt_lang_interlinear \\ef \\ca \\xo \\_single_boxed_para \\sts" + }, + }), - }), + ProjectCollection = Backbone.Collection.extend({ + model: Project, + url: function() { + // TODO: global function to prepend server:port to url path + // return this.document.url() + '/projects'; + return "http://localhost:3042/projects"; + }, - ProjectCollection = Backbone.Collection.extend({ + // parse: function (data) { + // if (_.isObject(data.results)) { + // console.log("Parsing project data results: " + data.results); + // return data.results; + // } else { + // console.log("Parsing project data: " + data); + // return data; + // } + // }, - model: Project, + fetch: function(options) { - url: "/projects" + console.log("Fetching project"); - }); + //Call Backbone's fetch + return Backbone.Collection.prototype.fetch.call(this, options); + } + + // sync: function (method, model, options) { + // if (method === "read") { + // // special case for sql - remove the blank name property for json + // if (options.data.hasOwnProperty('name') && options.data.name === "") { + // delete options.data.name; + // } + // } + // } + + }); return { + checkSchema: checkSchema, Project: Project, ProjectCollection: ProjectCollection }; diff --git a/www/js/models/json/sourcephrase.js b/www/js/models/json/sourcephrase.js index 752950c7..95ced00e 100755 --- a/www/js/models/json/sourcephrase.js +++ b/www/js/models/json/sourcephrase.js @@ -7,19 +7,39 @@ define(function (require) { var Backbone = require('backbone'), - SourcePhrase = Backbone.Model.extend({ - - urlRoot: "/sp" - - }), - - SourcePhraseCollection = Backbone.Collection.extend({ - - model: SourcePhrase, - - url: "/sps" - - }); + SourcePhrase = Backbone.Model.extend({ + // default values + defaults: { + spid: "", + chapterid: "", + vid: "", // 1.6 (verse ID for multiple imports) + norder: 0, + markers: "", + orig: null, + prepuncts: "", + midpuncts: "", + follpuncts: "", + flags: "0000000000000000000000", // 22 + texttype: 0, + gloss: "", + freetrans: "", + note: "", + srcwordbreak: "", + tgtwordbreak: "", + source: "", // source includes punctuation as of 1.2 (was inconsistent before) + target: "" + }, + + }), + + SourcePhraseCollection = Backbone.Collection.extend({ + model: SourcePhrase, + url: function() { + // TODO: global function to prepend server:port to url path + // return this.document.url() + '/sourcephrases'; + return "http://localhost:3042/sourcephrases"; + } + }); return { SourcePhrase: SourcePhrase, diff --git a/www/js/models/json/targetunit.js b/www/js/models/json/targetunit.js index ef2a327f..25e8bf3b 100644 --- a/www/js/models/json/targetunit.js +++ b/www/js/models/json/targetunit.js @@ -7,19 +7,34 @@ define(function (require) { var Backbone = require('backbone'), - TargetUnit = Backbone.Model.extend({ - - urlRoot: "/targetunit" - - }), - - TargetUnitCollection = Backbone.Collection.extend({ - - model: TargetUnit, - - url: "/targetunits" - - }); + TargetUnit = Backbone.Model.extend({ + // default values + defaults: { + tuid: "", + projectid: "", + source: "", + mn: 1, + f: "0", + refstring: [], + timestamp: "", + user: "", + isGloss: 1 + }, + + }), + + TargetUnitCollection = Backbone.Collection.extend({ + model: TargetUnit, + url: function() { + // TODO: global function to prepend server:port to url path + // return this.document.url() + '/targetunits'; + return "http://localhost:3042/targetunits"; + }, + + parse: function (data) { + return data.targetunits; + } + }); return { TargetUnit: TargetUnit, diff --git a/www/js/models/json/user.js b/www/js/models/json/user.js new file mode 100644 index 00000000..f009e50b --- /dev/null +++ b/www/js/models/json/user.js @@ -0,0 +1,70 @@ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define */ + +define(function (require) { + + "use strict"; + + var Backbone = require('backbone'), + + wordSpacingEnum = { + NONE: 0, + SMALL: 1, + NORMAL: 2, + WIDE: 3 + }, + + User = Backbone.Model.extend({ + urlRoot: '/users', + // default values + defaults: { + username: "", // must be unique + userid: "", + // password: "", + roles: [], + // user preferences (in local storage for AIM 1.x) + copysource: 0, + wrapusfm: 0, + stopatboundaries: 0, + alloweditblanksp: 0, + showtranslationchecks: 0, + defaultfttarget: 0, + uilang: 0, + darkmode: 1, + bookmarks: [], + wordspacing: wordSpacingEnum.NORMAL + }, + + }), + + UserCollection = Backbone.Collection.extend({ + model: User, + url: "/users" + }); + + // Represents a placeholder in a project (book, chapter, and source phrase location). Can be more than 1 per user. + Bookmark = Backbone.Model.extend({ + urlRoot: '/bookmarks', + defaults: { + bookmarkid: "", + projectid: "", + bookname: "", + bookid: 0, + chapterid: 0, + spid: "" + }, + }); + + BookmarkCollection = Backbone.Collection.extend({ + model: Bookmark, + url: "/bookmarks" + }) + + return { + User: User, + UserCollection: UserCollection, + Bookmark: Bookmark, + BookmarkCollection: BookmarkCollection + }; + +}); \ No newline at end of file diff --git a/www/js/models/sql/user.js b/www/js/models/sql/user.js new file mode 100644 index 00000000..519d523b --- /dev/null +++ b/www/js/models/sql/user.js @@ -0,0 +1,322 @@ +/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ +/*global define */ + +// Model file for user-related classes: +// - user: contains authentication / authorization info +// - UserPreferences: contains editor / UI settings (this used to be stored in localStorage) +// - Bookmark: contains per-user placeholder info (last adapted XXX) settings, previously in the Project table +define(function (require) { + + "use strict"; + + var $ = require('jquery'), + Backbone = require('backbone'), + users = [], + wordSpacingEnum = { + NONE: 0, + SMALL: 1, + NORMAL: 2, + WIDE: 3 + }, + + // authenticate user + signIn = function(username, password) { + + }, + + // add / create user + signUp = function (username, email, password) { + + }, + + findById = function (searchKey) { + var deferred = $.Deferred(); + var results = users.filter(function (element) { + return element.attributes.userid === searchKey; + }); + deferred.resolve(results); + return deferred.promise(); + }, + + User = Backbone.Model.extend({ + defaults: { + username: "", + userid: "", + // email: "", + // password: "", + roles: [], + copysource: 0, + wrapusfm: 0, + stopatboundaries: 0, + alloweditblanksp: 0, + showtranslationchecks: 0, + defaultfttarget: 0, + uilang: 0, + darkmode: 1, + bookmarks: [], + wordspacing: wordSpacingEnum.NORMAL + }, + initialize: function () { + this.on('change', this.save, this); + }, + fetch: function () { + var deferred = $.Deferred(); + var obj = this; + window.Application.db.transaction(function (tx) { + tx.executeSql("SELECT * from user WHERE username=?;", [obj.attributes.username], function (tx, res) { + console.log("SELECT ok: " + res.rows); + obj.set(res.rows.item(0)); + deferred.resolve(obj); + }); + }, function (err) { + console.log("SELECT error: " + err.message); + deferred.reject(err); + }); + return deferred.promise(); + }, + create: function () { + var attributes = this.attributes; + var sql = "INSERT INTO user (username, userid, roles, copysource, wrapusfm, stopatboundaries, alloweditblanksp, showtranslationchecks, defaultfttarget, uilang, darkmode, bookmarks, wordspacing) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?);"; + window.Application.db.transaction(function (tx) { + tx.executeSql(sql, [attributes.username, attributes.userid, attributes.roles, attributes.copysource, attributes.wrapusfm, attributes.stopatboundaries, attributes.alloweditblanksp, attributes.showtranslationchecks, attributes.defaultfttarget, attributes.uilang, attributes.darkmode, attributes.bookmarks, attributes.wordspacing], function (tx, res) { + console.log("INSERT ok: " + res.toString()); + }, function (tx, err) { + console.log("INSERT (create) error: " + err.message); + }); + }); + }, + update: function () { + var attributes = this.attributes; + var sql = "UPDATE user SET username=?, roles=? copysource=?, wrapusfm=?, stopatboundaries=?, alloweditblanksp=?, showtranslationchecks=?, defaultfttarget=?, uilang=?, darkmode=?, bookmarks=?, wordspacing=? WHERE userid=?;"; + window.Application.db.transaction(function (tx) { + tx.executeSql(sql, [attributes.username, attributes.roles, attributes.copysource, attributes.wrapusfm, attributes.stopatboundaries, attributes.alloweditblanksp, attributes.showtranslationchecks, attributes.defaultfttarget, attributes.uilang, attributes.darkmode, attributes.bookmarks, attributes.wordspacing, attributes.userid], function (tx, res) { + console.log("UPDATE ok: " + res.toString()); + }, function (tx, err) { + console.log("UPDATE error: " + err.message); + }); + }); + }, + + sync: function (method, model, options) { + switch (method) { + case 'create': + model.create(); + break; + + case 'read': + findById(this.userid).done(function (data) { + options.success(data); + }); + break; + + case 'update': + model.update(); + break; + + case 'delete': + model.destroy(options); + break; + } + } + }); + + UserCollection = Backbone.Collection.extend({ + model: User, + + resetFromDB: function () { + var deferred = $.Deferred(), + i = 0, + len = 0; + + window.Application.db.transaction(function (tx) { + tx.executeSql('CREATE TABLE IF NOT EXISTS user (id integer primary key, username text, userid text, roles text, CopySource integer, WrapUSFM integer, StopAtBoundaries integer, AllowEditBlankSP integer, ShowTranslationChecks integer, DefaultFTTarget integer, UILang integer, DarkMode integer, bookmarks Text, WordSpacing integer);'); + tx.executeSql("SELECT * from user;", [], function (tx, res) { + var tmpString = ""; + for (i = 0, len = res.rows.length; i < len; ++i) { + // add the user + var user = new User(); + user.off("change"); + user.set(res.rows.item(i)); + // convert text strings back into an array objects + tmpString = user.get('roles'); + user.set('roles', JSON.parse(tmpString)); + tmpString = user.get('bookmarks'); + user.set('bookmarks', JSON.parse(tmpString)); + users.push(user); + user.on("change", user.save, user); + } + console.log("SELECT ok: " + res.rows.length + " user items"); + }); + }, function (e) { + deferred.reject(e); + }, function () { + deferred.resolve(); + }); + return deferred.promise(); + }, + + initialize: function () { + return this.resetFromDB(); + }, + + // Removes all chapters from the collection (and database) + clearAll: function () { + window.Application.db.transaction(function (tx) { + tx.executeSql('DELETE from user;'); // clear out the table + users.length = 0; // delete local copy + }, function (err) { + console.log("DELETE error: " + err.message); + }); + }, + + sync: function (method, model, options) { + if (method === "read") { + if (options.data.hasOwnProperty('userid')) { + findById(options.data.userid).done(function (data) { + options.success(data); + }); + } else if (options.data.hasOwnProperty('username')) { + var deferred = $.Deferred(); + var username = options.data.username; + var len = 0; + var i = 0; + var retValue = null; + // special case -- empty name query ==> reset local copy so we force a retrieve + // from the database + if (username === "") { + users.length = 0; + } + var results = users.filter(function (element) { + return element.attributes.username === username; + }); + if (results.length === 0) { + // not in collection -- retrieve them from the db + window.Application.db.transaction(function (tx) { + tx.executeSql("SELECT * FROM user;", [], function (tx, res) { + var tmpString = ""; + // populate the chapter collection with the query results + for (i = 0, len = res.rows.length; i < len; ++i) { + // add the book + var user = new User(); + user.off("change"); + user.set(res.rows.item(i)); + // convert text strings back into an array objects + tmpString = user.get('roles'); + user.set('roles', JSON.parse(tmpString)); + tmpString = user.get('bookmarks'); + user.set('bookmarks', JSON.parse(tmpString)); + users.push(user); + user.on("change", user.save, user); + } + // return the filtered results (now that we have them) + retValue = users.filter(function (element) { + return element.attributes.username === username; + }); + options.success(retValue); + deferred.resolve(retValue); + }); + }, function (e) { + options.error(); + deferred.reject(e); + }); + } else { + // results already in collection -- return them + options.success(results); + deferred.resolve(results); + } + // return the promise + return deferred.promise(); + } + } + } + }); + + // Represents a placeholder in a project (book, chapter, and source phrase location). Can be more than 1 per user. + Bookmark = Backbone.Model.extend({ + defaults: { + bookmarkid: "", + projectid: "", + bookname: "", + bookid: 0, + chapterid: 0, + spid: "" + }, + + initialize: function () { + this.on('change', this.save, this); + }, + fetch: function () { + var deferred = $.Deferred(); + var obj = this; + window.Application.db.transaction(function (tx) { + tx.executeSql("SELECT * from bookmark WHERE bookmarkid=?;", [obj.attributes.bookmarkid], function (tx, res) { + console.log("SELECT ok: " + res.rows); + obj.set(res.rows.item(0)); + deferred.resolve(obj); + }); + }, function (err) { + console.log("SELECT error: " + err.message); + deferred.reject(err); + }); + return deferred.promise(); + }, + create: function () { + var attributes = this.attributes; + var sql = "INSERT INTO bookmark (bookmarkid, bookname, bookid, chapterid, spid) VALUES (?,?,?,?,?);"; + window.Application.db.transaction(function (tx) { + tx.executeSql(sql, [attributes.bookmarkid, attributes.bookname, attributes.bookid, attributes.chapterid, attributes.spid], function (tx, res) { + console.log("INSERT ok: " + res.toString()); + }, function (tx, err) { + console.log("INSERT (create) error: " + err.message); + }); + }); + }, + update: function () { + var attributes = this.attributes; + var sql = "UPDATE bookmark SET bookname=?, bookid=?, chapterid=?, spid=? WHERE bookmarkid=?;"; + window.Application.db.transaction(function (tx) { + //JSON.stringify(attributes.chapters) + tx.executeSql(sql, [attributes.bookname, attributes.bookid, attributes.chapterid, attributes.spid, attributes.bookmarkid], function (tx, res) { + console.log("UPDATE ok: " + res.toString()); + }, function (tx, err) { + console.log("UPDATE error: " + err.message); + }); + }); + }, + + sync: function (method, model, options) { + + switch (method) { + case 'create': + options.success(model); + break; + + case 'read': + options.success(data); + break; + + case 'update': + options.success(model); + break; + + case 'delete': + options.success(model); + break; + } + } + }); + + BookmarkCollection = Backbone.Collection.extend({ + model: Bookmark, + url: "/bookmarks" + }); + + + return { + User: User, + UserCollection: UserCollection, + Bookmark: Bookmark, + BookmarkCollection: BookmarkCollection + }; + +}); \ No newline at end of file diff --git a/www/lib/featherlight.gallery.min.js b/www/lib/featherlight.gallery.min.js old mode 100755 new mode 100644 index c79118c9..8569539f --- a/www/lib/featherlight.gallery.min.js +++ b/www/lib/featherlight.gallery.min.js @@ -1,7 +1,7 @@ /** * Featherlight Gallery – an extension for the ultra slim jQuery lightbox - * Version 1.7.6 - http://noelboss.github.io/featherlight/ + * Version 1.7.14 - http://noelboss.github.io/featherlight/ * - * Copyright 2017, Noël Raoul Bossart (http://www.noelboss.com) + * Copyright 2019, Noël Raoul Bossart (http://www.noelboss.com) * MIT Licensed. -**/!function(a){"use strict";function b(c,d){if(!(this instanceof b)){var e=new b(a.extend({$source:c,$currentTarget:c.first()},d));return e.open(),e}a.featherlight.apply(this,arguments),this.chainCallbacks(h)}var c=function(a){window.console&&window.console.warn&&window.console.warn("FeatherlightGallery: "+a)};if("undefined"==typeof a)return c("Too much lightness, Featherlight needs jQuery.");if(!a.featherlight)return c("Load the featherlight plugin before the gallery plugin");var d="ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch,e=a.event&&a.event.special.swipeleft&&a,f=window.Hammer&&function(a){var b=new window.Hammer.Manager(a[0]);return b.add(new window.Hammer.Swipe),b},g=d&&(e||f);d&&!g&&c("No compatible swipe library detected; one must be included before featherlightGallery for swipe motions to navigate the galleries.");var h={afterClose:function(a,b){var c=this;return c.$instance.off("next."+c.namespace+" previous."+c.namespace),c._swiper&&(c._swiper.off("swipeleft",c._swipeleft).off("swiperight",c._swiperight),c._swiper=null),a(b)},beforeOpen:function(a,b){var c=this;return c.$instance.on("next."+c.namespace+" previous."+c.namespace,function(a){var b="next"===a.type?1:-1;c.navigateTo(c.currentNavigation()+b)}),g&&(c._swiper=g(c.$instance).on("swipeleft",c._swipeleft=function(){c.$instance.trigger("next")}).on("swiperight",c._swiperight=function(){c.$instance.trigger("previous")}),c.$instance.addClass(this.namespace+"-swipe-aware",g)),c.$instance.find("."+c.namespace+"-content").append(c.createNavigation("previous")).append(c.createNavigation("next")),a(b)},beforeContent:function(a,b){var c=this.currentNavigation(),d=this.slides().length;return this.$instance.toggleClass(this.namespace+"-first-slide",0===c).toggleClass(this.namespace+"-last-slide",c===d-1),a(b)},onKeyUp:function(a,b){var c={37:"previous",39:"next"}[b.keyCode];return c?(this.$instance.trigger(c),!1):a(b)}};a.featherlight.extend(b,{autoBind:"[data-featherlight-gallery]"}),a.extend(b.prototype,{previousIcon:"◀",nextIcon:"▶",galleryFadeIn:100,galleryFadeOut:300,slides:function(){return this.filter?this.$source.find(this.filter):this.$source},images:function(){return c("images is deprecated, please use slides instead"),this.slides()},currentNavigation:function(){return this.slides().index(this.$currentTarget)},navigateTo:function(b){var c=this,d=c.slides(),e=d.length,f=c.$instance.find("."+c.namespace+"-inner");return b=(b%e+e)%e,c.$currentTarget=d.eq(b),c.beforeContent(),a.when(c.getContent(),f.fadeTo(c.galleryFadeOut,.2)).always(function(a){c.setContent(a),c.afterContent(),a.fadeTo(c.galleryFadeIn,1)})},createNavigation:function(b){var c=this;return a(''+this[b+"Icon"]+"").click(function(){a(this).trigger(b+"."+c.namespace)})}}),a.featherlightGallery=b,a.fn.featherlightGallery=function(a){return b.attach(this,a),this},a(document).ready(function(){b._onReady()})}(jQuery); \ No newline at end of file +**/!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=function(b,c){return void 0===c&&(c="undefined"!=typeof window?require("jquery"):require("jquery")(b)),a(c),c}:a(jQuery)}(function(a){"use strict";function b(c,d){if(!(this instanceof b)){var e=new b(a.extend({$source:c,$currentTarget:c.first()},d));return e.open(),e}a.featherlight.apply(this,arguments),this.chainCallbacks(h)}var c=function(a){window.console&&window.console.warn&&window.console.warn("FeatherlightGallery: "+a)};if("undefined"==typeof a)return c("Too much lightness, Featherlight needs jQuery.");if(!a.featherlight)return c("Load the featherlight plugin before the gallery plugin");var d="ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch,e=a.event&&a.event.special.swipeleft&&a,f=window.Hammer&&function(a){var b=new window.Hammer.Manager(a[0]);return b.add(new window.Hammer.Swipe),b},g=d&&(e||f);d&&!g&&c("No compatible swipe library detected; one must be included before featherlightGallery for swipe motions to navigate the galleries.");var h={afterClose:function(a,b){var c=this;return c.$instance.off("next."+c.namespace+" previous."+c.namespace),c._swiper&&(c._swiper.off("swipeleft",c._swipeleft).off("swiperight",c._swiperight),c._swiper=null),a(b)},beforeOpen:function(a,b){var c=this;return c.$instance.on("next."+c.namespace+" previous."+c.namespace,function(a){var b="next"===a.type?1:-1;c.navigateTo(c.currentNavigation()+b)}),g&&(c._swiper=g(c.$instance).on("swipeleft",c._swipeleft=function(){c.$instance.trigger("next")}).on("swiperight",c._swiperight=function(){c.$instance.trigger("previous")}),c.$instance.addClass(this.namespace+"-swipe-aware",g)),c.$instance.find("."+c.namespace+"-content").append(c.createNavigation("previous")).append(c.createNavigation("next")),a(b)},beforeContent:function(a,b){var c=this.currentNavigation(),d=this.slides().length;return this.$instance.toggleClass(this.namespace+"-first-slide",0===c).toggleClass(this.namespace+"-last-slide",c===d-1),a(b)},onKeyUp:function(a,b){var c={37:"previous",39:"next"}[b.keyCode];return c?(this.$instance.trigger(c),!1):a(b)}};a.featherlight.extend(b,{autoBind:"[data-featherlight-gallery]"}),a.extend(b.prototype,{previousIcon:"◀",nextIcon:"▶",galleryFadeIn:100,galleryFadeOut:300,slides:function(){return this.filter?this.$source.find(this.filter):this.$source},images:function(){return c("images is deprecated, please use slides instead"),this.slides()},currentNavigation:function(){return this.slides().index(this.$currentTarget)},navigateTo:function(b){var c=this,d=c.slides(),e=d.length,f=c.$instance.find("."+c.namespace+"-inner");return b=(b%e+e)%e,this.$instance.addClass(this.namespace+"-loading"),c.$currentTarget=d.eq(b),c.beforeContent(),a.when(c.getContent(),f.fadeTo(c.galleryFadeOut,.2)).always(function(a){c.setContent(a),c.afterContent(),a.fadeTo(c.galleryFadeIn,1)})},createNavigation:function(b){var c=this;return a(''+this[b+"Icon"]+"").click(function(d){a(this).trigger(b+"."+c.namespace),d.preventDefault()})}}),a.featherlightGallery=b,a.fn.featherlightGallery=function(a){return b.attach(this,a),this},a(document).ready(function(){b._onReady()})}); \ No newline at end of file diff --git a/www/lib/featherlight.min.js b/www/lib/featherlight.min.js old mode 100755 new mode 100644 index c0299e65..3b53d668 --- a/www/lib/featherlight.min.js +++ b/www/lib/featherlight.min.js @@ -1,8 +1,8 @@ /** * Featherlight - ultra slim jQuery lightbox - * Version 1.7.6 - http://noelboss.github.io/featherlight/ + * Version 1.7.14 - http://noelboss.github.io/featherlight/ * - * Copyright 2017, Noël Raoul Bossart (http://www.noelboss.com) + * Copyright 2019, Noël Raoul Bossart (http://www.noelboss.com) * MIT Licensed. **/ -!function(a){"use strict";function b(a,c){if(!(this instanceof b)){var d=new b(a,c);return d.open(),d}this.id=b.id++,this.setup(a,c),this.chainCallbacks(b._callbackChain)}function c(a,b){var c={};for(var d in a)d in b&&(c[d]=a[d],delete a[d]);return c}function d(a,b){var c={},d=new RegExp("^"+b+"([A-Z])(.*)");for(var e in a){var f=e.match(d);if(f){var g=(f[1]+f[2].replace(/([A-Z])/g,"-$1")).toLowerCase();c[g]=a[e]}}return c}if("undefined"==typeof a)return void("console"in window&&window.console.info("Too much lightness, Featherlight needs jQuery."));var e=[],f=function(b){return e=a.grep(e,function(a){return a!==b&&a.$instance.closest("body").length>0})},g={allowfullscreen:1,frameborder:1,height:1,longdesc:1,marginheight:1,marginwidth:1,name:1,referrerpolicy:1,scrolling:1,sandbox:1,src:1,srcdoc:1,width:1},h={keyup:"onKeyUp",resize:"onResize"},i=function(c){a.each(b.opened().reverse(),function(){return c.isDefaultPrevented()||!1!==this[h[c.type]](c)?void 0:(c.preventDefault(),c.stopPropagation(),!1)})},j=function(c){if(c!==b._globalHandlerInstalled){b._globalHandlerInstalled=c;var d=a.map(h,function(a,c){return c+"."+b.prototype.namespace}).join(" ");a(window)[c?"on":"off"](d,i)}};b.prototype={constructor:b,namespace:"featherlight",targetAttr:"data-featherlight",variant:null,resetCss:!1,background:null,openTrigger:"click",closeTrigger:"click",filter:null,root:"body",openSpeed:250,closeSpeed:250,closeOnClick:"background",closeOnEsc:!0,closeIcon:"✕",loading:"",persist:!1,otherClose:null,beforeOpen:a.noop,beforeContent:a.noop,beforeClose:a.noop,afterOpen:a.noop,afterContent:a.noop,afterClose:a.noop,onKeyUp:a.noop,onResize:a.noop,type:null,contentFilters:["jquery","image","html","ajax","iframe","text"],setup:function(b,c){"object"!=typeof b||b instanceof a!=!1||c||(c=b,b=void 0);var d=a.extend(this,c,{target:b}),e=d.resetCss?d.namespace+"-reset":d.namespace,f=a(d.background||['
','
','",'
'+d.loading+"
","
","
"].join("")),g="."+d.namespace+"-close"+(d.otherClose?","+d.otherClose:"");return d.$instance=f.clone().addClass(d.variant),d.$instance.on(d.closeTrigger+"."+d.namespace,function(b){var c=a(b.target);("background"===d.closeOnClick&&c.is("."+d.namespace)||"anywhere"===d.closeOnClick||c.closest(g).length)&&(d.close(b),b.preventDefault())}),this},getContent:function(){if(this.persist!==!1&&this.$content)return this.$content;var b=this,c=this.constructor.contentFilters,d=function(a){return b.$currentTarget&&b.$currentTarget.attr(a)},e=d(b.targetAttr),f=b.target||e||"",g=c[b.type];if(!g&&f in c&&(g=c[f],f=b.target&&e),f=f||d("href")||"",!g)for(var h in c)b[h]&&(g=c[h],f=b[h]);if(!g){var i=f;if(f=null,a.each(b.contentFilters,function(){return g=c[this],g.test&&(f=g.test(i)),!f&&g.regex&&i.match&&i.match(g.regex)&&(f=i),!f}),!f)return"console"in window&&window.console.error("Featherlight: no content filter found "+(i?' for "'+i+'"':" (no target specified)")),!1}return g.process.call(b,f)},setContent:function(b){var c=this;return b.is("iframe")&&c.$instance.addClass(c.namespace+"-iframe"),c.$instance.removeClass(c.namespace+"-loading"),c.$instance.find("."+c.namespace+"-inner").not(b).slice(1).remove().end().replaceWith(a.contains(c.$instance[0],b[0])?"":b),c.$content=b.addClass(c.namespace+"-inner"),c},open:function(b){var c=this;if(c.$instance.hide().appendTo(c.root),!(b&&b.isDefaultPrevented()||c.beforeOpen(b)===!1)){b&&b.preventDefault();var d=c.getContent();if(d)return e.push(c),j(!0),c.$instance.fadeIn(c.openSpeed),c.beforeContent(b),a.when(d).always(function(a){c.setContent(a),c.afterContent(b)}).then(c.$instance.promise()).done(function(){c.afterOpen(b)})}return c.$instance.detach(),a.Deferred().reject().promise()},close:function(b){var c=this,d=a.Deferred();return c.beforeClose(b)===!1?d.reject():(0===f(c).length&&j(!1),c.$instance.fadeOut(c.closeSpeed,function(){c.$instance.detach(),c.afterClose(b),d.resolve()})),d.promise()},resize:function(a,b){if(a&&b){this.$content.css("width","").css("height","");var c=Math.max(a/(parseInt(this.$content.parent().css("width"),10)-1),b/(parseInt(this.$content.parent().css("height"),10)-1));c>1&&(c=b/Math.floor(b/c),this.$content.css("width",""+a/c+"px").css("height",""+b/c+"px"))}},chainCallbacks:function(b){for(var c in b)this[c]=a.proxy(b[c],this,a.proxy(this[c],this))}},a.extend(b,{id:0,autoBind:"[data-featherlight]",defaults:b.prototype,contentFilters:{jquery:{regex:/^[#.]\w/,test:function(b){return b instanceof a&&b},process:function(b){return this.persist!==!1?a(b):a(b).clone(!0)}},image:{regex:/\.(png|jpg|jpeg|gif|tiff|bmp|svg)(\?\S*)?$/i,process:function(b){var c=this,d=a.Deferred(),e=new Image,f=a('');return e.onload=function(){f.naturalWidth=e.width,f.naturalHeight=e.height,d.resolve(f)},e.onerror=function(){d.reject(f)},e.src=b,d.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(b){return a(b)}},ajax:{regex:/./,process:function(b){var c=a.Deferred(),d=a("
").load(b,function(a,b){"error"!==b&&c.resolve(d.contents()),c.fail()});return c.promise()}},iframe:{process:function(b){var e=new a.Deferred,f=a("