<commit_before>const getBrowserBottomDelta = () => {
  // Firefox displays tooltip at the bottom which obstructs the view.
  // As a workaround ensure extra space from the bottom in the viewport
  // firefox detection (https://stackoverflow.com/a/7000222/2870889).
  if (navigator.userAgent.toLowerCase().indexOf('firefox') >= 0) {
    // Hardcoded height of the tooltip plus some margin
    return 26;
  }
  return 0;
};

// Returns true if scrolling was done.
const scrollToElement = (searchEngine, element) => {
  let topMargin = 0;
  if (searchEngine.getMarginTop) {
    topMargin = searchEngine.getMarginTop(element);
  }
  const bottomMargin = getBrowserBottomDelta();
  const elementBounds = element.getBoundingClientRect();
  const scrollY = window.scrollY;
  // It seems that it's only possible to scroll by
  if (elementBounds.top < topMargin) {
    // scroll element to top
    element.scrollIntoView(true);
    window.scrollBy(0, -topMargin);
  } else if (elementBounds.bottom + bottomMargin > window.innerHeight) {
    // scroll element to bottom
    element.scrollIntoView(false);
    window.scrollBy(0, bottomMargin);
  }
  return Math.abs(window.scrollY - scrollY) > 0.01;
};

class SearchResultsManager {
  constructor(searchEngine, options) {
    this.searchEngine = searchEngine;
    this.options = options;
    this.focusedIndex = 0;
  }

  reloadSearchResults() {
    this.searchResults = this.searchEngine.getSearchResults();
  }

  /**
   * Returns the element to click on upon navigation. The focused element in the
   * document is preferred (if there is one) over the highlighted result. Note
   * that the focused element does not have to be an anchor <a> element.
   *
   * @param {boolean} linkOnly If true the focused element is preferred only
   * when it is a link with "href" attribute.
   * @return {Element}
   */
  getElementToNavigate(linkOnly = false) {
    const focusedElement = document.activeElement;
    if (focusedElement == null) {
      return this.searchResults[this.focusedIndex].anchor;
    }
    const isLink = focusedElement.localName === 'a' &&
        focusedElement.hasAttribute('href');
    if (!linkOnly || isLink) {
      return focusedElement;
    }
  }

  focus(index, scrollToResult = true) {
    if (this.focusedIndex >= 0) {
      const searchResult = this.searchResults[this.focusedIndex];
      // If the current result is outside the viewport and scrolling was
      // requested, only scroll to it, but don't focus on the new result.
      if (scrollToResult && scrollToElement(this.searchEngine,
          searchResult.container)) {
        return;
      }
      const highlighted = searchResult.highlightedElement;
      // Remove highlighting from previous item.
      highlighted.classList.remove(searchResult.highlightClass);
      highlighted.classList.remove('wsn-no-outline');
    }
    const searchResult = this.searchResults[index];
    if (!searchResult) {
      this.focusedIndex = -1;
      return;
    }
    const highlighted = searchResult.highlightedElement;
    // Add the focus outline and caret.
    highlighted.classList.add(searchResult.highlightClass);
    if (this.options.hideOutline || searchResult.anchor !== highlighted) {
      searchResult.anchor.classList.add('wsn-no-outline');
    }
    // We already scroll below, so no need for focus to scroll. The scrolling
    // behavior of `focus` also seems less predictable and caused an issue, see:
    // https://github.com/infokiller/web-search-navigator/issues/35
    searchResult.anchor.focus({preventScroll: true});
    // Ensure whole search result container is visible in the viewport, not only
    // the search result link.
    if (scrollToResult) {
      scrollToElement(this.searchEngine, searchResult.container);
    }
    this.focusedIndex = index;
  }

  focusNext(shouldWrap) {
    if (this.focusedIndex < this.searchResults.length - 1) {
      this.focus(this.focusedIndex + 1);
    } else if (shouldWrap) {
      this.focus(0);
    }
  }

  focusPrevious(shouldWrap) {
    if (this.focusedIndex > 0) {
      this.focus(this.focusedIndex - 1);
    } else if (shouldWrap) {
      this.focus(this.searchResults.length - 1);
    } else {
      window.scrollTo(window.scrollX, 0);
    }
  }
}

class WebSearchNavigator {
  async init() {
    /* eslint-disable-next-line no-undef */
    this.options = new ExtensionOptions();
    await this.options.load();
    /* eslint-disable-next-line no-undef */
    this.searchEngine = await getSearchEngine(this.options.sync.values);
    if (this.searchEngine == null) {
      return;
    }
    await sleep(this.options.sync.values.delay);
    this.initSearchInputNavigation();
    this.initTabsNavigation();
    this.initResultsNavigation();
    this.initChangeToolsNavigation();
    this.initEndlessScrolling();
  }

  initSearchInputNavigation() {
    const searchInput = document.querySelector(
        this.searchEngine.searchBoxSelector);
    // If insideSearchboxHandler returns true, outsideSearchboxHandler will also
    // be called (because it's defined on document, hence has lower priority),
    // in which case we don't want to handle the event. Therefore, we store the
    // last event handled in insideSearchboxHandler, and only handle the event
    // in outsideSearchboxHandler if it's not the same one.
    let lastEvent;
    const outsideSearchboxHandler = (event) => {
      if (event === lastEvent) {
        return false;
      }
      // Scroll to the search box in case it's outside the viewport so that it's
      // clear to the user that it has focus.
      scrollToElement(this.searchEngine, searchInput);
      searchInput.select();
      searchInput.click();
      return false;
    };
    const insideSearchboxHandler = (event) => {
      lastEvent = event;
      // Everything is selected; deselect all.
      if (searchInput.selectionStart === 0 &&
          searchInput.selectionEnd === searchInput.value.length) {
        // Scroll to the search box in case it's outside the viewport so that
        // it's clear to the user that it has focus.
        scrollToElement(this.searchEngine, searchInput);
        searchInput.setSelectionRange(
            searchInput.value.length, searchInput.value.length);
        return false;
      }
      // Closing search suggestions via document.body.click() or
      // searchInput.blur() breaks the state of google's controller.
      // The suggestion box is closed, yet it won't re-appear on the next
      // search box focus event.

      // Input can be blurred only when the suggestion box is already
      // closed, hence the blur event is queued.
      window.setTimeout(() => searchInput.blur());
      // Invoke the default handler which will close-up search suggestions
      // properly (google's controller won't break), but it won't remove the
      // focus.
      return true;
    };
    this.register(this.options.sync.values.focusSearchInput,
        outsideSearchboxHandler);
    // Bind globally, otherwise Mousetrap ignores keypresses inside inputs.
    // We must bind it separately to the search box element, or otherwise the
    // key event won't always be captured (for example this is the case on
    // Google Search as of 2020-06-22), presumably because the javascript in the
    // page will disable further processing.
    this.registerGlobal(this.options.sync.values.focusSearchInput,
        insideSearchboxHandler, searchInput);
  }

  initTabsNavigation() {
    const tabs = this.searchEngine.tabs || {};
    for (const [optionName, element] of Object.entries(tabs)) {
      this.register(this.options.sync.values[optionName], () => {
        if (element == null) {
          return;
        }
        // Some search engines use forms instead of links for navigation
        if (element.tagName == 'FORM') {
          element.submit();
        } else {
          element.click();
        }
      });
    }
  }

  initResultsNavigation() {
    this.resultsManager = new SearchResultsManager(this.searchEngine,
        this.options.sync.values);
    this.resultsManager.reloadSearchResults();
    if (this.resultsManager.searchResults.length === 0) {
      return;
    }
    const options = this.options.sync.values;
    const lastNavigation = this.options.local.values;
    let isFirstNavigation = true;
    if (options.autoSelectFirst) {
      // Highlight the first result when the page is loaded, but don't scroll to
      // it because there may be KP cards such as stock graphs.
      this.resultsManager.focus(0, false);
    }
    if (location.href === lastNavigation.lastQueryUrl) {
      isFirstNavigation = false;
      this.resultsManager.focus(lastNavigation.lastFocusedIndex);
    }
    this.register(options.nextKey, () => {
      if (!options.autoSelectFirst && isFirstNavigation) {
        this.resultsManager.focus(0);
        isFirstNavigation = false;
      } else {
        this.resultsManager.focusNext(options.wrapNavigation);
      }
    });
    this.register(options.previousKey, () => {
      if (!options.autoSelectFirst && isFirstNavigation) {
        this.resultsManager.focus(0);
        isFirstNavigation = false;
      } else {
        this.resultsManager.focusPrevious(options.wrapNavigation);
      }
    });
    this.register(options.navigateKey, () => {
      const link = this.resultsManager.getElementToNavigate();
      lastNavigation.lastQueryUrl = location.href;
      lastNavigation.lastFocusedIndex = this.resultsManager.focusedIndex;
      this.options.local.save();
      link.click();
    });
    this.register(options.navigateNewTabKey, () => {
      const link = this.resultsManager.getElementToNavigate(true);
      /* eslint-disable-next-line no-undef */
      browser.runtime.sendMessage({
        type: 'tabsCreate',
        options: {
          url: link.href,
          active: true,
        },
      });
    });
    this.register(options.navigateNewTabBackgroundKey, () => {
      const link = this.resultsManager.getElementToNavigate(true);
      /* eslint-disable-next-line no-undef */
      browser.runtime.sendMessage({
        type: 'tabsCreate',
        options: {
          url: link.href,
          active: false,
        },
      });
    });
  }

  initChangeToolsNavigation() {
    const options = this.options.sync.values;
    this.register(options.navigateShowAll, () =>
      this.searchEngine.changeTools('a'));
    this.register(options.navigateShowHour, () =>
      this.searchEngine.changeTools('h'));
    this.register(options.navigateShowDay, () =>
      this.searchEngine.changeTools('d'));
    this.register(options.navigateShowWeek, () =>
      this.searchEngine.changeTools('w'));
    this.register(options.navigateShowMonth, () =>
      this.searchEngine.changeTools('m'));
    this.register(options.navigateShowYear, () =>
      this.searchEngine.changeTools('y'));
    this.register(options.toggleSort, () =>
      this.searchEngine.changeTools(null));
  }

  registerGlobal(shortcut, callback, element = document) {
    /* eslint-disable-next-line no-undef,new-cap */
    Mousetrap(element).bindGlobal(shortcut, (event) => {
      return callback(event);
    });
  }

