├── .bowerrc ├── .gitattributes ├── .gitconfig ├── .gitignore ├── README.md ├── bower.json ├── build.js ├── doc ├── api │ ├── GM_addStyle.html │ ├── GM_deleteValue.html │ ├── GM_getResourceText.html │ ├── GM_getResourceURL.html │ ├── GM_getValue.html │ ├── GM_info.html │ ├── GM_listValues.html │ ├── GM_log.html │ ├── GM_openInTab.html │ ├── GM_registerMenuCommand.html │ ├── GM_setClipboard.html │ ├── GM_setValue.html │ └── GM_xmlhttpRequest.html ├── intro │ ├── about.html │ └── gmScript.html └── tutorial │ ├── meta.html │ ├── other.html │ ├── publish.html │ └── warning.html ├── index.html ├── makefile ├── package.json ├── res ├── App.js └── App.scss └── tpl ├── api.html ├── arg.html ├── define.html ├── deprecated.html ├── meta.html └── snipset ├── gmAddStyle.html └── gmValue.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "cdn" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | filter=cr 2 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [filter "cr"] 2 | clean = tr '\\r' '\\n' 3 | smudge = tr '\\n' '\\r' 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | 4 | # CDN needs to be downloaded separately 5 | cdn/* 6 | 7 | build.log 8 | .idea 9 | 10 | res/App.min.js 11 | res/App.css -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 关于该项目 2 | 这是一个很有爱的中文 GreaseMonkey 用户脚本开发手册 :3 3 | 4 | 手册采用下述开源库进行开发: 5 | 6 | * Angular JS 7 | * ANgular UI (ui-router) 8 | * Bootstrap 9 | * jQuery 10 | 11 | 该项目于 [Firefox8](http://firefox8.qiniudn.com/doc/index.html) 获得灵感制作而成,其中 API 资料均从 [GM 官方百科](http://wiki.greasespot.net/)提取翻译而成。 12 | 13 | # 安装 14 | 首先需要安装 Bower。 15 | ```bash 16 | sudo npm install bower -g 17 | ``` 18 | 19 | 执行 `bower install` 安装所需第三方库 (Angular, Bootstrap, jQuery) 20 | 21 | 如果需要压缩小册子为 index + css + js 这三个文档的话执行 `make` 即可 (需要安装 closure-compiler、nodejs、npm、sass)。 22 | ```bash 23 | # Ubuntu 下安装依赖项 (未测试) 24 | sudo apt-get install libclosure-compiler-java nodejs npm ruby 25 | # 安装 sass 26 | sudo gem install sass 27 | # 安装构建用的库 28 | npm install 29 | ``` 30 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ucDevBook", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "angular": "~1.2.16", 6 | "angular-ui": "~0.4.0", 7 | "angular-ui-router": "~0.2.10", 8 | "bootstrap": "~3.1.1", 9 | "jquery": "~2.1.1", 10 | "jquery.scrollTo": "~1.4.12" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | // Build Site, require node js. 2 | 3 | var fs = require ('fs'); 4 | var CleanCSS = require('clean-css'); 5 | var HTMLMin = require('html-minifier').minify; 6 | 7 | var outDir = './build/'; 8 | 9 | var indexFile = fs.readFileSync('./index.html').toString(); 10 | 11 | var rmComment = function (r) { 12 | return r.replace(//g, ''); 13 | }; 14 | 15 | var writeFile = function (writeTo, fileContent) { 16 | console.log ('Write to: %s', writeTo); 17 | fs.writeFileSync(outDir + writeTo, fileContent); 18 | }; 19 | 20 | var minHTML = function (HTML) { 21 | return HTMLMin (HTML.toString(), { 22 | removeComments: true, 23 | removeCommentsFromCDATA: true, 24 | removeCDATASectionsFromCDATA: true, 25 | collapseWhitespace: true, 26 | conservativeCollapse: true, 27 | collapseBooleanAttributes: true, 28 | // removeAttributeQuotes: true, 29 | removeRedundantAttributes: true, 30 | // removeEmptyAttributes: true, 31 | removeOptionalTags: true, 32 | // removeEmptyElements: true, 33 | keepClosingSlash: true, 34 | caseSensitive: true 35 | }).replace(/>\s+<'); 36 | }; 37 | 38 | var procDir = function (dirName) { 39 | var ret = ''; 40 | console.log ('Build directory: %s', dirName); 41 | fs.readdirSync (dirName).forEach (function (file) { 42 | var curPath = dirName + file; 43 | if (fs.lstatSync(curPath).isDirectory()) { 44 | ret += procDir (curPath + '/'); 45 | return ; 46 | } 47 | 48 | // Process file 49 | console.log ('Add file: %s', curPath); 50 | ret += ''; 52 | }); 53 | 54 | return ret ; 55 | }; 56 | 57 | // 构建 CSS 档 58 | writeFile ('index.html', minHTML(indexFile.replace (/<\!--CSS\:START-->[\s\S]+<\!--CSS\:END-->/g, function (z) { 59 | var css = ''; 60 | rmComment(z).replace (/href="(.+?)"/g, function (z, link) { 61 | css += fs.readFileSync (link).toString(); 62 | }); 63 | 64 | writeFile ('App.css', new CleanCSS().minify(css.replace(/\/\*[\s\S]*?\*\//g, ''))); 65 | return ''; 66 | }). 67 | 68 | // 构建 JS 档 69 | replace (/<\!--JS\:START-->[\s\S]+<\!--JS\:END-->/g, function (z) { 70 | var js = ''; 71 | rmComment(z).replace (/src="(.+?)"/g, function (z, src) { 72 | js += '\n;' + fs.readFileSync (src).toString(); 73 | }); 74 | 75 | writeFile ('App.d.js', 76 | js.slice(1) 77 | ); 78 | return ''; 79 | }). 80 | // 构建全部 HTML 页面到一个文件 81 | replace('', procDir ('./tpl/') + procDir ('./doc/')))); 82 | -------------------------------------------------------------------------------- /doc/api/GM_addStyle.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数用于插入一段 CSS 到当前页面。它将插入一个新的 <style> 元素,添加输入的 CSS,然后插入到 <head> 末端。

