Created
December 7, 2013 01:43
-
-
Save Swader/7836294 to your computer and use it in GitHub Desktop.
Background final part 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var Base64 = {_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", encode: function (r) { | |
var t, e, a, o, h, n, C, c = "", i = 0; | |
for (r = Base64._utf8_encode(r); i < r.length;)t = r.charCodeAt(i++), e = r.charCodeAt(i++), a = r.charCodeAt(i++), o = t >> 2, h = (3 & t) << 4 | e >> 4, n = (15 & e) << 2 | a >> 6, C = 63 & a, isNaN(e) ? n = C = 64 : isNaN(a) && (C = 64), c = c + this._keyStr.charAt(o) + this._keyStr.charAt(h) + this._keyStr.charAt(n) + this._keyStr.charAt(C); | |
return c | |
}, _utf8_encode: function (r) { | |
r = r.replace(/\r\n/g, "\n"); | |
for (var t = "", e = 0; e < r.length; e++) { | |
var a = r.charCodeAt(e); | |
128 > a ? t += String.fromCharCode(a) : a > 127 && 2048 > a ? (t += String.fromCharCode(192 | a >> 6), t += String.fromCharCode(128 | 63 & a)) : (t += String.fromCharCode(224 | a >> 12), t += String.fromCharCode(128 | 63 & a >> 6), t += String.fromCharCode(128 | 63 & a)) | |
} | |
return t | |
}}; | |
/** | |
* Flag to define whether or not logging is active | |
* @type {boolean} | |
*/ | |
const CONSOLE_LOGGING = false; | |
/** | |
* Logging function that replaces console.log | |
* @param val | |
*/ | |
function clog(val) { | |
if (CONSOLE_LOGGING) { | |
console.log(val); | |
} | |
} | |
/** | |
* Returns an array of common elements from both arrays | |
* @param array | |
* @returns {Array} | |
*/ | |
Array.prototype.intersect = function (array) { | |
return this.filter(function (n) { | |
return array.indexOf(n) != -1 | |
}); | |
}; | |
/** | |
* Removes duplicate elements from the array | |
*/ | |
Array.prototype.unique = function () { | |
var result = []; | |
var len = this.length; | |
while (len--) { | |
if (result.indexOf(this[len]) == -1) { | |
result.push(this[len]); | |
} | |
} | |
this.length = 0; | |
len = result.length; | |
while (len--) { | |
this.push(result[len]); | |
} | |
}; | |
/** | |
* Returns an array - the difference between the two provided arrays. | |
* If the mirror parameter is undefined or true, returns only left-to-right difference. | |
* Otherwise, returns a merge of left-to-right and right-to-left difference. | |
* @param array {Array} | |
* @param mirror | |
* @returns {Array} | |
*/ | |
Array.prototype.diff = function (array, mirror) { | |
var current = this; | |
mirror = (mirror === undefined); | |
var a = current.filter(function (n) { | |
return array.indexOf(n) == -1 | |
}); | |
if (mirror) { | |
return a.concat(array.filter(function (n) { | |
return current.indexOf(n) == -1 | |
})); | |
} | |
return a; | |
}; | |
/** | |
* Iterates through children of the item with ID: {id} and calls callback with | |
* first child of a matching title, or false. | |
* @param id | |
* @param title | |
* @param callback | |
*/ | |
chrome.bookmarks.getFirstChildByTitle = function (id, title, callback) { | |
chrome.bookmarks.getChildren(id, function (children) { | |
var iLength = children.length; | |
while (iLength--) { | |
var item = children[iLength]; | |
if (item.title == title) { | |
return callback(item); | |
} | |
} | |
return callback(false); | |
}); | |
}; | |
/** | |
* Iterates through children of the item with ID: {id} and calls callback with | |
* first child of a matching URL, or false | |
* @param id | |
* @param url | |
* @param callback | |
*/ | |
chrome.bookmarks.getFirstChildByUrl = function (id, url, callback) { | |
chrome.bookmarks.getChildren(id, function (children) { | |
var iLength = children.length; | |
while (iLength--) { | |
var item = children[iLength]; | |
if (item.hasOwnProperty('url') && item.url == url) { | |
return callback(item); | |
} | |
} | |
return callback(false); | |
}); | |
}; | |
/** | |
* Makes a basic Base64 encoded auth header for basic HTTP authentication requests | |
* @param user | |
* @param password | |
* @returns {string} | |
*/ | |
function make_basic_auth(user, password) { | |
var tok = user + ':' + password; | |
var hash = Base64.encode(tok); | |
return "Basic " + hash; | |
} | |
var user = 'user'; | |
var password = 'pass'; | |
var auth = make_basic_auth(user, password); | |
var rootUrl = "https://secure.diigo.com/api/v2/bookmarks?key=KEY&"; | |
var possibleErrors = { | |
400: 'Bad Request: Some request parameters are invalid or the API rate limit is exceeded.', | |
401: 'Not Authorized: Authentication credentials are missing or invalid.', | |
403: 'Forbidden: The request has been refused because of the lack of proper permission.', | |
404: 'Not Found: Either you\'re requesting an invalid URI or the resource in question doesn\'t exist (e.g. no such user).', | |
500: 'Internal Server Error: Something is broken.', | |
502: 'Bad Gateway: Diigo is down or being upgraded.', | |
503: 'Service Unavailable: The Diigo servers are too busy to server your request. Please try again later.', | |
other: 'Unknown error. Something went wrong.' | |
}; | |
var doRequest = function (bookmarknode, tag) { | |
var xml = new XMLHttpRequest(); | |
if (bookmarknode !== undefined) { | |
if (tag === undefined) { | |
console.error("Tag not passed in. Unaware of where to store bookmark in Diigo. Nothing done."); | |
} else { | |
// Bookmark node was passed in. We're doing a POST for update, create or delete | |
// Currently only create is supported | |
var uriPart = encodeURI("url=" + bookmarknode.url + "&title=" + bookmarknode.title + "&tags=" + tag); | |
xml.open('POST', rootUrl + uriPart); | |
xml.setRequestHeader('Authorization', auth); | |
xml.send(); | |
xml.onreadystatechange = function () { | |
if (xml.readyState === 4) { | |
if (xml.status === 200) { | |
clog("Successfully created new bookmark in Diigo"); | |
} else { | |
if (possibleErrors[xml.status] !== undefined) { | |
console.error(xml.status + ' ' + possibleErrors[xml.status]); | |
} else { | |
console.error(possibleErrors.other); | |
} | |
} | |
} | |
}; | |
} | |
} else { | |
xml.open('GET', rootUrl + "&count=100&filter=all&user=" + user); | |
xml.setRequestHeader('Authorization', auth); | |
xml.send(); | |
xml.onreadystatechange = function () { | |
if (xml.readyState === 4) { | |
if (xml.status === 200) { | |
process(JSON.parse(xml.responseText)); | |
} else { | |
if (possibleErrors[xml.status] !== undefined) { | |
console.error(xml.status + ' ' + possibleErrors[xml.status]); | |
} else { | |
console.error(possibleErrors.other); | |
console.error(xml.status); | |
} | |
} | |
} | |
}; | |
} | |
}; | |
var process = function (response) { | |
var iLength = response.length; | |
var allTags = []; | |
var rootBookmarks = []; | |
if (iLength) { | |
clog(iLength + " bookmarks were found."); | |
var i = iLength; | |
while (i--) { | |
var item = response[i]; | |
/** @namespace item.tags */ | |
if (item.tags !== undefined && item.tags != "") { | |
var tags = item.tags.split(','); | |
if (tags.indexOf('bbs-root') > -1) { | |
rootBookmarks.push(item); | |
} | |
allTags = allTags.concat(tags); | |
} | |
} | |
allTags.unique(); | |
allTags.sort(); | |
var folderName = 'Diigo #BBS'; | |
chrome.bookmarks.getFirstChildByTitle("1", folderName, function (value) { | |
/** | |
* Creates the main bookmark bar folder if it doesn't exist | |
*/ | |
if (value === false) { | |
chrome.bookmarks.create({ | |
parentId: "1", | |
title: folderName | |
}, function (folder) { | |
clog(folderName + " not found and has been created at ID " + folder.id); | |
processTagsFolder(folder, allTags); | |
}); | |
} else { | |
processTagsFolder(value, allTags); | |
} | |
/** | |
* Creates the Tags master folder if it doesn't exist | |
* Initiates the check for tag subfolders | |
* Creates ROOT bookmarks | |
* @param rootNode | |
* @param tagsArray | |
*/ | |
function processTagsFolder(rootNode, tagsArray) { | |
// Get all current root bookmarks, if any | |
chrome.bookmarks.getChildren(rootNode.id, function (currentRoots) { | |
var crl = currentRoots.length; | |
var ignoredUrls = []; | |
var rootNumOrig = rootBookmarks.length; | |
if (crl) { | |
var bAmongThem = false; | |
var rootNum = rootNumOrig; | |
// Iterate through all the current items in the root folder | |
while (crl--) { | |
// Check if current item is a URL bookmark, not a folder | |
if (currentRoots[crl].hasOwnProperty('url')) { | |
// Iterate through downloaded bookmarks to see if it's among them | |
bAmongThem = false; | |
while (rootNum--) { | |
if (rootBookmarks[rootNum].url == currentRoots[crl].url) { | |
// Found among existing! | |
bAmongThem = true; | |
if (rootBookmarks[rootNum].title != currentRoots[crl].title) { | |
// Does title need updating? | |
chrome.bookmarks.update(currentRoots[crl].id, { | |
title: rootBookmarks[rootNum].title | |
}); | |
} | |
// Ignore this URL when later adding the downloaded root bookmarks | |
ignoredUrls.push(rootBookmarks[rootNum].url); | |
break; | |
} | |
} | |
if (!bAmongThem) { | |
// Does not exist in downloaded - needs to be deleted from browser | |
chrome.bookmarks.remove(currentRoots[crl].id); | |
} | |
} | |
} | |
} | |
// At this point, we know we removed all the bookmarks that are no longer in our Diigo account | |
// Now let's add those that are left | |
while (rootNumOrig--) { | |
if (ignoredUrls.indexOf(rootBookmarks[rootNumOrig].url) === -1) { | |
chrome.bookmarks.create({ | |
url: rootBookmarks[rootNumOrig].url, | |
title: rootBookmarks[rootNumOrig].title, | |
parentId: rootNode.id | |
}); | |
} | |
} | |
}); | |
chrome.bookmarks.getFirstChildByTitle(rootNode.id, 'Tags', function (tagsFolder) { | |
if (tagsFolder === false) { | |
chrome.bookmarks.create({ | |
parentId: rootNode.id, | |
title: "Tags" | |
}, function (folder) { | |
processTags(folder, tagsArray); | |
}); | |
} else { | |
processTags(tagsFolder, tagsArray); | |
} | |
}); | |
} | |
/** | |
* Creates all non-existent tag subfolders. | |
* Removes all tag subfolders that do not have any bookmarks. | |
* @param tagsFolder | |
* @param tagsArray | |
*/ | |
function processTags(tagsFolder, tagsArray) { | |
// Remove all unused tag subfolders | |
chrome.bookmarks.getChildren(tagsFolder.id, function (currentTagSubfolders) { | |
var numCurrentTags = currentTagSubfolders.length; | |
if (numCurrentTags > 0) { | |
var currentTags = []; | |
var currentTagsIds = {}; | |
var cTag; | |
while (numCurrentTags--) { | |
cTag = currentTagSubfolders[numCurrentTags]; | |
currentTags.push(cTag.title); | |
currentTagsIds[cTag.title] = cTag.id; | |
} | |
var diff = currentTags.diff(allTags, false); | |
var numUnused = diff.length; | |
if (numUnused) { | |
while (numUnused--) { | |
chrome.bookmarks.removeTree(currentTagsIds[diff[numUnused]]); | |
} | |
} | |
} | |
}); | |
// Create necessary tag subfolders | |
var numTags = tagsArray.length; | |
while (numTags--) { | |
let title = tagsArray[numTags]; | |
chrome.bookmarks.getFirstChildByTitle(tagsFolder.id, title, function (tagFolder) { | |
if (tagFolder === false) { | |
// Needs to be created | |
chrome.bookmarks.create({ | |
parentId: tagsFolder.id, | |
title: title | |
}, function (folder) { | |
addAllBookmarksWithTag(folder); | |
}); | |
} else { | |
addAllBookmarksWithTag(tagFolder); | |
} | |
}); | |
} | |
} | |
/** | |
* Adds all bookmarks with given tag to provided folder, if they don't exist. | |
* Looks at URL for comparison, not title. | |
* @param folder | |
*/ | |
function addAllBookmarksWithTag(folder) { | |
chrome.bookmarks.getChildren(folder.id, function (children) { | |
var urls = {}; | |
if (children.length > 0) { | |
var numChildren = children.length; | |
var subItem; | |
while (numChildren--) { | |
subItem = children[numChildren]; | |
urls[subItem.url] = subItem; | |
} | |
} | |
var i = iLength; | |
var key = false; | |
while (i--) { | |
var item = response[i]; | |
var tags = item.tags.split(','); | |
if (tags.indexOf(folder.title) > -1) { | |
// Bookmark belongs in folder | |
clog("-----------------------------"); | |
clog("Checking for " + item.url + " in "); | |
clog(urls); | |
clog("Found? " + urls.hasOwnProperty(item.url)); | |
if (urls.hasOwnProperty(item.url)) { | |
key = item.url; | |
} | |
if (urls.hasOwnProperty(item.url + "/")) { | |
key = item.url + "/"; | |
} | |
if (key) { | |
// Bookmark already exists in folder | |
if (urls[key].title != item.title) { | |
// Title needs an update | |
clog('Title updated: "' + urls[key].title + '" to "' + item.title + '"'); | |
chrome.bookmarks.update(urls[key].id, {title: item.title}); | |
} | |
} else { | |
// Bookmark needs to be created | |
chrome.bookmarks.create({ | |
parentId: folder.id, | |
title: item.title, | |
url: item.url | |
}, function (bookmarkItem) { | |
clog("Created Item: " + bookmarkItem.title + " on " + bookmarkItem.url); | |
}); | |
} | |
} | |
} | |
}); | |
} | |
}); | |
} else { | |
console.info("Response is empty - there are no bookmarks?"); | |
} | |
}; | |
chrome.bookmarks.onCreated.addListener(function (id, node) { | |
chrome.bookmarks.get(node.parentId, function (parent) { | |
if (parent !== false) { | |
chrome.bookmarks.get(parent[0].parentId, function (grandparent) { | |
/** @namespace grandparent.title */ | |
if (grandparent[0] !== false && grandparent[0].title == "Tags") { | |
// Bookmark was created in proper location, send to Diigo | |
doRequest(node, parent[0].title); | |
} | |
}); | |
} | |
}); | |
}); | |
chrome.bookmarks.onRemoved.addListener(function (id, removeInfo) { | |
// To be added when API supports it | |
}); | |
chrome.bookmarks.onChanged.addListener(function (id, changeInfo) { | |
// To be added when API supports it | |
}); | |
doRequest(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment