<commit_before>/**
 * background.js
 */
"use strict";
{
  /* api */
  const {contextMenus, extension, i18n, pageAction, runtime, tabs} = browser;

  /* constants */
  const CLIP_ELEMENT = "clipboard";
  const CLIP_TEXT = "clipboardText";
  const EXT_NAME = "extensionName";
  const ICON = "img/icon.svg";
  const KEY = "Alt + Shift + C";
  const LINK_HTML = "htmlAnchor";
  const LINK_MD = "markdownLink";
  const LINK_TEXT = "textLink";
  const MENU_ITEM_ID = "menuItemId";
  const MENU_POPUP = "html/popup.html";
  const TYPE_FROM = 8;
  const TYPE_TO = -1;
  const USER_INPUT_GET = "userInputGet";
  const USER_INPUT_RES = "userInputRes";

  /**
   * log error
   * @param {!Object} e - Error
   * @returns {boolean} - false
   */
  const logError = e => {
    console.error(e);
    return false;
  };

  /**
   * log warn
   * @param {*} msg - message
   * @returns {boolean} - false
   */
  const logWarn = msg => {
    msg && console.warn(msg);
    return false;
  };

  /**
   * get type
   * @param {*} o - object to check
   * @returns {string} - type of object
   */
  const getType = o =>
    Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);

  /**
   * is string
   * @param {*} o - object to check
   * @returns {boolean} - result
   */
  const isString = o => typeof o === "string" || o instanceof String;

  /**
   * stringify positive integer
   * @param {number} i - integer
   * @param {boolean} zero - treat 0 as a positive integer
   * @returns {?string} - stringified integer
   */
  const stringifyPositiveInt = (i, zero = false) =>
    Number.isSafeInteger(i) && (zero && i >= 0 || i > 0) && `${i}` || null;

  /**
   * is tabId
   * @param {*} tabId - tabId
   * @returns {boolean} - result
   */
  const isTabId = tabId =>
    Number.isInteger(tabId) && tabId !== tabs.TAB_ID_NONE;

  // NOTE: not working yet. issue #1
  /**
   * copy to clipboard
   * @param {string} text - text to copy
   * @returns {void} - Promise.<void>
   */
  const copyToClipboard = async text => {
    const elm = document.getElementById(CLIP_ELEMENT);
    if (elm) {
      if (isString(text)) {
        const range = document.createRange();
        const sel = window.getSelection();
        elm.textContent = text;
        range.selectNodeContents(elm);
        sel.removeAllRanges();
        sel.addRange(range);
        document.execCommand("copy");
        sel.removeAllRanges();
      } else {
        logWarn(`url2clipboard: Expected String but got ${getType(text)}.`);
      }
    } else {
      logWarn(`url2clipboard: Element#${CLIP_ELEMENT} not found.`);
    }
  };

  /**
   * send text to copy
   * @param {number} tabId - tab ID
   * @param {string} text - text to clip
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const sendText = async (tabId, text) => {
    let func;
    if (isTabId(tabId) && isString(text)) {
      const msg = {
        [CLIP_TEXT]: text,
      };
      func = tabs.sendMessage(tabId, msg);
    }
    return func || null;
  };

  /**
   * send user input request
   * @param {number} tabId - tab ID
   * @param {Object} data - input data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const requestInput = async (tabId, data) => {
    let func;
    if (isTabId(tabId)) {
      const msg = {
        [USER_INPUT_GET]: data,
      };
      func = tabs.sendMessage(tabId, msg);
    }
    return func || null;
  };

  /**
   * create HTML Anchor
   * @param {string} content - content title
   * @param {string} title - document title
   * @param {string} url - document URL
   * @returns {?string} - HTML Anchor
   */
  const createHtml = async (content, title, url) =>
    isString(content) && isString(title) && isString(url) &&
    `<a href="${url}" title="${title}">${content.trim()}</a>` || null;

  /**
   * create Markdown Link
   * @param {string} content - content title
   * @param {string} title - document title
   * @param {string} url - document URL
   * @returns {?string} - Markdown Link
   */
  const createMarkdown = async (content, title, url) =>
    isString(content) && isString(title) && isString(url) &&
    `[${content.trim()}](${url} "${title}")` || null;

  /**
   * create Text Link
   * @param {string} content - content title
   * @param {string} url - document URL
   * @returns {?string} - Text Link
   */
  const createText = async (content, url) =>
    isString(content) && isString(url) && `${content.trim()} <${url}>` || null;

  /**
   * extract data
   * @param {Object} data - tab data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const extractData = async (data = {}) => {
    const {info, tab} = data;
    let func;
    if (info && tab) {
      const {id: tabId, title, url} = tab;
      if (isTabId(tabId)) {
        const {menuItemId, selectionText} = info;
        const content = selectionText || title;
        let text;
        switch (menuItemId) {
          case LINK_HTML:
            text = await createHtml(content, title, url);
            text && (func = sendText(tabId, text));
            break;
          case LINK_MD:
            text = await createMarkdown(content, title, url);
            text && (func = sendText(tabId, text));
            break;
          case LINK_TEXT:
            text = await createText(content, url);
            text && (func = sendText(tabId, text));
            break;
          case `${LINK_HTML}.input`:
          case `${LINK_MD}.input`:
          case `${LINK_TEXT}.input`:
            func = requestInput(tabId, {
              content, menuItemId, tabId, title, url,
            });
            break;
          default:
        }
      }
    }
    return func || null;
  };

  /**
   * extract user input data
   * @param {Object} data - tab data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const extractInput = async (data = {}) => {
    const {content, menuItemId, tabId, title, url} = data;
    let func;
    if (isTabId(tabId)) {
      let text;
      switch (menuItemId) {
        case `${LINK_HTML}.input`:
          text = await createHtml(content, title, url);
          text && (func = sendText(tabId, text));
          break;
        case `${LINK_MD}.input`:
          text = await createMarkdown(content, title, url);
          text && (func = sendText(tabId, text));
          break;
        case `${LINK_TEXT}.input`:
          text = await createText(content, url);
          text && (func = sendText(tabId, text));
          break;
        default:
      }
    }
    return func || null;
  };

  /* enabled tabs collection */
  const enabledTabs = {};

  /**
   * set enabled tab
   * @param {number} tabId - tab ID
   * @param {boolean} enabled - enabled
   * @returns {void} - Promise.<void>
   */
  const setEnabledTab = async (tabId, enabled = false) => {
    if (isTabId(tabId)) {
      tabId = stringifyPositiveInt(tabId);
      tabId && (enabledTabs[tabId] = !!enabled);
    }
  };

  /**
   * remove enabled tab
   * @param {number} tabId - tab ID
   * @returns {boolean} - result
   */
  const removeEnabledTab = async tabId => {
    let bool;
    tabId = stringifyPositiveInt(tabId);
    if (tabId && enabledTabs[tabId]) {
      bool = delete enabledTabs[tabId];
    }
    return bool || false;
  };

  /**
   * get active tab
   * @returns {Object} - tabs.Tab
   */
  const getActiveTab = async () => {
    const arr = await tabs.query({active: true});
    let tab;
    if (arr.length) {
      [tab] = arr;
    }
    return tab || null;
  };

  /**
   * create data
   * @param {Object} menuItemId - menuItemId
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const createData = async menuItemId => {
    const info = isString(menuItemId) && {menuItemId};
    const tab = await getActiveTab();
    return info && tab && extractData({info, tab}) || null;
  };

  /* context menu */
  const menus = [LINK_HTML, LINK_MD, LINK_TEXT];

  /**
   * create context menu item
   * @param {string} id - menu item ID
   * @param {Array} contexts - contexts
   * @param {boolean} enabled - enabled
   * @returns {void} - Promise.<void>
   */
  const createMenuItem = async (id, contexts, enabled = false) => {
    isString(id) && Array.isArray(contexts) &&
      contextMenus.create({
        id, contexts,
        enabled: !!enabled,
        title: i18n.getMessage(id),
      });
  };

  /**
   * create context menu items
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const createMenuItems = async enabled => {
    const func = [];
    for (const item of menus) {
      func.push(
        createMenuItem(item, ["all"], enabled),
        createMenuItem(`${item}.input`, ["all"], enabled)
      );
    }
    return Promise.all(func);
  };

  /**
   * update context menu
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const updateContextMenu = async (enabled = false) => {
    const func = [];
    for (const item of menus) {
      func.push(
        contextMenus.update(item, {enabled}),
        contextMenus.update(`${item}.input`, {enabled})
      );
    }
    return Promise.all(func);
  };

  /**
   * show icon
   * @param {number} tabId - tab ID
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const showIcon = async (tabId, enabled = false) => {
    const func = [];
    if (isTabId(tabId)) {
      if (enabled) {
        const name = await i18n.getMessage(EXT_NAME);
        const icon = await extension.getURL(ICON);
        const path = `${icon}#neutral`;
        const popup = await extension.getURL(MENU_POPUP);
        const title = `${name} (${KEY})`;
        func.push(
          pageAction.setIcon({path, tabId}),
          pageAction.setPopup({popup, tabId}),
          pageAction.setTitle({tabId, title}),
          pageAction.show(tabId)
        );
      } else {
        func.push(pageAction.hide(tabId));
      }
    }
    return Promise.all(func);
  };

  /**
   * handle message
   * @param {*} msg - message
   * @param {Object} sender - sender
   * @returns {Object} - Promise.<Array>
   */
  const handleMsg = async (msg, sender = {}) => {
    const func = [];
    const items = msg && Object.keys(msg);
    const tabId = sender && sender.tab && sender.tab.id;
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case "contextmenu":
            func.push(updateContextMenu(obj));
            break;
          case "load":
            func.push(
              setEnabledTab(tabId, obj),
              showIcon(tabId, obj),
              updateContextMenu(obj)
            );
            break;
          case MENU_ITEM_ID:
            func.push(createData(obj));
            break;
          case USER_INPUT_RES:
            func.push(extractInput(obj));
            break;
          default:
        }
      }
    }
    return Promise.all(func);
  };

  /**
   * handle active tab
   * @param {Object} info - active tab info
   * @returns {Object} - Promise.<Array>
   */
  const handleActiveTab = async (info = {}) => {
    const {tabId} = info;
    const func = [];
    if (isTabId(tabId)) {
      const enabledTab = await stringifyPositiveInt(tabId);
      const enabled = enabledTab && enabledTabs[enabledTab] || false;
      func.push(updateContextMenu(enabled), showIcon(tabId, enabled));
    }
    return Promise.all(func);
  };

  /**
   * handle updated tab
   * @param {number} tabId - tab ID
   * @param {Object} tab - tab.Tab
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const handleUpdatedTab = async (tabId, tab = {}) => {
    const {active} = tab;
    const func = active && handleActiveTab({tabId});
    return func || null;
  };

  /* listeners */
  contextMenus.onClicked.addListener((info, tab) =>
    extractData({info, tab}).catch(logError)
  );
  runtime.onMessage.addListener((msg, sender) =>
    handleMsg(msg, sender).catch(logError)
  );
  tabs.onActivated.addListener(info =>
    handleActiveTab(info).catch(logError)
  );
  tabs.onRemoved.addListener(tabId =>
    removeEnabledTab(tabId).catch(logError)
  );
  tabs.onUpdated.addListener((tabId, info, tab) =>
    handleUpdatedTab(tabId, tab).catch(logError)
  );

  /* startup */
  createMenuItems().catch(logError);
}
<commit_msg>Add isTab() function<commit_after>/**
 * background.js
 */