3 | 4 |

语法

5 | 9 | 10 | 13 | 样式表的文本内容。 14 | 15 | 16 |

例子

17 |
GM_addStyle("body { color: white; background-color: black; } img { border: 0; }");
18 | 19 |

笔记

20 | 24 | 25 |

代码片断

26 | -------------------------------------------------------------------------------- /doc/api/GM_deleteValue.html: -------------------------------------------------------------------------------- 1 |

简介

2 |

该函数用于删除一个已经储存的值。

3 |

如果你需要寻找如何设定值,请参见 GM_setValue

4 | 5 |

语法

6 | 10 | 11 | 14 | 需要从脚本储存数据删除的值。 15 | 16 | 17 |

返回

18 |

undefined

19 | 20 |

例子

21 |

删除一个叫做 foo 的值。

22 |
GM_deleteValue("foo");
23 | 24 |

删除指定数组外的数据外的值

25 |
var GM_removeAndKeep = function (arrKeysToKeep) {
26 | 	if (!arrKeysToKeep instanceof Array)
27 | 		// 不是合法的数组参数
28 | 		return ;
29 | 
30 | 	GM_listValues().forEach (function (key) {
31 | 		if (arrKeysToKeep.indexOf (key) == -1) {
32 | 			// 不需要保留,删掉
33 | 			GM_deleteValue (key);
34 | 		}
35 | 	});
36 | };
37 | 
38 | // 删除 config、cache 外的数据
39 | GM_removeAndKeep (['config', 'cache']);
40 | 
41 | 42 |

代码片断

43 | -------------------------------------------------------------------------------- /doc/api/GM_getResourceText.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数用于获取定义的 @resource 的元属性值。

3 | 4 |

语法

5 | 9 | 10 | 13 | 声明的资源名称。 14 | 15 | 16 |

返回

17 |

String

18 | 19 |

异常

20 |

当资源不存在的时候将抛出异常。

21 | 22 |

例子

23 |
// ==UserScript==
24 | // 首先定义一个资源
25 | // @resource prototype http://www.example.com/prototype.js
26 | // ==/UserScript==
27 | 
28 | // 然后从这里获取资源地址
29 | var prototypeSource = GM_getResourceText("prototype");
30 | -------------------------------------------------------------------------------- /doc/api/GM_getResourceURL.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数用于获取定义的 @resource 所指向的内容。

3 | 4 |

语法

5 | 9 | 10 | 13 | 声明的资源名称。 14 | 15 | 16 |

返回

17 |

String

18 |
greasemonkey-script:[脚本唯一识别码]/[资源名]
19 | 如 20 |
greasemonkey-script:94242686-1400-4dce-982a-090cbfef7ba1/image
21 | 22 | 23 |

Greasemonkey 1.0 后的更改

24 |

GM 1.0 后返回的数据为 base64 编码过的 data: 协议地址。

25 |

该地址可直接用于任何支援 data: 协议的元素 (如: <img>)。但是在 <object><embed> 下无效。

26 |

做出该项更改的原因是 Base64 编码的地址在这里被重新编码了,因为 Base64 使用了 +/ 这两个特殊字符。

27 |

因此,你可能需要使用 decodeURIComponent 将取得的 Base64 还原一次。

28 | 29 |

异常

30 |

当资源不存在的时候将抛出异常。

31 | 32 |

例子

33 |
// ==UserScript==
34 | // 首先定义一个资源
35 | // @resource logo http://www.example.com/logo.png
36 | // ==/UserScript==
37 | 
38 | var img = document.createElement('img');
39 | // 将取得的地址作为图像地址并插入到页面
40 | img.src = GM_getResourceURL("logo");
41 | document.body.appendChild(img);
42 | -------------------------------------------------------------------------------- /doc/api/GM_getValue.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数用于获取脚本之前使用 GM_setValue 赋值储存的数据,可以为 StringBoolean 等类型。

3 | 4 |

语法

5 | 9 | 10 | 13 | 欲获取数据的名称。 14 | 15 | 16 | 19 | 如果上述数据不存在时返回的值。 20 | 21 | 22 |

返回

23 |

该函数将返回获取到的值,如果不存在则返回 default 传入的值。

24 | 25 |

例子

26 |

抓取一个叫做 foo 的储存值

27 |
// 输出储存为 foo 的值或 undefined
28 | 
29 | GM_log(GM_getValue("foo")); 
30 | 31 |

抓取一个叫做 'timezoneOffset' 的值并提供默认值:

32 |
// 如果该值不存在 GM_getValue() 则会返回 +8 (整数)
33 | 
34 | GM_log(GM_getValue("timezoneOffset", +8));
35 | 36 |

代码片断

37 | 38 | -------------------------------------------------------------------------------- /doc/api/GM_info.html: -------------------------------------------------------------------------------- 1 |

