amWiki.search.worker.js
8.79 KB
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* amWiki Web端 - 搜索计算子进程模块
* @author Tevin
*/
(function (self) {
'use strict';
//通过 jQuery 检查判断是否处于子进程工作
var atWorker = typeof self.jQuery == 'undefined';
(function () {
/**
* 搜索计算器
* @constructor
*/
var Searcher = function () {
//文档存储
this._documents = null;
//搜索处理结果
this._processing = {};
//设置
this._data = {
//标题命中得分
titleScore: 100,
//接口地址命中得分
apiScore: 50,
//单次内容命中得分
textScore: 5
}
};
//初始文档
Searcher.prototype.initDocs = function (docs) {
this._documents = atWorker ? docs : JSON.parse(JSON.stringify(docs));
for (var id in this._documents) {
if (this._documents.hasOwnProperty(id)) {
this._preDoc(this._documents[id]);
}
}
};
//文档预处理
Searcher.prototype._preDoc = function (doc) {
doc.content = doc.content
.replace(/^\s+|\s+$/g, '')
//分离h1标题
.replace(/^#\s?(.*?)[\r|\n]/, function (match, s1) {
doc.title = s1;
return '';
})
//分离测试文档请求地址
.replace(/([^#]#{3} *请求地址[\n\r]{1,4})([-\w:\/\.]+?)[\n\r]{1,}(#{3} *请求类型[\s\S]+?#{3} *请求参数)/,
function (match, s1, s2, s3) {
doc.api = s2;
return s1 + s3;
})
//清除 Markdown 标题标记
.replace(/#{1,6}(.*?)#{0,6}\s*[\r\n]/g, '$1')
//清除 Markdown 强调斜体删除线标记
.replace(/[_\*~]{1,2}(.*?)[_\*~]{1,2}/g, '$1')
//直接删除 Markdown 图片
.replace(/!\[.*?]\(.*?\)/g, '')
//清除 Markdown 链接标记,还原为显示文本
.replace(/\[(.*?)]\(.*?\)/g, '$1')
//清除 Markdown 代码段标记
.replace(/`{3}.*?[\n\r]([\s\S]*?)`{3}/g, '$1')
//清除 Markdown 代码标记
.replace(/`(.*?)`/g, '$1')
//直接删除所有 html 标签
.replace(/<.+?>/g, '')
//清除 Markdown 引用标记
.replace(/> *(.+?)[n\r]/g, '$1')
//清除 Markdown 分割线标记
.replace(/-{3,} *[\n\r]/g, '')
//清除 Markdown 表格标记
.replace(/(\|.*?[\n\r]{1,2}){3,}/g, function (match) {
return match.replace(/\|.*?[\n\r]{1,2}/g, function (match) {
if (match.indexOf('---') >= 0) {
return '';
} else {
return match.replace(/\|/g, '');
}
});
})
//转换一个空白符为一空格
.replace(/[\n\r\t]/g, ' ')
//合并多个空白符为一个空格
.replace(/\s{2,}/g, ' ');
};
//给中转处理添加属性
Searcher.prototype._addPorcessing = function (id, key, value) {
//如果不存在此id则创建
if (typeof this._processing[id] == 'undefined') {
this._processing[id] = {};
this._processing[id][key] = value;
}
//如果存在此id
else {
//如果不存在此属性,直接赋值
if (typeof this._processing[id][key] == 'undefined') {
this._processing[id][key] = value;
}
//如果存在此属性,则相加(仅得分一项)
else {
this._processing[id][key] += value;
}
}
};
//匹配搜索词与得分计算
Searcher.prototype.matchWords = function (words) {
var wordsReg = new RegExp(words, 'gi');
for (var id in this._documents) {
if (this._documents.hasOwnProperty(id)) {
//标题命中
if (this._documents[id].title) {
var titleMatch = this._documents[id].title.match(wordsReg);
if (titleMatch && titleMatch.length > 0) {
var title = this._documents[id].title.replace(wordsReg, function (match) {
return '<mark>' + match + '</mark>';
});
this._addPorcessing(id, 'title', title);
this._addPorcessing(id, 'score', this._data.titleScore);
}
}
//接口地址命中
if (this._documents[id].api) {
var apiMatch = this._documents[id].api.match(wordsReg);
if (apiMatch && apiMatch.length > 0) {
var api = '<p class="p1"><em>接口</em>' +
this._documents[id].api.replace(wordsReg, function (match) {
return '<mark>' + match + '</mark>';
}) + '</p>';
this._addPorcessing(id, 'api', api);
this._addPorcessing(id, 'score', this._data.apiScore);
}
}
//内容命中
var contentMatch = this._documents[id].content.match(new RegExp('.{0,15}' + words + '.{0,30}', 'gi'));
if (contentMatch) {
var content = '<p>';
for (var i = 0, item; item = contentMatch[i]; i++) {
if (i < 2) {
content += item.replace(wordsReg, function (match) {
return '<mark>' + match + '</mark>';
}) + '... ';
}
}
content += '</p>';
this._addPorcessing(id, 'content', content);
this._addPorcessing(id, 'score', contentMatch.length * this._data.textScore);
}
}
}
this._auxiliary();
};
//辅助得分
Searcher.prototype._auxiliary = function () {
};
//排序与属性补齐
Searcher.prototype._sortByScore = function () {
var list = [];
for (var id in this._processing) {
if (this._processing.hasOwnProperty(id)) {
if (typeof this._processing[id].title == 'undefined') {
this._processing[id].title = this._documents[id].title ? this._documents[id].title : '';
}
if (typeof this._processing[id].api == 'undefined') {
this._processing[id].api = '';
}
if (typeof this._processing[id].content == 'undefined') {
this._processing[id].content = '<p>' + this._documents[id].content.substr(0, 45) + '...</p>';
}
this._processing[id].path = this._documents[id].uri;
this._processing[id].timestamp = this._documents[id].timestamp;
list.push(this._processing[id]);
}
}
list.sort(function (a, b) {
return a.score > b.score ? -1 : 1;
});
return list;
};
//获取结果
Searcher.prototype.getResult = function () {
return this._sortByScore();
};
//作为子进程加载时,仅子进程内有效
//作为全局加载时,全局有效
return this.AWSearcher = Searcher;
}).call(self);
//作为子进程工作时,通过 message 通讯工作
if (atWorker) {
//计算器
var searcher = new self.AWSearcher();
self.onmessage = function (event) {
var data = event.data;
if (data.type == 'searcher:docs') {
searcher.initDocs(data.docs);
self.postMessage({type: 'searcher:ready'});
} else if (data.type == 'searcher:search') {
searcher.matchWords(data.words);
self.postMessage({type: 'searcher:result', result: searcher.getResult()});
}
};
self.postMessage({type: 'searcher:loaded'});
}
})(self);