  register(shortcut, callback, element = document) {
    /* eslint-disable-next-line no-undef,new-cap */
    Mousetrap(element).bind(shortcut, (event) => {
      return callback(event);
    });
  }
  /**
   * Observes the number of childnodes of endlessScrollingContainer and compares
   * them with this.results.items. Automatically inits a reload of the
   * navigation when they don't match up. This ensures that all results are
   * always up to date when scrolling.
   */
  initEndlessScrolling() {
    const container = this.searchEngine.endlessScrollingContainer;
    if (!container) {
      return;
    }
    this.observedAdditions = 0;
    const config = {attributes: false, childList: true, subtree: false};
    let firstObservation = true;
    let observedHref = undefined;
    const observer = new MutationObserver(async (mutationsList, observer) => {
      if (firstObservation) {
        observedHref = location.href;
        this.observedAdditions = this.resultsManager.searchResults.length;
        firstObservation = false;
      }
      if (observedHref && observedHref != location.href) {
        // Mutation Server was triggered due to loading a new url -> disconnect
        // the observer
        observer.disconnect();
        return;
      }
      for (const mutations of mutationsList) {
        this.observedAdditions += mutations.addedNodes.length;
      }
      if (this.resultsManager.searchResults.length < this.observedAdditions) {
        this.resultsManager.reloadSearchResults();
      }
    });
    observer.observe(container, config);
  }
}

/**
 * Make functions sleeps
 *
 * Can be used with then() callback :
 * sleep.then(() => { stuff to do after sleeps }),
 * Or in an async function, like we do below extension initialization
 * @param {*} milliseconds, How long you want your function to sleep
 * @return {Promise} a Promise resolving a timeout
 */
const sleep = (milliseconds) => {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
};

const extension = new WebSearchNavigator();
extension.init();
<commit_msg>be explicit about other key handlers<commit_after>const getBrowserBottomDelta = () => {
  // Firefox displays tooltip at the bottom which obstructs the view.
  // As a workaround ensure extra space from the bottom in the viewport
  // firefox detection (https://stackoverflow.com/a/7000222/2870889).
  if (navigator.userAgent.toLowerCase().indexOf('firefox') >= 0) {
    // Hardcoded height of the tooltip plus some margin
    return 26;
  }
  return 0;
};

// Returns true if scrolling was done.
const scrollToElement = (searchEngine, element) => {
  let topMargin = 0;
  if (searchEngine.getMarginTop) {
    topMargin = searchEngine.getMarginTop(element);
  }
  const bottomMargin = getBrowserBottomDelta();
  const elementBounds = element.getBoundingClientRect();
  const scrollY = window.scrollY;
  // It seems that it's only possible to scroll by
  if (elementBounds.top < topMargin) {
    // scroll element to top
    element.scrollIntoView(true);
    window.scrollBy(0, -topMargin);
  } else if (elementBounds.bottom + bottomMargin > window.innerHeight) {
    // scroll element to bottom
    element.scrollIntoView(false);
    window.scrollBy(0, bottomMargin);
  }
  return Math.abs(window.scrollY - scrollY) > 0.01;
};

class SearchResultsManager {
  constructor(searchEngine, options) {
    this.searchEngine = searchEngine;
    this.options = options;
    this.focusedIndex = 0;
  }

  reloadSearchResults() {
    this.searchResults = this.searchEngine.getSearchResults();
  }

  /**
   * Returns the element to click on upon navigation. The focused element in the
   * document is preferred (if there is one) over the highlighted result. Note
   * that the focused element does not have to be an anchor <a> element.
   *
   * @param {boolean} linkOnly If true the focused element is preferred only
   * when it is a link with "href" attribute.
   * @return {Element}
   */
  getElementToNavigate(linkOnly = false) {
    const focusedElement = document.activeElement;
    if (focusedElement == null) {
      return this.searchResults[this.focusedIndex].anchor;
    }
    const isLink = focusedElement.localName === 'a' &&
        focusedElement.hasAttribute('href');
    if (!linkOnly || isLink) {
      return focusedElement;
    }
  }

  focus(index, scrollToResult = true) {
    if (this.focusedIndex >= 0) {
      const searchResult = this.searchResults[this.focusedIndex];
      // If the current result is outside the viewport and scrolling was
      // requested, only scroll to it, but don't focus on the new result.
      if (scrollToResult && scrollToElement(this.searchEngine,
          searchResult.container)) {
        return;
      }
      const highlighted = searchResult.highlightedElement;
      // Remove highlighting from previous item.
      highlighted.classList.remove(searchResult.highlightClass);
      highlighted.classList.remove('wsn-no-outline');
    }
    const searchResult = this.searchResults[index];
    if (!searchResult) {
      this.focusedIndex = -1;
      return;
    }
    const highlighted = searchResult.highlightedElement;
    // Add the focus outline and caret.
    highlighted.classList.add(searchResult.highlightClass);
    if (this.options.hideOutline || searchResult.anchor !== highlighted) {
      searchResult.anchor.classList.add('wsn-no-outline');
    }
    // We already scroll below, so no need for focus to scroll. The scrolling
    // behavior of `focus` also seems less predictable and caused an issue, see:
    // https://github.com/infokiller/web-search-navigator/issues/35
    searchResult.anchor.focus({preventScroll: true});
    // Ensure whole search result container is visible in the viewport, not only
    // the search result link.
    if (scrollToResult) {
      scrollToElement(this.searchEngine, searchResult.container);
    }
    this.focusedIndex = index;
  }

  focusNext(shouldWrap) {
    if (this.focusedIndex < this.searchResults.length - 1) {
      this.focus(this.focusedIndex + 1);
    } else if (shouldWrap) {
      this.focus(0);
    }
  }

  focusPrevious(shouldWrap) {
    if (this.focusedIndex > 0) {
      this.focus(this.focusedIndex - 1);
    } else if (shouldWrap) {
      this.focus(this.searchResults.length - 1);
    } else {
      window.scrollTo(window.scrollX, 0);
    }
  }
}

class WebSearchNavigator {
  async init() {
    /* eslint-disable-next-line no-undef */
    this.options = new ExtensionOptions();
    await this.options.load();
    /* eslint-disable-next-line no-undef */
    this.searchEngine = await getSearchEngine(this.options.sync.values);
    if (this.searchEngine == null) {
      return;
    }
    await sleep(this.options.sync.values.delay);
    this.initSearchInputNavigation();
    this.initTabsNavigation();
    this.initResultsNavigation();
    this.initChangeToolsNavigation();
    this.initEndlessScrolling();
  }

  initSearchInputNavigation() {
    const searchInput = document.querySelector(
        this.searchEngine.searchBoxSelector);
    // If insideSearchboxHandler returns true, outsideSearchboxHandler will also
    // be called (because it's defined on document, hence has lower priority),
    // in which case we don't want to handle the event. Therefore, we store the
    // last event handled in insideSearchboxHandler, and only handle the event
    // in outsideSearchboxHandler if it's not the same one.
    let lastEvent;
    const outsideSearchboxHandler = (event) => {
      if (event === lastEvent) {
        return false;
      }
      // Scroll to the search box in case it's outside the viewport so that it's
      // clear to the user that it has focus.
      scrollToElement(this.searchEngine, searchInput);
      searchInput.select();
      searchInput.click();
      return false;
    };
    const insideSearchboxHandler = (event) => {
      lastEvent = event;
      // Everything is selected; deselect all.
      if (searchInput.selectionStart === 0 &&
          searchInput.selectionEnd === searchInput.value.length) {
        // Scroll to the search box in case it's outside the viewport so that
        // it's clear to the user that it has focus.
        scrollToElement(this.searchEngine, searchInput);
        searchInput.setSelectionRange(
            searchInput.value.length, searchInput.value.length);
        return false;
      }
      // Closing search suggestions via document.body.click() or
      // searchInput.blur() breaks the state of google's controller.
      // The suggestion box is closed, yet it won't re-appear on the next
      // search box focus event.

      // Input can be blurred only when the suggestion box is already
      // closed, hence the blur event is queued.
      window.setTimeout(() => searchInput.blur());
      // Invoke the default handler which will close-up search suggestions
      // properly (google's controller won't break), but it won't remove the
      // focus.
      return true;
    };
    this.register(this.options.sync.values.focusSearchInput,
        outsideSearchboxHandler);
    // Bind globally, otherwise Mousetrap ignores keypresses inside inputs.
    // We must bind it separately to the search box element, or otherwise the
    // key event won't always be captured (for example this is the case on
    // Google Search as of 2020-06-22), presumably because the javascript in the
    // page will disable further processing.
    this.registerGlobal(this.options.sync.values.focusSearchInput,
        insideSearchboxHandler, searchInput);
  }

  initTabsNavigation() {
    const tabs = this.searchEngine.tabs || {};
    for (const [optionName, element] of Object.entries(tabs)) {
      this.register(this.options.sync.values[optionName], () => {
        if (element == null) {
          return true;
        }
        // Some search engines use forms instead of links for navigation
        if (element.tagName == 'FORM') {
          element.submit();
        } else {
          element.click();
        }
      });
    }
  }

  initResultsNavigation() {
    this.resultsManager = new SearchResultsManager(this.searchEngine,
        this.options.sync.values);
    this.resultsManager.reloadSearchResults();
    if (this.resultsManager.searchResults.length === 0) {
      return;
    }
    const options = this.options.sync.values;
    const lastNavigation = this.options.local.values;
    let isFirstNavigation = true;
    if (options.autoSelectFirst) {
      // Highlight the first result when the page is loaded, but don't scroll to
      // it because there may be KP cards such as stock graphs.
      this.resultsManager.focus(0, false);
    }
    if (location.href === lastNavigation.lastQueryUrl) {
      isFirstNavigation = false;
      this.resultsManager.focus(lastNavigation.lastFocusedIndex);
    }
    this.register(options.nextKey, () => {
      if (!options.autoSelectFirst && isFirstNavigation) {
        this.resultsManager.focus(0);
        isFirstNavigation = false;
      } else {
        this.resultsManager.focusNext(options.wrapNavigation);
      }
      return false;
    });
    this.register(options.previousKey, () => {
      if (!options.autoSelectFirst && isFirstNavigation) {
        this.resultsManager.focus(0);
        isFirstNavigation = false;
      } else {
        this.resultsManager.focusPrevious(options.wrapNavigation);
      }
      return false;
    });
    this.register(options.navigateKey, () => {
      const link = this.resultsManager.getElementToNavigate();
      lastNavigation.lastQueryUrl = location.href;
      lastNavigation.lastFocusedIndex = this.resultsManager.focusedIndex;
      this.options.local.save();
      link.click();
      return false;
    });
    this.register(options.navigateNewTabKey, () => {
      const link = this.resultsManager.getElementToNavigate(true);
      /* eslint-disable-next-line no-undef */
      browser.runtime.sendMessage({
        type: 'tabsCreate',
        options: {
          url: link.href,
          active: true,
        },
      });
      return false;
    });
    this.register(options.navigateNewTabBackgroundKey, () => {
      const link = this.resultsManager.getElementToNavigate(true);
      /* eslint-disable-next-line no-undef */
      browser.runtime.sendMessage({
        type: 'tabsCreate',
        options: {
          url: link.href,
          active: false,
        },
      });
      return false;
    });
  }

