Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 14 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,26 @@ For images that don't have the above those file endings, like say
## Tampermonkey Installation

1. Install the [Tampermonkey](http://tampermonkey.net).
2. Open the [Workflowy Image tampermonkey script](https://raw.githubusercontent.com/jonleung/workflowy-images/master/tampermonkey/workflowy_images_tampermonkey_script.js) and copy the entire contents of that file to your clipboard.
3. Click on your Tampermonkey icon in your Browser and click "Add a new script…"

> ![](screenshots/github/tampermonkey_installation/new_script.png)

4. Select everything in the resulting editor and delete it. It should look blank
blank like this:

> ![](screenshots/github/tampermonkey_installation/delete_script.png)

5. Now in your empty editor, paste the code in that you just copied from the
other file.

6. Click the save icon:

> ![](screenshots/github/tampermonkey_installation/save_script.png)

5. Then in your browser, refresh your `workflowy.com` window to let the
2. Click install [GreasyFork - workflowy-images-and-bilibili-videos](https://greasyfork.org/zh-CN/scripts/528715-workflowy-images-and-bilibili-videos/code)
3. Then in your browser, refresh your `workflowy.com` window to let the
installation take effect.

_(Credit for the Tampermonkey installation directions go to Frank Degenaar. I
took the directions and screenshots he wrote from [the blogpost he wrote on
the Workflowy Site](https://blog.workflowy.com/2016/01/06/inline-images/)._

## Version History

- 0.3:
- Add support for Bilibili videos.
- Remove images once link is removed.
- Fix some bugs
- 0.31:
- 增加 webp 格式
- 修复 mac 不显示 b 站视频问题
- 改为识别链接而不是内容
- 上传到 [GreasyFork](https://greasyfork.org/zh-CN/scripts/528715-workflowy-images-and-bilibili-videos/code)

## Credits

I did not come up with this idea.
Expand Down
Binary file added XiaolaiMonoSC-Regular.ttf
Binary file not shown.
177 changes: 149 additions & 28 deletions tampermonkey/workflowy_images_tampermonkey_script.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
// ==UserScript==
// @name workflowy-images
// @name workflowy-images-and-bilibili-videos
// @namespace http://tampermonkey.net/
// @version 0.2
// @version 0.31
// @description Embed image links into workflowy
// @author Jonathan Leung (https://github.com/jonleung)
// @author Jonathan Leung (https://github.com/jonleung)&eterlan(https://github.com/eterlan)
// @match https://workflowy.com/*
// @grant none
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.1/underscore-min.js
// @license MIT
// ==/UserScript==
'use strict';
"use strict";

var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp"];
// 在脚本最开始的部分,添加这个函数
function addReferrerMeta() {
const meta = document.createElement('meta');
meta.name = 'referrer';
meta.content = 'no-referrer';
document.head.appendChild(meta);
}

(function() {
if (document.head) {
addReferrerMeta();
} else {
document.addEventListener('DOMContentLoaded', addReferrerMeta);
}
})();

var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"];

function createImageNodeAfterNode($node, imgSrc) {
if ($node.parent().find(".content-img").length === 0) {
var $div = $("<div>")
.addClass("content-img");
var $img = $("<img>")
.attr("src", imgSrc)
.css({
"max-width": "100%",
"max-height": "350px"
});
var $div = $("<div>").addClass("content-img");
var $img = $("<img>").attr("src", imgSrc).css({
"max-width": "100%",
"max-height": "350px",
});
$div.append($img);

$node.after($div);
Expand All @@ -42,38 +58,143 @@ function generateImagesForContentNode(node) {

function generateImagesForLinkNode(node) {
var $node = $(node);
var href = $node.attr('href');

// 如果没有 href 属性,直接返回
if (!href) return;

var hasImageExtension = IMAGE_EXTENSIONS.some((ext) =>
href.toLowerCase().endsWith(ext)
);

if (hasImageExtension) {
createImageNodeAfterNode($node.parent().parent(), href);
}
}

// 添加 B 站视频 ID 提取函数
function getBilibiliVideoId(url) {
const bvMatch = url.match(/BV\w{10}/);
return bvMatch ? bvMatch[0] : null;
}

function createBilibiliIframeAfterNode($node, videoId) {
if ($node.parent().find(".content-video").length === 0) {
var $div = $("<div>").addClass("content-video");
var $iframe = $("<iframe>")
.attr(
"src",
`https://player.bilibili.com/player.html?bvid=${videoId}&page=1&autoplay=0`
)
.attr("scrolling", "no")
.attr("border", "0")
.attr("frameborder", "no")
.attr("framespacing", "0")
.attr("allowfullscreen", "true")
.css({
width: "100%",
height: "500px",
"max-width": "800px",
});
$div.append($iframe);
$node.after($div);
}
}

function generateVideoForLinkNode(node) {
var $node = $(node);
var url = $node.attr('href');

var url = $node.text();
var curExtension = url.substr(-4);
if (_.contains(IMAGE_EXTENSIONS, curExtension) && $node.parent().text()[0] !== "!") {
createImageNodeAfterNode($node.parent(), url);
// 检查是否是 B 站链接
if (url.includes("bilibili.com/video")) {
var videoId = getBilibiliVideoId(url);
if (videoId) {
createBilibiliIframeAfterNode($node.parent().parent(), videoId);
}
}
}

function checkForChanges() {
$("div.name div.content, div.notes div.content").each(function(i, node) {
// 清理不再需要的图片
$("div.content-img").each(function (i, imgDiv) {
var $imgDiv = $(imgDiv);
var $prevContent = $imgDiv.prev(".content");

// 检查前一个 content 元素中是否还包含图片链接
var hasMarkdownImage = $prevContent.text().match(/\!\[.*\]\((.+)\)/);

// 检查图片链接
var hasImageLink = false;
$prevContent.find("a.contentLink").each(function (_, link) {
var $link = $(link);
var href = $link.attr('href');
if (href && IMAGE_EXTENSIONS.some((ext) => href.toLowerCase().endsWith(ext))) {
hasImageLink = true;
return false; // break
}
});

// 如果既没有 markdown 图片也没有图片链接,则移除
if (!hasMarkdownImage && !hasImageLink) {
$imgDiv.remove();
}
});

// 移除不再有对应链接的视频
$("div.content-video").each(function (i, videoDiv) {
var $videoDiv = $(videoDiv);
var $prevContent = $videoDiv.prev(".content");
var hasVideoLink = false;

$prevContent.find("a.contentLink").each(function (_, link) {
var url = $(link).attr('href');
if (url.includes("bilibili.com/video")) {
hasVideoLink = true;
return false;
}
});

if (!hasVideoLink) {
$videoDiv.remove();
}
});

// 原有的图片处理逻辑
$("div.name div.content, div.notes div.content").each(function (i, node) {
generateImagesForContentNode(node);
});

$("div.name a.contentLink, div.notes a.contentLink").each(function(i, node) {
$("div.name a.contentLink, div.notes a.contentLink").each(function (i, node) {
generateImagesForLinkNode(node);
generateVideoForLinkNode(node); // 添加视频处理
});
}

// TODO: These currently need to be in this order because otherwise when
// there is a raw link in the notes, it will be overwritten
};
// 添加 MutationObserver 来监听 DOM 变化
const observer = new MutationObserver(function (mutations) {
checkForChanges();
});

// When the page finishes loading
$(window).load(function () {
checkForChanges();
// 当页面加载完成时
$(window).on("load", function () {
checkForChanges();

// 开始观察 DOM 变化
observer.observe(document.body, {
childList: true,
subtree: true,
});

// 为确保内容加载后能显示图片,额外延迟检查一次
setTimeout(checkForChanges, 1000);
});

// When you change nodes
window.onhashchange = checkForChanges;

// When you press any keyboard key
$(document).keydown(function(e) {
setTimeout(function() {
$(document).keydown(function (e) {
setTimeout(function () {
checkForChanges();
}, 250);
});
});