You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
10 KiB

let api = {};
let serverApi = {};
// chrome bookmark api wrapper
(function (api) {
/**
* 获得整个书签树
*/
const getTree = () => {
return new Promise((resolve) => {
chrome.bookmarks.getTree(resolve);
});
};
const getTreeAsync = async () => {
return await getTree();
};
/**
* 获得特定父书签组下的所有子书签和子书签组
* 返回的书签数组中是不包含children字段的即不包含子节点以下的节点
* @param {String} id 父书签组id
*/
const getChildren = (id) => {
return new Promise((resolve) => {
chrome.bookmarks.getChildren(id, resolve);
});
};
const getChildrenAsync = async (id) => {
return await getChildren(id);
};
/**
* 获得特定书签组下的所有书签
* 返回的书签数组中包含children字段即包含子节点以下的节点
* @param {String} id 父书签组id
*/
const getSubTree = (id) => {
return new Promise((resolve) => {
chrome.bookmarks.getSubTree(id, resolve);
});
};
const getSubTreeAsync = async (id) => {
return await getSubTree(id);
};
/**
* 删除指定id的书签
* @param {String} id 需要删除的书签的id
*/
const remove = (id) => {
return new Promise((resolve) => {
chrome.bookmarks.remove(id, resolve);
});
};
const removeAsync = async (id) => {
return await remove(id);
};
/**
* 删除指定id的空书签组如果书签组下有子书签或子书签组删除将失败
* @param {String} id 需要删除的书签文件夹id
*/
const removeTree = (id) => {
return new Promise((resolve) => {
chrome.bookmarks.removeTree(id, resolve);
});
};
const removeTreeAsync = async (id) => {
await removeTree(id);
};
/**
* 创建一个书签
* @param {Object} bookmark
* string (optional) parentId 父书签组如果不填则默认在**其他书签**一栏中
* integer (optional) index
* string (optional) title
* string (optional) url 如果为NULL或者不填则代表一个书签组文件夹
*/
const create = (bookmark) => {
return new Promise((resolve) => {
chrome.bookmarks.create(bookmark, resolve);
});
};
const createAsync = async (bookmark) => {
return await create(bookmark);
};
api.getTreeAsync = getTreeAsync;
api.getSubTreeAsync = getSubTreeAsync;
api.getChildrenAsync = getChildrenAsync;
api.removeAsync = removeAsync;
api.removeTreeAsync = removeTreeAsync;
api.createAsync = createAsync;
})(api);
// backend server api wrapper
(function (api) {
const API_VERSION = "v1";
let serverAddress = "";
const setServerAddress = (address) => {
serverAddress = address;
};
const getServerAddress = () => {
return serverAddress;
};
const getVersion = () => {
return new Promise((resolve, reject) => {
$.getJSON(`${serverAddress}/${API_VERSION}/version`, (response) => {
const { code, message, data } = response;
if (code === 20000) {
resolve(data);
} else {
reject(new Error(message));
}
});
});
};
const uploadBookmarks = data => {
return new Promise((resolve, reject) => {
$.post(`${serverAddress}/${API_VERSION}/bookmark`, data, (response) => {
const { code, message, data } = response;
if (code === 20000) {
resolve(data);
} else {
reject(new Error(message));
}
}, 'json');
});
};
const downloadBookmarks = () => {
return new Promise((resolve, reject) => {
$.getJSON(`${serverAddress}/${API_VERSION}/bookmark`, (response) => {
const { code, message, data } = response;
if (code === 20000) {
resolve(data);
} else {
reject(new Error(message));
}
});
});
};
api.setServerAddress = setServerAddress;
api.getServerAddress = getServerAddress;
api.getVersion = getVersion;
api.uploadBookmarks = uploadBookmarks;
api.downloadBookmarks = downloadBookmarks;
})(serverApi);
function Node() {
/**
* id ( string )
* 节点的唯一标识, id 在当前配置文件中是唯一的浏览器重启后依然有效
*/
this.id = "0";
/**
* 父节点的ID根节点没有此属性
*/
this.parentId = undefined;
/**
* 书签节点创建时的时间戳
*/
this.dateAdded = undefined;
/**
* 书签文件夹内容的最后更新时间戳书签节点没有此属性
*/
this.dateGroupModified = undefined;
/**
* 书签在父节点中的索引根节点没有此属性
*/
this.index = 0;
/**
* 书签标题
*/
this.title = "";
/**
* 书签的url书签文件夹没有此属性
*/
this.url = undefined;
/**
* 节点类型
* 0 为书签
* 1 为书签文件夹
*/
this.type = 0;
/**
* 是否为根节点
*/
this.root = false;
/**
* 子节点数组
*/
this.children = undefined;
}
let BookmarkTreeNodeList = [];
const BOOKMARK = 0;
const BOOKEMARK_FOLDER = 1;
const PROTO = "http";
const SERVER_ADDRESS = "192.168.31.161";
const SERVER_PORT = "3000";
const SERVER_URL = `${PROTO}://${SERVER_ADDRESS}:${SERVER_PORT}`;
/**
* 获得浏览器书签的map表
* 表的key值表示书签深度根目录深度为0
*/
async function getBookmarkMap() {
let localTree = await api.getTreeAsync();
let localMap = {};
async function addToMap(localTree, depth) {
for (let i = 0; i < localTree.length; i++) {
let node = localTree[i];
let bookmarkNode = new Node();
bookmarkNode.id = node.id;
bookmarkNode.parentId = node.parentId;
bookmarkNode.index = node.index;
bookmarkNode.title = node.title;
bookmarkNode.url = node.url;
bookmarkNode.type =
typeof node.dateGroupModified === "undefined"
? BOOKMARK
: BOOKEMARK_FOLDER;
bookmarkNode.root = typeof node.parentId === "undefined";
// 根节点没有 dateGroupModified 属性,但是应该是个书签组类型
if (bookmarkNode.root) {
bookmarkNode.type = BOOKEMARK_FOLDER;
}
if (!Array.isArray(localMap[depth])) {
localMap[depth] = [];
}
localMap[depth].push(bookmarkNode);
if (
bookmarkNode.type === BOOKEMARK_FOLDER &&
Array.isArray(node.children) &&
node.children.length > 0
) {
for (let j = 0; j < node.children.length; j++) {
let childNode = node.children[j];
let childTree = await api.getSubTreeAsync(childNode.id);
await addToMap(childTree, depth + 1);
}
}
}
}
await addToMap(localTree, 0);
return localMap;
}
function tree2List(tree) {
let cacheMap = {};
function add2Map(tree) {
for (let item of tree) {
// 给书签文件创建group属性
if (item.id === "0" || item.id === "1" || item.id === "2" || typeof item.dateGroupModified === 'number') {
item.group = true
}
cacheMap[item.id] = item;
if (Array.isArray(item.children)) {
add2Map(item.children);
}
}
}
add2Map(tree);
for (let key in cacheMap) {
let item = cacheMap[key];
if (typeof item.parentId === "string") {
if (!Array.isArray(cacheMap[item.parentId].nodes)) {
cacheMap[item.parentId].nodes = [];
}
cacheMap[item.parentId].nodes.push(item.id);
}
}
let list = [];
for (let key in cacheMap) {
const item = cacheMap[key];
list.push({
id: item.id,
parentId: item.parentId,
title: item.title,
url: item.url,
index: item.index,
group: item.group,
nodes: item.nodes,
});
}
return list;
}
/**
* 获得浏览器书签的数组
*/
async function getBookmarkList() {
let localTree = await api.getTreeAsync();
return tree2List(localTree);
}
/**
* 数组转map表
* @param {Object} bookmarkList
*/
function listToMap(bookmarkList) {
let map = {};
for (let i = 0; i < bookmarkList.length; i++) {
let bookmark = bookmarkList[i];
map[bookmark.id] = bookmark;
}
function getDepth(bookmark, depth) {
if (parseInt(bookmark.id) === 0) {
return depth;
} else {
return getDepth(map[bookmark.parentId], depth + 1);
}
}
let finalMap = {};
for (let i = 0; i < bookmarkList.length; i++) {
let bookmark = bookmarkList[i];
let finalDepth = getDepth(bookmark, 0);
if (!Array.isArray(finalMap[finalDepth])) {
finalMap[finalDepth] = [];
}
finalMap[finalDepth].push(bookmark);
}
return finalMap;
}
async function removeAllBookmarks() {
let localTree = await api.getTreeAsync();
}
async function restore(remoteBookmarkArray) {
function getNewbookmarkId(array, parentId) {
for (let i = 0; i < array.length; i++) {
if (array[i].id === parentId) {
return array[i].newId;
}
}
}
let array = listToMap(remoteBookmarkArray);
for (let depth in array) {
const bookmarks = array[depth];
for (let i = 0; i < bookmarks.length; i++) {
const bookmark = bookmarks[i];
if (
bookmark.root ||
bookmark.id === "0" ||
bookmark.id === "1" ||
bookmark.id === "2"
) {
bookmark.newId = bookmark.id;
continue;
}
try {
const newBookmark = await api.createAsync({
parentId: getNewbookmarkId(array[depth - 1], bookmark.parentId),
index: bookmark.index,
title: bookmark.title,
url: bookmark.url,
});
bookmark.newId = newBookmark.id;
console.log(
`restroe ${bookmark.title}:${bookmark.id} to ${newBookmark.title}:${newBookmark.id}`
);
} catch (error) {
console.error(error);
}
}
}
}
$("#upload").on("click", async () => {
let bookmarkArray = await getBookmarkList();
console.log(bookmarkArray)
serverApi.uploadBookmarks({
bookmarks: bookmarkArray
});
});
$("#download").on("click", async () => {
const bookmarkArray = await serverApi.downloadBookmarks();
console.log(bookmarkArray);
});
$("#test").on("click", async () => {
let array = await getBookmarkList();
console.log(array);
});
$("#connect").on("click", async () => {
const serverAddress = $("#server").val() || SERVER_URL;
serverApi.setServerAddress(serverAddress);
const version = await serverApi.getVersion();
$("#version").html(version);
});