<commit_before>const xtend = require('xtend');
const Constants = require('./constants');

const classTypes = ['mode', 'feature', 'mouse'];

module.exports = function(ctx) {

  const buttonElements = {};
  let activeButton = null;

  let currentMapClasses = {
    mode: null, // e.g. mode-direct_select
    feature: null, // e.g. feature-vertex
    mouse: null // e.g. mouse-move
  };

  let nextMapClasses = {
    mode: null,
    feature: null,
    mouse: null
  };

  function queueMapClasses(options) {
    nextMapClasses = xtend(nextMapClasses, options);
  }

  function updateMapClasses() {
    if (!ctx.container) return;

    const classesToRemove = [];
    const classesToAdd = [];

    classTypes.forEach((type) => {
      if (nextMapClasses[type] === currentMapClasses[type]) return;

      classesToRemove.push(`${type}-${currentMapClasses[type]}`);
      if (nextMapClasses[type] !== null) {
        classesToAdd.push(`${type}-${nextMapClasses[type]}`);
      }
    });

    if (classesToRemove.length > 0) {
      ctx.container.classList.remove.apply(ctx.container.classList, classesToRemove);
    }

    if (classesToAdd.length > 0) {
      ctx.container.classList.add.apply(ctx.container.classList, classesToAdd);
    }

    currentMapClasses = xtend(currentMapClasses, nextMapClasses);
  }

  function createControlButton(id, options = {}) {
    const button = document.createElement('button');
    button.className = `${Constants.classes.CONTROL_BUTTON} ${options.className}`;
    button.setAttribute('title', options.title);
    options.container.appendChild(button);

    button.addEventListener('click', (e) => {
      e.preventDefault();
      e.stopPropagation();

      const clickedButton = e.target;
      if (clickedButton === activeButton) {
        deactivateButtons();
        return;
      }

      setActiveButton(id);
      options.onActivate();
    }, true);

    return button;
  }

  function deactivateButtons() {
    if (!activeButton) return;
    activeButton.classList.remove(Constants.classes.ACTIVE_BUTTON);
    activeButton = null;
  }

  function setActiveButton(id) {
    deactivateButtons();

    const button = buttonElements[id];
    if (!button) return;

    if (button && id !== 'trash') {
      button.classList.add(Constants.classes.ACTIVE_BUTTON);
      activeButton = button;
    }
  }

  function addButtons() {
    const controls = ctx.options.controls;
    const controlGroup = document.createElement('div');
    controlGroup.className = `${Constants.classes.CONTROL_GROUP} ${Constants.classes.CONTROL_BASE}`;

    if (!controls) return controlGroup;

    if (controls[Constants.types.LINE]) {
      buttonElements[Constants.types.LINE] = createControlButton(Constants.types.LINE, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_LINE,
        title: `LineString tool ${ctx.options.keybindings && '(l)'}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_LINE_STRING)
      });
    }

    if (controls[Constants.types.POLYGON]) {
      buttonElements[Constants.types.POLYGON] = createControlButton(Constants.types.POLYGON, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_POLYGON,
        title: `Polygon tool ${ctx.options.keybindings && '(p)'}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POLYGON)
      });
    }

    if (controls[Constants.types.POINT]) {
      buttonElements[Constants.types.POINT] = createControlButton(Constants.types.POINT, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_POINT,
        title: `Marker tool ${ctx.options.keybindings && '(m)'}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POINT)
      });
    }

    if (controls.trash) {
      buttonElements.trash = createControlButton('trash', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_TRASH,
        title: 'Delete',
        onActivate: () => {
          ctx.events.trash();
        }
      });
    }

    if (controls.combine_features) {
      buttonElements.combine_features = createControlButton('combineFeatures', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_COMBINE_FEATURES,
        title: 'Combine',
        onActivate: () => {
          ctx.events.combineFeatures();
        }
      });
    }

    if (controls.uncombine_features) {
      buttonElements.uncombine_features = createControlButton('uncombineFeatures', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_UNCOMBINE_FEATURES,
        title: 'Uncombine',
        onActivate: () => {
          ctx.events.uncombineFeatures();
        }
      });
    }

    return controlGroup;
  }

  function removeButtons() {
    Object.keys(buttonElements).forEach(buttonId => {
      const button = buttonElements[buttonId];
      if (button.parentNode) {
        button.parentNode.removeChild(button);
      }
      delete buttonElements[buttonId];
    });
  }

  return {
    setActiveButton,
    queueMapClasses,
    updateMapClasses,
    addButtons,
    removeButtons
  };
};
<commit_msg>fix bug where `false` would be printed when keybindings were diabled<commit_after>const xtend = require('xtend');
const Constants = require('./constants');

const classTypes = ['mode', 'feature', 'mouse'];

module.exports = function(ctx) {

  const buttonElements = {};
  let activeButton = null;

  let currentMapClasses = {
    mode: null, // e.g. mode-direct_select
    feature: null, // e.g. feature-vertex
    mouse: null // e.g. mouse-move
  };

  let nextMapClasses = {
    mode: null,
    feature: null,
    mouse: null
  };

  function queueMapClasses(options) {
    nextMapClasses = xtend(nextMapClasses, options);
  }

  function updateMapClasses() {
    if (!ctx.container) return;

    const classesToRemove = [];
    const classesToAdd = [];

    classTypes.forEach((type) => {
      if (nextMapClasses[type] === currentMapClasses[type]) return;

      classesToRemove.push(`${type}-${currentMapClasses[type]}`);
      if (nextMapClasses[type] !== null) {
        classesToAdd.push(`${type}-${nextMapClasses[type]}`);
      }
    });

    if (classesToRemove.length > 0) {
      ctx.container.classList.remove.apply(ctx.container.classList, classesToRemove);
    }

    if (classesToAdd.length > 0) {
      ctx.container.classList.add.apply(ctx.container.classList, classesToAdd);
    }

    currentMapClasses = xtend(currentMapClasses, nextMapClasses);
  }

  function createControlButton(id, options = {}) {
    const button = document.createElement('button');
    button.className = `${Constants.classes.CONTROL_BUTTON} ${options.className}`;
    button.setAttribute('title', options.title);
    options.container.appendChild(button);

    button.addEventListener('click', (e) => {
      e.preventDefault();
      e.stopPropagation();

      const clickedButton = e.target;
      if (clickedButton === activeButton) {
        deactivateButtons();
        return;
      }

      setActiveButton(id);
      options.onActivate();
    }, true);

    return button;
  }

  function deactivateButtons() {
    if (!activeButton) return;
    activeButton.classList.remove(Constants.classes.ACTIVE_BUTTON);
    activeButton = null;
  }

  function setActiveButton(id) {
    deactivateButtons();

    const button = buttonElements[id];
    if (!button) return;

    if (button && id !== 'trash') {
      button.classList.add(Constants.classes.ACTIVE_BUTTON);
      activeButton = button;
    }
  }

  function addButtons() {
    const controls = ctx.options.controls;
    const controlGroup = document.createElement('div');
    controlGroup.className = `${Constants.classes.CONTROL_GROUP} ${Constants.classes.CONTROL_BASE}`;

    if (!controls) return controlGroup;

    if (controls[Constants.types.LINE]) {
      buttonElements[Constants.types.LINE] = createControlButton(Constants.types.LINE, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_LINE,
        title: `LineString tool ${ctx.options.keybindings ? '(l)' : ''}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_LINE_STRING)
      });
    }

    if (controls[Constants.types.POLYGON]) {
      buttonElements[Constants.types.POLYGON] = createControlButton(Constants.types.POLYGON, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_POLYGON,
        title: `Polygon tool ${ctx.options.keybindings ? '(p)' : ''}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POLYGON)
      });
    }

    if (controls[Constants.types.POINT]) {
      buttonElements[Constants.types.POINT] = createControlButton(Constants.types.POINT, {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_POINT,
        title: `Marker tool ${ctx.options.keybindings ? '(m)' : ''}`,
        onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POINT)
      });
    }

    if (controls.trash) {
      buttonElements.trash = createControlButton('trash', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_TRASH,
        title: 'Delete',
        onActivate: () => {
          ctx.events.trash();
        }
      });
    }

    if (controls.combine_features) {
      buttonElements.combine_features = createControlButton('combineFeatures', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_COMBINE_FEATURES,
        title: 'Combine',
        onActivate: () => {
          ctx.events.combineFeatures();
        }
      });
    }

    if (controls.uncombine_features) {
      buttonElements.uncombine_features = createControlButton('uncombineFeatures', {
        container: controlGroup,
        className: Constants.classes.CONTROL_BUTTON_UNCOMBINE_FEATURES,
        title: 'Uncombine',
        onActivate: () => {
          ctx.events.uncombineFeatures();
        }
      });
    }

    return controlGroup;
  }

  function removeButtons() {
    Object.keys(buttonElements).forEach(buttonId => {
      const button = buttonElements[buttonId];
      if (button.parentNode) {
        button.parentNode.removeChild(button);
      }
      delete buttonElements[buttonId];
    });
  }

  return {
    setActiveButton,
    queueMapClasses,
    updateMapClasses,
    addButtons,
    removeButtons
  };
};
<|endoftext|>


<commit_before>if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
                ;
        });
    };
}

toggle_button_loading_text = function($element){
    var btnText = $element.data('loading-text');
    $element
        .data('loading-text', $element.text())
        .data('loading-text', btnText)
    ;
};

$(function() {
    $('#sidebar-wrapper').slimscroll({
        height: '100%',
        width: '500px',
        position: 'right',
        alwaysVisible: true,
        color: '#73715e'
    });

    $('[data-toggle="tooltip"]').tooltip();

    $('select')
        .select2({
            placeholder: "Select a state",
            allowClear: true,
            width: '170px'
        })
        .change(function(e){
            var $target = $(e.target);
            var $img = $target.parents('.row:first').find('img');

            $img.attr('src', $target.children('option:selected').data('photo'));
        });

    $('.event-list>li').click(function(e){
        var $target = $(e.target);

        $('.background-image').css('background-image', "url('" + $target.data('background') + "')");
        $('#race-title').html($target.data('title'));
        $('input[name="stage"]').val($target.data('slug'));
    });

    $('*[data-event="ajaxRequest"]').click(function(e){
        e.preventDefault();

        var $target = $(e.target);
        var $container = $($target.data('container'));
        var $resultContainer = $($target.data('result-container'));
        var $form = $($target).parents('form:first');

        $.ajax({
            async: true,
            type: $form.attr('method'),
            url: decodeURI($form.attr('action')).format($('input[name="stage"]').val()),
            data: $form.serialize(),
            beforeSend: function(){
                toggle_button_loading_text($target);
            },
            success: function(data){
                if (data.status === "ok") {
                    $container.show();
                    $resultContainer.html(data.view);

                    toggle_button_loading_text($target);
                }
            }
        });
    });
});<commit_msg>quick fix<commit_after>if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
                ;
        });
    };
}

toggle_button_loading_text = function($element){
    var btnText = $element.data('loading-text');
    $element
        .data('loading-text', $element.text())
        .data('loading-text', btnText)
    ;
};

$(function() {
    $('#sidebar-wrapper').slimscroll({
        height: '100%',
        width: '500px',
        position: 'right',
        alwaysVisible: true,
        color: '#73715e'
    });

    $('[data-toggle="tooltip"]').tooltip();

    $('select')
        .select2({
            placeholder: "Select a state",
            allowClear: true,
            width: '170px'
        })
        .change(function(e){
            var $target = $(e.target);
            var $img = $target.parents('.row:first').find('img');

            $img.attr('src', $target.children('option:selected').data('photo'));
        });

    $('.event-list>li').click(function(e){
        var $target = $(this);

        $('.background-image').css('background-image', "url('" + $target.data('background') + "')");
        $('#race-title').html($target.data('title'));
        $('input[name="stage"]').val($target.data('slug'));
    });

    $('*[data-event="ajaxRequest"]').click(function(e){
        e.preventDefault();

        var $target = $(e.target);
        var $container = $($target.data('container'));
        var $resultContainer = $($target.data('result-container'));
        var $form = $($target).parents('form:first');

        $.ajax({
            async: true,
            type: $form.attr('method'),
            url: decodeURI($form.attr('action')).format($('input[name="stage"]').val()),
            data: $form.serialize(),
            beforeSend: function(){
                toggle_button_loading_text($target);
            },
            success: function(data){
                if (data.status === "ok") {
                    $container.show();
                    $resultContainer.html(data.view);

                    toggle_button_loading_text($target);
                }
            }
        });
    });
});<|endoftext|>


<commit_before>'use strict';

orangee.scroller = IScroll;
orangee.sidemenu = Snap;
orangee.spinner = Spinner;

Marionette.Behaviors.behaviorsLookup = function() {
  return window;
}

HotKeysBehavior = Marionette.Behavior.extend({
  onRender: function() {
    HotKeys.bind(this.view.keyEvents, this.view, this.view.cid);
  },
  onClose: function() {
    HotKeys.unbind(this.view.keyEvents, this.view, this.view.cid);
  },
});

Orangee.Model = Backbone.Model.extend({
  initialize: function() {
    // Applies the mixin:
    Backbone.Select.Me.applyTo(this);
  },
});

Orangee.Collection = Backbone.PageableCollection.extend({
  currentSelection: 0,//TODO the value will mess up with mouse click
  initialize: function(models, options) {
    // Applies the mixin:
    Backbone.Select.One.applyTo(this, models, options);
  },
  selectPrev: function() {
    this.currentSelection--;
    if (this.currentSelection >= this.length) {
      this.currentSelection = this.length - 1;
    }
    this.select(this.at(this.currentSelection));
  },
  selectNext: function() {
    this.currentSelection++;
    if (this.currentSelection >= this.length) {
      this.currentSelection = 0;
    }
    this.select(this.at(this.currentSelection));
  },
});

Orangee.ItemView = Marionette.ItemView.extend({
  behaviors: {
    HotKeysBehavior: {}
  },
});

Orangee.CollectionView = Marionette.CollectionView.extend({
  behaviors: {
    HotKeysBehavior: {}
  },
});

Orangee.XMLCollection = Orangee.Collection.extend({
  fetch: function (options) {
    options = options || {};
    options.dataType = "html";
    return Backbone.Collection.prototype.fetch.call(this, options);
  },
  parse: function(xml) {
    //var response = {data: json.opml.body.outline.map(function(x) {return {name: x._title, standardPic: x._img, url: x._url}})}
    return Orangee.xml2json(xml);
  },
});

Orangee.RSSCollection = Orangee.XMLCollection.extend();

Orangee.VideoView = Orangee.ItemView.extend({
  onRender: function() {
    orangee.debug("Orangee.VideoView#onRender");
    //orangee.debug(this.getOption('player'));
    this.videoplayer = new orangee.videoplayer();
    var onplaying = this.getOption('onPlaying');
    var onpause = this.getOption('onPause');
    var onend = this.getOption('onEnd');
    this.videoplayer.load(this.collection.toJSON(),
                          this.getOption('divid'),
                          _.extend({
                            onplaying: onplaying ? onplaying.bind(this) : onplaying,
                            onpause: onpause ? onpause.bind(this): onpause,
                            onend:  onend ? onend.bind(this) : onend,
                          }, this.getOption('playerVars'))
                         );
  },
  keyEvents: {
    'right': 'onKeyRight',
    'left' : 'onKeyLeft',
    'play' : 'onKeyPlay',
  },
  onKeyPlay: function() {
    orangee.debug('Orangee.VideoView#onKeyEnter');
    this.videoplayer.togglePlay();
  },
  onKeyRight: function() {
    orangee.debug('Orangee.VideoView#onKeyRight');
    this.videoplayer.seek(60);
  },
  onKeyLeft: function() {
    orangee.debug('Orangee.VideoView#onKeyLeft');
    this.videoplayer.seek(-60);
  },
});

Orangee.ScrollItemView = Orangee.ItemView.extend({
  events: {
    'click': 'onClick',
    'mouseover': 'onMouseOver',
  },
  modelEvents: {
    'selected': 'onSelect',
    'deselected': 'onDeselect',
    'clicked': 'onClick',
  },
  onClick: function() {
    orangee.debug('Orangee.ScrollItemView#onClick');
  },
  onMouseOver: function() {
    orangee.debug('Orangee.ScrollItemView#onMouseOver');
    this.model.select();
  },
  onSelect: function(model) {
    orangee.debug('Orangee.ScrollItemView#onSelect');
    this.$('li').addClass('active');
  },
  onDeselect: function(model) {
    orangee.debug('Orangee.ScrollItemView#onDeselect');
    this.$('li').removeClass('active');
  },
});

Orangee.ScrollView = Orangee.CollectionView.extend({
  onRender: function() {
    orangee.debug("Orangee.ScrollView#onRender");
    this.scroll = new orangee.scroller(this.el, this.getOption('scroll'));
  },
  keyEvents: {
    'enter': 'onKeyEnter',
    'up': 'onKeyUp',
    'down' : 'onKeyDown',
  },
  onKeyEnter: function() {
    orangee.debug('Orangee.ScrollView#onKeyEnter');
    this.collection.selected.trigger('clicked');
  },
  onKeyUp: function() {
    orangee.debug('Orangee.ScrollView#onKeyUp');
    this.collection.selectPrev();
  },
  onKeyDown: function() {
    orangee.debug('Orangee.ScrollView#onKeyDown');
    this.collection.selectNext();
  },
  //childEvents: {
  //},
});

<commit_msg>add Orangee.XMLModel<commit_after>'use strict';

orangee.scroller = IScroll;
orangee.sidemenu = Snap;
orangee.spinner = Spinner;

Marionette.Behaviors.behaviorsLookup = function() {
  return window;
}

HotKeysBehavior = Marionette.Behavior.extend({
  onRender: function() {
    HotKeys.bind(this.view.keyEvents, this.view, this.view.cid);
  },
  onClose: function() {
    HotKeys.unbind(this.view.keyEvents, this.view, this.view.cid);
  },
});

Orangee.Model = Backbone.Model.extend({
  initialize: function() {
    // Applies the mixin:
    Backbone.Select.Me.applyTo(this);
  },
});

Orangee.XMLModel = Orangee.Model.extend({
  fetch: function(options) {
    options = options || {};
    options.dataType = "html";
    return Backbone.Model.prototype.fetch.call(this, options);
  },
  parse: function(xml) {
    return Orangee.xml2json(xml);
  },
});

Orangee.Collection = Backbone.PageableCollection.extend({
  currentSelection: 0,//TODO the value will mess up with mouse click
  initialize: function(models, options) {
    // Applies the mixin:
    Backbone.Select.One.applyTo(this, models, options);
  },
  selectPrev: function() {
    this.currentSelection--;
    if (this.currentSelection >= this.length) {
      this.currentSelection = this.length - 1;
    }
    this.select(this.at(this.currentSelection));
  },
  selectNext: function() {
    this.currentSelection++;
    if (this.currentSelection >= this.length) {
      this.currentSelection = 0;
    }
    this.select(this.at(this.currentSelection));
  },
});

Orangee.ItemView = Marionette.ItemView.extend({
  behaviors: {
    HotKeysBehavior: {}
  },
});

Orangee.CollectionView = Marionette.CollectionView.extend({
  behaviors: {
    HotKeysBehavior: {}
  },
});

Orangee.XMLCollection = Orangee.Collection.extend({
  fetch: function(options) {
    options = options || {};
    options.dataType = "html";
    return Backbone.Collection.prototype.fetch.call(this, options);
  },
  parse: function(xml) {
    //var response = {data: json.opml.body.outline.map(function(x) {return {name: x._title, standardPic: x._img, url: x._url}})}
    return Orangee.xml2json(xml);
  },
});

Orangee.RSSCollection = Orangee.XMLCollection.extend();

Orangee.VideoView = Orangee.ItemView.extend({
  onRender: function() {
    orangee.debug("Orangee.VideoView#onRender");
    //orangee.debug(this.getOption('player'));
    this.videoplayer = new orangee.videoplayer();
    var onplaying = this.getOption('onPlaying');
    var onpause = this.getOption('onPause');
    var onend = this.getOption('onEnd');
    this.videoplayer.load(this.collection.toJSON(),
                          this.getOption('divid'),
                          _.extend({
                            onplaying: onplaying ? onplaying.bind(this) : onplaying,
                            onpause: onpause ? onpause.bind(this): onpause,
                            onend:  onend ? onend.bind(this) : onend,
                          }, this.getOption('playerVars'))
                         );
  },
  keyEvents: {
    'right': 'onKeyRight',
    'left' : 'onKeyLeft',
    'play' : 'onKeyPlay',
  },
  onKeyPlay: function() {
    orangee.debug('Orangee.VideoView#onKeyEnter');
    this.videoplayer.togglePlay();
  },
  onKeyRight: function() {
    orangee.debug('Orangee.VideoView#onKeyRight');
    this.videoplayer.seek(60);
  },
  onKeyLeft: function() {
    orangee.debug('Orangee.VideoView#onKeyLeft');
    this.videoplayer.seek(-60);
  },
});

Orangee.ScrollItemView = Orangee.ItemView.extend({
  events: {
    'click': 'onClick',
    'mouseover': 'onMouseOver',
  },
  modelEvents: {
    'selected': 'onSelect',
    'deselected': 'onDeselect',
    'clicked': 'onClick',
  },
  onClick: function() {
    orangee.debug('Orangee.ScrollItemView#onClick');
  },
  onMouseOver: function() {
    orangee.debug('Orangee.ScrollItemView#onMouseOver');
    this.model.select();
  },
  onSelect: function(model) {
    orangee.debug('Orangee.ScrollItemView#onSelect');
    this.$('li').addClass('active');
  },
  onDeselect: function(model) {
    orangee.debug('Orangee.ScrollItemView#onDeselect');
    this.$('li').removeClass('active');
  },
});

Orangee.ScrollView = Orangee.CollectionView.extend({
  onRender: function() {
    orangee.debug("Orangee.ScrollView#onRender");
    this.scroll = new orangee.scroller(this.el, this.getOption('scroll'));
  },
  keyEvents: {
    'enter': 'onKeyEnter',
    'up': 'onKeyUp',
    'down' : 'onKeyDown',
  },
  onKeyEnter: function() {
    orangee.debug('Orangee.ScrollView#onKeyEnter');
    this.collection.selected.trigger('clicked');
  },
  onKeyUp: function() {
    orangee.debug('Orangee.ScrollView#onKeyUp');
    this.collection.selectPrev();
  },
  onKeyDown: function() {
    orangee.debug('Orangee.ScrollView#onKeyDown');
    this.collection.selectNext();
  },
  //childEvents: {
  //},
});

<|endoftext|>


<commit_before>// @copyright: 2013 Single D Software - All Rights Reserved
// @summary: JavaScript logic for the Light Maestro GUI

'use strict';

// TODO comments
// TODO read channel values when picking individual fixture
// TODO arrange banks
// TODO add "select all in bank" button? perhaps with double tap or long-press?

function selectFixtures() {
    var type = $(this).html();
    var whitesChecked = type == 'All' || type == 'Whites';
    var colorsChecked = type == 'All' || type == 'Colors';
    $('input[class="fixture-white"]').prop('checked', whitesChecked);
    $('input[class="fixture-color"]').prop('checked', colorsChecked);
    $('input[type="checkbox"]').checkboxradio('refresh');
}

function changeValues(event) {
    var alpha = parseFloat($('#value-alpha').val());
    var red = parseFloat($('#value-red').val());
    var green = parseFloat($('#value-green').val());
    var blue = parseFloat($('#value-blue').val());
    var channels = {}
    $('input[type="checkbox"]').each( function() {
        if($(this).prop('checked')) {
           var id = parseInt($(this).attr('id').split('-')[1]);
           channels[id + 0] = alpha;
           channels[id + 1] = red;
           channels[id + 2] = green;
           channels[id + 3] = blue;
       }
    });
    $.ajax({data: JSON.stringify({'channels': channels})});
}

// Things to do before the page is shown.
$(document).bind('pagebeforeshow', function() {

    // Set up AJAX calls.
    $.ajaxSetup({method: 'POST', url: '/channels/_load', headers: {'content-type': 'application/json'}});

    // Disable any ability to select text in the GUI.
    $('body').bind('selectstart',function() {
        return false;
    });

    // Bind the select fixture function to selection buttons.
    $('button').bind('tap', selectFixtures);

    // Bind the change value function to the sliders (TODO make this one call).
    $('#value-alpha').bind('change', changeValues);
    $('#value-red').bind('change', changeValues);
    $('#value-green').bind('change', changeValues);
    $('#value-blue').bind('change', changeValues);

});

<commit_msg>Fix addressing of fixtures.<commit_after>// @copyright: 2013 Single D Software - All Rights Reserved
// @summary: JavaScript logic for the Light Maestro GUI

'use strict';

// TODO comments
// TODO read channel values when picking individual fixture
// TODO arrange banks
// TODO add "select all in bank" button? perhaps with double tap or long-press?

function selectFixtures() {
    var type = $(this).html();
    var whitesChecked = type == 'All' || type == 'Whites';
    var colorsChecked = type == 'All' || type == 'Colors';
    $('input[class="fixture-white"]').prop('checked', whitesChecked);
    $('input[class="fixture-color"]').prop('checked', colorsChecked);
    $('input[type="checkbox"]').checkboxradio('refresh');
}

function changeValues(event) {
    var alpha = parseFloat($('#value-alpha').val());
    var red = parseFloat($('#value-red').val());
    var green = parseFloat($('#value-green').val());
    var blue = parseFloat($('#value-blue').val());
    var channels = {}
    $('input[type="checkbox"]').each( function() {
        if($(this).prop('checked')) {
           var id = parseInt($(this).attr('id').split('-')[1]) * 4 - 3;
           channels[id + 0] = alpha;
           channels[id + 1] = red;
           channels[id + 2] = green;
           channels[id + 3] = blue;
       }
    });
    $.ajax({data: JSON.stringify({'channels': channels})});
}

// Things to do before the page is shown.
$(document).bind('pagebeforeshow', function() {

    // Set up AJAX calls.
    $.ajaxSetup({method: 'POST', url: '/channels/_load', headers: {'content-type': 'application/json'}});

    // Disable any ability to select text in the GUI.
    $('body').bind('selectstart',function() {
        return false;
    });

    // Bind the select fixture function to selection buttons.
    $('button').bind('tap', selectFixtures);

    // Bind the change value function to the sliders (TODO make this one call).
    $('#value-alpha').bind('change', changeValues);
    $('#value-red').bind('change', changeValues);
    $('#value-green').bind('change', changeValues);
    $('#value-blue').bind('change', changeValues);

});

<|endoftext|>


<commit_before>// *** UI ***
var ui = {
  initCanvas: function(canvas, data, callback) {
    var startx, starty, datax, datay;
    var mousedown = false;
    var start = data.start;
    canvas.addEventListener("mousedown", function(event) {
      mousedown = true;
      startx = event.x;
      starty = event.y;
      datax = start.x;
      datay = start.y;
    });
    canvas.addEventListener("mouseup", function(event) {
      mousedown = false;
    });
    canvas.addEventListener("mousemove", function(event) {
      if (mousedown) {
        start.x = datax - (startx - event.x);
        start.y = datay - (starty - event.y);
        callback();
        data.needsRender = true;
      }
    });
  },
  initExamples: function(data) {
    var exampleCollection = document.getElementsByClassName('example');
    var i = exampleCollection.length;
    var examples = [];
    while(i--) {
      exampleCollection[i].addEventListener("click", function(event) {
        window.location.hash = event.target.hash;
        data.needsDecode = true;
      });
    }
  }
};

module.exports = ui;<commit_msg>fix bug in mouse event positions on browsers other than chrome<commit_after>// *** UI ***
var ui = {
  initCanvas: function(canvas, data, callback) {
    var startx, starty, datax, datay;
    var mousedown = false;
    var start = data.start;
    canvas.addEventListener("mousedown", function(event) {
      mousedown = true;
      startx = event.clientX;
      starty = event.clientY;
      datax = start.x;
      datay = start.y;
    });
    canvas.addEventListener("mouseup", function(event) {
      mousedown = false;
    });
    canvas.addEventListener("mousemove", function(event) {
      if (mousedown) {
        start.x = datax - (startx - event.clientX);
        start.y = datay - (starty - event.clientY);
        callback();
        data.needsRender = true;
      }
    });
  },
  initExamples: function(data) {
    var exampleCollection = document.getElementsByClassName('example');
    var i = exampleCollection.length;
    var examples = [];
    while(i--) {
      exampleCollection[i].addEventListener("click", function(event) {
        window.location.hash = event.target.hash;
        data.needsDecode = true;
      });
    }
  }
};

module.exports = ui;<|endoftext|>


<commit_before>cm.define('Tpl.Servers', {
    'modules' : [
        'DataNodes',
        'Langs'
    ],
    'params' : {
        'langs' : {
            'bf3' : 'Battlefield 3',
            'bf4' : 'Battlefield 4',
            'bfh' : 'Battlefield Hardline',
            'bf5' : 'Battlefield 5'
        }
    }
},
function(params){
    var that = this;

    that.components = {};
    that.nodes = {
        'Template' : {
            'contentInner' : cm.Node('div')
        }
    };

    that.bans = [];
    that.servers = [];
    that.serversO = {};
    that.data = {};
    that.isRenderTab = {};

    var init = function(){
        that.setParams(params);
        that.getDataNodes(document.body, that.params['nodesDataMarker'], false);
        that.components['overlay'] = new Com.Overlay({
            'node' : that.nodes['Template']['contentInner']
        });
        get();
    };

    var get = function(){
        cm.ajax({
            'type' : 'json',
            'method' : 'get',
            'params' : cm.obj2URI({'type' : 'bans', 'sid' : 'all'}),
            'url' : 'http://bsb.artlark.ru',
            'handler' : function(responce){
                that.bans = cm.isArray(responce)? responce : [];

                cm.ajax({
                    'type' : 'json',
                    'method' : 'get',
                    'params' : cm.obj2URI({'type' : 'servers', 'sid' : 'all'}),
                    'url' : 'http://bsb.artlark.ru',
                    'handler' : function(responce){
                        that.servers = cm.isArray(responce)? responce : [];
                        prepare();
                        render();
                        that.components['overlay'].close();
                    }
                });
            }
        });
    };

    var prepare = function(){
        var server;
        cm.forEach(that.servers, function(item){
            that.serversO[item['id']] = item;
        });
        cm.forEach(that.bans, function(item){
            server = that.serversO[item['sid']];

            item['name'] = server['name'];
            item['game'] = server['game'];

            if(cm.isEmpty(server['name'])){
                item['name'] = server['id'];
            }

            if(cm.isEmpty(item['comment'])){
                item['comment'] = ['', ' --- ', that.lang('Comment not given'), ' --- ', ''].join('');
            }

            if(!cm.isEmpty(server['url'])){
                item['url'] = ['http://battlelog.battlefield.com', server['game'], 'servers/show/pc', server['id'], server['url'], ''].join('/');
            }else{
                item['url'] = ['http://battlelog.battlefield.com', server['game'], 'servers/show/pc', server['id'], ''].join('/');
            }

            if(!that.data[item['game']]){
                that.data[item['game']] = [];
            }

            that.data[item['game']].push(item);
        });
    };

    var render = function(){
        that.components['tabset'] = new Com.Tabset({
            'container' : that.params['node'],
            'toggleOnHashChange' : false
        });

        cm.forEach(that.data, function(item, key){
            that.components['tabset'].addTab({
                'id' : key,
                'title' : that.lang(key),
                'onShow' : renderTab
            })
        });

        that.components['tabset'].set('bf3');
    };

    var renderTab = function(tabset, tab){
        if(!that.isRenderTab[tab['id']]){
            that.isRenderTab[tab['id']] = true;

            new Com.Gridlist({
                'container' : tab['content'],
                'className' : 'bottom',
                'data' : that.data[tab['id']],
                'cols' : [
                    {'key' : 'name', 'type' : 'url', 'urlKey' : 'url', 'width' : '30%', 'title' : that.lang('Server'), 'showTitle' : true, 'textOverflow' : true},
                    {'key' : 'comment', 'type' : 'text', 'width' : 'auto', 'title' : that.lang('Comment'), 'showTitle' : true, 'textOverflow' : true},
                    {'key' : 'date', 'type' : 'date', 'width' : 160, 'title' : that.lang('Date')}
                ],
                'sortBy' : 'date',
                'orderBy' : 'DESC',
                'perPage' : 20,
                'showCounter' : true,
                'visibleDateFormat' : '%j %F %Y at %H:%i',
                'langs' : {
                    'counter' : that.lang('Bans') + ': '
                }
            })
        }
    };

    /* ******* MAIN ******* */

    init();
});<commit_msg>* WEB. Langs changes.<commit_after>cm.define('Tpl.Servers', {
    'modules' : [
        'DataNodes',
        'Langs'
    ],
    'params' : {
        'langs' : {
            'bf3' : 'Battlefield 3',
            'bf4' : 'Battlefield 4',
            'bfh' : 'Battlefield Hardline',
            'bf5' : 'Battlefield 5'
        }
    }
},
function(params){
    var that = this;

    that.components = {};
    that.nodes = {
        'Template' : {
            'contentInner' : cm.Node('div')
        }
    };

    that.bans = [];
    that.servers = [];
    that.serversO = {};
    that.data = {};
    that.isRenderTab = {};

    var init = function(){
        that.setParams(params);
        that.getDataNodes(document.body, that.params['nodesDataMarker'], false);
        that.components['overlay'] = new Com.Overlay({
            'node' : that.nodes['Template']['contentInner']
        });
        get();
    };

    var get = function(){
        cm.ajax({
            'type' : 'json',
            'method' : 'get',
            'params' : cm.obj2URI({'type' : 'bans', 'sid' : 'all'}),
            'url' : 'http://bsb.artlark.ru',
            'handler' : function(responce){
                that.bans = cm.isArray(responce)? responce : [];

                cm.ajax({
                    'type' : 'json',
                    'method' : 'get',
                    'params' : cm.obj2URI({'type' : 'servers', 'sid' : 'all'}),
                    'url' : 'http://bsb.artlark.ru',
                    'handler' : function(responce){
                        that.servers = cm.isArray(responce)? responce : [];
                        prepare();
                        render();
                        that.components['overlay'].close();
                    }
                });
            }
        });
    };

    var prepare = function(){
        var server;
        cm.forEach(that.servers, function(item){
            that.serversO[item['id']] = item;
        });
        cm.forEach(that.bans, function(item){
            server = that.serversO[item['sid']];

            item['name'] = server['name'];
            item['game'] = server['game'];

            if(cm.isEmpty(server['name'])){
                item['name'] = server['id'];
            }

            if(cm.isEmpty(item['comment'])){
                item['comment'] = ['', ' --- ', that.lang('No comments left'), ' --- ', ''].join('');
            }

            if(!cm.isEmpty(server['url'])){
                item['url'] = ['http://battlelog.battlefield.com', server['game'], 'servers/show/pc', server['id'], server['url'], ''].join('/');
            }else{
                item['url'] = ['http://battlelog.battlefield.com', server['game'], 'servers/show/pc', server['id'], ''].join('/');
            }

            if(!that.data[item['game']]){
                that.data[item['game']] = [];
            }

            that.data[item['game']].push(item);
        });
    };

    var render = function(){
        that.components['tabset'] = new Com.Tabset({
            'container' : that.params['node'],
            'toggleOnHashChange' : false
        });

        cm.forEach(that.data, function(item, key){
            that.components['tabset'].addTab({
                'id' : key,
                'title' : that.lang(key),
                'onShow' : renderTab
            })
        });

        that.components['tabset'].set('bf3');
    };

    var renderTab = function(tabset, tab){
        if(!that.isRenderTab[tab['id']]){
            that.isRenderTab[tab['id']] = true;

            new Com.Gridlist({
                'container' : tab['content'],
                'className' : 'bottom',
                'data' : that.data[tab['id']],
                'cols' : [
                    {'key' : 'name', 'type' : 'url', 'urlKey' : 'url', 'width' : '30%', 'title' : that.lang('Server'), 'showTitle' : true, 'textOverflow' : true},
                    {'key' : 'comment', 'type' : 'text', 'width' : 'auto', 'title' : that.lang('Comment'), 'showTitle' : true, 'textOverflow' : true},
                    {'key' : 'date', 'type' : 'date', 'width' : 160, 'title' : that.lang('Date')}
                ],
                'sortBy' : 'date',
                'orderBy' : 'DESC',
                'perPage' : 20,
                'showCounter' : true,
                'visibleDateFormat' : '%j %F %Y at %H:%i',
                'langs' : {
                    'counter' : that.lang('Bans') + ': '
                }
            })
        }
    };

    /* ******* MAIN ******* */

    init();
});<|endoftext|>


<commit_before>// help.js:
// This file is from Chemlogic, a logic programming computer chemistry system
// <http://icebergsystems.ca/chemlogic>
// (C) Copyright 2012-2016 Nicholas Paun

function set_paren_placeholder()
 {
	var e = document.getElementById('molar_unit');
	var selected = e.options[e.selectedIndex].value;
	var input = document.getElementById('molar_tail_input');

	if (selected == 'M')
	 {
    		input.setAttribute('placeholder','e.g. 1.43 L');
   		input.setAttribute('style','visibility: visible;');
		input.required = true;
     	 }
   	else if (selected == 'L(sol)')
   	 {
   		input.setAttribute('placeholder','e.g. 0.333 M');
   		input.setAttribute('style','visibility: visible;');
		input.required = true;
   	 }
   	else
   	 {
   		input.setAttribute('style','visibility: hidden');
		input.required = false;
		input.value = "";
   	 }
 }

function set_placeholder(module)
 {
 	var e = document.getElementById(module + '_type');
	var selected = e.options[e.selectedIndex].value;
	var input = document.getElementById(module + '_input');

	if (module == 'compounder')
	 {
		if (selected == "name")
	 		input.setAttribute('placeholder','e.g. copper(II) sulfate pentahydrate');
		else
			input.setAttribute('placeholder','e.g. H2SO4');
	 }
	 else if (module == 'molar')
	  {
	  	if (selected == 'name')
			input.setAttribute('placeholder','e.g. 0.500 L of 3.0 M hydrochloric acid');
		else
			input.setAttribute('placeholder','e.g. 46.93 g ethanol');

	 }
	else if (module == 'balancer')
	 {
	 	if (selected == 'symbolic')
			input.setAttribute('placeholder','e.g. Cu + HNO3 --> Cu(NO3)2 + NO2 + H2O');
		else
			input.setAttribute('placeholder','e.g. nonanol + oxygen --> carbon dioxide + water');
	 }
	else if (module == 'stoichiometer')
	 {
		if (selected == 'symbolic')
			input.setAttribute('placeholder','e.g. 15.00 L CH4 + 20.00 L O2 --> CO2 + H2O');
		else
			input.setAttribute('placeholder','e.g oxalic acid + 0.125 L of 1.000 M sodium hydroxide --> sodium oxalate + 300 g water');
	}
 }

function set_handler()
 {
 	var module = window.location.pathname.split(/[\\/]/).pop();

	if (!module)
		module = 'balancer';

 	document.getElementById(module + '_type').addEventListener('change',set_placeholder(module));
	set_placeholder(module);

	if (module == 'molar')
	 {
		document.getElementById('molar_unit').addEventListener('change',set_paren_placeholder);
		 set_paren_placeholder();
	 }
 }

set_handler();
<commit_msg>Correct an incorrect event listener setup that broke the placeholder changing logic<commit_after>// help.js:
// This file is from Chemlogic, a logic programming computer chemistry system
// <http://icebergsystems.ca/chemlogic>
// (C) Copyright 2012-2016 Nicholas Paun

function set_paren_placeholder()
 {
	var e = document.getElementById('molar_unit');
	var selected = e.options[e.selectedIndex].value;
	var input = document.getElementById('molar_tail_input');

	if (selected == 'M')
	 {
    		input.setAttribute('placeholder','e.g. 1.43 L');
   		input.setAttribute('style','visibility: visible;');
		input.required = true;
     	 }
   	else if (selected == 'L(sol)')
   	 {
   		input.setAttribute('placeholder','e.g. 0.333 M');
   		input.setAttribute('style','visibility: visible;');
		input.required = true;
   	 }
   	else
   	 {
   		input.setAttribute('style','visibility: hidden');
		input.required = false;
		input.value = "";
   	 }
 }

function set_placeholder(module)
 {
 	var e = document.getElementById(module + '_type');
	var selected = e.options[e.selectedIndex].value;
	var input = document.getElementById(module + '_input');

	if (module == 'compounder')
	 {
		if (selected == "name")
	 		input.setAttribute('placeholder','e.g. copper(II) sulfate pentahydrate');
		else
			input.setAttribute('placeholder','e.g. H2SO4');
	 }
	 else if (module == 'molar')
	  {
	  	if (selected == 'name')
			input.setAttribute('placeholder','e.g. 0.500 L of 3.0 M hydrochloric acid');
		else
			input.setAttribute('placeholder','e.g. 46.93 g ethanol');

	 }
	else if (module == 'balancer')
	 {
	 	if (selected == 'symbolic')
			input.setAttribute('placeholder','e.g. Cu + HNO3 --> Cu(NO3)2 + NO2 + H2O');
		else
			input.setAttribute('placeholder','e.g. nonanol + oxygen --> carbon dioxide + water');
	 }
	else if (module == 'stoichiometer')
	 {
		if (selected == 'symbolic')
			input.setAttribute('placeholder','e.g. 15.00 L CH4 + 20.00 L O2 --> CO2 + H2O');
		else
			input.setAttribute('placeholder','e.g oxalic acid + 0.125 L of 1.000 M sodium hydroxide --> sodium oxalate + 300 g water');
	}
 }

function set_handler()
 {
 	var module = window.location.pathname.split(/[\\/]/).pop();

	if (!module)
		module = 'balancer';

 	document.getElementById(module + '_type').addEventListener('change', function() {
		set_placeholder(module)
	});
	set_placeholder(module);

	if (module == 'molar')
	 {
		document.getElementById('molar_unit').addEventListener('change',set_paren_placeholder);
		set_paren_placeholder();
	 }
 }

set_handler();
<|endoftext|>


<commit_before>"use strict";
(function() {
  var $, CheckBoxOption, ExclusionRulesOption, NonEmptyTextOption, NumberOption, Option, TextOption,
    activateHelpDialog, bgSettings, bgExclusions, enableSaveButton, maintainLinkHintsView,
    ExclusionRulesOnPopupOption, initOptionsPage, initPopupPage,
    __hasProp = Object.prototype.hasOwnProperty,
    __extends = function(child, parent) {
      for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
      function ctor() { this.constructor = child; } ctor.prototype = parent.prototype;
      child.prototype = new ctor(); child.__super__ = parent.prototype;
      return child;
    };

  $ = document.getElementById.bind(document);
  bgSettings = chrome.extension.getBackgroundPage().Settings;
  bgExclusions = chrome.extension.getBackgroundPage().Exclusions;

  function Option(field, onUpdated) {
    this.field = field;
    this.onUpdated = onUpdated;
    this.element = $(this.field);
    this.element.addEventListener("change", this.onUpdated);
    this.fetch();
    Option.all.push(this);
  }

  Option.all = [];

  Option.prototype.fetch = function() {
    this.populateElement(this.previous = bgSettings.get(this.field));
    return this.previous;
  };

  Option.prototype.save = function() {
    var value = this.readValueFromElement();
    if (!this.areEqual(value, this.previous)) {
      bgSettings.set(this.field, this.previous = value);
    }
  };

  Option.prototype.areEqual = function(a, b) {
    return a === b;
  };

  Option.prototype.restoreToDefault = function() {
    bgSettings.clear(this.field);
    return this.fetch();
  };

  Option.saveOptions = function() {
    Option.all.forEach(function(option) {
      option.save();
    });
  };

  NumberOption = (function(_super) {
    __extends(NumberOption, _super);

    function NumberOption() {
      return NumberOption.__super__.constructor.apply(this, arguments);
    }

    NumberOption.prototype.populateElement = function(value) {
      return this.element.value = value;
    };

    NumberOption.prototype.readValueFromElement = function() {
      return parseFloat(this.element.value);
    };

    return NumberOption;

  })(Option);

  TextOption = (function(_super) {
    __extends(TextOption, _super);

    function TextOption() {
      TextOption.__super__.constructor.apply(this, arguments);
      this.element.addEventListener("input", this.onUpdated);
    }

    TextOption.prototype.populateElement = function(value) {
      return this.element.value = value.replace(/\n /g, '\n\xa0');
    };

    TextOption.prototype.readValueFromElement = function() {
      return this.element.value.trim().replace(/\xa0/g, ' ');
    };

    return TextOption;

  })(Option);

  NonEmptyTextOption = (function(_super) {
    __extends(NonEmptyTextOption, _super);

    function NonEmptyTextOption(field, enableSaveButton) {
      NonEmptyTextOption.__super__.constructor.apply(this, arguments);
      this.element.addEventListener("input", this.onUpdated);
    }

    NonEmptyTextOption.prototype.populateElement = function(value) {
      return this.element.value = value.replace(/\n /g, '\n\xa0');
    };

    NonEmptyTextOption.prototype.readValueFromElement = function() {
      var value = this.element.value.trim().replace(/\xa0/g, ' ');
      if (value) {
        return value;
      } else {
        return this.restoreToDefault();
      }
    };

    return NonEmptyTextOption;

  })(Option);

  CheckBoxOption = (function(_super) {
    __extends(CheckBoxOption, _super);

    function CheckBoxOption() {
      return CheckBoxOption.__super__.constructor.apply(this, arguments);
    }

    CheckBoxOption.prototype.populateElement = function(value) {
      return this.element.checked = value;
    };

    CheckBoxOption.prototype.readValueFromElement = function() {
      return this.element.checked;
    };

    return CheckBoxOption;

  })(Option);

  ExclusionRulesOption = (function(_super) {
    __extends(ExclusionRulesOption, _super);

    function ExclusionRulesOption() {
      this.onRemoveRow = this.onRemoveRow.bind(this);
      ExclusionRulesOption.__super__.constructor.apply(this, arguments);
      $("exclusionAddButton").addEventListener("click", this.addRule.bind(this, null));
    }

    ExclusionRulesOption.prototype.addRule = function(pattern) {
      var element, exclusionScrollBox;
      if (pattern == null) {
        pattern = "";
      }
      element = this.appendRule({
        pattern: pattern,
        passKeys: ""
      });
      this.getPattern(element).focus();
      exclusionScrollBox = $("exclusionScrollBox");
      exclusionScrollBox.scrollTop = exclusionScrollBox.scrollHeight;
      this.onUpdated();
      return element;
    };

    ExclusionRulesOption.prototype.populateElement = function(rules) {
      rules.forEach(this.appendRule.bind(this));
    };

    ExclusionRulesOption.prototype.appendRule = function(rule) {
      var element, field, row, _i, _j, _ref, _ref1;
      row = document.importNode($('exclusionRuleTemplate').content, true);
      _ref = ["pattern", "passKeys"];
      _ref1 = ["input", "change"];
      for (_i = _ref.length; 0 <= --_i; ) {
        field = _ref[_i];
        element = row.querySelector('.' + field);
        element.value = rule[field];
        for (_j = _ref1.length; 0 <= --_j; ) {
          element.addEventListener(_ref1[_j], this.onUpdated);
        }
      }
      this.getRemoveButton(row).addEventListener("click", this.onRemoveRow);
      this.element.appendChild(row);
      return this.element.children[this.element.children.length - 1];
    };

    ExclusionRulesOption.prototype.onRemoveRow = function(event) {
      var row1 = event.target.parentNode.parentNode;
      row1.parentNode.removeChild(row1);
      this.onUpdated();
    };

    ExclusionRulesOption.prototype.readValueFromElement = function() {
      var element, passKeys, pattern, rules, _i, _len, _ref, wchRegex;
      rules = [];
      wchRegex = /\s+/;
      _ref = this.element.getElementsByClassName("exclusionRuleInstance");
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        element = _ref[_i];
        pattern = this.getPattern(element).value.replace(wchRegex, "");
        if (!pattern) {
          continue;
        }
        passKeys = this.getPassKeys(element).value.replace(wchRegex, "");
        rules.push({
          pattern: pattern,
          passKeys: passKeys
        });
      }
      if (JSON.stringify(rules) === JSON.stringify(bgSettings.defaults.exclusionRules)) {
        rules = bgSettings.defaults.exclusionRules;
      }
      return rules;
    };

    ExclusionRulesOption.prototype.flatten = function(rule) {
      return (rule && rule.pattern) ? (rule.pattern + "\r" + rule.passKeys) : "";
    };

    ExclusionRulesOption.prototype.areEqual = function(a, b) {
      return a.map(this.flatten).join("\n") === b.map(this.flatten).join("\n");
    };

    ExclusionRulesOption.prototype.getPattern = function(element) {
      return element.querySelector(".pattern");
    };

    ExclusionRulesOption.prototype.getPassKeys = function(element) {
      return element.querySelector(".passKeys");
    };

    ExclusionRulesOption.prototype.getRemoveButton = function(element) {
      return element.querySelector(".exclusionRemoveButton");
    };

    return ExclusionRulesOption;

  })(Option);

  ExclusionRulesOnPopupOption = (function(_super) {
    __extends(ExclusionRulesOnPopupOption, _super);

    function ExclusionRulesOnPopupOption(url) {
      this.url = url;
      this.onKeyup = this.onKeyup.bind(this);
      ExclusionRulesOnPopupOption.__super__.constructor.apply(this,
        2 <= arguments.length ? Array.prototype.slice.call(arguments, 1) : []);
    }

    ExclusionRulesOnPopupOption.prototype.addRule = function() {
      var element = ExclusionRulesOnPopupOption.__super__.addRule.call(this,
        this.generateDefaultPattern());
      this.activatePatternWatcher(element);
      this.getPassKeys(element).focus();
      return element;
    };

    ExclusionRulesOnPopupOption.prototype.populateElement = function(rules) {
      var element, elements, haveMatch, pattern, _i, _j, _len, _len1;
      ExclusionRulesOnPopupOption.__super__.populateElement.call(this, rules);
      elements = this.element.getElementsByClassName("exclusionRuleInstance");
      for (_i = 0, _len = elements.length; _i < _len; _i++) {
        this.activatePatternWatcher(elements[_i]);
      }
      haveMatch = false;
      for (_j = 0, _len1 = elements.length; _j < _len1; _j++) {
        element = elements[_j];
        pattern = this.getPattern(element).value.trim();
        if (0 <= this.url.search(bgExclusions.getRegex(pattern))) {
          haveMatch = true;
          this.getPassKeys(element).focus();
        } else {
          element.style.display = 'none';
        }
      }
      if (!haveMatch) {
        this.addRule();
      }
    };

    ExclusionRulesOnPopupOption.prototype.activatePatternWatcher = function(element) {
      this.getPattern(element).addEventListener("keyup", this.onKeyup);
    };

    ExclusionRulesOnPopupOption.prototype.onKeyup = function(event) {
      var patternElement = event.target;
      if (this.url.match(bgExclusions.getRegex(patternElement.value))) {
        patternElement.title = patternElement.style.color = "";
      } else {
        patternElement.style.color = "red";
        patternElement.title = "Red text means that the pattern does not\nmatch the current URL.";
      }
    }

    ExclusionRulesOnPopupOption.httpRegex = /^https?:\/\/./;
    ExclusionRulesOnPopupOption.urlRegex = /^[a-z]{3,}:\/\/./;
    ExclusionRulesOnPopupOption.prototype.generateDefaultPattern = function() {
      return ExclusionRulesOnPopupOption.httpRegex.test(this.url)
        ? ("https?://" + this.url.split("/", 3)[2] + "/*") // TODO: check why;
        : ExclusionRulesOnPopupOption.urlRegex.test(this.url)
        ? (this.url.split("/", 3).join("/") + "/*")
        : (this.url + "*");
    };

    return ExclusionRulesOnPopupOption;

  })(ExclusionRulesOption);

  initOptionsPage = function() {
    var activateHelpDialog, element, maintainLinkHintsView, name, onUpdated //
      , options, saveOptions, toggleAdvancedOptions, type, _i, _ref;

    onUpdated = function() {
      var saveBtn = $("saveOptions");
      saveBtn.removeAttribute("disabled");
      saveBtn.innerHTML = "Save Changes";
    };

    maintainLinkHintsView = function() {
      var hide, show;
      hide = function(el) {
        el.parentNode.parentNode.style.display = "none";
      };
      show = function(el) {
        el.parentNode.parentNode.style.display = "table-row";
      };
      if ($("filterLinkHints").checked) {
        hide($("linkHintCharacters"));
        show($("linkHintNumbers"));
      } else {
        show($("linkHintCharacters"));
        hide($("linkHintNumbers"));
      }
    };

    var _advancedMode = !bgSettings.get("showAdvancedOptions");
    toggleAdvancedOptions = function(event) {
      if (_advancedMode) {
        $("advancedOptions").style.display = "none";
        $("advancedOptionsLink").innerHTML = "Show advanced options…";
      } else {
        $("advancedOptions").style.display = "table-row-group";
        $("advancedOptionsLink").innerHTML = "Hide advanced options";
      }
      _advancedMode = !_advancedMode;
      bgSettings.set("showAdvancedOptions", _advancedMode);
      event.preventDefault();
      document.activeElement.blur();
    };

    activateHelpDialog = function() {
      showHelpDialog({
        html: chrome.extension.getBackgroundPage().helpDialogHtml(true, true, "Command Listing"),
        advanced: bgSettings.get("showAdvancedCommands")
      });
      document.activeElement.blur();
    };

    saveOptions = function() {
      var btn = $("saveOptions");
      if (btn.disabled) {
        return;
      }
      Option.saveOptions();
      btn.disabled = true;
      btn.innerHTML = "No Changes";
      setTimeout(function () {
        window.onfocus();
        bgSettings.buildBuffer();
        chrome.extension.getBackgroundPage().sendRequestToAllTabs({
          name: "settings",
          load: bgSettings.bufferToLoad
        });
      }, 100);
    };

    $("saveOptions").addEventListener("click", saveOptions);
    $("advancedOptionsLink").addEventListener("click", toggleAdvancedOptions);
    toggleAdvancedOptions({preventDefault: function() {}});
    $("showCommands").addEventListener("click", activateHelpDialog);
    $("filterLinkHints").addEventListener("click", maintainLinkHintsView);
    _ref = document.getElementsByClassName("nonEmptyTextOption");
    for (_i = _ref.length; 0 <= --_i; ) {
      element = _ref[_i];
      element.className = element.className + " example info";
      element.innerHTML = "Leave empty to reset this option.";
    }
    maintainLinkHintsView();
    window.onbeforeunload = function() {
      if (!$("saveOptions").disabled) {
        return "You have unsaved changes to options.";
      }
    };
    document.addEventListener("keyup", function(event) {
      if (event.ctrlKey && event.keyCode === 13) {
        if (document.activeElement && document.activeElement.blur) {
          document.activeElement.blur();
        }
        saveOptions();
      }
    });

    options = {
      exclusionRules: ExclusionRulesOption,
      filterLinkHints: CheckBoxOption,
      hideHud: CheckBoxOption,
      keyMappings: TextOption,
      linkHintCharacters: NonEmptyTextOption,
      linkHintNumbers: NonEmptyTextOption,
      newTabUrl: NonEmptyTextOption,
      nextPatterns: NonEmptyTextOption,
      previousPatterns: NonEmptyTextOption,
      regexFindMode: CheckBoxOption,
      scrollStepSize: NumberOption,
      smoothScroll: CheckBoxOption,
      searchEngines: TextOption,
      searchUrl: NonEmptyTextOption,
      userDefinedCss: TextOption
    };
    for (name in options) {
      type = options[name];
      new type(name, onUpdated);
    }
  };

  initPopupPage = function(tab) {
    var exclusions, onUpdated, saveOptions, updateState, url;
    exclusions = null;
    url = chrome.extension.getBackgroundPage().urlForTab[tab.id] || tab.url;
    updateState = function() {
      var rule = bgExclusions.getRule(url, exclusions.readValueFromElement());
      $("state").innerHTML = "Vimium will " + (rule && rule.passKeys
        ? "exclude " + rule.passKeys + ""
        : rule ? "be disabled" : "be enabled");
    };
    onUpdated = function() {
      var btn = $("saveOptions");
      $("helpText").innerHTML = "Type Ctrl-Enter to save and close.";
      btn.removeAttribute("disabled");
      btn.innerHTML = "Save Changes";
      if (exclusions) {
        updateState();
      }
    };
    saveOptions = function() {
      var btn = $("saveOptions");
      if (btn.disabled) {
        return;
      }
      Option.saveOptions();
      btn.innerHTML = "Saved";
      btn.disabled = true;
      var rule = bgExclusions.getRule(url);
      chrome.extension.getBackgroundPage().setIcon(tab.id //
        , rule ? (rule.passKeys ? "partial" : "disabled") : "enabled");
    };
    $("saveOptions").addEventListener("click", saveOptions);
    document.addEventListener("keyup", function(event) {
      if (event.ctrlKey && event.keyCode === 13) {
        saveOptions();
        // although the tab calls window.onfocus after it closes,
        // it is too early for the tab to know new exclusion rules.
        setTimeout(window.close, 300);
      }
    });
    exclusions = new ExclusionRulesOnPopupOption(url, "exclusionRules", onUpdated);
    updateState();
    document.addEventListener("keyup", updateState);
  };

  document.addEventListener("DOMContentLoaded", function() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "/pages/exclusions.html", true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        $("exclusionScrollBox").innerHTML = xhr.responseText;
        if (window.location.pathname.endsWith("popup.html")) {
          chrome.tabs.getSelected(null, initPopupPage);
        } else if (location.pathname.endsWith("options.html") >= 0) {
          initOptionsPage();
        }
      }
    };
    xhr.send();
  });

})();
<commit_msg>options.js: var BG = chrome.extension.getBackgroundPage();<commit_after>"use strict";
(function() {
  var $, CheckBoxOption, ExclusionRulesOption, NonEmptyTextOption, NumberOption, Option, TextOption,
    activateHelpDialog, bgSettings, bgExclusions, enableSaveButton, maintainLinkHintsView,
    ExclusionRulesOnPopupOption, initOptionsPage, initPopupPage, BG,
    __hasProp = Object.prototype.hasOwnProperty,
    __extends = function(child, parent) {
      for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
      function ctor() { this.constructor = child; } ctor.prototype = parent.prototype;
      child.prototype = new ctor(); child.__super__ = parent.prototype;
      return child;
    };

  $ = document.getElementById.bind(document);
  BG = chrome.extension.getBackgroundPage();
  bgSettings = BG.Settings;
  bgExclusions = BG.Exclusions;

  function Option(field, onUpdated) {
    this.field = field;
    this.onUpdated = onUpdated;
    this.element = $(this.field);
    this.element.addEventListener("change", this.onUpdated);
    this.fetch();
    Option.all.push(this);
  }

  Option.all = [];

  Option.prototype.fetch = function() {
    this.populateElement(this.previous = bgSettings.get(this.field));
    return this.previous;
  };

  Option.prototype.save = function() {
    var value = this.readValueFromElement();
    if (!this.areEqual(value, this.previous)) {
      bgSettings.set(this.field, this.previous = value);
    }
  };

  Option.prototype.areEqual = function(a, b) {
    return a === b;
  };

  Option.prototype.restoreToDefault = function() {
    bgSettings.clear(this.field);
    return this.fetch();
  };

  Option.saveOptions = function() {
    Option.all.forEach(function(option) {
      option.save();
    });
  };

  NumberOption = (function(_super) {
    __extends(NumberOption, _super);

    function NumberOption() {
      return NumberOption.__super__.constructor.apply(this, arguments);
    }

    NumberOption.prototype.populateElement = function(value) {
      return this.element.value = value;
    };

    NumberOption.prototype.readValueFromElement = function() {
      return parseFloat(this.element.value);
    };

    return NumberOption;

  })(Option);

  TextOption = (function(_super) {
    __extends(TextOption, _super);

    function TextOption() {
      TextOption.__super__.constructor.apply(this, arguments);
      this.element.addEventListener("input", this.onUpdated);
    }

    TextOption.prototype.populateElement = function(value) {
      return this.element.value = value.replace(/\n /g, '\n\xa0');
    };

    TextOption.prototype.readValueFromElement = function() {
      return this.element.value.trim().replace(/\xa0/g, ' ');
    };

    return TextOption;

  })(Option);

  NonEmptyTextOption = (function(_super) {
    __extends(NonEmptyTextOption, _super);

    function NonEmptyTextOption(field, enableSaveButton) {
      NonEmptyTextOption.__super__.constructor.apply(this, arguments);
      this.element.addEventListener("input", this.onUpdated);
    }

    NonEmptyTextOption.prototype.populateElement = function(value) {
      return this.element.value = value.replace(/\n /g, '\n\xa0');
    };

    NonEmptyTextOption.prototype.readValueFromElement = function() {
      var value = this.element.value.trim().replace(/\xa0/g, ' ');
      if (value) {
        return value;
      } else {
        return this.restoreToDefault();
      }
    };

    return NonEmptyTextOption;

  })(Option);

  CheckBoxOption = (function(_super) {
    __extends(CheckBoxOption, _super);

    function CheckBoxOption() {
      return CheckBoxOption.__super__.constructor.apply(this, arguments);
    }

    CheckBoxOption.prototype.populateElement = function(value) {
      return this.element.checked = value;
    };

    CheckBoxOption.prototype.readValueFromElement = function() {
      return this.element.checked;
    };

    return CheckBoxOption;

  })(Option);

  ExclusionRulesOption = (function(_super) {
    __extends(ExclusionRulesOption, _super);

    function ExclusionRulesOption() {
      this.onRemoveRow = this.onRemoveRow.bind(this);
      ExclusionRulesOption.__super__.constructor.apply(this, arguments);
      $("exclusionAddButton").addEventListener("click", this.addRule.bind(this, null));
    }

    ExclusionRulesOption.prototype.addRule = function(pattern) {
      var element, exclusionScrollBox;
      if (pattern == null) {
        pattern = "";
      }
      element = this.appendRule({
        pattern: pattern,
        passKeys: ""
      });
      this.getPattern(element).focus();
      exclusionScrollBox = $("exclusionScrollBox");
      exclusionScrollBox.scrollTop = exclusionScrollBox.scrollHeight;
      this.onUpdated();
      return element;
    };

    ExclusionRulesOption.prototype.populateElement = function(rules) {
      rules.forEach(this.appendRule.bind(this));
    };

    ExclusionRulesOption.prototype.appendRule = function(rule) {
      var element, field, row, _i, _j, _ref, _ref1;
      row = document.importNode($('exclusionRuleTemplate').content, true);
      _ref = ["pattern", "passKeys"];
      _ref1 = ["input", "change"];
      for (_i = _ref.length; 0 <= --_i; ) {
        field = _ref[_i];
        element = row.querySelector('.' + field);
        element.value = rule[field];
        for (_j = _ref1.length; 0 <= --_j; ) {
          element.addEventListener(_ref1[_j], this.onUpdated);
        }
      }
      this.getRemoveButton(row).addEventListener("click", this.onRemoveRow);
      this.element.appendChild(row);
      return this.element.children[this.element.children.length - 1];
    };

    ExclusionRulesOption.prototype.onRemoveRow = function(event) {
      var row1 = event.target.parentNode.parentNode;
      row1.parentNode.removeChild(row1);
      this.onUpdated();
    };

    ExclusionRulesOption.prototype.readValueFromElement = function() {
      var element, passKeys, pattern, rules, _i, _len, _ref, wchRegex;
      rules = [];
      wchRegex = /\s+/;
      _ref = this.element.getElementsByClassName("exclusionRuleInstance");
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        element = _ref[_i];
        pattern = this.getPattern(element).value.replace(wchRegex, "");
        if (!pattern) {
          continue;
        }
        passKeys = this.getPassKeys(element).value.replace(wchRegex, "");
        rules.push({
          pattern: pattern,
          passKeys: passKeys
        });
      }
      if (JSON.stringify(rules) === JSON.stringify(bgSettings.defaults.exclusionRules)) {
        rules = bgSettings.defaults.exclusionRules;
      }
      return rules;
    };

    ExclusionRulesOption.prototype.flatten = function(rule) {
      return (rule && rule.pattern) ? (rule.pattern + "\r" + rule.passKeys) : "";
    };

    ExclusionRulesOption.prototype.areEqual = function(a, b) {
      return a.map(this.flatten).join("\n") === b.map(this.flatten).join("\n");
    };

    ExclusionRulesOption.prototype.getPattern = function(element) {
      return element.querySelector(".pattern");
    };

    ExclusionRulesOption.prototype.getPassKeys = function(element) {
      return element.querySelector(".passKeys");
    };

    ExclusionRulesOption.prototype.getRemoveButton = function(element) {
      return element.querySelector(".exclusionRemoveButton");
    };

    return ExclusionRulesOption;

  })(Option);

  ExclusionRulesOnPopupOption = (function(_super) {
    __extends(ExclusionRulesOnPopupOption, _super);

    function ExclusionRulesOnPopupOption(url) {
      this.url = url;
      this.onKeyup = this.onKeyup.bind(this);
      ExclusionRulesOnPopupOption.__super__.constructor.apply(this,
        2 <= arguments.length ? Array.prototype.slice.call(arguments, 1) : []);
    }

    ExclusionRulesOnPopupOption.prototype.addRule = function() {
      var element = ExclusionRulesOnPopupOption.__super__.addRule.call(this,
        this.generateDefaultPattern());
      this.activatePatternWatcher(element);
      this.getPassKeys(element).focus();
      return element;
    };

    ExclusionRulesOnPopupOption.prototype.populateElement = function(rules) {
      var element, elements, haveMatch, pattern, _i, _j, _len, _len1;
      ExclusionRulesOnPopupOption.__super__.populateElement.call(this, rules);
      elements = this.element.getElementsByClassName("exclusionRuleInstance");
      for (_i = 0, _len = elements.length; _i < _len; _i++) {
        this.activatePatternWatcher(elements[_i]);
      }
      haveMatch = false;
      for (_j = 0, _len1 = elements.length; _j < _len1; _j++) {
        element = elements[_j];
        pattern = this.getPattern(element).value.trim();
        if (0 <= this.url.search(bgExclusions.getRegex(pattern))) {
          haveMatch = true;
          this.getPassKeys(element).focus();
        } else {
          element.style.display = 'none';
        }
      }
      if (!haveMatch) {
        this.addRule();
      }
    };

    ExclusionRulesOnPopupOption.prototype.activatePatternWatcher = function(element) {
      this.getPattern(element).addEventListener("keyup", this.onKeyup);
    };

    ExclusionRulesOnPopupOption.prototype.onKeyup = function(event) {
      var patternElement = event.target;
      if (this.url.match(bgExclusions.getRegex(patternElement.value))) {
        patternElement.title = patternElement.style.color = "";
      } else {
        patternElement.style.color = "red";
        patternElement.title = "Red text means that the pattern does not\nmatch the current URL.";
      }
    }

    ExclusionRulesOnPopupOption.httpRegex = /^https?:\/\/./;
    ExclusionRulesOnPopupOption.urlRegex = /^[a-z]{3,}:\/\/./;
    ExclusionRulesOnPopupOption.prototype.generateDefaultPattern = function() {
      return ExclusionRulesOnPopupOption.httpRegex.test(this.url)
        ? ("https?://" + this.url.split("/", 3)[2] + "/*") // TODO: check why;
        : ExclusionRulesOnPopupOption.urlRegex.test(this.url)
        ? (this.url.split("/", 3).join("/") + "/*")
        : (this.url + "*");
    };

    return ExclusionRulesOnPopupOption;

  })(ExclusionRulesOption);

  initOptionsPage = function() {
    var activateHelpDialog, element, maintainLinkHintsView, name, onUpdated //
      , options, saveOptions, toggleAdvancedOptions, type, _i, _ref;

    onUpdated = function() {
      var saveBtn = $("saveOptions");
      saveBtn.removeAttribute("disabled");
      saveBtn.innerHTML = "Save Changes";
    };

    maintainLinkHintsView = function() {
      var hide, show;
      hide = function(el) {
        el.parentNode.parentNode.style.display = "none";
      };
      show = function(el) {
        el.parentNode.parentNode.style.display = "table-row";
      };
      if ($("filterLinkHints").checked) {
        hide($("linkHintCharacters"));
        show($("linkHintNumbers"));
      } else {
        show($("linkHintCharacters"));
        hide($("linkHintNumbers"));
      }
    };

    var _advancedMode = !bgSettings.get("showAdvancedOptions");
    toggleAdvancedOptions = function(event) {
      if (_advancedMode) {
        $("advancedOptions").style.display = "none";
        $("advancedOptionsLink").innerHTML = "Show advanced options…";
      } else {
        $("advancedOptions").style.display = "table-row-group";
        $("advancedOptionsLink").innerHTML = "Hide advanced options";
      }
      _advancedMode = !_advancedMode;
      bgSettings.set("showAdvancedOptions", _advancedMode);
      event.preventDefault();
      document.activeElement.blur();
    };

    activateHelpDialog = function() {
      showHelpDialog({
        html: BG.helpDialogHtml(true, true, "Command Listing"),
        advanced: bgSettings.get("showAdvancedCommands")
      });
      document.activeElement.blur();
    };

    saveOptions = function() {
      var btn = $("saveOptions");
      if (btn.disabled) {
        return;
      }
      Option.saveOptions();
      btn.disabled = true;
      btn.innerHTML = "No Changes";
      setTimeout(function () {
        window.onfocus();
        bgSettings.buildBuffer();
        BG.sendRequestToAllTabs({
          name: "settings",
          load: bgSettings.bufferToLoad
        });
      }, 100);
    };

    $("saveOptions").addEventListener("click", saveOptions);
    $("advancedOptionsLink").addEventListener("click", toggleAdvancedOptions);
    toggleAdvancedOptions({preventDefault: function() {}});
    $("showCommands").addEventListener("click", activateHelpDialog);
    $("filterLinkHints").addEventListener("click", maintainLinkHintsView);
    _ref = document.getElementsByClassName("nonEmptyTextOption");
    for (_i = _ref.length; 0 <= --_i; ) {
      element = _ref[_i];
      element.className = element.className + " example info";
      element.innerHTML = "Leave empty to reset this option.";
    }
    maintainLinkHintsView();
    window.onbeforeunload = function() {
      if (!$("saveOptions").disabled) {
        return "You have unsaved changes to options.";
      }
    };
    document.addEventListener("keyup", function(event) {
      if (event.ctrlKey && event.keyCode === 13) {
        if (document.activeElement && document.activeElement.blur) {
          document.activeElement.blur();
        }
        saveOptions();
      }
    });

    options = {
      exclusionRules: ExclusionRulesOption,
      filterLinkHints: CheckBoxOption,
      hideHud: CheckBoxOption,
      keyMappings: TextOption,
      linkHintCharacters: NonEmptyTextOption,
      linkHintNumbers: NonEmptyTextOption,
      newTabUrl: NonEmptyTextOption,
      nextPatterns: NonEmptyTextOption,
      previousPatterns: NonEmptyTextOption,
      regexFindMode: CheckBoxOption,
      scrollStepSize: NumberOption,
      smoothScroll: CheckBoxOption,
      searchEngines: TextOption,
      searchUrl: NonEmptyTextOption,
      userDefinedCss: TextOption
    };
    for (name in options) {
      type = options[name];
      new type(name, onUpdated);
    }
  };

  initPopupPage = function(tab) {
    var exclusions, onUpdated, saveOptions, updateState, url;
    exclusions = null;
    url = BG.urlForTab[tab.id] || tab.url;
    updateState = function() {
      var rule = bgExclusions.getRule(url, exclusions.readValueFromElement());
      $("state").innerHTML = "Vimium will " + (rule && rule.passKeys
        ? "exclude " + rule.passKeys + ""
        : rule ? "be disabled" : "be enabled");
    };
    onUpdated = function() {
      var btn = $("saveOptions");
      $("helpText").innerHTML = "Type Ctrl-Enter to save and close.";
      btn.removeAttribute("disabled");
      btn.innerHTML = "Save Changes";
      if (exclusions) {
        updateState();
      }
    };
    saveOptions = function() {
      var btn = $("saveOptions");
      if (btn.disabled) {
        return;
      }
      Option.saveOptions();
      btn.innerHTML = "Saved";
      btn.disabled = true;
      var rule = bgExclusions.getRule(url);
      BG.setIcon(tab.id //
        , rule ? (rule.passKeys ? "partial" : "disabled") : "enabled");
    };
    $("saveOptions").addEventListener("click", saveOptions);
    document.addEventListener("keyup", function(event) {
      if (event.ctrlKey && event.keyCode === 13) {
        saveOptions();
        // although the tab calls window.onfocus after it closes,
        // it is too early for the tab to know new exclusion rules.
        setTimeout(window.close, 300);
      }
    });
    exclusions = new ExclusionRulesOnPopupOption(url, "exclusionRules", onUpdated);
    updateState();
    document.addEventListener("keyup", updateState);
  };

  document.addEventListener("DOMContentLoaded", function() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "/pages/exclusions.html", true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        $("exclusionScrollBox").innerHTML = xhr.responseText;
        if (window.location.pathname.endsWith("popup.html")) {
          chrome.tabs.getSelected(null, initPopupPage);
        } else if (location.pathname.endsWith("options.html") >= 0) {
          initOptionsPage();
        }
      }
    };
    xhr.send();
  });

})();
<|endoftext|>


<commit_before>var cdb = require('cartodb-deep-insights.js');
var AnalysisFormTypeView = require('./analyses-form-types/analysis-form-type-view');

module.exports = cdb.core.View.extend({

  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('Layer definition is required');
    if (!opts.analysisDefinitionsCollection) throw new Error('analysisDefinitionsCollection is required');
    if (!opts.viewModel) throw new Error('viewModel is required');
    this.layerDefinitionModel = opts.layerDefinitionModel;
    this.analysisDefinitionsCollection = opts.analysisDefinitionsCollection;
    this.analysisDefinitionNodesCollection = this.analysisDefinitionsCollection.analysisDefinitionNodesCollection;
    this.viewModel = opts.viewModel;
    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    this.$el.empty();
    var currentNodeId = this.viewModel.get('selectedNodeId');
    var analysisDefinitionNode = this.analysisDefinitionNodesCollection.get(currentNodeId);
    var formView = new AnalysisFormTypeView({
      analysisDefinitionNode: analysisDefinitionNode
    });
    this.addView(formView);
    this.$el.append(formView.render().el);
    return this;
  },

  _initBinds: function () {
    this.viewModel.bind('change:selectedNodeId', this.render, this);
    this.add_related_model(this.viewModel);
  }
});
<commit_msg>Increase legibility<commit_after>var cdb = require('cartodb-deep-insights.js');
var AnalysisFormTypeView = require('./analyses-form-types/analysis-form-type-view');

module.exports = cdb.core.View.extend({

  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('Layer definition is required');
    if (!opts.analysisDefinitionsCollection) throw new Error('analysisDefinitionsCollection is required');
    if (!opts.viewModel) throw new Error('viewModel is required');

    this.layerDefinitionModel = opts.layerDefinitionModel;
    this.analysisDefinitionsCollection = opts.analysisDefinitionsCollection;
    this.analysisDefinitionNodesCollection = this.analysisDefinitionsCollection.analysisDefinitionNodesCollection;
    this.viewModel = opts.viewModel;

    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    this.$el.empty();

    var currentNodeId = this.viewModel.get('selectedNodeId');
    var analysisDefinitionNode = this.analysisDefinitionNodesCollection.get(currentNodeId);
    var formView = new AnalysisFormTypeView({
      analysisDefinitionNode: analysisDefinitionNode
    });

    this.addView(formView);
    this.$el.append(formView.render().el);

    return this;
  },

  _initBinds: function () {
    this.viewModel.bind('change:selectedNodeId', this.render, this);
    this.add_related_model(this.viewModel);
  }
});
<|endoftext|>


<commit_before>import { testAction } from '../helpers';
import notificationsStore from 'new-dashboard/store/notifications';

const noop = jest.fn();

describe('notificationsStore', () => {
  describe('mutations', () => {
    let state;
    let store;
    beforeEach(() => {
      store = notificationsStore;
      state = {
        notifications: ['fake_notifications_initial']
      };
    });

    describe('.setNotifications', () => {
      it('should update the state with the new notification list', () => {
        store.mutations.setNotifications(state, ['fake_notification']);

        expect(state.notifications).toEqual(['fake_notification']);
        expect(state.isFetching).toEqual(false);
        expect(state.isErrored).toEqual(false);
        expect(state.error).toEqual([]);
      });
    });

    describe('.setRequestError', () => {
      it('should update state with the new error list', () => {
        store.mutations.setRequestError(state, 'fake_error');

        expect(state.notifications).toEqual([]);
        expect(state.isFetching).toEqual(false);
        expect(state.isErrored).toEqual(true);
        expect(state.error).toEqual('fake_error');
      });
    });

    describe('.setFetchingState', () => {
      it('should update the state and mark it as fetching reseting the list and the erros', () => {
        store.mutations.setFetchingState(state);

        expect(state.notifications).toEqual([]);
        expect(state.isFetching).toEqual(true);
        expect(state.isErrored).toEqual(false);
        expect(state.error).toEqual([]);
      });
    });
  });

  describe.only('actions', () => {
    let rootState;
    beforeEach(() => {
      rootState = {
        client: {
          getConfig: callback => callback(null, null, {
            organization_notifications: ['fake_notification']
          })
        }
      };
    });
    describe('.fetchNotifications', () => {
      describe('when the request is succesful', () => {
        it('should update the state with the given notifications and mark notifications as read', () => {
          const store = notificationsStore;
          const action = store.actions.fetchNotifications;
          const state = {};
          const actionPayload = null;
          const expectedMutations = [{
            type: 'setFetchingState'
          }, {
            type: 'setNotifications'
          }];
          const expectedActions = [{
            type: 'markNotificationsAsRead',
            payload: null
          }];

          testAction(action, actionPayload, state, expectedMutations, expectedActions, noop, rootState);
        });
      });

      describe('when the request fails', () => {
        const dummyError = { error: "Wrong 'order' parameter value. Valid values are one of [:updated_at, :size, :mapviews, :likes]" };
        beforeEach(() => {
          rootState = {
            client: {
              getConfig: callback => callback(dummyError)
            }
          };
        });

        it('should update the state with the given notifications and mark notifications as read', () => {
          const store = notificationsStore;
          const action = store.actions.fetchNotifications;
          const state = {};
          const actionPayload = null;
          const expectedMutations = [{
            'type': 'setFetchingState'
          }, {
            'payload': dummyError,
            'type': 'setRequestError'
          }];
          const expectedActions = [];

          testAction(action, actionPayload, state, expectedMutations, expectedActions, noop, rootState);
        });
      });
    });

    describe('.markNotificationsAsRead', () => {
      let store, action, state, actionPayload;
      beforeEach(() => {
        rootState.client.updateNotification = jest.fn();
        store = notificationsStore;
        action = store.actions.markNotificationsAsRead;
        state = {
          notifications: [{
            id: 'fake_id_0',
            read_at: 1
          }, {
            id: 'fake_id_1',
            read_at: null
          }]
        };
        actionPayload = {
          userId: 'fake_user_id',
          apiKey: 'fake_api_key'
        };
      });

      it('should notify the server about read_at', () => {
        testAction(action, actionPayload, state, [], [], noop, rootState);
        expect(rootState.client.updateNotification).toHaveBeenCalledWith('fake_user_id', 'fake_api_key', {
          'id': 'fake_id_1',
          'read_at': expect.any(String)
        });
      });

      it('should not modify state notifications', () => {
        testAction(action, actionPayload, state, [], [], noop, rootState);
        expect(state.notifications[1].read_at).toBeNull();
      });
    });
  });
});
<commit_msg>fix: Fix async test<commit_after>import { testAction } from '../helpers';
import notificationsStore from 'new-dashboard/store/notifications';

const noop = jest.fn();

describe('notificationsStore', () => {
  describe('mutations', () => {
    let state;
    let store;
    beforeEach(() => {
      store = notificationsStore;
      state = {
        notifications: ['fake_notifications_initial']
      };
    });

    describe('.setNotifications', () => {
      it('should update the state with the new notification list', () => {
        store.mutations.setNotifications(state, ['fake_notification']);

        expect(state.notifications).toEqual(['fake_notification']);
        expect(state.isFetching).toEqual(false);
        expect(state.isErrored).toEqual(false);
        expect(state.error).toEqual([]);
      });
    });

    describe('.setRequestError', () => {
      it('should update state with the new error list', () => {
        store.mutations.setRequestError(state, 'fake_error');

        expect(state.notifications).toEqual([]);
        expect(state.isFetching).toEqual(false);
        expect(state.isErrored).toEqual(true);
        expect(state.error).toEqual('fake_error');
      });
    });

    describe('.setFetchingState', () => {
      it('should update the state and mark it as fetching reseting the list and the erros', () => {
        store.mutations.setFetchingState(state);

        expect(state.notifications).toEqual([]);
        expect(state.isFetching).toEqual(true);
        expect(state.isErrored).toEqual(false);
        expect(state.error).toEqual([]);
      });
    });
  });

  describe('actions', () => {
    let rootState;
    beforeEach(() => {
      rootState = {
        client: {
          getConfig: callback => callback(null, null, {
            organization_notifications: ['fake_notification']
          })
        }
      };
    });
    describe('.fetchNotifications', () => {
      describe('when the request is succesful', () => {
        it('should update the state with the given notifications and mark notifications as read', done => {
          const store = notificationsStore;
          const action = store.actions.fetchNotifications;
          const state = {};
          const actionPayload = null;
          const expectedMutations = [{
            type: 'setFetchingState'
          }, {
            type: 'setNotifications',
            payload: ['fake_notification']
          }];
          const expectedActions = [{
            type: 'markNotificationsAsRead',
            payload: null
          }];

          testAction(action, actionPayload, state, expectedMutations, expectedActions, done, rootState);
        });
      });

      describe('when the request fails', () => {
        const dummyError = { error: "Wrong 'order' parameter value. Valid values are one of [:updated_at, :size, :mapviews, :likes]" };
        beforeEach(() => {
          rootState = {
            client: {
              getConfig: callback => callback(dummyError)
            }
          };
        });

        it('should update the state with the given notifications and mark notifications as read', () => {
          const store = notificationsStore;
          const action = store.actions.fetchNotifications;
          const state = {};
          const actionPayload = null;
          const expectedMutations = [{
            'type': 'setFetchingState'
          }, {
            'payload': dummyError,
            'type': 'setRequestError'
          }];
          const expectedActions = [];

          testAction(action, actionPayload, state, expectedMutations, expectedActions, noop, rootState);
        });
      });
    });

    describe('.markNotificationsAsRead', () => {
      let store, action, state, actionPayload;
      beforeEach(() => {
        rootState.client.updateNotification = jest.fn();
        store = notificationsStore;
        action = store.actions.markNotificationsAsRead;
        state = {
          notifications: [{
            id: 'fake_id_0',
            read_at: 1
          }, {
            id: 'fake_id_1',
            read_at: null
          }]
        };
        actionPayload = {
          userId: 'fake_user_id',
          apiKey: 'fake_api_key'
        };
      });

      it('should notify the server about read_at', () => {
        testAction(action, actionPayload, state, [], [], noop, rootState);
        expect(rootState.client.updateNotification).toHaveBeenCalledWith('fake_user_id', 'fake_api_key', {
          'id': 'fake_id_1',
          'read_at': expect.any(String)
        });
      });

      it('should not modify state notifications', () => {
        testAction(action, actionPayload, state, [], [], noop, rootState);
        expect(state.notifications[1].read_at).toBeNull();
      });
    });
  });
});
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import Layout from '../components/Layout'
import * as Moltin from '../utils/js/moltin'
import Button from '../components/Button'
import { addProduct } from '../actions/cart'
import type { TMoltinProduct, TMoltinImage } from '../utils/js/types'
import classNames from 'classnames'
import providerConnect from '../components/_Provider'

type Props = {
  product: TMoltinProduct,
  dispatch: () => any,
  isServer: boolean,
  initialState: Object
}

type State = {
  currentPicture: TMoltinImage,
  isLoading: boolean
}

class ProductDetails extends React.Component {
  props: Props
  state: State
  store: Object

  static async getInitialProps ({ query, req }) {
    const id = query.id || query.slug.split('_')[1]
    const product = await Moltin.fetchProduct(id)

    return { product }
  }

  componentDidMount () {
    this.setState({ currentPicture: this.props.product.images[0] })
  }

  componentDidUpdate (prevProps, prevState) {
    if (prevProps.product.id !== this.props.product.id) {
      this.setState({ currentPicture: this.props.product.images[0] })
    }
  }

  constructor (props: Props) {
    super(props)

    this.state = {
      currentPicture: null,
      isLoading: false
    }
  }

  render () {
    const { product } = this.props
    const { currentPicture, isLoading } = this.state
    const { title, description, brand, images } = product

    const addButtonCartClassName = classNames({
      'is-loading': isLoading
    })

    return product ? (
      <Layout title={title}>

                {
                  currentPicture ?  : null
                }

                {
                  images.map(this._renderPictures)
                }

{ title }

{ brand.value }

                  { description }

                  <Button type='primary' onClick={this._addProduct} className={addButtonCartClassName}>
                    Ajouter au panier
                  </Button>

      </Layout>
    ) : null
  }

  _renderPictures = (picture: TMoltinImage, i: number): React$Element<*> =>

  _changeCurrentPicture = (picture: TMoltinImage): Function => () => {
    this.setState({ currentPicture: picture })
  }

  _addProduct = (): void => {
    const { product } = this.props
    this.props.dispatch(addProduct(product))
  }
}

export default providerConnect()(ProductDetails)
<commit_msg>Add eslint rule<commit_after>// @flow
import React from 'react'
import Layout from '../components/Layout'
import * as Moltin from '../utils/js/moltin'
import Button from '../components/Button'
import { addProduct } from '../actions/cart'
import type { TMoltinProduct, TMoltinImage } from '../utils/js/types'
import classNames from 'classnames'
import providerConnect from '../components/_Provider'

type Props = {
  product: TMoltinProduct,
  dispatch: () => any,
  isServer: boolean,
  initialState: Object
}

type State = {
  currentPicture: TMoltinImage,
  isLoading: boolean
}

class ProductDetails extends React.Component {
  props: Props
  state: State
  store: Object

  static async getInitialProps ({ query, req }) {
    const id = query.id || query.slug.split('_')[1]
    const product = await Moltin.fetchProduct(id)

    return { product }
  }

  componentDidMount () {
    this.setState({ currentPicture: this.props.product.images[0] })
  }

  componentDidUpdate (prevProps, prevState) {
    if (prevProps.product.id !== this.props.product.id) {
      this.setState({ currentPicture: this.props.product.images[0] }) // eslint-disable-line react/no-did-update-set-state
    }
  }

  constructor (props: Props) {
    super(props)

    this.state = {
      currentPicture: null,
      isLoading: false
    }
  }

  render () {
    const { product } = this.props
    const { currentPicture, isLoading } = this.state
    const { title, description, brand, images } = product

    const addButtonCartClassName = classNames({
      'is-loading': isLoading
    })

    return product ? (
      <Layout title={title}>

                {
                  currentPicture ?  : null
                }

                {
                  images.map(this._renderPictures)
                }

{ title }

{ brand.value }

                  { description }

                  <Button type='primary' onClick={this._addProduct} className={addButtonCartClassName}>
                    Ajouter au panier
                  </Button>

      </Layout>
    ) : null
  }

  _renderPictures = (picture: TMoltinImage, i: number): React$Element<*> =>

  _changeCurrentPicture = (picture: TMoltinImage): Function => () => {
    this.setState({ currentPicture: picture })
  }

  _addProduct = (): void => {
    const { product } = this.props
    this.props.dispatch(addProduct(product))
  }
}

export default providerConnect()(ProductDetails)
<|endoftext|>