"use strict";
{
  /* api */
  const {contextMenus, extension, i18n, pageAction, runtime, tabs} = browser;

  /* constants */
  const CLIP_ELEMENT = "clipboard";
  const CLIP_TEXT = "clipboardText";
  const EXT_NAME = "extensionName";
  const ICON = "img/icon.svg";
  const KEY = "Alt+Shift+C";
  const LINK_HTML = "htmlAnchor";
  const LINK_MD = "markdownLink";
  const LINK_TEXT = "textLink";
  const MENU_ITEM_ID = "menuItemId";
  const MENU_POPUP = "html/popup.html";
  const TYPE_FROM = 8;
  const TYPE_TO = -1;
  const USER_INPUT_GET = "userInputGet";
  const USER_INPUT_RES = "userInputRes";

  /**
   * log error
   * @param {!Object} e - Error
   * @returns {boolean} - false
   */
  const logError = e => {
    console.error(e);
    return false;
  };

  /**
   * log warn
   * @param {*} msg - message
   * @returns {boolean} - false
   */
  const logWarn = msg => {
    msg && console.warn(msg);
    return false;
  };

  /**
   * get type
   * @param {*} o - object to check
   * @returns {string} - type of object
   */
  const getType = o =>
    Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);

  /**
   * is string
   * @param {*} o - object to check
   * @returns {boolean} - result
   */
  const isString = o => typeof o === "string" || o instanceof String;

  /**
   * stringify positive integer
   * @param {number} i - integer
   * @param {boolean} zero - treat 0 as a positive integer
   * @returns {?string} - stringified integer
   */
  const stringifyPositiveInt = (i, zero = false) =>
    Number.isSafeInteger(i) && (zero && i >= 0 || i > 0) && `${i}` || null;

  /**
   * is tab
   * @param {*} tabId - tab ID
   * @returns {boolean} - result
   */
  const isTab = async tabId => {
    let tab;
    if (Number.isInteger(tabId) && tabId !== tabs.TAB_ID_NONE) {
      try {
        tab = await tabs.get(tabId);
      } catch (e) {
        tab = false;
      }
    }
    return !!tab;
  };

  // NOTE: not working yet. issue #1
  /**
   * copy to clipboard
   * @param {string} text - text to copy
   * @returns {void} - Promise.<void>
   */
  const copyToClipboard = async text => {
    const elm = document.getElementById(CLIP_ELEMENT);
    if (elm) {
      if (isString(text)) {
        const range = document.createRange();
        const sel = window.getSelection();
        elm.textContent = text;
        range.selectNodeContents(elm);
        sel.removeAllRanges();
        sel.addRange(range);
        document.execCommand("copy");
        sel.removeAllRanges();
      } else {
        logWarn(`url2clipboard: Expected String but got ${getType(text)}.`);
      }
    } else {
      logWarn(`url2clipboard: Element#${CLIP_ELEMENT} not found.`);
    }
  };

  /**
   * send text to copy
   * @param {number} tabId - tab ID
   * @param {string} text - text to clip
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const sendText = async (tabId, tab, text) => {
    let func;
    if ((tab || await isTab(tabId)) && isString(text)) {
      const msg = {
        [CLIP_TEXT]: text,
      };
      func = tabs.sendMessage(tabId, msg);
    }
    return func || null;
  };

  /**
   * send user input request
   * @param {number} tabId - tab ID
   * @param {Object} data - input data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const requestInput = async (tabId, tab, data) => {
    let func;
    if (tab || await isTab(tabId)) {
      const msg = {
        [USER_INPUT_GET]: data,
      };
      func = tabs.sendMessage(tabId, msg);
    }
    return func || null;
  };

  /**
   * create HTML Anchor
   * @param {string} content - content title
   * @param {string} title - document title
   * @param {string} url - document URL
   * @returns {?string} - HTML Anchor
   */
  const createHtml = async (content, title, url) =>
    isString(content) && isString(title) && isString(url) &&
    `<a href="${url}" title="${title}">${content.trim()}</a>` || null;

  /**
   * create Markdown Link
   * @param {string} content - content title
   * @param {string} title - document title
   * @param {string} url - document URL
   * @returns {?string} - Markdown Link
   */
  const createMarkdown = async (content, title, url) =>
    isString(content) && isString(title) && isString(url) &&
    `[${content.trim()}](${url} "${title}")` || null;

  /**
   * create Text Link
   * @param {string} content - content title
   * @param {string} url - document URL
   * @returns {?string} - Text Link
   */
  const createText = async (content, url) =>
    isString(content) && isString(url) && `${content.trim()} <${url}>` || null;

  /**
   * extract data
   * @param {Object} data - tab data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const extractData = async (data = {}) => {
    const {info, tab} = data;
    let func;
    if (info && tab) {
      const {id: tabId, title, url} = tab;
      if (Number.isInteger(tabId) && tabId !== tabs.TAB_ID_NONE) {
        const {menuItemId, selectionText} = info;
        const content = selectionText || title;
        let text;
        switch (menuItemId) {
          case LINK_HTML:
            text = await createHtml(content, title, url);
            text && (func = sendText(tabId, tab, text));
            break;
          case LINK_MD:
            text = await createMarkdown(content, title, url);
            text && (func = sendText(tabId, tab, text));
            break;
          case LINK_TEXT:
            text = await createText(content, url);
            text && (func = sendText(tabId, tab, text));
            break;
          case `${LINK_HTML}.input`:
          case `${LINK_MD}.input`:
          case `${LINK_TEXT}.input`:
            func = requestInput(tabId, tab, {
              content, menuItemId, tabId, title, url,
            });
            break;
          default:
        }
      }
    }
    return func || null;
  };

  /**
   * extract user input data
   * @param {Object} data - tab data
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const extractInput = async (data = {}) => {
    const {content, menuItemId, tabId, title, url} = data;
    const tab = await isTab(tabId);
    let func;
    if (tab) {
      let text;
      switch (menuItemId) {
        case `${LINK_HTML}.input`:
          text = await createHtml(content, title, url);
          text && (func = sendText(tabId, tab, text));
          break;
        case `${LINK_MD}.input`:
          text = await createMarkdown(content, title, url);
          text && (func = sendText(tabId, tab, text));
          break;
        case `${LINK_TEXT}.input`:
          text = await createText(content, url);
          text && (func = sendText(tabId, tab, text));
          break;
        default:
      }
    }
    return func || null;
  };

  /* enabled tabs collection */
  const enabledTabs = {};

  /**
   * set enabled tab
   * @param {number} tabId - tab ID
   * @param {boolean} enabled - enabled
   * @returns {void} - Promise.<void>
   */
  const setEnabledTab = async (tabId, tab, enabled = false) => {
    if (tab || await isTab(tabId)) {
      tabId = stringifyPositiveInt(tabId);
      tabId && (enabledTabs[tabId] = !!enabled);
    }
  };

  /**
   * remove enabled tab
   * @param {number} tabId - tab ID
   * @returns {boolean} - result
   */
  const removeEnabledTab = async tabId => {
    let bool;
    tabId = stringifyPositiveInt(tabId);
    if (tabId && enabledTabs[tabId]) {
      bool = delete enabledTabs[tabId];
    }
    return bool || false;
  };

  /**
   * get active tab
   * @returns {Object} - tabs.Tab
   */
  const getActiveTab = async () => {
    const arr = await tabs.query({active: true});
    let tab;
    if (arr.length) {
      [tab] = arr;
    }
    return tab || null;
  };

  /**
   * create data
   * @param {Object} menuItemId - menuItemId
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const createData = async menuItemId => {
    const info = isString(menuItemId) && {menuItemId};
    const tab = await getActiveTab();
    return info && tab && extractData({info, tab}) || null;
  };

  /* context menu */
  const menus = [LINK_HTML, LINK_MD, LINK_TEXT];

  /**
   * create context menu item
   * @param {string} id - menu item ID
   * @param {Array} contexts - contexts
   * @param {boolean} enabled - enabled
   * @returns {void} - Promise.<void>
   */
  const createMenuItem = async (id, contexts, enabled = false) => {
    isString(id) && Array.isArray(contexts) &&
      contextMenus.create({
        id, contexts,
        enabled: !!enabled,
        title: i18n.getMessage(id),
      });
  };

  /**
   * create context menu items
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const createMenuItems = async enabled => {
    const func = [];
    for (const item of menus) {
      func.push(
        createMenuItem(item, ["all"], enabled),
        createMenuItem(`${item}.input`, ["all"], enabled)
      );
    }
    return Promise.all(func);
  };

  /**
   * update context menu
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const updateContextMenu = async (enabled = false) => {
    const func = [];
    for (const item of menus) {
      func.push(
        contextMenus.update(item, {enabled}),
        contextMenus.update(`${item}.input`, {enabled})
      );
    }
    return Promise.all(func);
  };

  /**
   * show icon
   * @param {number} tabId - tab ID
   * @param {boolean} enabled - enabled
   * @returns {Object} - Promise.<Array>
   */
  const showIcon = async (tabId, tab, enabled = false) => {
    const func = [];
    if (tab || await isTab(tabId)) {
      if (enabled) {
        const name = await i18n.getMessage(EXT_NAME);
        const icon = await extension.getURL(ICON);
        const path = `${icon}#neutral`;
        const popup = await extension.getURL(MENU_POPUP);
        const title = `${name} (${KEY})`;
        func.push(
          pageAction.setIcon({path, tabId}),
          pageAction.setPopup({popup, tabId}),
          pageAction.setTitle({tabId, title}),
          pageAction.show(tabId)
        );
      } else {
        func.push(pageAction.hide(tabId));
      }
    }
    return Promise.all(func);
  };

  /**
   * handle message
   * @param {*} msg - message
   * @param {Object} sender - sender
   * @returns {Object} - Promise.<Array>
   */
  const handleMsg = async (msg, sender = {}) => {
    const func = [];
    const items = msg && Object.keys(msg);
    const tab = sender && sender.tab;
    const tabId = tab && tab.id;
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case "contextmenu":
            func.push(updateContextMenu(obj));
            break;
          case "load":
            func.push(
              setEnabledTab(tabId, tab, obj),
              showIcon(tabId, tab, obj),
              updateContextMenu(obj)
            );
            break;
          case MENU_ITEM_ID:
            func.push(createData(obj));
            break;
          case USER_INPUT_RES:
            func.push(extractInput(obj));
            break;
          default:
        }
      }
    }
    return Promise.all(func);
  };

  /**
   * handle active tab
   * @param {Object} info - active tab info
   * @returns {Object} - Promise.<Array>
   */
  const handleActiveTab = async (info = {}, tab = null) => {
    const {tabId} = info;
    const func = [];
    if (tab || await isTab(tabId)) {
      const enabledTab = await stringifyPositiveInt(tabId);
      const enabled = enabledTab && enabledTabs[enabledTab] || false;
      func.push(
        updateContextMenu(enabled),
        showIcon(tabId, tab, enabled)
      );
    }
    return Promise.all(func);
  };

  /**
   * handle updated tab
   * @param {number} tabId - tab ID
   * @param {Object} tab - tab.Tab
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const handleUpdatedTab = async (tabId, tab = {}) => {
    const {active} = tab;
    const func = active && handleActiveTab({tabId}, tab);
    return func || null;
  };

  /* listeners */
  contextMenus.onClicked.addListener((info, tab) =>
    extractData({info, tab}).catch(logError)
  );
  runtime.onMessage.addListener((msg, sender) =>
    handleMsg(msg, sender).catch(logError)
  );
  tabs.onActivated.addListener(info =>
    handleActiveTab(info).catch(logError)
  );
  tabs.onRemoved.addListener(tabId =>
    removeEnabledTab(tabId).catch(logError)
  );
  tabs.onUpdated.addListener((tabId, info, tab) =>
    handleUpdatedTab(tabId, tab).catch(logError)
  );

  /* startup */
  createMenuItems().catch(logError);
}
<|endoftext|>


