· 10 years ago · Nov 17, 2015, 09:21 PM
1/* Osmium
2 * Copyright (C) 2012 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18osmium_gettheme = function() {
19 var links = document.getElementsByTagName("link");
20 for(var i = 0; i < links.length; ++i) {
21 if(links[i].getAttribute('title') && links[i].getAttribute('rel').indexOf('stylesheet') !== -1) {
22 if(!links[i].disabled) return links[i].getAttribute('title');
23 }
24 }
25};
26
27osmium_settheme = function(title) {
28 var links = document.getElementsByTagName("link");
29 var foundit = false;
30
31 for(var i = 0; i < links.length; ++i) {
32 if(links[i].getAttribute('title') && links[i].getAttribute('rel').indexOf('stylesheet') !== -1) {
33 links[i].disabled = true;
34 if(links[i].getAttribute('title') === title) {
35 foundit = true;
36 links[i].disabled = false;
37 }
38 }
39 }
40
41 if(foundit) {
42 return;
43 }
44 alert('not found');
45
46 /* If the title was not found, enable the first sheet as a fallback */
47 for(var i = 0; i < links.length; ++i) {
48 if(links[i].getAttribute('title') && links[i].getAttribute('rel').indexOf('stylesheet') !== -1) {
49 links[i].disabled = false;
50 return;
51 }
52 }
53};
54
55osmium_setcookie = function(name, value, validityms) {
56 var d = new Date();
57 d.setTime(d.getTime() + validityms);
58 document.cookie = name + "=" + value + "; expires=" + d.toGMTString() + "; path=/";
59};
60
61$(function() {
62 var theme, label;
63 if(osmium_gettheme() === 'Light') {
64 theme = 'Dark';
65 label = 'Paint it black';
66 } else {
67 theme = 'Light';
68 label = 'Paint it white';
69 }
70
71 var rlink = $(document.createElement('a'));
72 rlink.prop('id', 'repaint');
73 rlink.data('theme', theme);
74 rlink.text(label);
75 rlink.click(function() {
76 var theme, label, tts;
77 if((tts = $(this).data('theme')) === 'Dark') {
78 theme = 'Light';
79 label = 'Paint it white';
80 } else {
81 theme = 'Dark';
82 label = 'Paint it black';
83 }
84
85 osmium_setcookie('t', tts, 86400 * 7 * 1000);
86 osmium_settheme(tts);
87 $(this).data('theme', theme);
88 $(this).text(label);
89 $(this).blur();
90 });
91
92 $("div#wrapper + footer > p").append(' — ').append(rlink);
93});
94/* Osmium
95 * Copyright (C) 2012, 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
96 *
97 * This program is free software: you can redistribute it and/or modify
98 * it under the terms of the GNU Affero General Public License as published by
99 * the Free Software Foundation, either version 3 of the License, or
100 * (at your option) any later version.
101 *
102 * This program is distributed in the hope that it will be useful,
103 * but WITHOUT ANY WARRANTY; without even the implied warranty of
104 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105 * GNU Affero General Public License for more details.
106 *
107 * You should have received a copy of the GNU Affero General Public License
108 * along with this program. If not, see <http://www.gnu.org/licenses/>.
109 */
110
111osmium_notifications = function(relative) {
112 var fetch = function() {
113 $.get(relative + '/internal/nc', function(cnt) {
114 var a = $("a#ncount");
115 var rawtitle = document.title.replace(/^\([1-9][0-9]*\) /, "");
116
117 a.text(cnt);
118 a.data('count', cnt);
119 a.prop('title', cnt + ' new notification(s)');
120
121 if(parseInt(cnt, 10) > 0) {
122 a.show().css('display', 'inline-block');
123 document.title = "(" + cnt + ") " + rawtitle;
124 } else {
125 a.hide();
126 document.title = rawtitle;
127 }
128 });
129
130 setTimeout(fetch, 63000);
131 };
132
133 setTimeout(fetch, 60000);
134};
135
136$(function() {
137 var prefix = window.location.href.split("/");
138 prefix[prefix.length - 1] = '';
139
140 osmium_notifications(
141 prefix.join('/') + $("div#osmium-data").data('relative')
142 );
143});
144/* Osmium
145 * Copyright (C) 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
146 *
147 * This program is free software: you can redistribute it and/or modify
148 * it under the terms of the GNU Affero General Public License as published by
149 * the Free Software Foundation, either version 3 of the License, or
150 * (at your option) any later version.
151 *
152 * This program is distributed in the hope that it will be useful,
153 * but WITHOUT ANY WARRANTY; without even the implied warranty of
154 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155 * GNU Affero General Public License for more details.
156 *
157 * You should have received a copy of the GNU Affero General Public License
158 * along with this program. If not, see <http://www.gnu.org/licenses/>.
159 */
160
161$(function() {
162 var fbdiv = $(document.createElement('div')).prop('id', 'glob_feedback');
163 var ul = $(document.createElement('ul'));
164
165 fbdiv.append($(document.createElement('span')).text('Feedback'));
166 fbdiv.append(ul);
167
168 ul.append(
169 $(document.createElement('li')).append(
170 $(document.createElement('a'))
171 .prop('href', 'https://github.com/osmium-org/osmium/issues/new')
172 .text('Report an issue')
173 )
174 );
175
176 ul.append(
177 $(document.createElement('li')).append(
178 $(document.createElement('a'))
179 .prop('href', 'http://irc.lc/coldfront/osmium/osmiumguest@@@')
180 .text('Live chat')
181 )
182 );
183
184 ul.append(
185 $(document.createElement('li')).append(
186 $('footer a[rel="help"]').clone().text('Help & FAQ')
187 )
188 );
189
190 $('div#wrapper').append(fbdiv);
191 fbdiv.children('span').first().on('click', function() {
192 var fb = $(this).parent();
193 var nfb = fb.clone(true); /* Hack to restart the CSS animation */
194
195 if(nfb.hasClass('extended')) {
196 nfb.removeClass('extended');
197 nfb.addClass('notextended');
198 } else {
199 nfb.removeClass('notextended');
200 nfb.addClass('extended');
201 }
202
203 fb.before(nfb);
204 fb.remove();
205 });
206});
207/* This snippet will be included in every page (generated with DOM\Page). */
208
209/* Whenever you change this script, update the information in about.php. */
210/*<<< require external //cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js before >>>*/
211
212/*<<< require snippet persistent_theme >>>*/
213/*<<< require snippet notifications >>>*/
214/*<<< require snippet feedback >>>*/
215
216/* Osmium
217 * Copyright (C) 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
218 *
219 * This program is free software: you can redistribute it and/or modify
220 * it under the terms of the GNU Affero General Public License as published by
221 * the Free Software Foundation, either version 3 of the License, or
222 * (at your option) any later version.
223 *
224 * This program is distributed in the hope that it will be useful,
225 * but WITHOUT ANY WARRANTY; without even the implied warranty of
226 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
227 * GNU Affero General Public License for more details.
228 *
229 * You should have received a copy of the GNU Affero General Public License
230 * along with this program. If not, see <http://www.gnu.org/licenses/>.
231 */
232
233osmium_put_setting = function(name, value) {
234 $.ajax({
235 type: 'POST',
236 url: osmium_relative + '/internal/ps/' + name,
237 data: {
238 payload: JSON.stringify(value),
239 'o___csrf': osmium_token
240 }
241 });
242};
243/*<<< require external /static-1/mousetrap.min.js >>>*/
244if(typeof(localStorage) === 'undefined') {
245 localStorage = {
246 getItem: function() { return null; },
247 setItem: function() {},
248 removeItem: function() {},
249 };
250}
251
252if(typeof(sessionStorage) === 'undefined') {
253 sessionStorage = {
254 getItem: function() { return null; },
255 setItem: function() {},
256 removeItem: function() {},
257 };
258}
259/* Osmium
260 * Copyright (C) 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
261 *
262 * This program is free software: you can redistribute it and/or modify
263 * it under the terms of the GNU Affero General Public License as published by
264 * the Free Software Foundation, either version 3 of the License, or
265 * (at your option) any later version.
266 *
267 * This program is distributed in the hope that it will be useful,
268 * but WITHOUT ANY WARRANTY; without even the implied warranty of
269 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
270 * GNU Affero General Public License for more details.
271 *
272 * You should have received a copy of the GNU Affero General Public License
273 * along with this program. If not, see <http://www.gnu.org/licenses/>.
274 */
275
276/*<<< require snippet localstorage_fallback >>>*/
277
278
279
280osmium_keyboard_commands = {};
281
282/* Register a keyboard command.
283 *
284 * @param shortnames a Mousetrap compatible shortcut definition, or an
285 * array of definitions, or null.
286 *
287 * @param longname a long descriptive name of the command ([a-z-]
288 * only).
289 *
290 * @param description a description of what the command does.
291 *
292 * @param action called when the command is used.
293 */
294osmium_register_keyboard_command = function(shortnames, longname, description, action) {
295 if(longname in osmium_keyboard_commands) {
296 osmium_unregister_keyboard_command(longname);
297 }
298
299 if($.isEmptyObject(osmium_keyboard_commands)) {
300 /* Bind M-x */
301 Mousetrap.bind([ 'meta+x', 'alt+x', 'command+x' ], function() {
302 if($('div#mx-cont').length !== 0) {
303 $('div#mx-cont > form > input[type="text"]').focus();
304 return false;
305 }
306
307 var history = sessionStorage.getItem('mx-history');
308 history = (typeof(history) === 'string') ? JSON.parse(history) : [];
309 var histposition = history.length;
310 var histlast = '';
311
312 var c = $(document.createElement('div')).prop('id', 'mx-cont');
313 var tabcount = 0;
314
315 var bg = $(document.createElement('div')).prop('id', 'mx-bg');
316 c.append(bg);
317
318 var form = $(document.createElement('form'));
319 form.prop('method', 'get');
320 form.prop('action', '?');
321 c.append(form);
322
323 var inp = $(document.createElement('input'));
324 inp.prop('type', 'text');
325 inp.prop('placeholder', 'Enter command… (Press C-g or ESC twice to exit)');
326 inp.addClass('mousetrap'); /* Fire events even if this input has focus */
327 var lastval = inp.val();
328 form.append(inp);
329
330 var setinpval = function(val) {
331 inp.val(val);
332 inp.get(0).setSelectionRange(val.length, val.length);
333 };
334
335 var submit = $(document.createElement('input'));
336 submit.prop('type', 'submit');
337 form.append(submit); /* Form won't submit on RET without a submit button */
338
339 var ul = $(document.createElement('ul'));
340 c.append(ul);
341 for(var lc in osmium_keyboard_commands) {
342 var cmd = osmium_keyboard_commands[lc];
343
344 ul.append(
345 $(document.createElement('li'))
346 .text(lc)
347 .prop(
348 'title',
349 lc + "\n"
350 + (
351 cmd.shortnames !== null ?
352 (((typeof(cmd.shortnames) === 'string') ?
353 cmd.shortnames
354 : cmd.shortnames.join(', ')) + "\n")
355 : ''
356 )
357 + cmd.description
358 )
359 );
360 }
361 ul.find('li').sort(function(a, b) {
362 var at = $(a).text();
363 var bt = $(b).text();
364 return (at < bt) ? -1 : ((at > bt) ? 1 : 0);
365
366 }).appendTo(ul);
367
368 var exit = function(e, after) {
369 Mousetrap.unbind([ 'esc esc', 'ctrl+g' ]);
370 Mousetrap.unbind('tab');
371 Mousetrap.unbind('up');
372 Mousetrap.unbind('down');
373
374 c.fadeOut(100, function() {
375 c.remove();
376 if(typeof after === 'function') {
377 after();
378 }
379 });
380
381 return false;
382 };
383
384 Mousetrap.bind([ 'esc esc', 'ctrl+g' ], exit);
385 bg.click(exit);
386
387 form.submit(function(e) {
388 var command = inp.val();
389 if(command in osmium_keyboard_commands) {
390 inp.removeClass('error');
391 inp.addClass('success');
392
393 history.push(command);
394 sessionStorage.setItem('mx-history', JSON.stringify(history));
395
396 exit(e, function() {
397 osmium_keyboard_commands[command].action();
398 });
399 } else {
400 inp.addClass('error');
401 }
402
403 return false;
404 });
405
406 inp.on('keyup', function() {
407 if(inp.val() !== lastval) {
408 lastval = inp.val();
409 tabcount = 0;
410 inp.removeClass('error');
411 }
412 });
413
414 Mousetrap.bind('tab', function() {
415 var buf = inp.val();
416
417 if(tabcount === 0) {
418 /* Hide non-matching commands, fill up input with
419 * largest prefix of matched commands */
420 ul.find('li').each(function() {
421 var li = $(this);
422 if(li.text().substring(0, buf.length) === buf) {
423 li.show();
424 } else {
425 li.hide();
426 }
427 });
428
429 var matches = ul.find('li:visible');
430 if(matches.length === 0) {
431 inp.addClass('error');
432 } else {
433 inp.removeClass('error');
434 var largestprefix = matches.first().text();
435
436 matches.each(function() {
437 var v = $(this).text();
438 var i = 0;
439 var ml = largestprefix.length;
440
441 while(i <= ml && largestprefix.substring(0, i) === v.substring(0, i)) {
442 ++i;
443 }
444
445 largestprefix = v.substring(0, i-1);
446 });
447
448 setinpval(largestprefix);
449 lastval = largestprefix;
450 }
451 } else if(tabcount >= 2) {
452 /* Cycle through matches */
453
454 var matches = ul.find('li:visible');
455 if(matches.length >= 1) {
456 setinpval($(matches[(tabcount - 2) % matches.length]).text());
457 lastval = inp.val();
458 }
459 }
460
461 ++tabcount;
462 return false;
463 });
464
465 Mousetrap.bind('up', function() {
466 --histposition;
467
468 if(histposition < 0) {
469 histposition = history.length;
470 setinpval(histlast);
471 } else {
472 if(histposition === history.length - 1) histlast = inp.val();
473 setinpval(history[histposition]);
474 }
475
476 return false;
477 });
478 Mousetrap.bind('down', function() {
479 ++histposition;
480
481 if(histposition === history.length) {
482 setinpval(histlast);
483 }
484
485 if(histposition >= history.length) histposition = history.length;
486 else {
487 setinpval(history[histposition]);
488 }
489
490 return false;
491 });
492
493 c.hide();
494 $('body').append(c);
495
496 c.fadeIn(100);
497 inp.focus();
498
499 return false;
500 });
501 }
502
503 osmium_keyboard_commands[longname] = {
504 shortnames: shortnames,
505 longname: longname,
506 description: description,
507 action: action,
508 };
509
510 if(shortnames !== null) {
511 Mousetrap.bind(shortnames, action);
512 }
513};
514
515/* Unregister a keyboard command. Use the same longname you used in
516 * osmium_register_keyboard_command. */
517osmium_unregister_keyboard_command = function(longname) {
518 if(!(longname in osmium_keyboard_commands)) return;
519
520 if(osmium_keyboard_commands[longname].shortnames !== null) {
521 Mousetrap.unbind(osmium_keyboard_commands[longname].shortnames);
522 }
523
524 delete osmium_keyboard_commands[longname];
525
526 if($.isEmptyObject(osmium_keyboard_commands)) {
527 Mousetrap.unbind([ 'meta+x', 'alt+x', 'command+x' ]);
528 }
529};
530if(typeof(localStorage) === 'undefined') {
531 localStorage = {
532 getItem: function() { return null; },
533 setItem: function() {},
534 removeItem: function() {},
535 };
536}
537
538if(typeof(sessionStorage) === 'undefined') {
539 sessionStorage = {
540 getItem: function() { return null; },
541 setItem: function() {},
542 removeItem: function() {},
543 };
544}
545/* Osmium
546 * Copyright (C) 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
547 * Copyright (C) 2013 Josiah Boning <jboning@gmail.com>
548 *
549 * This program is free software: you can redistribute it and/or modify
550 * it under the terms of the GNU Affero General Public License as published by
551 * the Free Software Foundation, either version 3 of the License, or
552 * (at your option) any later version.
553 *
554 * This program is distributed in the hope that it will be useful,
555 * but WITHOUT ANY WARRANTY; without even the implied warranty of
556 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
557 * GNU Affero General Public License for more details.
558 *
559 * You should have received a copy of the GNU Affero General Public License
560 * along with this program. If not, see <http://www.gnu.org/licenses/>.
561 */
562
563argsh = function(x) {
564 return Math.log(x + Math.sqrt(x*x + 1.0));
565};
566
567osmium_targeting_time = function(targeter_scanres, targetee_sigradius) {
568 /* Formula taken from the official wiki */
569 return 40000.0 / (targeter_scanres * Math.pow(argsh(targetee_sigradius), 2));
570};
571
572osmium_gen_fattribs = function() {
573 osmium_fattribs_load();
574
575 var s = osmium_clf['X-damage-profile'][1][0] + osmium_clf['X-damage-profile'][1][1]
576 + osmium_clf['X-damage-profile'][1][2] + osmium_clf['X-damage-profile'][1][3];
577
578 $("section#defense > h4 > span.pname")
579 .text(osmium_clf['X-damage-profile'][0])
580 .prop('title',
581 "EM: \t\t\t" + (100 * osmium_clf['X-damage-profile'][1][0] / s).toFixed(1) + "%\n" +
582 "Explosive: \t" + (100 * osmium_clf['X-damage-profile'][1][1] / s).toFixed(1) + "%\n" +
583 "Kinetic: \t\t" + (100 * osmium_clf['X-damage-profile'][1][2] / s).toFixed(1) + "%\n" +
584 "Thermal: \t\t" + (100 * osmium_clf['X-damage-profile'][1][3] / s).toFixed(1) + "%"
585 )
586 ;
587
588 var t = "Scan resolution\n\nTime to lock…";
589 var sr = parseFloat($("span#scan_resolution").data('value'));
590 var sig = parseFloat($("p#signature_radius").data('value'));
591
592 for(var i = 0; i < osmium_targetclass.length; ++i) {
593 if(!osmium_targetclass[i][1]) continue;
594 t += "\n" + osmium_targetclass[i][0] + " (" + osmium_targetclass[i][3].toFixed(0) + " m): "
595 + osmium_targeting_time(sr, osmium_targetclass[i][3]).toFixed(1) + " s"
596 }
597
598 $("span#scan_resolution").prop('title', t);
599
600 t = "Signature radius\n\nTime to be locked by…";
601
602 for(var i = 0; i < osmium_targetclass.length; ++i) {
603 if(!osmium_targetclass[i][2]) continue;
604 t += "\n" + osmium_targetclass[i][0] + " (" + osmium_targetclass[i][4].toFixed(0) + " mm) : "
605 + osmium_targeting_time(osmium_targetclass[i][4], sig).toFixed(1) + " s"
606 }
607
608 $("p#signature_radius").prop('title', t);
609
610 var capacitor = $("p#capacitor");
611 capacitor.children("span.mainsprite:first-child, svg:first-child").replaceWith(
612 osmium_gen_capacitor(capacitor.data('capacity'), capacitor.data('usage'))
613 );
614};
615
616osmium_init_fattribs = function() {
617 osmium_ctxmenu_bind($("div#computed_attributes > section#mastery"), function() {
618 var menu = osmium_ctxmenu_create();
619 for(var i = 0; i < osmium_skillsets.length; ++i) {
620 osmium_ctxmenu_add_subctxmenu(menu, osmium_skillsets[i], (function(sname) {
621 return function() {
622 var smenu = osmium_ctxmenu_create();
623
624 osmium_ctxmenu_add_option(smenu, "Use", function() {
625 osmium_clf.metadata['X-Osmium-skillset'] = sname;
626 osmium_undo_push();
627 osmium_commit_clf();
628 }, { 'default': true });
629
630 osmium_ctxmenu_add_option(smenu, "Set default", function() {
631 osmium_put_setting('default_skillset', sname);
632 }, {});
633
634 return smenu;
635 };
636 })(osmium_skillsets[i]), {
637 toggled: osmium_clf.metadata['X-Osmium-skillset'] === osmium_skillsets[i]
638 });
639 }
640 return menu;
641 });
642
643 osmium_ctxmenu_bind($("div#computed_attributes > section#defense"), function() {
644 var menu = osmium_ctxmenu_create();
645
646 osmium_ctxmenu_add_subctxmenu(menu, "Damage profiles", function() {
647 var smenu = osmium_ctxmenu_create();
648
649 for(var k in osmium_damage_profiles) {
650 osmium_ctxmenu_add_subctxmenu(smenu, k, (function(profiles) {
651 return function() {
652 var ssmenu = osmium_ctxmenu_create();
653
654 for(var z in profiles) {
655 var s = profiles[z][0] + profiles[z][1] + profiles[z][2] + profiles[z][3];
656
657 var opts = {
658 toggled: z === osmium_clf['X-damage-profile'][0],
659 title: "EM: \t\t\t" + (100 * profiles[z][0] / s).toFixed(1) + "%\n" +
660 "Explosive: \t" + (100 * profiles[z][1] / s).toFixed(1) + "%\n" +
661 "Kinetic: \t\t" + (100 * profiles[z][2] / s).toFixed(1) + "%\n" +
662 "Thermal: \t\t" + (100 * profiles[z][3] / s).toFixed(1) + "%"
663 };
664
665 if(profiles[z].length >= 5) {
666 opts.icon = profiles[z][4];
667 }
668
669 osmium_ctxmenu_add_option(ssmenu, z, (function(name, profile) {
670 return function() {
671 osmium_clf['X-damage-profile'] = [ name, profile.slice(0, 4) ];
672 osmium_undo_push();
673 osmium_commit_clf();
674 };
675 })(z, profiles[z]), opts);
676 }
677 return ssmenu;
678 };
679 })(osmium_damage_profiles[k]), {});
680 }
681
682 osmium_ctxmenu_add_subctxmenu(smenu, "Custom", function() {
683 var ssmenu = osmium_ctxmenu_create();
684 var count = 0;
685
686 for(var k in osmium_custom_damage_profiles) {
687 ++count;
688
689 var profile = osmium_custom_damage_profiles[k];
690 var s = profile[0] + profile[1] + profile[2] + profile[3];
691
692 osmium_ctxmenu_add_subctxmenu(ssmenu, k, (function(k, profile) {
693 return function() {
694 var sssmenu = osmium_ctxmenu_create();
695
696 osmium_ctxmenu_add_option(sssmenu, "Use", function() {
697 osmium_clf['X-damage-profile'] = [ k, profile ];
698 osmium_undo_push();
699 osmium_commit_clf();
700 }, { 'default': true });
701
702 osmium_ctxmenu_add_option(sssmenu, "Remove", function() {
703 if(k === osmium_clf['X-damage-profile'][0]) {
704 osmium_clf['X-damage-profile'] = [ "Uniform", [ .25, .25, .25, .25 ] ];
705 osmium_commit_clf();
706 }
707
708 delete osmium_custom_damage_profiles[k];
709 osmium_commit_custom_damage_profiles();
710 }, {});
711
712 return sssmenu;
713 };
714 })(k, osmium_custom_damage_profiles[k]), {
715 toggled: k === osmium_clf['X-damage-profile'][0],
716 title: "EM: \t\t\t" + (100 * profile[0] / s).toFixed(1) + "%\n" +
717 "Explosive: \t" + (100 * profile[1] / s).toFixed(1) + "%\n" +
718 "Kinetic: \t\t" + (100 * profile[2] / s).toFixed(1) + "%\n" +
719 "Thermal: \t\t" + (100 * profile[3] / s).toFixed(1) + "%"
720 });
721 }
722
723 if(count >= 1) {
724 osmium_ctxmenu_add_separator(ssmenu);
725 }
726
727 osmium_ctxmenu_add_option(ssmenu, "Create…", function() {
728 var name = prompt("Damage profile name:");
729 if(!name) return;
730 var prof = prompt("Damage values (EM, Explosive, Kinetic, Thermal):",
731 "[ 0.25, 0.25, 0.25, 0.25 ]");
732 if(!prof) return;
733
734 try {
735 var p = JSON.parse(prof);
736 var s;
737
738 if(p[0] < 0 || p[1] < 0 || p[2] < 0 || p[3] < 0 || (s = p[0] + p[1] + p[2] + p[3]) <= 0) {
739 alert("Incorrect damage values: all four numbers must be positive, and at least one of them must be nonzero.");
740 } else {
741 osmium_custom_damage_profiles[name] = [
742 p[0] / s, p[1] / s, p[2] / s, p[3] / s
743 ];
744
745 osmium_clf['X-damage-profile'] = [ name, osmium_custom_damage_profiles[name] ];
746 osmium_undo_push();
747 osmium_commit_clf();
748 osmium_commit_custom_damage_profiles();
749 }
750 } catch(e) {
751 alert("Incorrect syntax in damage values.");
752 }
753
754 $("ul#ctxmenu").trigger('delete_menu');
755 }, {});
756
757 return ssmenu;
758 }, {});
759
760 return smenu;
761 }, {});
762
763 return menu;
764 });
765};
766
767osmium_commit_custom_damage_profiles = function() {
768 osmium_put_setting('custom_damage_profiles', osmium_custom_damage_profiles);
769};
770/* Osmium
771 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
772 *
773 * This program is free software: you can redistribute it and/or modify
774 * it under the terms of the GNU Affero General Public License as published by
775 * the Free Software Foundation, either version 3 of the License, or
776 * (at your option) any later version.
777 *
778 * This program is distributed in the hope that it will be useful,
779 * but WITHOUT ANY WARRANTY; without even the implied warranty of
780 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
781 * GNU Affero General Public License for more details.
782 *
783 * You should have received a copy of the GNU Affero General Public License
784 * along with this program. If not, see <http://www.gnu.org/licenses/>.
785 */
786
787/*<<< require snippet perfectscrollbar >>>*/
788/*<<< require snippet mousetrap >>>*/
789
790osmium_modal_clear = function() {
791 $("body > div#modalbg").fadeOut(250);
792 $("body > div#modal").animate({
793 'margin-top': -$('body').width() + "px"
794 }, 250);
795}
796
797osmium_modal = function(inside) {
798 Mousetrap.unbind('esc');
799 $("body > div#modalbg, body > div#modal").remove();
800
801 var bg = $(document.createElement('div'));
802 bg.prop('id', 'modalbg');
803 bg.click(osmium_modal_clear);
804 bg.hide();
805
806 var modal = $(document.createElement('div'));
807 modal.prop('id', 'modal');
808
809 $('body')
810 .append(bg)
811 .append(modal)
812 ;
813
814 Mousetrap.bind('esc', osmium_modal_clear);
815
816 modal
817 .css('margin-left', (-modal.width() / 2) + "px")
818 .css('margin-top', -$('body').width() + "px")
819 .append(inside)
820 .animate({
821 'margin-top': (-modal.height() / 2) + "px"
822 }, 500)
823 ;
824
825 modal.perfectScrollbar({ wheelSpeed: 40 });
826
827 bg.fadeIn(500);
828};
829
830osmium_modal_rotextarea = function(title, contents) {
831 var m = $(document.createElement('div'));
832 var h = $(document.createElement('header'));
833 var textarea = $(document.createElement('textarea'));
834
835 h.append($(document.createElement('h2')).text(title));
836 m.append(h);
837
838 textarea.text(contents);
839 textarea.prop('readonly', 'readonly').prop('spellcheck', false);
840 textarea.css({
841 position: 'absolute',
842 top: '0',
843 left: '0',
844 width: '100%',
845 height: '100%',
846 'font-size': '0.8em'
847 });
848 m.append($(document.createElement('div')).css({
849 position: 'absolute',
850 top: '3.25em',
851 left: '1em',
852 right: '1em',
853 bottom: '1em'
854 }).append(textarea));
855
856 osmium_modal(m.children());
857 textarea.focus().select();
858};
859/* Osmium
860 * Copyright (C) 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
861 *
862 * This program is free software: you can redistribute it and/or modify
863 * it under the terms of the GNU Affero General Public License as published by
864 * the Free Software Foundation, either version 3 of the License, or
865 * (at your option) any later version.
866 *
867 * This program is distributed in the hope that it will be useful,
868 * but WITHOUT ANY WARRANTY; without even the implied warranty of
869 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
870 * GNU Affero General Public License for more details.
871 *
872 * You should have received a copy of the GNU Affero General Public License
873 * along with this program. If not, see <http://www.gnu.org/licenses/>.
874 */
875
876osmium_sprite = function(alt, grid_x, grid_y, grid_width, grid_height, width, height) {
877 var span = $(document.createElement('span'));
878 var img = $(document.createElement('img'));
879
880 span.addClass('mainsprite');
881 span.css({
882 width: width + 'px',
883 height: height + 'px'
884 });
885
886 img.prop('src', osmium_relative + '/static-' + osmium_staticver + '/icons/sprite.png');
887 img.prop('alt', alt);
888 img.prop('title', alt);
889 img.css({
890 width: (width / grid_width * 1024) + 'px',
891 height: (height / grid_height * 1024) + 'px',
892 top: (-grid_x * width) + 'px',
893 left: (-grid_y * height) + 'px'
894 });
895
896 span.append(img);
897 return span;
898};
899/* Osmium
900 * Copyright (C) 2012, 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
901 *
902 * This program is free software: you can redistribute it and/or modify
903 * it under the terms of the GNU Affero General Public License as published by
904 * the Free Software Foundation, either version 3 of the License, or
905 * (at your option) any later version.
906 *
907 * This program is distributed in the hope that it will be useful,
908 * but WITHOUT ANY WARRANTY; without even the implied warranty of
909 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
910 * GNU Affero General Public License for more details.
911 *
912 * You should have received a copy of the GNU Affero General Public License
913 * along with this program. If not, see <http://www.gnu.org/licenses/>.
914 */
915
916osmium_orig_anchor = null;
917osmium_selected_tabs = [];
918osmium_available_tabs = [];
919osmium_tab_ul_count = 0;
920
921osmium_tabify = function(ul, selected) {
922 if(osmium_orig_anchor === null) {
923 if(window.location.hash) {
924 osmium_orig_anchor = window.location.hash.substring(1).split(",");
925 } else {
926 osmium_orig_anchor = [];
927 }
928 }
929
930 var tabs = [];
931 var i = 0;
932 var selected_pref = 0;
933
934 ul.find('li > a').each(function() {
935 var t = $(this);
936 var href = t.attr('href');
937 if(href.substring(0, 1) != '#') return;
938 t.parent().addClass('anchor');
939 tabs.push(href.substring(1));
940 ++i;
941 });
942
943 for(var j = 0; j < osmium_orig_anchor.length; ++j) {
944 var index = $.inArray(osmium_orig_anchor[j], tabs);
945 if(index !== -1) {
946 /* Got one of our tabs in hash */
947 if(selected_pref < 1) {
948 selected = index;
949 selected_pref = 1;
950 }
951 osmium_orig_anchor.splice(j, 1);
952
953 /* Don't break here, as this choice may be overridden by a
954 * "true" anchor in another tab */
955 } else {
956 if(selected_pref >= 2) continue; /* Already found */
957
958 /* Not one of our tabs, see if it is an anchor in one of our tabs */
959 var target = $('#' + osmium_orig_anchor[j]);
960 if(target.length === 0) continue;
961 target = target.parent();
962 do {
963 var id = target.prop('id');
964 var index;
965 if(id && ((index = $.inArray(id, tabs)) !== -1)) {
966 /* Found one of our tabs as parent */
967 selected = index;
968 selected_pref = 2;
969 break;
970 }
971 target = target.parent();
972 } while("length" in target && target.length !== 0);
973 }
974 }
975
976 i = 0;
977 ul.find('li.anchor').each(function() {
978 var t = $(this);
979 var href = t.children('a').attr('href');
980 var tget = $(href).addClass('notarget');
981
982 if(i !== selected) {
983 tget.hide().trigger('made_hidden');
984 } else {
985 t.addClass('active');
986 tget.trigger('made_visible');
987 }
988 ++i;
989 });
990
991 var found = false;
992 for(i = 0; i < osmium_available_tabs.length; ++i) {
993 if($.inArray(tabs[selected], osmium_available_tabs[i]) !== -1) {
994 ul.data('tab_ul_index', i);
995 found = true;
996 break;
997 }
998 }
999 if(!found) {
1000 osmium_available_tabs.push(tabs);
1001 osmium_selected_tabs.push(tabs[selected]);
1002 ul.data('tab_ul_index', osmium_tab_ul_count++);
1003 }
1004
1005 ul.find('li.anchor').on('click', osmium_tab_click);
1006
1007 for(i = 0; i < osmium_orig_anchor.length; ++i) {
1008 var target = $("#" + osmium_orig_anchor[i]);
1009 if(target.length === 0) continue;
1010 if(!target.is(":visible")) continue;
1011 $(window).scrollTop(target.offset().top);
1012 return;
1013 }
1014
1015 $(window).scrollTop(0);
1016};
1017
1018osmium_tab_click = function(e) {
1019 var li = $(this);
1020 var ul_index = li.parent().data('tab_ul_index');
1021 var tabnames = osmium_available_tabs[ul_index];
1022 var want = li.children('a').blur().attr('href').substring(1);
1023
1024 for(var i = 0; i < tabnames.length; ++i) {
1025 if(tabnames[i] === want) {
1026 $("#" + want).fadeIn(250).trigger('made_visible');
1027 } else {
1028 $("#" + tabnames[i]).hide().trigger('made_hidden');
1029 }
1030 }
1031
1032 li.parent().children('li.active').removeClass('active');
1033 li.addClass('active');
1034
1035 osmium_selected_tabs[ul_index] = want;
1036
1037 if(window.history && window.history.replaceState) {
1038 history.replaceState(history.state, null, '#' + osmium_selected_tabs.join(','));
1039 }
1040
1041 e.preventDefault();
1042 e.stopPropagation();
1043 return false;
1044};
1045
1046osmium_tabify_nohash = function(ul, selected) {
1047 ul.find('li > a').on('click', function(e) {
1048 var t = $(this);
1049 var href = t.attr('href');
1050 if(href.substring(0, 1) !== '#') return;
1051 var tgt = $(t.attr('href'));
1052 var li = t.parent();
1053
1054 if(li.hasClass('active')) return false;
1055 ul.find('li.active > a').each(function() {
1056 var a = $(this);
1057 var tgt = $(a.attr('href'));
1058 tgt.hide().trigger('made_hidden');
1059 a.parent().removeClass('active');
1060 });
1061
1062 li.addClass('active');
1063 tgt.fadeIn(250).trigger('made_visible');
1064
1065 t.blur();
1066 return false;
1067 }).each(function() {
1068 var t = $(this);
1069 var href = t.attr('href');
1070 if(href.substring(0, 1) !== '#') return;
1071 $(t.attr('href')).hide();
1072 });
1073
1074 ul.children('li').eq(selected).children('a').click();
1075};
1076/* Osmium
1077 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
1078 *
1079 * This program is free software: you can redistribute it and/or modify
1080 * it under the terms of the GNU Affero General Public License as published by
1081 * the Free Software Foundation, either version 3 of the License, or
1082 * (at your option) any later version.
1083 *
1084 * This program is distributed in the hope that it will be useful,
1085 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1086 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1087 * GNU Affero General Public License for more details.
1088 *
1089 * You should have received a copy of the GNU Affero General Public License
1090 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1091 */
1092
1093/*<<< require snippet modal >>>*/
1094/*<<< require snippet sprite >>>*/
1095/*<<< require snippet tabs >>>*/
1096/*<<< require snippet loadout_common >>>*/
1097
1098
1099
1100
1101
1102
1103
1104osmium_showinfo_sprite_position = [ 6, 58, 16, 16 ];
1105
1106osmium_showinfo = function(opts) {
1107 osmium_showinfo_internal(opts, function() {
1108 /* First error… Try committing CLF and retry once */
1109 osmium_commit_clf({
1110 success: function() {
1111 osmium_showinfo_internal(opts, function(xhr, error, httperror) {
1112 if(xhr.readyState === 0 || xhr.status === 0) {
1113 return;
1114 }
1115
1116 alert('Could not show info: ' + error + ' (' + httperror
1117 + '). Try refreshing the page and report if the problem persists.');
1118 });
1119 }
1120 });
1121 });
1122};
1123
1124osmium_showinfo_igb = function(opts) {
1125 osmium_showinfo_internal_igb(opts, function() {
1126 /* First error… Try committing CLF and retry once */
1127 osmium_commit_clf({
1128 success: function() {
1129 osmium_showinfo_internal_igb(opts, function(xhr, error, httperror) {
1130 if(xhr.readyState === 0 || xhr.status === 0) {
1131 return;
1132 }
1133
1134 alert('Could not show info: ' + error + ' (' + httperror
1135 + '). Try refreshing the page and report if the problem persists.');
1136 });
1137 }
1138 });
1139 });
1140};
1141
1142osmium_showinfo_internal = function(opts, onerror) {
1143 osmium_clfspinner_push();
1144
1145 opts.relative = osmium_relative;
1146 opts['o___csrf'] = osmium_token;
1147 opts['clftoken'] = osmium_clftoken;
1148
1149 $.ajax({
1150 type: 'POST',
1151 url: osmium_relative + '/internal/showinfo',
1152 data: opts,
1153 dataType: 'json',
1154 error: onerror,
1155 complete: function() {
1156 osmium_clfspinner_pop();
1157 },
1158 success: function(json) {
1159 osmium_modal(json['modal']);
1160 osmium_tabify_nohash($('ul.showinfotabs'), 0);
1161
1162 var ul = $("ul.sivariations").last();
1163 var vartypeids = [];
1164
1165 for(var i = 0; i < json.variations.length; ++i) {
1166 var t = osmium_types[json.variations[i][0]];
1167 var li = $(document.createElement('li'));
1168
1169 li.addClass('module');
1170 li.data('typeid', t[0]);
1171 li.text(t[1]);
1172 li.data('category', t[2]);
1173 li.data('subcategory', t[3]);
1174 vartypeids.push(t[0]);
1175
1176 li.prepend(
1177 $(document.createElement('img'))
1178 .prop('src', '//image.eveonline.com/Type/' + t[0] + '_64.png')
1179 .prop('alt', '')
1180 );
1181
1182 li.append(
1183 $(document.createElement('span'))
1184 .addClass('metalevel')
1185 .text(', meta level ' + json.variations[i][1])
1186 );
1187
1188
1189
1190
1191 if(osmium_loadout_readonly) {
1192 osmium_ctxmenu_bind(li, (function(typeid) {
1193 return function() {
1194 var menu = osmium_ctxmenu_create();
1195
1196 osmium_ctxmenu_add_option(menu, "Show info", function() {
1197 osmium_showinfo({
1198 type: 'generic',
1199 typeid: typeid
1200 });
1201 }, { icon: osmium_showinfo_sprite_position, 'default': true });
1202
1203
1204 if (typeof CCPEVE !== 'undefined') {
1205
1206 osmium_ctxmenu_add_option(menu, "Show IGB info", function() {
1207
1208 osmium_showinfo_igb({
1209 type: 'generic',
1210 typeid: typeid
1211 });
1212 }, { icon: osmium_showinfo_sprite_position, 'default': true });
1213
1214 }
1215
1216
1217 return menu;
1218 };
1219 })(t[0]));
1220 } else {
1221 osmium_add_non_shortlist_contextmenu(li);
1222 }
1223
1224 ul.append(li);
1225 }
1226
1227 ul.after($(document.createElement('p')).addClass('compare').append(
1228 $(document.createElement('a'))
1229 .prop('target', '_blank')
1230 .addClass('external')
1231 .prop('href', osmium_relative + '/db/comparetypes/'
1232 + vartypeids.join(',') + '/auto')
1233 .text('Compare these types')
1234 ));
1235 }
1236 });
1237}
1238
1239
1240osmium_showinfo_internal_igb = function(opts, onerror) {
1241 osmium_clfspinner_push();
1242
1243 opts.relative = osmium_relative;
1244 opts['o___csrf'] = osmium_token;
1245 opts['clftoken'] = osmium_clftoken;
1246
1247 $.ajax({
1248 type: 'POST',
1249 url: osmium_relative + '/internal/showinfo',
1250 data: opts,
1251 dataType: 'json',
1252 error: onerror,
1253 complete: function() {
1254 osmium_clfspinner_pop();
1255 },
1256 success: function(json) {
1257
1258 //console.debug(opts);
1259
1260 if (opts.type == 'ship') {
1261 var t = osmium_types[json.variations[0][0]];
1262 CCPEVE.showInfo (t[0]);
1263 }
1264
1265 if (opts.type == 'generic') {
1266 CCPEVE.showInfo (opts.typeid);
1267 }
1268
1269 if (opts.type == 'drone') {
1270 CCPEVE.showInfo (opts.typeid);
1271 }
1272 if (opts.type == 'module') {
1273 CCPEVE.showInfo (opts.typeid);
1274 }
1275 if (opts.type == 'charge') {
1276 CCPEVE.showInfo (opts.typeid);
1277 }
1278
1279 }
1280 });
1281}
1282/* Osmium
1283 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
1284 *
1285 * This program is free software: you can redistribute it and/or modify
1286 * it under the terms of the GNU Affero General Public License as published by
1287 * the Free Software Foundation, either version 3 of the License, or
1288 * (at your option) any later version.
1289 *
1290 * This program is distributed in the hope that it will be useful,
1291 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1292 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1293 * GNU Affero General Public License for more details.
1294 *
1295 * You should have received a copy of the GNU Affero General Public License
1296 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1297 */
1298
1299osmium_ctxmenu_bind = function(element, menu_constructor) {
1300 var indicator = $(document.createElement('span'));
1301
1302 element.children('.contextmenuindicator').remove();
1303 indicator.text('≡');
1304 indicator.addClass('contextmenuindicator');
1305
1306 element.append(indicator);
1307
1308 var showmenu = function(e) {
1309 var menu = menu_constructor();
1310 menu.prop('id', 'ctxmenu');
1311
1312 div = $(document.createElement('div'));
1313 div.prop('id', 'ctxbg');
1314
1315 div.bind('click contextmenu', function(e2) {
1316 menu.click();
1317 $(document.elementFromPoint(e2.pageX, e2.pageY)).trigger(e2);
1318 return false;
1319 });
1320
1321 menu.bind('click delete_menu', function() {
1322 $("ul#ctxmenu, div#ctxbg, ul.subctxmenu").remove();
1323 });
1324
1325 $('ul#ctxmenu, div#ctxbg, ul.subctxmenu').remove();
1326 $('body').append(div).append(menu);
1327
1328 var x = Math.min(e.pageX, $(document).width() - menu.width() - 5);
1329 var y = e.pageY;
1330 menu.css('left', x);
1331 menu.css('top', y);
1332
1333 return false;
1334 };
1335
1336 element.on('dblclick do_default_ctxmenu_action', function() {
1337 var menu = menu_constructor();
1338 menu.children('li.default').trigger('do_action');
1339 return false;
1340 });
1341
1342 element.on('contextmenu', showmenu);
1343 indicator.on('click', showmenu);
1344
1345 element.addClass('hascontextmenu');
1346};
1347
1348osmium_ctxmenu_create = function() {
1349 return $(document.createElement('ul'));
1350};
1351
1352/* opts is a Hashtable that can accept the properties:
1353 * - icon: URI of the icon to show
1354 * - title: tooltip of this option (uses title attribute)
1355 * - enabled: whether this option is enabled or not (default yes); disabled elements cannot be clicked on
1356 * - default: whether this option is the default when the element is double-clicked (default false)
1357 * - toggled: whether this option is "checked" or "selected"
1358 */
1359osmium_ctxmenu_add_option = function(menu, name, action, opts) {
1360 var li = $(document.createElement('li'));
1361
1362 li.append($(document.createElement('span')).text(name));
1363 osmium_ctxmenu_apply_opts(menu, li, opts);
1364
1365 if(("enabled" in opts) && !opts.enabled) {
1366 li.addClass('disabled');
1367 } else {
1368 li.on('do_action click', function() {
1369 action();
1370 li.closest('ul#ctxmenu').click();
1371 });
1372 }
1373
1374 if(("default" in opts) && opts['default'] && !li.hasClass('disabled')) {
1375 li.addClass('default');
1376 }
1377
1378 menu.append(li);
1379};
1380
1381osmium_ctxmenu_add_separator = function(menu) {
1382 var li = $(document.createElement('li'));
1383 li.addClass('separator');
1384 li.text('Â ');
1385 menu.append(li);
1386};
1387
1388osmium_ctxmenu_add_heading = function(menu, name, opts) {
1389 var li = $(document.createElement('li'));
1390
1391 li.addClass('hd');
1392 li.addClass('disabled');
1393 li.append($(document.createElement('span')).text(name));
1394 osmium_ctxmenu_apply_opts(menu, li, opts);
1395
1396 menu.append(li);
1397};
1398
1399/* Same parameters as osmium_ctxmenu_add_option(), but the action is
1400 * replaced by a submenu constructor function. */
1401osmium_ctxmenu_add_subctxmenu = function(menu, name, submenu_ctor, opts) {
1402 var li = $(document.createElement('li'));
1403 var timeout_in, timeout_out;
1404 var show_submenu;
1405
1406 li.append($(document.createElement('span')).text(name));
1407 osmium_ctxmenu_apply_opts(menu, li, opts);
1408
1409 show_submenu = function() {
1410 var submenu = submenu_ctor();
1411
1412 submenu.addClass('subctxmenu');
1413 if(li.children('ul.subctxmenu').length == 1) return;
1414
1415 li.parent().find('ul.subctxmenu').remove();
1416 li.append(submenu);
1417
1418 var offset = li.offset();
1419 var ow = li.outerWidth();
1420 var sow = submenu.outerWidth();
1421
1422 if(offset.left + ow + sow > $(document).width()) {
1423 submenu.offset({
1424 top: offset.top,
1425 left: offset.left - sow
1426 });
1427 } else {
1428 submenu.offset({
1429 top: offset.top,
1430 left: offset.left + ow
1431 });
1432 }
1433 };
1434
1435 if(("enabled" in opts) && !opts.enabled) {
1436 li.addClass('disabled');
1437 } else {
1438 li.on('show_submenu', function(e) {
1439 show_submenu();
1440 e.stopPropagation();
1441 return false;
1442 }).on('hide_submenu', function(e) {
1443 li.children('ul.subctxmenu').remove();
1444 e.stopPropagation();
1445 return false;
1446 }).on('click', function(e) {
1447 var def = li.children('ul.subctxmenu').children('li.default');
1448 if(def.length === 1) {
1449 def.trigger('do_action');
1450 return;
1451 }
1452
1453 li.trigger('show_submenu');
1454 e.stopPropagation();
1455 return false;
1456 }).on('mouseenter', function(e) {
1457 clearTimeout(timeout_out);
1458 timeout_in = setTimeout(function() {
1459 li.trigger('show_submenu');
1460 }, 100);
1461 }).on('mouseleave', function(e) {
1462 clearTimeout(timeout_in);
1463 timeout_out = setTimeout(function() {
1464 li.trigger('hide_submenu');
1465 }, 250);
1466 });
1467 }
1468
1469 li.addClass('hassubcontextmenu');
1470 menu.append(li);
1471};
1472
1473/* @internal */
1474osmium_ctxmenu_apply_opts = function(menu, li, opts) {
1475 if(opts === undefined) opts = {};
1476
1477 if("title" in opts) {
1478 li.prop('title', opts.title);
1479 }
1480
1481 if("icon" in opts && typeof opts.icon === "string") {
1482 var img = $(document.createElement('img'));
1483 img.prop('alt', '');
1484 if(opts.icon.substring(0, 2) === '//') {
1485 /* Absolute URI of type //foo.tld/path.png */
1486 img.prop('src', opts.icon);
1487 } else {
1488 /* Relative URI */
1489 img.prop('src', osmium_relative + '/static-' + osmium_staticver + '/icons/' + opts.icon);
1490 }
1491 img.addClass('icon');
1492 li.prepend(img);
1493 li.addClass('hasicon');
1494 } else if("icon" in opts && typeof opts.icon === "object") {
1495 li.prepend(osmium_sprite(
1496 '',
1497 opts.icon[0],
1498 opts.icon[1],
1499 opts.icon[2],
1500 opts.icon[3],
1501 16, 16
1502 ));
1503 li.addClass('hasicon');
1504 }
1505
1506 if("toggled" in opts) {
1507 var c = $(document.createElement('input'));
1508 c.prop('type', 'checkbox');
1509 c.prop('checked', opts.toggled);
1510 li.prepend(c);
1511 li.addClass('hastoggle');
1512
1513 if(opts.toggled) {
1514 li.addClass('toggled');
1515 }
1516 }
1517};
1518/* Osmium
1519 * Copyright (C) 2012, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
1520 *
1521 * This program is free software: you can redistribute it and/or modify
1522 * it under the terms of the GNU Affero General Public License as published by
1523 * the Free Software Foundation, either version 3 of the License, or
1524 * (at your option) any later version.
1525 *
1526 * This program is distributed in the hope that it will be useful,
1527 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1528 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1529 * GNU Affero General Public License for more details.
1530 *
1531 * You should have received a copy of the GNU Affero General Public License
1532 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1533 */
1534
1535osmium_fattribs_load = function() {
1536 var hidden = $('div#osmium-data').data('fattribshidden');
1537 if(!hidden) return;
1538
1539 var hc = hidden.length;
1540 var s = $("div#computed_attributes");
1541 for(var i = 0; i < hc; ++i) s.children("section#" + hidden[i]).addClass('hidden').children('div').hide();
1542};
1543
1544osmium_fattribs_toggle = function(section) {
1545 if(section.hasClass('hidden')) {
1546 section.children('div').fadeIn(250);
1547 section.removeClass('hidden');
1548 } else {
1549 section.children('div').fadeOut(250);
1550 section.addClass('hidden');
1551 }
1552
1553 var hidden = [];
1554
1555 $("div#computed_attributes > section.hidden").each(function() {
1556 hidden.push($(this).prop('id'));
1557 });
1558
1559 osmium_put_setting('fattribs_hidden', hidden);
1560};
1561
1562$(function() {
1563 $(document).on('click', "div#computed_attributes > section > h4", function() {
1564 osmium_fattribs_toggle($(this).parent());
1565 });
1566
1567 osmium_fattribs_load();
1568});
1569/* Osmium
1570 * Copyright (C) 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
1571 *
1572 * This program is free software: you can redistribute it and/or modify
1573 * it under the terms of the GNU Affero General Public License as published by
1574 * the Free Software Foundation, either version 3 of the License, or
1575 * (at your option) any later version.
1576 *
1577 * This program is distributed in the hope that it will be useful,
1578 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1579 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1580 * GNU Affero General Public License for more details.
1581 *
1582 * You should have received a copy of the GNU Affero General Public License
1583 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1584 */
1585
1586/**
1587 * Try to auto-guess "best" initial values. Returns an array of three
1588 * values [ tsrOptimal, tvOptimal, tdOptimal ].
1589 */
1590osmium_probe_optimals_from_ia = function(ia) {
1591 var tsrc = 0, tsrs = 0, tvc = 0, tvs = 0, tdc = 0, tds = 0;
1592
1593 for(var i = 0; i < ia.length; ++i) {
1594 var a = ia[i].raw;
1595
1596 if(!("damagetype" in a)) continue;
1597
1598 if("sigradius" in a) {
1599 ++tsrc;
1600 tsrs += a.sigradius;
1601 }
1602
1603 if("expradius" in a) {
1604 ++tsrc;
1605 tsrs += a.expradius;
1606 }
1607
1608 if(a.damagetype === "turret" && "range" in a) {
1609 ++tdc;
1610 tds += a.range / 1000.0;
1611 }
1612 }
1613
1614 return [
1615 tsrc === 0 ? 250 : Math.round(tsrs / tsrc),
1616 tvc === 0 ? 0 : Math.round(tvs / tvc),
1617 tdc === 0 ? 1 : Math.round(tds / tdc),
1618 ];
1619};
1620
1621/**
1622 * Try to auto-guess graph boundaries with some given
1623 * constraints. Parameters tsr, tv, td can be filled or left
1624 * out. Returns an array of three values [ tsrMax, tvMax, tdMax ].
1625 */
1626osmium_probe_boundaries_from_ia = function(ia, tsr, tv, td) {
1627 var tsrmax = 50, tvmax = 50, tdmax = 5000;
1628 var a;
1629
1630 if(isNaN(td)) {
1631 for(var j = 0; j < ia.length; ++j) {
1632 a = ia[j].raw;
1633 if(!("damagetype" in a)) continue;
1634
1635 var m = Math.min(
1636 ("range" in a && "falloff" in a) ? (a.range + 3 * a.falloff) : Infinity,
1637 ("maxrange" in a) ? (a.maxrange * 1.1) : Infinity,
1638 ("controlrange" in a) ? (a.controlrange * 1.1) : Infinity
1639 );
1640
1641 if(isFinite(m)) tdmax = Math.max(tdmax, m);
1642 }
1643
1644 tdmax /= 1000;
1645 } else {
1646 tdmax = td;
1647 }
1648
1649 if(isNaN(tsr)) {
1650 for(var j = 0; j < ia.length; ++j) {
1651 a = ia[j].raw;
1652 if(!("damagetype" in a)) continue;
1653
1654 if("sigradius" in a) {
1655 tsrmax = Math.max(tsrmax, a.sigradius * 3);
1656 continue;
1657 }
1658
1659 if("expradius" in a) {
1660 tsrmax = Math.max(tsrmax, a.expradius * 3);
1661 continue;
1662 }
1663 }
1664 } else {
1665 tsrmax = tsr;
1666 }
1667
1668 if(isNaN(tv)) {
1669 for(var j = 0; j < ia.length; ++j) {
1670 a = ia[j].raw;
1671 if(!("damagetype" in a)) continue;
1672
1673 if("trackingspeed" in a && "range" in a && "falloff" in a) {
1674 if(a.damagetype === "combatdrone" && a.maxvelocity > 0) {
1675 continue;
1676 }
1677
1678 tvmax = Math.max(
1679 tvmax,
1680 Math.min(a.damagetype === "combatdrone" ? 2500 : 12000,
1681 (a.range + a.falloff) * a.trackingspeed)
1682 );
1683 continue;
1684 }
1685
1686 if("expvelocity" in a) {
1687 tvmax = Math.max(tvmax, a.expvelocity * 8);
1688 continue;
1689 }
1690 }
1691 } else {
1692 tvmax = tv;
1693 }
1694
1695 return [ tsrmax, tvmax, tdmax ];
1696};
1697
1698/**
1699 * Return a color from a parameter between 0 and 1. The color is red
1700 * for 1, and will smoothly go through all the color spectrum to reach
1701 * transparent-ish purple at zero.
1702 */
1703osmium_heat_color = function(t) {
1704 return "hsla("
1705 + Math.round((1 - t) * 360).toString()
1706 + ", 100%, 50%, "
1707 + Math.min(1, t).toFixed(2)
1708 + ")";
1709};
1710
1711/**
1712 * Generate labels and append them next to a canvas element.
1713 *
1714 * @param ctx the root element to add the labels to
1715 * @param canvas the canvas element
1716 * @param xlabel text to label the X axis with
1717 * @param ylabel text to label the Y axis with
1718 */
1719osmium_graph_gen_labels = function(ctx, canvas, xlabel, ylabel) {
1720 var xl, yl;
1721 ctx.append(xl = $(document.createElement('span')).addClass('xlabel').text(xlabel));
1722 ctx.append(yl = $(document.createElement('span')).addClass('ylabel').text(ylabel));
1723
1724 var cpos = canvas.offset();
1725
1726 xl.offset({
1727 top: cpos.top + canvas.height() + 4,
1728 left: cpos.left + canvas.width() / 2 - xl.width() / 2
1729 });
1730
1731 /* Rotating first gives different results on Chromium/Firefox */
1732 yl.offset({
1733 top: cpos.top + canvas.height() / 2 - yl.height() / 2,
1734 left: cpos.left - yl.width() / 2 - yl.height() / 2 - 4
1735 }).addClass('rotated');
1736};
1737
1738/**
1739 * Draw a labeled grid using a given canvas context.
1740 *
1741 * @param cctx the canvas context to draw with
1742 * @param cw canvas width
1743 * @param ch canvas height
1744 * @param xmin minimum value for X axis
1745 * @param xmax maximum value for X axis
1746 * @param xsteps minimum number of vertical guides to draw
1747 * @param ymin minimum value for Y axis
1748 * @param ymax maximum value for Y axis
1749 * @param ysteps minimum value of horizontal guides to draw
1750 * @param axisopacity opacity (between 0 and 1) of the drawn guides
1751 * @param labelopacity opacity (between 0 and 1) of the drawn labels
1752 */
1753osmium_graph_draw_grid = function(cctx, cw, ch, xmin, xmax, xsteps, ymin, ymax, ysteps, axisopacity, labelopacity) {
1754 var steps = [ 50000, 20000, 10000,
1755 5000, 2000, 1000,
1756 500, 200, 100,
1757 50, 20, 10,
1758 5, 2, 1,
1759 .5, .2, .1,
1760 .05, .02, .01,
1761 .005, .002, .001,
1762 .0005, .0002, .0001 ];
1763
1764 var xstep = 1, ystep = 1;
1765 for(var i = 0; i < steps.length; ++i) {
1766 if((xmax - xmin) / steps[i] >= xsteps) {
1767 xstep = steps[i];
1768 break;
1769 }
1770 }
1771 for(var i = 0; i < steps.length; ++i) {
1772 if((ymax - ymin) / steps[i] >= ysteps) {
1773 ystep = steps[i];
1774 break;
1775 }
1776 }
1777
1778 cctx.beginPath();
1779 cctx.font = '0.8em "Droid Sans"';
1780 cctx.fillStyle = "hsla(0, 0%, 50%, " + labelopacity.toString() + ")";
1781
1782 cctx.textAlign = "center";
1783 cctx.textBaseline = "bottom";
1784 for(var x = Math.ceil(xmin / xstep) * xstep; x < xmax; x += xstep) {
1785 if(x === xmin) continue;
1786
1787 var xc = Math.floor(cw * (x - xmin) / (xmax - xmin)) + 0.5;
1788 cctx.moveTo(xc, 0.5);
1789 cctx.lineTo(xc, ch - 0.5);
1790 cctx.fillText(x.toString(), xc, ch - 0.5);
1791 }
1792
1793 cctx.textAlign = "left";
1794 cctx.textBaseline = "middle";
1795 for(var y = Math.ceil(ymin / ystep) * ystep; y < ymax; y += ystep) {
1796 if(y === ymin) continue;
1797
1798 var yc = Math.floor(ch * (y - ymin) / (ymax - ymin)) + 0.5;
1799 cctx.moveTo(0.5, ch - yc);
1800 cctx.lineTo(cw - 0.5, ch - yc);
1801 cctx.fillText(y.toString(), 2.5, ch - yc);
1802 }
1803
1804 cctx.strokeStyle = "hsla(0, 0%, 50%, " + axisopacity.toString() + ")";
1805 cctx.stroke();
1806};
1807
1808/**
1809 * Get the average DPS of a turret-like weapon.
1810 *
1811 * http://wiki.eveuniversity.org/Turret_Damage
1812 *
1813 * @param dps the raw DPS of the turret
1814 * @param trackingspeed tracking speed of the turret, in rad/s
1815 * @param sigresolution signature resolution of the turret, in meters
1816 * @param range optimal range of the turret, in meters
1817 * @param falloff falloff range of the turret, in meters
1818 * @param tsr target signature radius, in meters
1819 * @param tv target velocity, in m/s
1820 * @param td target distance, in km
1821 */
1822osmium_turret_damage_f = function(dps, trackingspeed, sigresolution, range, falloff, tsr, tv, td) {
1823 if(tv == 0 && td == 0) td = .001;
1824 if(tsr == 0) return 0;
1825
1826 var cth = Math.pow(
1827 0.5,
1828 Math.pow(
1829 ((tv / (1000 * td)) / trackingspeed) * (sigresolution / tsr),
1830 2
1831 ) + Math.pow(
1832 Math.max(0, (1000 * td) - range) / falloff,
1833 2
1834 )
1835 );
1836
1837 return (
1838 Math.min(cth, 0.01) * 3 + Math.max(cth - 0.01, 0) * (0.49 + (cth + 0.01) / 2)
1839 ) * dps;
1840};
1841
1842/**
1843 * Get the average DPS of a missile-like weapon.
1844 *
1845 * http://wiki.eveuniversity.org/Missile_Damage
1846 *
1847 * @param dps the raw DPS of the missile launcher
1848 * @param maxrange the maximum range of the missile
1849 * @param expradius explosion radius of the missile
1850 * @param expvelocity explosion velocity of the missile
1851 * @param drf damage reduction factor
1852 * @param drs damage reduction sensitivity
1853 * @param tsr target signature radius, in meters
1854 * @param tv target velocity, in m/s
1855 * @param td target distance, in km
1856 */
1857osmium_missile_damage_f = function(dps, maxrange, expradius, expvelocity, drf, drs, tsr, tv, td) {
1858 if(1000 * td > maxrange || dps == 0) return 0;
1859
1860 return dps * Math.min(
1861 1,
1862 tsr / expradius,
1863 (tsr != 0 && expvelocity != 0) ?
1864 Math.pow((tsr / expradius) * (expvelocity / tv), Math.log(drf) / Math.log(drs))
1865 : 0
1866 );
1867};
1868
1869/** Get the average DPS of a fitted type. */
1870osmium_get_dps_from_type_internal = function(a, tsr, tv, td) {
1871 if(!("damagetype" in a)) return 0;
1872
1873 if(a.damagetype === "combatdrone" || a.damagetype === "fighter" || a.damagetype === "fighterbomber") {
1874 if(a.damagetype === "combatdrone" && "controlrange" in a && 1000 * td > a.controlrange) return 0;
1875
1876 if(a.maxvelocity == 0) {
1877 /* Sentry drone */
1878 return osmium_turret_damage_f(
1879 a.damage / a.duration,
1880 a.trackingspeed, a.sigradius, a.range, a.falloff,
1881 tsr, tv, td
1882 );
1883 }
1884
1885 /* XXX: this is a very simplistic model, totally inaccurate
1886 * guesswork. Critique & improvements most welcomed! */
1887
1888 /* Drone tries to keep orbit at flyrange m @ cruisespeed m/s */
1889 /* After a full cycle, assume the drone will use MWD to
1890 * reenter orbit distance */
1891 var ddur = a.duration;
1892
1893 if(tv > a.cruisespeed) {
1894 if(tv >= a.maxvelocity) {
1895 /* Drone will never catch up */
1896 ddur = Infinity;
1897 } else {
1898 ddur += (tv - a.cruisespeed) * a.duration / (a.maxvelocity - tv);
1899 }
1900 }
1901
1902 if(a.damagetype === "fighterbomber") {
1903 return osmium_missile_damage_f(
1904 a.damage / ddur,
1905 a.maxrange, a.expradius, a.expvelocity, a.drf, a.drs,
1906 tsr, tv, a.flyrange / 1000.0
1907 );
1908 }
1909
1910 return osmium_turret_damage_f(
1911 a.damage / ddur,
1912 a.trackingspeed, a.sigradius, a.range, a.falloff,
1913 tsr, a.cruisespeed, a.flyrange / 1000.0
1914 );
1915 }
1916
1917 if(a.damagetype === "turret") {
1918 return osmium_turret_damage_f(
1919 a.damage / a.duration,
1920 a.trackingspeed, a.sigradius, a.range, a.falloff,
1921 tsr, tv, td
1922 );
1923 }
1924
1925 if(a.damagetype === "missile") {
1926 return osmium_missile_damage_f(
1927 a.damage / a.duration,
1928 a.maxrange, a.expradius, a.expvelocity, a.drf, a.drs,
1929 tsr, tv, td
1930 );
1931 }
1932
1933 if(a.damagetype === "smartbomb") {
1934 if(1000 * td > a.maxrange) return 0;
1935 return a.damage / a.duration;
1936 }
1937
1938 return 0;
1939};
1940
1941/** @internal */
1942osmium_get_dps_internal = function(ia, args) {
1943 var dps = 0;
1944 for(var j = 0; j < ia.length; ++j) {
1945 dps += osmium_get_dps_from_type_internal(ia[j].raw, args[0], args[1], args[2]);
1946 }
1947 return 1000 * dps;
1948};
1949
1950/**
1951 * Draw a line graph for every set of attributes in ia_map, using colors in color_map.
1952 *
1953 * @param ctx the root element to append the canvas and labels into
1954 * @param xlabel the X label
1955 * @param xmin the minimum X value
1956 * @param xmax the maximum X value
1957 * @param genfunc_x a function which takes the X coordinate and returns an array [ tsr, tv, td ]
1958 * @param dpsmin the minimum Y value
1959 * @param dpsmax the maximum Y value, leave null to autodetect
1960 */
1961osmium_draw_dps_graph_1d = function(ia_map, color_map, ctx,
1962 xlabel, xmin, xmax, genfunc_x, dpsmin, dpsmax) {
1963 ctx.empty();
1964
1965 var canvas = document.createElement('canvas');
1966 var cctx = canvas.getContext('2d');
1967 var cw, ch;
1968 canvas = $(canvas);
1969 ctx.append($(document.createElement('div')).addClass('cctx').append(canvas));
1970 canvas.attr('width', cw = canvas.width());
1971 canvas.attr('height', ch = canvas.height());
1972
1973 osmium_graph_gen_labels(ctx, canvas, xlabel, "Damage per second");
1974
1975 var x, dps, px, py;
1976
1977 if(!dpsmax) {
1978 dpsmax = 10;
1979
1980 for(var i = 0; i <= cw; ++i) {
1981 x = xmin + (i / cw) * (xmax - xmin);
1982
1983 for(var k in ia_map) {
1984 if(!("ia" in ia_map[k])) continue;
1985 dpsmax = Math.max(dpsmax, osmium_get_dps_internal(ia_map[k].ia, genfunc_x(x)));
1986 }
1987 }
1988
1989 dpsmax *= 1.05;
1990 }
1991
1992 osmium_graph_draw_grid(cctx, cw, ch, xmin, xmax, 8, dpsmin, dpsmax, 4, 0.15, 0.5);
1993
1994 for(var k in ia_map) {
1995 if(!("ia" in ia_map[k])) continue;
1996 cctx.beginPath();
1997 cctx.moveTo(0, 0);
1998
1999 for(var i = 0; i <= cw; ++i) {
2000 x = xmin + (i / cw) * (xmax - xmin);
2001 dps = osmium_get_dps_internal(ia_map[k].ia, genfunc_x(x));
2002 px = i + 0.5;
2003 py = Math.floor(ch * (1 - (dps - dpsmin) / (dpsmax - dpsmin))) + 0.5;
2004
2005 if(i === 0) {
2006 cctx.moveTo(px, py);
2007 } else {
2008 cctx.lineTo(px, py);
2009 }
2010 }
2011
2012 cctx.strokeStyle = color_map[k];
2013 cctx.lineWidth = 3;
2014 cctx.stroke();
2015 }
2016};
2017
2018/**
2019 * Draw a 2d graph. Most parameters are similar to the 1d version.
2020 *
2021 * @param genfunc_xy a function that takes two parameters (the X,Y
2022 * coordinates) and returns an array [ tsr, tv, td ].
2023 *
2024 * @param cololfunc a function that takes one parameter, a map of
2025 * array [ DPS, MaxDPS ] values and returns a color.
2026 *
2027 * @param pixelsize the size of the rectangles drawn on the
2028 * graph. Higher values means less rectangles to draw, but results in
2029 * a blockier graph.
2030 *
2031 * @returns global maximum dps
2032 */
2033osmium_draw_dps_graph_2d = function(ia_map, colorfunc, ctx,
2034 xlabel, xmin, xmax, ylabel, ymin, ymax,
2035 genfunc_xy, pixelsize) {
2036 ctx.empty();
2037
2038 var canvas = document.createElement('canvas');
2039 var cctx = canvas.getContext('2d');
2040 var cw, ch;
2041 canvas = $(canvas);
2042 ctx.append($(document.createElement('div')).addClass('cctx').append(canvas));
2043 canvas.attr('width', cw = canvas.width());
2044 canvas.attr('height', ch = canvas.height());
2045
2046 osmium_graph_gen_labels(ctx, canvas, xlabel, ylabel);
2047
2048 cctx.moveTo(0, ch);
2049
2050 var x, y, px, py, localmax = {}, globalmax = 10, hps = pixelsize / 2;
2051
2052 for(var k in ia_map) {
2053 if(!("ia" in ia_map[k])) continue;
2054 var ia = ia_map[k].ia;
2055 localmax[k] = 0;
2056
2057 for(var i = 0; i <= cw; i += pixelsize) {
2058 x = xmin + ((i + hps) / cw) * (xmax - xmin);
2059
2060 for(var j = 0; j <= ch; j += pixelsize) {
2061 y = ymin + ((j + hps) / ch) * (ymax - ymin);
2062 localmax[k] = Math.max(localmax[k], osmium_get_dps_internal(ia, genfunc_xy(x, y)));
2063 }
2064 }
2065
2066 globalmax = Math.max(localmax[k], globalmax);
2067 }
2068
2069 var dps = {};
2070
2071 for(var k in ia_map) {
2072 dps[k] = [ 0, Math.max(1, localmax[k]) ];
2073 }
2074
2075 for(var i = 0; i <= cw; i += pixelsize) {
2076 x = xmin + ((i + hps) / cw) * (xmax - xmin);
2077
2078 for(var j = 0; j <= ch; j += pixelsize) {
2079 y = ymin + ((j + hps) / ch) * (ymax - ymin);
2080
2081 for(var k in ia_map) {
2082 if(!("ia" in ia_map[k])) continue;
2083
2084 dps[k][0] = osmium_get_dps_internal(ia_map[k].ia, genfunc_xy(x, y));
2085 }
2086
2087 cctx.fillStyle = colorfunc(dps);
2088 cctx.fillRect(i, ch - j, pixelsize, pixelsize);
2089 }
2090 }
2091
2092 osmium_graph_draw_grid(cctx, cw, ch, xmin, xmax, 8, ymin, ymax, 4, 0.15, 0.75);
2093
2094 return globalmax;
2095};
2096
2097/** Draw a legend for colored 2d graphs. */
2098osmium_draw_dps_legend = function(ctx, maxdps, heatfunc) {
2099 ctx.find('div.cctx').addClass('twodim');
2100
2101 var lcanvas = document.createElement('canvas');
2102 var lctx = lcanvas.getContext('2d');
2103 var lw, lh;
2104 lcanvas = $(lcanvas);
2105 ctx.append($(document.createElement('div')).addClass('legend').append(lcanvas));
2106 lcanvas.attr('width', lw = lcanvas.width());
2107 lcanvas.attr('height', lh = lcanvas.height());
2108
2109 for(var i = 0; i <= lh; ++i) {
2110 lctx.fillStyle = heatfunc(i / lh);
2111 lctx.fillRect(0, lh - i, 100, 1);
2112 }
2113
2114 var dlabel = $(document.createElement('span')).text('DPS');
2115 ctx.append(dlabel);
2116 var lpos = lcanvas.parent().offset();
2117 dlabel.offset({
2118 top: lpos.top + lcanvas.parent().height() + 5,
2119 left: lpos.left + lcanvas.parent().width() / 2 - dlabel.width() / 2
2120 });
2121
2122 lpos = lcanvas.offset();
2123 var nlabels = 6;
2124 for(var i = 0; i <= nlabels; ++i) {
2125 dlabel = $(document.createElement('span')).addClass('dpslabel')
2126 .text(Math.round((i / nlabels) * maxdps).toString());
2127 ctx.append(dlabel);
2128 dlabel.offset({
2129 top: Math.min(
2130 Math.max(
2131 lpos.top + lcanvas.height() * (1 - i / nlabels) - dlabel.height() / 2,
2132 lpos.top
2133 ),
2134 lpos.top + lcanvas.height() - dlabel.height()
2135 ),
2136 left: lpos.left - dlabel.width() - 4
2137 });
2138 }
2139};
2140/* Osmium
2141 * Copyright (C) 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
2142 *
2143 * This program is free software: you can redistribute it and/or modify
2144 * it under the terms of the GNU Affero General Public License as published by
2145 * the Free Software Foundation, either version 3 of the License, or
2146 * (at your option) any later version.
2147 *
2148 * This program is distributed in the hope that it will be useful,
2149 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2150 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2151 * GNU Affero General Public License for more details.
2152 *
2153 * You should have received a copy of the GNU Affero General Public License
2154 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2155 */
2156
2157osmium_gen_capacitor = function(capacity, current) {
2158 if(capacity === null) capacity = 0;
2159 if(current === null) current = 0;
2160
2161 var nbranches = Math.min(10, Math.max(2, Math.floor(capacity / 50.0)));
2162 var nbubbles = 3;
2163 var bubblecapacity = (capacity > 0) ? (capacity / (nbubbles * nbranches)) : 0;
2164 /* Avoid using the same IDs on different <svg> elements in the
2165 * same page */
2166 var idsuffix = Math.random().toFixed(20).substring(2);
2167
2168 var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
2169 svg.setAttribute('viewBox', '-1 -1 2 2');
2170 svg.setAttribute('class', 'capacitorwheel');
2171
2172 var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
2173
2174 for(var t in { full: 1, empty: 1 }) {
2175 var lg = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
2176 lg.setAttribute('id', 'gradient-' + t + '-' + idsuffix);
2177 lg.setAttribute('class', t);
2178
2179 var stop;
2180
2181 stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
2182 stop.setAttribute('offset', '0%');
2183 lg.appendChild(stop);
2184
2185 stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
2186 stop.setAttribute('offset', '33%');
2187 lg.appendChild(stop);
2188
2189 stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
2190 stop.setAttribute('offset', '67%');
2191 lg.appendChild(stop);
2192
2193 stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
2194 stop.setAttribute('offset', '100%');
2195 lg.appendChild(stop);
2196
2197 defs.appendChild(lg);
2198 }
2199
2200 svg.appendChild(defs);
2201
2202 var progress = 0;
2203 for(var i = 0; i < nbranches; ++i) {
2204 var angle = -360 * i / nbranches;
2205 var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
2206 g.setAttribute('transform', 'rotate(' + angle + ' 0 0)');
2207
2208 for(var j = 0; j < nbubbles; ++j) {
2209 var bubble = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
2210 var w = 0.2 + j * 0.12;
2211 bubble.setAttribute('width', w + '');
2212 bubble.setAttribute('height', '0.15');
2213 bubble.setAttribute('x', (-w / 2) + '');
2214 bubble.setAttribute('y', (-0.9 + 0.8 * (nbubbles - j - 1) / nbubbles) + '');
2215 bubble.setAttribute('rx', '0.075');
2216 bubble.setAttribute('ry', '0.075');
2217 bubble.setAttribute(
2218 'fill',
2219 (progress < current) ?
2220 ('url(#gradient-full-' + idsuffix + ')')
2221 : ('url(#gradient-empty-' + idsuffix + ')')
2222 );
2223 g.appendChild(bubble);
2224
2225 progress += bubblecapacity;
2226 }
2227
2228 svg.appendChild(g);
2229 }
2230
2231 var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
2232 svg.appendChild(g);
2233
2234 var title = document.createElementNS('http://www.w3.org/2000/svg', 'title');
2235 title.appendChild(document.createTextNode('Capacity: ' + capacity.toFixed(0) + ' GJ'));
2236 g.setAttribute('class', 'overlay');
2237 g.appendChild(title);
2238
2239 var r = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
2240 r.setAttribute('x', '-1');
2241 r.setAttribute('y', '-1');
2242 r.setAttribute('width', '2');
2243 r.setAttribute('height', '2');
2244 g.appendChild(r);
2245
2246 svg = $(svg);
2247
2248 svg.data('capacity', capacity);
2249 svg.data('current', current);
2250
2251 svg.on('redraw', function() {
2252 var t = $(this);
2253 t.replaceWith(
2254 osmium_gen_capacitor(t.data('capacity'), t.data('current'))
2255 );
2256 });
2257
2258 return svg;
2259};
2260/* Osmium
2261 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
2262 *
2263 * This program is free software: you can redistribute it and/or modify
2264 * it under the terms of the GNU Affero General Public License as published by
2265 * the Free Software Foundation, either version 3 of the License, or
2266 * (at your option) any later version.
2267 *
2268 * This program is distributed in the hope that it will be useful,
2269 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2270 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2271 * GNU Affero General Public License for more details.
2272 *
2273 * You should have received a copy of the GNU Affero General Public License
2274 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2275 */
2276
2277osmium_undo_stack = [];
2278osmium_undo_stack_position = 0;
2279osmium_pushed_state_count = 0;
2280osmium_popstate_disablefor = 0;
2281
2282
2283
2284/* Push the current CLF to the undo history. */
2285osmium_undo_push = function() {
2286 osmium_undo_stack.push($.extend(true, {}, osmium_clf));
2287 osmium_undo_stack_position = osmium_undo_stack.length - 1;
2288 osmium_set_history_undo();
2289};
2290
2291/* Restore the previous CLF in the undo history. Negative values also
2292 * supported, in which case, use fallback_clf if going too far in the
2293 * future. */
2294osmium_undo_pop = function(nsteps, fallback_clf) {
2295 if(nsteps === undefined) nsteps = 1;
2296
2297 if(osmium_undo_stack_position < nsteps) {
2298 /* No more history to undo */
2299 return false;
2300 }
2301
2302 /* Very similar to the "undo" feature of Emacs. Powerful and
2303 * cannot lose data by undoing stuff then doing modifications. */
2304
2305 osmium_undo_stack_position -= nsteps;
2306
2307 if(fallback_clf !== undefined) {
2308 osmium_undo_stack[osmium_undo_stack_position] = $.extend(true, {}, fallback_clf);
2309 }
2310
2311 var clf = osmium_undo_stack[osmium_undo_stack_position];
2312 if(clf === undefined) {
2313 return false;
2314 }
2315
2316 osmium_clf = $.extend(true, {}, clf);
2317 osmium_undo_stack.push($.extend(true, {}, clf));
2318 osmium_set_history_undo();
2319 return true;
2320}
2321
2322/* @internal */
2323osmium_set_history_undo = function() {
2324 if(!window.history || !window.history.pushState) return;
2325
2326 /* This sucks, but popstate is async */
2327 osmium_popstate_disablefor += Math.max(0, osmium_pushed_state_count - osmium_undo_stack_position);
2328 while(osmium_pushed_state_count > osmium_undo_stack_position) {
2329 history.back();
2330 --osmium_pushed_state_count;
2331 }
2332
2333 while(osmium_pushed_state_count < osmium_undo_stack_position) {
2334 ++osmium_pushed_state_count;
2335 history.pushState([
2336 osmium_pushed_state_count,
2337 osmium_undo_stack[osmium_pushed_state_count],
2338 ], null);
2339 }
2340};
2341
2342
2343
2344$(function() {
2345 $(window).on('popstate', function(e) {
2346 if(osmium_popstate_disablefor > 0) {
2347 --osmium_popstate_disablefor;
2348 return;
2349 }
2350
2351 var state = e.originalEvent.state;
2352 if(state === null) state = [ 0, undefined ];
2353 var nsteps = osmium_undo_stack_position - state[0];
2354
2355 osmium_pushed_state_count -= nsteps;
2356 if(osmium_undo_pop(nsteps, state[1]) === false) return;
2357 osmium_commit_clf();
2358 osmium_user_initiated_push(false);
2359 osmium_gen();
2360 osmium_user_initiated_pop();
2361 });
2362});
2363
2364
2365
2366osmium_register_keyboard_command('ctrl+z', 'undo', 'Undo the last change made to the loadout.', function() {
2367 if(osmium_undo_pop() === false) return false;
2368 osmium_commit_clf();
2369 osmium_user_initiated_push(false);
2370 osmium_gen();
2371 osmium_user_initiated_pop();
2372 return false;
2373});
2374
2375osmium_register_keyboard_command(null, 'debug-log-clf-undo-stack', 'Print the undo history to the Javascript console.', function() {
2376 console.log(osmium_undo_stack_position, osmium_undo_stack);
2377});
2378/* Osmium
2379 * Copyright (C) 2012, 2013, 2014, 2015 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
2380 * Copyright (C) 2013 Josiah Boning <jboning@gmail.com>
2381 *
2382 * This program is free software: you can redistribute it and/or modify
2383 * it under the terms of the GNU Affero General Public License as published by
2384 * the Free Software Foundation, either version 3 of the License, or
2385 * (at your option) any later version.
2386 *
2387 * This program is distributed in the hope that it will be useful,
2388 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2389 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2390 * GNU Affero General Public License for more details.
2391 *
2392 * You should have received a copy of the GNU Affero General Public License
2393 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2394 */
2395
2396/* Whenever you change this script, update the information in about.php. */
2397/*<<< require external //cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js >>>*/
2398/*<<< require external /static-1/jquery.jsPlumb-1.6.0-min.js >>>*/
2399/*<<< require external /static-1/rawdeflate.min.js >>>*/
2400
2401/*<<< require snippet settings >>>*/
2402/*<<< require snippet mousetrap >>>*/
2403/*<<< require snippet keyboard >>>*/
2404/*<<< require snippet localstorage_fallback >>>*/
2405/*<<< require snippet new_loadout-fattribs >>>*/
2406/*<<< require snippet show_info >>>*/
2407/*<<< require snippet context_menu >>>*/
2408/*<<< require snippet formatted_attributes >>>*/
2409/*<<< require snippet graph_common >>>*/
2410/*<<< require snippet capacitor >>>*/
2411/*<<< require snippet loadout_undo >>>*/
2412
2413
2414
2415osmium_user_initiated = false;
2416osmium_user_initiated_stack = [];
2417
2418osmium_clfspinner = undefined;
2419osmium_clfspinner_level = 0;
2420
2421osmium_must_send_clf = false;
2422osmium_sending_clf = false;
2423osmium_next_clf_opts = undefined;
2424
2425osmium_load_static_client_data = function(staticver, onsuccess) {
2426 var idx = 'osmium_static_client_data_' + staticver;
2427
2428 var onsuccess2 = function(json) {
2429 osmium_groups = json.groups;
2430 osmium_types = json.groups.types;
2431 osmium_charges = json.charges;
2432 osmium_metagroups = json.metagroups;
2433 osmium_module_states = json.modulestates;
2434 osmium_module_state_names = json.modulestatenames;
2435 osmium_slot_types = json.slottypes;
2436 osmium_ship_slots = json.shipslots;
2437 osmium_chargedmg = json.chargedmg;
2438 osmium_targetclass = json.targetclass;
2439 osmium_damage_profiles = json.dmgprofiles;
2440 osmium_booster_side_effects = json.boostersideeffects;
2441 osmium_modes = json.modes;
2442
2443 /* Module states as they are defined in the CLF specification */
2444 osmium_states = ['offline', 'online', 'active', 'overloaded'];
2445
2446 return onsuccess(json);
2447 };
2448
2449 try {
2450 for(var i = 0; i < staticver; ++i) {
2451 localStorage.removeItem('osmium_static_client_data_' + i);
2452 }
2453
2454 var cdata = localStorage.getItem(idx);
2455 if(cdata !== null) {
2456 return onsuccess2(JSON.parse(cdata));
2457 }
2458 } catch(e) { /* Incognito mode probably */ }
2459
2460 $.ajax({
2461 type: 'GET',
2462 url: osmium_relative + '/static-' + staticver + '/cache/clientdata.json',
2463 dataType: 'json',
2464 error: function(xhr, error, httperror) {
2465 if(xhr.readyState === 0 || xhr.status === 0) {
2466 /* User probably clicked cancel button or is closing
2467 * the page */
2468 return;
2469 }
2470
2471 alert('Could not fetch static client data: ' + error + ' (' + httperror
2472 + '). Try refreshing the page and report if the problem persists.');
2473 },
2474 success: function(json) {
2475 try { localStorage.setItem(idx, JSON.stringify(json)); }
2476 catch(e) { /* Incognito mode probably */ }
2477 return onsuccess2(json);
2478 }
2479 });
2480};
2481
2482osmium_user_initiated_push = function(value) {
2483 osmium_user_initiated_stack.push(osmium_user_initiated);
2484 osmium_user_initiated = value;
2485};
2486
2487osmium_user_initiated_pop = function() {
2488 osmium_user_initiated = osmium_user_initiated_stack.pop();
2489};
2490
2491
2492
2493osmium_register_keyboard_command(
2494 'ctrl+l', 'regen-from-clf',
2495 'Regenerate most DOM elements from the CLF.',
2496 function() {
2497 osmium_gen();
2498 return false;
2499 }
2500);
2501
2502osmium_register_keyboard_command(
2503 null, 'debug-log-clf',
2504 'Log the current CLF to the Javascript console.',
2505 function() {
2506 console.log(osmium_clf);
2507 console.log(JSON.stringify(osmium_clf));
2508 return false;
2509 }
2510);
2511
2512
2513
2514/**
2515 * Synchronize the CLF with the server and update the attribute list,
2516 * etc. It is safe to call this function repeatedly in a short amount
2517 * of time, it has built-in rate limiting. Requires osmium_clftype and
2518 * to be set. Will call osmium_on_clf_payload if defined with the
2519 * payload as parameter. Will also call osmium_on_clftoken_change if
2520 * defined when the clf token changes, with the old and new tokens as
2521 * parameters.
2522 *
2523 * If specified, opts is an object which can contain any of the following properties:
2524 *
2525 * - params: send these additional params to process_clf
2526 * - before: function(), called before actually sending the CLF
2527 * - after: function(), called when process_clf is done
2528 * - success: function(payload), called when process_clf is done and didn't throw an error
2529 */
2530osmium_commit_clf = function(opts) {
2531 osmium_must_send_clf = true;
2532
2533 if(osmium_sending_clf) {
2534 if(opts !== undefined) {
2535 osmium_next_clf_opts = opts;
2536 }
2537
2538 return;
2539 }
2540 osmium_sending_clf = true;
2541
2542 osmium_send_clf(opts);
2543};
2544
2545/** @internal */
2546osmium_send_clf = function(opts) {
2547 if(!osmium_must_send_clf) {
2548 osmium_sending_clf = false;
2549 return;
2550 }
2551 osmium_must_send_clf = false;
2552
2553 if(opts === undefined) {
2554 opts = osmium_next_clf_opts;
2555 osmium_next_clf_opts = undefined;
2556 }
2557
2558 if(opts === undefined) {
2559 opts = {};
2560 }
2561
2562 var postopts = $.extend({
2563 type: osmium_clftype,
2564 'o___csrf': osmium_token,
2565 relative: osmium_relative,
2566 clf: osmium_compress_json(osmium_clf),
2567 clftoken: osmium_clftoken
2568 }, (("params" in opts) ? opts.params : {}));
2569
2570 osmium_clfspinner_push();
2571
2572 if("before" in opts) opts.before();
2573
2574 $.ajax({
2575 type: 'POST',
2576 url: osmium_relative + '/internal/syncclf',
2577 data: postopts,
2578 dataType: 'json',
2579 complete: function() {
2580 osmium_clfspinner_pop();
2581 if("after" in opts) {
2582 opts.after();
2583 }
2584 },
2585 error: function(xhr, error, httperror) {
2586 if(xhr.readyState === 0 || xhr.status === 0) {
2587 return;
2588 }
2589
2590 alert('Could not sync loadout with remote: ' + error + ' (' + httperror
2591 + '). This shouldn\'t normally happen, try again or refresh the page. Please report if the problem persists.');
2592 setTimeout(osmium_send_clf, 500);
2593 },
2594 success: function(payload) {
2595 if(osmium_clftoken !== payload.clftoken) {
2596 if(typeof(osmium_on_clf_token_change) === 'function') {
2597 osmium_on_clf_token_change(osmium_clftoken, payload.clftoken);
2598 }
2599 osmium_clftoken = payload.clftoken;
2600 }
2601
2602 osmium_capacitors = payload.capacitors;
2603 osmium_ia = payload.ia;
2604
2605 if("slots" in payload) osmium_clf_slots = payload.slots;
2606 if("hardpoints" in payload) osmium_clf_hardpoints = payload.hardpoints;
2607
2608 osmium_update_slotcounts();
2609
2610 for(var key in osmium_capacitors) {
2611 osmium_regen_remote_capacitor(key);
2612 }
2613
2614 $("tr.error.clferror").removeClass('error').removeClass('clferror');
2615 $("tr.error_message.clferror").remove();
2616 $("p.error_box.clferror").remove();
2617 $(".clferror").removeClass('clferror');
2618
2619 if("form-errors" in payload) {
2620 for(var i = 0; i < payload['form-errors'].length; ++i) {
2621 var err = payload['form-errors'][i];
2622
2623 var tr = $(document.createElement('tr'));
2624 var td = $(document.createElement('td'));
2625 var p = $(document.createElement('p'));
2626
2627 tr.addClass('error_message').addClass('clferror');
2628 td.attr('colspan', '2');
2629 p.text(err[2]);
2630 td.append(p);
2631 tr.append(td);
2632
2633 $(err[1]).closest('tr').addClass('error').addClass('clferror').before(tr);
2634 if(err[0]) {
2635 $("a[href='#" + err[0] + "']").click();
2636 }
2637 }
2638 }
2639
2640 if("p-errors" in payload) {
2641 for(var i = 0; i < payload['p-errors'].length; ++i) {
2642 var err = payload['p-errors'][i];
2643
2644 var p = $(document.createElement('p'));
2645 p.addClass('error_box').addClass('clferror').text(err[2]);
2646
2647 $(err[1]).before(p);
2648 if(err[0]) {
2649 $("a[href='#" + err[0] + "']").click();
2650 }
2651 }
2652 }
2653
2654 $('div#computed_attributes').empty().append($(payload.attributes).children());
2655 osmium_clf_rawattribs = payload.rawattribs;
2656 osmium_gen_fattribs();
2657 osmium_init_fattribs();
2658
2659 $("section#modules div.slots li.hasattribs, section#drones div.drones li.hasattribs")
2660 .removeClass('hasattribs')
2661 .children('small.attribs').remove()
2662 ;
2663
2664 var s, el;
2665
2666 for(var i = 0; i < osmium_ia.length; ++i) {
2667 if(!("fshort" in osmium_ia[i])) continue;
2668
2669 s = $(document.createElement('small'));
2670 s.text(osmium_ia[i].fshort);
2671 if("flong" in osmium_ia[i]) {
2672 s.prop('title', osmium_ia[i].flong);
2673 }
2674 s.addClass('attribs');
2675
2676 if(osmium_ia[i].location[0] === "module") {
2677 el = $("section#modules div.slots." + osmium_ia[i].location[1] + " li")
2678 .filter(function() {
2679 return $(this).data('index') == osmium_ia[i].location[2];
2680 });
2681 } else if(osmium_ia[i].location[0] === "drone") {
2682 el = $("section#drones div.drones.space li").filter(function() {
2683 return $(this).data('typeid') == osmium_ia[i].location[1];
2684 });
2685 } else {
2686 continue;
2687 }
2688
2689 el.addClass('hasattribs').append(s);
2690 }
2691
2692 $("section#modules div.slots li > span.charge.hasncycles").removeClass('hasncycles')
2693 .children('span.ncycles').remove();
2694 for(var i = 0; i < payload.ncycles.length; ++i) {
2695 var s = $(document.createElement('span'));
2696 s.text(payload.ncycles[i][2]);
2697 s.prop('title', 'Number of module cycles before having to reload');
2698 s.addClass('ncycles');
2699
2700 $("section#modules div.slots." + payload.ncycles[i][0] + " li").filter(function() {
2701 return $(this).data('index') == payload.ncycles[i][1];
2702 }).children('span.charge').addClass('hasncycles').append(s);
2703 }
2704
2705 osmium_highlight_missing_prereqs(payload.missingprereqs);
2706
2707 $("section#drones small.bayusage").text(
2708 osmium_clf_rawattribs.dronecapacityused
2709 + ' / ' + osmium_clf_rawattribs.dronecapacity + ' m³'
2710 ).toggleClass(
2711 'overflow',
2712 osmium_clf_rawattribs.dronecapacityused > osmium_clf_rawattribs.dronecapacity
2713 );
2714 $("section#drones small.bandwidth").text(
2715 osmium_clf_rawattribs.dronebandwidthused
2716 + ' / ' + osmium_clf_rawattribs.dronebandwidth + ' Mbps'
2717 ).toggleClass(
2718 'overflow',
2719 osmium_clf_rawattribs.dronebandwidthused > osmium_clf_rawattribs.dronebandwidth
2720 );
2721 var ndrones = 0;
2722 var dp = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
2723 if("inspace" in dp) {
2724 for(var i = 0; i < dp.inspace.length; ++i) {
2725 ndrones += dp.inspace[i].quantity;
2726 }
2727 }
2728 $("section#drones small.maxdrones").text(
2729 ndrones + ' / ' + osmium_clf_rawattribs.maxactivedrones
2730 ).toggleClass(
2731 'overflow',
2732 ndrones > osmium_clf_rawattribs.maxactivedrones
2733 );
2734 osmium_clf_rawattribs.activedrones = ndrones;
2735
2736 if(typeof(osmium_on_clf_payload) === 'function') {
2737 osmium_on_clf_payload(payload);
2738 }
2739
2740 if("success" in opts) opts.success(payload);
2741 setTimeout(osmium_send_clf, 500);
2742 }
2743 });
2744};
2745
2746osmium_compress_json = function(json) {
2747 return btoa(RawDeflate.deflate(
2748 JSON.stringify(json).replace(/[\u007F-\uFFFF]/g, function(m) {
2749 /* Thanks to Jason S. for this neat code, see
2750 * http://stackoverflow.com/a/4901205/615776 */
2751 return "\\u" + ('0000' + m.charCodeAt(0).toString(16)).slice(-4);
2752 })
2753 ));
2754};
2755
2756osmium_clfspinner_push = function() {
2757 if(osmium_clfspinner_level === 0) {
2758 if(osmium_clfspinner === undefined) {
2759 osmium_clfspinner = $(document.createElement('span'))
2760 .prop('id', 'clfspinner')
2761 .hide()
2762 ;
2763
2764 osmium_clfspinner
2765 .append($(document.createElement('span')).addClass('spinner'))
2766 .append(' Osmium is thinking!')
2767 ;
2768
2769 $('body').append(osmium_clfspinner);
2770 }
2771
2772 osmium_clfspinner.fadeIn(100);
2773 }
2774
2775 ++osmium_clfspinner_level;
2776};
2777
2778osmium_clfspinner_pop = function() {
2779 --osmium_clfspinner_level;
2780
2781 if(osmium_clfspinner_level === 0) {
2782 osmium_clfspinner.fadeOut(1000);
2783 }
2784};
2785
2786osmium_load_common_data = function() {
2787 var d = $("div#osmium-data");
2788
2789 osmium_cdatastaticver = d.data('cdatastaticver');
2790 osmium_staticver = d.data('staticver');
2791 osmium_relative = d.data('relative');
2792 osmium_token = d.data('token');
2793 osmium_clftoken = d.data('clftoken');
2794 osmium_clf = d.data('clf');
2795 osmium_custom_damage_profiles = d.data('customdamageprofiles');
2796 osmium_skillsets = d.data('skillsets');
2797};
2798
2799osmium_highlight_missing_prereqs = function(missingprereqs) {
2800 $("section#modules div.slots > ul > li, section#drones div.drones > ul > li, section#implants div.implants > ul > li").each(function() {
2801 var li = $(this);
2802
2803 var s = li.children('span.name');
2804 if(li.data('typeid') in missingprereqs) {
2805 s.addClass('missingskill');
2806 } else {
2807 s.removeClass('missingskill');
2808 }
2809
2810 if(!li.hasClass('hascharge')) return;
2811 s = li.children('span.charge').children('span.name');
2812 if(li.data('chargetypeid') in missingprereqs) {
2813 s.addClass('missingskill');
2814 } else {
2815 s.removeClass('missingskill');
2816 }
2817 });
2818
2819 if("ship" in osmium_clf && "typeid" in osmium_clf.ship) {
2820 var s = $("section#ship h1 > strong > span.name")
2821 if(osmium_clf.ship.typeid in missingprereqs) {
2822 s.addClass('missingskill');
2823 } else {
2824 s.removeClass('missingskill');
2825 }
2826 }
2827};
2828/*<<< require external //cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.4.6/jquery.perfect-scrollbar-with-mousewheel.min.js >>>*/
2829/*<<< require css //cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.4.6/perfect-scrollbar.css >>>*/
2830/* Osmium
2831 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
2832 *
2833 * This program is free software: you can redistribute it and/or modify
2834 * it under the terms of the GNU Affero General Public License as published by
2835 * the Free Software Foundation, either version 3 of the License, or
2836 * (at your option) any later version.
2837 *
2838 * This program is distributed in the hope that it will be useful,
2839 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2840 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2841 * GNU Affero General Public License for more details.
2842 *
2843 * You should have received a copy of the GNU Affero General Public License
2844 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2845 */
2846
2847/*<<< require snippet perfectscrollbar >>>*/
2848
2849osmium_init_sources = function() {
2850 $('div#nlsources > section#search > form > ul.filters, div#nlsources > section#browse > ul.filters, div#nlsources > section#shortlist > ul.filters').each(function() {
2851 var t = $(this);
2852 var li, input, a, b;
2853
2854 for(var id in osmium_metagroups) {
2855 li = $(document.createElement('li'));
2856
2857 input = $(document.createElement('input'));
2858 input.prop('type', 'hidden');
2859 input.prop('name', 'mg[' + id + ']');
2860 input.val('1');
2861 input.data('metagroupid', id);
2862 li.append(input);
2863
2864 a = $(document.createElement('a'));
2865 a.addClass('metagroup');
2866 a.addClass('mg' + id);
2867 a.addClass('on');
2868 a.prop('title', osmium_metagroups[id] + ' types');
2869 a.append(
2870 $(document.createElement('img'))
2871 .prop('alt', osmium_metagroups[id])
2872 .prop('src', osmium_relative + '/static/icons/metagroups.svg') /* XXX: staticver? */
2873 );
2874 li.append(a);
2875
2876 li.append(b = a.clone().removeClass('on').addClass('off'));
2877 a.prop('title', a.prop('title') + ' [shown]');
2878 b.prop('title', b.prop('title') + ' [hidden]');
2879
2880 t.append(li);
2881 }
2882 }).find('a.metagroup').click(function() {
2883 var t = $(this).parent().children('input:first-child');
2884 if(t.val() === '1') {
2885 t.val('0');
2886 } else {
2887 t.val('1');
2888 }
2889
2890 $(this).closest('form').find('input[type="search"]').trigger('mark-dirty');
2891 $(this).blur();
2892 });
2893
2894 $('div#nlsources > section#search > form').submit(function() {
2895 var t = $(this);
2896 var s = t.find('input[type="submit"]');
2897 var ul = t.parent().children('ul.results');
2898 var li, img, p, spinner;
2899
2900 if(t.data('dirty') === false) {
2901 ul.find('li').first().trigger('dblclick');
2902 return false;
2903 }
2904 t.data('dirty', false);
2905
2906 if(s.prop('disabled')) return false;
2907 s.prop('disabled', true);
2908 ul.empty();
2909 t.parent().children('p.notice').remove();
2910 ul.after(
2911 spinner = $(document.createElement('p'))
2912 .addClass('loading')
2913 .addClass('placeholder')
2914 .text("Searching types…")
2915 .append(
2916 $(document.createElement('div'))
2917 .addClass('spinner')
2918 )
2919 );
2920
2921 var data = {};
2922 t.find('input[type="hidden"][name][value]').each(function() {
2923 var i = $(this);
2924 data[i.prop('name')] = i.val();
2925 });
2926
2927 $.ajax({
2928 type: 'POST',
2929 dataType: 'json',
2930 url: "../../internal/searchtypes/" + encodeURIComponent(t.find("input[name='q']").val())
2931 .replace(/%20/g, "+"),
2932 data: data,
2933 success: function(json) {
2934 for(var i in json.payload) {
2935 if(!(json.payload[i] in osmium_types)) {
2936 alert('Type ' + json.payload[i] + ' not in static client data ; try deleting your cache and refreshing. Please report issue if this persists.');
2937 continue;
2938 }
2939
2940 var m = osmium_types[json.payload[i]];
2941 li = $(document.createElement('li'));
2942 li.addClass('module');
2943 li.data('typeid', m[0]);
2944 li.data('category', m[2]);
2945 li.data('subcategory', m[3]);
2946 li.addClass('mg' + m[4]);
2947 li.text(m[1]);
2948 li.prop('title', m[1]);
2949
2950 img = $(document.createElement('img'));
2951 img.prop('alt', '');
2952 img.prop('src', '//image.eveonline.com/Type/' + m[0] + '_64.png');
2953 li.prepend(img);
2954
2955 osmium_add_non_shortlist_contextmenu(li);
2956
2957 ul.append(li);
2958 }
2959
2960 if('warning' in json) {
2961 p = $(document.createElement('p'));
2962 p.addClass('placeholder');
2963 p.addClass('notice');
2964 p.html(json.warning);
2965
2966 ul.after(p);
2967 }
2968
2969 ul.closest('section').trigger('osmium-update-overflow');
2970 },
2971 complete: function() {
2972 if(ul.children('li').length === 0) {
2973 s.prop('dirty', true);
2974 } else {
2975 s.val('Add');
2976 }
2977
2978 s.prop('disabled', false);
2979 spinner.remove();
2980 }
2981 });
2982
2983 return false;
2984 }).find('input[type="search"]').on('mark-dirty', function() {
2985 $(this)
2986 .closest('form').data('dirty', true)
2987 .find('input[type="submit"]').val('Search')
2988 ;
2989 }).on('change', function() {
2990 $(this).trigger('mark-dirty');
2991 }).on('keydown', function(e) {
2992 if(e.which != 13) {
2993 $(this).trigger('mark-dirty');
2994 }
2995 });
2996
2997 osmium_add_metagroup_style("div#nlsources > section#browse > ", "div#nlsources > section#browse > div.mgroot");
2998 osmium_add_metagroup_style("div#nlsources > section#shortlist > ", "div#nlsources > section#shortlist > ul");
2999
3000 osmium_init_browser();
3001 osmium_init_shortlist();
3002
3003 $("div#nlsources > section").on('osmium-update-overflow', function() {
3004 var s = $(this);
3005 var mh;
3006
3007 s.css(
3008 'max-height',
3009 (mh = ($(window).height() - $("div#nlsources").offset().top - 64)) + "px"
3010 );
3011
3012 if(s[0].scrollHeight >= mh) {
3013 if(s.children('div.ps-scrollbar-y-rail').length === 0) {
3014 s.perfectScrollbar({
3015 wheelSpeed: 40,
3016 suppressScrollX: true
3017 });
3018 } else {
3019 s.perfectScrollbar('update');
3020 }
3021 } else {
3022 s.perfectScrollbar('destroy');
3023 }
3024
3025 return false;
3026 });
3027
3028 $(window).resize(function() { $("div#nlsources > section").trigger('osmium-update-overflow'); });
3029 $("div#nlsources > section").trigger('osmium-update-overflow');
3030};
3031
3032osmium_init_browser = function() {
3033 var section = $('div#nlsources > section#browse');
3034 var div, displaymg;
3035
3036 div = $(document.createElement('div'));
3037 div.addClass('mgroot');
3038
3039 var displaymg = function(parent, mg) {
3040 var ul, li, img, heading;
3041
3042 if("children" in osmium_groups[mg] && osmium_groups[mg].children.length > 0) {
3043 ul = $(document.createElement('ul'));
3044 ul.addClass('children');
3045
3046 for(var i in osmium_groups[mg].children) {
3047 li = $(document.createElement('li'));
3048 li.addClass('uninitialized');
3049 li.addClass('folded');
3050 li.data('mgid', osmium_groups[mg].children[i]);
3051
3052 heading = $(document.createElement('h4'));
3053 heading.text(osmium_groups[osmium_groups[mg].children[i]].name);
3054
3055 li.append(heading);
3056 ul.append(li);
3057 }
3058
3059 parent.append(ul);
3060 }
3061
3062 if("types" in osmium_groups[mg] && osmium_groups[mg].types.length > 0) {
3063 ul = $(document.createElement('ul'));
3064 ul.addClass('types');
3065
3066 for(var i in osmium_groups[mg].types) {
3067 var type = osmium_types[osmium_groups[mg].types[i]];
3068
3069 li = $(document.createElement('li'));
3070 li.addClass('module');
3071 li.data('typeid', type[0]);
3072 li.text(type[1]);
3073 li.prop('title', type[1]);
3074 li.data('category', type[2]);
3075 li.data('subcategory', type[3]);
3076 li.addClass('mg' + type[4]);
3077
3078 img = $(document.createElement('img'));
3079 img.prop('src', '//image.eveonline.com/Type/' + type[0] + '_64.png');
3080 img.prop('alt', '');
3081 li.prepend(img);
3082
3083 osmium_add_non_shortlist_contextmenu(li);
3084
3085 ul.append(li);
3086 }
3087
3088 parent.append(ul);
3089 }
3090 };
3091 displaymg(div, 'root');
3092
3093 section.append(div);
3094
3095 section.on('click', 'li.uninitialized', function() {
3096 var t = $(this);
3097 t.removeClass('uninitialized');
3098 displaymg(t, t.data('mgid'));
3099 });
3100
3101 section.on('click', 'li', function(e) {
3102 var t = $(this);
3103
3104 t.toggleClass('folded');
3105 e.stopPropagation();
3106
3107 if(t.parent().children('li:not(.folded)').length > 0) {
3108 t.parent().addClass('partiallyunfolded');
3109 } else {
3110 t.parent().removeClass('partiallyunfolded');
3111 }
3112
3113 t.closest('section').trigger('osmium-update-overflow');
3114 });
3115};
3116
3117osmium_init_shortlist = function() {
3118 var ul, li, img, section;
3119
3120 section = $('div#nlsources > section#shortlist');
3121
3122 ul = $(document.createElement('ul'));
3123 ul.addClass('types');
3124
3125 for(var i in osmium_shortlist) {
3126 var type = osmium_types[osmium_shortlist[i]];
3127
3128 li = $(document.createElement('li'));
3129 li.addClass('module');
3130 li.data('typeid', type[0]);
3131 li.data('category', type[2]);
3132 li.data('subcategory', type[3]);
3133 li.addClass('mg' + type[4]);
3134 li.text(type[1]);
3135 li.prop('title', type[1]);
3136
3137 img = $(document.createElement('img'));
3138 img.prop('alt', '');
3139 img.prop('src', '//image.eveonline.com/Type/' + type[0] + '_64.png');
3140 li.prepend(img);
3141
3142 osmium_add_shortlist_contextmenu(li);
3143
3144 ul.append(li);
3145 }
3146
3147 section.append(ul);
3148};
3149
3150osmium_add_metagroup_style = function(aselector, liselector) {
3151 $(aselector + " ul.filters > li > a.metagroup").click(function() {
3152 var t = $(this).parent().children('input:first-child');
3153 var mg = t.data('metagroupid');
3154 var v = t.val();
3155
3156 if(v === '1') {
3157 $('style.mg' + mg).remove();
3158 } else {
3159 var style = $(document.createElement('style'));
3160 style.prop('type', 'text/css');
3161 style.addClass('mg' + mg);
3162 style.text(liselector + ' li.module.mg' + mg + ' { display: none; }');
3163 $('head').append(style);
3164 }
3165 });
3166};
3167
3168osmium_add_add_to_fit_option = function(menu, source, opts) {
3169 if(osmium_loadout_readonly) return;
3170
3171 var name;
3172 var cat = source.data('category');
3173 var typeid = source.data('typeid');
3174
3175 if(cat === 'ship') name = 'Use ship';
3176 else if(cat === 'module') name = 'Fit module';
3177 else name = 'Add ' + cat;
3178
3179 osmium_ctxmenu_add_option(menu, name, function() {
3180 source.data({ qty: null, dest: null });
3181 osmium_add_to_clf(source);
3182 }, opts);
3183
3184 if(cat === 'drone') {
3185 osmium_ctxmenu_add_separator(menu);
3186
3187 osmium_ctxmenu_add_option(menu, 'Add 1 to bay', function() {
3188 source.data({ qty: 1, dest: 'bay' });
3189 osmium_add_to_clf(source);
3190 }, { });
3191
3192 osmium_ctxmenu_add_option(menu, 'Add 5 to bay', function() {
3193 source.data({ qty: 5, dest: 'bay' });
3194 osmium_add_to_clf(source);
3195 }, { });
3196
3197 osmium_ctxmenu_add_option(menu, 'Add 1 to space', function() {
3198 source.data({ qty: 1, dest: 'space' });
3199 osmium_add_to_clf(source);
3200 }, { });
3201
3202 osmium_ctxmenu_add_option(menu, 'Add 5 to space', function() {
3203 source.data({ qty: 5, dest: 'space' });
3204 osmium_add_to_clf(source);
3205 }, { });
3206 }
3207
3208 if(cat === 'module' && osmium_types[typeid][8] === 1) {
3209 osmium_ctxmenu_add_option(menu, 'Project on local', function() {
3210 $("a[href='#remote']").click();
3211 osmium_add_projected(typeid + '::', 'local');
3212 }, { });
3213 }
3214
3215 osmium_ctxmenu_add_separator(menu);
3216};
3217
3218osmium_add_generic_showinfo = function(menu, typeid) {
3219 osmium_ctxmenu_add_option(menu, "Show info", function() {
3220 osmium_showinfo({
3221 type: 'generic',
3222 typeid: typeid
3223 });
3224 }, { icon: osmium_showinfo_sprite_position });
3225};
3226
3227osmium_add_generic_browse = function(menu, typeid) {
3228 osmium_ctxmenu_add_subctxmenu(menu, "Compare", function() {
3229 var sub = osmium_ctxmenu_create();
3230
3231 osmium_ctxmenu_add_option(sub, "Compare variations", function() {
3232 window.open(osmium_relative + '/db/comparevariations/' + typeid + '/auto', '_blank');
3233 }, { icon: 'external.svg' });
3234
3235 var mg = osmium_types[typeid][9];
3236 if(mg > 0) {
3237 osmium_ctxmenu_add_option(sub, "Compare market group", function() {
3238 window.open(osmium_relative + '/db/comparemarketgroup/' + mg + '/auto', '_blank');
3239 }, { icon: 'external.svg' });
3240 }
3241
3242 return sub;
3243 }, {});
3244
3245 osmium_ctxmenu_add_option(menu, "Browse market group", function() {
3246 var mgroot = $("div#nlsources > section#browse div.mgroot");
3247 var groupid = osmium_types[typeid][9];
3248 var stack = [];
3249 var lasth4;
3250
3251 while(groupid !== undefined) {
3252 stack.push(groupid);
3253 groupid = osmium_groups[groupid].parent;
3254 }
3255
3256 mgroot.find('ul.children > li').not('.folded').children('h4').click();
3257
3258 while((groupid = stack.pop()) !== undefined) {
3259 lasth4 = mgroot.find('ul.children > li').filter(function() {
3260 return $(this).data('mgid') === groupid;
3261 }).children('h4').click();
3262 }
3263
3264 $("div#nlsources ul.tabs > li > a[href='#browse']").click();
3265 mgroot.parent()
3266 .scrollTop(0)
3267 .scrollTop(lasth4.offset().top - mgroot.parent().offset().top)
3268 .trigger('osmium-update-overflow')
3269 ;
3270 }, { icon: [ 0, 11, 64, 64 ] });
3271};
3272
3273osmium_add_non_shortlist_contextmenu = function(li) {
3274 osmium_ctxmenu_bind(li, function() {
3275 var menu = osmium_ctxmenu_create();
3276
3277 osmium_add_add_to_fit_option(menu, li, { 'default': true });
3278 osmium_ctxmenu_add_option(menu, "Add to shortlist", function() {
3279 if($('div#nlsources > section#shortlist > ul.types > li.module').filter(function() {
3280 return $(this).data('typeid') === li.data('typeid');
3281 }).length >= 1) {
3282 return;
3283 }
3284
3285 var n = li.clone(true).unbind();
3286 n.find('span.metalevel, span.slot').remove();
3287 osmium_add_shortlist_contextmenu(n);
3288
3289 $('div#nlsources > section#shortlist > ul.types').append(n);
3290 osmium_commit_shortlist();
3291 }, {});
3292 osmium_ctxmenu_add_separator(menu);
3293 osmium_add_generic_browse(menu, li.data('typeid'));
3294 osmium_add_generic_showinfo(menu, li.data('typeid'));
3295
3296 return menu;
3297 });
3298};
3299
3300osmium_add_shortlist_contextmenu = function(li) {
3301 osmium_ctxmenu_bind(li, function() {
3302 var menu = osmium_ctxmenu_create();
3303
3304 osmium_add_add_to_fit_option(menu, li, { 'default': true });
3305 osmium_ctxmenu_add_option(menu, "Remove from shortlist", function() {
3306 li.remove();
3307 osmium_commit_shortlist();
3308 }, {});
3309 osmium_ctxmenu_add_separator(menu);
3310 osmium_add_generic_browse(menu, li.data('typeid'));
3311 osmium_add_generic_showinfo(menu, li.data('typeid'));
3312
3313 return menu;
3314 });
3315};
3316
3317osmium_commit_shortlist = function() {
3318 var sl = [];
3319
3320 $("div#nlsources > section#shortlist > ul.types > li.module").each(function() {
3321 sl.push($(this).data('typeid'));
3322 });
3323
3324 osmium_put_setting('shortlist_modules', sl);
3325};
3326/* Osmium
3327 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
3328 *
3329 * This program is free software: you can redistribute it and/or modify
3330 * it under the terms of the GNU Affero General Public License as published by
3331 * the Free Software Foundation, either version 3 of the License, or
3332 * (at your option) any later version.
3333 *
3334 * This program is distributed in the hope that it will be useful,
3335 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3336 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3337 * GNU Affero General Public License for more details.
3338 *
3339 * You should have received a copy of the GNU Affero General Public License
3340 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3341 */
3342
3343osmium_gen_control = function() {
3344 var submit = $("section#control input#submit_loadout");
3345 if(!submit.hasClass('force')) {
3346 submit
3347 .prop('disabled', 'disabled')
3348 .prop('title', 'Select a ship before submitting your loadout.')
3349 ;
3350 }
3351
3352 if(!("metadata" in osmium_clf)) return;
3353 if(!("X-Osmium-update-reason" in osmium_clf.metadata)) return;
3354 $("section#control input#ureason").val(osmium_clf.metadata['X-Osmium-update-reason']);
3355};
3356
3357osmium_init_control = function() {
3358 $("section#control form").submit(function() {
3359 return false;
3360 });
3361
3362
3363 var lockcontrol = function() {
3364 var s = $("section#control");
3365 s.find('input, select').prop('disabled', true);
3366 s.append($(document.createElement('span')).addClass('spinner'));
3367 };
3368
3369 var unlockcontrol = function() {
3370 var s = $("section#control");
3371 s.find('input, select').prop('disabled', false);
3372 s.find('span.spinner').remove();
3373 };
3374
3375 $("section#control input#export_loadout").click(function() {
3376 var b = $(this);
3377 var exporttype = $("section#control select#export_type").val();
3378
3379 osmium_commit_clf({
3380 params: {
3381 'export': true,
3382 'exportfmt': exporttype
3383 },
3384 success: function(payload) {
3385 osmium_modal_rotextarea('Exported loadout (' + exporttype + ')', payload['export-payload']);
3386 },
3387 before: lockcontrol,
3388 after: unlockcontrol,
3389 });
3390 });
3391
3392 $("section#control input#submit_loadout").click(function() {
3393 var b = $(this);
3394
3395 osmium_commit_clf({
3396 params: {
3397 submit: true,
3398 },
3399 success: function(payload) {
3400 if("submit-error" in payload) {
3401 alert(payload['submit-error']);
3402 } else if("submit-loadout-uri" in payload) {
3403 window.location.replace(payload['submit-loadout-uri']);
3404 }
3405 },
3406 before: lockcontrol,
3407 after: unlockcontrol,
3408 });
3409 });
3410
3411 $("section#control input#ureason").change(function() {
3412 if(!("metadata" in osmium_clf)) {
3413 osmium_clf.metadata = {};
3414 }
3415
3416 osmium_clf.metadata['X-Osmium-update-reason'] = $("section#control input#ureason").val();
3417 osmium_commit_clf();
3418 osmium_undo_push();
3419 });
3420};
3421
3422osmium_loadout_can_be_submitted = function() {
3423 var submit = $("section#control input#submit_loadout");
3424 if(!submit.hasClass('force')) {
3425 submit
3426 .removeProp('disabled')
3427 .prop('title', '')
3428 ;
3429 }
3430};
3431/* Osmium
3432 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
3433 *
3434 * This program is free software: you can redistribute it and/or modify
3435 * it under the terms of the GNU Affero General Public License as published by
3436 * the Free Software Foundation, either version 3 of the License, or
3437 * (at your option) any later version.
3438 *
3439 * This program is distributed in the hope that it will be useful,
3440 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3441 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3442 * GNU Affero General Public License for more details.
3443 *
3444 * You should have received a copy of the GNU Affero General Public License
3445 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3446 */
3447
3448/*<<< require snippet new_loadout-control >>>*/
3449
3450osmium_gen_ship = function() {
3451 var section = $('section#ship');
3452 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
3453 var img, h, small, shipname, groupname;
3454
3455 if("ship" in osmium_clf && "typeid" in osmium_clf.ship) {
3456 groupname = osmium_types[osmium_clf.ship.typeid][5];
3457 shipname = osmium_types[osmium_clf.ship.typeid][1];
3458
3459 img = $(document.createElement('img'));
3460 img.prop('src', '//image.eveonline.com/Render/' + osmium_clf.ship.typeid + '_256.png');
3461
3462 osmium_loadout_can_be_submitted();
3463
3464 var availslots = osmium_ship_slots[osmium_clf.ship.typeid];
3465 osmium_clf_slots = {
3466 high: availslots[0],
3467 medium: availslots[1],
3468 low: availslots[2],
3469 rig: availslots[3],
3470 subsystem: availslots[4]
3471 };
3472 osmium_clf_hardpoints = {
3473 turret: 0,
3474 launcher: 0
3475 };
3476 } else {
3477 groupname = '';
3478 shipname = 'ï½¢No ship selectedï½£';
3479
3480 img = $(document.createElement('div'));
3481 img.addClass('notype');
3482
3483 osmium_clf_slots = {
3484 high: 8,
3485 medium: 8,
3486 low: 8,
3487 rig: 3,
3488 subsystem: 5
3489 };
3490 osmium_clf_hardpoints = {
3491 turret: 0,
3492 launcher: 0
3493 };
3494 }
3495
3496 h = $(document.createElement('h1'));
3497 h.append(img);
3498
3499 small = $(document.createElement('small')).addClass('groupname').text(groupname);
3500 if(('X-mode' in p) && ('typeid' in p['X-mode'])) {
3501 small.append(' (' + osmium_modes[osmium_clf.ship.typeid][p['X-mode'].typeid] + ')');
3502 }
3503
3504 h.append(small);
3505 h.append($(document.createElement('strong')).append(
3506 $(document.createElement('span')).addClass('name').text(shipname)
3507 ).prop('title', shipname));
3508
3509 section.children('h1').remove();
3510 section.append(h);
3511};
3512
3513osmium_init_ship = function() {
3514 osmium_ctxmenu_bind($("section#ship"), function() {
3515 var menu = osmium_ctxmenu_create();
3516
3517 osmium_ctxmenu_add_option(menu, "Undo (C-z)", function() {
3518 osmium_undo_pop();
3519 osmium_commit_clf();
3520 osmium_user_initiated_push(false);
3521 osmium_gen();
3522 osmium_user_initiated_pop();
3523 }, { icon: [ 1, 13, 64, 64 ] });
3524
3525 osmium_ctxmenu_add_separator(menu);
3526
3527 if("ship" in osmium_clf && "typeid" in osmium_clf.ship
3528 && osmium_clf.ship.typeid in osmium_modes) {
3529 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
3530 var mtid = ('X-mode' in p) && ('typeid' in p['X-mode']) ? p['X-mode'].typeid : 0;
3531
3532 osmium_ctxmenu_add_subctxmenu(menu, 'Ship modes', function() {
3533 var smenu = osmium_ctxmenu_create();
3534 var modes = osmium_modes[osmium_clf.ship.typeid];
3535
3536 for(var t in modes) {
3537 osmium_ctxmenu_add_option(smenu, modes[t], (function(t) {
3538 return function() {
3539 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]['X-mode'] = { typeid: t };
3540 osmium_gen_ship();
3541 osmium_undo_push();
3542 osmium_commit_clf();
3543 };
3544 })(t), { toggled: t == mtid });
3545 }
3546
3547 return smenu;
3548 }, {});
3549 }
3550
3551 osmium_ctxmenu_add_subctxmenu(menu, "Reload times", function() {
3552 var smenu = osmium_ctxmenu_create();
3553
3554 osmium_ctxmenu_add_option(smenu, "Include in capacitor time", function() {
3555 osmium_clf.metadata['X-Osmium-capreloadtime'] = !osmium_clf.metadata['X-Osmium-capreloadtime'];
3556 osmium_undo_push();
3557 osmium_commit_clf();
3558 }, { toggled: osmium_clf.metadata['X-Osmium-capreloadtime'] });
3559
3560 osmium_ctxmenu_add_option(smenu, "Include in DPS", function() {
3561 osmium_clf.metadata['X-Osmium-dpsreloadtime'] = !osmium_clf.metadata['X-Osmium-dpsreloadtime'];
3562 osmium_undo_push();
3563 osmium_commit_clf();
3564 }, { toggled: osmium_clf.metadata['X-Osmium-dpsreloadtime'] });
3565
3566 osmium_ctxmenu_add_option(smenu, "Include in sustained tank", function() {
3567 osmium_clf.metadata['X-Osmium-tankreloadtime'] = !osmium_clf.metadata['X-Osmium-tankreloadtime'];
3568 osmium_undo_push();
3569 osmium_commit_clf();
3570 }, { toggled: osmium_clf.metadata['X-Osmium-tankreloadtime'] });
3571
3572 return smenu;
3573 }, {});
3574
3575 osmium_ctxmenu_add_separator(menu);
3576
3577 osmium_ctxmenu_add_option(menu, "DPS graphs…", function() {
3578 var hdr = $(document.createElement('header')).append(
3579 $(document.createElement('h2')).text('Damage per second graph ')
3580 .append($(document.createElement('a'))
3581 .text('(compare and tweak…)')
3582 .prop('href', osmium_relative + '/compare/dps/s,0,'
3583 + encodeURIComponent(window.location.href)
3584 + ',' + encodeURIComponent(osmium_clf.metadata.title)))
3585 );
3586 var form = $(document.createElement('form'))
3587 .prop('id', 'm-dpsg');
3588 var table = $(document.createElement('table'));
3589 var tbody = $(document.createElement('tbody'));
3590 var tr = $(document.createElement('tr'));
3591 tbody.append(tr);
3592 table.append(tbody);
3593 form.append(table);
3594
3595 var td, label, input;
3596
3597 td = $(document.createElement('td')).addClass('signatureradius');
3598 label = $(document.createElement('label'))
3599 .prop('for', 'm-dpsg-signatureradius')
3600 .text('Target signature radius: ')
3601 ;
3602 input = $(document.createElement('input'))
3603 .prop('type', 'text')
3604 .prop('id', 'm-dpsg-signatureradius')
3605 ;
3606 td.append([ label, input, " m" ]);
3607 tr.append(td);
3608
3609 td = $(document.createElement('td')).addClass('velocity');
3610 label = $(document.createElement('label'))
3611 .prop('for', 'm-dpsg-velocity')
3612 .text('Target velocity: ')
3613 ;
3614 input = $(document.createElement('input'))
3615 .prop('type', 'text')
3616 .prop('id', 'm-dpsg-velocity')
3617 ;
3618 td.append([ label, input, " m/s" ]);
3619 tr.append(td);
3620
3621 td = $(document.createElement('td')).addClass('distance');
3622 label = $(document.createElement('label'))
3623 .prop('for', 'm-dpsg-distance')
3624 .text('Target distance: ')
3625 ;
3626 input = $(document.createElement('input'))
3627 .prop('type', 'text')
3628 .prop('id', 'm-dpsg-distance')
3629 ;
3630 td.append([ label, input, " km" ]);
3631 tr.append(td);
3632
3633 td = $(document.createElement('td'));
3634 input = $(document.createElement('input'))
3635 .prop('type', 'submit')
3636 .val('Generate graph')
3637 ;
3638 td.append(input);
3639 tr.append(td);
3640
3641 var ctx = $(document.createElement('div')).prop('id', 'm-dpsg-ctx');
3642
3643 form.on('submit', function(e) {
3644 e.preventDefault();
3645
3646 var tsr, tv, td;
3647 tsr = parseFloat(form.find('td.signatureradius input').val());
3648 tv = parseFloat(form.find('td.velocity input').val());
3649 td = parseFloat(form.find('td.distance input').val());
3650
3651 var nans = 0;
3652 if(isNaN(tsr)) ++nans;
3653 if(isNaN(tv)) ++nans;
3654 if(isNaN(td)) ++nans;
3655
3656 if(nans !== 1 && nans !== 2) {
3657 alert('You must fill exactly one or two fields with number values.');
3658 return false;
3659 }
3660
3661 ctx.empty();
3662
3663 if(nans === 1) {
3664 var genfunc, xlabel, xmax;
3665 var limits = osmium_probe_boundaries_from_ia(osmium_ia, tsr, tv, td);
3666
3667 if(isNaN(tsr)) {
3668 genfunc = function(x) { return [ x, tv, td ]; };
3669 xlabel = "Target signature radius (m)";
3670 xmax = limits[0];
3671 } else if(isNaN(tv)) {
3672 genfunc = function(x) { return [ tsr, x, td ]; };
3673 xlabel = "Target velocity (m/s)";
3674 xmax = limits[1];
3675 } else if(isNaN(td)) {
3676 genfunc = function(x) { return [ tsr, tv, x ]; };
3677 xlabel = "Target distance (km)";
3678 xmax = limits[2];
3679 }
3680
3681 osmium_draw_dps_graph_1d(
3682 { foo: { ia: osmium_ia } },
3683 { foo: "hsl(0, 100%, 50%)" },
3684 ctx, xlabel, 0, xmax, genfunc,
3685 0, null
3686 );
3687 } else if(nans === 2) {
3688 var genfunc, xlabel, ylabel, xmax, ymax, b;
3689 b = osmium_probe_boundaries_from_ia(osmium_ia, tsr, tv, td);
3690
3691 if(!isNaN(tsr)) {
3692 genfunc = function(x, y) { return [ tsr, y, x ]; };
3693 ylabel = "Target velocity (m/s)";
3694 xlabel = "Target distance (km)";
3695 ymax = b[1]; xmax = b[2];
3696 } else if(!isNaN(tv)) {
3697 genfunc = function(x, y) { return [ y, tv, x ]; };
3698 ylabel = "Target signature radius (m)";
3699 xlabel = "Target distance (km)";
3700 ymax = b[0]; xmax = b[2];
3701 } else if(!isNaN(td)) {
3702 genfunc = function(x, y) { return [ y, x, td ]; };
3703 ylabel = "Target signature radius (m)";
3704 xlabel = "Target velocity (m/s)";
3705 ymax = b[0]; xmax = b[1];
3706 }
3707
3708 var maxdps = osmium_draw_dps_graph_2d(
3709 { foo: { ia: osmium_ia } },
3710 function(fracs, cmap) {
3711 for(var k in fracs) {
3712 return osmium_heat_color(fracs[k][0] / fracs[k][1]);
3713 }
3714 return osmium_heat_color(0);
3715 },
3716 ctx,
3717 xlabel, 0, xmax,
3718 ylabel, 0, ymax,
3719 genfunc,
3720 4
3721 );
3722
3723 osmium_draw_dps_legend(ctx, maxdps, osmium_heat_color);
3724 }
3725
3726 return false;
3727 });
3728
3729 var limits = osmium_probe_boundaries_from_ia(osmium_ia, NaN, NaN, NaN);
3730 form.find('td.signatureradius input').val(Math.round(limits[0] / 3).toString());
3731
3732 osmium_modal([ hdr, form, ctx ]);
3733 form.trigger('submit');
3734 }, {});
3735
3736 if("ship" in osmium_clf && "typeid" in osmium_clf.ship) {
3737 osmium_ctxmenu_add_separator(menu);
3738
3739 if(!osmium_loadout_readonly) {
3740 osmium_add_generic_browse(menu, osmium_clf.ship.typeid);
3741 }
3742
3743 osmium_ctxmenu_add_option(menu, "Show ship info", function() {
3744 osmium_showinfo({ type: "ship" });
3745 }, { icon: osmium_showinfo_sprite_position, 'default': true });
3746 }
3747
3748 if("ship" in osmium_clf && "typeid" in osmium_clf.ship) {
3749 osmium_ctxmenu_add_separator(menu);
3750
3751 if(!osmium_loadout_readonly) {
3752 osmium_add_generic_browse(menu, osmium_clf.ship.typeid);
3753 }
3754
3755 if (typeof CCPEVE !== 'undefined') {
3756 osmium_ctxmenu_add_option(menu, "Show IGB info", function() {
3757 osmium_showinfo_igb({ type: "ship" });
3758 }, { icon: osmium_showinfo_sprite_position, 'default': true });
3759 }
3760 }
3761
3762 return menu;
3763 });
3764};
3765/* Osmium
3766 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
3767 *
3768 * This program is free software: you can redistribute it and/or modify
3769 * it under the terms of the GNU Affero General Public License as published by
3770 * the Free Software Foundation, either version 3 of the License, or
3771 * (at your option) any later version.
3772 *
3773 * This program is distributed in the hope that it will be useful,
3774 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3775 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3776 * GNU Affero General Public License for more details.
3777 *
3778 * You should have received a copy of the GNU Affero General Public License
3779 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3780 */
3781
3782osmium_init_presets = function() {
3783 $('section#presets textarea#tpresetdesc').change(function() {
3784 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].presetdescription = $(this).val();
3785 osmium_commit_clf();
3786 osmium_undo_push();
3787 });
3788 $('section#presets textarea#tcpresetdesc').change(function() {
3789 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3790 var cpid = osmium_clf['X-Osmium-current-chargepresetid'];
3791 for(var i = 0; i < p.length; ++i) {
3792 if(p[i].id != cpid) continue;
3793 p[i].description = $(this).val();
3794 break;
3795 }
3796 osmium_commit_clf();
3797 osmium_undo_push();
3798 });
3799 $('section#presets textarea#tdpresetdesc').change(function() {
3800 osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']].presetdescription = $(this).val();
3801 osmium_commit_clf();
3802 osmium_undo_push();
3803 });
3804
3805 $('section#presets tr#rpresets select#spreset').change(function() {
3806 osmium_pre_preset_change();
3807 osmium_clf['X-Osmium-current-presetid'] = $(this).val();
3808 $('section#presets textarea#tpresetdesc').val(
3809 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].presetdescription
3810 );
3811
3812 osmium_clf['X-Osmium-current-chargepresetid'] =
3813 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets[0].id;
3814
3815 osmium_gen_charge_presets_only();
3816 osmium_commit_clf();
3817 osmium_post_preset_change();
3818 osmium_undo_push();
3819 });
3820 $('section#presets tr#rcpresets select#scpreset').change(function() {
3821 osmium_pre_preset_change();
3822 osmium_clf['X-Osmium-current-chargepresetid'] = $(this).val();
3823
3824 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3825 for(var i = 0; i < cps.length; ++i) {
3826 if(cps[i].id == osmium_clf['X-Osmium-current-chargepresetid']) {
3827 $('section#presets textarea#tcpresetdesc').val(cps[i].description);
3828 break;
3829 }
3830 }
3831
3832 osmium_commit_clf();
3833 osmium_post_preset_change();
3834 osmium_undo_push();
3835 });
3836 $('section#presets tr#rdpresets select#sdpreset').change(function() {
3837 osmium_pre_preset_change();
3838
3839 osmium_clf['X-Osmium-current-dronepresetid'] = $(this).val();
3840 $('section#presets textarea#tdpresetdesc').val(
3841 osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']].presetdescription
3842 );
3843
3844 osmium_commit_clf();
3845 osmium_post_preset_change();
3846 osmium_undo_push();
3847 });
3848
3849 var preset_name_exists = function(name) {
3850 for(var i = 0; i < osmium_clf.presets.length; ++i) {
3851 if(osmium_clf.presets[i].presetname === name) return true;
3852 }
3853 return false;
3854 };
3855 $('section#presets tr#rpresets input.createpreset').click(function() {
3856 var name = osmium_get_unique_preset_name('New preset', preset_name_exists);
3857 name = prompt('Enter the new preset name:', name);
3858 if(name !== null) {
3859 osmium_pre_preset_change();
3860 name = osmium_get_unique_preset_name(name, preset_name_exists);
3861 var id = osmium_clf.presets.push({
3862 presetname: name,
3863 presetdescription: '',
3864 modules: [],
3865 implants: [],
3866 boosters: [],
3867 chargepresets: [{
3868 id: 0,
3869 name: 'Default charge preset'
3870 }]
3871 }) - 1;
3872 osmium_clf['X-Osmium-current-presetid'] = id;
3873 osmium_clf['X-Osmium-current-chargepresetid'] = 0;
3874 osmium_gen_presets_only();
3875 osmium_commit_clf();
3876 osmium_post_preset_change();
3877 osmium_undo_push();
3878 }
3879 });
3880 $('section#presets tr#rpresets input.renamepreset').click(function() {
3881 var name = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].presetname;
3882 name = prompt('Enter the new preset name:', name);
3883 if(name !== null) {
3884 name = osmium_get_unique_preset_name(name, preset_name_exists);
3885 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].presetname = name;
3886 osmium_gen_presets_only();
3887 osmium_commit_clf();
3888 osmium_undo_push();
3889 }
3890 });
3891 $('section#presets tr#rpresets input.clonepreset').click(function() {
3892 osmium_pre_preset_change();
3893 var name = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].presetname;
3894 var id = osmium_clf.presets.push($.extend(
3895 true, {},
3896 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
3897 )) - 1;
3898 osmium_clf.presets[id].presetname = osmium_get_unique_clone_name(name, preset_name_exists);
3899 osmium_clf['X-Osmium-current-presetid'] = id;
3900 osmium_gen_presets_only();
3901 osmium_commit_clf();
3902 osmium_post_preset_change();
3903 osmium_undo_push();
3904 });
3905 $('section#presets tr#rpresets input.deletepreset').click(function() {
3906 osmium_pre_preset_change();
3907 osmium_clf.presets.splice(osmium_clf['X-Osmium-current-presetid'], 1);
3908 if(osmium_clf['X-Osmium-current-presetid'] >= osmium_clf.presets.length) {
3909 osmium_clf['X-Osmium-current-presetid'] = osmium_clf.presets.length - 1;
3910 }
3911 osmium_clf['X-Osmium-current-chargepresetid'] =
3912 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets[0].id;
3913 osmium_gen_presets_only();
3914 osmium_commit_clf();
3915 osmium_post_preset_change();
3916 osmium_undo_push();
3917 });
3918
3919 var charge_preset_name_exists = function(name) {
3920 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3921 for(var i = 0; i < cps.length; ++i) {
3922 if(cps[i].name === name) return true;
3923 }
3924 return false;
3925 };
3926 $('section#presets tr#rcpresets input.createpreset').click(function() {
3927 var name = osmium_get_unique_preset_name('New charge preset', charge_preset_name_exists);
3928 name = prompt('Enter the new preset name:', name);
3929 if(name !== null) {
3930 name = osmium_get_unique_preset_name(name, charge_preset_name_exists);
3931 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3932 var id = 0;
3933 for(var i = 0; i < cps.length; ++i) {
3934 if(cps[i].id >= id) {
3935 id = cps[i].id + 1;
3936 }
3937 }
3938 cps.push({
3939 id: id,
3940 name: name,
3941 description: ''
3942 });
3943 osmium_clf['X-Osmium-current-chargepresetid'] = id;
3944 osmium_gen_charge_presets_only();
3945 osmium_commit_clf();
3946 osmium_post_preset_change();
3947 osmium_undo_push();
3948 }
3949 });
3950 $('section#presets tr#rcpresets input.renamepreset').click(function() {
3951 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3952 var name;
3953 for(var i = 0; i < cps.length; ++i) {
3954 if(cps[i].id == osmium_clf['X-Osmium-current-chargepresetid']) {
3955 name = cps[i].name;
3956 break;
3957 }
3958 }
3959 name = prompt('Enter the new preset name:', name);
3960 if(name !== null) {
3961 name = osmium_get_unique_preset_name(name, charge_preset_name_exists);
3962 cps[i].name = name;
3963 osmium_gen_charge_presets_only();
3964 osmium_commit_clf();
3965 osmium_undo_push();
3966 }
3967 });
3968 $('section#presets tr#rcpresets input.clonepreset').click(function() {
3969 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
3970 var cp;
3971 var id = 0;
3972 for(var i = 0; i < cps.length; ++i) {
3973 if(cps[i].id == osmium_clf['X-Osmium-current-chargepresetid']) {
3974 cp = cps[i];
3975 }
3976 if(cps[i].id >= id) {
3977 id = cps[i].id + 1;
3978 }
3979 }
3980 var index = cps.push($.extend(true, {}, cp)) - 1;
3981 var oldcpid = osmium_clf['X-Osmium-current-chargepresetid'];
3982 osmium_clf['X-Osmium-current-chargepresetid'] = id;
3983 cps[index].id = id;
3984 cps[index].name = osmium_get_unique_clone_name(cp.name, charge_preset_name_exists);
3985
3986 for(var i = 0; i < osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
3987 .modules.length; ++i) {
3988 var m = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
3989 .modules[i];
3990 if(!("charges" in m)) continue;
3991
3992 for(var j = 0; j < m.charges.length; ++j) {
3993 if(m.charges[j].cpid === oldcpid) {
3994 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
3995 .modules[i].charges.push({
3996 cpid: id,
3997 typeid: m.charges[j].typeid
3998 });
3999 break;
4000 }
4001 }
4002 }
4003
4004 osmium_gen_charge_presets_only();
4005 osmium_commit_clf();
4006 osmium_post_preset_change();
4007 osmium_undo_push();
4008 });
4009 $('section#presets tr#rcpresets input.deletepreset').click(function() {
4010 var cps = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].chargepresets;
4011 var index;
4012 for(var i = 0; i < cps.length; ++i) {
4013 if(cps[i].id == osmium_clf['X-Osmium-current-chargepresetid']) {
4014 index = i;
4015 break;
4016 }
4017 }
4018 cps.splice(i, 1);
4019 osmium_clf['X-Osmium-current-chargepresetid'] = cps[0].id;
4020 osmium_gen_charge_presets_only();
4021 osmium_commit_clf();
4022 osmium_post_preset_change();
4023 osmium_undo_push();
4024 });
4025
4026
4027 var drone_preset_name_exists = function(name) {
4028 for(var i = 0; i < osmium_clf.drones.length; ++i) {
4029 if(osmium_clf.drones[i].presetname === name) return true;
4030 }
4031 return false;
4032 };
4033 $('section#presets tr#rdpresets input.createpreset').click(function() {
4034 var name = osmium_get_unique_preset_name('New drone preset', drone_preset_name_exists);
4035 name = prompt('Enter the new preset name:', name);
4036 if(name !== null) {
4037 name = osmium_get_unique_preset_name(name, drone_preset_name_exists);
4038 var id = osmium_clf.drones.push({
4039 presetname: name,
4040 presetdescription: '',
4041 inbay: [],
4042 inspace: []
4043 }) - 1;
4044 osmium_clf['X-Osmium-current-dronepresetid'] = id;
4045 osmium_gen_drone_presets_only();
4046 osmium_commit_clf();
4047 osmium_undo_push();
4048 }
4049 });
4050 $('section#presets tr#rdpresets input.renamepreset').click(function() {
4051 var name = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']].presetname;
4052 name = prompt('Enter the new preset name:', name);
4053 if(name !== null) {
4054 name = osmium_get_unique_preset_name(name, drone_preset_name_exists);
4055 osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']].presetname = name;
4056 osmium_gen_drone_presets_only();
4057 osmium_commit_clf();
4058 osmium_undo_push();
4059 }
4060 });
4061 $('section#presets tr#rdpresets input.clonepreset').click(function() {
4062 var name = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']].presetname;
4063 var id = osmium_clf.drones.push($.extend(
4064 true, {},
4065 osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']]
4066 )) - 1;
4067 osmium_clf.drones[id].presetname = osmium_get_unique_clone_name(name, drone_preset_name_exists);
4068 osmium_clf['X-Osmium-current-dronepresetid'] = id;
4069 osmium_gen_drone_presets_only();
4070 osmium_commit_clf();
4071 osmium_undo_push();
4072 });
4073 $('section#presets tr#rdpresets input.deletepreset').click(function() {
4074 osmium_clf.drones.splice(osmium_clf['X-Osmium-current-dronepresetid'], 1);
4075 if(osmium_clf['X-Osmium-current-dronepresetid'] >= osmium_clf.drones.length) {
4076 osmium_clf['X-Osmium-current-dronepresetid'] = osmium_clf.drones.length - 1;
4077 }
4078 osmium_gen_drone_presets_only();
4079 osmium_commit_clf();
4080 osmium_undo_push();
4081 });
4082};
4083
4084osmium_get_unique_preset_name = function(base, exists) {
4085 if(!exists(base)) {
4086 return base;
4087 } else {
4088 var i = 2;
4089 while(exists(base + " #" + i)) {
4090 ++i;
4091 }
4092 return base + " #" + i;
4093 }
4094};
4095
4096osmium_get_unique_clone_name = function(base, exists) {
4097 base = base.replace(/^(Clone of )+/, '').replace(/ #([2-9]|[1-9][0-9]+)$/, '');
4098 return osmium_get_unique_preset_name('Clone of ' + base, exists);
4099};
4100
4101osmium_gen_presets = function() {
4102 osmium_gen_presets_only();
4103 osmium_gen_drone_presets_only();
4104};
4105
4106osmium_gen_presets_only = function() {
4107 var p, option;
4108 var select = $('section#presets select#spreset');
4109
4110 select.empty();
4111 for(var i = 0; i < osmium_clf.presets.length; ++i) {
4112 p = osmium_clf.presets[i];
4113 option = $(document.createElement('option'));
4114 option.prop('value', i);
4115 option.text(p.presetname);
4116 select.append(option);
4117 }
4118 select.val(osmium_clf['X-Osmium-current-presetid']);
4119 p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
4120 $('section#presets textarea#tpresetdesc').val("presetdescription" in p ? p.presetdescription : '');
4121 $('section#presets tr#rpresets input.deletepreset').prop('disabled', osmium_clf.presets.length < 2);
4122
4123 osmium_gen_charge_presets_only();
4124};
4125
4126osmium_gen_charge_presets_only = function() {
4127 var option, cp;
4128 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
4129 var select = $('section#presets select#scpreset');
4130
4131 select.empty();
4132 for(var i = 0; i < p.chargepresets.length; ++i) {
4133 option = $(document.createElement('option'));
4134 option.prop('value', p.chargepresets[i].id);
4135 option.text(p.chargepresets[i].name);
4136 select.append(option);
4137 }
4138 select.val(osmium_clf['X-Osmium-current-chargepresetid']);
4139 for(var i = 0; i < p.chargepresets.length; ++i) {
4140 if(p.chargepresets[i].id == osmium_clf['X-Osmium-current-chargepresetid']) {
4141 cp = p.chargepresets[i];
4142 break;
4143 }
4144 }
4145 $('section#presets textarea#tcpresetdesc').val("description" in cp ? cp.description : '');
4146 $('section#presets tr#rcpresets input.deletepreset').prop('disabled', p.chargepresets.length < 2);
4147};
4148
4149osmium_gen_drone_presets_only = function() {
4150 var p, option;
4151 var select = $('section#presets select#sdpreset');
4152
4153 select.empty();
4154 for(var i = 0; i < osmium_clf.drones.length; ++i) {
4155 p = osmium_clf.drones[i];
4156 option = $(document.createElement('option'));
4157 option.prop('value', i);
4158 option.text(p.presetname);
4159 select.append(option);
4160 }
4161 select.val(osmium_clf['X-Osmium-current-dronepresetid']);
4162 p = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
4163 $('section#presets textarea#tdpresetdesc').val("presetdescription" in p ? p.presetdescription : '');
4164 $('section#presets tr#rdpresets input.deletepreset').prop('disabled', osmium_clf.drones.length < 2);
4165};
4166
4167osmium_pre_preset_change = function() {
4168 osmium_projected_clean();
4169};
4170
4171osmium_post_preset_change = function() {
4172 osmium_user_initiated_push(false);
4173 osmium_gen_modules();
4174 osmium_gen_projected();
4175 osmium_gen_drones();
4176 osmium_user_initiated_pop();
4177};
4178/* Osmium
4179 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
4180 *
4181 * This program is free software: you can redistribute it and/or modify
4182 * it under the terms of the GNU Affero General Public License as published by
4183 * the Free Software Foundation, either version 3 of the License, or
4184 * (at your option) any later version.
4185 *
4186 * This program is distributed in the hope that it will be useful,
4187 * but WITHOUT ANY WARRANTY; without even the implied warranty of
4188 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4189 * GNU Affero General Public License for more details.
4190 *
4191 * You should have received a copy of the GNU Affero General Public License
4192 * along with this program. If not, see <http://www.gnu.org/licenses/>.
4193 */
4194
4195osmium_init_metadata = function() {
4196 $('section#metadata select#password_mode').change(function() {
4197 var pm = $(this);
4198 var pw = $('section#metadata input#pw');
4199 var vis = $('section#metadata select#visibility');
4200
4201 if(pm.val() !== '0') {
4202 pw.prop('placeholder', 'Leave blank to keep current password');
4203 pw.prop('disabled', false);
4204 } else {
4205 pw.prop('placeholder', '');
4206 pw.prop('disabled', true);
4207 pw.val('');
4208 }
4209
4210 if(pm.val() === '2') {
4211 vis.prop('disabled', true);
4212 vis.val('1');
4213 } else {
4214 vis.prop('disabled', false);
4215 }
4216 }).change();
4217
4218 $('div#nlmain > section#metadata').find('input, textarea, select').change(function() {
4219 if(!("metadata" in osmium_clf)) {
4220 osmium_clf.metadata = {};
4221 }
4222
4223 osmium_clf.metadata.title = $("section#metadata input#name").val();
4224 osmium_clf.metadata.description = $("section#metadata textarea#description").val();
4225 osmium_clf['client-version'] = $("section#metadata select#evebuildnumber").val();
4226 osmium_clf.metadata['X-tags'] = $("section#metadata input#tags").val().split(/\s+/);
4227 osmium_clf.metadata['X-Osmium-view-permission'] = $("section#metadata select#view_perms").val();
4228 osmium_clf.metadata['X-Osmium-edit-permission'] = $("section#metadata select#edit_perms").val();
4229 osmium_clf.metadata['X-Osmium-visibility'] = $("section#metadata select#visibility").val();
4230 osmium_clf.metadata['X-Osmium-password-mode'] = $("section#metadata select#password_mode").val();
4231 osmium_clf.metadata['X-Osmium-clear-password'] = $("section#metadata input#pw").val();
4232
4233 osmium_commit_clf();
4234 osmium_undo_push();
4235 }).keyup(function() {
4236 //$(this).change(); /* XXX too much request spam? */
4237 });
4238
4239 $("section#metadata").on('click', 'ul.tags > li > a', function() {
4240 var t = $(this);
4241 var tags = $("section#metadata input#tags");
4242
4243 if(tags.val().match(new RegExp("(^|\\s)" + t.text() + "(\\s|$)")) === null) {
4244 tags.val(tags.val() + " " + t.text());
4245 }
4246
4247 t.blur();
4248 tags.trigger('change');
4249 });
4250};
4251
4252osmium_gen_metadata = function() {
4253 var section = $('div#nlmain > section#metadata');
4254
4255 if("client-version" in osmium_clf) {
4256 section.find("select#evebuildnumber").val(osmium_clf['client-version']);
4257 }
4258
4259 if(!("metadata" in osmium_clf)) return;
4260
4261 if("title" in osmium_clf.metadata) {
4262 section.find('input#name').val(osmium_clf.metadata.title);
4263 }
4264
4265 if("description" in osmium_clf.metadata) {
4266 section.find('textarea#description').val(osmium_clf.metadata.description);
4267 }
4268
4269 if("X-tags" in osmium_clf.metadata) {
4270 section.find('input#tags').val(osmium_clf.metadata['X-tags'].join(' '));
4271 }
4272
4273 section.find('select#edit_perms').val(osmium_clf.metadata['X-Osmium-edit-permission']);
4274 section.find('select#visibility').val(osmium_clf.metadata['X-Osmium-visibility']);
4275 section.find('select#view_perms').val(osmium_clf.metadata['X-Osmium-view-permission']);
4276 section.find('select#password_mode').val(osmium_clf.metadata['X-Osmium-password-mode']);
4277};
4278/* Osmium
4279 * Copyright (C) 2012, 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
4280 *
4281 * This program is free software: you can redistribute it and/or modify
4282 * it under the terms of the GNU Affero General Public License as published by
4283 * the Free Software Foundation, either version 3 of the License, or
4284 * (at your option) any later version.
4285 *
4286 * This program is distributed in the hope that it will be useful,
4287 * but WITHOUT ANY WARRANTY; without even the implied warranty of
4288 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4289 * GNU Affero General Public License for more details.
4290 *
4291 * You should have received a copy of the GNU Affero General Public License
4292 * along with this program. If not, see <http://www.gnu.org/licenses/>.
4293 */
4294
4295osmium_gen_modules = function() {
4296 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
4297 var cpid = osmium_clf['X-Osmium-current-chargepresetid'];
4298 var m, i, j, type, c, chargeid;
4299 var old_ias = {};
4300 var old_ncycles = {};
4301
4302 $('section#modules > div.slots > ul > li.hasattribs > small.attribs').each(function() {
4303 var s = $(this);
4304 var li = s.parent();
4305 var typeid = li.data('typeid');
4306 var index = li.data('index');
4307
4308 if(!(typeid in old_ias)) old_ias[typeid] = {};
4309 old_ias[typeid][index] = s.clone();
4310 });
4311
4312 $('section#modules > div.slots > ul > li > span.charge > span.ncycles').each(function() {
4313 var s = $(this);
4314 var li = s.parent().parent();
4315 var typeid = li.data('typeid');
4316 var index = li.data('index');
4317
4318 if(!(typeid in old_ncycles)) old_ncycles[typeid] = {};
4319 old_ncycles[typeid][index] = s.clone();
4320 });
4321
4322 $('section#modules > div.slots > ul > li').not('.placeholder').remove();
4323
4324 if(!("modules" in p)) p.modules = [];
4325
4326 for(i = 0; i < p.modules.length; ++i) {
4327 m = p.modules[i];
4328 chargeid = null;
4329 if("charges" in m) {
4330 for(j = 0; j < m.charges.length; ++j) {
4331 if(!("cpid" in m.charges[j])) {
4332 m.charges[j].cpid = 0;
4333 }
4334
4335 if(m.charges[j].cpid == cpid) {
4336 chargeid = m.charges[j].typeid;
4337 break;
4338 }
4339 }
4340 }
4341
4342 var li = osmium_add_module(m.typeid, m.index, m.state, chargeid);
4343
4344 if(m.typeid in old_ias && m.index in old_ias[m.typeid]) {
4345 li.addClass('hasattribs')
4346 .append(old_ias[m.typeid][m.index]);
4347 }
4348
4349 if(m.typeid in old_ncycles && m.index in old_ncycles[m.typeid]) {
4350 li.children('span.charge')
4351 .addClass('hasncycles')
4352 .append(old_ncycles[m.typeid][m.index]);
4353 }
4354 }
4355
4356 for(type in osmium_clf_slots) {
4357 $('section#modules > div.slots.' + type).data('type', type);
4358 }
4359
4360 osmium_update_slotcounts();
4361 osmium_projected_regen_local();
4362};
4363
4364osmium_init_modules = function() {
4365 $("section#modules > div.slots > h3 > span > small.groupcharges").on('click', function() {
4366 var t = $(this);
4367 var slotsdiv = t.parents("div.slots");
4368
4369 if(slotsdiv.hasClass('grouped')) {
4370 slotsdiv.removeClass('grouped').addClass('ungrouped');
4371 t.text('Charges are not grouped');
4372 } else {
4373 slotsdiv.removeClass('ungrouped').addClass('grouped');
4374 t.text('Charges are grouped');
4375 }
4376
4377 t.prop('title', t.text());
4378 }).each(function() {
4379 var t = $(this);
4380 t.prop('title', t.text());
4381 });
4382
4383 if(osmium_loadout_readonly) return;
4384
4385 $("section#modules > div.slots > ul").sortable({
4386 items: "li:not(.placeholder)",
4387 placeholder: "sortable-placeholder",
4388 start: function() {
4389 $("section#modules > div.slots").css('opacity', 0.5);
4390 $(this).addClass('sorting').parent().css('opacity', 1.0);
4391 },
4392 stop: function() {
4393 $("section#modules > div.slots").css('opacity', 1.0);
4394 $(this).removeClass('sorting');
4395 },
4396 update: function() {
4397 var z = 0;
4398 var map = {};
4399
4400 $("section#modules > div.slots").find('li').each(function() {
4401 var t = $(this).data('typeid');
4402 var i = $(this).data('index');
4403
4404 if(!t) return;
4405 if(!(t in map)) map[t] = {};
4406
4407 map[t][i] = z;
4408 ++z;
4409 });
4410
4411 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules.sort(function(x, y) {
4412 return map[x.typeid][x.index] - map[y.typeid][y.index];
4413 });
4414
4415 osmium_commit_clf();
4416 osmium_undo_push();
4417 }
4418 });
4419};
4420
4421osmium_update_slotcounts = function() {
4422 $('section#modules > div.slots').each(function() {
4423 var t = $(this);
4424 osmium_update_overflow(t);
4425 osmium_maybe_hide_slot_type(t);
4426 });
4427};
4428
4429osmium_maybe_hide_slot_type = function(slotsdiv) {
4430 if(slotsdiv.children('ul').find('li').length > 0) {
4431 slotsdiv.show();
4432 } else {
4433 slotsdiv.hide();
4434 }
4435};
4436
4437osmium_update_overflow = function(slotsdiv) {
4438 var smallcount = slotsdiv.find('h3 > span > small.counts');
4439 var used = slotsdiv.children('ul').children('li').not('.placeholder').length;
4440 var total = osmium_clf_slots[slotsdiv.data('type')];
4441
4442 smallcount.text(used + '/' + total);
4443
4444 var placeholders = slotsdiv.find('li.placeholder').length;
4445 var ideal = total - used;
4446 while(placeholders < ideal) {
4447 osmium_add_placeholder_module(slotsdiv);
4448 ++placeholders;
4449 }
4450 while(placeholders > ideal) {
4451 slotsdiv.find('li.placeholder').last().remove();
4452 --placeholders;
4453 }
4454
4455 if(used > total) {
4456 smallcount.addClass('overflow');
4457 slotsdiv.children('ul').children('li')
4458 .removeClass('overflow')
4459 .slice(total - used).addClass('overflow');
4460 } else {
4461 smallcount.removeClass('overflow');
4462 slotsdiv.children('ul').children('li.overflow').removeClass('overflow');
4463 }
4464};
4465
4466osmium_add_module = function(typeid, index, state, chargeid) {
4467 var m = osmium_types[typeid];
4468 var div = $('section#modules > div.' + m[3]);
4469 var ul = div.children('ul');
4470 var placeholders = ul.children('li.placeholder');
4471 var li, img, a, stateimg;
4472 var stateful, hascharges;
4473
4474 if(state === null) {
4475 if(osmium_module_states[typeid][2]) {
4476 /* Active state, if possible */
4477 state = osmium_states[2];
4478 } else if(osmium_module_states[typeid][1]) {
4479 /* Online state */
4480 state = osmium_states[1];
4481 } else {
4482 /* Offline state */
4483 state = osmium_states[0];
4484 }
4485 }
4486
4487 li = $(document.createElement('li'));
4488 li.data('typeid', typeid);
4489 li.data('slottype', m[3]);
4490 li.data('index', index);
4491 li.data('state', state);
4492 li.append($(document.createElement('span')).addClass('name').text(m[1]));
4493 li.prop('title', m[1]);
4494
4495 img = $(document.createElement('img'));
4496 img.prop('src', '//image.eveonline.com/Type/' + typeid + '_64.png');
4497
4498 li.prepend(img);
4499
4500 if(hascharges = (typeid in osmium_charges)) {
4501 li.on('remove_charge_nogroupcheck', function() {
4502 var span = li.children('span.charge');
4503 var charge = span.children('span.name');
4504
4505 li.data('chargetypeid', null);
4506 span.children('img, span.mainsprite').replaceWith(
4507 osmium_sprite('', 0, 28, 32, 32, 32, 32)
4508 );
4509 charge.empty();
4510 charge.append($(document.createElement('em')).text('(No charge)'));
4511
4512 var modules = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules;
4513 for(var i = 0; i < modules.length; ++i) {
4514 if(modules[i].index === index && modules[i].typeid === typeid) {
4515 /* Removing nonexistent charge */
4516 if(!("charges" in modules[i])) break;
4517
4518 var charges = modules[i].charges;
4519 var curcpid = osmium_clf['X-Osmium-current-chargepresetid'];
4520 var cpid;
4521 for(var j = 0; j < charges.length; ++j) {
4522 if(!("cpid" in charges[j])) {
4523 cpid = 0; /* The spec says a value of 0 must be assumed */
4524 } else {
4525 cpid = charges[j].cpid;
4526 }
4527
4528 if(curcpid == cpid) {
4529 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
4530 .modules[i].charges.splice(j, 1);
4531 break;
4532 }
4533 }
4534 break;
4535 }
4536 }
4537 }).on('remove_charge', function() {
4538 if(li.parents('div.slots').hasClass('grouped')) {
4539 li.parents('div.slots').find('li.hascharge').filter(function() {
4540 var t = $(this);
4541 return t.data('typeid') === li.data('typeid')
4542 && t.data('chargetypeid') === li.data('chargetypeid');
4543 }).trigger('remove_charge_nogroupcheck');
4544 } else {
4545 li.trigger('remove_charge_nogroupcheck');
4546 }
4547 });
4548
4549 var charge = $(document.createElement('span'));
4550 charge.addClass('charge');
4551 charge.text(',').append($(document.createElement('br')));
4552 charge.append($(document.createElement('img')).prop('alt', ''));
4553 charge.append($(document.createElement('span')).addClass('name'));
4554
4555 li.append(charge);
4556 li.addClass('hascharge');
4557
4558 if(chargeid === null) {
4559 li.trigger('remove_charge_nogroupcheck');
4560 } else {
4561 osmium_add_charge(li, chargeid);
4562 }
4563
4564 if(!osmium_loadout_readonly) {
4565 charge.on('dblclick', function(e) {
4566 /* When dblclicking the charge, remove the charge but not the module */
4567 li.trigger('remove_charge');
4568 osmium_commit_clf();
4569 osmium_undo_push();
4570 e.stopPropagation();
4571 return false;
4572 });
4573 }
4574 }
4575
4576 if(stateful = osmium_slot_types[m[3]][2]) {
4577 a = $(document.createElement('a'));
4578 stateimg = $(document.createElement('img'));
4579 a.addClass('toggle_state');
4580 stateimg.prop('alt', '');
4581 a.append(stateimg);
4582 li.append(a);
4583
4584 li.on('state_changed', function() {
4585 var a = li.children('a.toggle_state');
4586 var s = osmium_module_state_names[li.data('state')];
4587 a.empty();
4588
4589 a.append(osmium_sprite(
4590 s[0],
4591 s[1][0],
4592 s[1][1],
4593 s[1][2],
4594 s[1][3],
4595 16, 16
4596 ));
4597
4598 a.prop('title', s[0]);
4599 }).trigger('state_changed');
4600
4601 a.on('click', function() {
4602 var a = $(this);
4603 var li = a.parent();
4604 var state = li.data('state');
4605 var nextstate;
4606
4607 a.blur();
4608
4609 if(state === 'offline') {
4610 nextstate = (osmium_module_states[typeid][1] ? 'online' : 'offline');
4611 } else if(state === 'online') {
4612 nextstate = (osmium_module_states[typeid][2] ? 'active' : 'offline');
4613 } else if(state === 'active') {
4614 nextstate = (osmium_module_states[typeid][3] ? 'overloaded' : 'offline');
4615 } else if(state === 'overloaded') {
4616 nextstate = 'offline';
4617 }
4618
4619 osmium_set_module_state(li, nextstate);
4620 osmium_commit_clf();
4621 osmium_undo_push();
4622 return false;
4623 }).on('contextmenu', function() {
4624 var a = $(this);
4625 var li = a.parent();
4626 var state = li.data('state');
4627 var prevstate;
4628
4629 a.blur();
4630
4631 if(state === 'offline') {
4632 if(osmium_module_states[typeid][3]) {
4633 prevstate = 'overloaded';
4634 } else if(osmium_module_states[typeid][2]) {
4635 prevstate = 'active';
4636 } else if(osmium_module_states[typeid][1]) {
4637 prevstate = 'online';
4638 } else {
4639 prevstate = 'offline';
4640 }
4641 } else if(state === 'online') {
4642 prevstate = 'offline';
4643 } else if(state === 'active') {
4644 prevstate = 'online';
4645 } else if(state === 'overloaded') {
4646 prevstate = 'active';
4647 }
4648
4649 osmium_set_module_state(li, prevstate);
4650 osmium_commit_clf();
4651 osmium_undo_push();
4652 return false;
4653 }).on('dblclick', function(e) {
4654 /* Prevent dblclick fire on the <li> itself */
4655
4656 e.stopPropagation();
4657 return false;
4658 });
4659 }
4660
4661 if(placeholders.length > 0) {
4662 placeholders.first().before(li);
4663 } else {
4664 ul.append(li);
4665 }
4666
4667 if(osmium_user_initiated) {
4668 $('a[href="#modules"]').parent().click();
4669 }
4670
4671 li.on('remove_module', function() {
4672 var modules = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules;
4673 var li = $(this);
4674 var slotsdiv = li.closest('div.slots');
4675
4676 if(osmium_types[typeid][8] === 1) {
4677 osmium_user_initiated_push(false);
4678 var lis = $("section#projected div.pr-loadout.projected-local").find('li').filter(function() {
4679 var sli = $(this);
4680 return sli.data('typeid') === typeid && sli.data('index') === index;
4681 });
4682
4683 if(lis.length !== 1) {
4684 alert('could not detach module – please report!');
4685 console.log(typeid, index, modules);
4686 return;
4687 }
4688
4689 var fli = lis.first();
4690 jsPlumb.select({ source: fli }).detach();
4691
4692 osmium_user_initiated_pop();
4693 }
4694
4695 var found = false;
4696 for(var i = 0; i < modules.length; ++i) {
4697 if(modules[i].index === index && modules[i].typeid === typeid) {
4698 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules.splice(i, 1);
4699 found = true;
4700 break;
4701 }
4702 }
4703
4704 if(!found) {
4705 alert('could not delete module in CLF – please report!');
4706 return;
4707 }
4708
4709 li.remove();
4710
4711 if(slotsdiv.find('li.overflow').length > 0) {
4712 slotsdiv.find('li.overflow').first().removeClass('overflow');
4713 } else {
4714 osmium_add_placeholder_module(slotsdiv);
4715 }
4716
4717 if(osmium_types[typeid][8] === 1) {
4718 osmium_user_initiated_push(false);
4719 osmium_projected_regen_local();
4720 osmium_user_initiated_pop();
4721 }
4722 });
4723
4724 osmium_ctxmenu_bind(li, function() {
4725 var menu = osmium_ctxmenu_create();
4726
4727 if(!osmium_loadout_readonly) {
4728 osmium_ctxmenu_add_option(menu, "Unfit module", function() {
4729 li.trigger('remove_module');
4730 osmium_commit_clf();
4731 osmium_undo_push();
4732 }, { 'default': true });
4733
4734 osmium_ctxmenu_add_option(menu, "Unfit all of the same type", function() {
4735 li.parent().find('li').filter(function() {
4736 return $(this).data('typeid') === typeid
4737 }).trigger('remove_module');
4738
4739 osmium_commit_clf();
4740 osmium_undo_push();
4741 osmium_update_slotcounts();
4742 }, {});
4743
4744 osmium_ctxmenu_add_separator(menu);
4745 }
4746
4747 if(hascharges) {
4748 osmium_ctxmenu_add_subctxmenu(menu, "Charges", function() {
4749 var chargemenu = osmium_ctxmenu_create();
4750
4751 var charges_mg_pt = {}; /* metagroup -> parenttypeid -> chargetypeid */
4752 var charges_mg_pt_sorted = {}; /* metagroup -> [ [ parenttypeid, chargetypeids ], … ] */
4753 var mgcount = 0;
4754
4755 var append_charges = function(menu, chargetypeids, showhelpers) {
4756 showhelpers = showhelpers & (
4757 chargetypeids.length >= 2 && (chargetypeids[0] in osmium_chargedmg)
4758 && osmium_chargedmg[chargetypeids[0]] > 0
4759 );
4760
4761 if(showhelpers) {
4762 osmium_ctxmenu_add_option(menu, "More damage", function() {}, { enabled: false });
4763 osmium_ctxmenu_add_separator(menu);
4764 }
4765
4766 for(var i = 0; i < chargetypeids.length; ++i) {
4767 osmium_ctxmenu_add_option(
4768 menu,
4769 osmium_types[chargetypeids[i]][1],
4770 (function(chargeid) {
4771 return function() {
4772 var modules = osmium_clf.presets[
4773 osmium_clf['X-Osmium-current-presetid']
4774 ].modules;
4775
4776 for(var i = 0; i < modules.length; ++i) {
4777 if(modules[i].typeid === typeid && modules[i].index === index) {
4778 osmium_auto_add_charge_to_location(i, chargeid);
4779 osmium_commit_clf();
4780 osmium_undo_push();
4781 return;
4782 }
4783 }
4784 };
4785 })(chargetypeids[i]),
4786 { icon: "//image.eveonline.com/Type/" + chargetypeids[i] + "_64.png" }
4787 );
4788 }
4789
4790 if(showhelpers) {
4791 osmium_ctxmenu_add_separator(menu);
4792 osmium_ctxmenu_add_option(menu, "Less damage", function() {}, { enabled: false });
4793 }
4794 };
4795
4796 var pgroup = function(menu, charges_pt) {
4797 var showhelpers = charges_pt.length >= 2 && (charges_pt[0][1][0] in osmium_chargedmg)
4798 && osmium_chargedmg[charges_pt[0][1][0]] > 0;
4799
4800 if(showhelpers) {
4801 osmium_ctxmenu_add_option(menu, "More damage", function() {}, { enabled: false });
4802 osmium_ctxmenu_add_separator(menu);
4803 }
4804
4805 for(var z = 0; z < charges_pt.length; ++z) {
4806 if(charges_pt[z][1].length === 1) {
4807 append_charges(menu, charges_pt[z][1], false);
4808 } else {
4809 var c = osmium_types[charges_pt[z][0]];
4810
4811 osmium_ctxmenu_add_subctxmenu(menu, c[1], (function(typeids) {
4812 return function() {
4813 var smenu = osmium_ctxmenu_create();
4814 append_charges(smenu, typeids, true);
4815 return smenu;
4816 };
4817 })(charges_pt[z][1]), {
4818 icon: "//image.eveonline.com/Type/" + c[0] + "_64.png"
4819 });
4820 }
4821 }
4822
4823 if(showhelpers) {
4824 osmium_ctxmenu_add_separator(menu);
4825 osmium_ctxmenu_add_option(menu, "Less damage", function() {}, { enabled: false });
4826 }
4827 };
4828
4829 compare_damage = function(a, b) {
4830 var x = (a in osmium_chargedmg) ? osmium_chargedmg[a] : 0;
4831 var y = (b in osmium_chargedmg) ? osmium_chargedmg[b] : 0;
4832 return y < x ? -1 : (y > x ? 1 : 0);
4833 };
4834
4835 for(var i = 0; i < osmium_charges[typeid].length; ++i) {
4836 var t = osmium_types[osmium_charges[typeid][i]];
4837 var parent = t[7] > 0 ? t[7] : t[0];
4838
4839 if(!(t[4] in charges_mg_pt)) {
4840 charges_mg_pt[t[4]] = {};
4841 charges_mg_pt_sorted[t[4]] = {};
4842 ++mgcount;
4843 }
4844 if(!(parent in charges_mg_pt[t[4]])) {
4845 charges_mg_pt[t[4]][parent] = [];
4846 }
4847 charges_mg_pt[t[4]][parent].push(t[0]);
4848 }
4849
4850 for(var mg in charges_mg_pt) {
4851 var arr = [];
4852
4853 for(var pt in charges_mg_pt[mg]) {
4854 charges_mg_pt[mg][pt].sort(compare_damage);
4855 arr.push([ pt, charges_mg_pt[mg][pt] ]);
4856 }
4857
4858 arr.sort(function(a, b) {
4859 return compare_damage(a[1][0], b[1][0]);
4860 });
4861
4862 charges_mg_pt_sorted[mg] = arr;
4863 }
4864
4865 if(mgcount === 1) {
4866 for(var g in charges_mg_pt_sorted) {
4867 pgroup(chargemenu, charges_mg_pt_sorted[g]);
4868 }
4869 } else {
4870 for(var g in charges_mg_pt_sorted) {
4871 osmium_ctxmenu_add_subctxmenu(chargemenu, osmium_metagroups[g], (function(group) {
4872 return function() {
4873 var submenu = osmium_ctxmenu_create();
4874 pgroup(submenu, group);
4875 return submenu;
4876 };
4877 })(charges_mg_pt_sorted[g]), {
4878 icon: "//image.eveonline.com/Type/" + charges_mg_pt_sorted[g][0][0] + "_64.png"
4879 });
4880 }
4881 }
4882
4883 return chargemenu;
4884 }, { icon: "//image.eveonline.com/Type/" + osmium_charges[typeid][0] + "_64.png" });
4885
4886 osmium_ctxmenu_add_option(menu, "Remove charge", function() {
4887 li.trigger('remove_charge');
4888 osmium_commit_clf();
4889 osmium_undo_push();
4890 }, { icon: [ 0, 28, 32, 32 ] });
4891
4892 osmium_ctxmenu_add_separator(menu);
4893 }
4894
4895 if(stateful) {
4896 if(osmium_module_states[typeid][0]) {
4897 osmium_ctxmenu_add_option(menu, "Offline module", function() {
4898 osmium_set_module_state(li, "offline");
4899 osmium_commit_clf();
4900 osmium_undo_push();
4901 }, { icon: osmium_module_state_names['offline'][1] });
4902 }
4903 if(osmium_module_states[typeid][1]) {
4904 osmium_ctxmenu_add_option(menu, "Online module", function() {
4905 osmium_set_module_state(li, "online");
4906 osmium_commit_clf();
4907 osmium_undo_push();
4908 }, { icon: osmium_module_state_names['online'][1] });
4909 }
4910 if(osmium_module_states[typeid][2]) {
4911 osmium_ctxmenu_add_option(menu, "Activate module", function() {
4912 osmium_set_module_state(li, "active");
4913 osmium_commit_clf();
4914 osmium_undo_push();
4915 }, { icon: osmium_module_state_names['active'][1] });
4916 }
4917 if(osmium_module_states[typeid][3]) {
4918 osmium_ctxmenu_add_option(menu, "Toggle overload", function() {
4919 if(li.data('state') !== "overloaded") {
4920 osmium_set_module_state(li, "overloaded");
4921 } else {
4922 osmium_set_module_state(li, "active");
4923 }
4924 osmium_commit_clf();
4925 osmium_undo_push();
4926 }, { icon: osmium_module_state_names['overloaded'][1] });
4927 }
4928
4929 osmium_ctxmenu_add_separator(menu);
4930
4931 osmium_ctxmenu_add_option(menu, "Overload rack", function() {
4932 if(li.data('state') !== "overloaded") {
4933 li.closest('div.slots').find('li').each(function() {
4934 var t = $(this);
4935 var typeid = t.data('typeid');
4936 if(!(typeid in osmium_module_states)) return;
4937
4938 if(osmium_module_states[typeid][3]) {
4939 osmium_set_module_state(t, "overloaded");
4940 }
4941 });
4942 } else {
4943 li.closest('div.slots').find('li').each(function() {
4944 var t = $(this);
4945 if(t.data('state') !== 'overloaded') return;
4946 osmium_set_module_state(t, "active");
4947 });
4948 }
4949
4950 osmium_commit_clf();
4951 osmium_undo_push();
4952 }, { icon: osmium_module_state_names['overloaded'][1] });
4953
4954 osmium_ctxmenu_add_separator(menu);
4955 }
4956
4957 if(!osmium_loadout_readonly) {
4958 if(hascharges && li.data('chargetypeid') !== null) {
4959 osmium_ctxmenu_add_heading(menu, "Module");
4960 }
4961
4962 osmium_add_generic_browse(menu, typeid);
4963 osmium_ctxmenu_add_option(menu, "Show module info", function() {
4964 osmium_showinfo({
4965 type: "module",
4966 slottype: li.data('slottype'),
4967 index: li.data('index')
4968 });
4969 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
4970
4971 if (typeof CCPEVE !== 'undefined') {
4972 osmium_add_generic_browse(menu, typeid);
4973 osmium_ctxmenu_add_option(menu, "Show module IGB info", function() {
4974 osmium_showinfo_igb({
4975 type: "module",
4976 typeid: li.data('typeid'),
4977 slottype: li.data('slottype'),
4978 index: li.data('index')
4979 });
4980 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
4981 }
4982
4983 if(hascharges && li.data('chargetypeid') !== null) {
4984 osmium_ctxmenu_add_separator(menu);
4985 osmium_ctxmenu_add_heading(menu, "Charge");
4986
4987 osmium_add_generic_browse(menu, li.data('chargetypeid'));
4988 osmium_ctxmenu_add_option(menu, "Show charge info", function() {
4989 osmium_showinfo({
4990 type: "charge",
4991 slottype: li.data('slottype'),
4992 index: li.data('index')
4993 });
4994 }, { icon: osmium_showinfo_sprite_position });
4995
4996 if (typeof CCPEVE !== 'undefined') {
4997 osmium_ctxmenu_add_option(menu, "Show charge IGB info", function() {
4998 osmium_showinfo_igb({
4999 type: "charge",
5000 typeid: li.data('typeid'),
5001 slottype: li.data('slottype'),
5002 index: li.data('index')
5003 });
5004 }, { icon: osmium_showinfo_sprite_position });
5005 }
5006
5007 }
5008 } else {
5009 osmium_ctxmenu_add_option(menu, "Show module info", function() {
5010 osmium_showinfo({
5011 type: "module",
5012 slottype: li.data('slottype'),
5013 index: li.data('index')
5014 });
5015 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
5016
5017 if (typeof CCPEVE !== 'undefined') {
5018 osmium_ctxmenu_add_option(menu, "Show module IGB info", function() {
5019 osmium_showinfo_igb({
5020 type: "module",
5021 typeid: li.data('typeid'),
5022 slottype: li.data('slottype'),
5023 index: li.data('index')
5024 });
5025 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
5026 }
5027
5028 if(hascharges && li.data('chargetypeid') !== null) {
5029 osmium_ctxmenu_add_option(menu, "Show charge info", function() {
5030 osmium_showinfo({
5031 type: "charge",
5032 slottype: li.data('slottype'),
5033 index: li.data('index')
5034 });
5035 }, { icon: osmium_showinfo_sprite_position });
5036
5037 if (typeof CCPEVE !== 'undefined') {
5038 osmium_ctxmenu_add_option(menu, "Show charge IGB info", function() {
5039 osmium_showinfo_igb({
5040 type: "charge",
5041 typeid: li.data('chargetypeid'),
5042 slottype: li.data('slottype'),
5043 index: li.data('index')
5044 });
5045 }, { icon: osmium_showinfo_sprite_position });
5046 }
5047 }
5048 }
5049
5050 return menu;
5051 });
5052
5053 return li;
5054};
5055
5056osmium_add_placeholder_module = function(slotsdiv) {
5057 var ul = slotsdiv.children('ul');
5058 var li;
5059 var type = slotsdiv.data('type');
5060
5061 li = $(document.createElement('li'));
5062 li.addClass('placeholder');
5063 li.text('Unused ' + type + ' slot');
5064
5065 li.prepend(osmium_sprite(
5066 '',
5067 osmium_slot_types[type][1][0],
5068 osmium_slot_types[type][1][1],
5069 osmium_slot_types[type][1][2],
5070 osmium_slot_types[type][1][3],
5071 32, 32
5072 ));
5073 ul.append(li);
5074};
5075
5076osmium_set_module_state = function(li, newstate) {
5077 var index = li.data('index');
5078 var typeid = li.data('typeid');
5079
5080 li.data('state', newstate);
5081
5082 var modules = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules;
5083 for(var i = 0; i < modules.length; ++i) {
5084 if(modules[i].index === index && modules[i].typeid === typeid) {
5085 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5086 .modules[i].state = newstate;
5087 break;
5088 }
5089 }
5090
5091 li.trigger('state_changed');
5092};
5093
5094osmium_add_charge = function(li, chargetypeid) {
5095 var span = li.children('span.charge');
5096 var img = $(document.createElement('img'));
5097 var charge = span.children('span.name');
5098
5099 li.data('chargetypeid', chargetypeid);
5100 img.prop('src', '//image.eveonline.com/Type/' + chargetypeid + '_64.png');
5101 img.prop('alt', '');
5102 span.children('img, span.mainsprite').replaceWith(img);
5103
5104 charge.empty();
5105 charge.text(osmium_types[chargetypeid][1]);
5106 charge.prop('title', osmium_types[chargetypeid][1]);
5107};
5108
5109osmium_add_charge_by_location = function(locationtypeid, locationindex, chargetypeid) {
5110 var li = $('section#modules > div.slots li.hascharge').filter(function() {
5111 var t = $(this);
5112 return t.data('typeid') === locationtypeid && t.data('index') === locationindex;
5113 }).first();
5114
5115 return osmium_add_charge(li, chargetypeid);
5116};
5117
5118osmium_get_best_location_for_charge = function(typeid) {
5119 var location = null;
5120 var candidatelevel;
5121
5122 for(var i = 0; i < osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5123 .modules.length; ++i) {
5124 m = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules[i];
5125
5126 var validcharge = false, currentchargeid = null;
5127 if(!(m.typeid in osmium_charges)) {
5128 /* Module can't accept charges */
5129 continue;
5130 }
5131 for(var j = 0; j < osmium_charges[m.typeid].length; ++j) {
5132 if(osmium_charges[m.typeid][j] === typeid) {
5133 validcharge = true;
5134 break;
5135 }
5136 }
5137 if(!validcharge) continue;
5138
5139 if(location === null) {
5140 /* As a fallback, fit the charge to the first suitable location */
5141 location = i;
5142 candidatelevel = 0; /* This candidate is not very good */
5143 }
5144
5145 if(!("charges" in m)) {
5146 /* The module has no charges and can accept the charge, perfect */
5147 location = i;
5148 break;
5149 }
5150
5151 var charges = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5152 .modules[i].charges;
5153 var cpid;
5154
5155 /* Check if charge already present */
5156 for(var j = 0; j < charges.length; ++j) {
5157 if("cpid" in charges[j]) {
5158 cpid = charges[j].cpid;
5159 } else {
5160 cpid = 0;
5161 }
5162
5163 if(cpid == osmium_clf['X-Osmium-current-chargepresetid']) {
5164 currentchargeid = charges[j].typeid;
5165 break;
5166 }
5167 }
5168 if(currentchargeid === null) {
5169 /* The module has no charge in this preset and can accept the charge */
5170 location = i;
5171 break;
5172 } else if(currentchargeid !== typeid && candidatelevel < 1) {
5173 /* The module has a different charge, but it's still a
5174 * better candidate than the fallback */
5175 location = i;
5176 candidatelevel = 1;
5177 }
5178 }
5179
5180 return location;
5181};
5182
5183osmium_auto_add_charge_to_location = function(location, typeid) {
5184 var m = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5185 .modules[location];
5186 var moduletypeid = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5187 .modules[location].typeid;
5188 var moduletype = osmium_types[moduletypeid][3];
5189 var previouschargeid = null;
5190
5191 if(!("charges" in m)) {
5192 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5193 .modules[location].charges = [];
5194 }
5195
5196 var charges = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5197 .modules[location].charges;
5198 var cpid;
5199
5200 /* Remove previous charge (if there is one) */
5201 for(var j = 0; j < charges.length; ++j) {
5202 if("cpid" in charges[j]) {
5203 cpid = charges[j].cpid;
5204 } else {
5205 cpid = 0;
5206 }
5207
5208 if(cpid !== osmium_clf['X-Osmium-current-chargepresetid']) {
5209 continue;
5210 }
5211
5212 previouschargeid = charges[j].typeid;
5213
5214 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5215 .modules[location].charges.splice(j, 1);
5216 break;
5217 }
5218
5219 /* Finally, add the new charge */
5220 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5221 .modules[location].charges.push({
5222 typeid: typeid,
5223 cpid: osmium_clf['X-Osmium-current-chargepresetid']
5224 });
5225
5226 osmium_add_charge_by_location(m.typeid, m.index, typeid);
5227
5228 if($("section#modules > div.slots." + moduletype).hasClass('grouped')) {
5229 /* Also add this charge to identical modules with identical charges */
5230
5231 var curchargeid;
5232 var curchargeidx;
5233 for(var i = 0; i < osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5234 .modules.length; ++i) {
5235 curchargeid = null;
5236 curchargeidx = 0;
5237
5238 m = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules[i];
5239 if(m.typeid !== moduletypeid) {
5240 continue;
5241 }
5242
5243 if(!("charges" in m)) {
5244 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5245 .modules[i].charges = [];
5246 }
5247
5248 charges = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5249 .modules[i].charges;
5250
5251 for(var j = 0; j < charges.length; ++j) {
5252 if("cpid" in charges[j]) {
5253 cpid = charges[j].cpid;
5254 } else {
5255 cpid = 0;
5256 }
5257
5258 if(cpid !== osmium_clf['X-Osmium-current-chargepresetid']) {
5259 continue;
5260 }
5261
5262 curchargeid = charges[j].typeid;
5263 curchargeidx = j;
5264 break;
5265 }
5266
5267 if(curchargeid !== previouschargeid) {
5268 continue;
5269 }
5270
5271 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5272 .modules[i].charges.splice(curchargeidx, 1);
5273
5274 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5275 .modules[i].charges.push({
5276 typeid: typeid,
5277 cpid: osmium_clf['X-Osmium-current-chargepresetid']
5278 });
5279
5280 osmium_add_charge_by_location(m.typeid, m.index, typeid);
5281 }
5282 }
5283};
5284/* Osmium
5285 * Copyright (C) 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
5286 *
5287 * This program is free software: you can redistribute it and/or modify
5288 * it under the terms of the GNU Affero General Public License as published by
5289 * the Free Software Foundation, either version 3 of the License, or
5290 * (at your option) any later version.
5291 *
5292 * This program is distributed in the hope that it will be useful,
5293 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5294 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5295 * GNU Affero General Public License for more details.
5296 *
5297 * You should have received a copy of the GNU Affero General Public License
5298 * along with this program. If not, see <http://www.gnu.org/licenses/>.
5299 */
5300
5301osmium_gen_drones = function() {
5302 var drones = {
5303 bay: {},
5304 space: {}
5305 };
5306 var old_ias = {};
5307
5308 var dronep = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
5309
5310 for(var p in dronep) {
5311 if(p !== 'inbay' && p !== 'inspace') continue;
5312 var map = (p === 'inbay') ? drones.bay : drones.space;
5313
5314 for(var i = 0; i < dronep[p].length; ++i) {
5315 if(dronep[p][i].quantity == 0) continue;
5316 if(!(dronep[p][i].typeid in map)) {
5317 map[dronep[p][i].typeid] = 0;
5318 }
5319
5320 map[dronep[p][i].typeid] += dronep[p][i].quantity;
5321 }
5322 }
5323
5324 $('section#drones div.drones.space li.hasattribs > small.attribs').each(function() {
5325 var s = $(this);
5326 old_ias[s.parent().data('typeid')] = s.clone();
5327 });
5328
5329 for(var p in drones) {
5330 var dronesdiv = $("section#drones div.drones." + p);
5331 var ul = dronesdiv.children('ul');
5332 ul.empty();
5333
5334 for(var t in drones[p]) {
5335 var li = $(document.createElement('li'));
5336 var img = $(document.createElement('img'));
5337 var m = osmium_types[t];
5338 var qty = drones[p][t];
5339 var other = (p === 'bay') ? 'space' : 'bay';
5340
5341 li.data('typeid', m[0]);
5342 li.data('location', p);
5343 li.data('quantity', qty);
5344 li.append($(document.createElement('span')).addClass('name').text(m[1]));
5345 li.prop('title', m[1]);
5346 li.prepend($(document.createElement('strong')).addClass('qty').text(qty + '×'));
5347
5348 img.prop('src', '//image.eveonline.com/Type/' + t + '_64.png');
5349 img.prop('alt', '');
5350
5351 li.prepend(img);
5352
5353 if(t in old_ias) {
5354 li.append(old_ias[t]);
5355 }
5356
5357 ul.append(li);
5358
5359 osmium_ctxmenu_bind(li, (function(t, p, qty, other) {
5360 return function() {
5361 var menu = osmium_ctxmenu_create();
5362
5363 if(!osmium_loadout_readonly) {
5364 osmium_ctxmenu_add_option(menu, "Remove 1 drone", function() {
5365 osmium_remove_drone_from_clf(t, 1, p);
5366 osmium_gen_drones();
5367 osmium_undo_push();
5368 osmium_commit_clf();
5369 }, { 'default': true });
5370
5371 if(qty > 5) {
5372 osmium_ctxmenu_add_option(menu, "Remove 5 drones", function() {
5373 osmium_remove_drone_from_clf(t, 5, p);
5374 osmium_gen_drones();
5375 osmium_undo_push();
5376 osmium_commit_clf();
5377 }, { });
5378 }
5379
5380 if(qty > 1) {
5381 osmium_ctxmenu_add_option(menu, "Remove " + qty + " drones", function() {
5382 osmium_remove_drone_from_clf(t, qty, p);
5383 osmium_gen_drones();
5384 osmium_undo_push();
5385 osmium_commit_clf();
5386 }, { });
5387 }
5388
5389 osmium_ctxmenu_add_separator(menu);
5390 }
5391
5392 osmium_ctxmenu_add_option(menu, "Move 1 to " + other, function() {
5393 osmium_add_drone_to_clf(t, 1, other);
5394 osmium_remove_drone_from_clf(t, 1, p);
5395 osmium_gen_drones();
5396 osmium_undo_push();
5397 osmium_commit_clf();
5398 }, { });
5399
5400 if(qty > 5) {
5401 osmium_ctxmenu_add_option(menu, "Move 5 to " + other, function() {
5402 osmium_add_drone_to_clf(t, 5, other);
5403 osmium_remove_drone_from_clf(t, 5, p);
5404 osmium_gen_drones();
5405 osmium_undo_push();
5406 osmium_commit_clf();
5407 }, { });
5408 }
5409
5410 if(qty > 1) {
5411 osmium_ctxmenu_add_option(menu, "Move " + qty + " to " + other, function() {
5412 osmium_add_drone_to_clf(t, qty, other);
5413 osmium_remove_drone_from_clf(t, qty, p);
5414 osmium_gen_drones();
5415 osmium_undo_push();
5416 osmium_commit_clf();
5417 }, { });
5418 }
5419
5420 osmium_ctxmenu_add_separator(menu);
5421
5422 if(!osmium_loadout_readonly) {
5423 osmium_ctxmenu_add_option(menu, "Clear all drones in " + p, function() {
5424 osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']]['in' + p] = [];
5425 osmium_gen_drones();
5426 osmium_undo_push();
5427 osmium_commit_clf();
5428 }, { });
5429
5430 osmium_ctxmenu_add_separator(menu);
5431 }
5432
5433 if(!osmium_loadout_readonly) {
5434 osmium_add_generic_browse(menu, t);
5435 }
5436
5437 osmium_ctxmenu_add_option(menu, "Show drone info", function() {
5438 osmium_showinfo({
5439 type: "drone",
5440 typeid: t
5441 });
5442 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
5443
5444
5445 if (typeof CCPEVE !== 'undefined') {
5446 osmium_ctxmenu_add_option(menu, "Show drone IGB info", function() {
5447 osmium_showinfo_igb({
5448 type: "drone",
5449 typeid: t
5450 });
5451 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
5452 }
5453
5454 return menu;
5455 };
5456 })(m[0], p, qty, other));
5457 }
5458
5459 if(ul.children('li').length == 0) {
5460 /* Add placeholder entry */
5461 var li = $(document.createElement('li'));
5462 li.text('No drones in ' + p);
5463 li.addClass('placeholder');
5464 li.prepend(osmium_sprite('', 0, 13, 64, 64, 32, 32));
5465 ul.append(li);
5466 }
5467 }
5468
5469 if(osmium_user_initiated) {
5470 $('a[href="#drones"]').parent().click();
5471 }
5472};
5473
5474osmium_init_drones = function() {
5475 $("section#drones > div.drones > ul").sortable({
5476 items: "li:not(.placeholder)",
5477 placeholder: "sortable-placeholder",
5478 connectWith: "section#drones > div.drones > ul",
5479 remove: function(e, ui) {
5480 var d = ui.item;
5481 var t = d.data('typeid');
5482 var loc = d.data('location');
5483 var q = d.data('quantity');
5484
5485 var drones = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']]['in' + loc];
5486
5487 for(var i = 0; i < drones.length; ++i) {
5488 if(drones[i].typeid != t) continue;
5489
5490 drones[i].quantity -= q;
5491 if(drones[i].quantity <= 0) {
5492 drones.splice(i, 1);
5493 }
5494 }
5495 },
5496 receive: function(e, ui) {
5497 var d = ui.item;
5498 var t = d.data('typeid');
5499 var loc = (d.data('location') === 'bay') ? 'space' : 'bay';
5500 var q = d.data('quantity');
5501 var dp = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
5502 var key = 'in' + loc;
5503
5504 if(!(key in dp)) dp[key] = [];
5505 drones = dp[key];
5506 d.data('location', loc);
5507
5508 for(var i = 0; i < drones.length; ++i) {
5509 if(drones[i].typeid != t) continue;
5510
5511 drones[i].quantity += q;
5512 osmium_gen_drones();
5513 osmium_commit_clf();
5514 osmium_undo_push();
5515 return;
5516 }
5517
5518 drones.push({
5519 typeid: t,
5520 quantity: q
5521 });
5522 osmium_gen_drones();
5523 osmium_commit_clf();
5524 osmium_undo_push();
5525 }
5526 });
5527};
5528
5529osmium_remove_drone_from_clf = function(typeid, qty, location) {
5530 var dp = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
5531 dp = (location === 'space') ? dp.inspace : dp.inbay;
5532 var toremove = qty;
5533
5534 for(var i = dp.length - 1; i >= 0; --i) {
5535 if(toremove == 0) break;
5536 if(dp[i].typeid != typeid) continue;
5537
5538 if(dp[i].quantity > qty) {
5539 /* Easy case */
5540 dp[i].quantity -= qty;
5541 toremove = 0;
5542 break;
5543 } else {
5544 /* Annoying case */
5545 toremove -= dp[i].quantity;
5546 dp.splice(i, 1);
5547 }
5548 }
5549};
5550
5551osmium_add_drone_to_clf = function(typeid, qty, location) {
5552 var dp = osmium_clf.drones[osmium_clf['X-Osmium-current-dronepresetid']];
5553 if(!("inspace" in dp)) dp.inspace = [];
5554 if(!("inbay" in dp)) dp.inbay = [];
5555
5556 dp = (location === 'space') ? dp.inspace : dp.inbay;
5557
5558 for(var i = 0; i < dp.length; ++i) {
5559 if(dp[i].typeid === typeid) {
5560 dp[i].quantity += qty;
5561 return;
5562 }
5563 }
5564
5565 dp.push({
5566 typeid: typeid,
5567 quantity: qty
5568 });
5569};
5570/* Osmium
5571 * Copyright (C) 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
5572 *
5573 * This program is free software: you can redistribute it and/or modify
5574 * it under the terms of the GNU Affero General Public License as published by
5575 * the Free Software Foundation, either version 3 of the License, or
5576 * (at your option) any later version.
5577 *
5578 * This program is distributed in the hope that it will be useful,
5579 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5580 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5581 * GNU Affero General Public License for more details.
5582 *
5583 * You should have received a copy of the GNU Affero General Public License
5584 * along with this program. If not, see <http://www.gnu.org/licenses/>.
5585 */
5586
5587osmium_gen_implants = function() {
5588 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
5589 var i_ul = $("section#implants > div.implants > ul");
5590 var b_ul = $("section#implants > div.boosters > ul");
5591
5592 i_ul.empty(); b_ul.empty();
5593
5594 if('implants' in p && p.implants.length > 0) {
5595 p.implants.sort(function(x, y) {
5596 return parseInt(osmium_types[x.typeid][3], 10) - parseInt(osmium_types[y.typeid][3], 10);
5597 });
5598
5599 for(var i = 0; i < p.implants.length; ++i) {
5600 var t = p.implants[i].typeid;
5601 var imp = osmium_types[t];
5602 var li = $(document.createElement('li'));
5603 var img = $(document.createElement('img'));
5604 var span = $(document.createElement('span'));
5605
5606 img.prop('src', '//image.eveonline.com/Type/' + t + '_64.png');
5607 img.prop('alt', '');
5608
5609 li.append($(document.createElement('span')).addClass('name').text(imp[1]));
5610 li.prop('title', imp[1]);
5611 li.prepend(img);
5612 span.text(', implant slot ' + imp[3]).addClass('slot');
5613 li.append(span);
5614 li.data('typeid', t);
5615
5616 osmium_ctxmenu_bind(li, (function(li, t) {
5617 return function() {
5618 var menu = osmium_ctxmenu_create();
5619
5620 if(!osmium_loadout_readonly) {
5621 osmium_ctxmenu_add_option(menu, "Remove implant", function() {
5622 var p_imp = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].implants;
5623
5624 for(var z = 0; z < p_imp.length; ++z) {
5625 if(t === p_imp[z].typeid) {
5626 var ul = li.parent();
5627
5628 p_imp.splice(z, 1);
5629 osmium_undo_push();
5630 osmium_commit_clf();
5631 li.remove();
5632
5633 if(ul.children('li').length === 0) {
5634 osmium_gen_implants();
5635 }
5636 break;
5637 }
5638 }
5639 }, { 'default': true });
5640
5641 osmium_ctxmenu_add_separator(menu);
5642
5643 osmium_add_generic_browse(menu, t);
5644 }
5645
5646 osmium_ctxmenu_add_option(menu, "Show implant info", function() {
5647 osmium_showinfo({ type: 'implant', typeid: t });
5648 }, { icon: osmium_showinfo_sprite_position, "default": osmium_loadout_readonly });
5649
5650 return menu;
5651 };
5652 })(li, t));
5653
5654 i_ul.append(li);
5655 }
5656 } else {
5657 var li = $(document.createElement('li'));
5658 li.addClass('placeholder');
5659 li.text('No implants');
5660 i_ul.append(li);
5661 }
5662
5663 if('boosters' in p && p.boosters.length > 0) {
5664 p.boosters.sort(function(x, y) {
5665 return parseInt(osmium_types[x.typeid][3], 10) - parseInt(osmium_types[y.typeid][3], 10);
5666 });
5667
5668 for(var i = 0; i < p.boosters.length; ++i) {
5669 var t = p.boosters[i].typeid;
5670 var imp = osmium_types[t];
5671 var li = $(document.createElement('li'));
5672 var img = $(document.createElement('img'));
5673 var span = $(document.createElement('span'));
5674
5675 img.prop('src', '//image.eveonline.com/Type/' + t + '_64.png');
5676 img.prop('alt', '');
5677
5678 li.text(imp[1]);
5679 li.prop('title', imp[1]);
5680 li.prepend(img);
5681 span.text(', booster slot ' + imp[3]).addClass('slot');
5682 li.append(span);
5683
5684 osmium_ctxmenu_bind(li, (function(li, t) {
5685 return function() {
5686 var menu = osmium_ctxmenu_create();
5687
5688 if(!osmium_loadout_readonly) {
5689 osmium_ctxmenu_add_option(menu, "Remove booster", function() {
5690 var p_bst = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].boosters;
5691
5692 for(var z = 0; z < p_bst.length; ++z) {
5693 if(t === p_bst[z].typeid) {
5694 var ul = li.parent();
5695
5696 p_bst.splice(z, 1);
5697 osmium_undo_push();
5698 osmium_commit_clf();
5699 li.remove();
5700
5701 if(ul.children('li').length === 0) {
5702 osmium_gen_implants();
5703 }
5704 break;
5705 }
5706 }
5707 }, { 'default': true });
5708
5709 osmium_ctxmenu_add_separator(menu);
5710 }
5711
5712 osmium_ctxmenu_add_subctxmenu(menu, "Side effects", function() {
5713 var smenu = osmium_ctxmenu_create();
5714
5715 if(t in osmium_booster_side_effects) {
5716 for(var z = 0; z < osmium_booster_side_effects[t].length; ++z) {
5717 var effectid = osmium_booster_side_effects[t][z][0];
5718 var effectname = osmium_booster_side_effects[t][z][1];
5719 var clfbooster = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]
5720 .boosters;
5721 for(var k = 0; k < clfbooster.length; ++k) {
5722 if(clfbooster[k].typeid === t) {
5723 clfbooster = clfbooster[k];
5724 }
5725 }
5726
5727 osmium_ctxmenu_add_option(
5728 smenu, osmium_format_penalty_effectname(effectname),
5729 (function(effectid, clfbooster) {
5730 return function() {
5731 if("X-sideeffects" in clfbooster) {
5732 var index = $.inArray(effectid, clfbooster['X-sideeffects']);
5733
5734 if(index !== -1) {
5735 clfbooster['X-sideeffects'].splice(index, 1);
5736 } else {
5737 clfbooster['X-sideeffects'].push(effectid);
5738 }
5739 } else {
5740 clfbooster['X-sideeffects'] = [ effectid ];
5741 }
5742
5743 osmium_undo_push();
5744 osmium_commit_clf();
5745 };
5746 })(effectid, clfbooster),
5747 {
5748 toggled: "X-sideeffects" in clfbooster
5749 && $.inArray(effectid, clfbooster['X-sideeffects']) !== -1
5750 }
5751 );
5752 }
5753 } else {
5754 osmium_ctxmenu_add_option(smenu, "No side effects", function() {}, { enabled: false });
5755 }
5756
5757 return smenu;
5758 }, {});
5759
5760 osmium_ctxmenu_add_separator(menu);
5761
5762 osmium_ctxmenu_add_option(menu, "Show booster info", function() {
5763 osmium_showinfo({ type: 'implant', typeid: t });
5764 }, { icon: osmium_showinfo_sprite_position, "default": osmium_loadout_readonly });
5765
5766 return menu;
5767 };
5768 })(li, t));
5769
5770 b_ul.append(li);
5771 }
5772 } else {
5773 var li = $(document.createElement('li'));
5774 li.addClass('placeholder');
5775 li.text('No boosters');
5776 b_ul.append(li);
5777 }
5778};
5779
5780osmium_init_implants = function() {
5781
5782};
5783
5784osmium_format_penalty_effectname = function(name) {
5785 var s = name.split(/([A-Z])/);
5786 var words = [];
5787 words.push(s.shift());
5788 while(s.length > 0) {
5789 words.push(s.shift() + s.shift());
5790 }
5791
5792 if(words[0] === "booster") words.shift();
5793 var p = $.inArray("Penalty", words);
5794 if(p !== -1) words = words.slice(0, p);
5795
5796 return words.join(" ");
5797};
5798/* Osmium
5799 * Copyright (C) 2015 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
5800 *
5801 * This program is free software: you can redistribute it and/or modify
5802 * it under the terms of the GNU Affero General Public License as published by
5803 * the Free Software Foundation, either version 3 of the License, or
5804 * (at your option) any later version.
5805 *
5806 * This program is distributed in the hope that it will be useful,
5807 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5808 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5809 * GNU Affero General Public License for more details.
5810 *
5811 * You should have received a copy of the GNU Affero General Public License
5812 * along with this program. If not, see <http://www.gnu.org/licenses/>.
5813 */
5814
5815osmium_gen_beacons = function() {
5816 var ul = $("section#area > div > ul");
5817 var clfp = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
5818
5819 ul.empty();
5820
5821 if(!('X-beacons' in clfp) || clfp['X-beacons'].length === 0) {
5822 ul.append(
5823 $(document.createElement('li'))
5824 .addClass('placeholder')
5825 .text('No area effects')
5826 );
5827 return;
5828 }
5829
5830 for(var i = 0; i < clfp['X-beacons'].length; ++i) {
5831 var btypeid = clfp['X-beacons'][i];
5832 var beacon = osmium_types[btypeid];
5833 var li;
5834
5835 ul.append(
5836 li = $(document.createElement('li'))
5837 .prop('title', beacon[1])
5838 .append(
5839 $(document.createElement('img'))
5840 .prop('src', '//image.eveonline.com/Type/' + btypeid +'_64.png')
5841 .prop('alt', '')
5842 )
5843 .append(
5844 $(document.createElement('span'))
5845 .addClass('name')
5846 .text(beacon[1])
5847 )
5848 );
5849
5850 osmium_ctxmenu_bind(li, (function(li, typeid) {
5851 return function() {
5852 var menu = osmium_ctxmenu_create();
5853
5854 if(!osmium_loadout_readonly) {
5855 osmium_ctxmenu_add_option(menu, "Remove beacon", function() {
5856 var clfpb = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']]['X-beacons'];
5857
5858 for(var z = 0; z < clfpb.length; ++z) {
5859 if(typeid === clfpb[z]) {
5860 var ul = li.parent();
5861
5862 clfpb.splice(z, 1);
5863 osmium_undo_push();
5864 osmium_commit_clf();
5865 li.remove();
5866
5867 if(ul.children('li').length === 0) {
5868 osmium_gen_beacons();
5869 }
5870 break;
5871 }
5872 }
5873 }, { 'default': true });
5874
5875 osmium_ctxmenu_add_separator(menu);
5876
5877 osmium_add_generic_browse(menu, typeid);
5878 }
5879
5880 osmium_ctxmenu_add_option(menu, "Show beacon info", function() {
5881 osmium_showinfo({ type: 'beacon', typeid: typeid });
5882 }, { icon: osmium_showinfo_sprite_position, "default": osmium_loadout_readonly });
5883
5884 return menu;
5885 };
5886 })(li, btypeid));
5887 }
5888};
5889
5890osmium_init_beacons = function() {
5891
5892};
5893/* Osmium
5894 * Copyright (C) 2013, 2014 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
5895 *
5896 * This program is free software: you can redistribute it and/or modify
5897 * it under the terms of the GNU Affero General Public License as published by
5898 * the Free Software Foundation, either version 3 of the License, or
5899 * (at your option) any later version.
5900 *
5901 * This program is distributed in the hope that it will be useful,
5902 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5903 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5904 * GNU Affero General Public License for more details.
5905 *
5906 * You should have received a copy of the GNU Affero General Public License
5907 * along with this program. If not, see <http://www.gnu.org/licenses/>.
5908 */
5909
5910osmium_gen_remote = function() {
5911 osmium_gen_fleet();
5912 osmium_gen_projected();
5913};
5914
5915osmium_gen_fleet = function() {
5916 var selects = $("section#fleet select");
5917 selects.empty();
5918
5919 for(var i = 0; i < osmium_skillsets.length; ++i) {
5920 selects.append(
5921 $(document.createElement('option'))
5922 .text(osmium_skillsets[i])
5923 .prop('value', osmium_skillsets[i])
5924 );
5925 }
5926
5927 $("section#fleet").find('input, select')
5928 .not("[type='checkbox']").prop('disabled', true);
5929
5930 if(!("X-Osmium-fleet" in osmium_clf)) {
5931 osmium_clf['X-Osmium-fleet'] = {};
5932 }
5933
5934 for(var t in osmium_clf['X-Osmium-fleet']) {
5935 $("section#fleet select#" + t + "_skillset").val(osmium_clf['X-Osmium-fleet'][t].skillset);
5936 $("section#fleet input#" + t + "_fit").val(osmium_clf['X-Osmium-fleet'][t].fitting);
5937 $("section#fleet input#" + t + "_enabled").prop('checked', true).change();
5938 $("section#fleet").find("input, select").filter("." + t).prop('disabled', false);
5939 }
5940};
5941
5942osmium_projected_clean = function() {
5943 jsPlumb.unbind();
5944 jsPlumb.doWhileSuspended(function() {
5945 jsPlumb.detachEveryConnection();
5946 jsPlumb.deleteEveryEndpoint();
5947 jsPlumb.unmakeEverySource();
5948 jsPlumb.unmakeEveryTarget();
5949 });
5950}
5951
5952osmium_gen_projected = function() {
5953 jsPlumb.Defaults.Container = $("section#projected form#projected-list");
5954 jsPlumb.Defaults.Endpoints = [ "Blank", "Blank" ];
5955
5956 osmium_projected_clean();
5957
5958 jsPlumb.bind("connection", function(info) {
5959 var src = $(info.source), tgt = $(info.target);
5960
5961 if(src.closest('div.pr-loadout').get(0) === tgt.get(0)) {
5962 /* Disallow self-projection. While libdogma can handle it
5963 * in theory, it doesn't make a lot of sense to allow it
5964 * since real dogma dosen't allow it. */
5965 jsPlumb.detach(info.connection);
5966 return;
5967 }
5968
5969 /* A module can only target one entity at a time, so remove
5970 * other connections */
5971 jsPlumb.doWhileSuspended(function() {
5972 jsPlumb.select({ source: info.source }).each(function(conn) {
5973 if(conn !== info.connection) {
5974 jsPlumb.detach(conn);
5975 }
5976 });
5977 });
5978
5979 /* Update the target in CLF */
5980 var tkey = tgt.data('key');
5981 var skey = src.closest('div.pr-loadout').data('key');
5982 var stid = src.data('typeid');
5983 var sidx = src.data('index');
5984 var clf;
5985
5986 if(skey === 'local') {
5987 clf = osmium_clf;
5988 } else {
5989 clf = osmium_clf['X-Osmium-remote'][skey];
5990 }
5991
5992 var m = clf.presets[clf['X-Osmium-current-presetid']].modules;
5993 for(var i = 0; i < m.length; ++i) {
5994 if(m[i].typeid === stid && m[i].index === sidx) {
5995 m[i]['X-Osmium-target'] = tkey;
5996 osmium_commit_undo_deferred();
5997 src.addClass('hastarget');
5998 src.append(
5999 $(document.createElement('div'))
6000 .addClass('bghue')
6001 .css('background-color', src.closest('div.pr-loadout').css('border-color'))
6002 );
6003 return;
6004 }
6005 }
6006
6007 alert('Could not create connection in CLF – please report!');
6008 });
6009 jsPlumb.bind("connectionDetached", function(info) {
6010 var src = $(info.source);
6011
6012 /* Delete the target in CLF */
6013 var skey = src.closest('div.pr-loadout').data('key');
6014 var stid = src.data('typeid');
6015 var sidx = src.data('index');
6016 var clf;
6017
6018 if(skey === 'local') {
6019 clf = osmium_clf;
6020 } else {
6021 clf = osmium_clf['X-Osmium-remote'][skey];
6022 }
6023
6024 var m = clf.presets[clf['X-Osmium-current-presetid']].modules;
6025 for(var i = 0; i < m.length; ++i) {
6026 if(m[i].typeid === stid && m[i].index === sidx) {
6027 m[i]['X-Osmium-target'] = false;
6028 osmium_commit_undo_deferred();
6029 src.children('div.bghue').remove();
6030 src.removeClass('hastarget');
6031 return;
6032 }
6033 }
6034
6035 alert('Could not delete connection in CLF – please report!');
6036 console.log('connection not found in CLF', stid, sidx, m);
6037 });
6038
6039 var list = $("section#projected form#projected-list");
6040 list.empty();
6041
6042 var local = osmium_create_projected("local", osmium_clf, 0);
6043 list.append(local);
6044
6045 if(!("X-Osmium-remote" in osmium_clf)) {
6046 osmium_clf['X-Osmium-remote'] = {};
6047 }
6048
6049 var c = 0;
6050 var remotes = {};
6051 remotes.local = osmium_clf;
6052
6053 for(var key in osmium_clf['X-Osmium-remote']) {
6054 var pfit = osmium_clf['X-Osmium-remote'][key];
6055 list.append(osmium_create_projected(key, pfit, ++c));
6056 remotes[key] = pfit;
6057 }
6058
6059 for(var key in remotes) {
6060 var pclf = remotes[key];
6061
6062 if(!("X-Osmium-current-presetid" in pclf)) continue;
6063 if(!("presets" in pclf)) continue;
6064 if(!(pclf['X-Osmium-current-presetid'] in pclf.presets)) continue;
6065 if(!("modules" in pclf.presets[pclf['X-Osmium-current-presetid']])) continue;
6066
6067 var modules = pclf.presets[pclf['X-Osmium-current-presetid']].modules;
6068
6069 for(var i = 0; i < modules.length; ++i) {
6070 var m = modules[i];
6071 if("X-Osmium-target" in m && m['X-Osmium-target'] !== false) {
6072 var source = $('section#projected div.pr-loadout.projected-' + key)
6073 .find('li').filter(function() {
6074 var li = $(this);
6075 return li.data('typeid') === m.typeid && li.data('index') === m.index
6076 }).first();
6077
6078 var target = $('section#projected div.pr-loadout.projected-' + m['X-Osmium-target']);
6079
6080 if(source.length !== 1) {
6081 alert('Could not find source from CLF connection, please report!');
6082 continue;
6083 }
6084 if(target.length !== 1) {
6085 alert('Could not find target from CLF connection, please report!');
6086 continue;
6087 }
6088
6089 jsPlumb.connect({ source: source, target: target });
6090 }
6091 }
6092 }
6093};
6094
6095osmium_init_remote = function() {
6096 osmium_init_fleet();
6097 osmium_init_projected();
6098};
6099
6100osmium_init_fleet = function() {
6101 $("section#fleet").on('change', "input[type='checkbox']", function() {
6102 var c = $(this);
6103 var tr = c.closest('tr');
6104 var table = tr.closest('table');
6105 var type = tr.data('type');
6106
6107 if(!("X-Osmium-fleet" in osmium_clf)) {
6108 osmium_clf['X-Osmium-fleet'] = {};
6109 }
6110 var fleet = osmium_clf['X-Osmium-fleet'];
6111
6112 if(c.is(':checked')) {
6113 fleet[type] = {
6114 skillset: table.find('select#' + type + '_skillset').val(),
6115 fitting: table.find('input#' + type + '_fit').val()
6116 };
6117 table.find('input, select')
6118 .filter('.' + type).prop('disabled', false);
6119 } else {
6120 delete(fleet[type]);
6121 table.find('input, select')
6122 .filter('.' + type).not("[type='checkbox']")
6123 .prop('disabled', true);
6124 }
6125
6126 if(osmium_user_initiated) {
6127 osmium_undo_push();
6128 osmium_commit_clf();
6129 }
6130 }).on('change', 'select', function() {
6131 var s = $(this);
6132 var tr = s.closest('tr');
6133 var table = tr.closest('table');
6134 var checkbox = table.find("input#" + tr.data('type') + "_enabled");
6135
6136 if(!checkbox.is(':checked')) {
6137 return;
6138 }
6139
6140 checkbox.trigger('change');
6141 }).on('click', 'input.set', function() {
6142 var s = $(this);
6143 var tr = s.closest('tr');
6144 var table = tr.closest('table');
6145 var checkbox = table.find("input#" + tr.data('type') + "_enabled");
6146
6147 if(!checkbox.is(':checked')) {
6148 return;
6149 }
6150
6151 checkbox.trigger('change');
6152 }).on('click', 'input.clear', function() {
6153 var s = $(this);
6154 var tr = s.closest('tr');
6155 var table = tr.closest('table');
6156 var checkbox = table.find("input#" + tr.data('type') + "_enabled");
6157
6158 if(!checkbox.is(':checked')) {
6159 return;
6160 }
6161
6162 table.find('input#' + tr.data('type') + '_fit').val('');
6163 checkbox.trigger('change');
6164 }).on('keypress', 'input.fit', function(e) {
6165 if(e.which != 13) return;
6166 e.preventDefault();
6167
6168 var s = $(this);
6169 var tr = s.closest('tr');
6170 var table = tr.closest('table');
6171 var checkbox = table.find("input#" + tr.data('type') + "_enabled");
6172
6173 if(!checkbox.is(':checked')) {
6174 return false;
6175 }
6176
6177 checkbox.trigger('change');
6178 return false;
6179 });
6180};
6181
6182osmium_add_projected = function(remotefit, target) {
6183 if(!("X-Osmium-remote" in osmium_clf)) {
6184 osmium_clf['X-Osmium-remote'] = {};
6185 }
6186
6187 var key = 1;
6188 while((key + '') in osmium_clf['X-Osmium-remote']) ++key;
6189 key = key + '';
6190
6191 osmium_clf['X-Osmium-remote'][key] = {
6192 fitting: '',
6193 skillset: 'All V'
6194 };
6195
6196 var newproj = osmium_create_projected(
6197 key, { },
6198 $("section#projected > form#projected-list > div.pr-loadout").length
6199 );
6200
6201 $("section#projected > form#projected-list").append(newproj);
6202
6203 if(remotefit !== undefined) {
6204 osmium_clf['X-Osmium-remote'][key].fitting = remotefit;
6205 }
6206
6207 if(remotefit !== undefined && target !== undefined) {
6208 var target = $("section#projected div.pr-loadout.projected-" + target);
6209 osmium_projected_regen_remote(key, function() {
6210 $("section#projected div.pr-loadout.projected-" + key).find('ul > li').each(function() {
6211 jsPlumb.connect({ source: $(this), target: target });
6212 });
6213 });
6214 } else {
6215 osmium_commit_undo_deferred();
6216 }
6217
6218 return newproj;
6219};
6220
6221osmium_init_projected = function() {
6222 if(!osmium_loadout_readonly) {
6223 $("section#projected input#createprojected").on('click', function() {
6224 osmium_add_projected('').trigger('dblclick');
6225 });
6226 }
6227
6228 $("section#remote").on('made_visible', function() {
6229 osmium_regen_offsets();
6230 jsPlumb.repaintEverything();
6231
6232 $("section#remote").off('made_visible');
6233 });
6234
6235 $("section#projected input#projectedfstoggle").on('click', function() {
6236 var section = $("section#projected");
6237 var fs = section.hasClass('fs');
6238
6239 $("body").scrollTop(0);
6240
6241 section.animate({ opacity: 0 }, 250, function() {
6242 jsPlumb.doWhileSuspended(function() {
6243 jsPlumb.toggleDraggable(
6244 section.find('div.pr-loadout')
6245 .draggable("option", "disabled", fs)
6246 );
6247
6248 section.toggleClass('fs');
6249 var exitfs = function() {
6250 $("section#projected input#projectedfstoggle").click();
6251 return false;
6252 };
6253
6254 if(fs) {
6255 osmium_unregister_keyboard_command('exit-fullscreen-projected');
6256 $("div#fsbg").remove();
6257 } else {
6258 var bg = $(document.createElement('div'));
6259 bg.prop('id', 'fsbg');
6260 bg.click(exitfs);
6261 $("section#projected").prepend(bg);
6262 osmium_register_keyboard_command(
6263 'esc', 'exit-fullscreen-projected', 'Exit fullscreen projected mode.', exitfs
6264 );
6265 }
6266
6267 /* Swap fixed and draggable positions */
6268 $("section#projected div.pr-loadout").each(function() {
6269 var t = $(this);
6270 var otop = t.css('top');
6271 var oleft = t.css('left');
6272
6273 t.css('top', t.data('top')).data('top', otop);
6274 t.css('left', t.data('left')).data('left', oleft);
6275 });
6276
6277 osmium_regen_offsets();
6278
6279 /* Auto-rearrange if necessary */
6280 var localtop = $("section#projected div.pr-loadout.projected-local").css('top');
6281 if(section.hasClass('fs') && (!localtop || localtop === 'auto' || localtop === '0px')) {
6282 if($("section#projected div.pr-loadout").length <= 8) {
6283 $("section#projected a#rearrange-circle").click();
6284 } else {
6285 $("section#projected a#rearrange-grid").click();
6286 }
6287 }
6288 });
6289
6290 section.animate({ opacity: 1 }, 250);
6291 });
6292 });
6293
6294 $("section#projected a#rearrange-circle").on('click', function() {
6295 var s = $("section#projected");
6296 var f = s.children("form#projected-list");
6297
6298 var so = s.offset();
6299 var mx = ($(window).width() - so.left) / 2;
6300 var my = ($(window).height() - so.top) / 2;
6301 var m = Math.min(mx, my);
6302 var divs = f.find('div.pr-loadout');
6303
6304 jsPlumb.doWhileSuspended(function() {
6305 divs.each(function() {
6306 var d = $(this);
6307 var angle = d.index() / divs.length * 2 * Math.PI;
6308 var w = d.width();
6309 var h = d.height();
6310
6311 d.offset({
6312 left: (so.left + mx - (m - d.outerWidth() / 2 - 32) * Math.cos(angle) - w / 2).toFixed(0),
6313 top: (so.top + my - (m - d.outerHeight() / 2 - 32) * Math.sin(angle) - h / 2).toFixed(0)
6314 });
6315 });
6316 });
6317 });
6318
6319 $("section#projected a#rearrange-grid").on('click', function() {
6320 var s = $("section#projected");
6321 var f = s.children("form#projected-list");
6322
6323 var so = s.offset();
6324 var mx = ($(window).width() - so.left);
6325 var my = ($(window).height() - so.top - 30);
6326 var divs = f.find('div.pr-loadout');
6327
6328 var maxw = 1, maxh = 1;
6329 var rows = 1, cols = 1;
6330 var cellw = 1, cellh = 1;
6331
6332 divs.each(function() {
6333 var d = $(this);
6334 var w = d.outerWidth();
6335 var h = d.outerHeight();
6336
6337 if(w > maxw) maxw = w;
6338 if(h > maxh) maxh = h;
6339 });
6340
6341 /* Add some padding */
6342 maxw += 50;
6343 maxh += 50;
6344
6345 var maxrows = Math.max(1, Math.floor(my / maxh));
6346 var maxcols = Math.max(1, Math.floor(mx / maxw));
6347
6348 while((rows * cols) < divs.length) {
6349 if(cols < maxcols) {
6350 ++cols;
6351 }
6352
6353 if((rows * cols) >= divs.length) break;
6354
6355 ++rows;
6356 }
6357
6358 if(rows <= maxrows) {
6359 /* Everything can fit */
6360 cellw = Math.floor(mx / cols);
6361 cellh = Math.floor(my / rows);
6362 } else {
6363 /* Not enough space, use vertical scrolling */
6364 cols = Math.max(1, Math.floor(mx / maxw));
6365 cellw = Math.floor(mx / cols);
6366 cellh = maxh;
6367 }
6368
6369 jsPlumb.doWhileSuspended(function() {
6370 divs.each(function() {
6371 var d = $(this);
6372 var i = d.index();
6373
6374 d.offset({
6375 left: (so.left + (i % cols) * cellw + 10 * Math.cos(7 * i)
6376 + cellw / 2 - d.width() / 2).toFixed(0),
6377 top: (so.top + 30 + Math.floor(i / cols) * cellh + 10 * Math.sin(7 * i)
6378 + cellh / 2 - d.height() / 2).toFixed(0)
6379 });
6380 });
6381 });
6382 });
6383
6384 osmium_register_keyboard_command(null, 'debug-jsplumb-repaint', 'Call jsPlumb.repaintEverything().',
6385 function() {
6386 jsPlumb.repaintEverything();
6387 return false;
6388 });
6389
6390 osmium_register_keyboard_command(
6391 null, 'debug-jsplumb-recalculate-offsets', 'Recalculate jsPlumb offsets of remotes.',
6392 function() {
6393 osmium_regen_offsets();
6394 }
6395 );
6396};
6397
6398osmium_create_projected = function(key, clf, index) {
6399 var proj = $(document.createElement('div'));
6400 var ul = $(document.createElement('ul'));
6401
6402 var angle;
6403 if(index === undefined) {
6404 angle = (360 * Math.random()).toFixed(0);
6405 } else if(index === 0) {
6406 angle = 0;
6407 } else {
6408 if(index < 1 || typeof index !== 'number') throw 'Invalid index parameter';
6409
6410 var low = 1;
6411 var up = 2;
6412
6413 while(!(low <= index && index < up)) {
6414 low = up;
6415 up = up + up;
6416 }
6417
6418 angle = (360 * (2 * (index - low) + 1) / up).toFixed(0);
6419 }
6420
6421 proj.data('hue', angle);
6422 proj.addClass('projected-' + key);
6423 proj.data('key', key);
6424 proj.addClass('pr-loadout');
6425 proj.css('border-color', 'hsl(' + angle + ', 25%, 50%)');
6426 proj.css('background-color', 'hsla(' + angle + ', 25%, 50%, 0.1)');
6427
6428 proj.data('title', key === 'local' ? 'Local' : ('Remote #' + key));
6429
6430 if("ship" in clf && "typeid" in clf.ship) {
6431 var img = $(document.createElement('img'));
6432 img.prop('alt', clf.ship.typename);
6433 img.prop('src', '//image.eveonline.com/Render/' + clf.ship.typeid + '_512.png');
6434 img.addClass('render');
6435 proj.append(img);
6436 proj.data('shiptypeid', clf.ship.typeid);
6437 proj.data('title', proj.data('title') + ': ' + osmium_types[clf.ship.typeid][1]);
6438 }
6439
6440 if("presets" in clf && "X-Osmium-current-presetid" in clf
6441 && "modules" in clf.presets[clf['X-Osmium-current-presetid']]) {
6442 var p = clf.presets[clf['X-Osmium-current-presetid']].modules;
6443 var projectable = 0;
6444 var pindex = 0;
6445
6446 for(var i = 0; i < p.length; ++i) {
6447 var t = osmium_types[p[i].typeid];
6448 if(t[8] !== 1) continue;
6449 ++projectable;
6450 }
6451
6452 var size; /* Also diameter of the circle */
6453 if(projectable === 0) {
6454 size = 120;
6455 } else {
6456 size = 80 * Math.max(6, projectable) / Math.PI;
6457 }
6458
6459 proj.css({
6460 width: size + 'px',
6461 height: size + 'px'
6462 });
6463
6464 for(var i = 0; i < p.length; ++i) {
6465 var t = osmium_types[p[i].typeid];
6466 if(t[8] !== 1) continue;
6467
6468 var source =
6469 $(document.createElement('li'))
6470 .data('typeid', p[i].typeid)
6471 .data('index', p[i].index)
6472 .append(
6473 $(document.createElement('img'))
6474 .prop('alt', t[1] + ' (#' + p[i].index + ')')
6475 .prop('title', t[1] + ' (#' + p[i].index + ')')
6476 .prop('src', '//image.eveonline.com/Type/' + t[0] + '_64.png')
6477 );
6478
6479 var angle = (pindex / projectable) * 2 * Math.PI;
6480 var top = -size * .5 * Math.cos(angle) - 28;
6481 var left = size * .5 * Math.sin(angle) - 28
6482
6483 source.css({ top: top + 'px', left: left + 'px' });
6484
6485 osmium_ctxmenu_bind(source, (function(source, clfsource) {
6486 return function() {
6487 var menu = osmium_ctxmenu_create();
6488 var t = osmium_types[clfsource.typeid];
6489
6490 osmium_ctxmenu_add_option(menu, t[1], function() {}, {
6491 enabled: false
6492 });
6493
6494 osmium_ctxmenu_add_separator(menu);
6495
6496 osmium_ctxmenu_add_subctxmenu(menu, "Project on", function() {
6497 var smenu = osmium_ctxmenu_create();
6498 var ntargets = 0;
6499
6500 $('section#projected div.pr-loadout').each(function() {
6501 var div = $(this);
6502 var tkey = div.data('key');
6503 if(tkey === key) return;
6504 ++ntargets;
6505 osmium_ctxmenu_add_option(smenu, div.data('title'), function() {
6506 jsPlumb.connect({
6507 source: source,
6508 target: div
6509 });
6510 }, {});
6511 });
6512
6513 if(ntargets === 0) {
6514 osmium_ctxmenu_add_option(smenu, "No targets available", function() {}, {
6515 enabled: false
6516 });
6517 }
6518
6519 return smenu;
6520 }, {});
6521
6522 osmium_ctxmenu_add_option(menu, "Clear target", function() {
6523 jsPlumb.select({ source: source }).detach();
6524 }, { 'default': true });
6525
6526 osmium_ctxmenu_add_separator(menu);
6527
6528 osmium_ctxmenu_add_option(menu, "Show module info", function() {
6529 osmium_showinfo({
6530 remote: key,
6531 type: "module",
6532 slottype: osmium_types[source.data('typeid')][3],
6533 index: source.data('index')
6534 });
6535 }, { icon: osmium_showinfo_sprite_position });
6536
6537 return menu;
6538 }
6539 })(source, p[i]));
6540
6541 jsPlumb.makeSource(source, {
6542 anchor: [ 0.5, 0.5 ],
6543 paintStyle: { fillStyle: 'hsl(' + proj.data('hue') + ', 50%, 50%)' },
6544 connectorStyle: {
6545 strokeStyle: 'hsla(' + proj.data('hue') + ', 50%, 50%, 0.5)',
6546 lineWidth: 5
6547 }
6548 });
6549
6550 ul.append(source);
6551 ++pindex;
6552 }
6553 }
6554
6555 proj.append(ul);
6556 var cap = osmium_gen_capacitor(1000, 1000);
6557 proj.append(cap);
6558 osmium_regen_remote_capacitor(proj);
6559
6560 jsPlumb.makeTarget(proj, {
6561 anchor: [ 0.5, 0.5 ],
6562 paintStyle: { fillStyle: 'hsl(' + proj.data('hue') + ', 50%, 50%)' }
6563 });
6564 jsPlumb.draggable(proj);
6565
6566 if(!$("section#projected").hasClass('fs')) {
6567 jsPlumb.toggleDraggable(proj);
6568 }
6569
6570 osmium_ctxmenu_bind(proj, function() {
6571 var menu = osmium_ctxmenu_create();
6572
6573 osmium_ctxmenu_add_option(menu, proj.data('title'), function() {}, { enabled: false });
6574
6575 osmium_ctxmenu_add_separator(menu);
6576
6577 osmium_ctxmenu_add_subctxmenu(menu, "Use skills", (function(key) {
6578 return function() {
6579 var smenu = osmium_ctxmenu_create();
6580 var clf = key === 'local' ? osmium_clf : osmium_clf['X-Osmium-remote'][key];
6581
6582 for(var i = 0; i < osmium_skillsets.length; ++i) {
6583 osmium_ctxmenu_add_option(smenu, osmium_skillsets[i], (function(sname) {
6584 return function() {
6585 if(key === 'local') {
6586 clf.metadata['X-Osmium-skillset'] = sname;
6587 } else {
6588 clf.skillset = sname;
6589 }
6590
6591 osmium_undo_push();
6592 osmium_commit_clf();
6593 };
6594 })(osmium_skillsets[i]), {
6595 toggled: (key === 'local' && clf.metadata['X-Osmium-skillset'] === osmium_skillsets[i])
6596 || (key !== 'local' && "skillset" in clf && clf.skillset === osmium_skillsets[i])
6597 });
6598 }
6599
6600 return smenu;
6601 };
6602 })(proj.data('key')), { icon: "//image.eveonline.com/Type/3327_64.png" });
6603
6604 if(proj.data('key') !== 'local') {
6605 osmium_ctxmenu_add_separator(menu);
6606 }
6607
6608 if(proj.data('key') !== 'local' && !osmium_loadout_readonly) {
6609 osmium_ctxmenu_add_option(menu, "Edit fitting…", (function(key) {
6610 return function() {
6611 var hdr = $(document.createElement('header'));
6612 hdr.append($(document.createElement('h2')).text(
6613 'Edit remote loadout #' + key
6614 ));
6615
6616 var form = $(document.createElement('form'));
6617 var tbody = $(document.createElement('tbody'));
6618
6619 var input = $(document.createElement('input'))
6620 .prop('type', 'text')
6621 .prop('placeholder', 'Loadout URI, DNA string or gzclf:// data')
6622 .prop('name', 'm-remote-fitting')
6623 .prop('id', 'm-remote-fitting')
6624 ;
6625
6626 if("X-Osmium-remote" in osmium_clf
6627 && key in osmium_clf['X-Osmium-remote']
6628 && 'fitting' in osmium_clf['X-Osmium-remote'][key]) {
6629 input.val(osmium_clf['X-Osmium-remote'][key].fitting);
6630 }
6631
6632 tbody.append(
6633 $(document.createElement('tr'))
6634 .append(
6635 $(document.createElement('th'))
6636 .append(
6637 $(document.createElement('label'))
6638 .text('Fitting')
6639 .prop('for', 'm-remote-fitting')
6640 )
6641 )
6642 .append(
6643 $(document.createElement('td'))
6644 .append(input)
6645 )
6646 );
6647
6648 var select = $(document.createElement('select'))
6649 .prop('name', 'm-remote-skillset')
6650 .prop('id', 'm-remote-skillset')
6651 .on('change', function() {
6652 osmium_clf['X-Osmium-remote'][key].skillset = $(this).val();
6653 osmium_undo_push();
6654 osmium_commit_clf();
6655 })
6656 ;
6657
6658 for(var i = 0; i < osmium_skillsets.length; ++i) {
6659 select.append(
6660 $(document.createElement('option'))
6661 .text(osmium_skillsets[i])
6662 .prop('value', osmium_skillsets[i])
6663 );
6664 }
6665
6666 if("X-Osmium-remote" in osmium_clf
6667 && key in osmium_clf['X-Osmium-remote']
6668 && 'skillset' in osmium_clf['X-Osmium-remote'][key]) {
6669 select.val(osmium_clf['X-Osmium-remote'][key].skillset);
6670 }
6671
6672 tbody.append(
6673 $(document.createElement('tr'))
6674 .append(
6675 $(document.createElement('th'))
6676 .append(
6677 $(document.createElement('label'))
6678 .text('Skills')
6679 .prop('for', 'm-remote-skillset')
6680 )
6681 )
6682 .append(
6683 $(document.createElement('td'))
6684 .append(select)
6685 )
6686 );
6687
6688 tbody.append(
6689 $(document.createElement('tr'))
6690 .append($(document.createElement('th')))
6691 .append(
6692 $(document.createElement('td'))
6693 .addClass('l')
6694 .append(
6695 $(document.createElement('input'))
6696 .prop('type', 'submit')
6697 .prop('value', 'Use fitting')
6698 )
6699 )
6700 );
6701
6702 form
6703 .prop('id', 'm-remote')
6704 .append(
6705 $(document.createElement('table'))
6706 .append(tbody)
6707 )
6708 .on('submit', function(e) {
6709 e.preventDefault();
6710 var form = $(this);
6711
6712 form.find('input, select').prop('disabled', true);
6713 form
6714 .find('input[type="submit"]')
6715 .after(
6716 $(document.createElement('span'))
6717 .addClass('spinner')
6718 )
6719 ;
6720
6721 osmium_clf['X-Osmium-remote'][key].fitting =
6722 form.find('input#m-remote-fitting').val();
6723 osmium_clf['X-Osmium-remote'][key].skillset =
6724 form.find('select#m-remote-skillset').val();
6725
6726 osmium_projected_regen_remote(key, function() {
6727 osmium_modal_clear();
6728 }, function(errors) {
6729 form.find('span.spinner').remove();
6730 form.find('input, select').prop('disabled', false);
6731
6732 form.find('tr.error_message').remove();
6733 form.find('tr.error').removeClass('error');
6734
6735 for(var i = 0; i < errors.length; ++i) {
6736 input.closest('tr').addClass('error').before(
6737 $(document.createElement('tr'))
6738 .addClass('error_message')
6739 .append(
6740 $(document.createElement('td'))
6741 .prop('colspan', '2')
6742 .append(
6743 $(document.createElement('p')).text(errors[i])
6744 )
6745 )
6746 );
6747 }
6748 });
6749
6750 return false;
6751 })
6752 ;
6753
6754 osmium_modal([ hdr, form ]);
6755 };
6756 })(key), { 'default': true });
6757
6758 osmium_ctxmenu_add_option(menu, "Remove fitting", function() {
6759 jsPlumb.doWhileSuspended(function() {
6760 jsPlumb.detachAllConnections(proj);
6761 proj.find('ul > li').each(function() {
6762 jsPlumb.detachAllConnections($(this));
6763 });
6764 proj.remove();
6765 });
6766
6767 delete osmium_clf['X-Osmium-remote'][key];
6768 osmium_commit_undo_deferred();
6769 }, {});
6770 }
6771
6772 if(proj.data('key') !== 'local' && osmium_loadout_readonly) {
6773 osmium_ctxmenu_add_option(menu, "View fitting", function() {
6774 var loc = window.location.href.split("#")[0];
6775 var match = loc.match(/^(.+?)\/remote\/(.+)$/);
6776
6777 if(match !== null) {
6778 var localkey;
6779
6780 if(key.toString() === match[2]) {
6781 window.location.assign(match[1]);
6782 return;
6783 } else {
6784 localkey = key;
6785 }
6786
6787 window.location.assign(match[1] + "/remote/" + encodeURIComponent(localkey));
6788 } else {
6789 window.location.assign(loc + '/remote/' + encodeURIComponent(key));
6790 }
6791 }, {});
6792 }
6793
6794 if(proj.data('shiptypeid')) {
6795 /* No point allowing show ship info on shallow pools */
6796
6797 osmium_ctxmenu_add_separator(menu);
6798
6799 osmium_ctxmenu_add_option(menu, "Show ship info", function() {
6800 osmium_showinfo({
6801 remote: key,
6802 type: "ship"
6803 });
6804 }, { icon: osmium_showinfo_sprite_position, 'default': osmium_loadout_readonly });
6805 }
6806
6807 return menu;
6808 });
6809
6810 return proj;
6811};
6812
6813osmium_projected_regen_local = function() {
6814 var oldlocal = $("section#projected div.projected-local");
6815 if(oldlocal.length === 0) return; /* Not yet generated, will be done later */
6816
6817 var local = osmium_create_projected("local", osmium_clf, oldlocal.index());
6818 osmium_projected_replace_graceful(oldlocal, local);
6819};
6820
6821osmium_projected_regen_remote = function(key, onsuccess, onerror) {
6822 var t = $("section#projected div.pr-loadout.projected-" + key);
6823
6824 osmium_commit_clf({
6825 params: { "remoteclf": t.data('key') },
6826 success: function(payload) {
6827 if(!("remote-clf" in payload)) return;
6828
6829 osmium_clf['X-Osmium-remote'][t.data("key")] = payload['remote-clf'];
6830 osmium_undo_push();
6831
6832 osmium_projected_replace_graceful(
6833 t,
6834 osmium_create_projected(
6835 t.data('key'),
6836 osmium_clf['X-Osmium-remote'][t.data('key')],
6837 t.index()
6838 )
6839 );
6840
6841 if('remote-errors' in payload) {
6842 if(typeof onerror === 'function') onerror(payload['remote-errors']);
6843 } else {
6844 if(typeof onsuccess === 'function') onsuccess(payload);
6845 }
6846 }
6847 });
6848};
6849
6850osmium_projected_replace_graceful = function(stale, fresh) {
6851 var cssprops = [ "left", "top", "right", "bottom" ];
6852 for(var i = 0; i < cssprops.length; ++i) {
6853 fresh.css(cssprops[i], stale.css(cssprops[i]));
6854 }
6855
6856 jsPlumb.doWhileSuspended(function() {
6857 var newconnections = [];
6858
6859 osmium_user_initiated_push(false);
6860 /* Keep all incoming projections */
6861 jsPlumb.select({
6862 target: stale
6863 }).each(function(conn) {
6864 var source = conn.source;
6865 jsPlumb.detach(conn);
6866 newconnections.push({
6867 source: source,
6868 target: fresh
6869 });
6870 });
6871 osmium_user_initiated_pop();
6872
6873 osmium_user_initiated_push(false);
6874 /* Keep outgoing projections if modules match */
6875 stale.find('ul > li').each(function() {
6876 var source = $(this);
6877 var newsource = fresh.find('ul > li').filter(function() {
6878 var t = $(this);
6879 return t.data('typeid') == source.data('typeid') && t.data('index') == source.data('index');
6880 }).first();
6881
6882 var connections = jsPlumb.select({
6883 source: source
6884 });
6885
6886 if(newsource.length === 1) {
6887 /* Found a matching module, transfer all connections to it */
6888 connections.each(function(conn) {
6889 var target = conn.target;
6890 jsPlumb.detach(conn);
6891 newconnections.push({
6892 source: newsource,
6893 target: target
6894 });
6895 });
6896 } else {
6897 /* Drop connections */
6898 osmium_user_initiated_pop();
6899 connections.detach();
6900 osmium_user_initiated_push(false);
6901 }
6902
6903 jsPlumb.unmakeSource(source);
6904 });
6905 osmium_user_initiated_pop();
6906
6907 jsPlumb.unmakeTarget(stale);
6908 stale.before(fresh);
6909 stale.remove();
6910
6911 for(var i = 0; i < newconnections.length; ++i) {
6912 jsPlumb.connect(newconnections[i]);
6913 }
6914 });
6915
6916 jsPlumb.recalculateOffsets(fresh);
6917};
6918
6919osmium_regen_remote_capacitor = function(key_or_element) {
6920 if(typeof osmium_capacitors !== "object") return;
6921
6922 var c, s;
6923
6924 if(typeof key_or_element !== "object") {
6925 if(!(key_or_element in osmium_capacitors)) return;
6926 s = $("section#projected div.pr-loadout.projected-" + key_or_element);
6927 c = osmium_capacitors[key_or_element];
6928 } else {
6929 s = key_or_element;
6930 if(!(s.data('key') in osmium_capacitors)) return;
6931 c = osmium_capacitors[s.data('key')];
6932 }
6933
6934 if(s.length !== 1) return;
6935 s = s.find('svg');
6936
6937 if(c.capacity > 0) {
6938 var delta = -1000 * c.delta;
6939 if(delta >= 0) delta = '+' + delta.toFixed(1);
6940 else delta = delta.toFixed(1);
6941
6942 s.data({
6943 capacity: c.capacity,
6944 current: c.stable ? (c.capacity * c.stable_fraction) : 0
6945 });
6946 s.parent().prop(
6947 'title', delta + ' GJ/s, '
6948 + (c.stable ? ((100 * c.stable_fraction).toFixed(1) + '%') : c.depletion_time)
6949 );
6950 } else {
6951 s.data({ capacity: 1000, current: 1000 });
6952 s.parent().prop('title', ''); /* XXX: .removeProp() gives "undefined" as tooltip */
6953 }
6954
6955 s.trigger('redraw');
6956};
6957
6958osmium_regen_offsets = function() {
6959 var divs = $("section#projected form#projected-list").children('div.pr-loadout');
6960 divs.each(function() {
6961 jsPlumb.recalculateOffsets($(this));
6962 });
6963}
6964
6965osmium_commit_undo_deferred_timeoutid = undefined;
6966osmium_commit_undo_deferred = function(delay) {
6967 if(!osmium_user_initiated) return;
6968
6969 if(delay === undefined) delay = 100;
6970
6971 if(osmium_commit_undo_deferred_timeoutid !== undefined) {
6972 clearTimeout(osmium_commit_undo_deferred_timeoutid);
6973 } else {
6974 osmium_clfspinner_push();
6975 }
6976
6977 osmium_commit_undo_deferred_timeoutid = setTimeout(function() {
6978 osmium_commit_undo_deferred_timeoutid = undefined;
6979 osmium_commit_clf();
6980 osmium_undo_push();
6981 osmium_clfspinner_pop();
6982 }, delay);
6983};
6984/* Osmium
6985 * Copyright (C) 2012, 2013, 2014, 2015 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
6986 *
6987 * This program is free software: you can redistribute it and/or modify
6988 * it under the terms of the GNU Affero General Public License as published by
6989 * the Free Software Foundation, either version 3 of the License, or
6990 * (at your option) any later version.
6991 *
6992 * This program is distributed in the hope that it will be useful,
6993 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6994 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6995 * GNU Affero General Public License for more details.
6996 *
6997 * You should have received a copy of the GNU Affero General Public License
6998 * along with this program. If not, see <http://www.gnu.org/licenses/>.
6999 */
7000
7001/*<<< require snippet loadout_common >>>*/
7002/*<<< require snippet new_loadout-sources >>>*/
7003/*<<< require snippet new_loadout-ship >>>*/
7004/*<<< require snippet new_loadout-presets >>>*/
7005/*<<< require snippet new_loadout-metadata >>>*/
7006/*<<< require snippet new_loadout-modules >>>*/
7007/*<<< require snippet new_loadout-drones >>>*/
7008/*<<< require snippet new_loadout-implants >>>*/
7009/*<<< require snippet new_loadout-beacons >>>*/
7010/*<<< require snippet new_loadout-remote >>>*/
7011
7012$(function() {
7013 $('p#needjs').css({ visibility: 'hidden' });
7014
7015 var overlayt = setTimeout(function() {
7016 overlayt = null;
7017
7018 var odiv = $("div#loadingoverlay");
7019 if(odiv.length === 0) return;
7020
7021 var p = $(document.createElement('p'))
7022 .addClass('warning_box')
7023 .text('Still loading? Try refreshing the page, or report the issue if it persists.')
7024 .hide()
7025 ;
7026
7027 odiv.children('div').append(p);
7028 p.fadeIn(250);
7029 }, 8000);
7030
7031 osmium_load_common_data();
7032 osmium_shortlist = $("div#osmium-data").data('shortlist');
7033
7034 $("section#remote").on('made_visible', function() {
7035 jsPlumb.setSuspendDrawing(false);
7036 });
7037
7038 osmium_tabify($('div#nlmain > ul.tabs'), 0);
7039
7040 $('div#nlsources > ul.tabs').each(function() {
7041 osmium_tabify($(this), 0);
7042 });
7043
7044 jsPlumb.setSuspendDrawing(true);
7045
7046 osmium_load_common_data();
7047 osmium_shortlist = $("div#osmium-data").data('shortlist');
7048
7049 osmium_load_static_client_data(osmium_cdatastaticver, function(cdata) {
7050 osmium_gen();
7051 osmium_init();
7052
7053 if($("a[href='#remote']").parent().hasClass('active')) {
7054 $("section#remote").trigger('made_visible');
7055 }
7056
7057 /* Fetch computed attributes, etc. */
7058 osmium_commit_clf({
7059 success: function() {
7060 $("div#loadingoverlay").fadeOut(100);
7061 if(overlayt !== null) clearTimeout(overlayt);
7062 },
7063 });
7064
7065 /* Everything done from now on is user initiated */
7066 osmium_user_initiated_push(true);
7067
7068 osmium_undo_push();
7069 });
7070 });
7071
7072osmium_loadout_readonly = false;
7073osmium_clftype = 'new';
7074osmium_on_clf_payload = function(payload) {
7075 $("section#metadata tr#recommended_tags").remove();
7076 if(payload.rectags.length > 0) {
7077 var tr = $(document.createElement('tr'));
7078 tr.append(document.createElement('th'));
7079 tr.prop('id', 'recommended_tags');
7080 var td = $(document.createElement('td'));
7081 tr.append(td);
7082 td.append('Recommended tags: ');
7083 var ul = $(document.createElement('ul'));
7084 ul.addClass('tags');
7085 for(var i = 0; i < payload.rectags.length; ++i) {
7086 var li = $(document.createElement('li'));
7087 var a = $(document.createElement('a'));
7088 a.prop('title', 'Add this tag');
7089 a.text(payload.rectags[i]);
7090 li.append(a);
7091 ul.append(li);
7092 ul.append(' ');
7093 }
7094 td.append(ul);
7095
7096 $("input#tags").closest('tr').after(tr);
7097 }
7098};
7099osmium_on_clf_token_change = function(oldtok, newtok) {
7100 if(window.history && window.history.replaceState) {
7101 history.replaceState(history.state, null, './' + newtok + location.hash);
7102 }
7103};
7104
7105
7106
7107/* Generate all the missing DOM elements from the CLF */
7108osmium_gen = function() {
7109 osmium_gen_control();
7110 osmium_gen_ship();
7111 osmium_gen_metadata();
7112 osmium_gen_presets();
7113 osmium_gen_modules();
7114 osmium_gen_fattribs();
7115 osmium_gen_drones();
7116 osmium_gen_implants();
7117 osmium_gen_beacons();
7118 osmium_gen_remote();
7119};
7120
7121/* Set up event listeners that alter the CLF appropriately */
7122osmium_init = function() {
7123 osmium_init_control();
7124 osmium_init_ship();
7125 osmium_init_sources();
7126 osmium_init_metadata();
7127 osmium_init_presets();
7128 osmium_init_modules();
7129 osmium_init_fattribs();
7130 osmium_init_drones();
7131 osmium_init_implants();
7132 osmium_init_beacons();
7133 osmium_init_remote();
7134};
7135
7136osmium_add_to_clf = function(item) {
7137 var cat = item.data('category');
7138 var sub = item.data('subcategory');
7139 var typeid = item.data('typeid');
7140
7141 if(cat === 'ship') {
7142 osmium_clf.ship = { typeid: typeid };
7143
7144 /* Delete all modes */
7145 for(var i in osmium_clf.presets) {
7146 delete osmium_clf.presets[i]['X-mode'];
7147 }
7148
7149 /* If necessary, pick a mode */
7150 if(osmium_clf.ship.typeid in osmium_modes) {
7151 var modes = osmium_modes[osmium_clf.ship.typeid];
7152 var mtid;
7153
7154 for(var t in modes) {
7155 mtid = t;
7156 break;
7157 }
7158
7159 for(var i in osmium_clf.presets) {
7160 osmium_clf.presets[i]['X-mode'] = { typeid: mtid };
7161 }
7162 }
7163
7164 /* Regen everything as changing a ship changes pretty much
7165 * everything. */
7166 osmium_user_initiated_push(false);
7167 osmium_gen();
7168 osmium_user_initiated_pop();
7169 } else if(cat === 'module') {
7170 var state, index, m;
7171 var slotsdiv = $("section#modules > div.slots." + sub);
7172 var grouped = slotsdiv.hasClass('grouped');
7173 var other = osmium_types[typeid][6];
7174 var addcount = 1;
7175 var remaining = osmium_clf_slots[sub]
7176 - slotsdiv.children('ul').children('li:not(.placeholder)').length;
7177
7178 if(grouped && (other === 'turret' || other === 'launcher')) {
7179 addcount = osmium_clf_hardpoints[other];
7180 osmium_clf_hardpoints[other] = 0;
7181 }
7182
7183 if(addcount > remaining) {
7184 addcount = remaining;
7185 }
7186
7187 index = 0;
7188 for(var i = 0; i < osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules.length; ++i) {
7189 m = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules[i];
7190 if(m.index >= index) index = m.index + 1;
7191 }
7192
7193 if(osmium_module_states[typeid][2]) {
7194 /* Active state, if possible */
7195 state = osmium_states[2];
7196 } else {
7197 /* Online state */
7198 state = osmium_states[1];
7199 }
7200
7201 if(addcount < 1) addcount = 1;
7202 for(var i = 0; i < addcount; ++i) {
7203 osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']].modules.push({
7204 typeid: typeid,
7205 state: state,
7206 index: index
7207 });
7208
7209 osmium_add_module(typeid, index, state, null);
7210 ++index;
7211 }
7212
7213 if(osmium_types[typeid][8] === 1) {
7214 osmium_projected_regen_local();
7215 }
7216
7217 osmium_update_slotcounts();
7218 } else if(cat === 'charge') {
7219 var location = osmium_get_best_location_for_charge(typeid);
7220
7221 if(location !== null) {
7222 osmium_auto_add_charge_to_location(location, typeid);
7223 osmium_undo_push();
7224
7225 if(osmium_user_initiated) {
7226 $('a[href="#modules"]').parent().click();
7227 }
7228 } else {
7229 alert("This charge cannot be used with any fitted type.");
7230 }
7231 } else if(cat === 'drone') {
7232 var qty = item.data('qty');
7233 var dest = item.data('dest');
7234 if(qty < 1 || qty === undefined) qty = 1;
7235 var bw = parseInt(osmium_types[typeid][6], 10);
7236 if(dest !== 'bay' && dest !== 'space') {
7237 if(!("dronebandwidth" in osmium_clf_rawattribs)) {
7238 dest = 'space';
7239 } else {
7240 if(osmium_clf_rawattribs.dronebandwidthused + bw <= osmium_clf_rawattribs.dronebandwidth
7241 && osmium_clf_rawattribs.activedrones < osmium_clf_rawattribs.maxactivedrones) {
7242 dest = 'space';
7243 qty = Math.min(
7244 Math.floor(
7245 (osmium_clf_rawattribs.dronebandwidth
7246 - osmium_clf_rawattribs.dronebandwidthused) / bw
7247 ),
7248 osmium_clf_rawattribs.maxactivedrones - osmium_clf_rawattribs.activedrones
7249 );
7250 } else {
7251 dest = 'bay';
7252 }
7253 }
7254 }
7255 osmium_add_drone_to_clf(typeid, qty, dest);
7256 osmium_gen_drones();
7257 } else if(cat === 'implant') {
7258 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
7259 var implantness = osmium_types[typeid][3];
7260 if(!("implants" in p)) p.implants = [];
7261
7262 for(var i = 0; i < p.implants.length; ++i) {
7263 if(implantness === osmium_types[p.implants[i].typeid][3]) {
7264 p.implants.splice(i, 1);
7265 --i;
7266 }
7267 }
7268
7269 p.implants.push({ typeid: typeid });
7270
7271 osmium_gen_implants();
7272
7273 if(osmium_user_initiated) {
7274 $('a[href="#implants"]').parent().click();
7275 }
7276 } else if(cat === 'booster') {
7277 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
7278 var boosterness = osmium_types[typeid][3];
7279 if(!("boosters" in p)) p.boosters = [];
7280
7281 for(var i = 0; i < p.boosters.length; ++i) {
7282 if(boosterness === osmium_types[p.boosters[i].typeid][3]) {
7283 p.boosters.splice(i, 1);
7284 --i;
7285 }
7286 }
7287
7288 p.boosters.push({ typeid: typeid });
7289
7290 osmium_gen_implants();
7291
7292 if(osmium_user_initiated) {
7293 $('a[href="#implants"]').parent().click();
7294 }
7295 } else if(cat === 'beacon') {
7296 var p = osmium_clf.presets[osmium_clf['X-Osmium-current-presetid']];
7297 if(!('X-beacons' in p)) p['X-beacons'] = [];
7298
7299 if(p['X-beacons'].indexOf(typeid) === -1) {
7300 p['X-beacons'].push(typeid);
7301
7302 osmium_gen_beacons();
7303
7304 if(osmium_user_initiated) {
7305 $('a[href="#area"]').parent().click();
7306 }
7307 }
7308 } else {
7309 alert('Unknown category ' + cat);
7310 }
7311
7312 osmium_commit_clf();
7313 osmium_undo_push();
7314};