Refactor javascript files, so that to externalize utility functions, and split the evopedia.js file into 2 files implementing the 2 classes Title and LocalArchive

This commit is contained in:
mossroy 2013-07-27 15:37:59 +02:00
parent e3ef342e2e
commit edd97188ee
7 changed files with 936 additions and 893 deletions

View File

@ -9,7 +9,9 @@ define(function(require) {
var $ = require('zepto');
// Evopedia javascript dependencies
var evopedia = require('evopedia');
var evopediaTitle = require('title');
var evopediaArchive = require('localArchive');
var util = require('util');
var localArchive = null;
@ -50,7 +52,7 @@ define(function(require) {
if (storage !== null) {
// If DeviceStorage is available, we look for archives in it
$('#scanningForArchives').show();
evopedia.LocalArchive.scanForArchives(storage, populateDropDownListOfArchives);
evopediaArchive.LocalArchive.scanForArchives(storage, populateDropDownListOfArchives);
}
else {
// If DeviceStorage is not available, we display the file select components
@ -99,7 +101,7 @@ define(function(require) {
*/
function setLocalArchiveFromArchiveList() {
var archiveDirectory = $('#archiveList').val();
localArchive = new evopedia.LocalArchive();
localArchive = new evopediaArchive.LocalArchive();
localArchive.readTitleFilesFromStorage(storage, archiveDirectory);
localArchive.readDataFilesFromStorage(storage, archiveDirectory, 0);
localArchive.readMathFilesFromStorage(storage, archiveDirectory);
@ -121,7 +123,7 @@ define(function(require) {
* Sets the localArchive from the File selects populated by user
*/
function setLocalArchiveFromFileSelect() {
localArchive = new evopedia.LocalArchive();
localArchive = new evopediaArchive.LocalArchive();
localArchive.initializeFromArchiveFiles(document.getElementById('archiveFiles').files);
// The archive is set : focus on the prefix field to start searching
document.getElementById("prefix").focus();
@ -191,7 +193,7 @@ define(function(require) {
var titleId = event.target.getAttribute("titleId");
$("#titleList").empty();
findTitleFromTitleIdAndLaunchArticleRead(titleId);
var title = evopedia.Title.parseTitleId(localArchive, titleId);
var title = evopediaTitle.Title.parseTitleId(localArchive, titleId);
pushBrowserHistoryState(title.name);
return false;
}
@ -204,7 +206,7 @@ define(function(require) {
*/
function findTitleFromTitleIdAndLaunchArticleRead(titleId) {
if (localArchive.dataFiles && localArchive.dataFiles.length > 0) {
var title = evopedia.Title.parseTitleId(localArchive, titleId);
var title = evopediaTitle.Title.parseTitleId(localArchive, titleId);
$("#articleName").html(title.name);
$("#readingArticle").show();
$("#articleContent").html("");
@ -281,10 +283,10 @@ define(function(require) {
$(this).attr("target", "_blank");
}
else if (url.match(regexImageLink)
&& (evopedia.endsWith(lowerCaseUrl, ".png")
|| evopedia.endsWith(lowerCaseUrl, ".svg")
|| evopedia.endsWith(lowerCaseUrl, ".jpg")
|| evopedia.endsWith(lowerCaseUrl, ".jpeg"))) {
&& (util.endsWith(lowerCaseUrl, ".png")
|| util.endsWith(lowerCaseUrl, ".svg")
|| util.endsWith(lowerCaseUrl, ".jpg")
|| util.endsWith(lowerCaseUrl, ".jpeg"))) {
// It's a link to a file of wikipedia : change the URL to the online version and open in a new tab
var onlineWikipediaUrl = url.replace(regexImageLink, "https://"+localArchive.language+".wikipedia.org/wiki/File:$1");
$(this).attr("href", onlineWikipediaUrl);

View File

@ -2,7 +2,9 @@ require.config({
baseUrl: 'js/lib',
paths: {
'zepto': 'zepto',
'bootstrap': 'bootstrap'
'bootstrap': 'bootstrap',
'title': 'evopedia/title',
'localArchive': 'evopedia/localArchive'
},
shim: {
'zepto' : {

File diff suppressed because it is too large Load Diff

132
js/lib/evopedia/title.js Normal file
View File

@ -0,0 +1,132 @@
/*
* Class for the title of an article
*/
define(function(require) {
// Module dependencies
var utf8 = require('utf8');
var util = require('util');
/**
* Title class : defines the title of an article and some methods to manipulate it
*/
function Title() {
this.name = null;
this.fileNr = null;
this.blockStart = null;
this.blockOffset = null;
this.articleLength = null;
this.archive = null;
this.titleOffset = null;
this.titleEntryLength = null;
}
;
Title.prototype.getReadableName = function() {
return this.name.replace("_", " ");
};
/**
* Creates a Title instance from an encoded title line from a title file
* @param {type} encodedTitle
* @param {type} archive
* @param {type} titleOffset
* @returns {_L1.Title}
*/
Title.parseTitle = function(encodedTitle, archive, titleOffset) {
if (archive === null) {
throw "archive cannot be null";
}
if (titleOffset < 0) {
throw "titleOffset cannot be negative (was " + titleOffset + ")";
}
var t = new Title();
t.archive = archive;
t.titleOffset = titleOffset;
if (encodedTitle === null || encodedTitle.length < 15)
return null;
if (encodedTitle[encodedTitle.length - 1] == '\n') {
t.titleEntryLength = encodedTitle.length;
} else {
t.titleEntryLength = encodedTitle.length + 1;
}
var escapedEncodedTitle = new Uint8Array(encodedTitle);
var escapes = util.readIntegerFrom2Bytes(encodedTitle, 0);
if ((escapes & (1 << 14)) != 0)
escapes |= '\n';
for (var i = 0; i < 13; i++) {
if ((escapes & (1 << i)) != 0)
escapedEncodedTitle[i + 2] = 10; // Corresponds to \n
}
t.fileNr = 1 * escapedEncodedTitle[2];
t.blockStart = util.readIntegerFrom4Bytes(escapedEncodedTitle, 3);
t.blockOffset = util.readIntegerFrom4Bytes(escapedEncodedTitle, 7);
t.articleLength = util.readIntegerFrom4Bytes(escapedEncodedTitle, 11);
t.name = Title.parseNameOnly(escapedEncodedTitle);
return t;
};
/*
* Retrieves the name of an article from an encoded title line
*/
Title.parseNameOnly = function(encodedTitle) {
var len = encodedTitle.length;
if (len < 15) {
return null;
}
if (len > 15 && encodedTitle[len - 1] == '\n') {
len--;
}
return utf8.parse(encodedTitle.subarray(15, len));
};
/**
* Creates a title instance from a serialized id
* @param {type} localArchive
* @param {type} titleId
* @returns {_L1.Title}
*/
Title.parseTitleId = function(localArchive, titleId) {
var title = new Title();
var idParts = titleId.split("|");
title.archive = localArchive;
title.fileNr = parseInt(idParts[2], 10);
title.titleOffset = parseInt(idParts[3], 10);
title.name = idParts[4];
title.blockStart = parseInt(idParts[5], 10);
title.blockOffset = parseInt(idParts[6], 10);
title.articleLength = parseInt(idParts[7], 10);
return title;
};
/**
* Serialize the title with its values
* @returns {String}
*/
Title.prototype.toStringId = function() {
return this.archive.language + "|" + this.archive.date + "|" + this.fileNr + "|"
+ this.titleOffset + "|" + this.name + "|" + this.blockStart + "|" + this.blockOffset + "|" + this.articleLength;
};
/**
* Serialize the title in a readable way
*/
Title.prototype.toString = function() {
return "title.id = " + this.toStringId() + "title.name = " + this.name + " title.fileNr = " + this.fileNr + " title.blockStart = " + this.blockStart + " title.blockOffset = " + this.blockOffset + " title.articleLength = " + this.articleLength;
};
/**
* Functions and classes exposed by this module
*/
return {
Title: Title
};
});

91
js/lib/util.js Normal file
View File

@ -0,0 +1,91 @@
/*
* Utility functions
*/
define(function(require) {
/**
* Utility function : return true if the given string ends with the suffix
* @param str
* @param suffix
* @returns {Boolean}
*/
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
/**
* Read an integer encoded in 4 bytes
* @param {type} byteArray
* @param {type} firstIndex
* @returns {Number}
*/
function readIntegerFrom4Bytes(byteArray, firstIndex) {
return byteArray[firstIndex] + byteArray[firstIndex + 1] * 256 + byteArray[firstIndex + 2] * 65536 + byteArray[firstIndex + 3] * 16777216;
}
/**
* Read an integer encoded in 2 bytes
* @param {type} byteArray
* @param {type} firstIndex
* @returns {Number}
*/
function readIntegerFrom2Bytes(byteArray, firstIndex) {
return byteArray[firstIndex] + byteArray[firstIndex + 1] * 256;
}
/**
* Convert a Uint8Array to a lowercase hex string
* @param {type} byteArray
* @returns {String}
*/
function uint8ArrayToHex(byteArray) {
var s = '';
var hexDigits = '0123456789abcdef';
for (var i = 0; i < byteArray.length; i++) {
var v = byteArray[i];
s += hexDigits[(v & 0xff) >> 4];
s += hexDigits[v & 0xf];
}
return s;
}
/**
* Convert a Uint8Array to base64
* @param {type} byteArray
* @returns {String}
*/
function uint8ArrayToBase64(byteArray) {
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var bits, h1, h2, h3, h4, i = 0;
var enc = "";
for (var i = 0; i < byteArray.length; ) {
bits = byteArray[i++] << 16;
bits |= byteArray[i++] << 8;
bits |= byteArray[i++];
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;
enc += b64[h1] + b64[h2] + b64[h3] + b64[h4];
}
var r = byteArray.length % 3;
return (r > 0 ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
}
/**
* Functions and classes exposed by this module
*/
return {
endsWith: endsWith,
readIntegerFrom4Bytes: readIntegerFrom4Bytes,
readIntegerFrom2Bytes : readIntegerFrom2Bytes,
uint8ArrayToHex : uint8ArrayToHex,
uint8ArrayToBase64 : uint8ArrayToBase64
};
});

View File

@ -1,5 +1,9 @@
require.config({
baseUrl: '../js/lib'
baseUrl: '../js/lib',
paths: {
'title': 'evopedia/title',
'localArchive': 'evopedia/localArchive'
},
});
requirejs(['../../tests/tests']);

View File

@ -1,7 +1,8 @@
define(function(require) {
var $ = require('zepto');
var evopedia = require('evopedia');
var evopediaTitle = require('title');
var evopediaArchive = require('localArchive');
// Due to security restrictions in the browsers,
// we can not read directly the files and run the unit tests
@ -24,7 +25,7 @@ define(function(require) {
});
// Create a localArchive from selected files, in order to run the following tests
var localArchive = new evopedia.LocalArchive();
var localArchive = new evopediaArchive.LocalArchive();
localArchive.initializeFromArchiveFiles(document.getElementById('archiveFiles').files);
module("evopedia");
@ -73,7 +74,7 @@ define(function(require) {
});
// Create a title instance for the Article 'Abraham'
var titleAbraham = new evopedia.Title();
var titleAbraham = new evopediaTitle.Title();
titleAbraham.archive = localArchive;
titleAbraham.articleLength = 10071;
titleAbraham.blockOffset = 127640;
@ -101,7 +102,7 @@ define(function(require) {
test("check parseTitleFromId", function() {
var titleId = "small|2010-08-14|0|57|Abraham|2364940|127640|10071";
var title = evopedia.Title.parseTitleId(localArchive, titleId);
var title = evopediaTitle.Title.parseTitleId(localArchive, titleId);
ok(title, "Title instance created");
deepEqual(title, titleAbraham, "Parsing from titleId gives Abraham title");
});