简介

2 |

和其它 API 不同,这是一个变量而非函数。

3 |

该变量提供当前执行的用户脚本的元数据。

4 | 5 |

语法

6 |
GM_info
7 | 8 |

返回

9 |

该对象含有下述属性:

10 |
11 |
script
12 |
一个包含当前脚本的 元数据。 13 |
14 |
name
15 |
文本
16 | 17 |
namespace
18 |
可能为空文本。
19 | 20 |
description
21 |
可能为空文本。
22 | 23 |
run-at
24 |
文本
25 | 26 |
version
27 |
可能为空文本
28 | 29 |
includes
30 |
可能为空数组。
31 | 32 |
excludes
33 |
可能为空数组。
34 | 35 |
matches
36 |
@match,可能为空数组 (0.9.16 下有问题)
37 | 38 |
resources
39 |
包含所有资源和其对应的地址的对象 (自 GM 1.2)。
40 | 41 |
unwrap
42 |
布尔型
43 |
44 |
45 | 46 |
scriptMetaStr
47 |
文本,元数据文本原文 (不含分隔符)
48 | 49 |
scriptWillUpdate
50 |
如果修改为 true,GM 将尝试自动更新脚本。
51 | 52 |
version
53 |
GM 版本。如 0.9.16
54 |
-------------------------------------------------------------------------------- /doc/api/GM_listValues.html: -------------------------------------------------------------------------------- 1 |

简介

2 |

该函数用于获取所有被赋值的值名,作为一个文本数组返回。

3 | 4 |

语法

5 | 7 | 8 |

返回

9 |

Array: 文本数组

10 | 11 |

例子

12 |

输出所有储存的值名

13 |
GM_log(GM_listValues());
14 | 15 | -------------------------------------------------------------------------------- /doc/api/GM_log.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |

描述

7 |

一个简单的日志函数,用于输出数据至控制台。按下键盘 F12 查看。

8 | 9 |

输出数据将输出至「错误控制台」,包括所属脚本命名空间以及传入的文本。

10 | 11 |

因此,下述脚本:

12 | 13 |
// ==UserScript==
14 | // @name          GM_log Example
15 | // @namespace     http://www.example.com/
16 | // ==/UserScript==
17 | 
18 | GM_log("This is an example of GM_log");
19 | 20 |

将产生这样的输出:

21 |
http://www.example.com/GM_log Example: This is an example of GM_log
22 | 23 |

语法

24 | 25 | 29 | 30 | 33 | 用于输出的文本内容,也可以为带有 .toString () 方法的变量。 34 | 35 | 36 |

返回

37 |

undefined

38 | 39 |

例子

40 |
GM_log("Hello, World!");
41 | GM_log("Warning, " + someInputField.value + "!");
-------------------------------------------------------------------------------- /doc/api/GM_openInTab.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

在新标签页开启指定地址。

3 | 4 |

语法

5 | 6 | 10 | 11 | 14 | 在新标签页开启的地址。 15 | 16 | 17 | 20 | 是否后台开启目标标签页; 默认为 true,即后台开启。 21 | 22 | 23 |

返回

24 |

0.8.2 之前: undefined
25 | 0.8.2 之后: 新标签的 window 对象

26 | 27 |

例子

28 |
GM_openInTab("http://www.example.com/");
29 | GM_openInTab("http://www.example.com/", false); // 打开并切换到目标标签页
30 | 
31 | -------------------------------------------------------------------------------- /doc/api/GM_registerMenuCommand.html: -------------------------------------------------------------------------------- 1 |

简介

2 |

该函数允许用户脚本添加菜单到用户脚本指令。

3 | 4 |

语法

5 | 9 | 10 | 13 | 用于显示的项目标题。 14 | 15 | 18 | 单击菜单后执行的回调。 19 | 20 | 23 | 菜单界面的热键;一个单子节符号,一般为项目标题中的一个字 (MDN)。 24 | 25 | 26 |

返回

27 |

undefined

28 | 29 |

例子

30 |
GM_registerMenuCommand("Hello, world (simple)", function () {
31 | 	/// ...
32 | });
33 | 
34 | var yooooo = function () {
35 | 	// ...
36 | };
37 | GM_registerMenuCommand("Hello, world!", yooooo, "h");
38 | 
39 | -------------------------------------------------------------------------------- /doc/api/GM_setClipboard.html: -------------------------------------------------------------------------------- 1 |

简介

2 |

更改当前剪切版内容为参数内容。

3 | 4 |

语法

5 | 9 | 10 | 13 | 任意文本。 14 | 15 | 16 |

例子

17 |
GM_setClipboard('http://www.example.com/short-url-code');
-------------------------------------------------------------------------------- /doc/api/GM_setValue.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数用于写入一些数据并储存,可使用 GM_getValue 获取储存的数据。StringBoolean 等类型。

3 | 4 |

语法

5 | 9 | 10 | 13 | 欲写入数据的名称。 14 | 15 | 16 | 19 | 欲写入数据的内容。 20 | 21 | 22 |

返回

23 |

undefined

24 | 25 |

例子

26 |

将名为 foo 的项目储存为 bar

27 |
GM_setValue("foo", "bar");
28 | 29 |

代码片断

30 | -------------------------------------------------------------------------------- /doc/api/GM_xmlhttpRequest.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

该函数主要用于实现跨域传输信息调用,如从 www.example.com 请求 upload.example.com 的内容。

3 | 4 |

语法

5 | 9 | 10 | 13 | 14 | 15 |
16 | 19 |

