diff --git a/chrome/chromeFiles/content/scholar/data_access.js b/chrome/chromeFiles/content/scholar/data_access.js index 403666935e..145a59e7cf 100644 --- a/chrome/chromeFiles/content/scholar/data_access.js +++ b/chrome/chromeFiles/content/scholar/data_access.js @@ -43,7 +43,7 @@ Scholar.Object.prototype.isPrimaryField = function(field){ if (!Scholar.Object.primaryFields){ Scholar.Object.primaryFields = Scholar.DB.getColumnHash('objects'); Scholar.Object.primaryFields['firstCreator'] = true; - Scholar.Object.primaryFields['level'] = true; + Scholar.Object.primaryFields['parentFolderID'] = true; Scholar.Object.primaryFields['orderIndex'] = true; } @@ -68,10 +68,10 @@ Scholar.Object.prototype.isEditableField = function(field){ * Build object from database */ Scholar.Object.prototype.loadFromID = function(id){ - var sql = 'SELECT O.*, lastName AS firstCreator, F.level+1 AS level, ORD.orderIndex ' + var sql = 'SELECT O.*, lastName AS firstCreator, TS.parentFolderID, ' + + 'TS.orderIndex ' + 'FROM objects O ' - + 'LEFT JOIN folders F USING (folderID) ' - + 'LEFT JOIN treeOrder ORD ON (O.objectID=ORD.id AND isFolder=0) ' + + 'LEFT JOIN treeStructure TS ON (O.objectID=TS.id AND isFolder=0) ' + 'LEFT JOIN objectCreators OC ON (O.objectID=OC.objectID) ' + 'LEFT JOIN creators C ON (OC.creatorID=C.creatorID) ' + 'WHERE objectID=' + id + ' AND OC.orderIndex=0'; @@ -114,7 +114,7 @@ Scholar.Object.prototype.getType = function(){ Scholar.Object.prototype.getParent = function(){ - return this._data['folderID'] ? this._data['folderID'] : false; + return this._data['parentFolderID'] ? this._data['parentFolderID'] : false; } @@ -306,59 +306,72 @@ Scholar.Object.prototype.setField = function(field, value, loadIn){ } -/* - * Get the nesting level of the object (0 for root items) - */ -Scholar.Object.prototype.getLevel = function(){ - if (!this.getID()){ - throw ('Cannot get level of unsaved object'); // DEBUG: may change - } - return this._data['level']; -} - - /* * Move object to new position and shift surrounding objects * - * N.B. This action updates the DB immediately and reloads all cached - * objects -- a save() is not required + * N.B. Unless isNew is set, this function updates the DB immediately and + * reloads all cached objects -- a save() is not required + * + * If isNew is true, a transaction is not started or committed, so it + * should only be run from an existing transaction within save() */ -Scholar.Object.prototype.setPosition = function(newFolder, newPos){ - var oldFolder = this.getField('folderID'); +Scholar.Object.prototype.setPosition = function(newFolder, newPos, isNew){ + var oldFolder = this.getField('parentFolderID'); var oldPos = this.getField('orderIndex'); if (this.getID()){ if (newFolder==oldFolder && newPos==oldPos){ return true; } - var sql = "BEGIN;\n"; + + if (!isNew){ + Scholar.DB.beginTransaction(); + } // If no position provided, drop at end of folder if (!newPos){ newPos = Scholar.DB.valueQuery('SELECT MAX(orderIndex)+1 FROM ' + - 'objects WHERE folderID=' + newFolder); + 'treeStructure WHERE parentFolderID=' + newFolder); } // Otherwise shift down above it in old folder and shift up at it or // above it in new folder else { - sql += 'UPDATE objects SET orderIndex=orderIndex-1 WHERE folderID=' - + oldFolder + ' AND orderIndex>' + oldPos + ";\n"; + sql = 'UPDATE treeStructure SET orderIndex=orderIndex-1 ' + + 'WHERE parentFolderID=' + oldFolder + + ' AND orderIndex>' + oldPos + ";\n"; - sql += 'UPDATE objects SET orderIndex=orderIndex+1 WHERE folderID=' - + newFolder + ' AND orderIndex>=' + newPos + ";\n"; + sql += 'UPDATE treeStructure SET orderIndex=orderIndex+1 ' + + 'WHERE parentFolderID=' + newFolder + + ' AND orderIndex>=' + newPos + ";\n"; + + Scholar.DB.query(sql); } - sql += 'UPDATE objects SET folderID=' + newFolder + ', orderIndex=' + - newPos + ' WHERE objectID=' + this.getID() + ";\n"; - - sql += 'COMMIT;'; - + // If a new object, insert + if (isNew){ + sql = 'INSERT INTO treeStructure SET id=' + this.getID() + ', ' + + 'isFolder=0, orderIndex=' + newPos + ', ' + + 'parentFolderID=' + newFolder; + } + // Otherwise update + else { + sql = 'UPDATE treeStructure SET parentFolderID=' + newFolder + + ', orderIndex=' + newPos + ' WHERE id=' + this.getID() + + " AND isFolder=0;\n"; + } Scholar.DB.query(sql); + + if (!isNew){ + Scholar.DB.commitTransaction(); + } } - this._data['folderID'] = newFolder; + this._data['parentFolderID'] = newFolder; this._data['orderIndex'] = newPos; - Scholar.Objects.reloadAll(); + + if (!isNew){ + Scholar.Objects.reloadAll(); + } return true; } @@ -556,27 +569,9 @@ Scholar.Object.prototype.save = function(){ sqlValues.push({'string':this.getField('rights')}); } - sqlColumns.push('folderID'); - var newFolder = - this._changed.has('folderID') ? this.getField('folderID') : 0; - sqlValues.push({'int':newFolder}); - try { Scholar.DB.beginTransaction(); - // We set the index here within the transaction so that MAX()+1 - // stays consistent through the INSERT - sqlColumns.push('orderIndex'); - if (this._changed.has('orderIndex')){ - sqlValues.push({'int':this.getField('orderIndex')}); - } - else { - var newPos = Scholar.DB.valueQuery('SELECT MAX(orderIndex)+1 ' - + 'FROM objects WHERE folderID=' + newFolder); - sqlValues.push({'int': newPos}); - } - - // // Creators // @@ -641,7 +636,23 @@ Scholar.Object.prototype.save = function(){ } } + + Scholar.DB.query(sql); + + + // Set the position of the new object + var newFolder = this._changed.has('parentFolderID') + ? this.getField('parentFolderID') : 0; + + var newPos = this._changed.has('orderIndex') + ? this.getField('orderIndex') : false; + + this.setPosition(newFolder, newPos, true); + + // TODO: reload Folder or set the empty flag to false manually + // in case this was the first object in a folder + Scholar.DB.commitTransaction(); } catch (e){ @@ -800,7 +811,7 @@ Scholar.Objects = new function(){ */ function getAll(){ var sql = 'SELECT O.objectID FROM objects O ' - + 'LEFT JOIN treeOrder ORD ON (O.objectID=ORD.id AND isFolder=0) ' + + 'LEFT JOIN treeStructure TS ON (O.objectID=TS.id AND isFolder=0) ' + 'ORDER BY orderIndex'; var ids = Scholar.DB.columnQuery(sql); @@ -821,23 +832,20 @@ Scholar.Objects = new function(){ /* // To return all items (no longer used) - var sql = 'SELECT * FROM treeOrder WHERE id>0 ORDER BY orderIndex'; + var sql = 'SELECT * FROM treeStructure WHERE id>0 ORDER BY orderIndex'; */ if (!parent){ parent = 0; } - var sql = 'SELECT TORD.* FROM treeOrder TORD ' - + 'LEFT JOIN objects O ON (TORD.id=O.objectID AND isFolder=0) ' - + 'LEFT JOIN folders F ON (TORD.id=F.folderID AND isFolder=1) ' - + 'WHERE IFNULL(O.folderID, F.parentFolderID)=' + parent - + ' ORDER BY orderIndex'; + var sql = 'SELECT * FROM treeStructure TS ' + + 'WHERE parentFolderID=' + parent + ' ORDER BY orderIndex'; var tree = Scholar.DB.query(sql); if (!tree){ - throw ('treeOrder is empty'); + throw ('treeStructure is empty'); } _load('all'); @@ -914,11 +922,12 @@ Scholar.Objects = new function(){ return false; } - // Should be the same as query in Scholar.Object.loadFromID, just without objectID clause - var sql = 'SELECT O.*, lastName AS firstCreator, F.level+1 AS level, ORD.orderIndex ' + // Should be the same as query in Scholar.Object.loadFromID, just + // without objectID clause + var sql = 'SELECT O.*, lastName AS firstCreator, TS.parentFolderID, ' + + 'TS.orderIndex ' + 'FROM objects O ' - + 'LEFT JOIN folders F USING (folderID) ' - + 'LEFT JOIN treeOrder ORD ON (O.objectID=ORD.id AND isFolder=0) ' + + 'LEFT JOIN treeStructure TS ON (O.objectID=TS.id AND isFolder=0) ' + 'LEFT JOIN objectCreators OC ON (O.objectID=OC.objectID) ' + 'LEFT JOIN creators C ON (OC.creatorID=C.creatorID) ' + 'WHERE OC.orderIndex=0'; @@ -960,7 +969,13 @@ Scholar.Folder = function(){ * Build folder from database */ Scholar.Folder.prototype.loadFromID = function(id){ - var sql = 'SELECT * FROM folders WHERE folderID=' + id; + // Should be same as query in Scholar.Folders, just with folderID + var sql = "SELECT folderID, folderName, parentFolderID, " + + "(SELECT COUNT(*) FROM treeStructure WHERE parentFolderID=" + + id + ")=0 AS isEmpty FROM folders F " + + "JOIN treeStructure TS ON (F.folderID=TS.id AND TS.isFolder=1) " + + "WHERE folderID=" + id; + var row = Scholar.DB.rowQuery(sql); this.loadFromRow(row); } @@ -973,7 +988,7 @@ Scholar.Folder.prototype.loadFromRow = function(row){ this._id = row['folderID']; this._name = row['folderName']; this._parent = row['parentFolderID']; - this._level = row['level']; + this._empty = row['isEmpty']; } Scholar.Folder.prototype.getID = function(){ @@ -984,10 +999,6 @@ Scholar.Folder.prototype.getName = function(){ return this._name; } -Scholar.Folder.prototype.getLevel = function(){ - return this._level; -} - Scholar.Folder.prototype.isFolder = function(){ return true; } @@ -996,6 +1007,10 @@ Scholar.Folder.prototype.getParent = function(){ return this._parent; } +Scholar.Folder.prototype.isEmpty = function(){ + return !!parseInt(this._empty); +} + /* * Primary interface for accessing Scholar folders @@ -1018,7 +1033,11 @@ Scholar.Folders = new function(){ function _load(){ - var sql = "SELECT * FROM folders WHERE folderID>0"; // skip 'root' folder + var sql = "SELECT folderID, folderName, parentFolderID, " + + "(SELECT COUNT(*) FROM treeStructure WHERE " + + "parentFolderID=TS.id)=0 AS isEmpty FROM folders F " + + "JOIN treeStructure TS ON (F.folderID=TS.id AND TS.isFolder=1) " + + "WHERE folderID>0"; // skip 'root' folder var result = Scholar.DB.query(sql); if (!result){ diff --git a/chrome/chromeFiles/content/scholar/db.js b/chrome/chromeFiles/content/scholar/db.js index 96fcc16654..f93011e531 100644 --- a/chrome/chromeFiles/content/scholar/db.js +++ b/chrome/chromeFiles/content/scholar/db.js @@ -412,16 +412,11 @@ Scholar.DB = new function(){ for (var i=parseInt(fromVersion) + 1; i<=toVersion; i++){ // For now, just wipe and recreate - if (i==4){ + if (i==6){ _initializeSchema(); } - if (i==5){ - query("UPDATE folders SET level=-1, parentFolderID=NULL WHERE folderID=0"); - _updateDBVersion(i); - } - - if (i==6){ + if (i==7){ // do stuff // _updateDBVersion(i); } diff --git a/chrome/chromeFiles/content/scholar/scholar.js b/chrome/chromeFiles/content/scholar/scholar.js index ea6c0c3c86..f77f684aa6 100644 --- a/chrome/chromeFiles/content/scholar/scholar.js +++ b/chrome/chromeFiles/content/scholar/scholar.js @@ -1,7 +1,7 @@ const SCHOLAR_CONFIG = { GUID: 'scholar@chnm', DB_FILE: 'scholar.sqlite', - DB_VERSION: 5, // must match version at top of schema.sql + DB_VERSION: 6, // must match version at top of schema.sql DB_REBUILD: false, // erase DB and recreate from schema DEBUG_LOGGING: true, DEBUG_TO_CONSOLE: false // dump debug messages to console rather than (much slower) Debug Logger diff --git a/schema.sql b/schema.sql index 7c218ed99d..f7ecb119f8 100644 --- a/schema.sql +++ b/schema.sql @@ -1,4 +1,4 @@ --- 5 +-- 6 DROP TABLE IF EXISTS version; CREATE TABLE version ( @@ -13,11 +13,8 @@ dateAdded DATETIME DEFAULT CURRENT_TIMESTAMP, dateModified DATETIME DEFAULT CURRENT_TIMESTAMP, source TEXT, - rights TEXT, - folderID INT, - FOREIGN KEY (folderID) REFERENCES folders(folderID) + rights TEXT ); - CREATE INDEX folderID ON objects(folderID); DROP TABLE IF EXISTS objectTypes; CREATE TABLE objectTypes ( @@ -106,22 +103,22 @@ CREATE TABLE folders ( folderID INT, folderName TEXT, - parentFolderID INT DEFAULT 0, - level INT DEFAULT 0, - PRIMARY KEY (folderID), - FOREIGN KEY (parentFolderID) REFERENCES folders(folderID) + PRIMARY KEY (folderID) ); - CREATE INDEX parentFolderID ON folders(parentFolderID); - INSERT INTO folders VALUES (0, 'root', NULL, -1); + INSERT INTO folders VALUES (0, 'root'); - DROP TABLE IF EXISTS treeOrder; - CREATE TABLE treeOrder ( + DROP TABLE IF EXISTS treeStructure; + CREATE TABLE treeStructure ( id INT, isFolder INT, orderIndex INT, - PRIMARY KEY (id, isFolder) + parentFolderID INT DEFAULT 0, + PRIMARY KEY (id, isFolder), + FOREIGN KEY (parentFolderID) REFERENCES folders(folderID) ); - INSERT INTO treeOrder VALUES (0, 1, 0); + DROP INDEX IF EXISTS parentFolderID; + CREATE INDEX parentFolderID ON treeStructure(parentFolderID); + INSERT INTO treeStructure VALUES (0, 1, 0, NULL); -- Some sample data INSERT INTO objectTypes VALUES (1,'Book'); @@ -157,21 +154,21 @@ INSERT INTO objectTypeFields VALUES (2,3,3); INSERT INTO objectTypeFields VALUES (2,8,4); - INSERT INTO "objects" VALUES(1, 1, 'Online connections: Internet interpersonal relationships', '2006-03-12 05:24:40', '2006-03-12 05:24:40', NULL, NULL, 0); - INSERT INTO "objects" VALUES(2, 1, 'Computer-Mediated Communication: Human-to-Human Communication Across the Internet', '2006-03-12 05:25:50', '2006-03-12 05:25:50', NULL, NULL, 0); - INSERT INTO "objects" VALUES(3, 2, 'Residential propinquity as a factor in marriage selection', '2006-03-12 05:26:37', '2006-03-12 05:26:37', NULL, NULL, 0); - INSERT INTO "objects" VALUES(4, 1, 'Connecting: how we form social bonds and communities in the Internet age', '2006-03-12 05:27:15', '2006-03-12 05:27:15', NULL, NULL, 0); - INSERT INTO "objects" VALUES(5, 1, 'Male, Female, Email: The Struggle for Relatedness in a Paranoid Society', '2006-03-12 05:27:36', '2006-03-12 05:27:36', NULL, NULL, 0); - INSERT INTO "objects" VALUES(6, 2, 'Social Implications of Sociology', '2006-03-12 05:27:53', '2006-03-12 05:27:53', NULL, NULL, 0); - INSERT INTO "objects" VALUES(7, 1, 'Social Pressures in Informal Groups: A Study of Human Factors in Housing', '2006-03-12 05:28:05', '2006-03-12 05:28:05', NULL, NULL, 0); - INSERT INTO "objects" VALUES(8, 1, 'Cybersociety 2.0: Revisiting Computer-Mediated Community and Technology', '2006-03-12 05:28:37', '2006-03-12 05:28:37', NULL, NULL, 0); - INSERT INTO "objects" VALUES(9, 2, 'The Computer as a Communication Device', '2006-03-12 05:29:03', '2006-03-12 05:29:03', NULL, NULL, 0); - INSERT INTO "objects" VALUES(10, 2, 'What Does Research Say about the Nature of Computer-mediated Communication: Task-Oriented, Social-Emotion-Oriented, or Both?', '2006-03-12 05:29:12', '2006-03-12 05:29:12', NULL, NULL, 0); - INSERT INTO "objects" VALUES(11, 1, 'The second self: computers and the human spirit', '2006-03-12 05:30:38', '2006-03-12 05:30:38', NULL, NULL, 0); - INSERT INTO "objects" VALUES(12, 1, 'Life on the screen: identity in the age of the Internet', '2006-03-12 05:30:49', '2006-03-12 05:30:49', NULL, NULL, 1241); - INSERT INTO "objects" VALUES(13, 2, 'The computer conference: An altered state of communication', '2006-03-12 05:31:00', '2006-03-12 05:31:00', NULL, NULL, 6856); - INSERT INTO "objects" VALUES(14, 2, 'Computer Networks as Social Networks: Collaborative Work, Telework, and Community', '2006-03-12 05:31:17', '2006-03-12 05:31:17', NULL, NULL, 6856); - INSERT INTO "objects" VALUES(15, 1, 'The Internet in everyday life', '2006-03-12 05:31:41', '2006-03-12 05:31:41', NULL, NULL, 7373); + INSERT INTO "objects" VALUES(1, 1, 'Online connections: Internet interpersonal relationships', '2006-03-12 05:24:40', '2006-03-12 05:24:40', NULL, NULL); + INSERT INTO "objects" VALUES(2, 1, 'Computer-Mediated Communication: Human-to-Human Communication Across the Internet', '2006-03-12 05:25:50', '2006-03-12 05:25:50', NULL, NULL); + INSERT INTO "objects" VALUES(3, 2, 'Residential propinquity as a factor in marriage selection', '2006-03-12 05:26:37', '2006-03-12 05:26:37', NULL, NULL); + INSERT INTO "objects" VALUES(4, 1, 'Connecting: how we form social bonds and communities in the Internet age', '2006-03-12 05:27:15', '2006-03-12 05:27:15', NULL, NULL); + INSERT INTO "objects" VALUES(5, 1, 'Male, Female, Email: The Struggle for Relatedness in a Paranoid Society', '2006-03-12 05:27:36', '2006-03-12 05:27:36', NULL, NULL); + INSERT INTO "objects" VALUES(6, 2, 'Social Implications of Sociology', '2006-03-12 05:27:53', '2006-03-12 05:27:53', NULL, NULL); + INSERT INTO "objects" VALUES(7, 1, 'Social Pressures in Informal Groups: A Study of Human Factors in Housing', '2006-03-12 05:28:05', '2006-03-12 05:28:05', NULL, NULL); + INSERT INTO "objects" VALUES(8, 1, 'Cybersociety 2.0: Revisiting Computer-Mediated Community and Technology', '2006-03-12 05:28:37', '2006-03-12 05:28:37', NULL, NULL); + INSERT INTO "objects" VALUES(9, 2, 'The Computer as a Communication Device', '2006-03-12 05:29:03', '2006-03-12 05:29:03', NULL, NULL); + INSERT INTO "objects" VALUES(10, 2, 'What Does Research Say about the Nature of Computer-mediated Communication: Task-Oriented, Social-Emotion-Oriented, or Both?', '2006-03-12 05:29:12', '2006-03-12 05:29:12', NULL, NULL); + INSERT INTO "objects" VALUES(11, 1, 'The second self: computers and the human spirit', '2006-03-12 05:30:38', '2006-03-12 05:30:38', NULL, NULL); + INSERT INTO "objects" VALUES(12, 1, 'Life on the screen: identity in the age of the Internet', '2006-03-12 05:30:49', '2006-03-12 05:30:49', NULL, NULL); + INSERT INTO "objects" VALUES(13, 2, 'The computer conference: An altered state of communication', '2006-03-12 05:31:00', '2006-03-12 05:31:00', NULL, NULL); + INSERT INTO "objects" VALUES(14, 2, 'Computer Networks as Social Networks: Collaborative Work, Telework, and Community', '2006-03-12 05:31:17', '2006-03-12 05:31:17', NULL, NULL); + INSERT INTO "objects" VALUES(15, 1, 'The Internet in everyday life', '2006-03-12 05:31:41', '2006-03-12 05:31:41', NULL, NULL); INSERT INTO "objectData" VALUES(1, 7, 2001); INSERT INTO "objectData" VALUES(1, 5, 'Cresskill, N.J.'); @@ -216,29 +213,29 @@ INSERT INTO "objectCreators" VALUES(7, 8, 2); INSERT INTO "objectCreators" VALUES(9, 11, 1); - INSERT INTO folders VALUES (1241, 'Test Folder', 0, 0); - INSERT INTO folders VALUES (3262, 'Another Test Folder', 0, 0); - INSERT INTO folders VALUES (6856, 'Yet Another Folder', 0, 0); - INSERT INTO folders VALUES (7373, 'A Subfolder!', 6856, 1); - INSERT INTO folders VALUES (9233, 'A Sub-subfolder!', 7373, 2); + INSERT INTO folders VALUES (1241, 'Test Folder'); + INSERT INTO folders VALUES (3262, 'Another Test Folder'); + INSERT INTO folders VALUES (6856, 'Yet Another Folder'); + INSERT INTO folders VALUES (7373, 'A Subfolder!'); + INSERT INTO folders VALUES (9233, 'A Sub-subfolder!'); - INSERT INTO treeOrder VALUES (1, 0, 1); - INSERT INTO treeOrder VALUES (3262, 1, 2); - INSERT INTO treeOrder VALUES (2, 0, 3); - INSERT INTO treeOrder VALUES (3, 0, 4); - INSERT INTO treeOrder VALUES (4, 0, 5); - INSERT INTO treeOrder VALUES (5, 0, 6); - INSERT INTO treeOrder VALUES (6, 0, 7); - INSERT INTO treeOrder VALUES (7, 0, 8); - INSERT INTO treeOrder VALUES (8, 0, 9); - INSERT INTO treeOrder VALUES (9, 0, 10); - INSERT INTO treeOrder VALUES (6856, 1, 11); - INSERT INTO treeOrder VALUES (14, 0, 12); - INSERT INTO treeOrder VALUES (13, 0, 13); - INSERT INTO treeOrder VALUES (7373, 1, 14); - INSERT INTO treeOrder VALUES (15, 0, 15); - INSERT INTO treeOrder VALUES (9233, 1, 16); - INSERT INTO treeOrder VALUES (11, 0, 17); - INSERT INTO treeOrder VALUES (10, 0, 18); - INSERT INTO treeOrder VALUES (1241, 1, 19); - INSERT INTO treeOrder VALUES (12, 0, 20); + INSERT INTO treeStructure VALUES (1, 0, 1, 0); + INSERT INTO treeStructure VALUES (3262, 1, 2, 0); + INSERT INTO treeStructure VALUES (2, 0, 3, 0); + INSERT INTO treeStructure VALUES (3, 0, 4, 0); + INSERT INTO treeStructure VALUES (4, 0, 5, 0); + INSERT INTO treeStructure VALUES (5, 0, 6, 0); + INSERT INTO treeStructure VALUES (6, 0, 7, 0); + INSERT INTO treeStructure VALUES (7, 0, 8, 0); + INSERT INTO treeStructure VALUES (8, 0, 9, 0); + INSERT INTO treeStructure VALUES (9, 0, 10, 0); + INSERT INTO treeStructure VALUES (6856, 1, 11, 0); + INSERT INTO treeStructure VALUES (14, 0, 12, 6856); + INSERT INTO treeStructure VALUES (13, 0, 13, 6856); + INSERT INTO treeStructure VALUES (7373, 1, 14, 6856); + INSERT INTO treeStructure VALUES (15, 0, 15, 7373); + INSERT INTO treeStructure VALUES (9233, 1, 16, 7373); + INSERT INTO treeStructure VALUES (11, 0, 17, 0); + INSERT INTO treeStructure VALUES (10, 0, 18, 0); + INSERT INTO treeStructure VALUES (1241, 1, 19, 0); + INSERT INTO treeStructure VALUES (12, 0, 20, 1241);