<commit_before>/** ========================================================================
 * Mower: base.mower.js - v1.0.0
 *
 *  base script to handle utility methodes
 *
 * Copyright 2011-2014 Infinitus, Inc
 * Licensed under Apache Licence 2.0 (https://github.com/macula-projects/mower/blob/master/LICENSE)
 * ======================================================================== */

;
var Base = (function($, window, document, undefined) {

    'use strict';

    var base = {};

    // private functions & variables

    var _parseComposite = function(key, value, t, pre, pkey) {
        var opts     = {};
        var attrName = 'data-' + pre + (pkey ? (pkey.toLowerCase() + '-') : "") + key.toLowerCase();

        if (value === 'string') { //字符串直接从宿主对象对应属性中取值
            opts[key] = t.attr(attrName);
        } else if (value === 'boolean') { //布尔型从宿主对象对应属性中取值，同时将属性值转为布尔型
            opts[key] = t.attr(attrName) ? (t.attr(attrName) == 'true') : undefined;
        } else if (value === 'number') { //数字型也从宿主对象对应属性中取值，同时将属性值转为浮数
            opts[key] = t.attr(attrName) == '0' ? 0 : parseFloat(t.attr(attrName)) || undefined;
        } else if (value === 'array') { //数组型也从宿主对象对应属性中取值，同时将属性值转为数组
            var value = t.attr(attrName);
            if (value) {
                //嵌套数组 数值形式:'1,2,3;4,5,6'
                if (value.indexOf(';') >= 0) {
                    var nestedArray = new Array();
                    $.each(value.split(';'), function(index, value) {
                        if (value !== undefined && value.length > 0) {
                            nestedArray.push(value.split(','));
                        }
                    });
                    opts[key] = nestedArray;
                } else {
                    opts[key] = value.split(',');
                }
            } else {
                opts[key] = undefined;
            }
        }

        return opts;
    }

    // public functions

    /**
     * parse options, including standard 'data-options' attribute.
     *
     * @param target [DOM对象] 组件的宿主对象
     * @param tPrefix [DOM对象] 组件的宿主对象前缀
     * @param properties [数组] 需要优先从宿主对象属性(不包含data-options属性)中取的opts列表
     *
     * calling examples:
     * Base.parseOptions(target);
     * Base.parseOptions(target, ['id','title','width',{fit:'boolean',border:'boolean'},{min:'number'},{orderSeq:'array'}]);
     * Base.parseOptions(target, [{ajax:{url:'string',method:'string'}}]);
     */
    base.parseOptions = function(target, tPrefix, properties) {
        var t = $(target);
        var pre = (tPrefix ? (tPrefix.toLowerCase() + '-') : ('mu' + '-'));

        var options = {};
        //第一步：首先从data-options属性中取opts
        var s = $.trim(t.attr('data-options'));
        if (s) {
            //兼容写大括号和不写大括号的写法
            if (s.substring(0, 1) != '{') {
                s = '{' + s + '}';
            }
            //利用Function函数将字符串转为化对象
            options = (new Function('return ' + s))();
        }
        //第二步：如果properties不为空的话，则将properties中定义的属性增加或者覆盖到“第一步”中取到的属性列表中
        if (properties) {
            var opts = {};
            for (var i = 0; i < properties.length; i++) {
                var pp = properties[i];
                //如果是字符串型
                if (typeof pp == 'string') {
                    //width height left top四个属性从宿主对象的style属性中取值
                    if (pp === 'width' || pp === 'height' || pp === 'left' || pp === 'top') {
                        opts[pp] = parseInt(target.style[pp]) || undefined;
                    } else { //其它情况直接从宿主对象的对应属性中取值
                        opts[pp] = t.attr('data-' + pre + pp.toLowerCase());
                    }
                } else { //布尔型或者数字型或者数组[]或者对象'{}'
                    for (var pkey in pp) {
                        var pvalue = pp[pkey];

                        if (typeof pvalue == 'string') { //字符串型(布尔型或者数字型或者数组)
                            $.extend(opts, _parseComposite(pkey, pvalue, t, pre));
                        } else { //对象
                            var nestedOpts = {};
                            for (var ckey in pvalue) {
                                var cvalue = pvalue[ckey];
                                $.extend(nestedOpts, _parseComposite(ckey, cvalue, t, pre, pkey));
                            }

                            opts[pkey] = nestedOpts;
                        }
                    }
                }
            }
            //第二步取得的结果覆盖到第一步取得的结果中
            $.extend(options, opts);
        }
        return options;
    };

    return base;

}(jQuery, window, document));
<commit_msg>add dom remove event.<commit_after>/** ========================================================================
 * Mower: base.mower.js - v1.0.0
 *
 *  base script to handle utility methodes
 *
 * Copyright 2011-2014 Infinitus, Inc
 * Licensed under Apache Licence 2.0 (https://github.com/macula-projects/mower/blob/master/LICENSE)
 * ======================================================================== */

