開發網站有時會遇到一種狀況,某位使用者有個特殊需求,為一個人修改網頁設計正當性不足,但該功能確實可為他帶來可觀效益(我一直把增進人類全體之生活當成寫程式的核心價值呀)。因此,實務上偶爾會出現所謂 VIP 版,墮落自我要求不高的開發者會 Copy & Paste 改一版交差,認真精實的開發者會在原網頁加入客製功能並加上開關對特定使用者開放,如果要更專業一點,應設計成 Plugin 架構,開發擴充套件讓使用者自由載入,避免過多客製導致邏輯雜亂又能保有擴充性。如果需求可透過純 JavaScript 完成,除了從網站下手,針對非常個人化、少數人專屬的需求,還可以選擇從瀏覽器端下手,借用 TamperMonkey/GreaseMonkey 之類的機制針對特定網址插入客製 JavaScript 腳本實現個人客製化,只是在企業內部,瀏覽器是 IE 就沒轍了。之前我寫過 DarkMonkey For IE但操作複雜了點,對非技術背景使用者不友善,算不上良好的解決方案。最近,我想到一招古老但簡單直覺的做法 - Bookmarklet

Bookmarklet 原理是將一段"javascript:要執行的程式"存成書籤(在 IE 叫「我的最愛」),使用者點選時不跳轉新網頁而是執行該程式,對網頁進行操作實現客製化。書籤或我的最愛是瀏覽器內建功能,操作簡便,幾無技術門檻,很容易被使用者接受。

我用一個情境來示範。有某部落客提出奇怪的需求,他希望為自己的每篇文章加上一句噁心吹捧自我鼓勵的文字,以激勵自我建立自信。雖然這個需求超白爛,但迴歸技術面,這點小把戲只需幾行 JavaScript 即可完成:

(function() {
    var goodWords="讚!\t超棒!\t好文!\t推!\t實用。".split('\t');
    $('article.post h1').map(function() {
    	var rnd = Math.floor(Math.random()*goodWords.length);
    	$('<div></div>')
    	.css({
    		color: 'yellow',
    		display: 'inline-block',
    		marginLeft: '1em',
    		fontSize: '0.8em'
    	})
    	.text(goodWords[rnd])
    	.appendTo(this);
    });
})();

用 F12 測試一下,成功。

下一步是用 Minifier 將 JavaScript 縮成一行並加上 javascript: 字首及 void(0); 結尾:

javascript:!function(){var t="讚!\t超棒!\t好文!\t推!\t實用。".split("\t");$("article.post h1").map(function()).text(t[i]).appendTo(this)})}();void(0);

連上部落格,將這串文字貼到網址列,可以得到跟在 F12 執行一樣的效果:

測試 OK 之後,我們來把它轉成「我的最愛」書籤。IE 我的最愛實體會對映到 %userprofile%\Favorites 目錄,每則書籤是附檔名為 .url 的檔案:

將上述壓縮成單行的 JavaScript 填入以下格式存成 .url,書籤就完成了。

[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,15
[InternetShortcut]
URL=javascript:(function(){var n="讚!\t超棒!\t好文!\t推!\t實用。".split("\t");...略....appendTo(this)})})();void(0)
IDList=
[Bookmarklet]
ExtendedURL=javascript:(function(){var n="讚!\t超棒!\t好文!\t推!\t實用。".split("\t");$...略.....appendTo(this)})})();void(0)

Windows .url 檔案格式的文件不多,它偏向文件未記載的隱藏功能,我只有找到一篇 Gist,提到 URL 長度上限為 2038 bytes,完整部分放在 ExtendedURL (IE11 上限為 5119 Bytes)。另外,實測如指令包含中文,需存成 Unicode (UTF16 LTE) 編碼,不能存 UTF8。

如此一個內含 JavaScript 程式碼的書籤就做好了。將它複製到 %userprofile%\Favorites 目錄(或是 %userprofile%\Favorites\Links,會出現在展示動畫中的「我的最愛列」),點一下就能在網頁上施魔法,例如以下展示:

這樣子用起來是不是很方便?辦公室從阿伯阿姨大哥大姐到底迪美眉,人人都會。

最後,我覺得 Script Minify 跟打包 .url 的程序繁雜又沒營養,便把它寫成 PowerShell Module,寫完測好 JavaScript 存檔,叫出工具立刻轉成 .url,另外還有 Add-IEShortcut 指令幫忙把 .url 檔搬到 %userprofile%\Favorites,開發測試更省力:

一併附上 PowerShell 模組程式範例,模組製作請參考 讓小工具程式更順手 - PowerShell 模組

<#
 .Synopsis
  IE JavaScript 捷徑產生器

 .Description
  將 JavaScript 指令封裝成 IE 捷徑

 .Parameter scriptPath
  JavaScript 檔路徑

 .Parameter shortcutPath
  IE 捷徑路徑

 .Example
   ConvertTo-IEShortcut
#>
function ConvertTo-IEShortcut {
    Param(
        [Parameter(Mandatory = $true)]
        [string]$scriptPath,
        [Parameter(Mandatory = $true)]
        [string]$shortcutPath
    )
    $ErrorActionPreference = "STOP"
    Add-Type -Path $PSScriptRoot\NUglify.dll
    $rawJs = Get-Content $scriptPath -Raw
    [string]$fullMinJs = "javascript:$([NUglify.Uglify]::Js($rawJs).Code);void(0)"
    $shortMinJs = $fullMinJs.Substring(0, [System.Math]::Min($fullMinJs.Length, 2083))
    @"
[{000214A0-0000-0000-C000-000000000046}`]
Prop3=19,15
[InternetShortcut]
URL=$shortMinJs
IDList=
[Bookmarklet]
ExtendedURL=$fullMinJs
"@ | Out-File -FilePath $shortcutPath -Encoding unicode
}
Export-ModuleMember -Function ConvertTo-IEShortcut
#ConvertTo-IEShortcut .\sample.js .\test.url

<#
 .Synopsis
  加到 IE 我的最愛

 .Description
  將 IE 捷徑新增到我的最愛

 .Parameter shortcutPath
  IE 捷徑路徑

 .Example
   ConvertTo-IEShortcut
#>
function Add-IEShortcut {
    Param(
        [Parameter(Mandatory = $true)]
        [string]$shortcutPath
    )
    Copy-Item $shortcutPath  -Destination "$env:UserProfile\Favorites" -Force
 }

 Export-ModuleMember -Function Add-IEShortcut

Tutorial of how to create a .url file to execute customization scripts in IE.


Comments

# by Sam Chuang

以前我都叫他 bookmarklet,已經很久很久沒看到這個名詞了

# by Ben

想到以前很愛用的 Readability Bookmarklet 不知不覺已經十幾年前的事了

# by Leon

讚!超棒!好文!推!實用。

# by witcher 3

讚!\t超棒!\t好文!\t推!\t實用。

Post a comment