  initChangeToolsNavigation() {
    const options = this.options.sync.values;
    this.register(options.navigateShowAll, () =>
      this.searchEngine.changeTools('a'));
    this.register(options.navigateShowHour, () =>
      this.searchEngine.changeTools('h'));
    this.register(options.navigateShowDay, () =>
      this.searchEngine.changeTools('d'));
    this.register(options.navigateShowWeek, () =>
      this.searchEngine.changeTools('w'));
    this.register(options.navigateShowMonth, () =>
      this.searchEngine.changeTools('m'));
    this.register(options.navigateShowYear, () =>
      this.searchEngine.changeTools('y'));
    this.register(options.toggleSort, () =>
      this.searchEngine.changeTools(null));
  }

  registerGlobal(shortcut, callback, element = document) {
    /* eslint-disable-next-line no-undef,new-cap */
    Mousetrap(element).bindGlobal(shortcut, (event) => {
      return callback(event);
    });
  }

  register(shortcut, callback, element = document) {
    /* eslint-disable-next-line no-undef,new-cap */
    Mousetrap(element).bind(shortcut, (event) => {
      return callback(event);
    });
  }
  /**
   * Observes the number of childnodes of endlessScrollingContainer and compares
   * them with this.results.items. Automatically inits a reload of the
   * navigation when they don't match up. This ensures that all results are
   * always up to date when scrolling.
   */
  initEndlessScrolling() {
    const container = this.searchEngine.endlessScrollingContainer;
    if (!container) {
      return;
    }
    this.observedAdditions = 0;
    const config = {attributes: false, childList: true, subtree: false};
    let firstObservation = true;
    let observedHref = undefined;
    const observer = new MutationObserver(async (mutationsList, observer) => {
      if (firstObservation) {
        observedHref = location.href;
        this.observedAdditions = this.resultsManager.searchResults.length;
        firstObservation = false;
      }
      if (observedHref && observedHref != location.href) {
        // Mutation Server was triggered due to loading a new url -> disconnect
        // the observer
        observer.disconnect();
        return;
      }
      for (const mutations of mutationsList) {
        this.observedAdditions += mutations.addedNodes.length;
      }
      if (this.resultsManager.searchResults.length < this.observedAdditions) {
        this.resultsManager.reloadSearchResults();
      }
    });
    observer.observe(container, config);
  }
}

/**
 * Make functions sleeps
 *
 * Can be used with then() callback :
 * sleep.then(() => { stuff to do after sleeps }),
 * Or in an async function, like we do below extension initialization
 * @param {*} milliseconds, How long you want your function to sleep
 * @return {Promise} a Promise resolving a timeout
 */
const sleep = (milliseconds) => {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
};

const extension = new WebSearchNavigator();
extension.init();
<|endoftext|>


<commit_before>
/* global enchant, Class, HEIGHT, WIDTH, SPEED, TRANSITION, PLAYER_LIVES */

//init enchant.js
WIDTH = 2048;
HEIGHT = 1152;
SPEED = 800;
TRANSITION = 10;

PLAYER_LIVES = 3;

var FALLING_OBJECTS = [
];

// enchant.ENV.USE_ANIMATION  = false;
enchant.ENV.TOUCH_ENABLED  = false;
enchant.ENV.RETINA_DISPLAY = false;

enchant();

var Marker = Class.create(enchant.Node, { });

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

function Pool () {
  this.pools = [];
}
Pool.prototype.get = function() {
  if ( this.pools.length > 0 ) {
    return this.pools.pop();
  }
  // console.log('pool ran out!');
  return null;
};
Pool.prototype.add = function(v) {
  this.pools.push(v);
};

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

function spritefromAsset (asset) {
    var sprite = new enchant.Sprite(asset.width, asset.height);
    sprite.image = asset;
    sprite.touchEnabled = false;
    sprite.disableCollection();
    return sprite;
}

//////////////////  SCENES  /////////////////////

var SceneInfos = Class.create(enchant.Group, {
    initialize: function (game, lives, onLoose) {

      var self = this;

      enchant.Group.call(this);

      this.lives = lives;
      this.onLoose = onLoose;

      this.x = 100;
      this.y = 100;
      this.width = 3 * 70;
      this.height = 70;
      this.game = game;

      this.hearts = [];

      this.coeurgris = this.game.assets['distimg/coeurgris.png'];
      this.coeurrouge = game.assets['distimg/coeurrouge.png'];
      this.coeurrouge.coeurrouge = true;

      for (var i = 0; i < 3; i++) {
        this.hearts[i] = new enchant.Sprite(this.coeurgris.width, this.coeurgris.height);
        this.hearts[i].image = this.coeurrouge;
        this.hearts[i].y = 10;
        this.hearts[i].x = (3-i) * 70;
        this.hearts[i].width = 62;
        this.hearts[i].height = 53;
        this.hearts[i].coeurrouge = true;
        this.addChild(this.hearts[i]);
      }
    },
    lostALife: function () {
      for (var i = 0; i < 3; i++) {
        if (this.hearts[i].image.coeurrouge) {
          this.hearts[i].image = this.coeurgris;
          this.lives--;
          break;
        }
      }
      if (this.lives <= 0) {
        setTimeout(this.onLoose, 20);
      } else {
        setTimeout(function(){
          window.ggj.twist();
        }, 0);
      }
    }
});

var SceneOne = Class.create(enchant.Group, {
  initialize: function (game) {
    var self = this;

    this.game = game;
    enchant.Group.call(this);

    this.width   = WIDTH;
    this.height  = HEIGHT;

    // Preload backgounds
    var backgrounds = [];
    for (var i = 0; i < 3; i++) {
      backgrounds[i] = spritefromAsset(game.assets['distimg/BG'+(i+1)+'.jpg']);
      backgrounds[i].width = WIDTH;
      this.addChild(backgrounds[i]);
    }

    // Loop backgrounds
    var currentBG = 0;
    this.tl
      .delay(20)
      .then(function(){
        if (! self.lightsAreOff()) {
          backgrounds[currentBG].tl.fadeOut(10);
          currentBG = (currentBG + 1) % 3;
          backgrounds[currentBG].tl.fadeIn(10);
        }
      })
      .loop();

    // Preload spots
    var spots = this.spots = [];
    for (var i = 0; i < 3; i++) {
      spots[i] = spritefromAsset(game.assets['distimg/spot'+(i+1)+'.png']);
      spots[i].width = WIDTH;
      this.addChild(spots[i]);
    }

    // Load bath
    var theBath = spritefromAsset(game.assets['distimg/bain.png']);
    theBath.width = WIDTH;
    this.addChild(theBath);

    // Loop spots
    var currentSpot = 0;
    this.tl
      .delay(20)
      .then(function(){
        if (! self.lightsAreOff()) {
          spots[currentSpot].tl.fadeOut(10);
          currentSpot = (currentSpot + 1) % 3;
          spots[currentSpot].tl.fadeIn(10);
        }
      })
      .loop();

    // The "lights off" layer
    var lightsOff = this.lightsOff = new enchant.Sprite(WIDTH, HEIGHT);
    lightsOff.backgroundColor = 'black';
    lightsOff.opacity = 0;
    this.addChild(lightsOff);

    // Load switch
    var theSwitch = this.theSwitch = spritefromAsset(game.assets['distimg/interrupteur.png']);
    theSwitch.x = WIDTH * 0.9;
    theSwitch.y = HEIGHT * 0.7;
    theSwitch.touchEnabled = true;
    this.addChild(theSwitch);

    // Plug switch
    theSwitch.addEventListener('touchstart', function() {
      self.toggleLights();
    });

  },

  lightsAreOff: function () {
    return this.lightsOff.opacity > 0.5;
  },

  toggleLights: function (event) {
    this.lightsOff.opacity = this.lightsAreOff() ? 0 : 0.8;
    this.theSwitch.image = this.lightsAreOff() ? this.game.assets['distimg/interrupteur.png'] : this.game.assets['distimg/interrupteur2.png'];

    for (var i = 0; i < 3; i++) {
        this.spots[i].opacity = this.lightsAreOff() ? 0 : 1;
    }

  },

});
SceneOne.preload = [
];
for (var i = 0; i < 6; i++) { SceneOne.preload.push('distimg/imm' + (i+1) + '-j-fs8.png'); }