请求方式,最常见的有 GETPOST 两种。

20 |

也有其它的请求方式,详细请翻阅 w3 标准

21 |
22 | 25 | 请求访问的地址。 26 | 27 | 28 | 29 | 32 | 默认为 false。当为 true 的时候将使用 .sendAsBinary() 方法。 33 | 34 | 37 | 任意对象。搞对象同时将为 Response 对象的 context。 38 | 39 | 42 | 提交给网页的数据,一般为 POST 操作。 43 | 44 | 47 | 提交给网页使用的 HTTP 头部数据。 48 | 49 | 52 | 提交给网站的用户名 53 | 54 | 57 | 提交给网站的密码 (详细: 基础用户验证)。 58 | 59 | 62 | 当该值为 true 时,请求结束前将导致浏览器界面无项应。该模式下返回值即为返回数据。 63 | 64 | 65 | 68 | 超过指定数字的毫秒数后强行结束网页请求。 69 | 70 | 73 | 包含了 onabortonerroronloadonprogress 这四个上传回调函数的对象。 74 | 75 | 76 | 79 | 用于指定请求页面的元数据,如 text/html; charset=GBK 80 | 81 | 82 |
83 | 84 |
回调参数
85 |
86 |

回调参数将会被传入一个参数,请参考下方的「请求对象」。

87 |

可用的回调参数:

88 |
    89 |
  • onabort 断开操作时的回调
  • 90 |
  • onerror 请求出错时的回调
  • 91 |
  • onload 请求完毕后时的回调
  • 92 |
  • onprogress 请求进度更换时的回调
  • 93 |
  • onreadystatechange 准备状态切换时的回调
  • 94 |
  • ontimeout 请求超时时的回调
  • 95 |
96 |
97 |
98 | 99 |

请求对象

100 |

所有的回调参数调用时都会传入一个变量。根据回调的不同,下述数据可能不全部可用。

101 |
    102 |
  • readyState 准备状态
  • 103 |
  • responseHeaders 请求页面的头部信息
  • 104 |
  • responseText 请求的页面内容
  • 105 |
  • status 请求页面的状态,如 404
  • 106 |
  • statusText 请求页面的内容,如 404 Not Found
  • 107 |
108 |

其中,GM 还引用了自己独有的属性值:

109 |
110 | 113 | 114 | 使用 API 时传入的 context 属性。 115 | 116 | 119 | 120 | 获取跳转后的链接地址。 121 | 122 |
123 | 124 |

而针对 progress 的进度回调,传参包含下述属性:

125 |
    126 |
  • lengthComputable
  • 127 |
  • loaded
  • 128 |
  • total
  • 129 |
130 | 131 |

返回

132 |

在默认(异步请求, asynchronous)请求方式下,将返回一个带有 abort() 方法的对象。

133 |

在同步请求方式下,将返回一个带有 abort() 及下述属性的对象:

134 |
    135 |
  • finalUrl
  • 136 |
  • readyState
  • 137 |
  • responseHeaders
  • 138 |
  • responseText
  • 139 |
  • status
  • 140 |
  • statusText
  • 141 |
142 | 143 |

例子

144 |

最基础的调用

145 |
GM_xmlhttpRequest({
146 | 	method: "GET",
147 | 	url: "http://www.example.com/",
148 | 	onload: function(response) {
149 | 		alert(response.responseText);
150 | 	}
151 | });
152 | 153 |

GET 调用

154 |
GM_xmlhttpRequest({
155 | 	method: "GET",
156 | 	url: "http://www.example.net/",
157 | 	headers: {
158 | 		"User-Agent": "Mozilla/5.0",    // 如果未指定则使用浏览器默认值.
159 | 		"Accept": "text/xml"            // 如果未指定则教给浏览器自行判断
160 | 	},
161 | 	onload: function(response) {
162 | 		var responseXML = null;
163 | 		// 插入 responseXML 到现有对象 (仅限于 XML 对象)
164 | 		if (!response.responseXML) {
165 | 			responseXML = new DOMParser()
166 | 				.parseFromString(response.responseText, "text/xml");
167 | 		}
168 | 
169 | 		GM_log([
170 | 			response.status,
171 | 			response.statusText,
172 | 			response.readyState,
173 | 			response.responseHeaders,
174 | 			response.responseText,
175 | 			response.finalUrl,
176 | 			responseXML
177 | 		].join("\n"));
178 | 	}
179 | });
180 | 181 |

POST 请求

182 |

当发出 POST 请求时,大多数网站都要求 Content-Type 头部设定为 application/x-www-form-urlencoded 才允许提交。

183 |
GM_xmlhttpRequest({
184 | 	method: "POST",
185 | 	url: "http://www.example.net/login",
186 | 	data: "username=johndoe&password=xyz123",
187 | 	headers: {
188 | 		"Content-Type": "application/x-www-form-urlencoded"
189 | 	},
190 | 	onload: function(response) {
191 | 		if (response.responseText.indexOf("Logged in as") > -1) {
192 | 			location.href = "http://www.example.net/dashboard";
193 | 		}
194 | 	}
195 | });
196 | 197 |

HEAD 请求

198 | 199 |

如同 HTTP 的定义,你可以发出一个 HEAD 请求只获取网页的头部信息。

200 |
GM_xmlhttpRequest({
201 | 	url: "http://www.example.com",
202 | 	method: "HEAD",
203 | 	onload: function(response) {
204 | 		GM_log(response.responseHeaders);
205 | 	}
206 | });
207 | -------------------------------------------------------------------------------- /doc/intro/about.html: -------------------------------------------------------------------------------- 1 |

