VulpesOS/gaia/tv_apps/browser/js/sync/db.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

1958 lines
61 KiB
JavaScript
Executable file

'use strict';
/* exported SyncBrowserDB */
/* global Browser */
/* global Awesomescreen */
/* global IDBDatabaseException */
/* global IDBKeyRange */
const DBOS_PLACES = 'sync_places';
const DBOS_VISITS = 'sync_visits';
const DBOS_ICONS = 'sync_icons';
const DBOS_BOOKMARKS = 'sync_bookmarks';
var idb = window.indexedDB;
/**
* Provide access to bookmarks, topsites, and history in IndexedDB.
* @namespace SyncBrowserDB
*/
var SyncBrowserDB = {
/**
* How long is a icon expired in database in miliseconds.
* Default to 1 day.
*/
DEFAULT_ICON_EXPIRATION: 86400000, // One day
DEFAULT_TYPE_HISTORY: 'History',
DEFAULT_TYPE_BOOKMARK: 'Bookmark',
/**
* Maximum icon file size allowed.
* Default to 100kB.
*/
MAX_ICON_SIZE: 102400, // 100kB
variantObserver: null,
browserTitle: null,
/**
* Initialization. Open a database.
*/
init: function browserDB_init() {
this.db.open();
},
/**
* Add a DBOS_PLACES entry for the uri.
* @param {String} uri The uri to be added
* @param {Function} callback Runs when it finishs
*/
addPlace: function browserDB_addPlace(uri, callback) {
this.db.placeMaxCheck(uri, (function() {
this.db.createPlace(uri, callback);
}).bind(this));
},
/**
* Add a raw history entry to DBOS_PLACES store.
* @param {String} history The history to be added
* @param {Function} callback Runs when it finishs
*/
updateRawHistory: function browserDB_updateRawHistory(history, callback) {
this.db.createRawHistory(history, callback);
},
/**
* Get a place by URI from DBOS_PLACES object store.
* @param {String} uri URI query parameter
* @param {Function} callback Invoked with an icon object as argument on
* success. Invoked without arguments on error.
*/
getPlace: function browserDB_getPlace(uri, callback) {
this.db.getPlace(uri, callback);
},
/**
* Save the current time of the visit and update frequency (view count).
* @param {String} uri A visited URI to be saved
* @param {Function} callback Runs on frequency (view count) updated
*/
addVisit: function browserDB_addVisit(uri, callback) {
var urlTitle = uri;
if(SyncBrowserDB.browserTitle) {
urlTitle = SyncBrowserDB.browserTitle;
}
var visit = {
uri: uri,
title: urlTitle,
timestamp: new Date().getTime()
};
this.addPlace(uri, (function() {
this.db.visitMaxCheck(uri, (function() {
this.db.saveVisit(visit, (function() {
this.updateFrecency(uri, callback);
}).bind(this));
}).bind(this));
}).bind(this));
},
/**
* Remove visit to the oldest of URL.
* @param {String} uri A visited URI to be saved
* @param {Function} callback Runs on topsite delete
*/
oldVisitDelete: function browserDB_oldVisitDelete(uri, callback) {
this.removeHistory(uri,callback);
},
/**
* Update the visit(title) of the specified URI,
* @param {String} uri A visited URI to be saved
* @param {String} title A visited title to be saved
* @param {Function} callback Runs on frequency (view count) updated
*/
updateVisit: function browserDB_updateVisit(uri, title, callback) {
var visit = {
uri: uri,
title: title,
timestamp: new Date().getTime()
};
this.db.visitMaxCheck(uri, (function() {
this.db.saveVisit(visit, callback);
}).bind(this));
},
/**
* Update the frequency(view count) of the specified URI,
* if the URI has been visited.
* @param {String} uri The URI to be updated
* @param {Function} callback Runs if the URI is the start page or
* the update process is successful
*/
updateFrecency: function browserDB_updateFrecency(uri, callback) {
this.db.updatePlaceFrecency(uri, callback);
},
/**
* Update a screenshot by URI if the URI is in top sites.
* @param {String} uri URI query parameter
* @param {Blob} screenshot A webpage screenshot taken using
* HTMLIFrameElement.getScreenshot
* @param {Function} callback Runs on success
*/
updateScreenshot: function place_updateScreenshot(uri, screenshot, callback) {
var maximum = Browser.MAX_TOPSITE_LIST;
this.db.getPlaceUrisByFrecency(maximum + 1, (function(topSites) {
var runnerUp;
// Get the site that isn't quite a top site, if there is one
if (topSites.length > maximum) {
runnerUp = topSites.pop();
}
// If uri is not one of the top sites, don't store the screenshot
if (topSites.indexOf(uri) == -1) {
return;
}
this.db.updatePlaceScreenshot(uri, screenshot);
// If more top sites than we need screenshots, expire old screenshot
if (runnerUp) {
this.db.updatePlaceScreenshot(runnerUp, null);
}
}).bind(this));
},
/**
* Add a bookmark into database.
* @param {String} data New bookmark record
* @param {Function} callback Runs on success
*/
addBookmark: function browserDB_addBookmark(data, callback) {
data.timestamp = data.timestamp || new Date().getTime();
if (data.type === 'bookmark') {
this.addPlace(data.bmkUri, (function() {
this.db.saveBookmark(data, callback);
}).bind(this));
} else {
this.db.saveBookmark(data, callback);
}
},
/**
* Get a bookmark by an indexes object from database.
* @param {String} indexes Indexes Object query parameter. The parameters
* can be id, bmkUri, or parentid.
* @param {Function} callback Runs with a bookmark object on success. Runs
* without arguments on error.
*/
getBookmark: function browserDB_getBookmark(indexes, callback) {
const FXSYNCID_LEN = 12;
if (typeof indexes === 'string') {
this.db.getBookmark(indexes, callback);
} else if (indexes.id) {
this.db.getBookmark(indexes.id, callback);
} else if (indexes.bmkUri) {
this.db.getBookmarkByUri(indexes.bmkUri, callback);
} else if (indexes.parentid) {
this.db.getBookmark(indexes.parentid, folder => {
if (folder && folder.type === 'folder' && folder.children) {
this.db.getBookmarkByParentId(indexes.parentid, list => {
var children = folder.children;
var result = [];
for (var i = 0; i < children.length; i++) {
for (var j = 0; j < list.length; j++) {
var oriId = list[j].id;
// Append the reduntant underline to match the ID from Syncto.
var id = (oriId + '____________').substring(0, FXSYNCID_LEN);
if (children[i] === id) {
result.push(list[j]);
break;
}
}
}
callback(result);
});
} else {
this.db.getBookmarkByParentId(indexes.parentid, callback);
}
});
} else {
callback(null);
}
},
/**
* Get all bookmarks.
* @param {Function} callback Runs on success with an array of bookmarks
*/
getBookmarks: function browserDB_getBookmarks(callback) {
this.db.getAllBookmarks(callback);
},
/**
* Delete a bookmark by ID
* @param {String} id ID
* @param {Function} callback
*/
removeBookmark: function browserDB_removeBookmark(id, callback) {
this.db.deleteBookmark(id, (function() {
this.db.deleteIconUrl(id, this.DEFAULT_TYPE_BOOKMARK, callback);
}).bind(this));
},
/**
* Get history by timestamp range at (start <= record.timestamp <= end)
* @param {Number} start Start timestamp
* @param {Number} end End timestamp
* @param {Boolean} startEqual Include the record equaling start timestamp
* @param {Boolean} endEqual Include the record equaling end timestamp
* @param {Function} callback Runs on complete with an array of history
*/
getHistoryByTime: function browserDB_getHistoryByTime(start, end, startEqual,
endEqual, callback) {
this.db.getHistoryByTime(start, end, startEqual, endEqual, callback);
},
/**
* Get the timestamp of history range at these 4 combinations:
* (record.timestamp < timestamp) when direction == 'prev' && equal == false
* (record.timestamp <= timestamp) when direction == 'prev' && equal == true
* (record.timestamp > timestamp) when direction == 'next' && equal == false
* (record.timestamp >= timestamp) when direction == 'next' && equal == true
* @param {Number} ts The timestamp that you want to search by.
* @param {String} direction Cursor direction is the same with IndexedDB's.
* @param {Boolean} equal Want to include the record in the timestamp.
* @param {Function} callback Runs on complete with the previous/next
* timestamp of a history record.
*/
getHistoryTimestamp:
function browserDB_getHistoryTimestamp(ts, direction, equal, callback) {
this.db.getHistoryTimestamp(ts, direction, equal, callback);
},
/**
* Delete a history by URI
* @param {String} uri URI
* @param {Function} callback
*/
removeHistory: function browserDB_removeHistory(uri, callback) {
this.db.deleteHistory(uri, (function() {
this.db.deleteIconUrl(uri, this.DEFAULT_TYPE_HISTORY, callback);
}).bind(this));
},
/**
* Delete a topste by URI
* @param {String} uri URI
* @param {Function} callback
*/
removeTopsite: function browserDB_removeTopsite(uri, callback) {
this.db.deleteTopsite(uri, callback);
},
/**
* Add/Update a bookmark in database.
* @param {String} data New bookmark record
* @param {Function} callback Runs on success
*/
updateBookmark: function browserDB_updateBookmark(data, callback) {
this.db.getBookmark(data.id, (function(bookmark) {
if (bookmark) {
this.db.saveBookmark(data, callback);
} else {
this.addBookmark(data, callback);
}
}).bind(this));
},
/**
* Add/Update a bookmark in database without updating places.
* @param {String} data New bookmark record
* @param {Function} callback Runs on success
*/
updateRawBookmark: function browserDB_updateBookmark(data, callback) {
this.db.saveBookmark(data, callback);
},
/**
* Create/Update page title in database.
* @param {String} uri URI query parameter
* @param {String} title Page title
* @param {Function} callback Runs on success
*/
setPageTitle: function browserDB_setPageTitle(uri, title, callback) {
SyncBrowserDB.browserTitle = title;
if(!title){
title = uri;
}
this.db.placeMaxCheck(uri, (function() {
this.db.updatePlaceTitle(uri, title, (function() {
this.updateVisit(uri, title, callback);
}).bind(this));
}).bind(this));
},
/**
* Save iconUri in DBOS_PLACES object store in database.
* @param {String} uri URI
* @param {String} iconUri Base64 encoded image string
* @param {Function} callback Runs on success
*/
setPageIconUri: function browserDB_setPageIconUri(uri, iconUri, callback) {
this.db.updatePlaceIconUri(uri, iconUri, callback);
},
/**
* Create a DBOS_ICONS object store entry and save it in database.
* @param {String} iconUri Base64 encoded image string
* @param {Blob} data Image Blob
* @param {Function} callback Runs on success
* @param {Boolean} failed Specify if the image Blob data is successfully
* saved
*/
setIconData:
function browserDB_setIconData(uri, iconUri, data, callback, failed) {
var now = new Date().valueOf();
var iconEntry = {
uri: uri,
iconUri: iconUri,
data: data,
expiration: now + this.DEFAULT_ICON_EXPIRATION,
failed: failed
};
this.db.saveIcon(iconEntry, callback);
},
/**
* Load the image icon and save it to IndexedDB.
* @param {String} uri URI
* @param {String} iconUri Base64 encoded image string
* @param {Function} callback Run on saving to IndexedDB successful
*/
setAndLoadIconForPage: function browserDB_setAndLoadIconForPage(uri,
iconUri, callback) {
this.setPageIconUri(uri, iconUri);
// If icon is not already cached or has expired, load it
var now = new Date().valueOf();
this.db.getIcon(uri, iconUri, (function(icon) {
if (icon && icon.expiration > now) {
//return;
}
var xhr = new XMLHttpRequest({mozSystem: true});
xhr.open('GET', iconUri, true);
xhr.responseType = 'blob';
xhr.addEventListener('load', (function() {
// Check icon was successfully downloded
// 0 is due to https://bugzilla.mozilla.org/show_bug.cgi?id=716491
if (!(xhr.status === 200 || xhr.status === 0)) {
//this.setIconData(iconUri, null, callback, true);
this.setIconData(uri, Awesomescreen.DEFAULT_FAVICON,
null, callback, true);
console.error('error downloading icon: ' + xhr.status);
return;
}
var blob = xhr.response;
// Check the file is served as an image and isn't too big
if (blob.type.split('/')[0] != 'image' ||
blob.size > this.MAX_ICON_SIZE) {
this.setIconData(uri, iconUri, null, callback, true);
console.error('Icon was not an image or was too big');
return;
}
// Only save the icon if it can be loaded as an image bigger than 0px
var img = document.createElement('img');
var src = window.URL.createObjectURL(blob);
img.src = src;
img.onload = (function() {
if (img.naturalWidth > 0) {
this.setIconData(uri, iconUri, blob, callback);
} else {
this.setIconData(uri, iconUri, null, callback, true);
console.error('Icon not saved because less than 1px wide');
}
window.URL.revokeObjectURL(src);
}).bind(this);
img.onerror = (function() {
this.setIconData(uri, iconUri, null, callback, true);
console.error('Icon not saved because can not be decoded');
window.URL.revokeObjectURL(src);
}).bind(this);
}).bind(this), false);
xhr.onerror = function getIconError() {
console.error('Error fetching icon');
};
xhr.send();
}).bind(this));
},
/**
* Add a DBOS_PLACES entry of the URI.
* @param {String} uri The URI to be added in DB
* @param {String} title
* @param {Number} frequency View count of the specified URI
* @param {Function} callback Runs when it finishs
*/
addTopSite: function browserDB_addTopSite(uri, title, frequency, callback) {
this.addPlace(uri, (function() {
this.db.initPlaceFrecency(uri, title, frequency, callback);
}).bind(this));
},
/**
* Get top sites.
* @param {Number} maximum The maximum number of top sites to get
* @param {String} filter URI filter. Pass in null to ignore.
* @param {Function} callback Run on success with topsites array and filter
* as arguments.
*/
getTopSites: function browserDB_getTopSites(maximum, filter, callback) {
// Get the top 9 sites
this.db.getPlacesByFrecency(maximum, filter, callback);
},
/**
* Get default configured top sites.
* @param {Function} callback Run on success with default top sites array.
*/
getDefaultTopSites: function browserDB_getDefaultTopSites(callback) {
this.db.getDefaultPlaces(callback);
},
/**
* Get the latest history entries based on the maximum number of history.
* @param {Number} maxQuerySize The maximum number of history to get
* @param {Function} callback Run with array of history entries
*/
getHistory: function browserDB_getHistory(maxQuerySize, callback) {
// Just get the most recent 20 for now
var querySize = maxQuerySize ? maxQuerySize : Browser.MAX_HISTORY_LIST;
this.db.getHistory(querySize, callback);
},
/**
* Clear history and keep bookmarks.
* @param {Function} callback Runs on success
*/
clearHistory: function browserDB_clearHistory(callback) {
// Get a list of bookmarks
this.db.clearHistoryExcluding(callback);
},
clearBookmarks: function browserDB_clearBookmarks() {
return new Promise(resolve => {
this.db.clearBookmarks(resolve);
});
},
clearHistoryDeep: function browserDB_clearHistoryDeep() {
return Promise.all([
new Promise(this.db.clearVisits),
new Promise(this.db.clearPlaces),
new Promise(this.db.clearIcons)
]);
}
};
/**
* @memberOf SyncBrowserDB
* @namespace SyncBrowserDB.db
*/
SyncBrowserDB.db = {
_db: null,
START_PAGE_URI: document.location.protocol + '//' + document.location.host +
'/start.html',
/** Version of database being upgraded from */
upgradeFrom: -1,
/**
* Open a IndexedDB database with name as 'browser' and version as 7.
* @param {Function} callback The callback to be run on success
*/
open: function db_open(callback) {
const DB_VERSION = 7;
const DB_NAME = 'fxsync_browser';
var request = idb.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (function onUpgradeNeeded(e) {
console.log('Browser database upgrade needed, upgrading.');
this.upgradeFrom = e.oldVersion;
this._db = e.target.result;
this.upgrade();
}).bind(this);
request.onsuccess = (function onSuccess(e) {
this._db = e.target.result;
callback && callback();
}).bind(this);
request.onerror = (function onDatabaseError(e) {
console.error('Error opening browser database');
}).bind(this);
},
/**
* Create/Update object stores:
* places
* visits
* icons
* bookmarks
*/
upgrade: function db_upgrade() {
var db = this._db;
var upgradeFrom = this.upgradeFrom;
if (upgradeFrom < 1) {
var placesStore = db.createObjectStore(DBOS_PLACES, { keyPath: 'uri' });
// Index places by frecency
placesStore.createIndex('frecency', 'frecency', { unique: false });
var visitStore = db.createObjectStore(DBOS_VISITS, {
keyPath: 'uri' ,
autoIncrement: true
});
// Index visits by timestamp
visitStore.createIndex('timestamp', 'timestamp', { unique: false });
db.createObjectStore(DBOS_ICONS, { keyPath: 'uri' });
var bookmarkStore = db.createObjectStore(DBOS_BOOKMARKS, {
keyPath: 'id'
});
// Index bookmarks by timestamp
bookmarkStore.createIndex('timestamp', 'timestamp', { unique: false });
bookmarkStore.createIndex('bmkUri', 'bmkUri', { unique: false });
bookmarkStore.createIndex('parentid', 'parentid', { unique: false });
}
},
/**
* Create a new DBOS_PLACES entry of the URI if there's none.
* @param {String} uri The uri to be inserted
* @param {Function} callback Runs when the entry exists or a new entry
* created
*/
createPlace: function db_createPlace(uri, callback) {
var title = uri;
if (SyncBrowserDB.browserTitle) {
title = SyncBrowserDB.browserTitle;
SyncBrowserDB.browserTitle = null;
}
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (place) {
if (callback) {
callback();
}
return;
} else {
place = {
uri: uri,
title: title
};
}
var writeRequest = objectStore.add(place);
writeRequest.onsuccess = function onWriteSuccess(event) {
if (callback) {
callback();
}
};
writeRequest.onerror = function onError(event) {
console.error('error writing place');
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save place ' +
uri);
};
},
/**
* Create a new raw entry of the history if there's none.
* @param {String} history The history to be inserted
* @param {Function} callback Runs when the entry exists or a new entry
* created
*/
createRawHistory: function db_createRawHistory(history, callback) {
var transaction = this._db.transaction([DBOS_VISITS], 'readwrite');
var objectStore = transaction.objectStore(DBOS_VISITS);
var readRequest = objectStore.get(history.uri);
readRequest.onsuccess = function onReadSuccess(event) {
var existingPlace = event.target.result;
var writeRequest;
if (existingPlace) {
existingPlace.title = history.title;
existingPlace.timestamp = history.timestamp;
writeRequest = objectStore.put(history);
} else {
writeRequest = objectStore.add(history);
}
writeRequest.onsuccess = function onWriteSuccess(event) {
if (callback) {
callback();
}
};
writeRequest.onerror = function onError(event) {
console.error('error writing history');
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save history ', history);
};
},
/**
* Save an places object store entry in database
* @param {Object} places A visits entry
* @param {Function} callback Runs on success
*/
placeMaxCheck: function db_placeMaxCheck(uri, callback) {
var db = this._db;
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to count places');
};
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var places = event.target.result;
if (places) {
if (callback) {
callback();
}
} else {
//count check
var request = objectStore.count();
request.onsuccess = function onReadSuccess(event) {
var count = event.target.result;
if (count < Browser.MAX_TOPSITE_LIST) {
if (callback) {
callback();
}
}else{
var transaction = db.transaction([DBOS_PLACES]);
var placesStore = transaction.objectStore(DBOS_PLACES);
var placesIndex = placesStore.index('frecency');
placesIndex.openCursor(null, 'next').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var places = cursor.value;
SyncBrowserDB.removeTopsite(places.uri, callback);
} else {
console.error('error get places');
}
if (callback) {
callback();
}
};
}
};
request.onerror = function onReadError(event) {
console.error('error reading place');
};
}
};
readRequest.onerror = function onError(event) {
console.error('error writing places');
};
},
/**
* Get a place by URI from DBOS_PLACES object store.
* @param {String} uri URI query parameter
* @param {Function} callback Invoked with an icon object as argument on
* success. Invoked without arguments on error.
*/
getPlace: function db_getPlace(uri, callback) {
var db = this._db;
var request = db.transaction(DBOS_PLACES).objectStore(DBOS_PLACES).get(uri);
request.onsuccess = function onSuccess(event) {
callback(event.target.result);
};
request.onerror = function onError(event) {
if (event.target.errorCode == IDBDatabaseException.NOT_FOUND_ERR) {
callback();
}
};
},
/**
* Save an visits object store entry in database
* @param {Object} visit A visits entry
* @param {Function} callback Runs on success
*/
visitMaxCheck: function db_visitMaxCheck(uri, callback) {
var db = this._db;
var transaction = this._db.transaction([DBOS_VISITS], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to count visit');
};
var objectStore = transaction.objectStore(DBOS_VISITS);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var visits = event.target.result;
if (visits) {
if (callback) {
callback();
}
} else {
//count check
var request = objectStore.count();
request.onsuccess = function onReadSuccess(event) {
var count = event.target.result;
if (count < Browser.MAX_HISTORY_LIST) {
if (callback) {
callback();
}
}else{
var transaction = db.transaction([DBOS_VISITS]);
var visitsStore = transaction.objectStore(DBOS_VISITS);
var visitsIndex = visitsStore.index('timestamp');
visitsIndex.openCursor(null, 'next').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var visit = cursor.value;
SyncBrowserDB.oldVisitDelete(visit.uri, callback);
} else {
console.error('error get visits');
}
};
}
};
request.onerror = function onReadError(event) {
console.error('error reading visit');
};
}
};
readRequest.onerror = function onError(event) {
console.error('error writing visit');
};
},
/**
* Save an visits object store entry in database
* @param {Object} visit A visits entry
* @param {Function} callback Runs on success
*/
saveVisit: function db_saveVisit(visit, callback) {
var transaction = this._db.transaction([DBOS_VISITS], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save visit');
};
var objectStore = transaction.objectStore(DBOS_VISITS);
var readRequest = objectStore.get(visit.uri);
readRequest.onsuccess = function onReadSuccess(event) {
var visits = event.target.result;
if (visits) {
if(( visits.title != visit.title ) &&
( visits.title == visit.uri )) {
visits.title = visit.title;
visits.timestamp = visit.timestamp;
} else {
visits.timestamp = visit.timestamp;
}
} else {
//TODO num check
visits = {
uri: visit.uri,
title: visit.title,
timestamp: visit.timestamp
};
}
var writeRequest = objectStore.put(visits);
writeRequest.onsuccess = function onWriteSuccess(event) {
if (callback) {
callback();
}
};
writeRequest.onerror = function onError(event) {
console.error('error writing place');
};
};
readRequest.onerror = function onReadError(event) {
console.error('error reading place');
};
},
/**
* Get latest visits entries.
* @param {Number} maximum Maximum number of history entries to get
* @param {Function} callback Run with array of history entries
*/
getHistory: function db_getHistory(maximum, callback) {
var history = [];
var db = this._db;
function makeVisitProcessor(visit) {
return function(e) {
var object = e.target.result;
if(object){
visit.iconUri = object.iconUri;
}else{
visit.iconUri = Awesomescreen.DEFAULT_FAVICON;
}
history.push(visit);
};
}
var transaction = db.transaction([DBOS_VISITS, DBOS_ICONS]);
var visitsStore = transaction.objectStore(DBOS_VISITS);
var objectStore = transaction.objectStore(DBOS_ICONS);
var visitsIndex = visitsStore.index('timestamp');
visitsIndex.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor && history.length < maximum) {
var visit = cursor.value;
objectStore.get(visit.uri).onsuccess = makeVisitProcessor(visit);
cursor.continue();
} else {
callback(history);
}
};
},
/**
* Get default configured places entries. This is possibly broken. Need
* confirmation.
* @param {Function} callback Run on success with default top sites array.
*/
getDefaultPlaces: function db_defaultPlaces(callback) {
var topSites = [];
var transaction = this._db.transaction(DBOS_PLACES);
var placesStore = transaction.objectStore(DBOS_PLACES);
var frecencyIndex = placesStore.index('frecency');
frecencyIndex.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor && cursor.value && cursor.value.frecency < 0) {
topSites.push(cursor.value);
cursor.continue();
} else {
callback(topSites);
}
};
},
/**
* Get places entries ordered by frequency(view count).
* @param {Number} maximum The maximum number of top sites to get
* @param {String} filter URI filter. Pass in null to ignore.
* @param {Function} callback Run on success with topsites array and filter
* as arguments.
*/
getPlacesByFrecency: function db_placesByFrecency(maximum, filter, callback) {
var topSites = [];
var self = this;
var transaction = self._db.transaction(DBOS_PLACES);
var placesStore = transaction.objectStore(DBOS_PLACES);
var frecencyIndex = placesStore.index('frecency');
frecencyIndex.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor && topSites.length < maximum) {
var place = cursor.value;
var matched = false;
if (filter) {
matched = self.matchesFilter(place.uri, filter) ||
self.matchesFilter(place.title, filter);
}
if (matched || !filter) {
if(cursor.value.frecency >= 1){
topSites.push(cursor.value);
}
}
cursor.continue();
} else {
callback(topSites, filter);
}
};
},
/**
* Check if the URI matches the regular expression filter.
* @param {String} uri
* @param {String} filter
* @returns {Boolean}
*/
matchesFilter: function db_matchesFilter(uri, filter) {
return uri.match(new RegExp(filter, 'i')) !== null;
},
/**
* Get places URIs ordered by frequency(view count).
* @param {Number} maximum The maximum number of URIs to get
* @param {Function} callback Run on success with a URI array
*/
getPlaceUrisByFrecency: function db_getPlaceUrisByFrecency(maximum,
callback) {
var topSites = [];
var transaction = this._db.transaction(DBOS_PLACES);
var placesStore = transaction.objectStore(DBOS_PLACES);
var frecencyIndex = placesStore.index('frecency');
frecencyIndex.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor && topSites.length < maximum) {
topSites.push(cursor.value.uri);
cursor.continue();
} else {
callback(topSites);
}
};
},
/**
* Clear places object store.
* @param {Function} callback Runs on success
*/
clearPlaces: function db_clearPlaces(callback) {
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_PLACES, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear places');
};
var objectStore = transaction.objectStore(DBOS_PLACES);
var request = objectStore.clear();
request.onsuccess = function onSuccess() {
callback();
};
request.onerror = function onError(e) {
console.error('Error clearing places object store');
};
},
/**
* Clear visits object store.
* @param {Function} callback Runs on success
*/
clearVisits: function db_clearVisits(callback) {
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_VISITS, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear visits');
};
var objectStore = transaction.objectStore(DBOS_VISITS);
objectStore.openCursor().onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var visit = cursor.value;
SyncBrowserDB.db.deleteIconUrl(visit.uri,
SyncBrowserDB.DEFAULT_TYPE_HISTORY, null);
cursor.continue();
}else{
var request = objectStore.clear();
request.onsuccess = function onSuccess() {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error clearing visits object store');
};
}
};
objectStore.openCursor(null, 'prev').onerror =
function onError(e) {
console.error('Error Delete visits Icon object store');
};
},
/**
* Clear icons object store.
* @param {Function} callback Runs on success
*/
clearIcons: function db_clearIcons(callback) {
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_ICONS, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear icons');
};
var objectStore = transaction.objectStore(DBOS_ICONS);
var request = objectStore.clear();
request.onsuccess = function onSuccess() {
callback();
};
request.onerror = function onError(e) {
console.error('Error clearing icons object store');
};
},
/**
* Clear bookmarks object store.
* @param {Function} callback Runs on success
*/
clearBookmarks: function db_clearBookmarks(callback) {
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_BOOKMARKS, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear bookmarks');
};
var objectStore = transaction.objectStore(DBOS_BOOKMARKS);
var request = objectStore.clear();
request.onsuccess = function onSuccess() {
callback();
};
request.onerror = function onError(e) {
console.error('Error clearing bookmarks object store');
};
},
/**
* Save an icon object store entry in database
* @param {Object} iconEntry
* @param {Function} callback Runs on success
*/
saveIcon: function db_saveIcon(iconEntry, callback) {
var transaction = this._db.transaction([DBOS_ICONS], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save icon');
};
var objectStore = transaction.objectStore(DBOS_ICONS);
var request = objectStore.put(iconEntry);
request.onsuccess = function onSuccess(e) {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error while saving icon');
};
},
/**
* Get a icon by iconUri from DBOS_ICONS object store.
* @param {String} iconUri Base64 encoded icon image string
* @param {Function} callback Invoked with an icon object as argument on
* success. Invoked without arguments on error.
*/
getIcon: function db_getIcon(uri, iconUri, callback) {
var request = this._db.transaction(DBOS_ICONS).objectStore(DBOS_ICONS).
get(uri);
request.onsuccess = function onSuccess(event) {
callback(event.target.result);
};
request.onerror = function onError(event) {
if (event.target.errorCode == IDBDatabaseException.NOT_FOUND_ERR) {
callback();
}
};
},
/**
* Save a bookmarks object store entry in database
* @param {Object} bookmark A bookmarks object store entry
* @param {Function} callback Runs on success
*/
saveBookmark: function db_saveBookmark(bookmark, callback) {
var transaction = this._db.transaction([DBOS_BOOKMARKS], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save bookmark');
};
var objectStore = transaction.objectStore(DBOS_BOOKMARKS);
var request = objectStore.put(bookmark);
request.onsuccess = function onSuccess(e) {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error while saving bookmark');
};
},
/**
* Get a bookmark by ID from database.
* @param {String} id ID
* @param {Function} callback Runs with a bookmark object on success. Runs
* without arguments on error.
*/
getBookmark: function db_getBookmark(id, callback) {
var request = this._db.transaction(DBOS_BOOKMARKS).
objectStore(DBOS_BOOKMARKS).get(id);
request.onsuccess = function onSuccess(event) {
callback(event.target.result);
};
request.onerror = function onError(event) {
if (event.target.errorCode == IDBDatabaseException.NOT_FOUND_ERR) {
callback();
}
};
},
/**
* Get a bookmark by URI from database.
* @param {String} uri URI
* @param {Function} callback Runs with a bookmark object on success. Runs
* without arguments on error.
*/
getBookmarkByUri: function db_getBookmarkByUri(uri, callback) {
var request = this._db.transaction(DBOS_BOOKMARKS).
objectStore(DBOS_BOOKMARKS).index('bmkUri').get(uri);
request.onsuccess = function onSuccess(event) {
callback(event.target.result);
};
request.onerror = function onError(event) {
if (event.target.errorCode == IDBDatabaseException.NOT_FOUND_ERR) {
callback();
}
};
},
/**
* Get a bookmark by Parent ID from database.
* @param {String} parentId Parent ID
* @param {Function} callback Runs with a bookmark object on success. Runs
* without arguments on error.
*/
getBookmarkByParentId: function db_getBookmarkByParentId(parentId, callback) {
var records = [];
var db = this._db;
function fetchIconUri(data) {
return new Promise(resolve => {
if(data.type !== 'bookmark') {
resolve(data);
} else {
var iconRequest = iconsStore.get(data.bmkUri);
iconRequest.onsuccess = function(e) {
var icon = e.target.result;
if(icon && icon.iconUri){
data.iconUri = icon.iconUri;
} else {
data.iconUri = Awesomescreen.DEFAULT_FAVICON;
}
resolve(data);
};
iconRequest.onerror = function(e) {
resolve(data);
};
}
});
}
var transaction = db.transaction([DBOS_BOOKMARKS, DBOS_ICONS]);
var bookmarksStore =
transaction.objectStore(DBOS_BOOKMARKS).index('parentid');
var iconsStore = transaction.objectStore(DBOS_ICONS);
bookmarksStore.openCursor(parentId, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
fetchIconUri(cursor.value).then(bookmark => {
records.push(bookmark);
});
cursor.continue();
}
};
transaction.oncomplete = function db_bookmarkTransactionComplete() {
callback(records);
};
},
/**
* Delete a bookmark by ID from database.
* @param {String} id ID
* @param {Function} callback Runs on success
*/
deleteBookmark: function db_deleteBookmark(id, callback) {
var transaction = this._db.transaction([DBOS_BOOKMARKS], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to delete bookmark');
};
var objectStore = transaction.objectStore(DBOS_BOOKMARKS);
var request = objectStore.delete(id);
request.onsuccess = function onSuccess(event) {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error while deleting bookmark');
};
},
/**
* Delete a history by URI from database.
* @param {String} uri URI query parameter
* @param {Function} callback Runs on success
*/
deleteHistory: function db_deleteHistory(uri, callback) {
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_VISITS, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear visits');
};
var objectStore = transaction.objectStore(DBOS_VISITS);
var request = objectStore.delete(uri);
request.onsuccess = function onSuccess() {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error clearing visits object store');
};
},
/**
* Delete a iconUrl by URI from database.
* @param {String} uri URI query parameter
* @param {Function} callback Runs on success
*/
deleteIconUrl: function db_deleteIconUrl(uri, type, callback) {
var transaction = null;
var objectStore = null;
//In the case of history, it searches the same URL is to bookmark
if(type == SyncBrowserDB.DEFAULT_TYPE_HISTORY){
transaction = this._db.transaction([DBOS_BOOKMARKS], 'readwrite');
objectStore = transaction.objectStore(DBOS_BOOKMARKS);
}else{
transaction = this._db.transaction([DBOS_VISITS], 'readwrite');
objectStore = transaction.objectStore(DBOS_VISITS);
}
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var objList = event.target.result;
if (objList) {
if(callback){
callback();
}
}else{
var db = SyncBrowserDB.db._db;
var transaction = db.transaction(DBOS_ICONS, 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to clear icons');
};
var objectStore = transaction.objectStore(DBOS_ICONS);
var request = objectStore.delete(uri);
request.onsuccess = function onSuccess() {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error clearing icons object store');
};
}
};
readRequest.onerror = function onError(e) {
console.error('Error while read bookamrk or history');
};
},
/**
* Delete a topsite by URI from database.
* @param {String} uri URI query parameter
* @param {Function} callback Runs on success
*/
deleteTopsite: function db_deleteTopsite(uri, callback) {
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to delete topsite');
};
var objectStore = transaction.objectStore(DBOS_PLACES);
var request = objectStore.delete(uri);
request.onsuccess = function onSuccess(event) {
if (callback) {
callback();
}
};
request.onerror = function onError(e) {
console.error('Error while deleting topsite');
};
},
/**
* Get bookmarks
* @param {Function} callback Runs on complete with an array of bookmarks
*/
getAllBookmarks: function db_getAllBookmarks(callback) {
var bookmarks = [];
var db = this._db;
var icons;
function makeBookmarkProcessor(bookmark) {
return function(e) {
icons = e.target.result;
if(icons){
if(icons.iconUri){
bookmark.iconUri = icons.iconUri;
}else{
bookmark.iconUri = Awesomescreen.DEFAULT_FAVICON;
}
}
bookmarks.push(bookmark);
};
}
var transaction = db.transaction([DBOS_BOOKMARKS, DBOS_ICONS]);
var bookmarksStore = transaction.objectStore(DBOS_BOOKMARKS);
var bookmarksIndex = bookmarksStore.index('timestamp');
var objectStore = transaction.objectStore(DBOS_ICONS);
bookmarksIndex.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var bookmark = cursor.value;
objectStore.get(bookmark.id).onsuccess =
makeBookmarkProcessor(bookmark);
cursor.continue();
}
};
transaction.oncomplete = function db_bookmarkTransactionComplete() {
callback(bookmarks);
};
},
/**
* Get all URIs of bookmarks
* @param {Function} callback Runs on complete with an array of URIs
*/
getAllBookmarkUris: function db_getAllBookmarks(callback) {
var uris = [];
var db = this._db;
var transaction = db.transaction(DBOS_BOOKMARKS);
var objectStore = transaction.objectStore(DBOS_BOOKMARKS);
objectStore.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
uris.push(cursor.value.bmkUri);
cursor.continue();
}
};
transaction.oncomplete = function db_bookmarkTransactionComplete() {
callback(uris);
};
},
/**
* Get history by timestamp range at (start <= record.timestamp <= end)
* @param {Number} start Start timestamp
* @param {Number} end End timestamp
* @param {Boolean} startEqual Include the record equaling start timestamp
* @param {Boolean} endEqual Include the record equaling end timestamp
* @param {Function} callback Runs on complete with an array of history
*/
getHistoryByTime:
function db_getHistoryByTime(start, end, startEqual, endEqual, callback) {
var history = [];
var db = this._db;
function makeVisitProcessor(visit) {
return function(e) {
var object = e.target.result;
if(object){
visit.iconUri = object.iconUri;
}else{
visit.iconUri = Awesomescreen.DEFAULT_FAVICON;
}
history.push(visit);
};
}
var transaction = db.transaction([DBOS_VISITS, DBOS_ICONS]);
var visitsStore = transaction.objectStore(DBOS_VISITS);
var objectStore = transaction.objectStore(DBOS_ICONS);
var visitsIndex = visitsStore.index('timestamp');
var keyRange = IDBKeyRange.bound(start, end, !startEqual, !endEqual);
visitsIndex.openCursor(keyRange, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var visit = cursor.value;
objectStore.get(visit.uri).onsuccess = makeVisitProcessor(visit);
cursor.continue();
}
};
transaction.oncomplete = function db_historyTransactionComplete() {
callback(history);
};
},
/**
* Get the timestamp of history range at
* (record.timestamp < timestamp) when direction == 'prev' && equal == false
* (record.timestamp <= timestamp) when direction == 'prev' && equal == true
* (record.timestamp > timestamp) when direction == 'next' && equal == false
* (record.timestamp >= timestamp) when direction == 'next' && equal == true
* @param {Number} timestamp The timestamp that you want to search by.
* @param {String} direction Cursor direction is the same with IndexedDB's.
* @param {Boolean} equal Want to include the record in the timestamp.
* @param {Function} callback Runs on complete with the previous/next
* timestamp of a history record.
*/
getHistoryTimestamp:
function db_getHistoryTimestamp(timestamp, direction, equal, callback) {
const DIRECTION_TYPE = ['next', 'nextunique', 'prev', 'prevunique'];
if (!DIRECTION_TYPE.some(e => e === direction)) {
console.error('Incorrect direction type:', direction);
return ;
}
var db = this._db;
var lastestTimeStampInRange = null;
var transaction = db.transaction([DBOS_VISITS]);
var visitsStore = transaction.objectStore(DBOS_VISITS);
var visitsIndex = visitsStore.index('timestamp');
var keyRange;
if (direction === 'prev' || direction === 'prevunique') {
keyRange = IDBKeyRange.upperBound(timestamp, !equal);
} else {
keyRange = IDBKeyRange.lowerBound(timestamp, !equal);
}
visitsIndex.openCursor(keyRange, direction).onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
lastestTimeStampInRange = cursor.key;
}
};
transaction.oncomplete = function db_historyTransactionComplete() {
callback(lastestTimeStampInRange);
};
},
/**
* Init the frequency(view count) of the specified URI,
* if the URI is in DBOS_PLACES.
* @param {String} uri The URI to be init
* @param {String} title
* @param {Number} frequency View count of the specified URI
* @param {Function} callback Runs when init finishs
*/
initPlaceFrecency: function db_initPlaceFrecency(uri, title,
frecency, callback) {
// Don't assign frecency to the start page
if (uri == this.START_PAGE_URI) {
if (callback) {
callback();
}
return;
}
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (!place || (place.frecency && place.frecency > frecency)) {
return;
}
place.title = title;
place.frecency = frecency;
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while saving new frecency for ' + uri);
};
writeRequest.onsuccess = function onWriteSuccess() {
if (callback) {
callback();
}
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to update place: ' +
uri);
};
},
/**
* Update the frequency(view count) of the specified URI,
* if the URI is in DBOS_PLACES.
* @param {String} uri The URI to be updated
* @param {Function} callback Runs if the URI is the start page or
* the update process is successful
*/
updatePlaceFrecency: function db_updatePlaceFrecency(uri, callback) {
// Don't assign frecency to the start page
if (uri == this.START_PAGE_URI) {
if (callback) {
callback();
}
return;
}
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (!place) {
return;
}
if (!place.frecency) {
place.frecency = 1;
} else {
if (place.frecency < 0) {
place.frecency = 0;
}
// currently just frequency
place.frecency++;
}
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while saving new frecency for ' + uri);
};
writeRequest.onsuccess = function onWriteSuccess() {
if (callback) {
callback();
}
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to update place: ' +
uri);
};
},
/**
* Set the frequency(view count) to null of the specified URI,
* if the URI is in DBOS_PLACES.
* @param {String} uri The URI to be reset
* @param {Function} callback Runs if the reset process is successful
*/
resetPlaceFrecency: function db_resetPlaceFrecency(uri, callback) {
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (!place) {
return;
}
place.frecency = 0;
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while resetting frecency for ' + uri);
};
writeRequest.onsuccess = function onWriteSuccess() {
if (callback) {
callback();
}
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to reset frecency: ' +
uri);
};
},
/**
* Create/Update iconUri in DBOS_PLACES object store.
* @param {String} uri URI query parameter
* @param {String} iconUri Base64 encoded image string
* @param {Function} callback Runs on success
*/
updatePlaceIconUri: function db_updatePlaceIconUri(uri, iconUri, callback) {
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (place) {
place.iconUri = iconUri;
} else {
place = {
uri: uri,
title: uri,
iconUri: iconUri
};
}
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while saving iconUri for ' + uri);
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save iconUri for ' +
uri);
};
transaction.onsuccess = function dbTransactionSuccess(e) {
if (callback) {
callback();
}
};
},
/**
* Create/Update title in DBOS_PLACES object store.
* @param {String} uri URI query parameter
* @param {String} title Page title
* @param {Function} callback Runs on success
*/
updatePlaceTitle: function db_updatePlaceTitle(uri, title, callback) {
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (place) {
place.title = title;
} else {
place = {
uri: uri,
title: title
};
}
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while saving title for ' + uri);
};
writeRequest.onsuccess = function onWriteSuccess() {
if (callback) {
callback();
}
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save title for ' +
uri);
};
},
/**
* Update a screenshot of a places entry by URI.
* @param {String} uri URI query parameter
* @param {Blob} screenshot A webpage screenshot taken using
* HTMLIFrameElement.getScreenshot
* @param {Function} callback Runs on success
*/
updatePlaceScreenshot: function db_updatePlaceScreenshot(uri, screenshot,
callback) {
var transaction = this._db.transaction([DBOS_PLACES], 'readwrite');
var objectStore = transaction.objectStore(DBOS_PLACES);
var readRequest = objectStore.get(uri);
readRequest.onsuccess = function onReadSuccess(event) {
var place = event.target.result;
if (place) {
place.screenshot = screenshot;
} else {
place = {
uri: uri,
title: uri,
screenshot: screenshot
};
}
var writeRequest = objectStore.put(place);
writeRequest.onerror = function onError() {
console.error('Error while saving screenshot for ' + uri);
};
writeRequest.onsuccess = function onWriteSuccess() {
if (callback) {
callback();
}
};
};
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to save screenshot for ' +
uri);
};
},
/**
* Clear places and icons entries. For exceptions reset frequency only.
* @param {Array} exceptions URIs to be excluded from clearing
* @param {Function} callback Runs on success
*/
clearHistoryExcluding: function db_clearHistoryExcluding(callback) {
// Clear all visits
this.clearVisits();
var transaction = this._db.
transaction([DBOS_PLACES, DBOS_ICONS], 'readwrite');
var placesStore = transaction.objectStore(DBOS_PLACES);
var iconStore = transaction.objectStore(DBOS_ICONS);
placesStore.openCursor(null, 'prev').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var place = cursor.value;
// If not one of the exceptions then delete place and icon
placesStore.delete(place.uri);
if (place.iconUri) {
iconStore.delete(place.iconUri);
}
cursor.continue();
}
};
transaction.oncomplete = function db_bookmarkTransactionComplete() {
if (callback) {
callback();
}
};
},
/**
* indexedDB MaxNum Check.
* @param {type} Bookmark or History or Topsite
* @param {maxNum} Object-specific maximum number
*/
idbMaxCheck: function db_idbMaxCheck(objType, maxNum) {
var transaction = this._db.transaction([objType], 'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to ' + objType);
};
var objectStore = transaction.objectStore(objType);
var objectIndex = null;
//count check
var request = objectStore.count();
request.onsuccess = function onReadSuccess(event) {
var count = event.target.result;
var checkCount = count - maxNum;
if(checkCount <= 0) {
return;
}else{
switch(objType){
case DBOS_BOOKMARKS:
case DBOS_VISITS :
objectIndex = objectStore.index('timestamp');
break;
case DBOS_PLACES :
objectIndex = objectStore.index('frecency');
break;
default:
break;
}
objectIndex.openCursor(null, 'next').onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var objData = cursor.value;
switch(objType){
case DBOS_BOOKMARKS:
SyncBrowserDB.removeBookmark(objData.uri);
break;
case DBOS_VISITS :
SyncBrowserDB.removeHistory(objData.uri);
break;
case DBOS_PLACES :
SyncBrowserDB.removeTopsite(objData.uri);
break;
default:
break;
}
checkCount -= 1;
if(checkCount > 0) {
cursor.continue();
}else{
cursor = null;
}
}
};
}
};
request.onerror = function onReadError(event) {
console.error('error reading object count');
};
},
/**
* indexedDB icons MaxNum Check.
*/
iconMaxCheck: function db_iconMaxCheck(maxNum) {
var transaction = this._db.
transaction([DBOS_ICONS, DBOS_BOOKMARKS, DBOS_VISITS],'readwrite');
transaction.onerror = function dbTransactionError(e) {
console.error('Transaction error while trying to icons');
};
var iconsStore = transaction.objectStore(DBOS_ICONS);
var bookmarksStore = transaction.objectStore(DBOS_BOOKMARKS);
var visitsStore = transaction.objectStore(DBOS_VISITS);
//count check
var request = iconsStore.count();
request.onsuccess = function onReadSuccess(event) {
var count = event.target.result;
if (count > maxNum) {
iconsStore.openCursor().onsuccess =
function onSuccess(e) {
var cursor = e.target.result;
if (cursor) {
var icon = cursor.value;
var requestBookmark = bookmarksStore.get(icon.uri);
requestBookmark.onsuccess = function onReadSuccess(event) {
var bookmarks = event.target.result;
if (!bookmarks) {
var requestVisits = visitsStore.get(icon.uri);
requestVisits.onsuccess = function onReadSuccess(event) {
var visits = event.target.result;
if (!visits) {
var requestIcons = iconsStore.delete(icon.uri);
requestIcons.onerror = function onError(e) {
console.error('Error delete icons object store');
};
}
};
requestVisits.onerror = function onReadError(event) {
console.error('error reading visit');
};
}
};
requestBookmark.onerror = function onReadError(event) {
console.error('error reading bookmarks');
};
cursor.continue();
}
};
}
};
request.onerror = function onReadError(event) {
console.error('error reading object icon count');
};
}
};