feat:支持浏览器新标签页
This commit is contained in:
parent
b74be9f961
commit
1087f5e48b
@ -1,8 +1,10 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.service.impl;
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64Decoder;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import cn.hutool.core.util.HashUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.fanxb.bookmark.business.api.UserApi;
|
import com.fanxb.bookmark.business.api.UserApi;
|
||||||
@ -21,6 +23,7 @@ import com.fanxb.bookmark.common.constant.RedisConstant;
|
|||||||
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import com.fanxb.bookmark.common.exception.CustomException;
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
import com.fanxb.bookmark.common.util.*;
|
import com.fanxb.bookmark.common.util.*;
|
||||||
|
import com.mysql.cj.conf.url.SingleConnectionUrl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
@ -37,6 +40,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@ -53,7 +57,6 @@ import java.util.stream.Collectors;
|
|||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 15:00
|
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -116,7 +119,6 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
* @param path 节点路径,不包含自身
|
* @param path 节点路径,不包含自身
|
||||||
* @param sort 当前层级中的排序序号
|
* @param sort 当前层级中的排序序号
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 14:49
|
|
||||||
*/
|
*/
|
||||||
private void dealBookmark(int userId, Element ele, String path, int sort, List<Bookmark> bookmarks) {
|
private void dealBookmark(int userId, Element ele, String path, int sort, List<Bookmark> bookmarks) {
|
||||||
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
||||||
@ -125,7 +127,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
Element first = ele.child(0);
|
Element first = ele.child(0);
|
||||||
if (A.equalsIgnoreCase(first.tagName())) {
|
if (A.equalsIgnoreCase(first.tagName())) {
|
||||||
//说明为链接
|
//说明为链接
|
||||||
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), first.attr("icon")
|
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), ""
|
||||||
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
||||||
//存入数据库
|
//存入数据库
|
||||||
insertOne(node);
|
insertOne(node);
|
||||||
@ -155,7 +157,6 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
* @param node node
|
* @param node node
|
||||||
* @return boolean 如果已经存在返回true,否则false
|
* @return boolean 如果已经存在返回true,否则false
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 17:25
|
|
||||||
*/
|
*/
|
||||||
private boolean insertOne(Bookmark node) {
|
private boolean insertOne(Bookmark node) {
|
||||||
//先根据name,userId,parentId获取此节点id
|
//先根据name,userId,parentId获取此节点id
|
||||||
@ -217,7 +218,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
bookmark.setUserId(userId);
|
bookmark.setUserId(userId);
|
||||||
bookmark.setCreateTime(System.currentTimeMillis());
|
bookmark.setCreateTime(System.currentTimeMillis());
|
||||||
bookmark.setAddTime(bookmark.getCreateTime());
|
bookmark.setAddTime(bookmark.getCreateTime());
|
||||||
bookmark.setIcon(getIconPath(bookmark.getUrl()));
|
bookmark.setIcon(getIconPath(bookmark.getUrl(), bookmark.getIcon(), bookmark.getIconUrl()));
|
||||||
//文件夹和书签都建立搜索key
|
//文件夹和书签都建立搜索key
|
||||||
pinYinService.changeBookmark(bookmark);
|
pinYinService.changeBookmark(bookmark);
|
||||||
bookmarkDao.insertOne(bookmark);
|
bookmarkDao.insertOne(bookmark);
|
||||||
@ -231,7 +232,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
bookmark.setUserId(userId);
|
bookmark.setUserId(userId);
|
||||||
if (bookmark.getType() == 0) {
|
if (bookmark.getType() == 0) {
|
||||||
pinYinService.changeBookmark(bookmark);
|
pinYinService.changeBookmark(bookmark);
|
||||||
bookmark.setIcon(getIconPath(bookmark.getUrl()));
|
bookmark.setIcon(getIconPath(bookmark.getUrl(), null, null));
|
||||||
}
|
}
|
||||||
bookmarkDao.editBookmark(bookmark);
|
bookmarkDao.editBookmark(bookmark);
|
||||||
userApi.versionPlus(userId);
|
userApi.versionPlus(userId);
|
||||||
@ -290,7 +291,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
while ((deal = bookmarkDao.selectUserNoIcon(userId, start, size)).size() > 0) {
|
while ((deal = bookmarkDao.selectUserNoIcon(userId, start, size)).size() > 0) {
|
||||||
start += size;
|
start += size;
|
||||||
deal.forEach(item -> {
|
deal.forEach(item -> {
|
||||||
String icon = getIconPath(item.getUrl());
|
String icon = getIconPath(item.getUrl(), null, null);
|
||||||
if (StrUtil.isNotEmpty(icon)) {
|
if (StrUtil.isNotEmpty(icon)) {
|
||||||
bookmarkDao.updateIcon(item.getBookmarkId(), icon);
|
bookmarkDao.updateIcon(item.getBookmarkId(), icon);
|
||||||
}
|
}
|
||||||
@ -322,37 +323,56 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取icon
|
* 获取icon,通过网络获取,或者从base64还原
|
||||||
*
|
*
|
||||||
* @param url url
|
* @param url url
|
||||||
|
* @param icon icon
|
||||||
|
* @param iconUrl iconUrl
|
||||||
* @return {@link String}
|
* @return {@link String}
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
*/
|
*/
|
||||||
private String getIconPath(String url) {
|
private String getIconPath(String url, String icon, String iconUrl) {
|
||||||
if (StrUtil.isEmpty(url)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String host;
|
String host;
|
||||||
try {
|
try {
|
||||||
URL urlObj = new URL(url);
|
URL urlObj = new URL(url);
|
||||||
host = urlObj.getHost();
|
host = urlObj.getAuthority();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("url无法解析出domain:{}", url);
|
log.warn("url无法解析出domain:{}", url);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
if (StrUtil.isNotBlank(icon)) {
|
||||||
|
//优先从base64还原出图片
|
||||||
|
try {
|
||||||
|
byte[] b = Base64Decoder.decode(icon.substring(icon.indexOf(",") + 1));
|
||||||
|
String iconPath = saveToFile(iconUrl, host, b);
|
||||||
|
hostIconDao.insert(host, iconPath);
|
||||||
|
return iconPath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析base64获取icon故障:{}", iconUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String iconPath = hostIconDao.selectByHost(host);
|
String iconPath = hostIconDao.selectByHost(host);
|
||||||
if (iconPath != null) {
|
if (iconPath != null) {
|
||||||
return iconPath;
|
return iconPath;
|
||||||
}
|
}
|
||||||
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..64..256");
|
//再根据url解析
|
||||||
|
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..128..256");
|
||||||
if (StrUtil.isNotEmpty(iconPath)) {
|
if (StrUtil.isNotEmpty(iconPath)) {
|
||||||
hostIconDao.insert(host, iconPath);
|
hostIconDao.insert(host, iconPath);
|
||||||
}
|
}
|
||||||
return iconPath;
|
return iconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件到icon路径
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @param url url
|
||||||
|
* @return {@link String}
|
||||||
|
* @author FleyX
|
||||||
|
*/
|
||||||
private String saveFile(String host, String url) {
|
private String saveFile(String host, String url) {
|
||||||
try {
|
|
||||||
try (Response res = HttpUtil.getClient(false).newCall(new Request.Builder().url(url)
|
try (Response res = HttpUtil.getClient(false).newCall(new Request.Builder().url(url)
|
||||||
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.36")
|
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.36")
|
||||||
.get().build()).execute()) {
|
.get().build()).execute()) {
|
||||||
@ -362,18 +382,31 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
}
|
}
|
||||||
byte[] data = res.body().byteStream().readAllBytes();
|
byte[] data = res.body().byteStream().readAllBytes();
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
String iconUrl = res.request().url().toString();
|
String iconUrl = new URL(res.request().url().toString()).getPath();
|
||||||
String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf("."));
|
return saveToFile(iconUrl, host, data);
|
||||||
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 {
|
} else {
|
||||||
log.info("未获取到icon:{}", url);
|
log.info("未获取到icon:{}", url);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("url获取icon故障:{}", url, e);
|
log.error("url获取icon故障:{}", url, e);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存到文件中
|
||||||
|
*
|
||||||
|
* @param iconUrl icon文件名
|
||||||
|
* @param host host
|
||||||
|
* @param b 数据
|
||||||
|
* @return {@link String}
|
||||||
|
* @author FleyX
|
||||||
|
*/
|
||||||
|
private String saveToFile(String iconUrl, String host, byte[] b) {
|
||||||
|
String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf("."));
|
||||||
|
String filePath = Paths.get(FileConstant.FAVICON_PATH, host.replace("www", "").replaceAll("\\.", "").substring(0, 2), fileName).toString();
|
||||||
|
FileUtil.writeBytes(b, Paths.get(CommonConstant.fileSavePath, filePath).toString());
|
||||||
|
return File.separator + filePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import java.util.List;
|
|||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 11:19
|
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class Bookmark {
|
public class Bookmark {
|
||||||
@ -36,6 +35,7 @@ public class Bookmark {
|
|||||||
private String name;
|
private String name;
|
||||||
private String url = "";
|
private String url = "";
|
||||||
private String icon = "";
|
private String icon = "";
|
||||||
|
private String iconUrl;
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
private String searchKey = "";
|
private String searchKey = "";
|
||||||
private Long addTime;
|
private Long addTime;
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a ref="targetA" style="left: 1000000px" target="_blank" />
|
<a ref="targetA" style="left: 1000000px" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
await vuex.default.dispatch("treeData/clear");
|
await vuex.default.dispatch("treeData/clear");
|
||||||
await vuex.default.dispatch("globalConfig/clear");
|
await vuex.default.dispatch("globalConfig/clear");
|
||||||
next({
|
next({
|
||||||
path: "/public/login?to=" + btoa(location.href),
|
path: "/public/login?to=" + btoa(to.fullPath),
|
||||||
replace: true
|
replace: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,7 +22,13 @@ export const refreshHomePinList = "refreshHomePinList";
|
|||||||
* 通过id获取书签数据
|
* 通过id获取书签数据
|
||||||
*/
|
*/
|
||||||
export const getById = "getById";
|
export const getById = "getById";
|
||||||
|
/**
|
||||||
|
* 登录前初始化
|
||||||
|
*/
|
||||||
export const noLoginInit = "noLoginInit";
|
export const noLoginInit = "noLoginInit";
|
||||||
|
/**
|
||||||
|
* 登陆后初始化
|
||||||
|
*/
|
||||||
export const loginInit = "loginInit";
|
export const loginInit = "loginInit";
|
||||||
export const refresh = "refresh";
|
export const refresh = "refresh";
|
||||||
export const clear = "clear";
|
export const clear = "clear";
|
||||||
@ -39,6 +45,10 @@ export const addNode = "addNode";
|
|||||||
* 版本检查定时调度
|
* 版本检查定时调度
|
||||||
*/
|
*/
|
||||||
let timer = null;
|
let timer = null;
|
||||||
|
/**
|
||||||
|
* 检查本地版本是否有更新
|
||||||
|
*/
|
||||||
|
let checkLocalDataTimer = null;
|
||||||
/**
|
/**
|
||||||
* 刷新书签确认弹窗是否展示
|
* 刷新书签确认弹窗是否展示
|
||||||
*/
|
*/
|
||||||
@ -76,8 +86,8 @@ const getters = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async [noLoginInit]() {},
|
async [noLoginInit] () { },
|
||||||
async [loginInit](context) {
|
async [loginInit] (context) {
|
||||||
if (context.state.isInit || context.state.isIniting) {
|
if (context.state.isInit || context.state.isIniting) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -89,11 +99,12 @@ const actions = {
|
|||||||
context.commit(IS_INIT, true);
|
context.commit(IS_INIT, true);
|
||||||
context.commit(IS_INITING, false);
|
context.commit(IS_INITING, false);
|
||||||
timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL);
|
timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL);
|
||||||
|
checkLocalDataTimer = setInterval(() => checkLocalData(context), 2000);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 确保数据加载完毕
|
* 确保数据加载完毕
|
||||||
*/
|
*/
|
||||||
ensureDataOk(context) {
|
ensureDataOk (context) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let timer = setInterval(() => {
|
let timer = setInterval(() => {
|
||||||
try {
|
try {
|
||||||
@ -108,7 +119,7 @@ const actions = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
//刷新缓存数据
|
//刷新缓存数据
|
||||||
async [refresh](context) {
|
async [refresh] (context) {
|
||||||
let treeData = await HttpUtil.get("/bookmark/currentUser");
|
let treeData = await HttpUtil.get("/bookmark/currentUser");
|
||||||
if (!treeData[""]) {
|
if (!treeData[""]) {
|
||||||
treeData[""] = [];
|
treeData[""] = [];
|
||||||
@ -127,7 +138,7 @@ const actions = {
|
|||||||
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
||||||
},
|
},
|
||||||
//清除缓存数据
|
//清除缓存数据
|
||||||
async [clear](context) {
|
async [clear] (context) {
|
||||||
context.commit(TOTAL_TREE_DATA, null);
|
context.commit(TOTAL_TREE_DATA, null);
|
||||||
context.commit(VERSION, null);
|
context.commit(VERSION, null);
|
||||||
context.commit(SHOW_REFRESH_TOAST, false);
|
context.commit(SHOW_REFRESH_TOAST, false);
|
||||||
@ -137,13 +148,16 @@ const actions = {
|
|||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
}
|
}
|
||||||
|
if (checkLocalDataTimer != null) {
|
||||||
|
clearInterval(checkLocalDataTimer);
|
||||||
|
}
|
||||||
await localforage.removeItem(TOTAL_TREE_DATA);
|
await localforage.removeItem(TOTAL_TREE_DATA);
|
||||||
await localforage.removeItem(VERSION);
|
await localforage.removeItem(VERSION);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 移动节点
|
* 移动节点
|
||||||
*/
|
*/
|
||||||
async moveNode(context, info) {
|
async moveNode (context, info) {
|
||||||
let data = context.state[TOTAL_TREE_DATA];
|
let data = context.state[TOTAL_TREE_DATA];
|
||||||
const target = info.node.dataRef;
|
const target = info.node.dataRef;
|
||||||
const current = info.dragNode.dataRef;
|
const current = info.dragNode.dataRef;
|
||||||
@ -211,7 +225,7 @@ const actions = {
|
|||||||
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
|
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
|
||||||
return body;
|
return body;
|
||||||
},
|
},
|
||||||
async [refreshHomePinList]({ commit }) {
|
async [refreshHomePinList] ({ commit }) {
|
||||||
let list = await HttpUtil.get("/home/pin");
|
let list = await HttpUtil.get("/home/pin");
|
||||||
commit(HOME_PIN_LIST, list);
|
commit(HOME_PIN_LIST, list);
|
||||||
let map = {};
|
let map = {};
|
||||||
@ -221,14 +235,14 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 更新版本数据
|
* 更新版本数据
|
||||||
*/
|
*/
|
||||||
async updateVersion({ commit, state }, version) {
|
async updateVersion ({ commit, state }, version) {
|
||||||
commit(VERSION, version == null ? state[VERSION] + 1 : version);
|
commit(VERSION, version == null ? state[VERSION] + 1 : version);
|
||||||
await localforage.setItem(VERSION, state[VERSION]);
|
await localforage.setItem(VERSION, state[VERSION]);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 新增书签、文件夹
|
* 新增书签、文件夹
|
||||||
*/
|
*/
|
||||||
async [addNode](context, { sourceNode, targetNode }) {
|
async [addNode] (context, { sourceNode, targetNode }) {
|
||||||
if (sourceNode === null) {
|
if (sourceNode === null) {
|
||||||
if (context.state[TOTAL_TREE_DATA][""] === undefined) {
|
if (context.state[TOTAL_TREE_DATA][""] === undefined) {
|
||||||
context.state[TOTAL_TREE_DATA][""] = [];
|
context.state[TOTAL_TREE_DATA][""] = [];
|
||||||
@ -253,7 +267,7 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 删除节点数据
|
* 删除节点数据
|
||||||
*/
|
*/
|
||||||
async [deleteData](context, { pathList, bookmarkIdList }) {
|
async [deleteData] (context, { pathList, bookmarkIdList }) {
|
||||||
//待删除的书签
|
//待删除的书签
|
||||||
let bookmarkIdSet = new Set();
|
let bookmarkIdSet = new Set();
|
||||||
bookmarkIdList.forEach(item => bookmarkIdSet.add(item));
|
bookmarkIdList.forEach(item => bookmarkIdSet.add(item));
|
||||||
@ -281,7 +295,7 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 编辑书签节点
|
* 编辑书签节点
|
||||||
*/
|
*/
|
||||||
async editNode({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) {
|
async editNode ({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) {
|
||||||
node.name = newName;
|
node.name = newName;
|
||||||
node.url = newUrl;
|
node.url = newUrl;
|
||||||
node.icon = newIcon;
|
node.icon = newIcon;
|
||||||
@ -295,10 +309,10 @@ const mutations = {
|
|||||||
[TOTAL_TREE_DATA]: (state, totalTreeData) => {
|
[TOTAL_TREE_DATA]: (state, totalTreeData) => {
|
||||||
state.totalTreeData = totalTreeData;
|
state.totalTreeData = totalTreeData;
|
||||||
},
|
},
|
||||||
[IS_INIT](state, isInit) {
|
[IS_INIT] (state, isInit) {
|
||||||
state.isInit = isInit;
|
state.isInit = isInit;
|
||||||
},
|
},
|
||||||
[IS_INITING](state, isIniting) {
|
[IS_INITING] (state, isIniting) {
|
||||||
state.isIniting = isIniting;
|
state.isIniting = isIniting;
|
||||||
},
|
},
|
||||||
[VERSION]: (state, version) => {
|
[VERSION]: (state, version) => {
|
||||||
@ -322,7 +336,7 @@ const mutations = {
|
|||||||
* @param {*} isFirst
|
* @param {*} isFirst
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function treeDataCheck(context, isFirst) {
|
async function treeDataCheck (context, isFirst) {
|
||||||
if (toastShow || !checkJwtValid(context.rootState.globalConfig.token)) {
|
if (toastShow || !checkJwtValid(context.rootState.globalConfig.token)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -336,14 +350,14 @@ async function treeDataCheck(context, isFirst) {
|
|||||||
closable: false,
|
closable: false,
|
||||||
keyboard: false,
|
keyboard: false,
|
||||||
maskClosable: false,
|
maskClosable: false,
|
||||||
onOk() {
|
onOk () {
|
||||||
toastShow = false;
|
toastShow = false;
|
||||||
return new Promise(async resolve => {
|
return new Promise(async resolve => {
|
||||||
await context.dispatch(refresh);
|
await context.dispatch(refresh);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onCancel() {
|
onCancel () {
|
||||||
toastShow = false;
|
toastShow = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -354,6 +368,24 @@ async function treeDataCheck(context, isFirst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查本地缓存数据是否有更新
|
||||||
|
* @param {*} context
|
||||||
|
*/
|
||||||
|
async function checkLocalData (context) {
|
||||||
|
let data = await localforage.getItem(TOTAL_TREE_DATA);
|
||||||
|
let version = await localforage.getItem(VERSION);
|
||||||
|
if (!data || !version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (version > context.state[VERSION]) {
|
||||||
|
console.log("从local缓存更新数据:", version);
|
||||||
|
context.commit(TOTAL_TREE_DATA, data);
|
||||||
|
context.commit(VERSION, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export const store = {
|
export const store = {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state,
|
state,
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
<a-menu-item v-if="!rec.dataRef.isLeaf" key="add">新增</a-menu-item>
|
<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-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">
|
<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>
|
||||||
<a-menu-item key="edit">编辑</a-menu-item>
|
<a-menu-item key="edit">编辑</a-menu-item>
|
||||||
<a-menu-item key="delete">删除</a-menu-item>
|
<a-menu-item key="delete">删除</a-menu-item>
|
||||||
@ -114,7 +114,7 @@ export default {
|
|||||||
loadedKeys: [], // 已加载数据
|
loadedKeys: [], // 已加载数据
|
||||||
replaceFields: {
|
replaceFields: {
|
||||||
title: "name",
|
title: "name",
|
||||||
key: "bookmarkId"
|
key: "bookmarkId",
|
||||||
},
|
},
|
||||||
mulSelect: false, // 多选框是否显示
|
mulSelect: false, // 多选框是否显示
|
||||||
currentSelect: null, // 当前树的选择项
|
currentSelect: null, // 当前树的选择项
|
||||||
@ -126,19 +126,19 @@ export default {
|
|||||||
// 新增、修改目标数据,null说明向根节点增加数据
|
// 新增、修改目标数据,null说明向根节点增加数据
|
||||||
targetNode: null,
|
targetNode: null,
|
||||||
// 是否为新增动作
|
// 是否为新增动作
|
||||||
isAdd: false
|
isAdd: false,
|
||||||
},
|
},
|
||||||
copyBoard: null //剪贴板对象
|
copyBoard: null, //剪贴板对象
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("treeData", ["totalTreeData", HOME_PIN_LIST]),
|
...mapState("treeData", ["totalTreeData", HOME_PIN_LIST]),
|
||||||
...mapState("globalConfig", ["isPhone"])
|
...mapState("globalConfig", ["isPhone"]),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
totalTreeData(newVal, oldVal) {
|
totalTreeData(newVal, oldVal) {
|
||||||
this.resetData();
|
this.resetData();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, true);
|
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, true);
|
||||||
@ -147,21 +147,14 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
//初始化clipboard
|
//初始化clipboard
|
||||||
this.copyBoard = new ClipboardJS(".copy-to-board", {
|
this.copyBoard = new ClipboardJS(".copy-to-board", {
|
||||||
text: function(trigger) {
|
text: function (trigger) {
|
||||||
return trigger.attributes.data.nodeValue;
|
return trigger.attributes.data.nodeValue;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
this.copyBoard.on("success", e => {
|
this.copyBoard.on("success", (e) => {
|
||||||
this.$message.success("复制成功");
|
this.$message.success("复制成功");
|
||||||
e.clearSelection();
|
e.clearSelection();
|
||||||
});
|
});
|
||||||
|
|
||||||
window.onblur = e => {
|
|
||||||
console.log("窗口非激活");
|
|
||||||
};
|
|
||||||
window.onfocus = e => {
|
|
||||||
console.log("窗口激活");
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, false);
|
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, false);
|
||||||
@ -175,7 +168,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
loadData(treeNode) {
|
loadData(treeNode) {
|
||||||
console.log("加载数据", 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;
|
const data = typeof treeNode === "number" ? this.$store.getters["treeData/getById"](treeNode) : treeNode.dataRef;
|
||||||
let newPath = data.path + "." + data.bookmarkId;
|
let newPath = data.path + "." + data.bookmarkId;
|
||||||
if (!this.totalTreeData[newPath]) {
|
if (!this.totalTreeData[newPath]) {
|
||||||
@ -219,9 +212,9 @@ export default {
|
|||||||
this.expandedKeys = [
|
this.expandedKeys = [
|
||||||
...item.path
|
...item.path
|
||||||
.split(".")
|
.split(".")
|
||||||
.filter(item => item.length > 0)
|
.filter((item) => item.length > 0)
|
||||||
.map(item => parseInt(item)),
|
.map((item) => parseInt(item)),
|
||||||
item.bookmarkId
|
item.bookmarkId,
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
this.expandedKeys.pop();
|
this.expandedKeys.pop();
|
||||||
@ -235,7 +228,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.checkedKeys.splice(this.checkedKeys.indexOf(item.bookmarkId), 1);
|
this.checkedKeys.splice(this.checkedKeys.indexOf(item.bookmarkId), 1);
|
||||||
this.checkedNodes.splice(
|
this.checkedNodes.splice(
|
||||||
this.checkedNodes.findIndex(item1 => item1.bookmarkId === item.bookmarkId),
|
this.checkedNodes.findIndex((item1) => item1.bookmarkId === item.bookmarkId),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -255,9 +248,9 @@ export default {
|
|||||||
this.expandedKeys = [
|
this.expandedKeys = [
|
||||||
...item.path
|
...item.path
|
||||||
.split(".")
|
.split(".")
|
||||||
.filter(item => item.length > 0)
|
.filter((item) => item.length > 0)
|
||||||
.map(item => parseInt(item)),
|
.map((item) => parseInt(item)),
|
||||||
item.bookmarkId
|
item.bookmarkId,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -280,7 +273,7 @@ export default {
|
|||||||
const bookmarkIdList = [];
|
const bookmarkIdList = [];
|
||||||
const pathList = [];
|
const pathList = [];
|
||||||
if (this.checkedNodes) {
|
if (this.checkedNodes) {
|
||||||
this.checkedNodes.forEach(item =>
|
this.checkedNodes.forEach((item) =>
|
||||||
item.type === 1 ? pathList.push(item.path + "." + item.bookmarkId) : bookmarkIdList.push(item.bookmarkId)
|
item.type === 1 ? pathList.push(item.path + "." + item.bookmarkId) : bookmarkIdList.push(item.bookmarkId)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -297,7 +290,7 @@ export default {
|
|||||||
await HttpUtil.post("/bookmark/batchDelete", null, { pathList, bookmarkIdList });
|
await HttpUtil.post("/bookmark/batchDelete", null, { pathList, bookmarkIdList });
|
||||||
await this.$store.dispatch(TREE_DATA + "/" + deleteData, { pathList, bookmarkIdList });
|
await this.$store.dispatch(TREE_DATA + "/" + deleteData, { pathList, bookmarkIdList });
|
||||||
//删除已经被删除的数据
|
//删除已经被删除的数据
|
||||||
pathList.forEach(item => {
|
pathList.forEach((item) => {
|
||||||
const id = parseInt(item.split(".").reverse()[0]);
|
const id = parseInt(item.split(".").reverse()[0]);
|
||||||
let index = this.loadedKeys.indexOf(id);
|
let index = this.loadedKeys.indexOf(id);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
@ -329,13 +322,13 @@ export default {
|
|||||||
this.refresh(false);
|
this.refresh(false);
|
||||||
this.expandedKeys = item.path
|
this.expandedKeys = item.path
|
||||||
.split(".")
|
.split(".")
|
||||||
.filter(one => one.length > 0)
|
.filter((one) => one.length > 0)
|
||||||
.map(one => parseInt(one));
|
.map((one) => parseInt(one));
|
||||||
this.loadedKeys = item.path
|
this.loadedKeys = item.path
|
||||||
.split(".")
|
.split(".")
|
||||||
.filter(one => one.length > 0)
|
.filter((one) => one.length > 0)
|
||||||
.map(one => parseInt(one));
|
.map((one) => parseInt(one));
|
||||||
this.expandedKeys.forEach(async one => await this.loadData(one));
|
this.expandedKeys.forEach(async (one) => await this.loadData(one));
|
||||||
this.currentSelect = item;
|
this.currentSelect = item;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -351,7 +344,7 @@ export default {
|
|||||||
this.addModal = {
|
this.addModal = {
|
||||||
show: false,
|
show: false,
|
||||||
targetNode: null,
|
targetNode: null,
|
||||||
isAdd: false
|
isAdd: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async onDrop(info) {
|
async onDrop(info) {
|
||||||
@ -395,12 +388,12 @@ export default {
|
|||||||
await this.deleteBookmarks();
|
await this.deleteBookmarks();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
} else if (key === "edit") {
|
} else if (key === "edit") {
|
||||||
this.editData();
|
this.editData();
|
||||||
} else if (key === "pin") {
|
} 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) {
|
if (pin.length > 0) {
|
||||||
await HttpUtil.delete("/home/pin", { id: pin[0].id });
|
await HttpUtil.delete("/home/pin", { id: pin[0].id });
|
||||||
} else {
|
} else {
|
||||||
@ -418,8 +411,8 @@ export default {
|
|||||||
dealList(root, map[""], map);
|
dealList(root, map[""], map);
|
||||||
let content = exportFileHead + root.outerHTML;
|
let content = exportFileHead + root.outerHTML;
|
||||||
downloadFile(moment().format("YYYY-MM-DD") + "导出书签.html", content);
|
downloadFile(moment().format("YYYY-MM-DD") + "导出书签.html", content);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -14,14 +14,16 @@ export default {
|
|||||||
form: {
|
form: {
|
||||||
name: null,
|
name: null,
|
||||||
url: null,
|
url: null,
|
||||||
|
icon: null,
|
||||||
|
iconUrl: null,
|
||||||
type: 0,
|
type: 0,
|
||||||
path: ""
|
path: "",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
//接受父节点传递的书签信息
|
//接受父节点传递的书签信息
|
||||||
window.addEventListener("message", event => {
|
window.addEventListener("message", (event) => {
|
||||||
if (!event.data.code) {
|
if (!event.data.code) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -30,6 +32,8 @@ export default {
|
|||||||
console.log("新增书签");
|
console.log("新增书签");
|
||||||
this.form.name = event.data.data.name;
|
this.form.name = event.data.data.name;
|
||||||
this.form.url = event.data.data.url;
|
this.form.url = event.data.data.url;
|
||||||
|
this.form.icon = event.data.data.icon;
|
||||||
|
this.form.iconUrl = event.data.data.iconUrl;
|
||||||
this.addBookmark();
|
this.addBookmark();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -46,8 +50,8 @@ export default {
|
|||||||
this.$message.success("添加成功");
|
this.$message.success("添加成功");
|
||||||
await this.$store.dispatch(TREE_DATA + "/" + addNode, { sourceNode: null, targetNode: res });
|
await this.$store.dispatch(TREE_DATA + "/" + addNode, { sourceNode: null, targetNode: res });
|
||||||
setTimeout(this.closeIframe, 500);
|
setTimeout(this.closeIframe, 500);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -67,11 +67,15 @@ export default {
|
|||||||
loading: false, //是否加载中
|
loading: false, //是否加载中
|
||||||
oauthLogining: false, //true:正在进行oauth后台操作
|
oauthLogining: false, //true:正在进行oauth后台操作
|
||||||
page: null, //oauth打开的页面实例
|
page: null, //oauth打开的页面实例
|
||||||
|
redirect: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
let _this = this;
|
let _this = this;
|
||||||
window.addEventListener("storage", this.storageDeal.bind(this));
|
window.addEventListener("storage", this.storageDeal.bind(this));
|
||||||
|
if (this.$route.query.to) {
|
||||||
|
this.redirect = atob(this.$route.query.to);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.removeEventListener("storage", this.storageDeal);
|
window.removeEventListener("storage", this.storageDeal);
|
||||||
@ -85,7 +89,7 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
let token = await httpUtil.post("/user/login", null, this.form);
|
let token = await httpUtil.post("/user/login", null, this.form);
|
||||||
await this.$store.dispatch("globalConfig/setToken", token);
|
await this.$store.dispatch("globalConfig/setToken", token);
|
||||||
this.$router.replace("/");
|
this.$router.replace(this.redirect ? this.redirect : "/");
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ chrome.contextMenus.onClicked.addListener(async function (info, tab) {
|
|||||||
let body = {
|
let body = {
|
||||||
name: tab.title,
|
name: tab.title,
|
||||||
url: tab.url,
|
url: tab.url,
|
||||||
|
iconUrl: tab.favIconUrl
|
||||||
};
|
};
|
||||||
sendToContent(tab.id, { code: "addBookmark", data: body, token: await getVal("token") });
|
sendToContent(tab.id, { code: "addBookmark", data: body, token: await getVal("token") });
|
||||||
});
|
});
|
||||||
@ -33,7 +34,8 @@ chrome.runtime.onMessage.addListener(async (data, sender, sendResponse) => {
|
|||||||
await sendToContent(sender.tab.id, { code: "setTokenOk" });
|
await sendToContent(sender.tab.id, { code: "setTokenOk" });
|
||||||
} else if (data.code == 'getToken') {
|
} else if (data.code == 'getToken') {
|
||||||
let token = await getVal("token");
|
let token = await getVal("token");
|
||||||
sendToPopup({ code: "setToken", data: await getVal("token") });
|
|
||||||
|
sendToPopup({ code: "setToken", data: token });
|
||||||
} else if (data.code == "clearToken") {
|
} else if (data.code == "clearToken") {
|
||||||
await clearVal("token");
|
await clearVal("token");
|
||||||
}
|
}
|
||||||
@ -83,7 +85,12 @@ function setVal (key, val) {
|
|||||||
*/
|
*/
|
||||||
function getVal (key) {
|
function getVal (key) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.get([key], function (res) {
|
chrome.storage.local.get([key], async function (res) {
|
||||||
|
if (key === 'token' && !checkTokenValid(res[key])) {
|
||||||
|
console.log("token过期");
|
||||||
|
await clearVal("token");
|
||||||
|
res[key] = null;
|
||||||
|
}
|
||||||
console.log("取值成功", res);
|
console.log("取值成功", res);
|
||||||
resolve(res[key]);
|
resolve(res[key]);
|
||||||
})
|
})
|
||||||
@ -98,3 +105,23 @@ function clearVal (key) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查token是否有效
|
||||||
|
* @param {*} token
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function checkTokenValid (token) {
|
||||||
|
try {
|
||||||
|
if (token && token.trim().length > 0) {
|
||||||
|
//检查token是否还有效
|
||||||
|
let content = JSON.parse(atob(token.split(".")[1]));
|
||||||
|
if (content.exp > Date.now() / 1000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(token, err);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -8,7 +8,11 @@
|
|||||||
"newtab": "tab/index.html"
|
"newtab": "tab/index.html"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"default_popup": "popup/index.html"
|
"default_popup": "popup/index.html",
|
||||||
|
"default_icon": {
|
||||||
|
"48": "static/icons/favicon.png",
|
||||||
|
"128": "static/icons/favicon.png"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"48": "static/icons/favicon.png",
|
"48": "static/icons/favicon.png",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// var bookmarkHost = "https://fleyx.com";
|
// var bookmarkHost = "https://fleyx.com";
|
||||||
var bookmarkHost = "http://localhost:8080";
|
var bookmarkHost = "http://localhost:8080";
|
||||||
|
|
||||||
var version = "0.1";
|
var version = "0.1.1";
|
||||||
|
|
||||||
window.token = localStorage.getItem('token');
|
window.token = localStorage.getItem('token');
|
||||||
axios.defaults.baseURL = bookmarkHost + '/bookmark/api';
|
axios.defaults.baseURL = bookmarkHost + '/bookmark/api';
|
||||||
|
@ -46,6 +46,15 @@ async function addBookmark (data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//新增书签
|
//新增书签
|
||||||
|
try {
|
||||||
|
if (data.data.iconUrl) {
|
||||||
|
let icon = await axios.get(data.data.iconUrl, { responseType: 'arraybuffer' });
|
||||||
|
console.log(JSON.stringify(new Uint8Array(icon.data)));
|
||||||
|
data.data.icon = `data:` + icon.headers['content-type'] + ';base64,' + window.btoa(String.fromCharCode(...new Uint8Array(icon.data)));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
console.log("新增书签", data.data);
|
console.log("新增书签", data.data);
|
||||||
bookmarkInfo = data.data;
|
bookmarkInfo = data.data;
|
||||||
addBlockDiv = document.createElement("div");
|
addBlockDiv = document.createElement("div");
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-cn">
|
<html lang="zh-cn">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<title>Document</title>
|
<link rel="icon" href="https://fleyx.com/favicon.ico" type="image/x-icon" crossorigin="anonymous" sizes="32*32"/>
|
||||||
|
<title>新建标签页</title>
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
@ -13,8 +14,8 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="https://fleyx.com" style="display: block" height="100%" width="100%" frameborder="0" scrolling="auto"></iframe>
|
<iframe src="https://fleyx.com" style="display: block;border: 0" height="100%" width="100%"></iframe>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user