关于该项目

2 |

这是一个很有爱的中文 GreaseMonkey 用户脚本开发手册,托管于 GitHub :3

3 | 4 |

该项目使用下述开源库进行开发,在此表示感谢:

5 | 11 | 12 |

该项目于 Firefox8 获得灵感制作而成,其中 API 资料均从 GM 官方百科提取翻译而成。

14 | -------------------------------------------------------------------------------- /doc/intro/gmScript.html: -------------------------------------------------------------------------------- 1 |

从原理上来说,GreaseMonkey(GM) 脚本相当于在网页上插入一段 JavaScript(JS) 脚本。

2 | 3 |

因此,它的编写语言本质上就是 JS。JS 所能实现的功能,GM 脚本都能实现。但 GM 它的强大并不限与此,还能实现如跨域请求更改剪辑版等原生 JS 无法实现的功能。

4 | 5 |
6 |

该文档不包含 JS 的编写教程

7 |

您可以通过参阅 其它资料询问他人 获取帮助。

9 |
-------------------------------------------------------------------------------- /doc/tutorial/meta.html: -------------------------------------------------------------------------------- 1 |

描述

2 |

元数据 包含了用户脚本的元数据。一般包含脚本名称、命名空间、执行地址和不执行的地址。

3 |

这些数据一般为 JavaScript 注释形式储存于脚本顶部。

4 | 5 |

例子

6 |
// ==UserScript==
  7 | // @name          我的第一个脚本
  8 | // @namespace     http://www.example.com/gmscripts
  9 | // @description   看我突破天际的钻头
 10 | // @include       http://www.example.com/*
 11 | // @include       http://www.example.org/*
 12 | // @exclude       http://www.example.org/foo
 13 | // @require       https://example.com/foo.js
 14 | // @resource      logo logo.png
 15 | // @resource      yooo http://www.example.com/resource2.png
 16 | // @version       1.0
 17 | // @icon          http://www.example.net/icon.png
 18 | // ==/UserScript==
19 | 20 |

语法

21 |

元数据必须按照以下格式填写

22 |
// ==UserScript==
 23 | // @属性名 属性值
 24 | // ==/UserScript==
25 | 26 |

每一条属性必须使用双斜杠//开头,不得使用块注释/* */

27 |

28 | 与此同时,所有的脚本元数据必须放置于 29 | // ==UserScript==// ==/UserScript== 30 | 之间才会被认定为有效的元数据。 31 |

32 | 33 |

元数据名和值中间可以为了保持美观添加多个空格。

34 | 35 |

36 | 37 | 40 |

用于指示该脚本名称,将显示于「脚本管理」及「猴子菜单」。该值同时为相同命名空间的唯一识别码。

41 |

如果未指定该参数,将尝试从文件名获取。

42 |
43 | 46 |

简单描述当前脚本的功能。也会于用户脚本管理界面显示。

47 |
48 | 51 |

命名空间和脚本名称是 GM 用于识别脚本唯一性的方法。如果两个脚本的名称和命名空间均相同,那么后安装的脚本将覆盖之前安装的脚本。

52 |

一般脚本作者将其项目使用相同命名空间,然后每个项目使用不同名称。

53 |

同时因为命名空间没有语法限制,一些作者直接使用项目首页作为其命名空间。该值只要不与他人重复即可。

54 |
55 | 58 |

指定脚本的版本号,GM 用来判断脚本是否更新的依据。

59 |
60 | 61 | 64 |

引用一个外部链接的脚本作为库使用。最常见的外部库为 jQuery。

65 |

因为 GM 对 IE 的支援不佳,因此一般不用考虑 IE 的兼容性,放心去搞吧~

66 |
67 | 70 |

* GM 的默认设定要求该值使用 https:// 协议。

71 |

该值用于指定发现更新后使用的脚本地址。若未指定则使用安装脚本地址。

72 |
73 | 76 |

用于检查更新使用的地址。该地址应只包含元数据而不包含脚本内容。

77 |
78 | 79 | 82 |

指定脚本所请求的权限,如 unsafeWindow 用于访问浏览器的 window 对象。

83 |

其它可选值则为 GM 提供的 GM_ 开头的 API。

84 |
85 | 87 |
// ==UserScript==
 88 | // @include     http://www.example.com/foo/*
 89 | // @include     http://www.example.org/*.bar
 90 | // @exclude     http://www.example.com/foo/baz
 91 | 
 92 | // GM 0.9.8 开始, @include 允许使用正则表达式匹配
 93 | // @include     /^https?://www\.example\.com/.*$/
 94 | // @include     /^http://www\.example\.(org|net)//
 95 | // ==/UserScript==
96 |

@include@exclude 使用 * 表示任意字符,或标准正则表达式对象。

97 |

同时,它还支持一个特殊的匹配符,.tld

98 |
@include http://www.example.tld/*
99 |

请注意: 如果使用 tld 匹配请务必确保数据不会被泄露给无关网站。

100 |

其中, @exclude 的匹配权限比 @include 要高。

101 |
102 | 105 |

GM 根据 Chrome 的 Match Patterns 实现的另外一种匹配方案,比 @include / @exclude 的匹配更严格。详细请参考上述 Chrome 开发者页面。

106 |
107 | 108 | 111 |

用于脚本管理界面显示的图标。虽然什么图片都可以,但建议使用 32x32 大小的图标。