(function () {

var game;

var settings = {
  player: {
    lives: 3,
    sprite: 'distimg/claude.png',
  },
  levels: [
      SceneOne,
  ]
};

// Character
function addCharacter (game, scene, asset) {
  var object = new enchant.Sprite(asset.width, asset.height);
  object.image = asset;
  object.width = 20;
  object.x = WIDTH / 2 - object.width / 2;
  object.y = HEIGHT / 2 - object.height;
  object.touchEnabled = false;
  object.disableCollection();
  scene.addChild(object);
  return object;
}

// Table
function addTable (game, scene, objects) {
  var asset =  game.assets['table'];
  var object = new enchant.Sprite(asset.width, asset.height);
  object.image = asset;
  object.width = 20;
  object.x = WIDTH / 2 - object.width / 2;
  object.y = HEIGHT / 2 - object.height;
  object.touchEnabled = false;
  object.disableCollection();
  scene.addChild(object);
  return object;
}

// Player
var Player = Class.create(enchant.Sprite, {

  initialize: function () {
    this.image_j = game.assets[settings.player.sprite_j];
    this.image_n = game.assets[settings.player.sprite_n];

    enchant.Sprite.call(this, this.image_j.width/5, this.image_j.height);
    this.image = this.image_j;
    this.counter=this.age;
    this.x = WIDTH / 2;
    this.y = HEIGHT / 2 - this.height - 150;
    this.frames = [0,1,2,3,4,3,2,1];
    this.frame = this.frames;
  }

});

/**
 * Main
 */
var Game = function () {

  var self = this;

  game = this.game = new enchant.Core(WIDTH, HEIGHT); //screen res
  game.fps = 30;

  var preload = [
    'distimg/BG1.jpg',
    'distimg/BG2.jpg',
    'distimg/BG3.jpg',
    'distimg/spot1.png',
    'distimg/spot2.png',
    'distimg/spot3.png',
    'distimg/bain.png',
    'distimg/interrupteur.png',
    'distimg/interrupteur2.png',
  ];

  game.preload(preload); //preload assets png, wav etc

  game.onload = function () {
    self.loadLevel(0);
  };

  game.rootScene.addEventListener('touchstart', function() {
  });

  function changevisibility() {
    if (document.hidden === false || document.webkitHidden === false) {
      game.resume();
    } else {
      self.game.pause();
    }
  }
  document.addEventListener('visibilitychange', changevisibility, false);
  document.addEventListener('webkitvisibilitychange', changevisibility, false);

  game.start();
};

Game.prototype.loadLevel = function(levelIndex) {

  if (this.scene) {
    game.rootScene.removeChild(this.scene);
  }

  this.scene = new settings.levels[levelIndex](game);
  game.rootScene.addChild(this.scene);

  // this.playerScene = new settings.levels[levelIndex].playerScene();
  // this.player = new Player();
  // game.player = this.player;
  // this.playerScene.addChild(this.player);

  // game.infos = new SceneInfos(game, PLAYER_LIVES, this.loose.bind(this));
  // game.rootScene.addChild(game.infos);
};

Game.prototype.loose = function() {
  this.game.pause();
  setTimeout(function(){
    window.location = 'img/scenes/Game-over.png';
  }, 10);
};

window.ggj = new Game();

})();

<commit_msg>prepare characters<commit_after>
/* global enchant, Class, HEIGHT, WIDTH, SPEED, TRANSITION, PLAYER_LIVES */

//init enchant.js
WIDTH = 2048;
HEIGHT = 1152;
SPEED = 800;
TRANSITION = 10;

PLAYER_LIVES = 3;

var FALLING_OBJECTS = [
];

// enchant.ENV.USE_ANIMATION  = false;
enchant.ENV.TOUCH_ENABLED  = false;
enchant.ENV.RETINA_DISPLAY = false;

enchant();

var Marker = Class.create(enchant.Node, { });

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

function Pool () {
  this.pools = [];
}
Pool.prototype.get = function() {
  if ( this.pools.length > 0 ) {
    return this.pools.pop();
  }
  // console.log('pool ran out!');
  return null;
};
Pool.prototype.add = function(v) {
  this.pools.push(v);
};

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

function spritefromAsset (asset) {
    var sprite = new enchant.Sprite(asset.width, asset.height);
    sprite.image = asset;
    sprite.touchEnabled = false;
    sprite.disableCollection();
    return sprite;
}

//////////////////  SCENES  /////////////////////

var SceneInfos = Class.create(enchant.Group, {
    initialize: function (game, lives, onLoose) {

      var self = this;

      enchant.Group.call(this);

      this.lives = lives;
      this.onLoose = onLoose;

      this.x = 100;
      this.y = 100;
      this.width = 3 * 70;
      this.height = 70;
      this.game = game;

      this.hearts = [];

      this.coeurgris = this.game.assets['distimg/coeurgris.png'];
      this.coeurrouge = game.assets['distimg/coeurrouge.png'];
      this.coeurrouge.coeurrouge = true;

      for (var i = 0; i < 3; i++) {
        this.hearts[i] = new enchant.Sprite(this.coeurgris.width, this.coeurgris.height);
        this.hearts[i].image = this.coeurrouge;
        this.hearts[i].y = 10;
        this.hearts[i].x = (3-i) * 70;
        this.hearts[i].width = 62;
        this.hearts[i].height = 53;
        this.hearts[i].coeurrouge = true;
        this.addChild(this.hearts[i]);
      }
    },
    lostALife: function () {
      for (var i = 0; i < 3; i++) {
        if (this.hearts[i].image.coeurrouge) {
          this.hearts[i].image = this.coeurgris;
          this.lives--;
          break;
        }
      }
      if (this.lives <= 0) {
        setTimeout(this.onLoose, 20);
      }
    }
});

var SceneOne = Class.create(enchant.Group, {
  initialize: function (game) {
    var self = this;

    this.game = game;
    enchant.Group.call(this);

    this.width   = WIDTH;
    this.height  = HEIGHT;

    // Preload backgounds
    var backgrounds = [];
    for (var i = 0; i < 3; i++) {
      backgrounds[i] = spritefromAsset(game.assets['distimg/BG'+(i+1)+'.jpg']);
      backgrounds[i].width = WIDTH;
      this.addChild(backgrounds[i]);
    }

    // Loop backgrounds
    var currentBG = 0;
    this.tl
      .delay(20)
      .then(function(){
        if (! self.lightsAreOff()) {
          backgrounds[currentBG].tl.fadeOut(10);
          currentBG = (currentBG + 1) % 3;
          backgrounds[currentBG].tl.fadeIn(10);
        }
      })
      .loop();

    // Load characters
    var characters = this.characters = [];
    for (var i = 0; i < 1; i++) {
      characters[i] = spritefromAsset(game.assets['distimg/interrupteur.png']);
      characters[i].x = WIDTH / 2 -  3 * 50 + i * 50;
      characters[i].y = HEIGHT * 0.6;
      this.addChild(characters[i]);
    }

    // Preload spots
    var spots = this.spots = [];
    for (var i = 0; i < 3; i++) {
      spots[i] = spritefromAsset(game.assets['distimg/spot'+(i+1)+'.png']);
      spots[i].width = WIDTH;
      this.addChild(spots[i]);
    }

    // Load bath
    var theBath = spritefromAsset(game.assets['distimg/bain.png']);
    theBath.width = WIDTH;
    this.addChild(theBath);

    // Loop spots
    var currentSpot = 0;
    this.tl
      .delay(20)
      .then(function(){
        if (! self.lightsAreOff()) {
          spots[currentSpot].tl.fadeOut(10);
          currentSpot = (currentSpot + 1) % 3;
          spots[currentSpot].tl.fadeIn(10);
        }
      })
      .loop();

    // The "lights off" layer
    var lightsOff = this.lightsOff = new enchant.Sprite(WIDTH, HEIGHT);
    lightsOff.backgroundColor = 'black';
    lightsOff.opacity = 0;
    this.addChild(lightsOff);

    // Load switch
    var theSwitch = this.theSwitch = spritefromAsset(game.assets['distimg/interrupteur.png']);
    theSwitch.x = WIDTH * 0.9;
    theSwitch.y = HEIGHT * 0.3;
    theSwitch.touchEnabled = true;
    this.addChild(theSwitch);

    // Plug switch
    theSwitch.addEventListener('touchstart', function() {
      self.toggleLights();
    });

    // Load throwables
    var object = spritefromAsset(game.assets['distimg/interrupteur.png']);
    object.name = 'heart';
    object.x = object.original_x = WIDTH * 0.8;
    object.y = object.original_y = HEIGHT * 2;
    object.touchEnabled = true;
    this.addChild(object);

    setInterval(function () {
      self.game.throwObject(object, { name:'chick', x:WIDTH/2 * Math.random(), y:-100 });
    }, 1000);

  },

  lightsAreOff: function () {
    return this.lightsOff.opacity > 0.5;
  },

  toggleLights: function (event) {
    this.lightsOff.opacity = this.lightsAreOff() ? 0 : 0.8;
    this.theSwitch.image = this.lightsAreOff() ? this.game.assets['distimg/interrupteur.png'] : this.game.assets['distimg/interrupteur2.png'];

    for (var i = 0; i < 3; i++) {
        this.spots[i].opacity = this.lightsAreOff() ? 0 : 1;
    }

  },

});
SceneOne.preload = [
];
for (var i = 0; i < 6; i++) { SceneOne.preload.push('distimg/imm' + (i+1) + '-j-fs8.png'); }

(function () {

var game;

var settings = {
  player: {
    lives: 3,
    sprite: 'distimg/claude.png',
  },
  levels: [
      SceneOne,
  ]
};

// Character
function addCharacter (game, scene, asset) {
  var object = new enchant.Sprite(asset.width, asset.height);
  object.image = asset;
  object.width = 20;
  object.x = WIDTH / 2 - object.width / 2;
  object.y = HEIGHT / 2 - object.height;
  object.touchEnabled = false;
  object.disableCollection();
  scene.addChild(object);
  return object;
}

// Table
function addTable (game, scene, objects) {
  var asset =  game.assets['table'];
  var object = new enchant.Sprite(asset.width, asset.height);
  object.image = asset;
  object.width = 20;
  object.x = WIDTH / 2 - object.width / 2;
  object.y = HEIGHT / 2 - object.height;
  object.touchEnabled = false;
  object.disableCollection();
  scene.addChild(object);
  return object;
}

/**
 * Main
 */
var Game = function () {

  var self = this;

  game = this.game = new enchant.Core(WIDTH, HEIGHT); //screen res
  game.fps = 30;

  var preload = [
    'distimg/BG1.jpg',
    'distimg/BG2.jpg',
    'distimg/BG3.jpg',
    'distimg/spot1.png',
    'distimg/spot2.png',
    'distimg/spot3.png',
    'distimg/bain.png',
    'distimg/interrupteur.png',
    'distimg/interrupteur2.png',
  ];

  game.preload(preload); //preload assets png, wav etc

  game.onload = function () {
    self.loadLevel(0);
  };

  game.rootScene.addEventListener('touchstart', function() {
  });

  function changevisibility() {
    if (document.hidden === false || document.webkitHidden === false) {
      game.resume();
    } else {
      self.game.pause();
    }
  }
  document.addEventListener('visibilitychange', changevisibility, false);
  document.addEventListener('webkitvisibilitychange', changevisibility, false);

  game.throwObject = function(object, to) {
    object.tl
      .moveTo(to.x, to.y, 10)
      .then(function(){

          // heart on chick
          if (object.name == 'heart' && to.name == 'chick') {

          }

          // money on chick
          if (object.name == 'money' && to.name == 'chick') {

          }

          object.x = object.original_x;
          object.y = object.original_y;
      });
  };

  game.start();
};

Game.prototype.loadLevel = function(levelIndex) {

  if (this.scene) {
    game.rootScene.removeChild(this.scene);
  }

  this.scene = new settings.levels[levelIndex](game);
  game.rootScene.addChild(this.scene);

  // this.playerScene = new settings.levels[levelIndex].playerScene();
  // this.player = new Player();
  // game.player = this.player;
  // this.playerScene.addChild(this.player);

  // game.infos = new SceneInfos(game, PLAYER_LIVES, this.loose.bind(this));
  // game.rootScene.addChild(game.infos);
};

Game.prototype.loose = function() {
  this.game.pause();
  setTimeout(function(){
    alert('You loose');
  }, 10);
};

window.bbqggj = new Game();

})();

