Workflowy | 预览图片链接和嵌入视频文件

同时预览图片和嵌入视频/文件

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// ==UserScript==
// @name         Workflowy Image Preview, Embed & Extend
// @namespace    http://tampermonkey.net/
// @version      0.11.0
// @description  Add image preview, embed videos & extend Workflowy
// @author       Namkit
// @match        https://workflowy.com/*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  const imageUrlRegex = /(https?:\/\/[^\s]+?(?:\.(?:jpg|jpeg|png|gif|svg|webp))|(?:.+&)?f=(?:JPEG|PNG|GIF|SVG|WEBP)|[^\s]+mmbiz_png.+wx_fmt=(?:JPEG|PNG|GIF|SVG|WEBP)|[^\s]+webp|\/[^\s]+?\.(?:jpg|jpeg|png|gif|svg|webp)|[^\s]+?\.(?:jpg|jpeg|png|gif|svg|webp)|[^\s]+\/photo\/[^\s]+|[^\s]+\/media\/[^\s]+)/i;

  const modaoFormat = {
    regex: /https?:\/\/modao\.cc\/app\/([0-9a-zA-Z]+)/i,
    embed: 'https://modao.cc/app/$1/embed/v2'
  };

  const bilibiliFormat1 = {
    regex: /https?:\/\/(www\.)?bilibili\.com\/video\/(BV[\w]+)\//i,
    embed: '//player.bilibili.com/player.html?bvid=$2&high_quality=1&autoplay=0'
  };

  const bilibiliFormat2 = {
    regex: /https?:\/\/(b23\.)?tv\/(BV[\w]+)/i,
    embed: '//player.bilibili.com/player.html?bvid=$2&high_quality=1&autoplay=0'
  };

  const bilibiliFormat3 = {
    regex: /https?:\/\/(www\.)?bilibili\.com\/video\/(av[\d]+)\//i,
    embed: '//player.bilibili.com/player.html?aid=$2&high_quality=1&autoplay=0'
  };

  const mastergoFormat = {
    regex: /https?:\/\/mastergo\.com\/goto\/([A-Za-z0-9]+)\?page_id=([0-9]+):([0-9]+)&file=([0-9]+)/i,
    embed: 'https://mastergo.com/file/$4?page_id=$2:$3&source=iframe_share'
  };

  const figmaFormat = {
    regex: /https?:\/\/(www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]+)(\/.*)?/i,
    embed: 'https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2F$2%2F$3&type=design&node-id=0%253A1&mode=design&t=p6zHLdZVkWzkR00Y-1'
  };


  function createImagePreview(elem, imageUrl) {
  const container = document.createElement('div');
  container.style.position = 'fixed';  // Use fixed positioning
  container.style.zIndex = '100';
  container.style.backgroundColor = '#222';
  container.style.display = 'none';  // Initially hidden
  container.style.padding = '5px';

  const preview = document.createElement('img');
  preview.src = imageUrl;
  preview.style.maxWidth = '300px';  // Adjust as needed
  preview.style.maxHeight = '300px';  // Adjust as needed
  preview.style.objectFit = 'contain';
  preview.style.objectPosition = 'center';

  container.appendChild(preview);
  document.body.appendChild(container);  // Append to body to ensure it's on top

  return container;
}

function getModaoPreview(id) {
    return 'https://xxx/thumbnail/' + id;
  }