112 |
113 | 114 | 117 |

该参数可指定任意数量的资源。但请注意,同一脚本下资源名不得重复。

118 |

资源将在安装脚本的时候下载一次,之后不会进行更新。

119 |

这些资源可以稍后通过 GM_getResourceURLGM_getResourceText 获取其内容或地址。

120 |
自从 GM 0.9.0, 如果 GM 发现 @resource 的值被更改后将尝试重新下载。
121 |
122 | 123 | 124 | 127 |

该值用于指定脚本执行的时机,可用的参数只能为 document-startdocument-end 两种。

128 |

Chrome 下的 TamperMonkey 还提供了 document-body 这一选项,但是 GM 官方文档找不到说明,最好避免使用。

129 |

如果不填写该值,GM 将采用 document-end 作为默认值。

130 | 131 |

检查脚本是否执行于 document-start,检查 document.readyState 的值即可:

132 |
if ('loading' == document.readyState) {
133 | 	alert("脚本执行于 document-start。");
134 | } else {
135 | 	alert("脚本当前的 document.readyState: " + document.readyState);
136 | }
137 |
138 | 139 | 141 |

该功能在 GM 1.0+ 已经被抛弃使用,后期的 GM 默认启用该功能。

142 |
// @unwrap
143 |

该元数据表示代码将不会使用 (function () { /* 代码 */ })(); 这样的形式执行,因此请注意不要在外部填写 return 语句。

144 |
-------------------------------------------------------------------------------- /doc/tutorial/other.html: -------------------------------------------------------------------------------- 1 |

JS 开发

2 | 8 | 9 |

CSS 样式

10 | 15 | 16 |

jQuery 手册

17 |
18 | jQuery 19 | DevDocs 20 |
21 | 22 |

为什么不推荐 W3School 作为学习资料? (全文)

23 |

简单来说有以下几点:

24 |
    25 |
  1. 资料更新缓慢,而且没有社区帮忙维护
  2. 26 |
  3. 参考资料来源不准确导致开发者浪费时间
  4. 27 |
  5. HTML5 一直都在进步,而 W3School 一直都是陈旧的例子用法。
  6. 28 |
  7. 最后: W3School 和 W3C 没有任何从属关系 (来源)
  8. 29 |
30 | -------------------------------------------------------------------------------- /doc/tutorial/publish.html: -------------------------------------------------------------------------------- 1 |

Gist

2 |

https://gist.github.com/

3 |

Gist 是 GitHub 提供的代码分享服务。Gist 文件可以重命名为 .user.js 结尾,并通过分享「Raw Link」实现一键安装脚本。

4 |

该站默认使用 HTTPS 协议。

5 | 6 |

Greasy Fork

7 |

https://greasyfork.org/

8 |

UserStyles 维护者开发,默认使用 HTTPS 协议。

9 |

其网站源码托管于 GitHub

10 | 11 |

OpenUserJS.org

12 |

https://openuserjs.org/

13 |

「一个使用 Node.js 构建的用户脚本源」。仅限 HTTPS 协议,其网站源码也托管于 GitHub

14 | 15 |

MonkeyGuts

16 |

https://monkeyguts.com/

17 |

「Monkey Guts 是一个全新的脚本源」。仅限 HTTPS 协议,网站目前处于闭源状态。

18 | 19 |

UserScripts.org

20 |

https://userscripts.org/

21 |

规模最大以及运行时间最长的用户脚本托管站点。HTTPS 可用但默认未启用。从 2014 年开始,因年久是修导致关站。

22 | 23 |

全网络

24 |

只要你的地址结尾为 .user.js 并能正常访问就能使用 GM 一键安装了。

-------------------------------------------------------------------------------- /doc/tutorial/warning.html: -------------------------------------------------------------------------------- 1 |

沙盒环境

2 |

在最初的 GM 插件设计中,GM 脚本被直接插入到页面并提供了 GM_ 系列函数的访问权限。

3 |

2005 年 7月,Mark Pilgrim 发现了 一个安全漏洞 —— 运行 GM 脚本的网站可以直接调用 GM_ 系列函数。

4 |

为了填补这一漏洞,GM 团队更改了设计理念,使用匿名函数包装脚本后执行,并提供 unsafeWindow 接口用于访问网页变量。

5 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{entry}} - {{cat}} - GM 开发手册 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 | 55 | 56 |
57 | 58 |
59 |
60 | 61 | 62 |
63 |

{{cat}}/{{entry}}GM 开发手册