;
var Base = (function($, window, document, undefined) {

    'use strict';

    var base = {};

    // private functions & variables

    var _parseComposite = function(key, value, t, pre, pkey) {
        var opts     = {};
        var attrName = 'data-' + pre + (pkey ? (pkey.toLowerCase() + '-') : "") + key.toLowerCase();

        if (value === 'string') { //字符串直接从宿主对象对应属性中取值
            opts[key] = t.attr(attrName);
        } else if (value === 'boolean') { //布尔型从宿主对象对应属性中取值，同时将属性值转为布尔型
            opts[key] = t.attr(attrName) ? (t.attr(attrName) == 'true') : undefined;
        } else if (value === 'number') { //数字型也从宿主对象对应属性中取值，同时将属性值转为浮数
            opts[key] = t.attr(attrName) == '0' ? 0 : parseFloat(t.attr(attrName)) || undefined;
        } else if (value === 'array') { //数组型也从宿主对象对应属性中取值，同时将属性值转为数组
            var value = t.attr(attrName);
            if (value) {
                //嵌套数组 数值形式:'1,2,3;4,5,6'
                if (value.indexOf(';') >= 0) {
                    var nestedArray = new Array();
                    $.each(value.split(';'), function(index, value) {
                        if (value !== undefined && value.length > 0) {
                            nestedArray.push(value.split(','));
                        }
                    });
                    opts[key] = nestedArray;
                } else {
                    opts[key] = value.split(',');
                }
            } else {
                opts[key] = undefined;
            }
        }

        return opts;
    };

    var _attachDomRemoveEvent = function() {
        var _cleanData = $.cleanData;
        $.cleanData = function(elems) {
            for (var i = 0, elem;
                (elem = elems[i]) != null; i++) {
                try {
                    $(elem).triggerHandler("remove");
                } catch (e) {}
            }
            _cleanData(elems);
        };
    };

    // public functions
    base.init = function() {
        _attachDomRemoveEvent();
    };

    /**
     * parse options, including standard 'data-options' attribute.
     *
     * @param target [DOM对象] 组件的宿主对象
     * @param tPrefix [DOM对象] 组件的宿主对象前缀
     * @param properties [数组] 需要优先从宿主对象属性(不包含data-options属性)中取的opts列表
     *
     * calling examples:
     * Base.parseOptions(target);
     * Base.parseOptions(target, ['id','title','width',{fit:'boolean',border:'boolean'},{min:'number'},{orderSeq:'array'}]);
     * Base.parseOptions(target, [{ajax:{url:'string',method:'string'}}]);
     */
    base.parseOptions = function(target, tPrefix, properties) {
        var t = $(target);
        var pre = (tPrefix ? (tPrefix.toLowerCase() + '-') : ('mu' + '-'));

        var options = {};
        //第一步：首先从data-options属性中取opts
        var s = $.trim(t.attr('data-options'));
        if (s) {
            //兼容写大括号和不写大括号的写法
            if (s.substring(0, 1) != '{') {
                s = '{' + s + '}';
            }
            //利用Function函数将字符串转为化对象
            options = (new Function('return ' + s))();
        }
        //第二步：如果properties不为空的话，则将properties中定义的属性增加或者覆盖到“第一步”中取到的属性列表中
        if (properties) {
            var opts = {};
            for (var i = 0; i < properties.length; i++) {
                var pp = properties[i];
                //如果是字符串型
                if (typeof pp == 'string') {
                    //width height left top四个属性从宿主对象的style属性中取值
                    if (pp === 'width' || pp === 'height' || pp === 'left' || pp === 'top') {
                        opts[pp] = parseInt(target.style[pp]) || undefined;
                    } else { //其它情况直接从宿主对象的对应属性中取值
                        opts[pp] = t.attr('data-' + pre + pp.toLowerCase());
                    }
                } else { //布尔型或者数字型或者数组[]或者对象'{}'
                    for (var pkey in pp) {
                        var pvalue = pp[pkey];

                        if (typeof pvalue == 'string') { //字符串型(布尔型或者数字型或者数组)
                            $.extend(opts, _parseComposite(pkey, pvalue, t, pre));
                        } else { //对象
                            var nestedOpts = {};
                            for (var ckey in pvalue) {
                                var cvalue = pvalue[ckey];
                                $.extend(nestedOpts, _parseComposite(ckey, cvalue, t, pre, pkey));
                            }

                            opts[pkey] = nestedOpts;
                        }
                    }
                }
            }
            //第二步取得的结果覆盖到第一步取得的结果中
            $.extend(options, opts);
        }
        return options;
    };

    return base;

}(jQuery, window, document));

$(function(){
    Base.init();
});
<|endoftext|>


<commit_before>var HttpClient = function () {
    this.get = function (url, callback, protocol, cipherString) {
        var httpRequest = new XMLHttpRequest();
        httpRequest.onreadystatechange = function () {
            if (httpRequest.readyState === 4 && httpRequest.status === 200) {
                callback(httpRequest.responseText, protocol, cipherString);
            }
        };
        httpRequest.open("GET", url, true);
        httpRequest.send(null);
    };
};

function initFilters() {

    var protocol = document.getElementById("filterProtocol").value;
    var keyExAndAuth = document.getElementById("filterKeyExAndAuth").value;
    var bulkCipher = document.getElementById("filterCipher").value;
    var keyLen = document.getElementById("filterKeyLen").value;
    var msgAuth = document.getElementById("filterMsgAuth").value;

    if (protocol === "" && keyExAndAuth === "" && bulkCipher === "" && keyLen === ""
            && msgAuth === "") {
        document.getElementById("keyExAuth").innerHTML = getKeyAndAuth("all");
        document.getElementById("cipher").innerHTML = getCiphers("all");
        document.getElementById("keyLen").innerHTML = getKeyLengths("all", "all");
        document.getElementById("msgAuth").innerHTML = getMsgAuth("all");
        document.getElementById("displayFilterSelection").innerHTML = "[none]";
    }

}

function manageFilterSelection() {

    var cipherSelection = document.getElementById("filterCipher").value;
    var protocolSelection = document.getElementById("filterProtocol").value;

    document.getElementById("keyExAuth").innerHTML = getKeyAndAuth(protocolSelection);
    document.getElementById("cipher").innerHTML = getCiphers(protocolSelection);
    document.getElementById("keyLen").innerHTML = getKeyLengths(protocolSelection, cipherSelection);
    document.getElementById("msgAuth").innerHTML = getMsgAuth(protocolSelection);

    displayFilter();

}

function displayFilter() {

    var keyExAndAuth = document.getElementById("filterKeyExAndAuth").value;
    var bulkCipher = document.getElementById("filterCipher").value;
    var keyLen = document.getElementById("filterKeyLen").value;
    var msgAuth = document.getElementById("filterMsgAuth").value;

    if (keyExAndAuth !== "" || bulkCipher !== "" || keyLen !== "" || msgAuth !== "") {
        if (keyExAndAuth !== "") {
            keyExAndAuth += "-";
        }
        if (keyLen === "" && bulkCipher !== "") {
            bulkCipher += "-";
        } else if (keyLen !== "" && (bulkCipher === "AES-CBC" || bulkCipher === "AES-CCM" || bulkCipher === "AES-GCM")) {
            var left = bulkCipher.split("-")[0];
            var right = bulkCipher.split("-")[1];
            bulkCipher = left;
            keyLen += "-" + right + "-";
        } else if (keyLen !== "") {
            keyLen += "-";
        }

        document.getElementById("displayFilterSelection").innerHTML =
                [keyExAndAuth, bulkCipher, keyLen, msgAuth].join("");
    }
}

function resetFilters() {

    document.getElementById("keyExAuth").innerHTML = getKeyAndAuth("all");
    document.getElementById("cipher").innerHTML = getCiphers("all");
    document.getElementById("keyLen").innerHTML = getKeyLengths("all");
    document.getElementById("msgAuth").innerHTML = getMsgAuth("all");

    document.getElementById("displayFilterSelection").innerHTML = "[none]";
}

function applyFilters() {

    var url = "http://tls.thejetlag.de:1337/api/v0/ciphers/summary";
    var tldSelection = document.getElementById("filterTLD").value;

    if (tldSelection !== "") {
        tldSelection = tldSelection.replace('.', '');
        url += "?tld=" + tldSelection;
    }

    var protocol = document.getElementById("filterProtocol").value;
    var cipherString = document.getElementById("displayFilterSelection").innerHTML;
    var httpClient = new HttpClient();
    httpClient.get(url, parseResponse, protocol, cipherString);

}

function parseResponse(response, protocol, cipherString) {

    var totalHosts = "";
    var matchingHosts = "";
    response.split("month").forEach(function (monthlyScan) {
        //Nooooo, StackOverFlow is down...
    });

}