<|endoftext|>


<commit_before>(function (global) {
  "use strict";

  var languageDialect = (function(lang) {
        window.location.search.slice(1).split("&").some(function (searchTerm) {
          if (searchTerm.indexOf("lang=") === 0) {
            lang = searchTerm.split("=").slice(1).join("=");
            return true;
          }
        });

        return lang.toLowerCase();
      })(window.navigator.userLanguage || window.navigator.language),
      language = languageDialect.split("-")[0],
      QueryableObject = (function() {
        var scope = "_scope";

        function QueryableObject(o) {
          this[scope] = o;
        }

        QueryableObject.prototype.find = function(path) {
          return path.split(".").reduce(function (obj, key) {
            return obj ? obj[key] : undefined;
          }, this[scope]);
        };

        return QueryableObject;
      }());

  function applyTranslationToElement(ele, obj) {
    if(ele.hasAttribute("data-i18n")) {
      applyTranslation(ele, ele.getAttribute("data-i18n"), obj);
    }
  }

  function applyTranslation(ele, path, obj) {
    var translated = obj.find(path);

    if (typeof(translated) === "object" && !Array.isArray(translated)) {
      console.warn("Could not translate %o: path '%s' is of type object", ele, path);
    } else if(typeof(translated) !== "undefined") {
      clean(ele);
      ele.appendChild(toDom(translated));
      ele.lang = language;
    }
  }

  function getLang(ele, threshold) {
    do {
      if(ele.lang) {
        return ele.lang.toLowerCase();
      }
    } while((ele = ele.parentElement) && ele !== threshold);
  }

  function clean(ele) {
    var child;
    while((child = ele.firstChild)) {
      ele.removeChild(child);
    }
  }

  function toDom(content) {
    if(Array.isArray(content)) {
      return content.reduce(function(frag, text) {
        var ele = document.createElement("p");
        ele.textContent = text;
        frag.appendChild(ele);

        return frag;
      }, document.createDocumentFragment());
    }
    return document.createTextNode(content);
  }

  global.i18n = {
    base: (document.documentElement.getAttribute("data-i18n-base") || "locales/"),
    set: (document.documentElement.getAttribute("data-i18n-set") || "translation"),
    loadTranslations: function(lang, set, base) {
      var url = (base || this.base || "") + (lang || language) + "/" + (set || this.set) + ".json";
      console.info("loading translations from: " + url);

      return fetch(url, {
        headers: {
          "Accept": "application/json"
        }
      }).then(function (res) {
        if (res.status >= 200 && res.status < 300) {
          console.info("successfully loaded translations");

          return res.json().then(function(obj) {
            return new QueryableObject(obj);
          });
        }

        // TODO add error object instead of false
        return Promise.reject(false);
      }).catch(function (err) {
        console.error("Error loading translations: %o", err);
      });
    },
    translate: function(ele) {
      if(!this.translations) {
        this.translations = this.loadTranslations();
      }

      return this.translations.then(function(obj) {
        if(getLang(ele) === languageDialect) {
          if(!ele.hasAttribute("data-i18n")) {
            return Promise.all([].slice.call(ele.querySelectorAll("[lang]:not([lang='" + language + "'])")).map(global.i18n.translate.bind(global.i18n))).then(function() {
              return ele;
            });
          }

          return Promise.resolve(ele);
        }

        if(ele.hasAttribute("data-i18n")) {
          applyTranslationToElement(ele, obj);
        } else {
          [].slice.call(ele.querySelectorAll("[data-i18n]")).forEach(function(match) {
            if(getLang(match, ele) !== languageDialect) {
              applyTranslationToElement(match, obj);
            }
          });
        }
        return obj;
      });
    },
    translateAll: function() {
      this.translatedAll = true;
      return this.translate(document.documentElement);
    },
    set language(lang) {
      lang = String(lang);

      if(lang !== language) {
        language = lang;

        if(this.translatedAll) {
          this.translateAll(lang);
        } else if(this.translations) {
          this.translations = this.loadTranslations();
        }
      }
    },
    get language() {
      return language;
    }
  };

  if(!document.documentElement.hasAttribute("data-i18n-disable-auto")) {
    global.i18n.translateAll();
  }
}(this));
<commit_msg>Add translate method to translations<commit_after>(function (global) {
  "use strict";

  var languageDialect = (function(lang) {
        window.location.search.slice(1).split("&").some(function (searchTerm) {
          if (searchTerm.indexOf("lang=") === 0) {
            lang = searchTerm.split("=").slice(1).join("=");
            return true;
          }
        });

        return lang.toLowerCase();
      })(window.navigator.userLanguage || window.navigator.language),
      language = languageDialect.split("-")[0],
      Translations = (function() {
        var scope = "_scope";

        function Translations(o) {
          this[scope] = o;
        }

        Translations.prototype.find = function(path) {
          return path.split(".").reduce(function (obj, key) {
            return obj ? obj[key] : undefined;
          }, this[scope]);
        };

        Translations.prototype.translate = function(ele) {
          if(getLang(ele) === languageDialect) {
            if(!ele.hasAttribute("data-i18n")) {
              [].slice.call(ele.querySelectorAll("[lang]:not([lang='" + language + "'])")).forEach(this.translate.bind(this));
            }
          } else if(ele.hasAttribute("data-i18n")) {
            applyTranslationToElement(ele, this);
          } else {
            [].slice.call(ele.querySelectorAll("[data-i18n]")).map(function(match) {
              if(getLang(match, ele) !== languageDialect) {
                applyTranslationToElement(match, this);
              }
            });
          }

          return ele;
        };

        return Translations;
      }());

  function applyTranslationToElement(ele, obj) {
    if(ele.hasAttribute("data-i18n")) {
      applyTranslation(ele, ele.getAttribute("data-i18n"), obj);
    }
  }

  function applyTranslation(ele, path, obj) {
    var translated = obj.find(path);

    if (typeof(translated) === "object" && !Array.isArray(translated)) {
      console.warn("Could not translate %o: path '%s' is of type object", ele, path);
    } else if(typeof(translated) !== "undefined") {
      clean(ele);
      ele.appendChild(toDom(translated));
      ele.lang = language;
    }
  }

  function getLang(ele, threshold) {
    do {
      if(ele.lang) {
        return ele.lang.toLowerCase();
      }
    } while((ele = ele.parentElement) && ele !== threshold);
  }

  function clean(ele) {
    var child;
    while((child = ele.firstChild)) {
      ele.removeChild(child);
    }
  }

  function toDom(content) {
    if(Array.isArray(content)) {
      return content.reduce(function(frag, text) {
        var ele = document.createElement("p");
        ele.textContent = text;
        frag.appendChild(ele);

        return frag;
      }, document.createDocumentFragment());
    }
    return document.createTextNode(content);
  }

  global.i18n = {
    base: (document.documentElement.getAttribute("data-i18n-base") || "locales/"),
    set: (document.documentElement.getAttribute("data-i18n-set") || "translation"),
    loadTranslations: function(lang, set, base) {
      var url = (base || this.base || "") + (lang || language) + "/" + (set || this.set) + ".json";
      console.info("loading translations from: " + url);

      return fetch(url, {
        headers: {
          "Accept": "application/json"
        }
      }).then(function (res) {
        if (res.status >= 200 && res.status < 300) {
          console.info("successfully loaded translations");

          return res.json().then(function(obj) {
            return new Translations(obj);
          });
        }

        // TODO add error object instead of false
        return Promise.reject(false);
      }).catch(function (err) {
        console.error("Error loading translations: %o", err);
      });
    },
    translate: function(ele) {
      if(!this.translations) {
        this.translations = this.loadTranslations();
      }

      return this.translations.then(function(translations) {
        return translations.translate(ele);
      });
    },
    translateAll: function() {
      this.translatedAll = true;
      return this.translate(document.documentElement);
    },
    set language(lang) {
      lang = String(lang);

      if(lang !== language) {
        language = lang;

        if(this.translatedAll) {
          this.translateAll(lang);
        } else if(this.translations) {
          this.translations = this.loadTranslations();
        }
      }
    },
    get language() {
      return language;
    }
  };

  if(!document.documentElement.hasAttribute("data-i18n-disable-auto")) {
    global.i18n.translateAll();
  }
}(this));
<|endoftext|>


<commit_before>(function (window) {
    'use strict';

    // make sure xEasy is running in a browser
    if(!window || !window.document) {
        throw 'No window object found! Make sure xEasy is running in a browser.';
    }

    // load modules
    var xe = {};
    xe.functions = require('./functions');
    xe.domParser = require('./domParser');
    xe.init = require('./core').init;
    xe.binding = require('./binding');
    xe.ctrl = require('./controllers');

    // when all is loaded, wire up the controllers
    window.onload = function() {
        xe.init();
    };

    window.xe = xe;
}(window));<commit_msg>Changed the onload of xEasy<commit_after>(function(window) {
    'use strict';

    // make sure xEasy is running in a browser
    if(!window || !window.document) {
        throw 'No window object found! Make sure xEasy is running in a browser.';
    }

    // load modules
    var xe = {};
    xe.functions = require('./functions');
    xe.domParser = require('./domParser');
    xe.init = require('./core').init;
    xe.binding = require('./binding');
    xe.ctrl = require('./controllers');

    // when all is loaded, wire up the controllers
    window.document.addEventListener("DOMContentLoaded", function() {
        xe.init();
    }, false);

    window.xe = xe;
}(window));<|endoftext|>