64 | 65 |
66 |
67 |
68 |
69 |
70 | 71 |
72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: 2 | sass --scss --style compressed --no-cache res/App.scss res/App.css 3 | -mkdir build 4 | nodejs build.js 5 | # 压缩脚本, 详细日志请参考 build.log 6 | closure-compiler --compilation_level SIMPLE_OPTIMIZATIONS --js build/App.d.js --js_output_file build/App.js > build.log 2>&1 7 | rm build/App.d.js 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "buildSite", 3 | "description": "Build the site with minified css/html", 4 | "version": "1.0.0", 5 | "maintainers": [ 6 | { 7 | "name": "Jixun", 8 | "email": "jixun.moe@gmail.com", 9 | "web": "http://jixun.org/" 10 | } 11 | ], 12 | "dependencies": { 13 | "clean-css": "~2.1.8", 14 | "html-minifier": "~0.6.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /res/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve UserScript Chinese Dev. Document, by Jixun. 3 | */ 4 | /* global angular */ 5 | 6 | (function (window, Angular, $, _, $q, $scope, $state, $global) { 7 | 'use strict'; 8 | 9 | Angular 10 | .module ('gmDev', ['ui.router']) 11 | .directive ('api', ['$state', function ($state) { 12 | return { 13 | transclude: true, 14 | restrict: 'E', 15 | 16 | // 不需要 scope :3 17 | // scope: {}, 18 | compile: function ($element, tAttrs, transclude) { 19 | transclude ({}, function (clone) { 20 | var txt = $('
').append(clone).text(); 21 | 22 | $element.after($('').attr('href', $state.href ('doc', { 23 | cat: $element.attr('cat') || 'api', 24 | entry: $element.attr('entry') || txt 25 | })).text(txt)).remove(); 26 | }); 27 | } 28 | }; 29 | }]) 30 | .directive('tpl', function() { 31 | return { 32 | transclude: true, 33 | restrict: 'E', 34 | scope: {}, 35 | templateUrl: function(element, attrs) { 36 | return 'tpl/' + attrs.src + '.html'; 37 | }, 38 | controller:[$scope, '$transclude', '$sce', '$compile', 39 | function($scope, $transclude, $sce, $compile){ 40 | $transclude(function(clone){ 41 | $scope.$content = 42 | // Sign as trusted code. 43 | $sce.trustAsHtml( 44 | // Compile the content 45 | $compile(Angular.element('
').append(clone)[0].outerHTML) 46 | ($scope).html() 47 | ); 48 | }); 49 | }], 50 | link: function(scope, element, attrs) { 51 | scope.$split = function (str, what) { 52 | if (str) 53 | return str.split(what || ','); 54 | }; 55 | scope.$have = function (what) { 56 | return attrs.hasOwnProperty(what); 57 | }; 58 | for (var x in attrs) { 59 | if (attrs.hasOwnProperty(x) && x.indexOf('$')) { 60 | var attr = attrs[x]; 61 | if (!attr.indexOf('$')) { 62 | attr = scope.$eval(attr.slice(1)); 63 | } 64 | scope[x] = attr; 65 | } 66 | } 67 | } 68 | }; 69 | }) 70 | .run ([$global, function ($global) { 71 | var Nav = $global.Nav = { 72 | intro: { 73 | type: 0, // Hide Title 74 | title: '帮助', 75 | entries: { 76 | gmScript: '关于用户脚本', 77 | about: '关于该项目' 78 | } 79 | }, 80 | tutorial: { 81 | type: 1, // Normal one 82 | title: '开发教程', 83 | entries: { 84 | meta: '元数据', 85 | warning: '注意事项', 86 | other: '其它资料', 87 | publish: '脚本托管' 88 | } 89 | }, 90 | 91 | api: { 92 | type: 2, // URL = Name 93 | title: 'API 速查', 94 | list: [ 95 | "GM_info", 96 | 97 | "GM_addStyle", 98 | 99 | "GM_getValue", "GM_setValue", "GM_deleteValue", "GM_listValues", 100 | 101 | "GM_getResourceText", "GM_getResourceURL", 102 | 103 | "GM_log", "GM_openInTab", "GM_registerMenuCommand", 104 | "GM_setClipboard", "GM_xmlhttpRequest" 105 | ] 106 | } 107 | }; 108 | 109 | // Angular Sort the object auto 110 | $global.getKey = function (o) { 111 | if (!o) return []; 112 | return Object.keys(o); 113 | }; 114 | 115 | $global.$on('$stateChangeStart', function (e, curRoute, $param) { 116 | if (!Nav.hasOwnProperty($param.cat)) 117 | return ; 118 | 119 | var curCat = Nav[$param.cat]; 120 | $global.cat = curCat.title; 121 | 122 | if (curCat.type === 2) { 123 | $global.entry = $param.entry; 124 | } else { 125 | var curEntry = curCat.entries; 126 | if (!curEntry.hasOwnProperty($param.entry)) 127 | return ; 128 | 129 | $global.entry = curEntry[$param.entry]; 130 | } 131 | 132 | // Scroll page to the top. 133 | $(window).scrollTo (_('viewpt'), 800); 134 | }); 135 | }]).config (['$stateProvider', '$urlRouterProvider', function ($stateProv, $urlRouterProvider) { 136 | $urlRouterProvider.when ('', '/doc/intro/gmScript'); 137 | 138 | $stateProv.state ('doc', { 139 | url: '/doc/:cat/:entry', 140 | templateUrl: function ($param) { 141 | return 'doc/' + $param.cat + '/' + $param.entry + '.html'; 142 | } 143 | }); 144 | }]); 145 | 146 | 147 | }) (window, angular, jQuery, function ($) { 148 | return document.getElementById($); 149 | }, '$q', '$scope', '$state', '$rootScope'); 150 | -------------------------------------------------------------------------------- /res/App.scss: -------------------------------------------------------------------------------- 1 | // 默认字体配置,分别为 Ubuntu 微软正黑 微软雅黑 文泉驿微米黑 2 | $defaultFontConfig: Ubuntu, 'Microsoft JHengHei UI', 'Microsoft YaHei UI', 'Microsoft JHengHei', 'Microsoft YaHei', 'WenQuanYi MicroHei', sans-serif; 3 | 4 | body { 5 | font-family: $defaultFontConfig; 6 | font-size: 16px; 7 | overflow-y: scroll; 8 | } 9 | 10 | .alert { 11 | > h1, > h2, > h3, > h4, > h5, > h6 { 12 | margin-top: 0; 13 | } 14 | } 15 | 16 | .nav > li > a { 17 | padding: 3px 15px; 18 | } 19 | 20 | .text-ellipsis { 21 | overflow: hidden; 22 | text-overflow: ellipsis; 23 | } 24 | 25 | .panel-body { 26 | pre { 27 | // Fix for firefox (29.0) 28 | // When overflow set to auto, the transition does not work. 29 | overflow: initial; 30 | 31 | &:hover::before { 32 | color: #479BEC; 33 | opacity: .5; 34 | } 35 | 36 | &::before { 37 | content: '# 代码'; 38 | float: right; 39 | color: #0C70E8; 40 | transition: all .5s ; 41 | } 42 | } 43 | > h3 { 44 | border-bottom: 1px dashed #ccc; 45 | 46 | &:first-child { 47 | margin-top: 0; 48 | } 49 | 50 | &:hover::after { 51 | color: #ccc; 52 | padding-left: .5em; 53 | content: '¶'; 54 | } 55 | } 56 | } 57 | 58 | pre { 59 | tab-size: 4; 60 | 61 | &.sample, 62 | &.sample-good, 63 | &.sample-bad { 64 | border-left: 8px solid; 65 | border-color: #4D4D4D; 66 | } 67 | 68 | &.sample-good { 69 | border-color: #55DD8B; 70 | } 71 | 72 | &.sample-bad { 73 | border-color: #DD5555; 74 | } 75 | } 76 | 77 | dl { 78 | padding-left: .5em; 79 | border-left: 4px solid #55DD8B; 80 | } 81 | 82 | dt { 83 | margin-top: .5em; 84 | } 85 | dd > dl { 86 | margin-left: .5em; 87 | margin-bottom: 0; 88 | } 89 | 90 | 91 | @media (min-width: 768px) { 92 | .leftNav { 93 | height: auto; 94 | position: fixed; 95 | top: -1px; 96 | bottom: 0; 97 | margin-bottom: -1px; 98 | padding-top: 50px; 99 | > .leftNavContainer { 100 | overflow-y: auto; 101 | height: 100%; 102 | } 103 | } 104 | 105 | #searchAPI { 106 | // margin-bottom: .5em; 107 | position: fixed; 108 | width: initial; 109 | z-index: 9; 110 | top: .5em; 111 | } 112 | } 113 | 114 | .reset-count-arg { 115 | counter-reset: count-arg; 116 | } 117 | #pageBody { 118 | counter-reset: count-arg; 119 | 120 | .count-arg { 121 | counter-increment: count-arg; 122 | 123 | > dt::before { 124 | content: counter(count-arg, decimal) '. '; 125 | color: #999; 126 | font-size: 75%; 127 | } 128 | } 129 | } 130 | 131 | 132 | .text-indent { 133 | text-indent: 2em; 134 | } 135 | 136 | .text-normal { 137 | font-weight: normal; 138 | } 139 | 140 | .no-margin { 141 | margin: 0; 142 | } -------------------------------------------------------------------------------- /tpl/api.html: -------------------------------------------------------------------------------- 1 |