function getKeyAndAuth(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"EXP\"></option>\n\
                <option value=\"RSA\"></option>";
    } else if (protocolSelection === "SSLv3") {
        return "<option value=\"EXP\"></option>\n\
                      <option value=\"RSA\"></option>\n\
                      <option value=\"DH-DSS\"></option>\n\
                      <option value=\"DH-RSA\"></option>\n\
                      <option value=\"DHE-DSS\"></option>\n\
                      <option value=\"DHE-RSA\"></option>\n\
                      <option value=\"DH-anon\"></option>\n\
                      <option value=\"DH-anon-EXP\"></option>\n\
                      <option value=\"ECDHE-RSA\"></option>";
    } else if (protocolSelection === "TLSv1.0" || protocolSelection === "TLSv1.1"
            || protocolSelection === "TLSv1.2") {
        return "<option value=\"AECDH\"></option>\n\
                    <option value=\"RSA\"></option>\n\
                     <option value=\"DH-RSA\"></option>\n\
                     <option value=\"DHE-RSA\"></option>\n\
                     <option value=\"ECDH-RSA\"></option>\n\
                     <option value=\"ECDHE-RSA\"></option>\n\
                     <option value=\"EDH-RSA\"></option>\n\
                     <option value=\"DH-DSS\"></option>\n\
                     <option value=\"DHE-DSS\"></option>\n\
                     <option value=\"ECDH-ECDSA\"></option>\n\
                     <option value=\"ECDHE-ECDSA\"></option>\n\
                     <option value=\"PSK\"></option>\n\
                     <option value=\"PSK-RSA\"></option>\n\
                     <option value=\"DHE-PSK\"></option>\n\
                     <option value=\"ECDHE-PSK\"></option>\n\
                     <option value=\"SRP\"></option>\n\
                     <option value=\"SRP-DSS\"></option>\n\
                     <option value=\"SRP-RSA\"></option>\n\
                     <option value=\"KERBEROS\"></option>\n\
                     <option value=\"DH-ANON\"></option>\n\
                     <option value=\"ECDH-ANON\"></option>\n\
                     <option value=\"GOST\"></option>";
    } else {
        return "<option value=\"AECDH\"></option>\n\
                     <option value=\"RSA\"></option>\n\
                     <option value=\"DH-RSA\"></option>\n\
                     <option value=\"DHE-RSA\"></option>\n\
                     <option value=\"ECDH-RSA\"></option>\n\
                     <option value=\"ECDHE-RSA\"></option>\n\
                     <option value=\"EDH-RSA\"></option>\n\
                     <option value=\"DH-DSS\"></option>\n\
                     <option value=\"DHE-DSS\"></option>\n\
                     <option value=\"ECDH-ECDSA\"></option>\n\
                     <option value=\"ECDHE-ECDSA\"></option>\n\
                     <option value=\"PSK\"></option>\n\
                     <option value=\"PSK-RSA\"></option>\n\
                     <option value=\"DHE-PSK\"></option>\n\
                     <option value=\"ECDHE-PSK\"></option>\n\
                     <option value=\"SRP\"></option>\n\
                     <option value=\"SRP-DSS\"></option>\n\
                     <option value=\"SRP-RSA\"></option>\n\
                     <option value=\"KERBEROS\"></option>\n\
                     <option value=\"DH-ANON\"></option>\n\
                     <option value=\"ECDH-ANON\"></option>\n\
                     <option value=\"GOST\"></option>";
    }
}

function getCiphers(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"DES-CBC3\"></option>\n\
                        <option value=\"IDEA-CBC\"></option>\n\
                        <option value=\"DES-CBC\"></option>\n\
                        <option value=\"RC2-CBC\"></option>\n\
                        <option value=\"RC4\"></option>";
    } else if (protocolSelection === "SSLv3") {
        return "<option value=\"AES\"></option>\n\
                        <option value=\"DES-CBC3\"></option>\n\
                        <option value=\"IDEA-CBC\"></option>\n\
                        <option value=\"DES-CBC\"></option>\n\
                        <option value=\"RC2-CBC\"></option>\n\
                        <option value=\"RC4\"></option>\n\
                        <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.0") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-CBC\">\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC2-CBC\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.1") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-CBC\">\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.2") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-GCM\"></option>\n\
                                <option value=\"AES-CCM\"></option>\n\
                                <option value=\"AES-CBC\"></option>\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-GCM\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-GCM\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"ChaCha-20-POLY1305\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-GCM\"></option>\n\
                                <option value=\"AES-CCM\"></option>\n\
                                <option value=\"AES-CBC\"></option>\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-GCM\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-GCM\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC2-CBC\"></option>\n\
                                <option value=\"ChaCha-20-POLY1305\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    }
}

function getKeyLengths(protocolSelection, cipherSelection) {

    if (cipherSelection === "AES" || cipherSelection === "AES-GCM" || cipherSelection === "AES-CCM"
            || cipherSelection === "AES-CBC" || cipherSelection === "CAMELLIA"
            || cipherSelection === "CAMELLIA-GCM" || cipherSelection === "CAMELLIA-CBC"
            || cipherSelection === "ARIA-GCM" || cipherSelection === "ARIA-CBC") {
        return "<option value=\"128\">\n\
                <option value=\"256\">";
    } else if (cipherSelection === "SEED-CBC" || cipherSelection === "IDEA-CBC") {
        return "<option value=\"128\">";
    } else if (cipherSelection === "DES-CBC3") {
        return "<option value=\"112\">";
    } else if (cipherSelection === "GOST-28147-89-CNT") {
        return "<option value=\"256\">";
    } else if (cipherSelection === "DES-CBC") {
        if (protocolSelection === "TLS 1.1") {
            return "<option value=\"56\">";
        } else {
            return "<option value=\"40\">\n\
                <option value=\"56\">";
        }
    } else if (cipherSelection === "RC2-CBC") {
        return "<option value=\"40\">";
    } else if (cipherSelection === "ChaCha-20-POLY1305") {
        return "<option value=\"256\">";
    } else if (cipherSelection === "RC4") {
        if (protocolSelection === "TLSv1.1" || protocolSelection === "TLSv1.2") {
            return "<option value=\"128\">";
        } else {
            return "option value=\"40\">\n\
                    option value=\"128\">";
        }
    } else {
        return "<option value=\"40\">\n\
                <option value=\"56\">\n\
                <option value=\"112\">\n\
                <option value=\"128\">\n\
                <option value=\"256\">";
    }

}

function getMsgAuth(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"MD5\">";
    } else if (protocolSelection === "SSLv3" || protocolSelection === "TLSv1.0"
            || protocolSelection === "TLSv1.1") {
        return "<option value=\"MD5\">\n\
                <option value=\"SHA\">\n\
                <option value=\"SHA1\">\n\
                <option value=\"GOST-28147-89-IMIT\">\n\
                <option value=\"GOST-R34.11-94\">";
    } else {
        return "<option value=\"MD5\">\n\
                <option value=\"SHA\">\n\
                <option value=\"SHA1\">\n\
                <option value=\"SHA256\">\n\
                <option value=\"SHA384\">\n\
                <option value=\"AEAD\">\n\
                <option value=\"GOST-28147-89-IMIT\">\n\
                <option value=\"GOST-R34.11-94\">";
    }

}<commit_msg>Get simple parsing function to work, but displaying the results is not included yet.<commit_after>var HttpClient = function () {
    this.get = function (url, callback, protocol, cipherString) {
        var httpRequest = new XMLHttpRequest();
        httpRequest.onreadystatechange = function () {
            if (httpRequest.readyState === 4 && httpRequest.status === 200) {
                callback(httpRequest.responseText, protocol, cipherString);
            }
        };
        httpRequest.open("GET", url, true);
        httpRequest.send(null);
    };
};

function initFilters() {

    var protocol = document.getElementById("filterProtocol").value;
    var keyExAndAuth = document.getElementById("filterKeyExAndAuth").value;
    var bulkCipher = document.getElementById("filterCipher").value;
    var keyLen = document.getElementById("filterKeyLen").value;
    var msgAuth = document.getElementById("filterMsgAuth").value;

    if (protocol === "" && keyExAndAuth === "" && bulkCipher === "" && keyLen === ""
            && msgAuth === "") {
        document.getElementById("keyExAuth").innerHTML = getKeyAndAuth("all");
        document.getElementById("cipher").innerHTML = getCiphers("all");
        document.getElementById("keyLen").innerHTML = getKeyLengths("all", "all");
        document.getElementById("msgAuth").innerHTML = getMsgAuth("all");
        document.getElementById("displayFilterSelection").innerHTML = "[none]";
    }

}

function manageFilterSelection() {

    var cipherSelection = document.getElementById("filterCipher").value;
    var protocolSelection = document.getElementById("filterProtocol").value;

    document.getElementById("keyExAuth").innerHTML = getKeyAndAuth(protocolSelection);
    document.getElementById("cipher").innerHTML = getCiphers(protocolSelection);
    document.getElementById("keyLen").innerHTML = getKeyLengths(protocolSelection, cipherSelection);
    document.getElementById("msgAuth").innerHTML = getMsgAuth(protocolSelection);

    displayFilter();

}

function displayFilter() {

    var keyExAndAuth = document.getElementById("filterKeyExAndAuth").value;
    var bulkCipher = document.getElementById("filterCipher").value;
    var keyLen = document.getElementById("filterKeyLen").value;
    var msgAuth = document.getElementById("filterMsgAuth").value;

    if (keyExAndAuth !== "" || bulkCipher !== "" || keyLen !== "" || msgAuth !== "") {
        if (keyExAndAuth !== "") {
            keyExAndAuth += "-";
        }
        if (keyLen === "" && bulkCipher !== "") {
            bulkCipher += "-";
        } else if (keyLen !== "" && (bulkCipher === "AES-CBC" || bulkCipher === "AES-CCM" || bulkCipher === "AES-GCM")) {
            var left = bulkCipher.split("-")[0];
            var right = bulkCipher.split("-")[1];
            bulkCipher = left;
            keyLen += "-" + right + "-";
        } else if (keyLen !== "") {
            keyLen += "-";
        }

        document.getElementById("displayFilterSelection").innerHTML =
                [keyExAndAuth, bulkCipher, keyLen, msgAuth].join("");
    }
}