<commit_before>// require styles
import 'bootstrap/dist/css/bootstrap.min.css';

import $ from 'jquery';
import 'jquery-ui';
import es6Promise from 'es6-promise';

import i18next from 'i18next';
import _ from 'underscore';
import Backbone from 'backbone';
import Marionette from 'backbone.marionette';

import LayersCollection from 'eoxc/src/core/models/LayersCollection';
import MapModel from 'eoxc/src/core/models/MapModel';
import FiltersModel from 'eoxc/src/core/models/FiltersModel';
import HighlightModel from 'eoxc/src/core/models/HighlightModel';

import TimeSliderView from 'eoxc/src/core/views/TimeSliderView';
import LayerControlLayoutView from 'eoxc/src/core/views/layers/LayerControlLayoutView';

import SearchResultView from 'eoxc/src/search/views/SearchResultView';
import SearchModel from 'eoxc/src/search/models/SearchModel';
import { getParameters } from 'eoxc/src/search';

import DownloadOptionsModel from 'eoxc/src/download/models/DownloadOptionsModel';
import DownloadSelectionView from 'eoxc/src/download/views/DownloadSelectionView';
import DownloadOptionsModalView from 'eoxc/src/download/views/DownloadOptionsModalView';
import download from 'eoxc/src/download';

import OpenLayersMapView from 'eoxc/src/contrib/OpenLayers/OpenLayersMapView';

import RootLayoutView from './views/RootLayoutView';

import RootFiltersView from './views/filters/RootFiltersView';
import SidePanelView from './views/SidePanelView';
import StopSelectionView from './views/StopSelectionView';
import WarningsView from './views/WarningsView';
import RecordsDetailsModalView from './views/RecordsDetailsModalView';

import WarningsCollection from './models/WarningsCollection';

import VendorInfoView from './views/VendorInfoView';

import 'imports?jQuery=jquery!bootstrap/dist/js/bootstrap.min.js';

import getTutorialWidget from './tutorial';
import { premultiplyColor } from './utils';

// import './static/code-de.css';
import './_client.scss';

es6Promise.polyfill();

const germanFormalTranslation = require('./languages/de.json');
const germanInformalTranslation = require('./languages/deinformal.json');
const englishTranslation = require('./languages/en.json');

function combineParameter(setting, param) {
  const options = setting.options || param.options;
  return {
    type: param.type,
    name: param.name,
    mandatory: setting.mandatory || param.mandatory,
    options,
    minExclusive: param.minExclusive,
    maxExclusive: param.maxExclusive,
    minInclusive: param.minInclusive,
    maxInclusive: param.maxInclusive,
    range: setting.range,
    min: setting.min,
    max: setting.max,
  };
}

window.Application = Marionette.Application.extend({
  initialize({ config, configPath, container, navbarTemplate }) {
    this.config = config;
    this.configPath = configPath;
    this.container = container;
    this.navbarTemplate = navbarTemplate;
  },

  onStart() {
    if (this.config) {
      this.onConfigLoaded(this.config);
    } else {
      $.getJSON(this.configPath, (config) => {
        this.onConfigLoaded(config);
      });
    }
  },

  onConfigLoaded(config) {
    this.config = config;
    i18next.init({
      lng: this.config.settings.language || 'en',
      fallbackLng: 'en',
      resources: {
        'de': {
          translation: germanFormalTranslation,
        },
        'deinformal': {
          translation: germanInformalTranslation,
        },
        'en': {
          translation: englishTranslation,
        },
      },
    }, () => {
      this.onI18NextInitialized(config);
    });
  },

  onI18NextInitialized(config) {
    // TODO: check parameters

    const baseLayersCollection = new LayersCollection(config.baseLayers, {
      exclusiveVisibility: true,
    });
    const layersCollection = new LayersCollection(config.layers);
    const overlayLayersCollection = new LayersCollection(config.overlayLayers);

    if (config.settings.parameters) {
      const parameterPromises = layersCollection
        .filter(layerModel => layerModel.get('search.protocol'))
        .map(layerModel => getParameters(layerModel).then(parameters => [layerModel, parameters]));
      Promise.all(parameterPromises)
        .then((layersPlusParameters) => {
          const params = config.settings.parameters
            .map(param => [
              param, layersPlusParameters.filter(layerPlusParameters => (
                layerPlusParameters[1].find(p => p.type === param.type)
              )),
            ])

            // filter out the parameters that are nowhere available
            .filter(paramPlusApplicableLayers => paramPlusApplicableLayers[1].length)

            // combine the parameter settings info with the info from the search services
            .map((paramPlusApplicableLayers) => {
              let param = paramPlusApplicableLayers[0];
              for (let i = 0; i < paramPlusApplicableLayers[1].length; i += 1) {
                const [, layerParameters] = paramPlusApplicableLayers[1][i];
                param = combineParameter(
                  param, layerParameters.find(p => p.type === param.type)
                );
              }
              if (paramPlusApplicableLayers[1].length < layersCollection.length) {
                param.onlyAvailableAt = paramPlusApplicableLayers[1].map(layerPlusParameters => (
                  layerPlusParameters[0].get('displayName')
                ));
              }
              return param;
            });

          // const params = [].concat.apply([], extraParameters)
          //   .filter(param => param.type.startsWith('eo:'))
          //   .map((param) => {
          //     const paramSetting = config.settings.parameters[param.type];
          //     if (paramSetting) {
          //       return {
          //         type: param.type,
          //         name: param.name,
          //         mandatory: param.mandatory,
          //         options: param.options,
          //         minExclusive: param.minExclusive,
          //         maxExclusive: param.maxExclusive,
          //         minInclusive: param.minInclusive,
          //         maxInclusive: param.maxInclusive,
          //         ...paramSetting,
          //       };
          //     }
          //     return param;
          //   });

          this.onRun(
            config, baseLayersCollection, layersCollection, overlayLayersCollection, params
          );
        });
    } else {
      this.onRun(config, baseLayersCollection, layersCollection, overlayLayersCollection, []);
    }
  },

  onRun(config, baseLayersCollection, layersCollection, overlayLayersCollection, extraParameters) {
    const settings = config.settings;

    _.defaults(settings, {
      center: [0, 0],
      zoom: 2,
      minZoom: 0,
      maxZoom: 28,
      searchDebounceTime: 250,
      constrainTimeDomain: false,
      displayInterval: null,
      selectableInterval: null,
      maxTooltips: null,
      timeSliderControls: false,
      highlightFillColor: 'rgba(255, 255, 255, 0.2)',
      highlightStrokeColor: '#cccccc',
      highlightStrokeWidth: 1,
      filterFillColor: 'rgba(0, 165, 255, 0)',
      filterStrokeColor: 'rgba(0, 165, 255, 1)',
      filterOutsideColor: 'rgba(0, 0, 0, 0.5)',
      footprintFillColor: 'rgba(255, 255, 255, 0.2)',
      footprintStrokeColor: '#cccccc',
      selectedFootprintFillColor: 'rgba(255, 0, 0, 0.2)',
      selectedFootprintStrokeColor: '#ff0000',
      leftPanelOpen: false,
      rightPanelOpen: false,
      downloadFormats: [],
      downloadProjections: [],
    });

    // set up config
    const mapModel = new MapModel({
      center: settings.center,
      zoom: settings.zoom,
      minZoom: settings.minZoom,
      maxZoom: settings.maxZoom,
      time: [
        new Date(settings.selectedTimeDomain[0]),
        new Date(settings.selectedTimeDomain[1]),
      ],
    });
    const filtersModel = new FiltersModel({ });
    const highlightModel = new HighlightModel();

    const searchModels = layersCollection
      .filter(layerModel => layerModel.get('search.protocol'))
      .map(layerModel => new SearchModel({
        layerModel,
        filtersModel,
        mapModel,
        defaultPageSize: 50,
        maxCount: layerModel.get('search.searchLimit'),
        debounceTime: settings.searchDebounceTime,
      }));
    const searchCollection = new Backbone.Collection(searchModels);

    // set up layout
    const layout = new RootLayoutView({
      el: $(this.container),
      mapModel,
      searchCollection,
    });
    layout.render();

    const domain = {
      start: new Date(settings.timeDomain[0]),
      end: new Date(settings.timeDomain[1]),
    };
    const display = settings.displayTimeDomain ? {
      start: new Date(settings.displayTimeDomain[0]),
      end: new Date(settings.displayTimeDomain[1]),
    } : domain;

    layout.showChildView('timeSlider', new TimeSliderView({
      layersCollection,
      mapModel,
      filtersModel,
      highlightModel,
      highlightFillColor: settings.highlightFillColor,
      highlightStrokeColor: settings.highlightStrokeColor,
      filterFillColor: settings.filterFillColor,
      filterStrokeColor: settings.filterStrokeColor,
      filterOutsideColor: settings.filterOutsideColor,
      domain,
      display,
      constrainTimeDomain: settings.constrainTimeDomain,
      timeSliderControls: settings.timeSliderControls,
      displayInterval: settings.displayInterval,
      selectableInterval: settings.selectableInterval,
      maxTooltips: settings.maxTooltips,
    }));

    // set up panels

    const startDownload = (records) => {
      layout.showChildView('modals', new DownloadOptionsModalView({
        records,
        searchCollection,
        filtersModel,
        mapModel,
        model: new DownloadOptionsModel({
          availableDownloadFormats: settings.downloadFormats,
          availableProjections: settings.downloadProjections,
        }),
      }));
    };

    const showRecordDetails = (records) => {
      layout.showChildView('modals', new RecordsDetailsModalView({
        baseLayersCollection,
        overlayLayersCollection,
        layersCollection,
        records,
        highlightFillColor: settings.highlightFillColor,
        highlightStrokeColor: settings.highlightStrokeColor,
        filterFillColor: settings.filterFillColor,
        filterStrokeColor: settings.filterStrokeColor,
        filterOutsideColor: settings.filterOutsideColor,
        onStartDownload: startDownload,
      }));
    };

    layout.showChildView('content', new OpenLayersMapView({
      mapModel,
      filtersModel,
      baseLayersCollection,
      overlayLayersCollection,
      layersCollection,
      searchCollection,
      highlightModel,
      highlightFillColor: settings.highlightFillColor,
      highlightStrokeColor: settings.highlightStrokeColor,
      highlightStrokeWidth: settings.highlightStrokeWidth,
      filterFillColor: settings.filterFillColor,
      filterStrokeColor: settings.filterStrokeColor,
      filterOutsideColor: settings.filterOutsideColor,
      footprintFillColor: settings.footprintFillColor,
      footprintStrokeColor: settings.footprintStrokeColor,
      selectedFootprintFillColor: settings.selectedFootprintFillColor,
      selectedFootprintStrokeColor: settings.selectedFootprintStrokeColor,
      onFeatureClicked(records) {
        showRecordDetails(records);
      },
    }));

    layout.showChildView('leftPanel', new SidePanelView({
      position: 'left',
      icon: 'fa-cog',
      defaultOpen: settings.leftPanelOpen,
      views: [{
        name: 'Filters',
        view: new RootFiltersView({
          filtersModel,
          mapModel,
          highlightModel,
          layersCollection,
          extraParameters,
        }),
      }, {
        name: 'Layers',
        view: new LayerControlLayoutView({
          mapModel,
          filtersModel,
          baseLayersCollection,
          overlayLayersCollection,
          layersCollection,
        }),
      }],
    }));

    layout.showChildView('rightPanel', new SidePanelView({
      position: 'right',
      icon: 'fa-list',
      defaultOpen: settings.rightPanelOpen,
      views: [{
        name: 'Search Results',
        hasInfo: true,
        view: new SearchResultView({
          mapModel,
          filtersModel,
          highlightModel,
          collection: searchCollection,
        }),
      }, {
        name: 'Download',
        hasInfo: true,
        view: new DownloadSelectionView({
          filtersModel,
          highlightModel,
          collection: searchCollection,
          onStartDownload: startDownload,
          termsAndConditionsUrl: settings.termsAndConditionsUrl,
        }),
      }],
    }));

    // hook up record info modal
    searchCollection.each((searchModel) => {
      searchModel.on('showInfo', (recordModels) => {
        showRecordDetails(
          recordModels.map(recordModel => [recordModel, searchModel])
        );
      });
    });

    layout.showChildView('bottomPanel', new StopSelectionView({ mapModel }));

    const warningsCollection = new WarningsCollection([]);
    layout.showChildView('topPanel', new WarningsView({ collection: warningsCollection }));

    // hook up the events that shall generate warnings
    filtersModel.on('change', () => {
      // show warning when time filter is set
      warningsCollection.setWarning(
        i18next.t('timefilter_warning'),
        filtersModel.get('time') || false
      );

      const otherFilters = Object.keys(filtersModel.attributes)
        .filter(key => key !== 'time' && key !== 'area');
      warningsCollection.setWarning(
        i18next.t('advancedfilter_warning'),
        otherFilters.length
      );
    });

    searchCollection.on('change', () => {
      const show = searchCollection
        .filter(searchModel => (
          !searchModel.get('isSearching') && !searchModel.get('hasError')
        ))
        .reduce((acc, searchModel) => (
          acc || searchModel.get('totalResults') > searchModel.get('hasLoaded')
        ), false);
      warningsCollection.setWarning(i18next.t('toomanyresults_warning'), show);
    });

    if (settings.extent) {
      mapModel.show({ bbox: settings.extent });
    }

    // create a dynamic style to set up the border/background color of record
    // items in the search results and download selection view.

    $(`
    `).appendTo('head');

    layout.showChildView('infoPanel', new VendorInfoView({}));

    if (settings.hasOwnProperty('tutorial')) {
      if (settings.tutorial !== 'disabled') {
        const tutWidg = getTutorialWidget();

        if (settings.tutorial !== 'disabled') {
          $('.ol-attribution').append(
          `<button type="button" title="${i18next.t('Tutorial')}" id="tutorial" style="float:right;">

          </button>`);

          $('#tutorial').click(() => {
            // Iterate through anno elements to see if any is open and needs to
            // be closed
            /* eslint-disable no-underscore-dangle */
            let cv = tutWidg;
            while (cv._chainNext) {
              if (cv._annoElem) {
                cv.hide();
              }
              cv = cv._chainNext;
            }
            /* eslint-enable no-underscore-dangle */
            tutWidg.show();
          });
        }

        if (settings.tutorial === 'always') {
          tutWidg.show();
        }

        if (settings.tutorial === 'once') {
          if (typeof (Storage) !== 'undefined') {
            if (localStorage.getItem('firstVisit') === null) {
              // Open tutorial automatically if it is the first visit
              tutWidg.show();
              localStorage.setItem('firstVisit', false);
            }
          }
        }
      }
    }
    Backbone.history.start({ pushState: false });
  },
});
<commit_msg>Disabling warning when advanced filters are set.<commit_after>// require styles
import 'bootstrap/dist/css/bootstrap.min.css';