function {{foo}} ( 2 | 无参数 3 | {{$index?', ':''}}{{arg}} 4 | )

-------------------------------------------------------------------------------- /tpl/arg.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ arg }} 可选 ({{opt}})
3 |
4 |
类型: {{ type }}
5 |
6 |
7 |
-------------------------------------------------------------------------------- /tpl/define.html: -------------------------------------------------------------------------------- 1 |
项目: {{term}} 可选 ({{opt}})
2 |
3 |
类型: {{ type }}
4 |
5 |
-------------------------------------------------------------------------------- /tpl/deprecated.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /tpl/meta.html: -------------------------------------------------------------------------------- 1 |
2 |
@{{key}}
3 |
4 |
// @{{key}} {{code}}
5 |
6 |
7 |
-------------------------------------------------------------------------------- /tpl/snipset/gmAddStyle.html: -------------------------------------------------------------------------------- 1 |

不使用 API 实现该功能:

2 |
// 返回插入的 style 元素
3 | var myAddStyle = function (css) {
4 | 	var ret = document.createElement ('style');
5 | 	ret.textContent = css;
6 | 	(document.head || document.getElementsByTagName ('head')[0]).appendChild (ret);
7 | 	return ret;
8 | }
-------------------------------------------------------------------------------- /tpl/snipset/gmValue.html: -------------------------------------------------------------------------------- 1 |

储存、写入对象数据:

2 |
var GM_setObject = function (name, value) {
 3 | 	if (value instanceof Object) {
 4 | 		// 使用 JSON.stringify 将值转换为文本。
 5 | 		GM_setValue (name, JSON.stringify (value));
 6 | 	}
 7 | },  GM_getObject = function (name, default) {
 8 | 	try {
 9 | 		return JSON.parse (GM_getValue (name, '') || '{}');
10 | 	} catch (e) {
11 | 		// 如果抓取的数据有误报错就直接返回默认值。
12 | 		return default;
13 | 	}
14 | };
15 | 16 |

抓取所有储存的数据至对象数组:

17 |
var getAllKey = function () {
18 | 	var ret = {};
19 | 	GM_listValues().map(function (thing) {
20 | 		ret[thing] = GM_getValue (thing); // 值如果为对象数据需要手动调用 JSON.parse 解析。
21 | 	});
22 | };
23 | 24 |

清空所有储存的数据:

25 |
GM_listValues().map(GM_deleteValue);
26 | --------------------------------------------------------------------------------