TW Gold Jobs Finder (More Languages)

Shows a list of all silver and gold jobs!

// ==UserScript==
// @name TW Gold Jobs Finder (More Languages)
// @namespace TomRobert
// @author Macabre2077 (updated by Tom Robert)
// @description Shows a list of all silver and gold jobs!
// @include https://*.the-west.*/game.php*
// @version 1.15
// @grant none
// ==/UserScript==
// translation: Did97(Russian), tw81(Italian), Jakovlev(Hungarian), realfan2002(Romanian), Vebuus/Bartosz86(Polish), Ilja Iljic(Czech), pepe100(Spanish), Tom Robert(German & French), Elly Siranno(Portuguese), ruud99(Dutch), Kigka(Greek)
(function (fn) {
  var script = document.createElement('script');
  script.setAttribute('type', 'application/javascript');
  script.textContent = '(' + fn + ')();';
  document.body.appendChild(script);
  document.body.removeChild(script);
})(function () {
  GJ = {
    version: '1.15',
    name: 'Gold Jobs Finder',
    author: 'Macabre2077 (updated by Tom Robert)',
    minGame: '2.05',
    maxGame: Game.version.toString(),
    website: '//greasyfork.org/scripts/7226',
    updateUrl: '//tomrobert.safe-ws.de/sUp.js',
    toLoad: 0,
    loaded: 0,
    xMax: 181,
    yMax: 79,
    blockMaxLength: 300,
    dataLoaded: false,
    silverJobBbColor: '#708090',
    goldJobBbColor: '#AB9930',
    preferences: {
      jobName: '',
      showSilver: true,
      showGold: true,
      sortByName: 0,
      sortByDistance: 1
    },
    hiddenImageOpacity: 0.35,
    shownImageOpacity: 1,
    bestJobTime: 0,
    langs: {
      en: {
        language: 'English',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Successfully saved',
        chooseLang: 'Choose language',
        contact: 'Contact',
        jobName: 'Job name',
        distanceTime: 'Travel time',
        showJob: 'Show',
        title: 'Gold And Silver Jobs',
        loading: 'Loading...',
        exportButtonTitle: 'Export',
        generatedByBb: 'Generated by',
        goback: 'Go back',
        bbCode: 'BB code',
        enqueue: 'Enqueue',
        openWindowTitle: 'Open window',
        refreshTitle: 'Refresh',
        feedbackTitle: 'Send feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'If you have encountered any bugs or have ideas how to improve this script, describe them.. in English, German or French please..',
      },
      ru: {
        language: 'Russian (русский)',
        ApiGui: 'Этот скрипт добавляет кнопку справа, с помощью которой Вы можете посмотреть все серебрянные и золотые работы.<br>Это поможет найти их на карте.',
        save: 'Экономить',
        saveMessage: 'Сохранить успешно',
        chooseLang: 'Сменить язык',
        contact: 'Контакты',
        jobName: 'Работа',
        distanceTime: 'Расстояние',
        showJob: 'Показать',
        title: 'Золотые и серебряные работы',
        loading: 'Загрузка...',
        exportButtonTitle: 'Экспорт',
        generatedByBb: 'Получено с помощью',
        goback: 'Назад',
        bbCode: 'BB-код',
        enqueue: 'Начать',
        openWindowTitle: 'Открыть окно',
        refreshTitle: 'Обновить данные',
        feedbackTitle: 'Обратная связь',
        feedbackWindowTitle: 'Обратная связь',
        feedbackDescription: 'Если Вы нашли баг, или у Вас есть идеи по улучшению скрипта, свяжитесь со мной',
      },
      it: {
        language: 'Italian (italiano)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Salva con successo',
        chooseLang: 'Cambia lingua',
        contact: 'Contatto',
        jobName: 'Nome lavoro',
        distanceTime: 'Tempo di viaggio',
        showJob: 'Mostra',
        title: 'Lavoro Oro e Argento',
        loading: 'Caricamento in corso ... Ci vorrà un po \'',
        exportButtonTitle: 'Esportazione',
        generatedByBb: 'Generato da',
        goback: 'Di ritorno',
        bbCode: 'BB code',
        enqueue: 'Inizia',
        openWindowTitle: 'Aperto',
        refreshTitle: 'Aggiornare dati',
        feedbackTitle: 'Invia feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Se avete riscontrato qualche bug o avete idee su come migliorare questo script, vi prego di descriverle .. in inglese, tedesco o francese per favore.',
      },
      hu: {
        language: 'Hungarian (magyar)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Successfully saved',
        chooseLang: 'Choose language',
        contact: 'Érintkezés',
        jobName: 'Munka neve',
        distanceTime: 'Menetidő',
        showJob: 'Mutatás',
        title: 'Arany és ezüst munkák',
        loading: 'Kis türelmet, töltés alatt...',
        exportButtonTitle: 'Export',
        generatedByBb: 'által létrehozva[/i]',
        goback: 'Vissza',
        bbCode: 'BB kód',
        enqueue: 'Kezdés',
        openWindowTitle: 'Megnyitás',
        refreshTitle: 'Frissítés',
        feedbackTitle: 'Visszajelzés küldése',
        feedbackWindowTitle: 'Visszajelzés',
        feedbackDescription: 'Ha találkoztál hibákkal (bug), vagy javaslatod lenne a szkript bővítéséhez írd le őket. Értek angolul, németül és franciául.',
      },
      ro: {
        language: 'Romanian (român)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Successfully saved',
        chooseLang: 'Choose language',
        contact: 'Contact',
        jobName: 'Denumirea muncii',
        distanceTime: 'Distanţa',
        showJob: 'Arată',
        title: 'Munci aurii şi argintii',
        loading: 'Se încarcă... Poate dura ceva timp!',
        exportButtonTitle: 'Export',
        generatedByBb: 'Generat cu',
        goback: 'Înapoi',
        bbCode: 'BB code',
        enqueue: 'Start',
        openWindowTitle: 'Deschide',
        refreshTitle: 'Reîmprospăta',
        feedbackTitle: 'Trimite feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'If you have encountered any bugs or have ideas how to improve this script, describe them.. in English, German or French please..',
      },
      pl: {
        language: 'Polish (polski)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Zapisz',
        saveMessage: 'Zapisz powodzeniem',
        chooseLang: 'Wybierz język',
        contact: 'Kontakt',
        jobName: 'Nazwa pracy',
        distanceTime: 'Dystans',
        showJob: 'Pokaż',
        title: 'Złote i srebrne prace',
        loading: 'Ładowanie... To zajmie moment',
        exportButtonTitle: 'Eksport',
        generatedByBb: 'Stworzone przez',
        goback: 'Cofnij',
        bbCode: 'BB code',
        enqueue: 'Startuj',
        openWindowTitle: 'Otwórz',
        refreshTitle: 'Odświeżanie danych',
        feedbackTitle: 'Wystawienie opinii',
        feedbackWindowTitle: 'Opinie',
        feedbackDescription: 'Jeżeli znalazłeś błąd, lub masz pomysł jak można udoskonalić skrypt - napisz do mnie. Proszę o kontakt w języku angielskim, niemieckim bądź francuskim.',
      },
      cs: {
        language: 'Czech (čeština)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Successfully saved',
        chooseLang: 'Choose language',
        contact: 'Kontakt',
        jobName: 'Práce',
        distanceTime: 'Vzdálenost',
        showJob: 'Ukaž',
        title: 'Zlaté a stříbrné práce',
        loading: 'Nahrávám...',
        exportButtonTitle: 'Export',
        generatedByBb: 'Generated by',
        goback: 'Zpět',
        bbCode: 'BB code',
        enqueue: 'Zadat',
        openWindowTitle: 'Otevřít okno',
        refreshTitle: 'Obnovit',
        feedbackTitle: 'Pošli zpětnou vazbu',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Pokud jste nalezli bug nebo máte nápad na zlepšení skriptu, napište je..v angličtině, němčině nebo francouzštině prosím..',
      },
      es: {
        language: 'Spanish (español)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Guardar',
        saveMessage: 'Guardar correctamente',
        chooseLang: 'Elige idioma',
        contact: 'Contacto',
        jobName: 'Nombre Trabajo',
        distanceTime: 'Tiempo viaje',
        showJob: 'Mostrar',
        title: 'Trabajos con Bonus Oro y Plata',
        loading: 'Cargando...',
        exportButtonTitle: 'Exportación',
        generatedByBb: 'Generado por',
        goback: 'De regreso',
        bbCode: 'BB code',
        enqueue: 'Poner en cola',
        openWindowTitle: 'Abrir ventana',
        refreshTitle: 'Refrescar',
        feedbackTitle: 'Enviar comentarios',
        feedbackWindowTitle: 'Comentarios',
        feedbackDescription: 'Si ha encontrado algún error o tiene ideas de cómo mejorar este script, descríbalos.. por favor en inglés, alemán o francés..',
      },
      de: {
        language: 'German (Deutsch)',
        ApiGui: 'Das Script fügt am rechten Rand einen Button hinzu, wo man alle Gold- und Silber-Arbeiten laden kann.<br>So findet man sie ganz einfach auf der Karte.',
        save: 'Speichern',
        saveMessage: 'Speichern erfolgreich',
        chooseLang: 'Sprache ändern',
        contact: 'Kontakt',
        jobName: 'Arbeit',
        distanceTime: 'Distanz',
        showJob: 'Zeigen',
        title: 'Gold und Silber Arbeiten',
        loading: 'Laden...',
        exportButtonTitle: 'Exportieren',
        generatedByBb: 'Gefunden mit',
        goback: 'Zurück',
        bbCode: 'BB Code',
        enqueue: 'Einstellen',
        openWindowTitle: 'Fenster öffnen',
        refreshTitle: 'Aktualisieren',
        feedbackTitle: 'Feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Falls du auf Fehler gestossen bist oder Ideen hast, wie man das Script verbessern könnte, kannst du mich kontaktieren.',
      },
      fr: {
        language: 'French (français)',
        ApiGui: 'Avec ce script, tu peux voir une liste de tous les travaux argentés et dorés.<br>Comme ça il est très facile de trouve les travaux de bonus sur le Mini-map.',
        save: 'Sauver',
        saveMessage: 'Enregistré avec succès',
        chooseLang: 'Choisissez la langue',
        contact: 'Contact',
        jobName: 'Travail',
        distanceTime: 'Distance',
        showJob: 'Montre',
        title: 'Travaux argentés et dorés',
        loading: 'Chargement en cours...',
        exportButtonTitle: 'Exportation',
        generatedByBb: 'Trouvé avec',
        goback: 'De retour',
        bbCode: 'BB code',
        enqueue: 'Commencer',
        openWindowTitle: 'Ouvrir la fenêtre',
        refreshTitle: 'Rafraîchir',
        feedbackTitle: 'Contact',
        feedbackWindowTitle: 'Contact',
        feedbackDescription: 'Si tu as trouvé un bug ou si tu as des idées pour améliorer le script, contactez-moi.',
      },
      pt: {
        language: 'Portuguese (português)',
        ApiGui: 'Este Script faz uma busca automãtica e em tempo real de todos os Trabalhos com Bônus Ouro ou Prata em todo o Mundo.',
        save: 'Salvar',
        saveMessage: 'Economize com sucesso',
        chooseLang: 'Escolhe idioma',
        contact: 'Contato com Autor',
        jobName: 'Nome do Job',
        distanceTime: 'Distância',
        showJob: 'Show',
        title: 'Gold And Silver Jobs',
        loading: 'Procurando Jobs Ouro/Prata',
        exportButtonTitle: 'Exportar',
        generatedByBb: 'Generated by',
        goback: 'Go back',
        bbCode: 'BB code',
        enqueue: 'Iniciar Job',
        openWindowTitle: 'Procurar Jobs',
        refreshTitle: 'Atualizar Lista',
        feedbackTitle: 'Suporte',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Aqui vc encontra os meios de comunicação com o supporte do Script, pode reportar um erro, fazer uma crítica ou dar sugestões',
      },
      nl: {
        language: 'Dutch (Nederlands)',
        ApiGui: 'Dit script voegt een knop aan de rechterkant toe in het scherm. Deze button laadt alle zilveren en gouden werkzaamheden.<br>Zodat ze gemakkelijk gevonden kunnen worden op de kaart.',
        save: 'Besparen',
        saveMessage: 'Sparen succes',
        chooseLang: 'Kies een taal',
        contact: 'Contact',
        jobName: 'Werkzaamheid',
        distanceTime: 'Afstand',
        showJob: 'Toon',
        title: 'Gouden en zilveren arbeiden',
        loading: 'Laden...',
        exportButtonTitle: 'Exporteren',
        generatedByBb: 'Gemaakt door',
        goback: 'Terug',
        bbCode: 'BB code',
        enqueue: 'Starten',
        openWindowTitle: 'Scherm openen',
        refreshTitle: 'Herladen',
        feedbackTitle: 'Feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Als je bugs tegenkomt of ideeën hebt om dit script te verbeteren, omschrijf ze in Engels, Duits of Frans aub.',
      },
      el: {
        language: 'Greek (ελληνικά)',
        ApiGui: 'This script adds a button on the right side, where you can load all the silver and gold jobs.<br>So they can be easily found on the map.',
        save: 'Save',
        saveMessage: 'Successfully saved',
        chooseLang: 'Choose language',
        contact: 'Contact',
        jobName: 'Όνομα Δουλειάς',
        distanceTime: 'Απόσταση',
        showJob: 'Εμφάνιση',
        title: 'Χρυσές και Ασημένιες δουλειές',
        loading: 'Φόρτωση...',
        exportButtonTitle: 'Share',
        generatedByBb: 'Generated by',
        goback: 'Go back',
        bbCode: 'BB κώδικας',
        enqueue: 'Περπατήστε',
        openWindowTitle: 'Άνοιγμα παραθύρου',
        refreshTitle: 'Refresh',
        feedbackTitle: 'Στείλτε  feedback',
        feedbackWindowTitle: 'Feedback',
        feedbackDescription: 'Αν έχετε αντιμετωπίσει τυχόν σφάλματα ή έχετε ιδέες για τη βελτίωση αυτού του script, ενημερώστε με..'
      },
    },
    updateLang: function () {
      var lg = GJ.langs;
      GJ.lang = lg[localStorage.getItem('scriptsLang')] ? localStorage.getItem('scriptsLang') : lg[Game.locale.substr(0, 2)] ? Game.locale.substr(0, 2) : 'en';
      GJlang = lg[GJ.lang];
    },
  };
  GJ.updateLang();
  GJ.parseWholeMap = function (tiles, onLoad) {
    this.loaded = 0;
    var x,
    y;
    var arr = [];
    var currentBlock = 0;
    var currentBlockLength = 0;
    for (x in tiles) {
      for (y in tiles[x]) {
        if (isNaN(x) || isNaN(y)) {
          continue;
        }
        if (currentBlockLength === 0) {
          arr[currentBlock] = [
          ];
        }
        arr[currentBlock].push([parseInt(x),
            parseInt(y)]);
        if (++currentBlockLength == this.blockMaxLength) {
          currentBlock++;
          currentBlockLength = 0;
        }
      }
    }
    var i,
    to = arr.length;
    this.toLoad = to;
    for (i = 0; i < to; i++) {
      GameMap.Data.Loader.load(arr[i], function () {
        GJ.loaded++;
        if (GJ.loaded == GJ.toLoad) {
          onLoad();
        }
      });
    }
  };
  GJ.getJobIcon = function (jobId, x, y, shortname, gold) {
    var t = gold ? 'gold' : 'silver';
    return '<div class="job" style="left: 0; top: 0; position: relative;"><div  onclick="javascript:GameMap.JobHandler.openJob(' + jobId + ',{x:' + x + ',y:' + y + '})" class="featured ' + t + '"></div>' + this.getGotoIcon(x, y) + '<img src="images/jobs/' + shortname + '.png" class="job_icon"></div>';
  };
  GJ.getGotoIcon = function (x, y) {
    return '<div class="centermap" onclick="javascript:GameMap.center(' + x + ',' + y + ');"style="position: absolute;background-image: url(\'images/map/icons/instantwork.png\');width: 20px;height: 20px;top: 0;right: 3px;cursor: pointer;"></div>';
  };
  GJ.getBestJobTime = function () {
    var list = JobList.getDurations();
    var maxTime = 0;
    for (var name in list) {
      if (list[name].requirement <= Character.level && list[name].duration > maxTime) {
        maxTime = list[name].duration;
      }
    }
    GJ.bestJobTime = maxTime;
  };
  GJ.getEnqueueButton = function (jobId, x, y) {
    var job = JobList.getJobById(jobId);
    var canDo = job.canDo();
    if (GJ.bestJobTime === 0) {
      GJ.getBestJobTime();
    }
    var duration = GJ.bestJobTime;
    var b = this.gui.makeButton(GJlang.enqueue, function () {
      TaskQueue.add(new TaskJob(jobId, x, y, duration));
    });
    b.setWidth(100);
    if (!canDo)
      b.disable();
    return b.getMainDiv();
  };
  GJ.addColumnsCss = function () {
    $('.goldenJobs .jobIcon').css('width', '60px');
    $('.goldenJobs .jobName').css('width', '140px');
    $('.goldenJobs .startJob').css('width', '100px');
    $('.goldenJobs .distanceTime').css('width', '60px');
    $('.goldenJobs .row').css('height', '56px');
    $('.goldenJobs .row').css('background', 'none');
    $('.goldenJobs .row_head .jobName').css('width', '135px');
    $('.goldenJobs .row_head .distanceTime').css('width', '95px');
    $('.goldenJobs .row_head .startJob').css('width', '0px');
    $('.goldenJobs .tfoot .jobIcon').css('width', '100%');
    $('.goldenJobs .tfoot').css('height', '35px');
    $('.goldenJobs').find('.tw2gui_scrollpane').css('height', '280px');
  };
  GJ.calculateDistance = function (jobX, jobY) {
    var to = {
      x: jobX,
      y: jobY
    };
    return GameMap.calcWayTime(Character.position, to);
  };
  GJ.addEventListener = function (event, callback) {
    if (EventHandler.hasOwnProperty('add')) {
      EventHandler.add(event, callback);
    } else {
      EventHandler.listen(event, callback);
    }
  };
  GJ.openWindow = function () {
    var content = $('<div class=\'goldwindow\'/>');
    var table = this.makeJobsTable(this.preferences.jobName, this.preferences.showSilver, this.preferences.showGold, this.preferences.sortByName, this.preferences.sortByDistance);
    var win = wman.open('goldenJobs').setResizeable(true).setMinSize(450, 475).setSize(450, 475).setMiniTitle(GJlang.title);
    content.append(table.getMainDiv());
    win.appendToContentPane(content);
    this.addColumnsCss();
    this.addFilterEvent();
    this.addHeaderEvents();
    this.addEventListener('position_change', GJ.refreshWindow);
  };
  GJ.buildFooter = function (chosenJobName) {
    var footer = $('<div class="goldjobs_table_foot" style="margin-top: 3px"><span id="gj_job_search" style="position: relative; top: 0px;"></span><span id="gj_share" style="position: absolute;top: 3px;right: 7px;"></span></div>');
    var exportButton = this.gui.makeButton(GJlang.exportButtonTitle, function () {
      var jobName = $('#gj_job_search_textfield').val();
      var jobs = GJ.jobsDataToString(jobName);
      GJ.showExportWindow(jobs, false);
    }).setWidth(100);
    var textfield = this.gui.makeTextfield('gj_job_search_textfield').setSize(18).setWidth(137);
    var clearImage = $('<img/>', {
      src: 'images/chat/servicegrade_traitor.png',
      click: function () {
        $('#gj_job_search_textfield').val('').trigger('change');
      },
      css: {
        filter: 'grayscale(100%)',
        '-webkit-filter': 'grayscale(100%)',
        '-moz-filter': 'grayscale(100%)',
        '-o-filter': 'grayscale(100%)',
        position: 'absolute',
        top: '-1px',
        left: '130px'
      }
    });
    $('#gj_job_search', footer).append(textfield.getMainDiv());
    $('#gj_share', footer).append(exportButton.getMainDiv());
    $('#gj_job_search span.tw2gui_textfield span', footer).append('<span class=\'placeholder\' style=\'font-weight: lighter;color: #333;position: absolute;left: 12px; top: 1px;\'>' + GJlang.jobName + '</span>');
    var placeholder = $('#gj_job_search .placeholder', footer);
    placeholder.after(clearImage);
    placeholder.click(function () {
      $('#gj_job_search_textfield', footer).trigger('focus');
    });
    $('#gj_job_search_textfield', footer).on('focus', function () {
      placeholder.hide();
    });
    $('#gj_job_search_textfield', footer).on('focusout', function () {
      if ($('#gj_job_search_textfield').val() == '') {
        placeholder.show();
      }
    });
    if (chosenJobName) {
      $('#gj_job_search_textfield', footer).val(chosenJobName).trigger('focus');
    }
    return footer;
  };
  GJ.getJobIconHeaderCell = function (showGold, showSilver) {
    var hiddenImageOpacity = this.hiddenImageOpacity;
    var shownImageOpacity = this.shownImageOpacity;
    return '<img src="images/jobs/featured/goldjob.png" style="width: 15px; opacity: ' + (showGold ? shownImageOpacity : hiddenImageOpacity) + '; " onclick="javascript:GJ.onJobIconFilterClick(&quot;gold&quot;, $(this))">+\t\t\t\t<img src="images/jobs/featured/silverjob.png" style="width: 15px; opacity: ' + (showSilver ? shownImageOpacity : hiddenImageOpacity) + '; " onclick="javascript:GJ.onJobIconFilterClick(&quot;silver&quot;, $(this))">';
  };
  GJ.onJobIconFilterClick = function (type, element) {
    var hiddenImageOpacity = this.hiddenImageOpacity;
    var shownImageOpacity = this.shownImageOpacity;
    var disabled = ($(element).css('opacity') != shownImageOpacity);
    if (type == 'gold') {
      this.preferences.showGold = disabled;
    } else {
      this.preferences.showSilver = disabled;
    }
    $(element).css('opacity', (disabled ? hiddenImageOpacity : shownImageOpacity));
    this.refreshWindow();
  };
  GJ.getAllTiles = function (callback) {
    Ajax.get('map', 'get_minimap', {}, function (r) {
      if (r.error) {
        console.log(r.error);
        return;
      }
      var result = [];
      var jobGroups = r.job_groups,
      i,
      j;
      for (i in jobGroups) {
        for (j in jobGroups[i]) {
          var coords = jobGroups[i][j];
          var xTile = Math.floor(coords[0] / GameMap.tileSize);
          var yTile = Math.floor(coords[1] / GameMap.tileSize);
          if (!result.hasOwnProperty(xTile)) {
            result[xTile] = {};
          }
          result[xTile][yTile] = 1;
        }
      }
      GJ.tilesWithJobs = result;
      callback();
    });
  };
  GJ.getFilteredData = function (chosenJobName, showSilver, showGold, sortByName, sortByDistance) {
    chosenJobName = chosenJobName.toLowerCase();
    var jobs = GameMap.JobHandler.Featured;
    var k,
    jobId,
    job,
    j;
    var result = [];
    for (k in jobs) {
      var jobPlace = jobs[k];
      for (jobId in jobPlace) {
        job = JobList.getJobById(jobId);
        j = jobPlace[jobId];
        if ((j.silver && !showSilver) || (j.gold && !showGold)) {
          continue;
        }
        if (chosenJobName !== '' && job.name.toLowerCase().indexOf(chosenJobName) < 0) {
          continue;
        }
        result.push({
          jobId: jobId,
          x: j.x,
          y: j.y,
          name: job.name,
          shortname: job.shortname,
          gold: j.gold,
          distance: this.calculateDistance(j.x, j.y)
        });
      }
    }
    var nameSortFunctionReversed = function (o1, o2) {
      var t1 = o1.name.toUpperCase();
      var t2 = o2.name.toUpperCase();
      return (t1 > t2) ?  - 1 : (t1 < t2) ? 1 : 0;
    };
    var distanceSortFunctionReversed = function (o1, o2) {
      var t1 = parseInt(o1.distance);
      var t2 = parseInt(o2.distance);
      return (t1 > t2) ?  - 1 : (t1 < t2) ? 1 : 0;
    };
    var nameSortFunction = function (o1, o2) {
      var t1 = o1.name.toUpperCase();
      var t2 = o2.name.toUpperCase();
      return (t1 < t2) ?  - 1 : (t1 > t2) ? 1 : 0;
    };
    var distanceSortFunction = function (o1, o2) {
      var t1 = o1.distance;
      var t2 = o2.distance;
      return (t1 < t2) ?  - 1 : (t1 > t2) ? 1 : 0;
    };
    if (sortByName !== 0) {
      if (sortByName == 1) {
        result.sort(nameSortFunction);
      } else {
        result.sort(nameSortFunctionReversed);
      }
    } else if (sortByDistance !== 0) {
      if (sortByDistance == 1) {
        result.sort(distanceSortFunction);
      } else {
        result.sort(distanceSortFunctionReversed);
      }
    }
    return result;
  };
  GJ.makeJobsTable = function (chosenJobName, showSilver, showGold, sortByName, sortByDistance) {
    chosenJobName = chosenJobName || '';
    var arrow_desc = '&nbsp;<img src="images/window/jobs/sortarrow_desc.png"/>',
    arrow_asc = '&nbsp;<img src="images/window/jobs/sortarrow_asc.png"/>',
    footer = this.buildFooter(chosenJobName),
    table = this.gui.makeTable(),
    data = this.getFilteredData(chosenJobName, showSilver, showGold, sortByName, sortByDistance);
    table.addColumn('jobIcon', 'jobIcon').addColumn('jobName', 'jobName').addColumn('distanceTime', 'distanceTime').addColumn('startJob', 'startJob').appendToCell('head', 'jobIcon', this.getJobIconHeaderCell(showGold, showSilver)).appendToCell('head', 'jobName', GJlang.jobName + (sortByName == 1 ? arrow_asc : sortByName ==  - 1 ? arrow_desc : '')).appendToCell('head', 'distanceTime', GJlang.distanceTime + (sortByDistance == 1 ? arrow_asc : sortByDistance ==  - 1 ? arrow_desc : '')).appendToCell('head', 'startJob', '');
    $.each(data, function (k, j) {
      table.appendRow().appendToCell( - 1, 'jobIcon', GJ.getJobIcon(j.jobId, j.x, j.y, j.shortname, j.gold)).appendToCell( - 1, 'jobName', j.name).appendToCell( - 1, 'distanceTime', j.distance.formatDuration()).appendToCell( - 1, 'startJob', GJ.getEnqueueButton(j.jobId, j.x, j.y));
    });
    table.appendToFooter('jobIcon', footer);
    return table;
  };
  GJ.refreshWindow = function () {
    GJ.preferences.jobName = $('#gj_job_search_textfield').val();
    var newTable = GJ.makeJobsTable(GJ.preferences.jobName, GJ.preferences.showSilver, GJ.preferences.showGold, GJ.preferences.sortByName, GJ.preferences.sortByDistance);
    $('.goldenJobs .fancytable').remove();
    $('.goldwindow').prepend(newTable.getMainDiv());
    GJ.addColumnsCss();
    GJ.addFilterEvent();
    GJ.addHeaderEvents();
    $('#gj_job_search_textfield').trigger('focus');
  };
  GJ.addFilterEvent = function () {
    var f = function () {
      if (GJ.filterTimeout !== undefined) {
        clearTimeout(GJ.filterTimeout);
      }
      GJ.filterTimeout = setTimeout(function () {
        GJ.refreshWindow();
      }, 500);
    };
    $('#gj_job_search_textfield').on('change', f).on('keypress', f);
  };
  GJ.addHeaderEvents = function () {
    $('.goldenJobs .row_head .jobName').click(function () {
      GJ.preferences.sortByName = GJ.preferences.sortByName == 1 ?  - 1 : 1;
      GJ.preferences.sortByDistance = 0;
      GJ.refreshWindow();
    });
    $('.goldenJobs .row_head .distanceTime').click(function () {
      GJ.preferences.sortByName = 0;
      GJ.preferences.sortByDistance = GJ.preferences.sortByDistance == 1 ?  - 1 : 1;
      GJ.refreshWindow();
    });
  };
  GJ.getMessageDialog = function (text, type, title) {
    title = title || '';
    if (type == 'warning') {
      type = west.gui.Dialog.SYS_WARNING;
    }
    if (type == 'question') {
      type = west.gui.Dialog.SYS_QUESTION;
    }
    return new west.gui.Dialog(text, title, type);
  };
  GJ.getSelectBox = function () {
    var onLoad = function () {
      GJ.openWindow();
      GJ.dataLoaded = true;
    };
    var listener = function (k) {
      switch (k) {
      case 'feedback':
        GJ.openFeedbackWindow();
        break;
      case 'open':
        if (!GJ.hasOwnProperty('tilesWithJobs')) {
          new UserMessage(GJlang.loading, UserMessage.TYPE_HINT).show();
          GJ.getAllTiles(function () {
            GJ.parseWholeMap(GJ.tilesWithJobs, onLoad);
          });
        } else {
          onLoad();
        }
        break;
      case 'refresh':
        new UserMessage(GJlang.loading, UserMessage.TYPE_HINT).show();
        if (!GJ.hasOwnProperty('tilesWithJobs')) {
          GJ.getAllTiles(function () {
            GJ.parseWholeMap(GJ.tilesWithJobs, onLoad);
          });
        } else {
          GJ.parseWholeMap(GJ.tilesWithJobs, onLoad);
        }
        break;
      }
    };
    this.selectBox = new west.gui.Selectbox().setWidth(150).addListener(listener).addItem('open', GJlang.openWindowTitle).addItem('refresh', GJlang.refreshTitle).addItem('feedback', GJlang.feedbackTitle);
  };
  GJ.toggleSelectbox = function () {
    var pos = $('div#GoldJobsmenu').offset();
    pos = {
      clientX: pos.left,
      clientY: pos.top
    };
    GJ.selectBox.show(pos);
  };
  GJ.init = function () {
    var menuimage = 'data:image/png;base64,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';
    this.getSelectBox();
    var div = $('<div class="ui_menucontainer" />');
    var link = $('<div id="GoldJobsmenu" class="menulink" onclick="GJ.toggleSelectbox();" title="' + GJ.name + '" />').css('background-image', 'url(' + menuimage + ')').css('background-position', '0px 0px').on('mouseenter', function () {
      $(this).css('background-position', '-25px 0px');
    }).on('mouseleave', function () {
      $(this).css('background-position', '0px 0px');
    });
    $('#ui_menubar').append((div).append(link).append('<div class="menucontainer_bottom" />'));
  };
  GJ.jobsDataToString = function (chosenJobName) {
    chosenJobName = chosenJobName.toLowerCase();
    var str = '';
    var jobs = GameMap.JobHandler.Featured;
    var k,
    jobId,
    job,
    t,
    j;
    for (k in jobs) {
      var jobPlace = jobs[k];
      for (jobId in jobPlace) {
        job = JobList.getJobById(jobId);
        if (chosenJobName !== '' && job.name.toLowerCase().indexOf(chosenJobName) < 0)
          continue;
        j = jobPlace[jobId];
        t = j.gold ? 'gold' : 'silver';
        str += job.name + '; ' + t + '; ' + j.x + '-' + j.y + '; ' + jobId + '\n';
      }
    }
    return str;
  };
  GJ.jobsDataToBbString = function (chosenJobName) {
    chosenJobName = chosenJobName.toLowerCase();
    var str = '';
    var jobs = GameMap.JobHandler.Featured;
    var k,
    jobId,
    job,
    color,
    j,
    l,
    c = [];
    for (k in jobs) {
      var jobPlace = jobs[k];
      for (jobId in jobPlace) {
        job = JobList.getJobById(jobId);
        if (chosenJobName !== '' && job.name.toLowerCase().indexOf(chosenJobName) < 0)
          continue;
        j = jobPlace[jobId];
        color = j.gold ? GJ.goldJobBbColor : GJ.silverJobBbColor;
        c.push('[b][color=' + color + ']' + job.name + '[/color][/b] (' + j.x + ';' + j.y + ')\n');
      }
    }
    c.sort(function (a, b) {
      a = a.replace(new RegExp(GJ.goldJobBbColor, 'g'), '');
      a = a.replace(new RegExp(GJ.silverJobBbColor, 'g'), '');
      b = b.replace(new RegExp(GJ.goldJobBbColor, 'g'), '');
      b = b.replace(new RegExp(GJ.silverJobBbColor, 'g'), '');
      return (a == b) ? 0 : (a > b) ? 1 :  - 1;
    });
    for (l = 0; l < c.length; l++)
      str += c[l];
    return str;
  };
  GJ.showExportWindow = function (jobs, isBb) {
    var textarea = '<textarea style="height: 100px; width: 400px; background-color: transparent; border-width: 0px;" onclick="$(this).trigger(\'select\')">' + jobs + '</textarea>';
    var md = GJ.getMessageDialog(GJlang.exportButtonTitle, '', textarea);
    var jobName = $('#gj_job_search_textfield').val();
    if (isBb) {
      md.addButton(GJlang.goback, function () {
        var jobs = GJ.jobsDataToString(jobName);
        GJ.showExportWindow(jobs, false);
      });
    } else {
      md.addButton(GJlang.bbCode, function () {
        var jobs = GJ.jobsDataToBbString(jobName);
        GJ.showExportWindow(jobs + '[i]' + GJlang.generatedByBb + ' [url=' + GJ.website + ']TW Gold Jobs Finder[/url][/i]', true);
      });
    }
    md.addButton('ok').show();
  };
  GJ.openFeedbackWindow = function () {
    var langBox = new west.gui.Combobox();
    for (var j in GJ.langs)
      langBox.addItem(j, GJ.langs[j].language);
    langBox.select(GJ.lang);
    var saveBtn = new west.gui.Button(GJlang.save, function () {
      localStorage.setItem('scriptsLang', langBox.getValue());
      GJ.updateLang();
      new UserMessage(GJlang.saveMessage, 'success').show();
    });
    var fms = [['de', 'deutsches Forum'], ['net', 'English forum'], ['pl', 'forum polski'], ['es', 'foro español'], ['ru', 'Русский форум'], ['fr', 'forum français'], ['it', 'forum italiano'], ['net', 'beta forum', 'beta.']],
    add = '<b>' + GJlang.contact + ':</b><ul style="margin-left:15px;"><li>Send a message to <a target=\'_blank\' href="//www.the-west.de/?ref=west_invite_linkrl&player_id=647936&world_id=13&hash=7dda">Tom Robert on German world Arizona</a></li>' +
      '<li>Contact me on <a target=\'_blank\' href="' + GJ.website + '">Greasy Fork</a></li>' +
      '<li>Message me on one of these The West Forum:<br>';
    for (var l of fms)
      add += '/ <a target=\'_blank\' href="//forum.the-west.' + l[0] + '/index.php?conversations/add&to=Tom Robert">' + l[1] + '</a> ' + (l[0] == 'es' ? '<br>' : '');
    add += '/<br>I will get an e-mail when you sent me the message <img src="images/chat/emoticons/smile.png"></li></ul>';
    content = $('<div id="feedback_window_div">' + GJlang.chooseLang + ': </div>');
    content.append(langBox.getMainDiv(), saveBtn.getMainDiv(), '<br><br>' + GJlang.ApiGui + '<br><br><i>' + GJ.name + ' v' + GJ.version + '</i><br><br><br>' + GJlang.feedbackDescription + '<br><br>', add);
    win = wman.open('goldenJobsFeedback', 'GoldJobs ' + GJlang.feedbackWindowTitle, 'noreload').setSize(700, 430).setMiniTitle(GJ.name + ' - ' + GJlang.feedbackWindowTitle);
    win.appendToContentPane(content);
  };
  GJ.addNotification = function (title, jobId, jobX, jobY) {
    var n = new OnGoingEntry();
    n.init('', function () {
      GameMap.JobHandler.openJob(jobId, {
        x: jobX,
        y: jobY
      });
    }, 1);
    n.setTooltip('<b>' + title + '</b>', true);
    WestUi.NotiBar.add(n);
    var icon = JobList.getJobById(jobId).shortname;
    $(n.getMainDiv()).find('.image').css({
      'background-image': 'url(images/jobs/' + icon + '.png)',
      'background-position': '-11px -9px'
    });
  };
  GJ.gui = {};
  GJ.gui.init = function () {
    GJ.gui.makeButton = function (caption, callback) {
      return new west.gui.Button(caption, callback);
    };
    GJ.gui.makeTextfield = function (id) {
      return new west.gui.Textfield(id);
    };
    GJ.gui.makeTable = function () {
      return new west.gui.Table();
    };
  };
  (GJ.Updater = function () {
    if (!window.scriptRequest) {
      scriptRequest = true;
      $.getScript(GJ.updateUrl);
    }
    var intVal = setInterval(function () {
      if (window.scriptUp) {
        scriptUp.c('GJ', GJ.version, GJ.name, '', GJ.website, GJ.lang);
        clearInterval(intVal);
      }
    }, 2000);
  })();
  $(document).ready(function () {
    try {
      GJ.gui.init();
      GJ.init();
    } catch (e) {
      console.log(e.stack);
    }
  });
});