-
Notifications
You must be signed in to change notification settings - Fork 2
/
scratch.js
181 lines (154 loc) · 4.93 KB
/
scratch.js
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
var engine = {
/*
* Language setting
* @notice: language pack should be placed under the same directory of scratch.js
* file with the path like ./lang/zh-cn.json. If not, change the path in the mode setting to yout personal defined path
*
*/
lang: navigator.language, // Use browser default language
/* Mode settings
* @param empty: What to output if no matching value is in language pack
* @param strict: Use only perfectly match language pack if set to true
* @param motion: Set to true so the page can be rendered plenty of times
* @param path: Path to the directory containing language packs
*
*/
mode: {
'empty': '',
'strict': true,
'motion': true,
'path': './lang/'
},
setEmpty: function(str='') {
this.mode.empty = str;
},
setStrict: function(bool=true) {
this.mode.strict = bool;
},
setMotion: function(bool=true, clear=false) {
this.mode.motion = bool;
if (clear) {
localStorage.removeItem('motion_path');
localStorage.removeItem('motion_stream');
}
},
setPath: function(str='./lang/') {
this.mode.path = str;
},
/*
* Search pattern
* @notice: strings matching this pattern will be replaced, if no corresponding value is in language pack, will be replaced with mode.empty
*
*/
pattern: {
'prefix': '{:',
'suffix': ':}'
},
setPrefix: function(str='{:') {
this.pattern.prefix = str;
},
setSuffix: function(str=':}') {
this.pattern.suffix = str;
},
/*
* Reset settings to default
*
*/
reset: function(reset_lang=true, reset_mode=true, reset_pattern=true) {
if (reset_lang) {
this.lang = navigator.language;
}
if (reset_mode) {
this.mode = {
'empty': '',
'strict': true,
'motion': true,
'path': './lang/'
};
}
if (reset_pattern) {
this.pattern = {
'prefix': '{:',
'suffix': ':}'
};
}
},
defaultCallback: function() {
console.info('Scratch: no external callback called, process done');
},
/*
* Execute function, nice and easy
* @notice: if you're using some kind of front-end framework, you might use callback to update DOM after scratch's render process
*
*/
scratch: function(lang=this.lang, callback=this.defaultCallback, pattern=this.pattern, mode=this.mode) {
// Get corresponding language pack
var lang_path = mode.path + lang.toLowerCase() + '.json';
var request = new XMLHttpRequest();
request.open('GET', lang_path);
// Get status code
request.onload = function() {
if (this.status == 404) {
if (mode.strict) {
console.error('Scratch: No matching language pack, exit');
console.info('Scratch: Currently running under strict mode, you might want to change it by \'engine.setStrict(false)\'');
}
else if (!mode.strict) { // Under develop
console.warn('Scratch: No matching language pack, finding other packs');
console.error('Scratch: Function under develop, exit');
}
return false;
}
// Pack exists, ready for render
else if (this.status == 200) {
var data = JSON.parse(request.responseText);
var stream = document.documentElement.innerHTML;
// Check motion mode
if (mode.motion) {
console.info('Scratch: Motion mode enabled. To disable it, use \'engine.setMotion(false)\'');
var current_path = location.pathname;
// Page not stored before
if (localStorage.motion_path === undefined || localStorage.motion_path != current_path) {
localStorage.motion_path = current_path;
localStorage.motion_stream = stream;
}
// Stored before
else {
stream = localStorage.motion_stream;
}
}
// Loop for replacements
var prev = 0,lat = 0;
while(true) {
// Fall back
lat = prev;
// Search for pattern
prev = stream.indexOf(pattern.prefix, lat);
lat = stream.indexOf(pattern.suffix, prev);
// Cannot found matching values
if (prev == -1 || lat == -1) {
break;
}
// Find and replace
var tag = stream.slice(prev + pattern.prefix.length, lat).replace(/\s+/g,''); // Remove spaces
// Tag not in pack
if (data[tag] === undefined) {
stream = stream.slice(0, prev) + mode.empty + stream.slice(lat + pattern.suffix.length);
}
else {
stream = stream.slice(0, prev) + data[tag] + stream.slice(lat + pattern.suffix.length);
}
}
document.documentElement.innerHTML = stream; // Write back
callback(); // Callback
return true;
}
else {
console.error('Scratch: HTTP error code ' + this.status + ', exit');
return false;
}
}
request.send(null); // Ajax send
return true;
}
};