function resetFilters() {

    document.getElementById("keyExAuth").innerHTML = getKeyAndAuth("all");
    document.getElementById("cipher").innerHTML = getCiphers("all");
    document.getElementById("keyLen").innerHTML = getKeyLengths("all");
    document.getElementById("msgAuth").innerHTML = getMsgAuth("all");

    document.getElementById("displayFilterSelection").innerHTML = "[none]";
}

function applyFilters() {

    var url = "http://tls.thejetlag.de:1337/api/v0/ciphers/summary";
    var tldSelection = document.getElementById("filterTLD").value;

    if (tldSelection !== "") {
        tldSelection = tldSelection.replace('.', '');
        url += "?tld=" + tldSelection;
    }

    var protocol = document.getElementById("filterProtocol").value;
    var cipherString = document.getElementById("displayFilterSelection").innerHTML;
    var httpClient = new HttpClient();
    httpClient.get(url, parseResponse, protocol, cipherString);

}

function parseResponse(response, protocol, cipherString) {

    var months = [];
    var totalHosts = [];
    var monthBody = [];
    var hostsAccepting = [];
    var hostsPreferring = [];

    console.log("Hello!");
    cipherString = "\"cipher\":\"" + cipherString + "\",";
    console.log("Cipher string: " + cipherString);

    response.match(/month.:.(\d*).(\d*)/g).forEach(function (month) {
        months.push(month.split(":")[1].replace('"', ''));
    });

    response.match(/totalHosts.:.(\d*)/g).forEach(function (number) {
        totalHosts.push(number.split(":")[1]);
    });

    monthBody = response.match(/\[[^\[\]]*\]/g);
    monthBody.forEach(function (outer) {
        outer.match(/{(.*?)}/g).forEach(function (inner) {
            var count = 0;
            if (inner.match(protocol) !== null && inner.match(cipherString) !== null) {
                var count = ("" + inner.match(/.count.:(\d*)/g) + "").split(":")[1];
                if (inner.indexOf("preferred") > -1) {
                    hostsPreferring.push(count);
                } else {
                    hostsAccepting.push(count);
                }
            }
        });

    });

}

function getKeyAndAuth(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"EXP\"></option>\n\
                <option value=\"RSA\"></option>";
    } else if (protocolSelection === "SSLv3") {
        return "<option value=\"EXP\"></option>\n\
                      <option value=\"RSA\"></option>\n\
                      <option value=\"DH-DSS\"></option>\n\
                      <option value=\"DH-RSA\"></option>\n\
                      <option value=\"DHE-DSS\"></option>\n\
                      <option value=\"DHE-RSA\"></option>\n\
                      <option value=\"DH-anon\"></option>\n\
                      <option value=\"DH-anon-EXP\"></option>\n\
                      <option value=\"ECDHE-RSA\"></option>";
    } else if (protocolSelection === "TLSv1.0" || protocolSelection === "TLSv1.1"
            || protocolSelection === "TLSv1.2") {
        return "<option value=\"AECDH\"></option>\n\
                    <option value=\"RSA\"></option>\n\
                     <option value=\"DH-RSA\"></option>\n\
                     <option value=\"DHE-RSA\"></option>\n\
                     <option value=\"ECDH-RSA\"></option>\n\
                     <option value=\"ECDHE-RSA\"></option>\n\
                     <option value=\"EDH-RSA\"></option>\n\
                     <option value=\"DH-DSS\"></option>\n\
                     <option value=\"DHE-DSS\"></option>\n\
                     <option value=\"ECDH-ECDSA\"></option>\n\
                     <option value=\"ECDHE-ECDSA\"></option>\n\
                     <option value=\"PSK\"></option>\n\
                     <option value=\"PSK-RSA\"></option>\n\
                     <option value=\"DHE-PSK\"></option>\n\
                     <option value=\"ECDHE-PSK\"></option>\n\
                     <option value=\"SRP\"></option>\n\
                     <option value=\"SRP-DSS\"></option>\n\
                     <option value=\"SRP-RSA\"></option>\n\
                     <option value=\"KERBEROS\"></option>\n\
                     <option value=\"DH-ANON\"></option>\n\
                     <option value=\"ECDH-ANON\"></option>\n\
                     <option value=\"GOST\"></option>";
    } else {
        return "<option value=\"AECDH\"></option>\n\
                     <option value=\"RSA\"></option>\n\
                     <option value=\"DH-RSA\"></option>\n\
                     <option value=\"DHE-RSA\"></option>\n\
                     <option value=\"ECDH-RSA\"></option>\n\
                     <option value=\"ECDHE-RSA\"></option>\n\
                     <option value=\"EDH-RSA\"></option>\n\
                     <option value=\"DH-DSS\"></option>\n\
                     <option value=\"DHE-DSS\"></option>\n\
                     <option value=\"ECDH-ECDSA\"></option>\n\
                     <option value=\"ECDHE-ECDSA\"></option>\n\
                     <option value=\"PSK\"></option>\n\
                     <option value=\"PSK-RSA\"></option>\n\
                     <option value=\"DHE-PSK\"></option>\n\
                     <option value=\"ECDHE-PSK\"></option>\n\
                     <option value=\"SRP\"></option>\n\
                     <option value=\"SRP-DSS\"></option>\n\
                     <option value=\"SRP-RSA\"></option>\n\
                     <option value=\"KERBEROS\"></option>\n\
                     <option value=\"DH-ANON\"></option>\n\
                     <option value=\"ECDH-ANON\"></option>\n\
                     <option value=\"GOST\"></option>";
    }
}

function getCiphers(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"DES-CBC3\"></option>\n\
                        <option value=\"IDEA-CBC\"></option>\n\
                        <option value=\"DES-CBC\"></option>\n\
                        <option value=\"RC2-CBC\"></option>\n\
                        <option value=\"RC4\"></option>";
    } else if (protocolSelection === "SSLv3") {
        return "<option value=\"AES\"></option>\n\
                        <option value=\"DES-CBC3\"></option>\n\
                        <option value=\"IDEA-CBC\"></option>\n\
                        <option value=\"DES-CBC\"></option>\n\
                        <option value=\"RC2-CBC\"></option>\n\
                        <option value=\"RC4\"></option>\n\
                        <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.0") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-CBC\">\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC2-CBC\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.1") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-CBC\">\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else if (protocolSelection === "TLSv1.2") {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-GCM\"></option>\n\
                                <option value=\"AES-CCM\"></option>\n\
                                <option value=\"AES-CBC\"></option>\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-GCM\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-GCM\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"ChaCha-20-POLY1305\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    } else {
        return "<option value=\"AES\"></option>\n\
                                <option value=\"AES-GCM\"></option>\n\
                                <option value=\"AES-CCM\"></option>\n\
                                <option value=\"AES-CBC\"></option>\n\
                                <option value=\"CAMELLIA\"></option>\n\
                                <option value=\"CAMELLIA-GCM\"></option>\n\
                                <option value=\"CAMELLIA-CBC\"></option>\n\
                                <option value=\"ARIA-GCM\"></option>\n\
                                <option value=\"ARIA-CBC\"></option>\n\
                                <option value=\"SEED-CBC\"></option>\n\
                                <option value=\"DES-CBC3\"></option>\n\
                                <option value=\"GOST-28147-89-CNT\"></option>\n\
                                <option value=\"IDEA-CBC\"></option>\n\
                                <option value=\"DES-CBC\"></option>\n\
                                <option value=\"RC2-CBC\"></option>\n\
                                <option value=\"ChaCha-20-POLY1305\"></option>\n\
                                <option value=\"RC4\"></option>\n\
                                <option value=\"none\"></option>";
    }
}

function getKeyLengths(protocolSelection, cipherSelection) {

    if (cipherSelection === "AES" || cipherSelection === "AES-GCM" || cipherSelection === "AES-CCM"
            || cipherSelection === "AES-CBC" || cipherSelection === "CAMELLIA"
            || cipherSelection === "CAMELLIA-GCM" || cipherSelection === "CAMELLIA-CBC"
            || cipherSelection === "ARIA-GCM" || cipherSelection === "ARIA-CBC") {
        return "<option value=\"128\">\n\
                <option value=\"256\">";
    } else if (cipherSelection === "SEED-CBC" || cipherSelection === "IDEA-CBC") {
        return "<option value=\"128\">";
    } else if (cipherSelection === "DES-CBC3") {
        return "<option value=\"112\">";
    } else if (cipherSelection === "GOST-28147-89-CNT") {
        return "<option value=\"256\">";
    } else if (cipherSelection === "DES-CBC") {
        if (protocolSelection === "TLS 1.1") {
            return "<option value=\"56\">";
        } else {
            return "<option value=\"40\">\n\
                <option value=\"56\">";
        }
    } else if (cipherSelection === "RC2-CBC") {
        return "<option value=\"40\">";
    } else if (cipherSelection === "ChaCha-20-POLY1305") {
        return "<option value=\"256\">";
    } else if (cipherSelection === "RC4") {
        if (protocolSelection === "TLSv1.1" || protocolSelection === "TLSv1.2") {
            return "<option value=\"128\">";
        } else {
            return "option value=\"40\">\n\
                    option value=\"128\">";
        }
    } else {
        return "<option value=\"40\">\n\
                <option value=\"56\">\n\
                <option value=\"112\">\n\
                <option value=\"128\">\n\
                <option value=\"256\">";
    }

}

