osc-edge-extension/js/oschina.js

504 lines
18 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let Utils = {
object: {
isNull(obj) {
return typeof obj === "undefined" || obj === null;
},
isNotNull(obj) {
return !this.isNull(obj);
}
},
chromePlugin: {
placeholderReg: '\\${([^{}]+)}',
storagePrefix: {
'_': '',
'config': 'config_'
},
handleStorageKeyPrefix({ key, prefix = '_' } = {}) {
let text = '';
if (this.storagePrefix[prefix]) {
text += this.storagePrefix['_'];
if (prefix !== '_') {
text += this.storagePrefix[prefix];
}
}
return text + key
},
handleStorageKeysPrefix({ keys, prefix } = {}) {
if (!this.storagePrefix[prefix]) return keys;
if (typeof keys === "string") {
keys = [keys];
}
if (keys instanceof Array) {
for (let i = 0, len = keys.length; i < len; i++) {
keys[i] = this.handleStorageKeyPrefix({ key: keys[i], prefix });
}
} else {
keys = null;
}
return keys;
},
async storageGet({ keys, prefix = null } = {}) {
return new Promise((resolve, reject) => {
const isOne = typeof keys === "string";
try {
keys = this.handleStorageKeysPrefix({ keys, prefix });
chrome.storage.local.get(keys, (json) => {
if (!json) {
resolve(json)
return
}
if (isOne && keys) {
resolve(json[keys[0]])
} else {
const prefixStr = this.handleStorageKeyPrefix({ key: '', prefix });
const newJson = {};
for (const jk in json) {
if (!json.hasOwnProperty(jk)) continue;
if (!jk.startsWith(prefixStr)) continue;
newJson[jk.replace(prefixStr, '')] = json[jk];
}
resolve(newJson)
}
})
} catch (e) {
reject(e);
}
})
},
async storageSet({ map, prefix = null } = {}) {
return new Promise((resolve, reject) => {
try {
if (this.storagePrefix[prefix]) {
const newMap = {};
for (let key in map) {
if (!map.hasOwnProperty(key)) continue;
newMap[this.handleStorageKeyPrefix({ key, prefix })] = map[key];
}
map = newMap;
}
chrome.storage.local.set(map, () => {
resolve();
})
} catch (e) {
reject(e);
}
})
},
async storageRemove({ keys, prefix = null } = {}) {
return new Promise((resolve, reject) => {
try {
keys = this.handleStorageKeysPrefix({ keys, prefix });
chrome.storage.local.remove(keys, () => {
resolve();
})
} catch (e) {
reject(e);
}
})
}
}
};
function getRssData(rssLink, divId) {
var xhr = new XMLHttpRequest();
setLoadingLabel(divId);
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) {
return;
}
var responseXML = xhr.responseXML;
if (!responseXML) {
try {
responseXML = (new DOMParser()).parseFromString(xhr.responseText.replace(/[\x00-\x1F]/g, ' '), 'text/xml');
} catch (e) {
console.log('error->', error);
setErrorLabel(divId, 'text转换xml出错');
}
}
if (responseXML) {
getAllSubBookmark().then((allSubBookmark) => {
var xmlDoc = responseXML;
var fullCountSet = xmlDoc.evaluate("//channel/item", xmlDoc, createNSResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
try {
var fullCountNode = fullCountSet.iterateNext();
var divContent = '';
while (fullCountNode) {
divContent += constructListDiv(constructRssItem(fullCountNode), allSubBookmark);
fullCountNode = fullCountSet.iterateNext();
}
if (divContent) {
document.getElementById(divId).innerHTML = divContent;
}
} catch (error) {
console.log('error->', error);
setErrorLabel(divId, '数据解析错误');
} //end of try-catch
});
} //end of if(xhr.responseXML)
};
xhr.onerror = function (error) {
console.error('error->', error);
setErrorLabel(divId, '网络错误');
};
xhr.open("GET", rssLink, true);
xhr.send(null);
} //end of function getRssData()
function constructRssItem(xmlNode) {
var title = xmlNode.getElementsByTagName("title")[0].firstChild.nodeValue;
var description = xmlNode.getElementsByTagName("description")[0].firstChild.nodeValue;
var link = xmlNode.getElementsByTagName("link")[0].firstChild.nodeValue;
var pubDate = xmlNode.getElementsByTagName("pubDate")[0].firstChild.nodeValue;
var guid = xmlNode.getElementsByTagName("guid")[0].firstChild.nodeValue;
return new RssItem(title, description, link, pubDate, guid);
}
function constructListDiv(item, bookmarks = []) {
const bookmark = bookmarks.find(b => item.link === b.url);
return `
<div class="item"><a target="_blank" href="${item.link +
'?' +
UTM_SOURCE_STR}">\
<div class="title">${stripHtml(item.title)}</div></a>\
<div is-icon-heart ${bookmark
? `class="icon-heart-fill collected" data-bookmark-id="${bookmark.id}"`
: 'class="icon-heart-fill"'
}\
data-title="${stripHtml(item.title)}" data-link="${item.link}"></div>\
<div class="description">${stripHtml(item.description)}</div>\
<div class="pubDate">${item.pubDate}</div></div>`;
}
function RssItem(title, description, link, pubDate, guid) {
this.title = title;
this.description = description;
this.link = link;
this.pubDate = new Intl.DateTimeFormat('zh-CN').format(Date.parse(pubDate));
this.guid = guid;
}
function createNSResolver(xmlDoc) {
return xmlDoc.createNSResolver(xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement);
}
function setLoadingLabel(divId) {
document.getElementById(divId).innerHTML = '<p style="text-align:center;font-size:20px">Loading ... </p>';
}
function setErrorLabel(divId, error) {
document.getElementById(divId).innerHTML = '<p style="color:red;text-align:center;font-size:22px">Error (' + error + ') </p>';
}
// 创建书签到书签栏最前端,不传 url 即为创建文件夹
function createBookmark(title = OSC_BOOKMARKS_NAME, parentId = '1', url = '') {
return new Promise(function (resolve) {
let prams = {
parentId: parentId,
index: 0,
title: title
};
if (url) {
prams.url = url;
}
chrome.bookmarks.create(prams, (bookmarkData) => {
resolve(bookmarkData);
});
});
}
// 查找书签文件夹 ,并返回文件夹信息,如果已创建则直接返回文件夹信息
function searchBookmarksFolder() {
return new Promise(function (resolve) {
// 查找名含 OSC_BOOKMARKS_NAME 的书签
chrome.bookmarks.search(OSC_BOOKMARKS_NAME, (searchResult) => {
const isIncludeBookmark = Array.isArray(searchResult) && searchResult.length > 0;
if (isIncludeBookmark) {
// 存在名为 OSC_BOOKMARKS_NAME 的书签文件夹: title相同 且 不存在url属性
let index = searchResult.findIndex((item) => item.title === OSC_BOOKMARKS_NAME && !item.url)
if (index > -1) {
resolve(searchResult[index])
} else {
createBookmark().then((bookmarkData) => {
resolve(bookmarkData);
})
}
} else {
// 不存在任何包含 OSC_BOOKMARKS_NAME 的书签或文件夹
createBookmark().then((bookmarkData) => {
resolve(bookmarkData);
})
} //end of if-else
}); //end of Promise()
}); //end of function searchBookmarksFolder
}
let allSubBookmark = [];
function getAllSubBookmark({ title = OSC_BOOKMARKS_NAME, cache = false } = {}) {
return new Promise((resolve) => {
if (cache && allSubBookmark && allSubBookmark.length > 0) {
resolve(allSubBookmark);
}
chrome.bookmarks.search(title, async (searchResult) => {
if (!searchResult) {
resolve([]);
}
const bookmarks = [];
const dirs = searchResult.filter((item) => item.title === title && !item.url);
for (let i = 0, len = dirs.length; i < len; i++) {
const dir = dirs[i];
await new Promise(resolveSubTree => chrome.bookmarks.getSubTree(dir.id, async (subTree) => {
if (!subTree) {
resolveSubTree();
}
const HandleTree = (items) => {
items.forEach(item => {
if (item.children) {
HandleTree(item.children)
} else {
if (!item.url) return;
bookmarks.push({ ...item })
}
})
}
HandleTree(subTree);
resolveSubTree();
}))
}
allSubBookmark = bookmarks;
resolve(bookmarks)
});
});
}
/**
* 获取开源资讯数据
* @param selectedValue
*/
function getRssNewsRssData(selectedValue = 'all') {
Utils.chromePlugin.storageSet({ map: { 'rssNewsSelected': selectedValue }, prefix: 'config' })
handleSelect('news-selector', selectedValue);
setLoadingLabel('news-list');
if (selectedValue === 'all') {
getRssData(RSS_NEWS, 'news-list');
} else {
getRssData(RSS_NEWS_PREFIX + selectedValue, 'news-list');
}
}
/**
* 获取推荐博客数据
* @param selectedValue
*/
function getBlogsListRssData(selectedValue = 'all') {
Utils.chromePlugin.storageSet({ map: { 'blogsListSelected': selectedValue }, prefix: 'config' })
handleSelect('blogs-selector', selectedValue);
setLoadingLabel('blogs-list');
if (selectedValue === 'all') {
getRssData(RSS_RECOMM_BLOGS, 'blogs-list');
} else {
getRssData(RSS_RECOMM_BLOGS_CATEGORY_PREFIX + selectedValue, 'blogs-list');
}
}
/**
* 获取开源软件数据
* @param selectedValue
*/
function getProjectsListRssData(selectedValue = 'all') {
Utils.chromePlugin.storageSet({ map: { 'projectsListSelected': selectedValue }, prefix: 'config' })
handleSelect('projects-selector', selectedValue);
setLoadingLabel('projects-list');
if (selectedValue === 'recomm') {
getRssData(RSS_RECOMM_PROJECTS, 'projects-list');
} else {
getRssData(RSS_PROJECTS, 'projects-list');
}
}
/**
* 获取最新问答数据
* @param selectedValue
*/
function getQuestionsListRssData(selectedValue = '1') {
Utils.chromePlugin.storageSet({ map: { 'questionsListSelected': selectedValue }, prefix: 'config' })
handleSelect('questions-selector', selectedValue);
setLoadingLabel('questions-list');
getRssData(RSS_QUESTIONS_PREFIX + selectedValue, 'questions-list');
}
/**
* 获取专区文章数据
* @param selectedValue
*/
function getCircleArticlesListRssData(selectedValue = 'cross-front') {
Utils.chromePlugin.storageSet({ map: { 'circleArticlesListSelected': selectedValue }, prefix: 'config' })
handleSelect('circle-selector', selectedValue);
setLoadingLabel('blogs-list');
if (selectedValue === 'cross-front') {
getRssData(RSS_CIRCLE_ARTICLES_PREFIX + 'cross-front', 'blogs-list');
} else {
getRssData(RSS_CIRCLE_ARTICLES_PREFIX + selectedValue, 'blogs-list');
}
}
function handleSelect(selectId, val) {
const ele = document.getElementById(selectId);
if (ele.value === val) {
return;
}
ele.value = val;
}
////////////////// 页面上的各类时间点击 ///////////////////////
Utils.chromePlugin.storagePrefix._ = '_ydA2ge_';
getAllSubBookmark();
document.addEventListener('DOMContentLoaded', async function () {
const config = await Utils.chromePlugin.storageGet({
prefix: 'config'
}) || {};
// DOM内容加载完成之后开始获取数据并展示
getRssNewsRssData(config.rssNewsSelected); //最新资讯
getQuestionsListRssData(config.questionsListSelected); //最新发布问答
//getBlogsListRssData(config.blogsListSelected); //最新推荐博客
getCircleArticlesListRssData(config.circleArticlesListSelected);//专区文章列表
getProjectsListRssData(config.projectsListSelected); //最新收录开源软件
// //下载源码按钮点击事件
document.getElementById('btn-download').onclick = function () {
chrome.tabs.create({
'url': GITEE_REPO_URL
});
};
//搜索按钮点击事件
document.getElementById('btn-search').onclick = function () {
var txtSearch = document.getElementById('txt-search').value;
if (txtSearch) {
var query = encodeURIComponent(txtSearch);
chrome.tabs.create({
'url': OSC_SEARCH_PREFIX + query + '&' + UTM_SOURCE_STR
});
} //end of if
};
//搜索输入框中的回车事件
document.getElementById('txt-search').onkeydown = function (event) {
if (event.keyCode == 13) {
document.getElementById('btn-search').click();
}
};
//标题「开源资讯」的点击事件
document.getElementById('news-title').onclick = function (event) {
var selectedValue = document.getElementById('news-selector').value;
if (selectedValue) {
getRssNewsRssData(selectedValue);
}
};
//标题「推荐博客」的点击事件
document.getElementById('blogs-title').onclick = function (event) {
var selectedValue = document.getElementById('circle-selector').value;
if (selectedValue) {
getCircleArticlesListRssData(selectedValue);//专区文章列表
}
};
//标题「开源软件」的点击事件
document.getElementById('projects-title').onclick = function (event) {
var selectedValue = document.getElementById('projects-selector').value;
if (selectedValue) {
getProjectsListRssData(selectedValue);
}
};
//标题「最新问答」的点击事件
document.getElementById('questions-title').onclick = function (event) {
var selectedValue = document.getElementById('questions-selector').value;
if (selectedValue) {
getQuestionsListRssData(selectedValue);
}
};
//资讯:下拉框的变化事件
document.getElementById('news-selector').onchange = function (event) {
document.getElementById('news-title').click();
};
//专区文章:下拉框的变化事件
document.getElementById('circle-selector').onchange = function (event) {
document.getElementById('blogs-title').click();
};
//问答:下拉框的变化事件
document.getElementById('questions-selector').onchange = function (event) {
document.getElementById('questions-title').click();
};
//软件:下拉框的变化事件
document.getElementById('projects-selector').onchange = function (event) {
document.getElementById('projects-title').click();
};
// 收藏:心形图标点击事件
// 各个list列表容器。数据未加载 ,dom未生成,不能绑定在.heart元素上
const arrListContainer = [
...document.querySelectorAll(
'#news-list,#blogs-list,#projects-list,#questions-list'
)
];
for (let oItem of arrListContainer) {
oItem.addEventListener('click', async event => {
const ele = event.target;
let targetDataset = ele.dataset;
const isIconHeart = ele.hasAttribute('is-icon-heart');
// 判断事件是否在 icon-heart上触发
if (!isIconHeart) {
return false;
}
if (targetDataset.bookmarkId) {
chrome.bookmarks.remove(
targetDataset.bookmarkId,
async bookmarkData => {
console.log(bookmarkData);
await getAllSubBookmark();
ele.removeAttribute('data-bookmark-id');
ele.className = ele.className.replace(' collected', '');
}
);
return;
}
const bookmarkFolder = await searchBookmarksFolder();
// 创建书签 不带http或https 会抛出错误,添加http://
if (
targetDataset.link &&
!/^http:\/\//.test(targetDataset.link) &&
!/^https:\/\//.test(targetDataset.link)
) {
targetDataset.link = 'http://' + targetDataset.link;
}
const bookmarkData = await createBookmark(
targetDataset.title || '无标题',
bookmarkFolder.id,
targetDataset.link
);
await getAllSubBookmark();
ele.setAttribute('data-bookmark-id', bookmarkData.id);
ele.className = ele.className + ' collected';
});
}
});