· 9 years ago · Nov 16, 2016, 08:36 PM
1// ==UserScript==
2// @name FleetLogBeautifier
3// @namespace kelder.ogame.org
4// @description Fleetlog parser
5// @include https://*.ogame.*/game/admin2/flottenlog.php?session=*&uid=*&list=*
6// @include https://*.ogame.*/game/admin2/flottenlog.php?session=*&showplanet=*
7// @version 2013.3.17
8// @grant none
9// ==/UserScript==
10//** Copyright © 2008 by Kelder for ogame.org community. **
11//** May only be used by ogame staff. If you are not ogame staff, then delete this script immediately. **
12//** Obtain permission before redistributing. **
13// ******** CONSTANTS ********
14// Config settings can be set from a javascript console while logged into the AT:
15// Just type localStorage['COMBINE_FLEETS_AND_RESOURCES'] = 1 to set the option.
16// localStorage['COMBINE_FLEETS_AND_RESOURCES'] boolean (0 = false, 1 = true)
17// localStorage['externalCSS'] string (0 = off, else 'http://<yourCSSfilehere>' )
18// localStorage['DATE_FORMAT'] string (default = '%d/%m %H:%M:%S' )
19// -> see http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html for info on format.
20(function() {
21var LNG_START_BUTTON = 'Beautify!';
22// The function that contains all the REAL stuff to parse logs and display them
23function DoModify() {
24var CONV = new Array();
25var CLS = new Array();
26// ***************
27// LANGUAGE CONFIG
28// ***************
29// Mission names (do not have to be exact like in admin tool)
30var LNG_ESPIONAGE = 'Espionage';
31var LNG_ATTACK = 'Attack';
32var LNG_TRANSPORT = 'Transport';
33var LNG_HARVEST = 'Harvest';
34var LNG_DEPLOYMENT = 'Deployment';
35var LNG_EXPEDITION = 'Expedition';
36var LNG_ACS_ATTACK = 'ACS Attack';
37var LNG_COLONIZATION = 'Colonization';
38var LNG_MOON_DESTRUCTION = 'Moon Destruction';
39var LNG_ACS_DEFEND = 'ACS Defend';
40var LNG_IPM = 'IPM';
41// table header text
42var LNG_HDR_MISSION = 'Mission';
43var LNG_HDR_PLAYER1 = 'Player 1';
44var LNG_HDR_PLAYER2 = 'Player 2';
45var LNG_HDR_ORIGIN = 'From';
46var LNG_HDR_DESTINATION = 'To';
47var LNG_HDR_LAUNCH = 'Start';
48var LNG_HDR_ARRIVAL = 'Arrival';
49var LNG_HDR_RESOURCES = 'Res';
50var LNG_HDR_FLEET = 'Fleet';
51var LNG_HDR_RETURN_TIME = 'Return';
52var LNG_HDR_RETURN_RES = 'Res';
53var LNG_HDR_RETURN_FLEET = 'Fleet';
54// coordinates stuff
55var LNG_SHORT_DF = 'D';
56var LNG_SHORT_MOON = 'M';
57var LNG_SHORT_PLANET = 'P';
58var LNG_NO_COORDS = '?:?:?';
59
60// for each CSS class name give the label of the button
61var mission = {
62 Att: 'Attack',
63 Esp: 'Espionage',
64 Exp: 'Exp',
65 Own: 'Own',
66 Tra: 'Transport',
67 Dep: 'Deploy',
68 Col: 'Colonize',
69 Hrv: 'Harvest',
70 ACS: 'any ACS',
71 Des: 'Moon destr',
72 Def: 'ACS Def',
73 Ipm: 'IPM',
74 returns: 'Recalled'
75};
76var LNG_OLD_LOGS_BUTTON = 'Old logs';
77// misc+missions
78var LNG_CONV_DF = /^debris field/;
79var LNG_CONV_MOON = /\(M\) \[/;
80//Copy EXACTLY like it appears in admin tool
81var LNG_FLEET_ARRIVES_TO_TARGET = 'Fleet Arrives to Target';
82var LNG_SPACE_PLAYER_NAME = 'space';
83var LNG_UNKNOWN_PLAYER_NAME = 'unknown';
84var LNG_UNKNOWN_PLANET_NAME = 'unknown';
85// Copy what's between CONV[' and '] = EXACTLY like it appears in admin tool
86// res
87CONV['Metal'] = 'M';
88CONV['Crystal'] = 'C';
89CONV['Deuterium'] = 'D';
90// ships
91CONV['Small Cargo'] = 'SC';
92CONV['Large Cargo'] = 'LC';
93CONV['Light Fighter'] = 'LF';
94CONV['Heavy Fighter'] = 'HF';
95CONV['Cruiser'] = 'CR';
96CONV['Espionage Probe'] = 'ESP';
97CONV['Battleship'] = 'BS';
98CONV['Bomber'] = 'BOM';
99CONV['Battlecruiser'] = 'BC';
100CONV['Destroyer'] = 'DES';
101CONV['Deathstar'] = 'RIP';
102CONV['Colony Ship'] = 'COL';
103CONV['Recycler'] = 'REC';
104CONV['Solar Sattellite'] = 'SAT';
105// END OF CONFIG
106// *********************
107// no changes below here
108//chrome additions
109if (Date.prototype.toLocaleFormat == null) {
110 function pad(n) { return n < 10 ? '0' + n : n; }
111 Date.prototype.toLocaleFormat = function() {
112 return this.getFullYear() + '-' + pad(this.getMonth()+1) + '-' + pad(this.getDate()) + ' '
113 + pad(this.getHours()) + ':' + pad(this.getMinutes()) + ':' + pad(this.getSeconds()); };
114}
115//end chrome additions
116getValue = function(name, defaultValue) {
117 var value = localStorage.getItem(name);
118 if (value === undefined || value == null) {
119 return defaultValue;
120 }
121 return value;
122}
123var COMBINE_FLEETS_AND_RESOURCES = getValue('COMBINE_FLEETS_AND_RESOURCES', false);
124var LNG_DATE_FORMAT = getValue('DATE_FORMAT','%d/%m %H:%M:%S');
125var ORIG_DATE_FORMAT = getValue('ORIG_DATE_FORMAT','%Y-%m-%d %H:%M:%S');
126var OPT_EXTERNAL_CSS = getValue('externalCSS',false);
127var UNI_SPEED = getValue(window.location.hostname + '_UNI_SPEED',1);
128if (isNaN(UNI_SPEED)) { UNI_SPEED = 1; }
129// missions (CLS means CSS class for that mission log)
130CLS[LNG_ATTACK] = 'Att ';
131CLS[LNG_ACS_ATTACK] = 'Att ACS ';
132CLS[LNG_TRANSPORT] = 'Tra ';
133CLS[LNG_DEPLOYMENT] = 'Dep ';
134CLS[LNG_ACS_DEFEND] = 'Def ACS ';
135CLS[LNG_ESPIONAGE] = 'Esp ';
136CLS[LNG_COLONIZATION] = 'Col ';
137CLS[LNG_HARVEST] = 'Hrv ';
138CLS[LNG_MOON_DESTRUCTION] = 'Des ';
139CLS[LNG_IPM] = 'Ipm ';
140CLS[LNG_EXPEDITION] = 'Exp ';
141// use mission number to find short name. the 1 in "Attack 1" up to " 15"
142var CONV_SHORT_MISSION = [0,
143 LNG_ATTACK, LNG_ACS_ATTACK, LNG_TRANSPORT, LNG_DEPLOYMENT,
144 LNG_ACS_DEFEND, LNG_ESPIONAGE, LNG_COLONIZATION, LNG_HARVEST,
145 LNG_MOON_DESTRUCTION, LNG_IPM, 0, 0,
146 0, 0, LNG_EXPEDITION];
147// contains the CSS class names to put under the buttons
148var missionButtons = [ 'Att', 'Esp', 'Own', 'Tra', 'Dep', 'Col', 'Hrv', 'ACS', 'Exp', 'Des', 'Def', 'Ipm', 'returns'];
149var head = document.getElementsByTagName('head')[0];
150// load external css
151if (OPT_EXTERNAL_CSS) { createEl({n:'link',a:{rel:'stylesheet', '@type': 'text/css', href: OPT_EXTERNAL_CSS}}, head);
152} else { createStyle('flb_extCSS','.Esp {background-color:#8F813D}.Att{background-color:#8F3D3D}.Att.ACS{background-color:#8F3D5A}.Des{background-color:#AF1B94}.Def.ACS{background-color:#8F553C}.Ipm{background-color:#8F6C3D}.Tra{background-color:#3C5A8F}.Tra.Own{background-color:#3E3C8F}.Dep{background-color:#623C8F}.Col{background-color:#418F3C}.Exp{background-color:#999}.Hrv{background-color:#3C8F6B}.returns{color:black}.arrived{color:white}.res .tp{color:#FFF;font-weight:bold;margin-right:.2em}.fleet .tp{color:#FF9;font-weight:bold;margin-right:.2em; font-size:.8em}.res.return .tp{color:#FFF}.fleet.return .tp{color:#BFB}.res .am,.fleet .am{color:#EEE;margin-right:1em}.score{font-size:70%;color:#9FF}.state{color:#FF4}td.player{cursor:pointer}#GM_menu_middle{position:absolute;top:140px;left:240px;padding:5px;border:1px solid orange;max-width:650px}#GM_menu_bar{position:fixed;top:0px;left:10px;padding:3px;border:1px solid orange;background-color:black;z-index:5}.DisplayButton.GM__HIDDEN,.FilterButton.GM__HIDDEN{color:#F33}.DisplayButton.GM__SHOW_ONLY,.FilterButton.GM__SHOW_ONLY{color:#3FF}.FilterButton{margin:3px;padding:1px;border:1px solid #666;display:inline-block;text-align:center;min-width:9em}.FilterButton .score{display:none}span.res,span.fleet{display:inline-block}body,table,td{font-size:10pt}#GM_fleetlog{position:absolute;top:500px;left:10px;padding-bottom:20px;z-index:2}#GM_fleetlog td{background-image:none}.DisplayButton{margin-right:1em}.GM__MINIMIZED div.fleet,.GM__MINIMIZED div.res {display:inline}tr.GM__MINIMIZED td{ font-size:1px;padding:0;margin:0;height:4px;}.st{text-decoration:line-through}.empty{font-size:.8em}#OGB_DISP_UNI_SPEED{width:1.8em;font-size:80%}td.p2{cursor:pointer}td.mission{cursor:row-resize}th.t1,th.t2,th.t3{width:6.2em}.GM_TextBox {z-index:3;min-width:700px}'); }
153function createStyle(id, content) { //custom GM_addStyle to have id for later removal
154 return createEl({n: 'style', a: {type:'text/css', '@id':id, textContent:content}}, head);
155}
156
157document.getElementById('GM_ActivateButton').parentNode.removeChild(document.getElementById('GM_ActivateButton'));
158var PLAYERS = new Object();
159
160function Player(td) {
161 if (arguments.length > 1) {
162 this.name = arguments[1];
163 this.uid = arguments[2];
164 this.score = 0;
165 this.state = '';
166 this.dom = createEl( // trg attribute is to know which uid to toggle when clicked
167 {n: 'td', a: {'@class' : 'st player', '@trg': 'u' + this.uid, textContent: this.name}}
168 , null);
169 return;
170 }
171 this.uid = td.firstChild.href.replace( /^.+uid=(\d+).*$/, '$1');
172 this.name = td.firstChild.firstChild.nodeValue;
173 if (this.name == null) this.name = td.firstChild.firstChild.firstChild.nodeValue; // font tag around name
174 if (this.name == LNG_UNKNOWN_PLAYER_NAME) {
175 this.name = 'uid ' + this.uid;
176 this.score = '?';
177 this.state = '';
178 this.dom = createEl(
179 {n: 'td', a: {'@class' : 'st player', '@trg': 'u' + this.uid, textContent: this.name}}
180 , null);
181 return;
182 }
183 this.state = '';
184 if (td.childNodes.length) {
185 var i = td.childNodes.length - 1;
186 while ((td.childNodes.item(i)) && (td.childNodes.item(i).nodeType != 3)) --i;
187 this.score = ''+td.childNodes.item(i).nodeValue.match(/\d[\d+\.]*/);
188 i = 2;
189 while (td.childNodes.item(++i)) {
190 if (td.childNodes.item(i).tagName == 'FONT') this.state += td.childNodes.item(i).firstChild.nodeValue;
191 }
192 } else { this.score = 0; }
193 if (this.state == '') {
194 this.dom = createEl( // removed: '@class': 'u1',
195 // {n: 'td', a: {'@trg': 'u' + this.uid, textContent: this.name + ' (' + this.score + ')'}}
196 {n: 'td', a: {'@class': 'player', '@trg': 'u' + this.uid },
197 c: [ this.name, {n:'span', a: {'@class': 'score', textContent: ' ' + this.score}} ]}
198 , null);
199 } else {
200 this.dom = createEl( // removed: '@class': 'u1',
201 // {n: 'td', a: {'@trg': 'u' + this.uid, textContent: this.name + this.state + ' (' + this.score + ')'}}
202 {n: 'td', a: {'@class': this.state + ' player', '@trg': 'u' + this.uid },
203 c: [ this.name,
204 {n:'span', a: {'@class': 'state ' + this.state, textContent: ' (' + this.state + ')'}},
205 {n:'span', a: {'@class': 'score', textContent: ' ' + this.score}} ]}
206 , null);
207 }
208}
209Player.prototype.domElem = function() { return this.dom.cloneNode(true); }
210PLAYERS['u0'] = new Player(null, '*'+LNG_UNKNOWN_PLAYER_NAME+'*', 0);
211PLAYERS['u99999'] = new Player(null, LNG_SPACE_PLAYER_NAME, 99999);
212function getPlayer(td) {
213 if (td.firstChild.nodeName == 'A') {
214 //find uid
215 var uid = td.firstChild.href.replace( /^.+uid=(\d+).*$/, "$1");
216 return PLAYERS['u'+uid] || (PLAYERS['u'+uid] = new Player(td));
217 } else return PLAYERS['u0'];
218}
219
220// show or hide all elements of a certain class (for menu buttons)
221function toggleDisplay(evt) {
222 var cls = this.getAttribute('trg');
223 var e = document.getElementById('GM__STYLE_' + cls);
224 if (e) {
225 e.parentNode.removeChild(e);
226 this.className = this.className.replace(/\bGM__HIDDEN\b|\bGM__SHOW_ONLY\b/,'');
227 } else { var s; // create style
228 // specialcase the Old Logs button...
229 if (cls == 'GM_TextBox') { this.className += ' GM__HIDDEN'; s = 'div.GM_TextBox {display:none;}';
230 } else if (evt.ctrlKey) {
231 s = 'table tr.'+cls+'{display:table-row;}tr.arrived,tr.returns{display:none;}';
232 this.className += ' GM__SHOW_ONLY';
233 } else {
234 s = 'table#newTable tr.'+cls+'{display:none;}';
235 this.className += ' GM__HIDDEN';
236 }
237 createStyle('GM__STYLE_' + cls, s);
238 }
239}
240
241// show or hide all elements of a certain class (for players/planets, creates click box)
242function toggleDisplay2(evt,td) {
243 if (!td) td = this;
244 var cls = td.getAttribute('trg');
245 var e = document.getElementById('GM__STYLE_' + cls);
246 if (e) {
247 e.parentNode.removeChild(e);
248 e = document.getElementById('GM__FILTER_' + cls);
249 if (e) { e.parentNode.removeChild(e); }
250 }
251 else { var s; // create style
252 e = createEl({n: 'span', a: { '@id': 'GM__FILTER_' + cls, '@class': 'FilterButton ',
253 '@trg': cls, innerHTML: td.innerHTML }},menu_mid_div);
254 e.addEventListener('click', toggleDisplay2, true);
255 if (evt.ctrlKey) {
256 s = 'tr.arrived.'+cls+',tr.returns.'+cls+'{display:table-row;}tr.arrived,tr.returns{display:none;}';
257 e.className += ' GM__SHOW_ONLY';
258 } else {
259 s = 'table#newTable tr.'+cls+'{display:none;}';
260 e.className += ' GM__HIDDEN';
261 }
262 createStyle('GM__STYLE_' + cls, s);
263 }
264}
265
266// minimizes parent
267function minimizeDisplay(td) {
268 var p = td.parentNode;
269 if (p.className.match(/\bGM__MINIMIZED\b/)) p.className = p.className.replace(/ ?\bGM__MINIMIZED\b/,'')
270 else p.className += ' GM__MINIMIZED';
271}
272
273// add resources or fleet to a TD container. Create new container if needed
274function stuffConvert(res, isfleet, isreturn, container) {
275 var f;
276 if (isfleet) f = 'fleet';
277 else f = 'res';
278 if (isreturn) f += ' return';
279 var parts = res.match(/(?:[^\s:]+(?: [^\s:]+)*) : [.\d]+/g);
280 //if (!container) container = createEl({n: 'td', a: {'@class': f}}, null);
281 if (!container) container = createEl({n: 'td'}, null);
282 if (parts == null) return container;
283 var p;
284 for (var i = 0;i < parts.length; i++) {
285 p = parts[i].match(/(.+)\s:\s([.\d]+)/);
286 createEl({n: 'span', a: {'@class': f}, c: [
287 {n: 'span', a: {'@class': 'tp', textContent: CONV[p[1]] || p[1]}},
288 {n: 'span', a: {'@class': 'am', textContent: p[2]}}
289 ]},container);
290 }
291 return container;
292}
293
294// input: "2007-12-01 22:09:58" output: new Date(input)
295function parseTime(time) {
296 return new Date(time.replace(/-/g,'/') + ' GMT');
297}
298function Planet(pCell) {
299 if (pCell == null) return;
300 if (pCell.firstChild.nodeType == 3) { // unknown planet
301 this.name = LNG_UNKNOWN_PLANET_NAME;
302 this.id = 'p0';
303 this.type = '';
304 this.coords = LNG_NO_COORDS;
305 } else { // planet exists
306 this.name = pCell.firstChild.firstChild.nodeValue;
307 this.id = pCell.firstChild.href.replace( /^.+planet=(\d+).*$/, "p$1" );
308 this.coords = this.name.replace( /^.*\[([\d:]+)\].*$/, "$1");
309 this.type = (this.name.match(LNG_CONV_DF) ? LNG_SHORT_DF : (this.name.match(LNG_CONV_MOON) ? LNG_SHORT_MOON : LNG_SHORT_PLANET));
310 this.name = this.name.replace(/\s*[\(\[].+$/,'');
311 }
312}
313
314// Get main content box
315var textbox = document.evaluate('/html/body/div[@class="contbox"]/div[2]/div[1]', document, null, XPathResult.ELEMENT_NODE, null).iterateNext()
316var fl_div = createEl({n: 'div', a: {'@id': 'GM_fleetlog', textContent:''}},document.body);
317var menu_bar_div = createEl({n: 'div', a: {'@id': 'GM_menu_bar', textContent:''}},document.body);
318var menu_mid_div = createEl({n: 'div', a: {'@id': 'GM_menu_middle', textContent:''}},document.body);
319var newtable = createEl({n: 'table', a: {'@class': 'newTable', id: 'newTable'}});
320function tableClick(event) {
321 if (!event || !event.target) return;
322 var t = event.target;
323 if (!t.tagName || t.tagName == 'TABLE' || t.tagName == 'TH' || t.tagName == 'TR' ) return;
324 if (t.tagName == 'DIV' || t.tagName == 'SPAN') t = t.parentNode;
325 if (t.tagName != 'TD') { console.log("didn't find tag :(" + event.target); }
326 // found correct TD, not check className to know which action to do
327 if (t.className.match(/\bmission\b/)) { minimizeDisplay(t); }
328 if (t.className.match(/\bplayer\b/)) { toggleDisplay2(event, t); }
329 if (t.className.match(/\bp2\b/)) { toggleDisplay2(event, t); }
330
331}
332newtable.addEventListener('click', tableClick, true);
333//create menu items to show/hide stuff
334for (var b in missionButtons) {
335 var a = createEl({n: 'a', a: { '@id': 'OGB_DISP_'+missionButtons[b], '@class': 'DisplayButton',
336 '@trg': missionButtons[b], textContent: mission[missionButtons[b]] }},menu_bar_div);
337 a.addEventListener('click', toggleDisplay, true);
338}
339createEl({n: 'a', a: { '@id': 'OGB_DISP_GM_TextBox', '@class': 'DisplayButton GM__HIDDEN',
340 '@trg': 'GM_TextBox', textContent: LNG_OLD_LOGS_BUTTON }},menu_bar_div)
341 .addEventListener('click', toggleDisplay, true);
342
343function updateSpeed() {
344 var box = document.getElementById('OGB_DISP_UNI_SPEED');
345 if (!box.value.match(/^\d+(\.\d+)?$/)) box.value = 1;
346 localStorage.setItem(window.location.hostname + '_UNI_SPEED', box.value);
347
348}
349createEl({n: 'input', a: { '@id': 'OGB_DISP_UNI_SPEED',
350 '@type': 'input', '@maxlength': '5', value: UNI_SPEED }},menu_bar_div)
351 .addEventListener('blur', updateSpeed, true);
352updateSpeed();
353//log header:
354createEl({n: 'tr', a: {'@class': 'header'}, c: [
355 {n: 'th', a: {'@class': 'mission', textContent: LNG_HDR_MISSION}},
356 {n: 'th', a: {'@class': 'u1', textContent: LNG_HDR_PLAYER1}},
357 {n: 'th', a: {'@class': 'u2', textContent: LNG_HDR_PLAYER2}},
358 {n: 'th', a: {'@class': 'p1', textContent: LNG_HDR_ORIGIN}},
359 {n: 'th', a: {'@class': 'p2', textContent: LNG_HDR_DESTINATION}},
360 {n: 'th', a: {'@class': 't1', textContent: LNG_HDR_LAUNCH}},
361 {n: 'th', a: {'@class': 't2', textContent: LNG_HDR_ARRIVAL}},
362 COMBINE_FLEETS_AND_RESOURCES ? null : {n: 'th', a: {'@class': 'res', textContent: LNG_HDR_RESOURCES}},
363 {n: 'th', a: {'@class': 'fleet', textContent: LNG_HDR_FLEET}},
364 {n: 'th', a: {'@class': 't3', textContent: LNG_HDR_RETURN_TIME}},
365 COMBINE_FLEETS_AND_RESOURCES ? null : {n: 'th', a: {'@class': 'res return', textContent: LNG_HDR_RETURN_RES}},
366 {n: 'th', a: {'@class': 'fleet return', textContent: LNG_HDR_RETURN_FLEET}},
367]}, newtable);
368
369// check all tables and br's to recompose logs
370var currlog = 0;
371var xpres = document.evaluate('table[@width="650"]|br', textbox, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
372for (var i=0; i<xpres.snapshotLength; ++i) {
373 var logitem = xpres.snapshotItem(i);
374 if (logitem.nodeName == "TABLE") {
375 // parse each td of the table, they should have fixed order and contents
376 var cells = document.evaluate('.//td', logitem, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
377 if (cells.snapshotLength != 12) {
378 console.log('INCORRECT TABLE STRUCTURE, aborting:' + cells.snapshotLength + '; ' + cells.innerHTML);
379 return;
380 }
381 var mission = cells.snapshotItem(0).textContent;
382 var player1 = getPlayer(cells.snapshotItem(1));
383 var player2 = getPlayer(cells.snapshotItem(2));
384 var arrival = cells.snapshotItem(3).textContent == LNG_FLEET_ARRIVES_TO_TARGET;
385 var planet1 = new Planet(cells.snapshotItem(5));
386 var planet2 = new Planet(cells.snapshotItem(6));
387 var fleet = cells.snapshotItem(8).textContent;
388 var res = cells.snapshotItem(9).textContent;
389 var time1 = cells.snapshotItem(10).textContent;
390 var time2 = cells.snapshotItem(11).textContent;
391 res = stuffConvert(res,0,0,null);
392 fleet = stuffConvert(fleet,1,0,COMBINE_FLEETS_AND_RESOURCES ? res : null);
393 var p1d = player1.domElem();
394 var p2d = player2.domElem();
395
396 var cls = '';
397 mission = CONV_SHORT_MISSION[mission.match(/ \(?(\d*)\)?$/)[1]];
398 cls += CLS[mission];
399 cls += planet2.id;
400 if (player1.uid == player2.uid) {
401 if (mission == LNG_TRANSPORT) { cls += ' Own'; }
402 cls += ' u' + player1.uid;
403 } else { cls += ' u' + player1.uid + ' u' + player2.uid; }
404 cls += (arrival ? ' arrived' : ' returns');
405
406 var logitem = xpres.snapshotItem(++i);
407 if ((logitem.nodeName == "BR") || (mission == LNG_DEPLOYMENT)) { // (deployments do not need return)
408 if (mission == LNG_IPM) { //IPMs
409 if (time2.match(/^1970/)) {
410 if ((planet1.coords == LNG_NO_COORDS) || (planet2.coords == LNG_NO_COORDS)) time2 = '??'
411 else {
412 time2 = new Date(parseTime(time1).getTime() + (
413 30000 + // 30 seconds in-system + 60 seconds per SS
414 60000 * Math.abs(planet2.coords.match(/:(\d+):/)[1] - planet1.coords.match(/:(\d+):/)[1] )) / UNI_SPEED
415 );
416 time2.setMinutes(time2.getMinutes() + time2.getTimezoneOffset());
417 time2 = time2.toLocaleFormat(ORIG_DATE_FORMAT)
418 }
419 }
420 cls = cls.replace(/ returns$/, ' arrived');
421 createEl({n: 'tr', a: {'@class': cls}, c: [
422 {n: 'td', a: {'@class': 'mission', textContent: mission}},
423 p1d,
424 p2d,
425 {n: 'td', a: {'@class': 'p1', textContent: planet1.coords + planet1.type}},
426 {n: 'td', a: {'@class': 'p2', '@trg': planet2.id, textContent: planet2.coords + planet2.type}},
427 {n: 'td', a: {'@class': 't1', textContent: time1}},
428 {n: 'td', a: {'@class': 't2', textContent: time2}},
429 COMBINE_FLEETS_AND_RESOURCES?null:res, fleet,
430 {n: 'td', a: {'@class': 'empty st', '@colspan': COMBINE_FLEETS_AND_RESOURCES?2:3, textContent: '' }}
431 ]}, newtable);
432 } else {
433 //NO RETURN FLEET - create log entry
434 var time3 = new Date(2 * parseTime(time2).getTime() - parseTime(time1).getTime());
435 time3.setMinutes(time3.getMinutes() + time3.getTimezoneOffset());
436 createEl({n: 'tr', a: {'@class': cls}, c: [
437 {n: 'td', a: {'@class': 'mission', textContent: mission}},
438 p1d,
439 p2d,
440 {n: 'td', a: {'@class': 'p1', textContent: planet1.coords + planet1.type}},
441 {n: 'td', a: {'@class': 'p2', '@trg': planet2.id, textContent: planet2.coords + planet2.type}},
442 {n: 'td', a: {'@class': 't1', textContent: time1}},
443 {n: 'td', a: {'@class': 't2', textContent: time2}},
444 COMBINE_FLEETS_AND_RESOURCES?null:res,
445 fleet,
446 {n: 'td', a: {'@class': 'empty st', '@colspan': COMBINE_FLEETS_AND_RESOURCES?2:3,
447 textContent: (mission == LNG_DEPLOYMENT ? '' :(arrival?'not returned? >':'recalled <') + time3.toLocaleFormat(ORIG_DATE_FORMAT))}}
448 ]}, newtable);
449 }
450 } else if(logitem.nodeName == "TABLE") {
451 //PARSE RETURN FLEET
452 // parse each td of the table, they should have fixed order and contents
453 var cells = document.evaluate('.//td', logitem, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
454 if (cells.snapshotLength != 12) {
455 console.log('INCORRECT TABLE STRUCTURE for return, aborting:' + cells.snapshotLength + '; ' + cells.innerHTML);
456 return;
457 }
458 var fleet2 = cells.snapshotItem(8).textContent;
459 var res2 = cells.snapshotItem(9).textContent;
460 var time3 = new Date(2 * parseTime(time2).getTime() - parseTime(time1).getTime());
461 time3.setMinutes(time3.getMinutes() + time3.getTimezoneOffset());
462 res2 = stuffConvert(res2,0,1);
463 fleet2 = stuffConvert(fleet2,1,1,COMBINE_FLEETS_AND_RESOURCES?res2:null);
464
465 //create log entry
466 createEl({n: 'tr', a: {'@class': cls}, c: [
467 {n: 'td', a: {'@class': 'mission', textContent: mission}},
468 p1d,
469 p2d,
470 {n: 'td', a: {'@class': 'p1', textContent: planet1.coords + planet1.type}},
471 {n: 'td', a: {'@class': 'p2', '@trg': planet2.id, textContent: planet2.coords + planet2.type}},
472 {n: 'td', a: {'@class': 't1', textContent: time1}},
473 {n: 'td', a: {'@class': 't2', textContent: time2}},
474 COMBINE_FLEETS_AND_RESOURCES?null:res,
475 fleet,
476 {n: 'td', a: {'@class': 't3', textContent: time3.toLocaleFormat(ORIG_DATE_FORMAT)}},
477 COMBINE_FLEETS_AND_RESOURCES?null:res2,
478 fleet2
479 ]}, newtable);
480 // END RETURN FLEET
481 }
482 }
483}
484
485fl_div.appendChild(newtable);
486textbox.parentNode.parentNode.className += ' GM_TextBox';
487createEl({n: 'style', a: {type:'text/css', '@id':'GM__STYLE_GM_TextBox', textContent:'div.GM_TextBox {display:none;}'}}, head);
488} //end of DoModify
489
490// create DOM nodes using hash syntax and add it to end of parent node (if != null)
491function createEl(elObj, parent) {
492 var el;
493 if (elObj == null) return;
494 if (typeof elObj == 'string') {
495 el = document.createTextNode(elObj);
496 } else if (elObj.nodeType) { // it's an Element node already
497 el = elObj;
498 } else if (elObj.n) { // it's the hash type thing
499 el = document.createElement(elObj.n);
500 if (elObj.a) {
501 attributes = elObj.a;
502 for (var key in attributes) {
503 if (key.charAt(0) == '@')
504 el.setAttribute(key.substring(1), attributes[key]);
505 else
506 el[key] = attributes[key];
507 }
508 }
509 if (elObj.evl) {
510 el.addEventListener(elObj.evl.type, elObj.evl.f, elObj.evl.bubble);
511 }
512 if (elObj.c) {
513 elObj.c.forEach(function (v, i, a) { createEl(v, el); });
514 }
515 } else {
516 alert(elObj.toString());
517 el = elObj;
518 }
519 if (parent)
520 parent.appendChild(el);
521 return el;
522}
523// Get main content box
524var textbox = document.evaluate('/html/body/div[@class="contbox"]/div[2]/div[1]/h3[1]', document, null, XPathResult.ELEMENT_NODE, null).iterateNext();
525//create activate button
526createEl({n: 'style', a: {type:'text/css', textContent:'#GM_ActivateButton { margin-left:10px; }'}},document.getElementsByTagName('head')[0]);
527var activateButton = createEl({n: 'button', a: {'@id':'GM_ActivateButton', name:'GM_ActivateButton', textContent:LNG_START_BUTTON }},textbox)
528 .addEventListener('click',DoModify,true);
529})();