-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
304 lines (282 loc) · 9.62 KB
/
index.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
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
'use strict';
/*
go to previous/next 'page'
@isNext - Boolean value
@rows - Number of rows in a 'page' to scroll
*/
let gotoPage = (isNext, rows) => {
const direction = isNext ? 'next' : 'prev';
const buttons = {
prev: document.getElementById('decrementPage') || document.getElementsByClassName('vertical-scrollbar-up-button scrollbar-button-enabled')[0], // get a previous page button from either old or new interface
next: document.getElementById('incrementPage') || document.getElementsByClassName('vertical-scrollbar-down-button scrollbar-button-enabled')[0], // get a next page button handler from either old or new interface
};
const quasiClick = (node, evType) => {
let clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent(evType, true, true);
node.dispatchEvent(clickEvent);
};
if (buttons[direction]) {
// the action does the job for 'proper pages' (old interface)
quasiClick(buttons[direction], 'click');
// the action does the job for 'infinite pages' (new interface)
if (!rows) { rows = 20; }
for (let i = 0; i < rows; i++) {
quasiClick(buttons[direction], 'mousedown');
quasiClick(buttons[direction], 'mouseup');
}
} else {
console.log('Sorry, no page to go');
}
};
/*
go to the next segment missing translation or not confirmed yet
@isNext - Boolean value
*/
let gotoEmpty = (isNext) => {
let editable = $('.status-cell:not(.confirmed):not(.r1confirmed):not(.r2confirmed):not(:has(a.locked))').prev('.translated-segment-grid').parent('tr:not(.lock):not(.not-loaded-row)');
if (!editable.length) {
gotoPage(isNext);
setTimeout(() => {memoq.nextEmpty()}, 400);
} else {
editable[0].scrollIntoView(true);
console.log('Found a result:', editable[0]);
// editable[0].click();
}
};
/*
use one of the TM suggestions
@choice - row number to choose from a TM suggestion list
*/
let useTm = (choice) => {
let suggestions = $('#resultsList tr');
if (!suggestions.length || !choice || isNaN(choice)) { return; } // no TM suggestions or choice is invalid
choice = !choice ? 0 : Number(choice) - 1; // use the first suggestion available on the list
$(suggestions[choice]).dblclick();
};
/*
gets parameters (like string id, character limit, etc.)
returns an object with parameters
@key - optional key to return a parameter only
*/
let getParams = (key) => {
// if parameters are stored in a comment
let commentString = $('div#comment ul li.info span.comment b span').text();
// ea format
let params = {}; // parsed string with parameters
if (commentString) {
let a = commentString.slice(6, -1); // remove redundant characters at the beginning and the end of the string in globaloc format
let b = a.split('||');
b.filter(function (el) {
let a = el.trim();
let b = el.split(':');
if (b.length > 1) {
params[b[0].trim()] = b[1].trim();
}
});
}
if (key) { return params[key]; }
return params;
};
/*
gets the source string and returns either element (el === true) or its text (el !== true)
@el - switch between element (true) and text (false)
@src - switch between original (true) and translation (false)
*/
const getSource = (el, src) => {
const elem = (src && $('.focused.editor-cell').parent('.active').children('.original-segment-grid')) || $('.focused.editor-cell').parent('.active').children('.translated-segment-grid');
if (el) {
return elem;
} return elem.text();
};
/*
gets length of an element
Returns the number or 'n/a'
@el - element to get the length of
*/
const getLength = (el) => {
if (el) {
return el.length;
}
return 'n/a';
};
/*
checks against known set of rules and returns an array of matches
@data - a string to search in
@rules - user defined set of regex to check the data string against
*/
const listMatches = (data, rules) => {
if (!data) { return []; }
const RULES = rules || [ // ...or default set
'\\${[\\w\\[\\]\\s]+}', // ea NBA LIVE: ${OVR}, ${RES2}, ${fast furious}, ${[0]}, etc.
'\\\\n', // ea NBA LIVE: \n
'%%\\w+%%', // eden games F1
'</?[a-zA-Z0-9=]+>', // <a>, </ab>, <23>, </g45>, <foo=5>, etc.
];
return data.match(new RegExp(RULES.join('|'), 'g')) || [];
};
/*
takes two arrays as its arguments and returns an object with two arrays of elements missing from either and an array of shared
@set1 - array to be compared
@set2 - another array to be compared
*/
const diffArray = (set1, set2) => {
let shared = [];
const diff = set2.slice();
const diff2 = set1.filter((el) => {
if (diff.indexOf(el) >= 0) {
shared.push(diff.splice(diff.indexOf(el), 1));
return false;
}
return true;
});
return {
missing: diff2 || [], // elements missing from set1
redundant: diff || [], // elements missing from set2
shared: shared // elements shared between the two
};
};
/*
inserts text to an element in focus
@input - element to be updated with new text
@text - text to insert
*/
const insertAtCursor = (input, text) => {
// const inpt = getSource(true, false);
getSource(true, false).focus();
// console.log(`input: ${inpt}, text: ${text}`);
// inpt.focus(); // make sure we have focus in the right input
document.execCommand('insertText', false, text);
// see https://www.everythingfrontend.com/posts/insert-text-into-textarea-at-cursor-position.html
};
let charsLimit = () => {
let params = getParams();
if (params.MAX_LENGTH > 0) {
// console.log('limit:', params.MAX_LENGTH);
// console.log('string id:', params['STRING ID']);
return params.MAX_LENGTH;
} else { return ''; }
// return params.MAX_LENGTH > 0 ? params.MAX_LENGTH : '';
};
/*
describes a global object with methods available
*/
let memoq = {
prevPage: () => gotoPage(false),
nextPage: () => gotoPage(true),
prevEmpty: () => gotoEmpty(false),
nextEmpty: () => gotoEmpty(true),
useTm: useTm,
limit: charsLimit,
};
/*
adds actions for the menu:
draggable - the menu could be dragged around
offset - sets offset for the menu
*/
let menuActions = {
draggable: () => {
$('#memoqwtools').draggable({
handle: '#memoqwtools-handle',
stop: (event, ui) => {
// console.log('dragging has stopped!');
// chrome.storage.local.set({'position': new Date()}, () => {console.log('Saved to local storage')});
// console.log('ui:', ui);
}
});
},
offset: () => {
let offset = $('td.editor-cell.focused').offset(); // edited block's offset
let height = $('td.editor-cell.focused').outerHeight(); // edited block's height
$('#memoqwtools:not(.sticky)').offset({
'top': offset.top + height,
'left': offset.left
});
},
};
document.onkeyup = (obj) => {
if (!obj.code) { return; } // no actual key code is given
const createButton = (value, action) => {
// const el = $('#memoqwtools-vars')[0];
const el = document.createElement('button');
const text = document.createTextNode(value);
el.name = value;
el.onclick = function(action) { insertAtCursor(false, value); };
// console.log(`el: ${el}, text: ${text}`);
el.appendChild(text);
return el;
};
/*
@values - array of values to
@names - optional array of names to be used
*/
const createInserts = (values, names) => {
if (!values) { return; }
if (!names) { names = values.slice(); }
// an element insert buttons to be appended to
const parent = document.getElementById('memoqwtools-vars');
// console.log(`values: ${values}`);
values.forEach((el, ind) => {
// console.log(`value: ${el}, name: ${names[ind]}`);
const btn = createButton(names[ind] || el, el);
// console.log(`btn: ${btn}, parent: ${parent}`);
parent.appendChild(btn);
});
// return parent;
};
/*
shows variables in a source segment and in a translated segment not matching each other
*/
const showVars = (div) => {
const matchVars = diffArray(listMatches(getSource(false, true)), listMatches(getSource()));
if (matchVars.missing.length !== 0 || matchVars.redundant.length !== 0) {
// createInserts(matchVars.missing);
// const buttons = createInserts(matchVars.missing);
// console.log('buttons:', buttons);
// const missing = document.createElement('span');
// missing.class = 'memoqwtools-varsmissing';
// missing.innerText = matchVars.missing;
// const redundant = document.createElement('span');
// redundant.class = 'memoqwtools-varsredundant';
// redundant.innerText = matchVars.redundant;
// div.appendChild(missing);
// div.appendChild(redundant);
while (div.firstChild) {
div.removeChild(div.firstChild);
}
['missing', 'redundant'].forEach((name) => {
const el = document.createElement('span');
el.className = 'memoqwtools-vars' + name;
el.innerText = matchVars[name];
div.appendChild(el);
});
// div.innerText = `<span class='memoqwtools-varsmissing'>${matchVars.missing}</span> > > | < < <span class='memoqwtools-varsredundant'>${matchVars.redundant}</span>`;
} else { div.innerText = ''; }
return div.innerText;
};
/*
shows character limits and segment length and handles them
@lngth - element containing segment length
@lmt - element containing character limit for a segment
@edtr - element containting text of a segment
*/
const showLimits = (lngth, limit, edtr) => {
const len = getLength(getSource()) || 0;
const lmt = charsLimit() || 'n/a';
const src = getLength(getSource(false, true));
const errClass = 'limit-exceeded';
lngth.innerText = len;
limit.innerText = `${src} (${lmt})`;
if (lmt < len) {
lngth.classList.add(errClass);
edtr.classList.add(errClass);
} else {
lngth.classList.remove(errClass);
edtr.classList.remove(errClass);
}
};
showLimits($('#memoqwtools-length')[0], $('#memoqwtools-limit')[0], $('.focused.editor-cell')[0]);
showVars($('#memoqwtools-vars')[0]);
$('#memoqwtools-stringId')[0].innerText = getParams('STRING ID');
menuActions.offset();
menuActions.draggable();
};