feat:浏览器插件新增书签功能实现

This commit is contained in:
fanxb 2022-04-15 15:45:19 +08:00
parent 50e1e0e951
commit d44700a971
18 changed files with 369 additions and 353 deletions

View File

@ -36,12 +36,14 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
@ -324,7 +326,6 @@ public class BookmarkServiceImpl implements BookmarkService {
*
* @param url url
* @return {@link String}
* @throws
* @author fanxb
*/
private String getIconPath(String url) {
@ -343,10 +344,7 @@ public class BookmarkServiceImpl implements BookmarkService {
if (iconPath != null) {
return iconPath;
}
iconPath = saveFile(host, "http://" + host + "/favicon.ico");
if (StrUtil.isEmpty(iconPath)) {
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..64..256");
}
if (StrUtil.isNotEmpty(iconPath)) {
hostIconDao.insert(host, iconPath);
}
@ -366,9 +364,9 @@ public class BookmarkServiceImpl implements BookmarkService {
if (data.length > 0) {
String iconUrl = res.request().url().toString();
String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf("."));
String filePath = Paths.get(CommonConstant.fileSavePath, FileConstant.FAVICON_PATH, host.substring(0, 2), fileName).toString();
FileUtil.writeBytes(data, filePath);
return filePath;
String filePath = Paths.get(FileConstant.FAVICON_PATH, host.substring(0, 2), fileName).toString();
FileUtil.writeBytes(data, Paths.get(CommonConstant.fileSavePath, filePath).toString());
return File.separator + filePath;
} else {
log.info("未获取到icon:{}", url);
}

View File

@ -3,6 +3,7 @@ node_modules
/dist
package-lock.json
yarn.lock
public/files
# local env files
.env.local

Binary file not shown.

View File

@ -17,7 +17,7 @@ body {
margin: 0;
padding: 0;
font-size: 100px;
// background-color: @bgColor;
background-color: @bgColor;
height: initial;
}
#app {

View File

@ -30,6 +30,10 @@ export const clear = "clear";
* 删除书签数据
*/
export const deleteData = "deleteData";
/**
* 新增节点
*/
export const addNode = "addNode";
/**
* 版本检查定时调度
@ -72,9 +76,7 @@ const getters = {
};
const actions = {
async [noLoginInit] () {
},
async [noLoginInit]() {},
async [loginInit](context) {
if (context.state.isInit || context.state.isIniting) {
return;
@ -213,9 +215,8 @@ const actions = {
let list = await HttpUtil.get("/home/pin");
commit(HOME_PIN_LIST, list);
let map = {};
list.filter(item => item.id).forEach(item => map[item.bookmarkId] = true);
list.filter(item => item.id).forEach(item => (map[item.bookmarkId] = true));
commit(HOME_PIN_BOOKMARK_ID_MAP, map);
},
/**
* 更新版本数据
@ -227,7 +228,7 @@ const actions = {
/**
* 新增书签文件夹
*/
async addNode (context, { sourceNode, targetNode }) {
async [addNode](context, { sourceNode, targetNode }) {
if (sourceNode === null) {
if (context.state[TOTAL_TREE_DATA][""] === undefined) {
context.state[TOTAL_TREE_DATA][""] = [];
@ -314,7 +315,6 @@ const mutations = {
}
};
/**
* 检查书签缓存是否最新
*
@ -338,7 +338,7 @@ async function treeDataCheck (context, isFirst) {
maskClosable: false,
onOk() {
toastShow = false;
return new Promise(async (resolve) => {
return new Promise(async resolve => {
await context.dispatch(refresh);
resolve();
});
@ -361,4 +361,3 @@ export const store = {
actions,
mutations
};

View File

@ -77,7 +77,7 @@
<a-menu-item v-if="!rec.dataRef.isLeaf" key="add">新增</a-menu-item>
<a-menu-item v-else key="copy" class="copy-to-board" :data="rec.dataRef.url">复制URL</a-menu-item>
<a-menu-item v-if="rec.dataRef.isLeaf" key="pin">
{{ homePinList.filter((item) => item.id && item.bookmarkId == rec.dataRef.bookmarkId).length > 0 ? "从首页移除" : "固定到首页" }}
{{ homePinList.filter(item => item.id && item.bookmarkId == rec.dataRef.bookmarkId).length > 0 ? "从首页移除" : "固定到首页" }}
</a-menu-item>
<a-menu-item key="edit">编辑</a-menu-item>
<a-menu-item key="delete">删除</a-menu-item>
@ -114,7 +114,7 @@ export default {
loadedKeys: [], //
replaceFields: {
title: "name",
key: "bookmarkId",
key: "bookmarkId"
},
mulSelect: false, //
currentSelect: null, //
@ -126,19 +126,19 @@ export default {
// null
targetNode: null,
//
isAdd: false,
isAdd: false
},
copyBoard: null, //
copyBoard: null //
};
},
computed: {
...mapState("treeData", ["totalTreeData", HOME_PIN_LIST]),
...mapState("globalConfig", ["isPhone"]),
...mapState("globalConfig", ["isPhone"])
},
watch: {
totalTreeData(newVal, oldVal) {
this.resetData();
},
}
},
async mounted() {
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, true);
@ -149,12 +149,19 @@ export default {
this.copyBoard = new ClipboardJS(".copy-to-board", {
text: function(trigger) {
return trigger.attributes.data.nodeValue;
},
}
});
this.copyBoard.on("success", (e) => {
this.copyBoard.on("success", e => {
this.$message.success("复制成功");
e.clearSelection();
});
window.onblur = e => {
console.log("窗口非激活");
};
window.onfocus = e => {
console.log("窗口激活");
};
},
beforeDestroy() {
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, false);
@ -168,7 +175,7 @@ export default {
*/
loadData(treeNode) {
console.log("加载数据", treeNode);
return new Promise((resolve) => {
return new Promise(resolve => {
const data = typeof treeNode === "number" ? this.$store.getters["treeData/getById"](treeNode) : treeNode.dataRef;
let newPath = data.path + "." + data.bookmarkId;
if (!this.totalTreeData[newPath]) {
@ -212,9 +219,9 @@ export default {
this.expandedKeys = [
...item.path
.split(".")
.filter((item) => item.length > 0)
.map((item) => parseInt(item)),
item.bookmarkId,
.filter(item => item.length > 0)
.map(item => parseInt(item)),
item.bookmarkId
];
} else {
this.expandedKeys.pop();
@ -228,7 +235,7 @@ export default {
} else {
this.checkedKeys.splice(this.checkedKeys.indexOf(item.bookmarkId), 1);
this.checkedNodes.splice(
this.checkedNodes.findIndex((item1) => item1.bookmarkId === item.bookmarkId),
this.checkedNodes.findIndex(item1 => item1.bookmarkId === item.bookmarkId),
1
);
}
@ -248,9 +255,9 @@ export default {
this.expandedKeys = [
...item.path
.split(".")
.filter((item) => item.length > 0)
.map((item) => parseInt(item)),
item.bookmarkId,
.filter(item => item.length > 0)
.map(item => parseInt(item)),
item.bookmarkId
];
}
} else {
@ -273,7 +280,7 @@ export default {
const bookmarkIdList = [];
const pathList = [];
if (this.checkedNodes) {
this.checkedNodes.forEach((item) =>
this.checkedNodes.forEach(item =>
item.type === 1 ? pathList.push(item.path + "." + item.bookmarkId) : bookmarkIdList.push(item.bookmarkId)
);
}
@ -290,7 +297,7 @@ export default {
await HttpUtil.post("/bookmark/batchDelete", null, { pathList, bookmarkIdList });
await this.$store.dispatch(TREE_DATA + "/" + deleteData, { pathList, bookmarkIdList });
//
pathList.forEach((item) => {
pathList.forEach(item => {
const id = parseInt(item.split(".").reverse()[0]);
let index = this.loadedKeys.indexOf(id);
if (index > -1) {
@ -322,13 +329,13 @@ export default {
this.refresh(false);
this.expandedKeys = item.path
.split(".")
.filter((one) => one.length > 0)
.map((one) => parseInt(one));
.filter(one => one.length > 0)
.map(one => parseInt(one));
this.loadedKeys = item.path
.split(".")
.filter((one) => one.length > 0)
.map((one) => parseInt(one));
this.expandedKeys.forEach(async (one) => await this.loadData(one));
.filter(one => one.length > 0)
.map(one => parseInt(one));
this.expandedKeys.forEach(async one => await this.loadData(one));
this.currentSelect = item;
},
/**
@ -344,7 +351,7 @@ export default {
this.addModal = {
show: false,
targetNode: null,
isAdd: false,
isAdd: false
};
},
async onDrop(info) {
@ -388,12 +395,12 @@ export default {
await this.deleteBookmarks();
resolve();
});
},
}
});
} else if (key === "edit") {
this.editData();
} else if (key === "pin") {
let pin = this.homePinList.filter((one) => one.id && one.bookmarkId == item.bookmarkId);
let pin = this.homePinList.filter(one => one.id && one.bookmarkId == item.bookmarkId);
if (pin.length > 0) {
await HttpUtil.delete("/home/pin", { id: pin[0].id });
} else {
@ -411,8 +418,8 @@ export default {
dealList(root, map[""], map);
let content = exportFileHead + root.outerHTML;
downloadFile(moment().format("YYYY-MM-DD") + "导出书签.html", content);
},
},
}
}
};
</script>

View File

@ -1,17 +1,17 @@
<template>
<div class="ssoAddBookmark">
正在添加请稍后
<button @click="closeIframe">关闭</button>
<!-- <button @click="closeIframe">关闭</button> -->
</div>
</template>
<script>
import HttpUtil from "@/util/HttpUtil";
import { TREE_DATA, addNode } from "@/store/modules/treeData";
export default {
data() {
return {
form: {
icon: null,
name: null,
url: null,
type: 0,
@ -20,6 +20,7 @@ export default {
};
},
mounted() {
//
window.addEventListener("message", event => {
if (!event.data.code) {
return;
@ -27,7 +28,6 @@ export default {
console.log("收到content消息", event);
if (event.data.code == "addBookmarkAction") {
console.log("新增书签");
this.form.icon = event.data.data.icon ? event.data.data.icon : null;
this.form.name = event.data.data.name;
this.form.url = event.data.data.url;
this.addBookmark();
@ -44,7 +44,8 @@ export default {
async addBookmark() {
let res = await HttpUtil.put("/bookmark", null, this.form);
this.$message.success("添加成功");
// setTimeout(this.closeIframe, 2000);
await this.$store.dispatch(TREE_DATA + "/" + addNode, { sourceNode: null, targetNode: res });
setTimeout(this.closeIframe, 500);
}
}
};
@ -55,5 +56,8 @@ export default {
display: flex;
justify-content: center;
align-items: center;
background: white;
width: 100%;
height: 100vh;
}
</style>

View File

@ -9,6 +9,11 @@
使用教程
<a href="https://blog.fleyx.com/blog/detail/20220329" target="_blank">点击跳转</a>
</div>
<div>
浏览器插件
<a href="/static/bookmarkBrowserPlugin.7z" download="浏览器插件.7z" target="_blank">点击下载</a>
,使用详情请参考使用教程
</div>
<div>交流反馈qq群150056494,邮箱fleyx20@outlook.com</div>
<div>
统计
@ -38,7 +43,7 @@ export default {
script.defer = true;
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
document.getElementsByTagName("head")[0].appendChild(script);
},
}
};
</script>

View File

@ -15,7 +15,6 @@ chrome.contextMenus.onClicked.addListener(async function (info, tab) {
let body = {
name: tab.title,
url: tab.url,
iconUrl: tab.favIconUrl
};
sendToContent(tab.id, { code: "addBookmark", data: body, token: await getVal("token") });
});

View File

@ -1,6 +1,6 @@
{
"name": "bookmark-chrome",
"description": "A Vue.js web extension",
"name": "签签世界",
"description": "云书签管理平台",
"version": "1.0",
"manifest_version": 3,
"permissions": ["contextMenus", "storage"],
@ -8,8 +8,8 @@
"default_popup": "popup/index.html"
},
"icons": {
"48": "static/icons/icon_48.png",
"128": "static/icons/icon_128.png"
"48": "static/icons/favicon.png",
"128": "static/icons/favicon.png"
},
"background": {
"service_worker": "background.js"

View File

@ -19,10 +19,11 @@
<a id="login" href="https://fleyx.com/userSpace/ssoAuth" target="_blank">点击登录</a>
<div id="action" style="display: none">
<button id="logout">退出登陆</button>
<button title="同步云端书签到浏览器(覆盖本地)">同步云端书签</button>
<button title="同步浏览器书签到云端(覆盖云端)">同步浏览器</button>
<!-- <button title="同步云端书签到浏览器(覆盖本地)">同步云端书签</button> -->
<!-- <button title="同步浏览器书签到云端(覆盖云端)">同步浏览器</button> -->
</div>
<p id="content"></p>
<div class="bottom">插件版本:<span id="version"></span></div>
<script type="text/javascript" src="/static/js/axios.min.js"></script>
<script type="text/javascript" src="/static/js/config.js"></script>
<script type="text/javascript" src="/popup/index.js"></script>

View File

@ -8,6 +8,7 @@ var action = document.getElementById("action");
(async () => {
//初始化
login.href = bookmarkHost + "/manage/sso/auth";
document.getElementById("version").innerText = version;
sendToBg("getToken", null);
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,6 +1,7 @@
// var bookmarkHost = "https://fleyx.com";
var bookmarkHost = "http://localhost:8080";
var bookmarkHost = "https://fleyx.com";
// var bookmarkHost = "http://localhost:8080";
var version = "0.1";
window.token = localStorage.getItem('token');
axios.defaults.baseURL = bookmarkHost + '/bookmark/api';