function getMsgAuth(protocolSelection) {

    if (protocolSelection === "SSLv2") {
        return "<option value=\"MD5\">";
    } else if (protocolSelection === "SSLv3" || protocolSelection === "TLSv1.0"
            || protocolSelection === "TLSv1.1") {
        return "<option value=\"MD5\">\n\
                <option value=\"SHA\">\n\
                <option value=\"SHA1\">\n\
                <option value=\"GOST-28147-89-IMIT\">\n\
                <option value=\"GOST-R34.11-94\">";
    } else {
        return "<option value=\"MD5\">\n\
                <option value=\"SHA\">\n\
                <option value=\"SHA1\">\n\
                <option value=\"SHA256\">\n\
                <option value=\"SHA384\">\n\
                <option value=\"AEAD\">\n\
                <option value=\"GOST-28147-89-IMIT\">\n\
                <option value=\"GOST-R34.11-94\">";
    }

}<|endoftext|>


<commit_before>/**
 * Content Script
 * @author: Karthik VJ
 */

var pathName = window.location.pathname;
var template_main = '
YouTube to XBMC: $play_all $sep $play_now
';
var template_playnow = 'Play Now | [+] Add to Queue';
var template_playnow_sidebar = 'Play Now | [+] Add to Queue';
var template_playall = 'Play All';
var template_playall_sidebar = 'Play All';
var timer;

console.log("pathName, " + pathName);

var RpcService = function()
{
    this.playVideoOnXBMC = function(vId)
    {
        chrome.extension.sendMessage({message: "playVideo", videoId: vId}, function(response) {
            console.log("video sent!");
        });
    };

    this.queueVideoToXBMC = function(vId)
    {
        chrome.extension.sendMessage({message: "queueVideo", videoId: vId}, function(response) {
            console.log("inject script >> video sent! " + response);
            if(response == ResultData.OK)
            {
                toastr.success("Added to Queue!");
            }
            else
            {
                toastr.error("Error! Can't Add to Queue!");
            }
        });
    };
    this.playListOnXBMC = function(listId, videoId)
    {
        chrome.extension.sendMessage({message: "playList", listId: listId, videoId: videoId}, function(response) {
            console.log("list sent!");
        });
    };
};

var Utils = new function()
{
    this.findPropertyFromString = function(str, property)
    {
        //console.log("findPropertyFromString, str = " + str);
        //console.log("findPropertyFromString, property = " + property);
        property = property + "=";
        var index = str.indexOf('?');
        str = str.substring(index + 1);
        //console.log("index = " + index);
        //console.log("str = " + str);

        var list = str.split('&');
        //console.log("list.length, " + list.length);
        for(var i = 0; i < list.length; i++)
        {
            if(list[i].search(property) == 0)
            {
                return list[i].replace(property, "");
            }
        }
        return 0;
    }
};

this.injectLinks = function()
{
	console.log("injectLinks");
	// (home / subscription on home page), search page, video manager, user page, user browse video, Popular on YouTube, Popular on youtube right side, video list (on video page), play list page
	$(".feed-item-content, .yt-lockup2-content, .vm-video-info-container, .yt-tile-visible, .channels-content-item, .lohp-category-shelf-item, .lohp-large-shelf-container, .lohp-medium-shelf-content, .lohp-vertical-shelf-item-content, .video-list-item, .playlist-video-item, .yt-lockup-content").each(function(index)
	{
		var alreadyAdded = false;
		$(this).find(".xbmc_control").each(function(xIndex)
		{
			alreadyAdded = true;
			return false;

		});

		if(alreadyAdded)
		{
			return; // continue
		}

		console.log(index);
		var videoPathString;
		var listId;
		var videoId;
		// (home / subscription on home page), search page, video manager, (user page / user browse video / Popular on YouTube)
		$(this).find(".feed-video-title, .yt-uix-tile-link, .vm-video-title-content, .yt-uix-sessionlink").each(function(vIndex)
		{
			//console.log("video link, " + vIndex + ", " + $(this).attr("href"));
			videoPathString = $(this).attr("href");
			return false;
		});

		if(videoPathString)
		{
			console.log("videoPathString, " + videoPathString);
			var mainTemplate = template_main;

			// just a single video
			videoId = Utils.findPropertyFromString(videoPathString, "v");
			if(videoId == 0)
			{
				videoId = Utils.findPropertyFromString(videoPathString, "video_id");
			}

			var copyTemp = template_playnow;
			var playStr;
			var queueStr;
			if(videoId != 0)
			{
				console.log("videoId, "  +videoId);
				if($(this).hasClass("video-list-item") || $(this).hasClass("playlist-video-item"))
				{
					copyTemp = template_playnow_sidebar;
				}
				copyTemp = copyTemp.replace("$pid", videoId);
				copyTemp = copyTemp.replace("$qid", videoId);

				mainTemplate = mainTemplate.replace("$play_now", copyTemp);
				//mainTemplate = mainTemplate.replace("$sep", "|");
				//$(this).prepend(copyTemp);

				playStr = "play_" + videoId.toString();
				queueStr = "queue_" + videoId.toString();
			}
			else
			{
				//mainTemplate = mainTemplate.replace("$sep", "");
				mainTemplate = mainTemplate.replace("$play_now", "");
			}

			// find play list id
			listId = Utils.findPropertyFromString(videoPathString, "list");
			var listTemp = template_playall;
			var listStr;
			if(listId)
			{
				if($(this).hasClass("video-list-item") || $(this).hasClass("playlist-video-item"))
				{
					listTemp = template_playall_sidebar;
				}
				// it is play list
				if(videoId != 0)
				{
					// there is video too
					listId = listId + " " + videoId;
					mainTemplate = mainTemplate.replace("$sep", "|");
				}
				else
				{
					// just play list
					mainTemplate = mainTemplate.replace("$sep", "");
				}
				listTemp = listTemp.replace("$lid", listId);

				mainTemplate = mainTemplate.replace("$play_all", listTemp);
				//$(this).prepend(copyTemp);

				listStr = "list_" + listId.toString();
			}
			else
			{
				mainTemplate = mainTemplate.replace("$sep", "");
				mainTemplate = mainTemplate.replace("$play_all", "");
			}

			//////
			if(listId != 0 || videoId !=0)
			{
				$(this).prepend(mainTemplate);
			}

			listId = 0;
			videoId = 0;

		}

	});

	$("#content").bind('DOMNodeInserted', function(event)
	{
		console.log("DOM updated!");
		var element = event.target;
		console.log("element, " + element.tagName);

		clearInterval(timer);
		timer = setInterval(function(){
			clearInterval(timer);
			$("#content").unbind('DOMNodeInserted');
			injectLinks();
		}, 2000)
	});

};

this.initListeners = function()
{
	// click event listeners
	$(document).on('click', '.xbmc_playlist', function(event)
	{
		console.log("playlist, " + $(this).attr("rel"));
		var listId = $(this).attr("rel");

		if(listId)
		{
			var listData = listId.split(" ");

			//console.log(listData[0]);
			//console.log(listData[1]);
			rpc.playListOnXBMC(listData[0], listData[1]);
			event.preventDefault();
		}

	});

	$(document).on('click', '.xbmc_playNow', function(event)
	{
		console.log("play single video, " + $(this).attr("rel"));
		rpc.playVideoOnXBMC($(this).attr("rel"));
		event.preventDefault();

	});

	$(document).on('click', '.xbmc_queue', function(event)
	{
		console.log("queue single video, " + $(this).attr("rel"));
		rpc.queueVideoToXBMC($(this).attr("rel"));
		event.preventDefault();
	});
}

/////////////////////////////

var rpc = new RpcService();
this.initListeners();

////////////////////////////
if(pathName == "/watch")
{
	console.log("window.location, " + window.location);
	var loc = window.location.toString();
	var mainVideoId = Utils.findPropertyFromString(loc, "v");
	//alert("mainVideoId, " + mainVideoId);
	var mainTemplate = template_main;
	if(mainVideoId != 0)
	{
		var copyTemp = template_playnow.replace("$pid", mainVideoId);
		copyTemp = copyTemp.replace("$qid", mainVideoId);

		mainTemplate = mainTemplate.replace("$play_now", copyTemp);

	}
	else
	{
		mainTemplate = mainTemplate.replace("$play_now", "");
	}

	var listId = Utils.findPropertyFromString(loc, "list");
	if(listId != 0)
	{
		if(mainVideoId != 0)
		{
			listId = listId + " " + mainVideoId;
		}
		copyTemp = template_playall.replace("$lid", listId);
		mainTemplate = mainTemplate.replace("$play_all", copyTemp);
		mainTemplate = mainTemplate.replace("$sep", "|");
	}
	else
	{
		mainTemplate = mainTemplate.replace("$sep", "");
		mainTemplate = mainTemplate.replace("$play_all", "");
	}

	if(listId != 0 || videoId !=0)
	{
		$("#watch7-headline").prepend(mainTemplate);
	}

	injectLinks();

}
else if(pathName.indexOf("/embed") == 0)
{
	var videoId = pathName.replace("/embed/", "");
	console.log("videoId, " + videoId);

	var copyTemp = template_playnow_sidebar.replace("$pid", videoId);
	copyTemp = copyTemp.replace("$qid", videoId);

	var mainTemplate = template_main;
	mainTemplate = mainTemplate.replace("$play_all", "");
	mainTemplate = mainTemplate.replace("$sep", "");
	mainTemplate = mainTemplate.replace("$play_now", copyTemp);

	$(".player-actions-container").prepend(mainTemplate);

}
else if(pathName == "/share_popup")
{
    var loc = window.location.toString();
    var mainVideoId = Utils.findPropertyFromString(loc, "v");

    var mainTemplate = template_main;
    if(mainVideoId != 0)
    {
        var copyTemp = template_playnow.replace("$pid", mainVideoId);
        copyTemp = copyTemp.replace("$qid", mainVideoId);
        mainTemplate = mainTemplate.replace("$play_now", copyTemp);

        mainTemplate = mainTemplate.replace("$sep", "");
        mainTemplate = mainTemplate.replace("$play_all", "");

        $("#page").prepend(mainTemplate);
    }

}
else
{
	injectLinks();
}