import $ from 'jquery';
import 'jquery-ui';
import es6Promise from 'es6-promise';

import i18next from 'i18next';
import _ from 'underscore';
import Backbone from 'backbone';
import Marionette from 'backbone.marionette';

import LayersCollection from 'eoxc/src/core/models/LayersCollection';
import MapModel from 'eoxc/src/core/models/MapModel';
import FiltersModel from 'eoxc/src/core/models/FiltersModel';
import HighlightModel from 'eoxc/src/core/models/HighlightModel';

import TimeSliderView from 'eoxc/src/core/views/TimeSliderView';
import LayerControlLayoutView from 'eoxc/src/core/views/layers/LayerControlLayoutView';

import SearchResultView from 'eoxc/src/search/views/SearchResultView';
import SearchModel from 'eoxc/src/search/models/SearchModel';
import { getParameters } from 'eoxc/src/search';

import DownloadOptionsModel from 'eoxc/src/download/models/DownloadOptionsModel';
import DownloadSelectionView from 'eoxc/src/download/views/DownloadSelectionView';
import DownloadOptionsModalView from 'eoxc/src/download/views/DownloadOptionsModalView';
import download from 'eoxc/src/download';

import OpenLayersMapView from 'eoxc/src/contrib/OpenLayers/OpenLayersMapView';

import RootLayoutView from './views/RootLayoutView';

import RootFiltersView from './views/filters/RootFiltersView';
import SidePanelView from './views/SidePanelView';
import StopSelectionView from './views/StopSelectionView';
import WarningsView from './views/WarningsView';
import RecordsDetailsModalView from './views/RecordsDetailsModalView';

import WarningsCollection from './models/WarningsCollection';

import VendorInfoView from './views/VendorInfoView';

import 'imports?jQuery=jquery!bootstrap/dist/js/bootstrap.min.js';

import getTutorialWidget from './tutorial';
import { premultiplyColor } from './utils';

// import './static/code-de.css';
import './_client.scss';

es6Promise.polyfill();

const germanFormalTranslation = require('./languages/de.json');
const germanInformalTranslation = require('./languages/deinformal.json');
const englishTranslation = require('./languages/en.json');

function combineParameter(setting, param) {
  const options = setting.options || param.options;
  return {
    type: param.type,
    name: param.name,
    mandatory: setting.mandatory || param.mandatory,
    options,
    minExclusive: param.minExclusive,
    maxExclusive: param.maxExclusive,
    minInclusive: param.minInclusive,
    maxInclusive: param.maxInclusive,
    range: setting.range,
    min: setting.min,
    max: setting.max,
  };
}

