WME Bookmarklets

Put bookmarklets in a tab and provide a better code execution environment

当前为 2017-08-16 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        WME Bookmarklets
// @author      Tom 'Glodenox' Puttemans
// @namespace   http://www.tomputtemans.com/
// @description Put bookmarklets in a tab and provide a better code execution environment
// @include     /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/
// @version     1.0.4
// @grant       none
// ==/UserScript==
(function() {
  var bookmarklets = [];
  if (localStorage.WME_Bookmarklets) {
    importBookmarklets(JSON.parse(localStorage.WME_Bookmarklets).bookmarklets);
  }

  function init(e) {
    if (e && e.user == null) {
      return;
    }
    if (document.getElementById('user-info') == null) {
      setTimeout(init, 500);
      log('user-info element not yet available, page still loading');
      return;
    }
    if (typeof Waze.loginManager === 'undefined') {
      setTimeout(init, 300);
      return;
    }
    if (!Waze.loginManager.hasUser()) {
      Waze.loginManager.events.register('login', null, init);
      Waze.loginManager.events.register('loginStatus', null, init);
      // Double check as event might have triggered already
      if (!Waze.loginManager.hasUser()) {
        return;
      }
    }

    // Deal with events mode
    if (Waze.app.modeController) {
      Waze.app.modeController.model.bind('change:mode', function(model, modeId) {
        if (modeId == 0) {
          addTab(tab);
        }
      });
    }

    var om_strings = {
      en: {
        tab_title: 'Bookmarklets',
        add_bookmarklet: 'Add bookmarklet',
        empty_list: 'No bookmarklets added yet',
        bookmarklet_name: 'Name',
        bookmarklet_script: 'Script',
        bookmarklet_error: 'Bookmarklet threw an error',
        message: 'Activate a bookmarklet or add a new one:',
        bookmarklet_sources: 'Many Wazers have created bookmarklets to perform small tasks within the WME. Most of these can be found on <a href="https://wiki.waze.com/wiki/Bookmarklets" target="_blank">the wiki</a> or by <a href="https://www.waze.com/forum/search.php?keywords=Bookmarklet&terms=all&sv=0&sc=1&sf=all&sr=posts&sk=t&sd=d&st=0&ch=300&t=0&submit=Search" target="_blank">seaching the forums</a>.',
        bookmarklet_remove: 'Remove bookmarklet'
      }
    };
    om_strings['en-GB'] = om_strings['en-US'] = om_strings.en;
    for (var i = 0; i < I18n.availableLocales.length; i++) {
      var locale = I18n.availableLocales[i];
      if (I18n.translations[locale]) {
        I18n.translations[locale].bookmarklets = om_strings[locale];
      }
    }

    var tab = addTab();
    var message = document.createElement('p');
    message.appendChild(document.createTextNode(I18n.t('bookmarklets.message')));
    tab.appendChild(message);

    var emptyList = document.createElement('span');
    emptyList.id = 'emptyBookmarklets';
    emptyList.style.fontStyle = 'italic';
    emptyList.style.display = (bookmarklets.length == 0 ? 'block' : 'none');
    emptyList.appendChild(document.createTextNode(I18n.t('bookmarklets.empty_list')));
    tab.appendChild(emptyList);

    var bookmarkletList = document.createElement('div');
    bookmarkletList.className = 'result-list';
    bookmarkletList.style.marginBottom = '1em';
    bookmarklets.forEach(function(bookmarklet) {
      addBookmarklet(bookmarklet);
    });
    tab.appendChild(bookmarkletList);

    var addBookmarkletForm = document.createElement('form');
    var addBookmarkletTitle = document.createElement('h4');
    addBookmarkletTitle.appendChild(document.createTextNode(I18n.t('bookmarklets.add_bookmarklet')));
    addBookmarkletForm.appendChild(addBookmarkletTitle);
    addBookmarkletForm.style.display = 'none';
    var nameGroup = document.createElement('div');
    nameGroup.className = 'form-group';
    var nameFieldLabel = document.createElement('label');
    nameFieldLabel.htmlFor = 'name';
    nameFieldLabel.appendChild(document.createTextNode(I18n.t('bookmarklets.bookmarklet_name')));
    nameGroup.appendChild(nameFieldLabel);
    var nameField = document.createElement('input');
    nameField.type = 'text';
    nameField.autocomplete = 'off';
    nameField.style.width = '100%';
    nameField.name = 'name';
    nameField.className = 'from-control';
    nameGroup.appendChild(nameField);
    addBookmarkletForm.appendChild(nameGroup);
    var scriptGroup = document.createElement('div');
    scriptGroup.className = 'form-group';
    var scriptFieldLabel = document.createElement('label');
    scriptFieldLabel.htmlFor = 'script';
    scriptFieldLabel.appendChild(document.createTextNode(I18n.t('bookmarklets.bookmarklet_script')));
    scriptGroup.appendChild(scriptFieldLabel);
    var scriptField = document.createElement('textarea');
    scriptField.name = 'script';
    scriptField.className = 'from-control';
    scriptField.style.width = '100%';
    scriptField.style.height = 'auto';
    scriptGroup.appendChild(scriptField);
    addBookmarkletForm.appendChild(scriptGroup);
    var createBookmarklet = document.createElement('input');
    createBookmarklet.type = 'submit';
    createBookmarklet.className = 'btn btn-default';
    createBookmarklet.value = I18n.t('bookmarklets.add_bookmarklet');
    addBookmarkletForm.appendChild(createBookmarklet);

    var addBookmarkletButton = document.createElement('button');
    addBookmarkletButton.className = 'btn btn-default';
    var addSpan = document.createElement('span');
    addSpan.appendChild(document.createTextNode(''));
    addSpan.className = 'fa';
    addSpan.style.marginRight = '5px';
    addBookmarkletButton.appendChild(addSpan);
    addBookmarkletButton.appendChild(document.createTextNode(I18n.t('bookmarklets.add_bookmarklet')));
    addBookmarkletButton.addEventListener('click', function() {
      addBookmarkletButton.style.display = 'none';
      addBookmarkletForm.style.display = 'block';
    });
    tab.appendChild(addBookmarkletButton);
    tab.appendChild(addBookmarkletForm);
    addBookmarkletForm.addEventListener('submit', function(e) {
      e.preventDefault();
      addBookmarkletForm.style.display = 'none';
      addBookmarkletButton.style.display = 'block';
      var newBookmarklet = {};
      newBookmarklet.name = nameField.value;
      newBookmarklet.script = scriptField.value;
      addBookmarklet(newBookmarklet);
      bookmarklets.push(newBookmarklet);
      saveBookmarklets();
      return false;
    }, true);

    var bookmarkletSources = document.createElement('p');
    bookmarkletSources.innerHTML = I18n.t('bookmarklets.bookmarklet_sources');
    bookmarkletSources.style.marginTop = '1em';
    tab.appendChild(bookmarkletSources);
    var versionInfo = document.createElement('a');
    versionInfo.appendChild(document.createTextNode(GM_info.script.name + ' (v' + GM_info.script.version + ')'));
    versionInfo.href = 'https://greasyfork.org/nl/scripts/20379-wme-bookmarklets/';
    versionInfo.target = '_blank';
    tab.appendChild(versionInfo);

    // Create a tab and possibly receive a previous tab to restore (usually in case of a mode change)
    function addTab(recoveredTab) {
      var userInfo = document.getElementById('user-info'),
          tabHandles = userInfo.querySelector('.nav-tabs'),
          tabs = userInfo.querySelector('.tab-content'),
          tabHandle = document.createElement('li'),
          tab = document.createElement('div');
      tabHandle.innerHTML = '<a href="#sidepanel-bookmarklets" data-toggle="tab" title="' + I18n.t('bookmarklets.tab_title') + '"><span class="fa"></span></a>';
      if (recoveredTab) {
        tab = recoveredTab;
      } else {
        tab.id = 'sidepanel-bookmarklets';
        tab.className = 'tab-pane';
      }
      tabHandles.appendChild(tabHandle);
      $(tabHandle.childNodes[0]).tooltip();
      tabs.appendChild(tab);
      return tab;
    }

    function addBookmarklet(bookmarklet) {
      document.getElementById('emptyBookmarklets').style.display = 'none';
      var bookmarkletContainer = document.createElement('div');
      bookmarkletContainer.className = 'result session-available';
      var bookmarkletRemove = document.createElement('button');
      bookmarkletRemove.style.position = 'absolute';
      bookmarkletRemove.style.display = 'none';
      bookmarkletRemove.style.fontSize = '14px';
      bookmarkletRemove.style.top = '4px';
      bookmarkletRemove.style.right = '4px'
      bookmarkletRemove.className = 'btn btn-default fa';
      bookmarkletRemove.addEventListener('click', function(e) {
        e.stopPropagation();
        removeBookmarklet(bookmarklet);
      });
      bookmarkletRemove.appendChild(document.createTextNode(''));
      bookmarkletRemove.title = I18n.t('bookmarklets.bookmarklet_remove');
      $(bookmarkletRemove).tooltip();
      bookmarkletContainer.appendChild(bookmarkletRemove);
      bookmarkletContainer.addEventListener('mouseenter', function() {
        bookmarkletRemove.style.display = 'block';
      });
      bookmarkletContainer.addEventListener('mouseleave', function() {
        bookmarkletRemove.style.display = 'none';
      });
      var bookmarkletName = document.createElement('div');
      bookmarkletName.appendChild(document.createTextNode(bookmarklet.name));
      bookmarkletContainer.appendChild(bookmarkletName);
      var bookmarkletError = document.createElement('div');
      bookmarkletError.style.display = 'none';
      bookmarkletError.style.backgroundColor = 'red';
      bookmarkletError.style.color = '#f2dede';
      bookmarkletError.style.border = '2px solid #f2dede';
      bookmarkletError.style.padding = '4px';
      bookmarkletError.style.margin = '4px 0 4px 0';
      bookmarkletContainer.appendChild(bookmarkletError);
      var bookmarkletErrorClose = document.createElement('button');
      bookmarkletErrorClose.style.fontFamily = 'FontAwesome';
      bookmarkletErrorClose.style.color = '#f2dede';
      bookmarkletErrorClose.style.border = 'none';
      bookmarkletErrorClose.style.background = 'none';
      bookmarkletErrorClose.style.padding = '3px';
      bookmarkletErrorClose.style.float = 'right';
      bookmarkletErrorClose.style.cursor = 'pointer';
      bookmarkletErrorClose.style.height = 'auto';
      bookmarkletErrorClose.style.outline = 'none';
      bookmarkletErrorClose.appendChild(document.createTextNode(''));
      bookmarkletError.addEventListener('click', function(e) {
        e.stopPropagation();
        bookmarkletError.style.display = 'none';
      }, true);
      bookmarkletError.appendChild(bookmarkletErrorClose);
      var bookmarkletErrorTitle = document.createElement('strong');
      bookmarkletErrorTitle.appendChild(document.createTextNode(I18n.t('bookmarklets.bookmarklet_error')));
      bookmarkletError.appendChild(bookmarkletErrorTitle);
      bookmarkletError.appendChild(document.createElement('br'));
      bookmarkletContainer.addEventListener('click', function() {
        try {
          var cleanedUpScript = decodeURI(bookmarklet.script);
          cleanedUpScript = cleanedUpScript.replace('javascript:', '');
          eval(cleanedUpScript);
        } catch (e) {
          log(e);
          if (bookmarkletError.childNodes[3]) { // Remove previous error message
            bookmarkletError.removeChild(bookmarkletError.childNodes[3]);
          }
          bookmarkletError.appendChild(document.createTextNode((e && e.message ? e.message : e)));
          bookmarkletError.style.display = 'block';
        }
      });
      bookmarkletList.appendChild(bookmarkletContainer);
      bookmarklet.container = bookmarkletContainer;
    }

    function removeBookmarklet(bookmarklet) {
      var idx = bookmarklets.indexOf(bookmarklet);
      if (idx > -1) {
        bookmarklets.splice(idx, 1);
      }
      saveBookmarklets();
      bookmarkletList.removeChild(bookmarklet.container);
      if (bookmarklets.length == 0) {
        document.getElementById('emptyBookmarklets').style.display = 'block';
      }
    }
  }

  function importBookmarklets(data) {
    data.forEach(function(bookmarklet) {
      bookmarklets.push(bookmarklet);
    });
  }

  function saveBookmarklets() {
    var storage;
    if (typeof localStorage.WME_Bookmarklets == 'undefined') {
      storage = {};
    } else {
      storage = JSON.parse(localStorage.WME_Bookmarklets);
    }
    storage.bookmarklets = bookmarklets.map(function(bookmarklet) {
      return {
        'name': bookmarklet.name,
        'script': bookmarklet.script
      };
    });
    localStorage.WME_Bookmarklets = JSON.stringify(storage);
  }

  function log(message) {
    if (typeof message === 'string') {
      console.log('%c' + GM_info.script.name + ' (v' + GM_info.script.version + '): %c' + message, 'color:black', 'color:#d97e00');
    } else {
      console.log('%c' + GM_info.script.name + ' (v' + GM_info.script.version + ')', 'color:black', message);
    }
  }

  init();
})();