function processLink(linkElem) {
  const match = linkElem.href.match(imageUrlRegex);
  if (match) {
    const imageUrl = match[1];
    const previewElem = createImagePreview(linkElem, imageUrl);

    // Show preview on mouseover
    // Show preview on mouseover
    linkElem.addEventListener('mouseover', function(e) {
    // Position the preview near the mouse cursor, with a small offset
      previewElem.style.left = (e.clientX + 10) + 'px';
      previewElem.style.top = e.clientY + 'px';
      previewElem.style.display = 'block';
    });

    // Hide preview on mouseout
    linkElem.addEventListener('mouseout', function() {
      previewElem.style.display = 'none';
    });
  }
  match = linkElem.href.match(modaoFormat.regex);
  if (match) {
    const embedUrl = linkElem.href.replace(modaoFormat.regex, modaoFormat.embed);
    appendIframe(linkElem, embedUrl, true);
  }
}

    function processAllLinks() {
        const links = document.querySelectorAll('a');
        links.forEach((link) => {
            if (!link.hasAttribute('data-image-preview')) {
                link.setAttribute('data-image-preview', 'true');
                processLink(link);
            }
        });
    }

  function checkForEmbeds() {
    document.querySelectorAll('a:not([data-processed])').forEach(a => {
      const url = a.href;
      let match = url.match(bilibiliFormat1.regex);
      if (match) {
        const embedUrl = url.replace(bilibiliFormat1.regex, bilibiliFormat1.embed);
        appendIframe(a, embedUrl);
      }

      match = url.match(bilibiliFormat2.regex);
      if (match) {
        const embedUrl = url.replace(bilibiliFormat2.regex, bilibiliFormat2.embed);
        appendIframe(a, embedUrl);
      }

      match = url.match(bilibiliFormat3.regex);
      if (match) {
        const embedUrl = url.replace(bilibiliFormat3.regex, bilibiliFormat3.embed);
        appendIframe(a, embedUrl);
      }

      match = url.match(figmaFormat.regex);
      if (match) {
        const embedUrl = url.replace(figmaFormat.regex, figmaFormat.embed);
        appendIframe(a, embedUrl, 800, 450);
      }

      match = url.match(mastergoFormat.regex);
      if (match) {
        const embedUrl = url.replace(mastergoFormat.regex, mastergoFormat.embed);
        appendIframe(a, embedUrl, 800, 450);
      }
      match = url.match(modaoFormat.regex);
        if (match) {
        const embedUrl = url.replace(modaoFormat.regex, modaoFormat.embed);
        appendIframe(a, embedUrl);
        }
    });
  }

  function appendIframe(a, embedUrl, width=560, height=315) {
    const iframe = document.createElement('iframe');
    iframe.src = embedUrl;
    iframe.width = width;
    iframe.height = height;
    iframe.style.border = '0';
    iframe.style.display = "block";
    iframe.allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture";
    a.parentElement.insertBefore(iframe, a.nextSibling);
    a.setAttribute('data-processed', true);

    const lineBreak = document.createElement('br');
    a.parentElement.insertBefore(lineBreak, iframe.nextSibling);
  }

  setInterval(() => {
    processAllLinks();
    checkForEmbeds();
  }, 500);

})();

Changelog

  • 2023-08-01,0.1版本,支持预览bilibili视频;
  • 2023-08-02,0.2版本,支持预览Figma/FigJam文件;
  • 2023-08-03,0.3版本,支持预览bilibili的短地址B23.tv、AV序列的视频;
  • 2023-08-18,0.4版本,支持预览MasterGO文件;
  • 2023-08-19,0.5版本,支持预览图片链接;
  • 2023-08-20,0.6版本,支持预览百度的图片链接、知乎的图片链接;压缩图片链接预览的大小和尺寸;
  • 2023-08-21,0.7版本,支持预览微信的图片链接;
  • 2023-08-24,0.8版本,支持预览Twitter图片链接;
  • 2023-08-29,0.9版本,支持预览墨刀链接;
  • 2023-09-5,0.10版本,图片预览模式改为鼠标经过预览,为了节省流量;
  • 2023-09-12,0.11版本,优化了图片位移的问题;
  • 2023-09-25,为了方便管理代码,最新的脚本会放到Github里,Github上的脚本将会回滚到0.9版本,因为目前的鼠标经过版本只适合图片的轻量使用。在0.9版本里修复了微信链接图片重复出现的问题。
  • 2023-11-9,0.11版本,优化了预览速度,Github

备注:Bilibili不可避免地会有视频预览被屏蔽,不能正常预览的情况。

updatedupdated2023-12-222023-12-22