window.Application = Marionette.Application.extend({
  initialize({ config, configPath, container, navbarTemplate }) {
    this.config = config;
    this.configPath = configPath;
    this.container = container;
    this.navbarTemplate = navbarTemplate;
  },

  onStart() {
    if (this.config) {
      this.onConfigLoaded(this.config);
    } else {
      $.getJSON(this.configPath, (config) => {
        this.onConfigLoaded(config);
      });
    }
  },

  onConfigLoaded(config) {
    this.config = config;
    i18next.init({
      lng: this.config.settings.language || 'en',
      fallbackLng: 'en',
      resources: {
        'de': {
          translation: germanFormalTranslation,
        },
        'deinformal': {
          translation: germanInformalTranslation,
        },
        'en': {
          translation: englishTranslation,
        },
      },
    }, () => {
      this.onI18NextInitialized(config);
    });
  },

  onI18NextInitialized(config) {
    // TODO: check parameters

    const baseLayersCollection = new LayersCollection(config.baseLayers, {
      exclusiveVisibility: true,
    });
    const layersCollection = new LayersCollection(config.layers);
    const overlayLayersCollection = new LayersCollection(config.overlayLayers);

    if (config.settings.parameters) {
      const parameterPromises = layersCollection
        .filter(layerModel => layerModel.get('search.protocol'))
        .map(layerModel => getParameters(layerModel).then(parameters => [layerModel, parameters]));
      Promise.all(parameterPromises)
        .then((layersPlusParameters) => {
          const params = config.settings.parameters
            .map(param => [
              param, layersPlusParameters.filter(layerPlusParameters => (
                layerPlusParameters[1].find(p => p.type === param.type)
              )),
            ])

            // filter out the parameters that are nowhere available
            .filter(paramPlusApplicableLayers => paramPlusApplicableLayers[1].length)

            // combine the parameter settings info with the info from the search services
            .map((paramPlusApplicableLayers) => {
              let param = paramPlusApplicableLayers[0];
              for (let i = 0; i < paramPlusApplicableLayers[1].length; i += 1) {
                const [, layerParameters] = paramPlusApplicableLayers[1][i];
                param = combineParameter(
                  param, layerParameters.find(p => p.type === param.type)
                );
              }
              if (paramPlusApplicableLayers[1].length < layersCollection.length) {
                param.onlyAvailableAt = paramPlusApplicableLayers[1].map(layerPlusParameters => (
                  layerPlusParameters[0].get('displayName')
                ));
              }
              return param;
            });

          // const params = [].concat.apply([], extraParameters)
          //   .filter(param => param.type.startsWith('eo:'))
          //   .map((param) => {
          //     const paramSetting = config.settings.parameters[param.type];
          //     if (paramSetting) {
          //       return {
          //         type: param.type,
          //         name: param.name,
          //         mandatory: param.mandatory,
          //         options: param.options,
          //         minExclusive: param.minExclusive,
          //         maxExclusive: param.maxExclusive,
          //         minInclusive: param.minInclusive,
          //         maxInclusive: param.maxInclusive,
          //         ...paramSetting,
          //       };
          //     }
          //     return param;
          //   });

          this.onRun(
            config, baseLayersCollection, layersCollection, overlayLayersCollection, params
          );
        });
    } else {
      this.onRun(config, baseLayersCollection, layersCollection, overlayLayersCollection, []);
    }
  },

  onRun(config, baseLayersCollection, layersCollection, overlayLayersCollection, extraParameters) {
    const settings = config.settings;

    _.defaults(settings, {
      center: [0, 0],
      zoom: 2,
      minZoom: 0,
      maxZoom: 28,
      searchDebounceTime: 250,
      constrainTimeDomain: false,
      displayInterval: null,
      selectableInterval: null,
      maxTooltips: null,
      timeSliderControls: false,
      highlightFillColor: 'rgba(255, 255, 255, 0.2)',
      highlightStrokeColor: '#cccccc',
      highlightStrokeWidth: 1,
      filterFillColor: 'rgba(0, 165, 255, 0)',
      filterStrokeColor: 'rgba(0, 165, 255, 1)',
      filterOutsideColor: 'rgba(0, 0, 0, 0.5)',
      footprintFillColor: 'rgba(255, 255, 255, 0.2)',
      footprintStrokeColor: '#cccccc',
      selectedFootprintFillColor: 'rgba(255, 0, 0, 0.2)',
      selectedFootprintStrokeColor: '#ff0000',
      leftPanelOpen: false,
      rightPanelOpen: false,
      downloadFormats: [],
      downloadProjections: [],
    });

    // set up config
    const mapModel = new MapModel({
      center: settings.center,
      zoom: settings.zoom,
      minZoom: settings.minZoom,
      maxZoom: settings.maxZoom,
      time: [
        new Date(settings.selectedTimeDomain[0]),
        new Date(settings.selectedTimeDomain[1]),
      ],
    });
    const filtersModel = new FiltersModel({ });
    const highlightModel = new HighlightModel();

    const searchModels = layersCollection
      .filter(layerModel => layerModel.get('search.protocol'))
      .map(layerModel => new SearchModel({
        layerModel,
        filtersModel,
        mapModel,
        defaultPageSize: 50,
        maxCount: layerModel.get('search.searchLimit'),
        debounceTime: settings.searchDebounceTime,
      }));
    const searchCollection = new Backbone.Collection(searchModels);

    // set up layout
    const layout = new RootLayoutView({
      el: $(this.container),
      mapModel,
      searchCollection,
    });
    layout.render();

    const domain = {
      start: new Date(settings.timeDomain[0]),
      end: new Date(settings.timeDomain[1]),
    };
    const display = settings.displayTimeDomain ? {
      start: new Date(settings.displayTimeDomain[0]),
      end: new Date(settings.displayTimeDomain[1]),
    } : domain;

    layout.showChildView('timeSlider', new TimeSliderView({
      layersCollection,
      mapModel,
      filtersModel,
      highlightModel,
      highlightFillColor: settings.highlightFillColor,
      highlightStrokeColor: settings.highlightStrokeColor,
      filterFillColor: settings.filterFillColor,
      filterStrokeColor: settings.filterStrokeColor,
      filterOutsideColor: settings.filterOutsideColor,
      domain,
      display,
      constrainTimeDomain: settings.constrainTimeDomain,
      timeSliderControls: settings.timeSliderControls,
      displayInterval: settings.displayInterval,
      selectableInterval: settings.selectableInterval,
      maxTooltips: settings.maxTooltips,
    }));

    // set up panels

    const startDownload = (records) => {
      layout.showChildView('modals', new DownloadOptionsModalView({
        records,
        searchCollection,
        filtersModel,
        mapModel,
        model: new DownloadOptionsModel({
          availableDownloadFormats: settings.downloadFormats,
          availableProjections: settings.downloadProjections,
        }),
      }));
    };

    const showRecordDetails = (records) => {
      layout.showChildView('modals', new RecordsDetailsModalView({
        baseLayersCollection,
        overlayLayersCollection,
        layersCollection,
        records,
        highlightFillColor: settings.highlightFillColor,
        highlightStrokeColor: settings.highlightStrokeColor,
        filterFillColor: settings.filterFillColor,
        filterStrokeColor: settings.filterStrokeColor,
        filterOutsideColor: settings.filterOutsideColor,
        onStartDownload: startDownload,
      }));
    };

    layout.showChildView('content', new OpenLayersMapView({
      mapModel,
      filtersModel,
      baseLayersCollection,
      overlayLayersCollection,
      layersCollection,
      searchCollection,
      highlightModel,
      highlightFillColor: settings.highlightFillColor,
      highlightStrokeColor: settings.highlightStrokeColor,
      highlightStrokeWidth: settings.highlightStrokeWidth,
      filterFillColor: settings.filterFillColor,
      filterStrokeColor: settings.filterStrokeColor,
      filterOutsideColor: settings.filterOutsideColor,
      footprintFillColor: settings.footprintFillColor,
      footprintStrokeColor: settings.footprintStrokeColor,
      selectedFootprintFillColor: settings.selectedFootprintFillColor,
      selectedFootprintStrokeColor: settings.selectedFootprintStrokeColor,
      onFeatureClicked(records) {
        showRecordDetails(records);
      },
    }));

    layout.showChildView('leftPanel', new SidePanelView({
      position: 'left',
      icon: 'fa-cog',
      defaultOpen: settings.leftPanelOpen,
      views: [{
        name: 'Filters',
        view: new RootFiltersView({
          filtersModel,
          mapModel,
          highlightModel,
          layersCollection,
          extraParameters,
        }),
      }, {
        name: 'Layers',
        view: new LayerControlLayoutView({
          mapModel,
          filtersModel,
          baseLayersCollection,
          overlayLayersCollection,
          layersCollection,
        }),
      }],
    }));

    layout.showChildView('rightPanel', new SidePanelView({
      position: 'right',
      icon: 'fa-list',
      defaultOpen: settings.rightPanelOpen,
      views: [{
        name: 'Search Results',
        hasInfo: true,
        view: new SearchResultView({
          mapModel,
          filtersModel,
          highlightModel,
          collection: searchCollection,
        }),
      }, {
        name: 'Download',
        hasInfo: true,
        view: new DownloadSelectionView({
          filtersModel,
          highlightModel,
          collection: searchCollection,
          onStartDownload: startDownload,
          termsAndConditionsUrl: settings.termsAndConditionsUrl,
        }),
      }],
    }));

    // hook up record info modal
    searchCollection.each((searchModel) => {
      searchModel.on('showInfo', (recordModels) => {
        showRecordDetails(
          recordModels.map(recordModel => [recordModel, searchModel])
        );
      });
    });

    layout.showChildView('bottomPanel', new StopSelectionView({ mapModel }));

    const warningsCollection = new WarningsCollection([]);
    layout.showChildView('topPanel', new WarningsView({ collection: warningsCollection }));

    // hook up the events that shall generate warnings
    filtersModel.on('change', () => {
      // show warning when time filter is set
      warningsCollection.setWarning(
        i18next.t('timefilter_warning'),
        filtersModel.get('time') || false
      );

      // const otherFilters = Object.keys(filtersModel.attributes)
      //   .filter(key => key !== 'time' && key !== 'area');
      // warningsCollection.setWarning(
      //   i18next.t('advancedfilter_warning'),
      //   otherFilters.length
      // );
    });

    searchCollection.on('change', () => {
      const show = searchCollection
        .filter(searchModel => (
          !searchModel.get('isSearching') && !searchModel.get('hasError')
        ))
        .reduce((acc, searchModel) => (
          acc || searchModel.get('totalResults') > searchModel.get('hasLoaded')
        ), false);
      warningsCollection.setWarning(i18next.t('toomanyresults_warning'), show);
    });

    if (settings.extent) {
      mapModel.show({ bbox: settings.extent });
    }

    // create a dynamic style to set up the border/background color of record
    // items in the search results and download selection view.

    $(`
    `).appendTo('head');

    layout.showChildView('infoPanel', new VendorInfoView({}));

    if (settings.hasOwnProperty('tutorial')) {
      if (settings.tutorial !== 'disabled') {
        const tutWidg = getTutorialWidget();

        if (settings.tutorial !== 'disabled') {
          $('.ol-attribution').append(
          `<button type="button" title="${i18next.t('Tutorial')}" id="tutorial" style="float:right;">

          </button>`);

          $('#tutorial').click(() => {
            // Iterate through anno elements to see if any is open and needs to
            // be closed
            /* eslint-disable no-underscore-dangle */
            let cv = tutWidg;
            while (cv._chainNext) {
              if (cv._annoElem) {
                cv.hide();
              }
              cv = cv._chainNext;
            }
            /* eslint-enable no-underscore-dangle */
            tutWidg.show();
          });
        }

        if (settings.tutorial === 'always') {
          tutWidg.show();
        }

        if (settings.tutorial === 'once') {
          if (typeof (Storage) !== 'undefined') {
            if (localStorage.getItem('firstVisit') === null) {
              // Open tutorial automatically if it is the first visit
              tutWidg.show();
              localStorage.setItem('firstVisit', false);
            }
          }
        }
      }
    }
    Backbone.history.start({ pushState: false });
  },
});
<|endoftext|>


<commit_before>/**
 * get-currency
 * Copyright (c) 2014 Johnie Hjelm
 */

/*-------------------------------------------------------------------
  Required modules
-------------------------------------------------------------------*/

var currencySymbols = require('./dist/symbols.json');

/*-------------------------------------------------------------------
  Get symbol
-------------------------------------------------------------------*/

function getCurrency( currencyCode ) {

  if ( currencySymbols.hasOwnProperty( currencyCode ) ) {

    return currencySymbols[currencyCode];

  } else {

    return '?';

  }

}
<commit_msg>Fixed issue with module export<commit_after>/**
 * get-currency
 * Copyright (c) 2014 Johnie Hjelm
 */

/*-------------------------------------------------------------------
  Required modules
-------------------------------------------------------------------*/

var currencySymbols = require('./dist/symbols.json');

/*-------------------------------------------------------------------
  Get symbol
-------------------------------------------------------------------*/
(function () {
  'use strict';

  var getCurrency = function( currencyCode ) {

    if ( currencySymbols.hasOwnProperty( currencyCode ) ) {

      return currencySymbols[currencyCode];

    } else {

      return '?';

    }

  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = getCurrency;
  } else {
    window.getCurrency = getCurrency;
  }

})();
<|endoftext|>