<commit_msg>refactor<commit_after>/**
 * Content Script
 * @author: Karthik VJ
 */

var pathName = window.location.pathname;
var template_main = '
YouTube to XBMC: $play_all $sep $play_now
';
var template_playnow = 'Play Now | [+] Add to Queue';
var template_playnow_sidebar = 'Play Now | [+] Add to Queue';
var template_playall = 'Play All';
var template_playall_sidebar = 'Play All';
var timer;

console.log("pathName, " + pathName);

var RpcService = function()
{
    this.playVideoOnXBMC = function(vId)
    {
        chrome.extension.sendMessage({message: "playVideo", videoId: vId}, function(response) {
            console.log("video sent! " + response);
        });
    };

    this.queueVideoToXBMC = function(vId)
    {
        chrome.extension.sendMessage({message: "queueVideo", videoId: vId}, function(response) {
            console.log("inject script >> video sent! " + response);
            if(response == ResultData.OK)
            {
                toastr.success("Added to Queue!");
            }
            else
            {
                toastr.error("Error! Can't Add to Queue!");
            }
        });
    };
    this.playListOnXBMC = function(listId, videoId)
    {
        chrome.extension.sendMessage({message: "playList", listId: listId, videoId: videoId}, function(response) {
            console.log("list sent! " + response);
        });
    };
};

var Utils = new function()
{
    this.findPropertyFromString = function(str, property)
    {
        //console.log("findPropertyFromString, str = " + str);
        //console.log("findPropertyFromString, property = " + property);
        property = property + "=";
        var index = str.indexOf('?');
        str = str.substring(index + 1);
        //console.log("index = " + index);
        //console.log("str = " + str);

        var list = str.split('&');
        //console.log("list.length, " + list.length);
        for(var i = 0; i < list.length; i++)
        {
            if(list[i].search(property) == 0)
            {
                return list[i].replace(property, "");
            }
        }
        return 0;
    }
};

this.injectLinks = function()
{
	console.log("injectLinks");
	// (home / subscription on home page), search page, video manager, user page, user browse video, Popular on YouTube, Popular on youtube right side, video list (on video page), play list page
	$(".feed-item-content, .yt-lockup2-content, .vm-video-info-container, .yt-tile-visible, .channels-content-item, .lohp-category-shelf-item, .lohp-large-shelf-container, .lohp-medium-shelf-content, .lohp-vertical-shelf-item-content, .video-list-item, .playlist-video-item, .yt-lockup-content").each(function(index)
	{
		var alreadyAdded = false;
		$(this).find(".xbmc_control").each(function(xIndex)
		{
			alreadyAdded = true;
			return false;

		});

		if(alreadyAdded)
		{
			return; // continue
		}

		console.log(index);
		var videoPathString;
		var listId;
		var videoId;
		// (home / subscription on home page), search page, video manager, (user page / user browse video / Popular on YouTube)
		$(this).find(".feed-video-title, .yt-uix-tile-link, .vm-video-title-content, .yt-uix-sessionlink").each(function(vIndex)
		{
			//console.log("video link, " + vIndex + ", " + $(this).attr("href"));
			videoPathString = $(this).attr("href");
			return false;
		});

		if(videoPathString)
		{
			console.log("videoPathString, " + videoPathString);
			var mainTemplate = template_main;

			// just a single video
			videoId = Utils.findPropertyFromString(videoPathString, "v");
			if(videoId == 0)
			{
				videoId = Utils.findPropertyFromString(videoPathString, "video_id");
			}

			var copyTemp = template_playnow;
			if(videoId != 0)
			{
				console.log("videoId, "  +videoId);
				if($(this).hasClass("video-list-item") || $(this).hasClass("playlist-video-item"))
				{
					copyTemp = template_playnow_sidebar;
				}
				copyTemp = copyTemp.replace("$pid", videoId);
				copyTemp = copyTemp.replace("$qid", videoId);

				mainTemplate = mainTemplate.replace("$play_now", copyTemp);
				//mainTemplate = mainTemplate.replace("$sep", "|");
				//$(this).prepend(copyTemp);
			}
			else
			{
				//mainTemplate = mainTemplate.replace("$sep", "");
				mainTemplate = mainTemplate.replace("$play_now", "");
			}

			// find play list id
			listId = Utils.findPropertyFromString(videoPathString, "list");
			var listTemp = template_playall;
			if(listId)
			{
				if($(this).hasClass("video-list-item") || $(this).hasClass("playlist-video-item"))
				{
					listTemp = template_playall_sidebar;
				}
				// it is play list
				if(videoId != 0)
				{
					// there is video too
					listId = listId + " " + videoId;
					mainTemplate = mainTemplate.replace("$sep", "|");
				}
				else
				{
					// just play list
					mainTemplate = mainTemplate.replace("$sep", "");
				}
				listTemp = listTemp.replace("$lid", listId);

				mainTemplate = mainTemplate.replace("$play_all", listTemp);
				//$(this).prepend(copyTemp);

			}
			else
			{
				mainTemplate = mainTemplate.replace("$sep", "");
				mainTemplate = mainTemplate.replace("$play_all", "");
			}

			//////
			if(listId != 0 || videoId !=0)
			{
				$(this).prepend(mainTemplate);
			}

			listId = 0;
			videoId = 0;

		}

	});

	$("#content").bind('DOMNodeInserted', function(event)
	{
		console.log("DOM updated!");
		var element = event.target;
		console.log("element, " + element.tagName);

		clearInterval(timer);
		timer = setInterval(function(){
			clearInterval(timer);
			$("#content").unbind('DOMNodeInserted');
			injectLinks();
		}, 2000)
	});

};

this.initListeners = function()
{
	// click event listeners
	$(document).on('click', '.xbmc_playlist', function(event)
	{
		console.log("playlist, " + $(this).attr("rel"));
		var listId = $(this).attr("rel");

		if(listId)
		{
			var listData = listId.split(" ");

			//console.log(listData[0]);
			//console.log(listData[1]);
			rpc.playListOnXBMC(listData[0], listData[1]);
			event.preventDefault();
		}

	});

	$(document).on('click', '.xbmc_playNow', function(event)
	{
		console.log("play single video, " + $(this).attr("rel"));
		rpc.playVideoOnXBMC($(this).attr("rel"));
		event.preventDefault();

	});

	$(document).on('click', '.xbmc_queue', function(event)
	{
		console.log("queue single video, " + $(this).attr("rel"));
		rpc.queueVideoToXBMC($(this).attr("rel"));
		event.preventDefault();
	});
}

/////////////////////////////

var rpc = new RpcService();
this.initListeners();

////////////////////////////
if(pathName == "/watch")
{
	console.log("window.location, " + window.location);
	var loc = window.location.toString();
	var mainVideoId = Utils.findPropertyFromString(loc, "v");
	//alert("mainVideoId, " + mainVideoId);
	var mainTemplate = template_main;
	if(mainVideoId != 0)
	{
		var copyTemp = template_playnow.replace("$pid", mainVideoId);
		copyTemp = copyTemp.replace("$qid", mainVideoId);

		mainTemplate = mainTemplate.replace("$play_now", copyTemp);

	}
	else
	{
		mainTemplate = mainTemplate.replace("$play_now", "");
	}

	var listId = Utils.findPropertyFromString(loc, "list");
	if(listId != 0)
	{
		if(mainVideoId != 0)
		{
			listId = listId + " " + mainVideoId;
		}
		copyTemp = template_playall.replace("$lid", listId);
		mainTemplate = mainTemplate.replace("$play_all", copyTemp);
		mainTemplate = mainTemplate.replace("$sep", "|");
	}
	else
	{
		mainTemplate = mainTemplate.replace("$sep", "");
		mainTemplate = mainTemplate.replace("$play_all", "");
	}

	if(listId != 0 || videoId !=0)
	{
		$("#watch7-headline").prepend(mainTemplate);
	}

	injectLinks();

}
else if(pathName.indexOf("/embed") == 0)
{
	var videoId = pathName.replace("/embed/", "");
	console.log("videoId, " + videoId);

	var copyTemp = template_playnow_sidebar.replace("$pid", videoId);
	copyTemp = copyTemp.replace("$qid", videoId);

	var mainTemplate = template_main;
	mainTemplate = mainTemplate.replace("$play_all", "");
	mainTemplate = mainTemplate.replace("$sep", "");
	mainTemplate = mainTemplate.replace("$play_now", copyTemp);

	$(".player-actions-container").prepend(mainTemplate);

}
else if(pathName == "/share_popup")
{
    var loc = window.location.toString();
    var mainVideoId = Utils.findPropertyFromString(loc, "v");

    var mainTemplate = template_main;
    if(mainVideoId != 0)
    {
        var copyTemp = template_playnow.replace("$pid", mainVideoId);
        copyTemp = copyTemp.replace("$qid", mainVideoId);
        mainTemplate = mainTemplate.replace("$play_now", copyTemp);

        mainTemplate = mainTemplate.replace("$sep", "");
        mainTemplate = mainTemplate.replace("$play_all", "");

        $("#page").prepend(mainTemplate);
    }

}
else
{
	injectLinks();
}

<|endoftext|>