<commit_before>/**
 * @license AngularJS v1.3.0-beta.13
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, angular, undefined) {'use strict';

/**
 * @ngdoc module
 * @name ngMessages
 * @description
 *
 * The `ngMessages` module provides enhanced support for displaying messages within templates
 * (typically within forms or when rendering message objects that return key/value data).
 * Instead of relying on JavaScript code and/or complex ng-if statements within your form template to
 * show and hide error messages specific to the state of an input field, the `ngMessages` and
 * `ngMessage` directives are designed to handle the complexity, inheritance and priority
 * sequencing based on the order of how the messages are defined in the template.
 *
 * Currently, the ngMessages module only contains the code for the `ngMessages`
 * and `ngMessage` directives.
 *
 * # Usage
 * The `ngMessages` directive listens on a key/value collection which is set on the ngMessages attribute.
 * Since the {@link ngModel ngModel} directive exposes an `$error` object, this error object can be
 * used with `ngMessages` to display control error messages in an easier way than with just regular angular
 * template directives.
 *
 * ```html
 * <form name="myForm">
 *   <input type="text" ng-model="field" name="myField" required minlength="5" />
 *   <div ng-messages="myForm.myField.$error">
 *     <div ng-message="required">You did not enter a field</div>
 *     <div ng-message="minlength">The value entered is too short</div>
 *   </div>
 * </form>
 * ```
 *
 * Now whatever key/value entries are present within the provided object (in this case `$error`) then
 * the ngMessages directive will render the inner first ngMessage directive (depending if the key values
 * match the attribute value present on each ngMessage directive). In other words, if your errors
 * object contains the following data:
 *
 * ```javascript
 * <!-- keep in mind that ngModel automatically sets these error flags -->
 * myField.$error = { minlength : true, required : false };
 * ```
 *
 * Then the `required` message will be displayed first. When required is false then the `minlength` message
 * will be displayed right after (since these messages are ordered this way in the template HTML code).
 * The prioritization of each message is determined by what order they're present in the DOM.
 * Therefore, instead of having custom JavaScript code determine the priority of what errors are
 * present before others, the presentation of the errors are handled within the template.
 *
 * By default, ngMessages will only display one error at a time. However, if you wish to display all
 * messages then the `ng-messages-multiple` attribute flag can be used on the element containing the
 * ngMessages directive to make this happen.
 *
 * ```html
 * <div ng-messages="myForm.myField.$error" ng-messages-multiple>...</div>
 * ```
 *
 * ## Reusing and Overriding Messages
 * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline
 * template. This allows for generic collection of messages to be reused across multiple parts of an
 * application.
 *
 * ```html
 * <script type="text/ng-template" id="error-messages">
 *   <div ng-message="required">This field is required</div>
 *   <div ng-message="minlength">This field is too short</div>
 * </script>
 * <div ng-messages="myForm.myField.$error" ng-messages-include="error-messages"></div>
 * ```
 *
 * However, including generic messages may not be useful enough to match all input fields, therefore,
 * `ngMessages` provides the ability to override messages defined in the remote template by redefining
 * then within the directive container.
 *
 * ```html
 * <!-- a generic template of error messages known as "my-custom-messages" -->
 * <script type="text/ng-template" id="my-custom-messages">
 *   <div ng-message="required">This field is required</div>
 *   <div ng-message="minlength">This field is too short</div>
 * </script>
 *
 * <form name="myForm">
 *   <input type="email"
 *          id="email"
 *          name="myEmail"
 *          ng-model="email"
 *          minlength="5"
 *          required />
 *
 *   <div ng-messages="myForm.myEmail.$error" ng-messages-include="my-custom-messages">
 *     <!-- this required message has overridden the template message -->
 *     <div ng-message="required">You did not enter your email address</div>
 *
 *     <!-- this is a brand new message and will appear last in the prioritization -->
 *     <div ng-message="email">Your email address is invalid</div>
 *   </div>
 * </form>
 * ```
 *
 * In the example HTML code above the message that is set on required will override the corresponding
 * required message defined within the remote template. Therefore, with particular input fields (such
 * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied
 * while more generic messages can be used to handle other, more general input errors.
 *
 * ## Animations
 * If the `ngAnimate` module is active within the application then both the `ngMessages` and
 * `ngMessage` directives will trigger animations whenever any messages are added and removed
 * from the DOM by the `ngMessages` directive.
 *
 * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS
 * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no
 * animations present. Therefore, CSS transitions and keyframes as well as JavaScript animations can
 * hook into the animations whenever these classes are added/removed.
 *
 * Let's say that our HTML code for our messages container looks like so:
 *
 * ```html
 * <div ng-messages="myMessages" class="my-messages">
 *   <div ng-message="alert" class="some-message">...</div>
 *   <div ng-message="fail" class="some-message">...</div>
 * </div>
 * ```
 *
 * Then the CSS animation code for the message container looks like so:
 *
 * ```css
 * .my-messages {
 *   transition:1s linear all;
 * }
 * .my-messages.ng-active {
 *   // messages are visible
 * }
 * .my-messages.ng-inactive {
 *   // messages are hidden
 * }
 * ```
 *
 * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter
 * and leave animation is triggered for each particular element bound to the `ngMessage` directive.
 *
 * Therefore, the CSS code for the inner messages looks like so:
 *
 * ```css
 * .some-message {
 *   transition:1s linear all;
 * }
 *
 * .some-message.ng-enter {}
 * .some-message.ng-enter.ng-enter-active {}
 *
 * .some-message.ng-leave {}
 * .some-message.ng-leave.ng-leave-active {}
 * ```
 *
 * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
 */
angular.module('ngMessages', [])

   /**
    * @ngdoc directive
    * @module ngMessages
    * @name ngMessages
    * @restrict AE
    *
    * @description
    * `ngMessages` is a directive that is designed to show and hide messages based on the state
    * of a key/value object that is listens on. The directive itself compliments error message
    * reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
    *
    * `ngMessages` manages the state of internal messages within its container element. The internal
    * messages use the `ngMessage` directive and will be inserted/removed from the page depending
    * on if they're present within the key/value object. By default, only one message will be displayed
    * at a time and this depends on the prioritization of the messages within the template. (This can
    * be changed by using the ng-messages-multiple on the directive container.)
    *
    * A remote template can also be used to promote message reuseability and messages can also be
    * overridden.
    *
    * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
    *
    * @usage
    * ```html
    * <!-- using attribute directives -->
    * <ANY ng-messages="expression">
    *   <ANY ng-message="keyValue1">...</ANY>
    *   <ANY ng-message="keyValue2">...</ANY>
    *   <ANY ng-message="keyValue3">...</ANY>
    * </ANY>
    *
    * <!-- or by using element directives -->
    * <ng-messages for="expression">
    *   <ng-message when="keyValue1">...</ng-message>
    *   <ng-message when="keyValue2">...</ng-message>
    *   <ng-message when="keyValue3">...</ng-message>
    * </ng-messages>
    * ```
    *
    * @param {string} ngMessages an angular expression evaluating to a key/value object
    *                 (this is typically the $error object on an ngModel instance).
    * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
    * @param {string=} ngMessagesInclude|include when set, the specified template will be included into the ng-messages container
    *
    * @example
    * <example name="ngMessages-directive" module="ngMessagesExample"
    *          deps="angular-messages.js"
    *          animations="true" fixBase="true">
    *   <file name="index.html">
    *     <form name="myForm">
    *       Enter your name:
    *       <input type="text"
    *              name="myName"
    *              ng-model="name"
    *              ng-minlength="5"
    *              ng-maxlength="20"
    *              required />
    *
    *
myForm.myName.$error = {{ myForm.myName.$error | json }}

    *
    *

    *
You did not enter a field

    *
Your field is too short

    *
Your field is too long

    *

    *     </form>
    *   </file>
    *   <file name="script.js">
    *     angular.module('ngMessagesExample', ['ngMessages']);
    *   </file>
    * </example>
    */
  .directive('ngMessages', ['$compile', '$animate', '$http', '$templateCache',
                   function($compile,    $animate,   $http,   $templateCache) {
    var ACTIVE_CLASS = 'ng-active';
    var INACTIVE_CLASS = 'ng-inactive';

    return {
      restrict: 'AE',
      controller: ['$scope', function($scope) {
        this.$renderNgMessageClasses = angular.noop;

        var messages = [];
        this.registerMessage = function(index, message) {
          for(var i = 0; i < messages.length; i++) {
            if(messages[i].type == message.type) {
              if(index != i) {
                var temp = messages[index];
                messages[index] = messages[i];
                if(index < messages.length) {
                  messages[i] = temp;
                } else {
                  messages.splice(0, i); //remove the old one (and shift left)
                }
              }
              return;
            }
          }
          messages.splice(index, 0, message); //add the new one (and shift right)
        };

        this.renderMessages = function(values, multiple) {
          values = values || {};

          var found;
          angular.forEach(messages, function(message) {
            if((!found || multiple) && truthyVal(values[message.type])) {
              message.attach();
              found = true;
            } else {
              message.detach();
            }
          });

          this.renderElementClasses(found);

          function truthyVal(value) {
            return value !== null && value !== false && value;
          }
        };
      }],
      require: 'ngMessages',
      link: function($scope, element, $attrs, ctrl) {
        ctrl.renderElementClasses = function(bool) {
          bool ? $animate.setClass(element, ACTIVE_CLASS, INACTIVE_CLASS)
               : $animate.setClass(element, INACTIVE_CLASS, ACTIVE_CLASS);
        };

        //JavaScript treats empty strings as false, but ng-message-multiple by itself is an empty string
        var multiple = angular.isString($attrs.ngMessagesMultiple) ||
                       angular.isString($attrs.multiple);

        var cachedValues, watchAttr = $attrs.ngMessages || $attrs['for']; //for is a reserved keyword
        $scope.$watchCollection(watchAttr, function(values) {
          cachedValues = values;
          ctrl.renderMessages(values, multiple);
        });

        var tpl = $attrs.ngMessagesInclude || $attrs.include;
        if(tpl) {
          $http.get(tpl, { cache: $templateCache })
            .success(function processTemplate(html) {
              var after, container = angular.element('
').html(html);
              angular.forEach(container.children(), function(elm) {
               elm = angular.element(elm);
               after ? after.after(elm)
                     : element.prepend(elm); //start of the container
               after = elm;
               $compile(elm)($scope);
              });
              ctrl.renderMessages(cachedValues, multiple);
            });
        }
      }
    };
  }])

   /**
    * @ngdoc directive
    * @name ngMessage
    * @restrict AE
    * @scope
    *
    * @description
    * `ngMessage` is a directive with the purpose to show and hide a particular message.
    * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
    * must be situated since it determines which messages are visible based on the state
    * of the provided key/value map that `ngMessages` listens on.
    *
    * @usage
    * ```html
    * <!-- using attribute directives -->
    * <ANY ng-messages="expression">
    *   <ANY ng-message="keyValue1">...</ANY>
    *   <ANY ng-message="keyValue2">...</ANY>
    *   <ANY ng-message="keyValue3">...</ANY>
    * </ANY>
    *
    * <!-- or by using element directives -->
    * <ng-messages for="expression">
    *   <ng-message when="keyValue1">...</ng-message>
    *   <ng-message when="keyValue2">...</ng-message>
    *   <ng-message when="keyValue3">...</ng-message>
    * </ng-messages>
    * ```
    *
    * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
    *
    * @param {string} ngMessage a string value corresponding to the message key.
    */
  .directive('ngMessage', ['$animate', function($animate) {
    var COMMENT_NODE = 8;
    return {
      require: '^ngMessages',
      transclude: 'element',
      terminal: true,
      restrict: 'AE',
      link: function($scope, $element, $attrs, ngMessages, $transclude) {
        var index, element;

        var commentNode = $element[0];
        var parentNode = commentNode.parentNode;
        for(var i = 0, j = 0; i < parentNode.childNodes.length; i++) {
          var node = parentNode.childNodes[i];
          if(node.nodeType == COMMENT_NODE && node.nodeValue.indexOf('ngMessage') >= 0) {
            if(node === commentNode) {
              index = j;
              break;
            }
            j++;
          }
        }

        ngMessages.registerMessage(index, {
          type : $attrs.ngMessage || $attrs.when,
          attach : function() {
            if(!element) {
              $transclude($scope, function(clone) {
                $animate.enter(clone, null, $element);
                element = clone;
              });
            }
          },
          detach : function(now) {
            if(element) {
              $animate.leave(element);
              element = null;
            }
          }
        });
      }
    };
  }]);

})(window, window.angular);
<commit_msg>1.2.18 revert<commit_after><|endoftext|>


<commit_before>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2017 Google Inc.
 * https://developers.google.com/blockly/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Object for configuring and updating a workspace grid in
 * Blockly.
 * @author fenichel@google.com (Rachel Fenichel)
 */
'use strict';

goog.provide('Blockly.Grid');

goog.require('Blockly.utils');

goog.require('goog.userAgent');

/**
 * Class for a workspace's grid.
 * @param {!SVGElement} pattern The grid's SVG pattern, created during injection.
 * @param {!Object} options A dictionary of normalized options for the grid.
 *     See grid documentation:
 *     https://developers.google.com/blockly/guides/configure/web/grid
 * @constructor
 */
Blockly.Grid = function(pattern, options) {
  /**
   * The grid's SVG pattern, created during injection.
   * @type {!SVGElement}
   * @private
   */
  this.gridPattern_ = pattern;

  /**
   * The spacing of the grid lines (in px).
   * @type {number}
   * @private
   */
  this.spacing_ = options['spacing'];

  /**
   * How long the grid lines should be (in px).
   * @type {number}
   * @private
   */
  this.length_ = options['length'];

  /**
   * The horizontal grid line, if it exists.
   * @type {SVGElement}
   * @private
   */
  this.line1_ = pattern.firstChild;

  /**
   * The vertical grid line, if it exists.
   * @type {SVGElement}
   * @private
   */
  this.line2_ = this.line1_ && this.line1_.nextSibling;

  /**
   * Whether blocks should snap to the grid.
   * @type {boolean}
   * @private
   */
  this.snapToGrid_ = options['snap'];
};

/**
 * The scale of the grid, used to set stroke width on grid lines.
 * This should always be the same as the workspace scale.
 * @type {number}
 * @private
 */
Blockly.Grid.prototype.scale_ = 1;

/**
 * Dispose of this grid and unlink from the DOM.
 * @package
 */
Blockly.Grid.prototype.dispose = function() {
  this.gridPattern_ = null;
};

/**
 * Whether blocks should snap to the grid, based on the initial configuration.
 * @return {boolean} True if blocks should snap, false otherwise.
 * @package
 */
Blockly.Grid.prototype.shouldSnap = function() {
  return this.snapToGrid_;
};

/**
 * Get the spacing of the grid points (in px).
 * @return {number} The spacing of the grid points.
 * @package
 */
Blockly.Grid.prototype.getSpacing = function() {
  return this.spacing_;
};

/**
 * Get the id of the pattern element, which should be randomized to avoid
 * conflicts with other Blockly instances on the page.
 * @return {string} The pattern ID.
 * @package
 */
Blockly.Grid.prototype.getPatternId = function() {
  return this.gridPattern_.id;
};

/**
 * Update the grid with a new scale.
 * @param {number} scale The new workspace scale.
 * @package
 */
Blockly.Grid.prototype.update = function(scale) {
  this.scale_ = scale;
  // MSIE freaks if it sees a 0x0 pattern, so set empty patterns to 100x100.
  var safeSpacing = (this.spacing_ * scale) || 100;

  this.gridPattern_.setAttribute('width', safeSpacing);
  this.gridPattern_.setAttribute('height', safeSpacing);

  var half = Math.floor(this.spacing_ / 2) + 0.5;
  var start = half - this.length_ / 2;
  var end = half + this.length_ / 2;

  half *= scale;
  start *= scale;
  end *= scale;

  this.setLineAttributes_(this.line1_, scale, start, end, half, half);
  this.setLineAttributes_(this.line2_, scale, half, half, start, end);
};

/**
 * Set the attributes on one of the lines in the grid.  Use this to update the
 * length and stroke width of the grid lines.
 * @param {!SVGElement} line Which line to update.
 * @param {number} width The new stroke size (in px).
 * @param {number} x1 The new x start position of the line (in px).
 * @param {number} x2 The new x end position of the line (in px).
 * @param {number} y1 The new y start position of the line (in px).
 * @param {number} y2 The new y end position of the line (in px).
 * @private
 */
Blockly.Grid.prototype.setLineAttributes_ = function(line, width, x1, x2, y1, y2) {
  if (line) {
    line.setAttribute('stroke-width', width);
    line.setAttribute('x1', x1);
    line.setAttribute('y1', y1);
    line.setAttribute('x2', x2);
    line.setAttribute('y2', y2);
  }
};

/**
 * Move the grid to a new x and y position, and make sure that change is visible.
 * @param {number} x The new x position of the grid (in px).
 * @param {number} y The new y position ofthe grid (in px).
 * @package
 */
Blockly.Grid.prototype.moveTo = function(x, y) {
  this.gridPattern_.setAttribute('x', x);
  this.gridPattern_.setAttribute('y', y);

  if (goog.userAgent.IE || goog.userAgent.EDGE) {
    // IE/Edge doesn't notice that the x/y offsets have changed.
    // Force an update.
    this.update(this.scale_);
  }
};

/**
 * Create the DOM for the grid described by options.
 * @param {string} rnd A random ID to append to the pattern's ID.
 * @param {!Object} gridOptions The object containing grid configuration.
 * @param {!SVGElement} defs The root SVG element for this workspace's defs.
 * @return {!SVGElement} The SVG element for the grid pattern.
 * @package
 */
Blockly.Grid.createDom = function(rnd, gridOptions, defs) {
  /*
    <pattern id="blocklyGridPattern837493" patternUnits="userSpaceOnUse">
      <rect stroke="#888" />
      <rect stroke="#888" />
    </pattern>
  */
  var gridPattern = Blockly.utils.createSvgElement('pattern',
      {
        'id': 'blocklyGridPattern' + rnd,
        'patternUnits': 'userSpaceOnUse'
      }, defs);
  if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) {
    Blockly.utils.createSvgElement('line',
        {'stroke': gridOptions['colour']}, gridPattern);
    if (gridOptions['length'] > 1) {
      Blockly.utils.createSvgElement('line',
          {'stroke': gridOptions['colour']}, gridPattern);
    }
    // x1, y1, x1, x2 properties will be set later in update.
  }
  return gridPattern;
};
<commit_msg>Fix #1484<commit_after>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2017 Google Inc.
 * https://developers.google.com/blockly/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Object for configuring and updating a workspace grid in
 * Blockly.
 * @author fenichel@google.com (Rachel Fenichel)
 */
'use strict';

goog.provide('Blockly.Grid');

goog.require('Blockly.utils');

goog.require('goog.userAgent');

/**
 * Class for a workspace's grid.
 * @param {!SVGElement} pattern The grid's SVG pattern, created during injection.
 * @param {!Object} options A dictionary of normalized options for the grid.
 *     See grid documentation:
 *     https://developers.google.com/blockly/guides/configure/web/grid
 * @constructor
 */
Blockly.Grid = function(pattern, options) {
  /**
   * The grid's SVG pattern, created during injection.
   * @type {!SVGElement}
   * @private
   */
  this.gridPattern_ = pattern;

  /**
   * The spacing of the grid lines (in px).
   * @type {number}
   * @private
   */
  this.spacing_ = options['spacing'];

  /**
   * How long the grid lines should be (in px).
   * @type {number}
   * @private
   */
  this.length_ = options['length'];

  /**
   * The horizontal grid line, if it exists.
   * @type {SVGElement}
   * @private
   */
  this.line1_ = pattern.firstChild;

  /**
   * The vertical grid line, if it exists.
   * @type {SVGElement}
   * @private
   */
  this.line2_ = this.line1_ && this.line1_.nextSibling;

  /**
   * Whether blocks should snap to the grid.
   * @type {boolean}
   * @private
   */
  this.snapToGrid_ = options['snap'];
};

/**
 * The scale of the grid, used to set stroke width on grid lines.
 * This should always be the same as the workspace scale.
 * @type {number}
 * @private
 */
Blockly.Grid.prototype.scale_ = 1;

/**
 * Dispose of this grid and unlink from the DOM.
 * @package
 */
Blockly.Grid.prototype.dispose = function() {
  this.gridPattern_ = null;
};

/**
 * Whether blocks should snap to the grid, based on the initial configuration.
 * @return {boolean} True if blocks should snap, false otherwise.
 * @package
 */
Blockly.Grid.prototype.shouldSnap = function() {
  return this.snapToGrid_;
};

/**
 * Get the spacing of the grid points (in px).
 * @return {number} The spacing of the grid points.
 * @package
 */
Blockly.Grid.prototype.getSpacing = function() {
  return this.spacing_;
};

/**
 * Get the id of the pattern element, which should be randomized to avoid
 * conflicts with other Blockly instances on the page.
 * @return {string} The pattern ID.
 * @package
 */
Blockly.Grid.prototype.getPatternId = function() {
  return this.gridPattern_.id;
};

/**
 * Update the grid with a new scale.
 * @param {number} scale The new workspace scale.
 * @package
 */
Blockly.Grid.prototype.update = function(scale) {
  this.scale_ = scale;
  // MSIE freaks if it sees a 0x0 pattern, so set empty patterns to 100x100.
  var safeSpacing = (this.spacing_ * scale) || 100;

  this.gridPattern_.setAttribute('width', safeSpacing);
  this.gridPattern_.setAttribute('height', safeSpacing);

  var half = Math.floor(this.spacing_ / 2) + 0.5;
  var start = half - this.length_ / 2;
  var end = half + this.length_ / 2;

  half *= scale;
  start *= scale;
  end *= scale;

  this.setLineAttributes_(this.line1_, scale, start, end, half, half);
  this.setLineAttributes_(this.line2_, scale, half, half, start, end);
};

/**
 * Set the attributes on one of the lines in the grid.  Use this to update the
 * length and stroke width of the grid lines.
 * @param {!SVGElement} line Which line to update.
 * @param {number} width The new stroke size (in px).
 * @param {number} x1 The new x start position of the line (in px).
 * @param {number} x2 The new x end position of the line (in px).
 * @param {number} y1 The new y start position of the line (in px).
 * @param {number} y2 The new y end position of the line (in px).
 * @private
 */
Blockly.Grid.prototype.setLineAttributes_ = function(line, width, x1, x2, y1, y2) {
  if (line) {
    line.setAttribute('stroke-width', width);
    line.setAttribute('x1', x1);
    line.setAttribute('y1', y1);
    line.setAttribute('x2', x2);
    line.setAttribute('y2', y2);
  }
};

/**
 * Move the grid to a new x and y position, and make sure that change is visible.
 * @param {number} x The new x position of the grid (in px).
 * @param {number} y The new y position ofthe grid (in px).
 * @package
 */
Blockly.Grid.prototype.moveTo = function(x, y) {
  this.gridPattern_.setAttribute('x', x);
  this.gridPattern_.setAttribute('y', y);

  if (goog.userAgent.IE || goog.userAgent.EDGE) {
    // IE/Edge doesn't notice that the x/y offsets have changed.
    // Force an update.
    this.update(this.scale_);
  }
};

/**
 * Create the DOM for the grid described by options.
 * @param {string} rnd A random ID to append to the pattern's ID.
 * @param {!Object} gridOptions The object containing grid configuration.
 * @param {!SVGElement} defs The root SVG element for this workspace's defs.
 * @return {!SVGElement} The SVG element for the grid pattern.
 * @package
 */
Blockly.Grid.createDom = function(rnd, gridOptions, defs) {
  /*
    <pattern id="blocklyGridPattern837493" patternUnits="userSpaceOnUse">
      <rect stroke="#888" />
      <rect stroke="#888" />
    </pattern>
  */
  var gridPattern = Blockly.utils.createSvgElement('pattern',
      {
        'id': 'blocklyGridPattern' + rnd,
        'patternUnits': 'userSpaceOnUse'
      }, defs);
  if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) {
    Blockly.utils.createSvgElement('line',
        {'stroke': gridOptions['colour']}, gridPattern);
    if (gridOptions['length'] > 1) {
      Blockly.utils.createSvgElement('line',
          {'stroke': gridOptions['colour']}, gridPattern);
    }
    // x1, y1, x1, x2 properties will be set later in update.
  } else {
    // Edge 16 doesn't handle empty patterns
    Blockly.utils.createSvgElement('line', {}, gridPattern);
  }
  return gridPattern;
};
<|endoftext|>


<commit_before>(function($){

	module("events");

	test("multiselectopen", function(){
		expect(27);

	 	// inject widget
		el = $("<select multiple><option value='foo'>foo</option></select>").appendTo(body);
		el.multiselect({
			open: function(e,ui){
				ok( true, 'option: multiselect("open") fires open callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectopen', 'option: event type in callback');
				equals(menu().css("display"), 'block', 'menu display css property equals block');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectopen", function(e,ui){
			ok(true, 'event: multiselect("open") fires multiselectopen event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		});

		// now try to open it..
		el.multiselect("open")

		// make sure the width of the menu and button are equivalent
		equals( button().outerWidth(), menu().outerWidth(), 'button and menu widths are equivalent');

		// close
		el.multiselect("close");

		// make sure a click event on the button opens the menu as well.
		button().trigger("click");
		el.multiselect("close");

		// make sure a click event on a span inside the button opens the menu as well.
		button().find("span:first").trigger("click");

		// reset for next test
		el.multiselect("destroy").remove();

		// now try returning false prevent opening
		el = $("<select></select>")
			.appendTo(body)
			.multiselect()
			.bind("multiselectbeforeopen", function(){
				ok( true, "event: binding multiselectbeforeopen to return false (prevent from opening)" );
				return false;
			})
			.multiselect("open");

		ok( !el.multiselect("isOpen"), "multiselect is not open after multiselect('open')" );
		el.multiselect("destroy").remove();
	});

	test("multiselectclose", function(){
		expect(25);

	 	// inject widget
		el = $("<select multiple><option>foo</option></select>").appendTo(body);
		el.multiselect({
			close: function(e,ui){
				ok( true, 'option: multiselect("close") fires close callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectclose', 'option: event type in callback');
				equals(menu().css("display"), 'none', 'menu display css property equals none');
				same(ui, {}, 'option: ui hash');
			}
		})
		.bind("multiselectclose", function(e,ui){
			ok(true, 'multiselect("close") fires multiselectclose event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.multiselect("open")
		.multiselect("close")
		.multiselect("open");

		// make sure a click event on the button closes the menu as well.
		button().click();
		el.multiselect("open");

		// make sure a click event on a span inside the button closes the menu as well.
		button().find("span:first").click();

		// make sure that the menu is actually closed.  see issue #68
		ok( el.multiselect('isOpen') === false, 'menu is indeed closed' );

		el.multiselect("destroy").remove();
	});

	test("multiselectbeforeclose", function(){
		expect(8);

	 	// inject widget
		el = $("<select multiple></select>").appendTo(body);
		el.multiselect({
			beforeclose: function(e,ui){
				ok( true, 'option: multiselect("beforeclose") fires close callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectbeforeclose', 'option: event type in callback');
				same(ui, {}, 'option: ui hash');
			}
		})
		.bind("multiselectbeforeclose", function(e,ui){
			ok(true, 'multiselect("beforeclose") fires multiselectclose event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.multiselect("open")
		.multiselect("close");

		el.multiselect("destroy").remove();

		// test 'return false' functionality
		el = $("<select multiple></select>").appendTo(body);
		el.multiselect({
			beforeclose: function(){
				return false;
			}
		});

		el.multiselect('open').multiselect('close');
		ok( widget().is(':visible') && el.multiselect("isOpen"), "returning false inside callback prevents menu from closing" );
		el.multiselect("destroy").remove();
	});

	test("multiselectclick", function(){
		expect(26);

	 	var times = 0;

	 	// inject widget.  test will use the second option tag because the
	 	// first will be selected by default by some (if not all) browsers
		el = $("<select multiple><option value='1'>Option 1</option><option value='2'>Option 2</option></select>")
			.appendTo(body);

		// quick check to prove that the second option tag is NOT selected.
		ok( el.find("option").eq(1).is(":selected") === false, "option tag is not selected." );

		el.multiselect({
			click: function(e,ui){
				ok( true, 'option: triggering the click event on the second checkbox fires the click callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectclick', 'option: event type in callback');
				equals(ui.value, "2", "option: ui.value equals");
				equals(ui.text, "Option 2", "option: ui.title equals");
			}
		})
		.bind("multiselectclick", function(e,ui){
			ok(true, 'event: triggering the click event on the second checkbox triggers multiselectclick');
			equals(this, el[0], 'event: context of event');
			equals(ui.value, "2", "event: ui.value equals");
			equals(ui.text, "Option 2", "event: ui.title equals");
		})
		.bind("change", function(e){
			if( ++times === 1 ){
				equals( el.val().join(), "2", "event: select element val() within the change event is correct" );
			} else {
				equals( el.val(), null, "event: select element val() within the change event is correct" );
			}

			ok(true, "event: the select's change event fires");
		})
		.multiselect("open");

		// trigger a click event on the input
		var lastOption = menu().find("input:last")[0];
		lastOption.click();

		// make sure the option we just selected has the selected attr
		equals(el.find('option[value="2"]')[0].getAttribute("selected"), "selected", "Option has the checked attribute");

		// make sure the option we just selected has the selected attr
		lastOption.click();
		equals(el.find('option[value="2"]')[0].getAttribute("selected"), null, "After checking the option again, the selected attribute is removed");

		// make sure menu isn't closed automatically
		equals( true, el.multiselect('isOpen'), 'menu stays open' );

		el.multiselect("destroy").remove();
	});

	test("multiselectcheckall", function(){
		expect(9);

	 	// inject widget
		el = $('<select multiple><option value="1">Option 1</option><option value="2">Option 2</option></select>').appendTo(body);

		el.multiselect({
			checkAll: function(e,ui){
				ok( true, 'option: multiselect("checkAll") fires checkall callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectcheckall', 'option: event type in callback');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectcheckall", function(e,ui){
			ok( true, 'event: multiselect("checkall") fires multiselectcheckall event' );
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.bind("change", function(){
			ok(true, "event: the select's change event fires");
			equals( el.val().join(), "1,2", "event: select element val() within the change event is correct" );
		})
		.multiselect("open")
		.multiselect("checkAll");

		el.multiselect("destroy").remove();
	});

	test("multiselectuncheckall", function(){
		expect(9);

	 	// inject widget
		el = $('<select multiple><option value="1">Option 1</option><option value="2">Option 2</option></select>').appendTo(body);

		el.multiselect({
			uncheckAll: function(e,ui){
				ok( true, 'option: multiselect("uncheckAll") fires uncheckall callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectuncheckall', 'option: event type in callback');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectuncheckall", function(e,ui){
			ok( true, 'event: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.bind("change", function(){
			ok(true, "event: the select's change event fires");
			equals( el.val(), null, "event: select element val() within the change event is correct" );
		})
		.multiselect("open")
		.multiselect("uncheckAll");

		el.multiselect("destroy").remove();
	});

	test("multiselectbeforeoptgrouptoggle", function(){
		expect(9);

		// inject widget
		el = $('<select multiple><optgroup label="Set One"><option value="1">Option 1</option><option value="2">Option 2</option></optgroup></select>').appendTo(body);

		el.multiselect({
			beforeoptgrouptoggle: function(e,ui){
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectbeforeoptgrouptoggle', 'option: event type in callback');
				equals(ui.label, "Set One", 'option: ui.label equals');
				equals(ui.inputs.length, 2, 'option: number of inputs in the ui.inputs key');
			}
		})
		.bind("multiselectbeforeoptgrouptoggle", function(e,ui){
			ok( true, 'option: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			equals(ui.label, "Set One", 'event: ui.label equals');
			equals(ui.inputs.length, 2, 'event: number of inputs in the ui.inputs key');
		})
		.multiselect("open");

		menu().find("li.ui-multiselect-optgroup-label a").click();

		el.multiselect("destroy").remove();

		// test return false preventing checkboxes from activating
		el.multiselect({
			beforeoptgrouptoggle: function(){
				return false;
			},
			// if this fires the expected count will be off.  just a redundant way of checking that return false worked
            optgrouptoggle: function(){
                ok( true );
            }
		}).appendTo( body );

		menu().find("li.ui-multiselect-optgroup-label a").click();
		equals( menu().find(":input:checked").length, 0, "when returning false inside the optgrouptoggle handler, no checkboxes are checked" );

		el.multiselect("destroy").remove();
	});

	test("multiselectoptgrouptoggle", function(){
		expect(11);

		// inject widget
		el = $('<select multiple><optgroup label="Set One"><option value="1">Option 1</option><option value="2">Option 2</option></optgroup></select>').appendTo(body);

		el.multiselect({
			optgrouptoggle: function(e,ui){
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectoptgrouptoggle', 'option: event type in callback');
				equals(ui.label, "Set One", 'option: ui.label equals');
				equals(ui.inputs.length, 2, 'option: number of inputs in the ui.inputs key');
				equals(ui.checked, true, 'option: ui.checked equals true');
			}
		})
		.bind("multiselectoptgrouptoggle", function(e,ui){
			ok( true, 'option: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			equals(ui.label, "Set One", 'event: ui.label equals');
			equals(ui.inputs.length, 2, 'event: number of inputs in the ui.inputs key');
			equals(ui.checked, true, 'event: ui.checked equals true');
		})
		.multiselect("open");

		// trigger native click event on optgroup
		menu().find("li.ui-multiselect-optgroup-label a").click();
		equals( menu().find(":input:checked").length, 2, "both checkboxes are actually checked" );

		el.multiselect("destroy").remove();
	});

})(jQuery);
<commit_msg>change event unit tests<commit_after>(function($){

	module("events");

	test("multiselectopen", function(){
		expect(27);

	 	// inject widget
		el = $("<select multiple><option value='foo'>foo</option></select>").appendTo(body);
		el.multiselect({
			open: function(e,ui){
				ok( true, 'option: multiselect("open") fires open callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectopen', 'option: event type in callback');
				equals(menu().css("display"), 'block', 'menu display css property equals block');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectopen", function(e,ui){
			ok(true, 'event: multiselect("open") fires multiselectopen event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		});

		// now try to open it..
		el.multiselect("open")

		// make sure the width of the menu and button are equivalent
		equals( button().outerWidth(), menu().outerWidth(), 'button and menu widths are equivalent');

		// close
		el.multiselect("close");

		// make sure a click event on the button opens the menu as well.
		button().trigger("click");
		el.multiselect("close");

		// make sure a click event on a span inside the button opens the menu as well.
		button().find("span:first").trigger("click");

		// reset for next test
		el.multiselect("destroy").remove();

		// now try returning false prevent opening
		el = $("<select></select>")
			.appendTo(body)
			.multiselect()
			.bind("multiselectbeforeopen", function(){
				ok( true, "event: binding multiselectbeforeopen to return false (prevent from opening)" );
				return false;
			})
			.multiselect("open");

		ok( !el.multiselect("isOpen"), "multiselect is not open after multiselect('open')" );
		el.multiselect("destroy").remove();
	});

	test("multiselectclose", function(){
		expect(25);

	 	// inject widget
		el = $("<select multiple><option>foo</option></select>").appendTo(body);
		el.multiselect({
			close: function(e,ui){
				ok( true, 'option: multiselect("close") fires close callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectclose', 'option: event type in callback');
				equals(menu().css("display"), 'none', 'menu display css property equals none');
				same(ui, {}, 'option: ui hash');
			}
		})
		.bind("multiselectclose", function(e,ui){
			ok(true, 'multiselect("close") fires multiselectclose event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.multiselect("open")
		.multiselect("close")
		.multiselect("open");

		// make sure a click event on the button closes the menu as well.
		button().click();
		el.multiselect("open");

		// make sure a click event on a span inside the button closes the menu as well.
		button().find("span:first").click();

		// make sure that the menu is actually closed.  see issue #68
		ok( el.multiselect('isOpen') === false, 'menu is indeed closed' );

		el.multiselect("destroy").remove();
	});

	test("multiselectbeforeclose", function(){
		expect(8);

	 	// inject widget
		el = $("<select multiple></select>").appendTo(body);
		el.multiselect({
			beforeclose: function(e,ui){
				ok( true, 'option: multiselect("beforeclose") fires close callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectbeforeclose', 'option: event type in callback');
				same(ui, {}, 'option: ui hash');
			}
		})
		.bind("multiselectbeforeclose", function(e,ui){
			ok(true, 'multiselect("beforeclose") fires multiselectclose event');
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.multiselect("open")
		.multiselect("close");

		el.multiselect("destroy").remove();

		// test 'return false' functionality
		el = $("<select multiple></select>").appendTo(body);
		el.multiselect({
			beforeclose: function(){
				return false;
			}
		});

		el.multiselect('open').multiselect('close');
		ok( widget().is(':visible') && el.multiselect("isOpen"), "returning false inside callback prevents menu from closing" );
		el.multiselect("destroy").remove();
	});

	test("multiselectclick", function(){
		expect(26);

	 	var times = 0;

	 	// inject widget.  test will use the second option tag because the
	 	// first will be selected by default by some (if not all) browsers
		el = $("<select multiple><option value='1'>Option 1</option><option value='2'>Option 2</option></select>")
			.appendTo(body);

		// quick check to prove that the second option tag is NOT selected.
		ok( el.find("option").eq(1).is(":selected") === false, "option tag is not selected." );

		el.multiselect({
			click: function(e,ui){
				ok( true, 'option: triggering the click event on the second checkbox fires the click callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectclick', 'option: event type in callback');
				equals(ui.value, "2", "option: ui.value equals");
				equals(ui.text, "Option 2", "option: ui.title equals");
			}
		})
		.bind("multiselectclick", function(e,ui){
			ok(true, 'event: triggering the click event on the second checkbox triggers multiselectclick');
			equals(this, el[0], 'event: context of event');
			equals(ui.value, "2", "event: ui.value equals");
			equals(ui.text, "Option 2", "event: ui.title equals");
		})
		.bind("change", function(e){
			if( ++times === 1 ){
				equals( el.val().join(), "2", "event: select element val() within the change event is correct" );
			} else {
				equals( el.val(), null, "event: select element val() within the change event is correct" );
			}

			ok(true, "event: the select's change event fires");
		})
		.multiselect("open");

		// trigger a click event on the input
		var lastOption = menu().find("input:last")[0];
		lastOption.click();

		// make sure the option we just selected has the selected attr
		equals(el.find('option[value="2"]')[0].getAttribute("selected"), "selected", "Option has the checked attribute");

		// make sure the option we just selected has the selected attr
		lastOption.click();
		equals(el.find('option[value="2"]')[0].getAttribute("selected"), null, "After checking the option again, the selected attribute is removed");

		// make sure menu isn't closed automatically
		equals( true, el.multiselect('isOpen'), 'menu stays open' );

		el.multiselect("destroy").remove();
	});

	test("multiselectcheckall", function(){
		expect(9);

	 	// inject widget
		el = $('<select multiple><option value="1">Option 1</option><option value="2">Option 2</option></select>').appendTo(body);

		el.multiselect({
			checkAll: function(e,ui){
				ok( true, 'option: multiselect("checkAll") fires checkall callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectcheckall', 'option: event type in callback');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectcheckall", function(e,ui){
			ok( true, 'event: multiselect("checkall") fires multiselectcheckall event' );
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.bind("change", function(){
			ok(true, "event: the select's change event fires");
			equals( el.val().join(), "1,2", "event: select element val() within the change event is correct" );
		})
		.multiselect("open")
		.multiselect("checkAll");

		el.multiselect("destroy").remove();
	});

	test("multiselectuncheckall", function(){
		expect(9);

	 	// inject widget
		el = $('<select multiple><option value="1">Option 1</option><option value="2">Option 2</option></select>').appendTo(body);

		el.multiselect({
			uncheckAll: function(e,ui){
				ok( true, 'option: multiselect("uncheckAll") fires uncheckall callback' );
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectuncheckall', 'option: event type in callback');
				same(ui, {}, 'option: ui hash in callback');
			}
		})
		.bind("multiselectuncheckall", function(e,ui){
			ok( true, 'event: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			same(ui, {}, 'event: ui hash');
		})
		.bind("change", function(){
			ok(true, "event: the select's change event fires");
			equals( el.val(), null, "event: select element val() within the change event is correct" );
		})
		.multiselect("open")
		.multiselect("uncheckAll");

		el.multiselect("destroy").remove();
	});

	test("multiselectbeforeoptgrouptoggle", function(){
		expect(11);

		// inject widget
		el = $('<select multiple><optgroup label="Set One"><option value="1">Option 1</option><option value="2">Option 2</option></optgroup></select>').appendTo(body);

		el.multiselect({
			beforeoptgrouptoggle: function(e,ui){
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectbeforeoptgrouptoggle', 'option: event type in callback');
				equals(ui.label, "Set One", 'option: ui.label equals');
				equals(ui.inputs.length, 2, 'option: number of inputs in the ui.inputs key');
				ok(true, "option: the select's change event fires");
			}
		})
		.bind("multiselectbeforeoptgrouptoggle", function(e,ui){
			ok( true, 'option: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			equals(ui.label, "Set One", 'event: ui.label equals');
			equals(ui.inputs.length, 2, 'event: number of inputs in the ui.inputs key');
			ok(true, "event: the select's change event fires");
		})
		.multiselect("open");

		menu().find("li.ui-multiselect-optgroup-label a").click();

		el.multiselect("destroy").remove();

		// test return false preventing checkboxes from activating
		el.multiselect({
			beforeoptgrouptoggle: function(){
				return false;
			},
			// if this fires the expected count will be off.  just a redundant way of checking that return false worked
            optgrouptoggle: function(){
                ok( true );
            }
		}).appendTo( body );

		menu().find("li.ui-multiselect-optgroup-label a").click();
		equals( menu().find(":input:checked").length, 0, "when returning false inside the optgrouptoggle handler, no checkboxes are checked" );

		el.multiselect("destroy").remove();
	});

	test("multiselectoptgrouptoggle", function(){
		expect(11);

		// inject widget
		el = $('<select multiple><optgroup label="Set One"><option value="1">Option 1</option><option value="2">Option 2</option></optgroup></select>').appendTo(body);

		el.multiselect({
			optgrouptoggle: function(e,ui){
				equals(this, el[0], "option: context of callback");
				equals(e.type, 'multiselectoptgrouptoggle', 'option: event type in callback');
				equals(ui.label, "Set One", 'option: ui.label equals');
				equals(ui.inputs.length, 2, 'option: number of inputs in the ui.inputs key');
				equals(ui.checked, true, 'option: ui.checked equals true');
			}
		})
		.bind("multiselectoptgrouptoggle", function(e,ui){
			ok( true, 'option: multiselect("uncheckall") fires multiselectuncheckall event' );
			equals(this, el[0], 'event: context of event');
			equals(ui.label, "Set One", 'event: ui.label equals');
			equals(ui.inputs.length, 2, 'event: number of inputs in the ui.inputs key');
			equals(ui.checked, true, 'event: ui.checked equals true');
		})
		.multiselect("open");

		// trigger native click event on optgroup
		menu().find("li.ui-multiselect-optgroup-label a").click();
		equals( menu().find(":input:checked").length, 2, "both checkboxes are actually checked" );

		el.multiselect("destroy").remove();
	});

})(jQuery);
<|endoftext|>


<commit_before>/**
 * test frameworks
 */
window.frameworks = [
//[iframe name, file name, css query method]

["native", "native", "document.querySelectorAll"],

["mojoQuery", "../mojoQuery.js", "mojoQuery"],

["jquery-2.1.1", "http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js", "$"],

["sizzle-1.10.19", "http://apps.bdimg.com/libs/sizzle/1.10.19/sizzle.min.js", "Sizzle"],

["Ext-core-3.1.0", "http://apps.bdimg.com/libs/ext-core/3.1.0/ext-core.js", "Ext.query"],

["MooTools-1.4.5", "http://apps.bdimg.com/libs/mootools/1.4.5/mootools-yui-compressed.js", "$$"],

["dojo-1.8.3", "http://apps.bdimg.com/libs/dojo/1.8.3/dojo.js", "dojo.query"]

];
<commit_msg>Update frameworks.js<commit_after>/**
 * test frameworks
 */
window.frameworks = [
//[iframe name, file name, css query method]

    ["native", "native", "document.querySelectorAll"],

    ["mojoQuery", "../mojoQuery.js", "mojoQuery"],

    ["sizzle-latest", "https://raw.githubusercontent.com/jquery/sizzle/master/src/sizzle.js", "Sizzle"],

];
<|endoftext|>


<commit_before>/**
 * @ngdoc service
 * @name $ionicModal
 * @module ionic
 * @description
 *
 * Related: {@link ionic.controller:ionicModal ionicModal controller}.
 *
 * The Modal is a content pane that can go over the user's main view
 * temporarily.  Usually used for making a choice or editing an item.
 *
 * Put the content of the modal inside of an `<ion-modal-view>` element.
 *
 * **Notes:**
 * - A modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating
 * scope, passing in itself as an event argument. Both the modal.removed and modal.hidden events are
 * called when the modal is removed.
 *
 * - This example assumes your modal is in your main index file or another template file. If it is in its own
 * template file, remove the script tags and call it by file name.
 *
 * @usage
 * ```html
 * <script id="my-modal.html" type="text/ng-template">
 *   <ion-modal-view>
 *     <ion-header-bar>
 *       <h1 class="title">My Modal title</h1>
 *     </ion-header-bar>
 *     <ion-content>
 *       Hello!
 *     </ion-content>
 *   </ion-modal-view>
 * </script>
 * ```
 * ```js
 * angular.module('testApp', ['ionic'])
 * .controller('MyController', function($scope, $ionicModal) {
 *   $ionicModal.fromTemplateUrl('my-modal.html', {
 *     scope: $scope,
 *     animation: 'slide-in-up'
 *   }).then(function(modal) {
 *     $scope.modal = modal;
 *   });
 *   $scope.openModal = function() {
 *     $scope.modal.show();
 *   };
 *   $scope.closeModal = function() {
 *     $scope.modal.hide();
 *   };
 *   //Cleanup the modal when we're done with it!
 *   $scope.$on('$destroy', function() {
 *     $scope.modal.remove();
 *   });
 *   // Execute action on hide modal
 *   $scope.$on('modal.hidden', function() {
 *     // Execute action
 *   });
 *   // Execute action on remove modal
 *   $scope.$on('modal.removed', function() {
 *     // Execute action
 *   });
 * });
 * ```
 */
IonicModule
.factory('$ionicModal', [
  '$rootScope',
  '$ionicBody',
  '$compile',
  '$timeout',
  '$ionicPlatform',
  '$ionicTemplateLoader',
  '$$q',
  '$log',
  '$ionicClickBlock',
  '$window',
  'IONIC_BACK_PRIORITY',
function($rootScope, $ionicBody, $compile, $timeout, $ionicPlatform, $ionicTemplateLoader, $$q, $log, $ionicClickBlock, $window, IONIC_BACK_PRIORITY) {

  /**
   * @ngdoc controller
   * @name ionicModal
   * @module ionic
   * @description
   * Instantiated by the {@link ionic.service:$ionicModal} service.
   *
   * Be sure to call [remove()](#remove) when you are done with each modal
   * to clean it up and avoid memory leaks.
   *
   * Note: a modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating
   * scope, passing in itself as an event argument. Note: both modal.removed and modal.hidden are
   * called when the modal is removed.
   */
  var ModalView = ionic.views.Modal.inherit({
    /**
     * @ngdoc method
     * @name ionicModal#initialize
     * @description Creates a new modal controller instance.
     * @param {object} options An options object with the following properties:
     *  - `{object=}` `scope` The scope to be a child of.
     *    Default: creates a child of $rootScope.
     *  - `{string=}` `animation` The animation to show & hide with.
     *    Default: 'slide-in-up'
     *  - `{boolean=}` `focusFirstInput` Whether to autofocus the first input of
     *    the modal when shown.  Default: false.
     *  - `{boolean=}` `backdropClickToClose` Whether to close the modal on clicking the backdrop.
     *    Default: true.
     *  - `{boolean=}` `hardwareBackButtonClose` Whether the modal can be closed using the hardware
     *    back button on Android and similar devices.  Default: true.
     */
    initialize: function(opts) {
      ionic.views.Modal.prototype.initialize.call(this, opts);
      this.animation = opts.animation || 'slide-in-up';
    },

    /**
     * @ngdoc method
     * @name ionicModal#show
     * @description Show this modal instance.
     * @returns {promise} A promise which is resolved when the modal is finished animating in.
     */
    show: function(target) {
      var self = this;

      if (self.scope.$$destroyed) {
        $log.error('Cannot call ' + self.viewType + '.show() after remove(). Please create a new ' + self.viewType + ' instance.');
        return $$q.when();
      }

      var modalEl = jqLite(self.modalEl);

      self.el.classList.remove('hide');
      $timeout(function() {
        if (!self._isShown) return;
        $ionicBody.addClass(self.viewType + '-open');
      }, 400, false);

      if (!self.el.parentElement) {
        modalEl.addClass(self.animation);
        $ionicBody.append(self.el);
      }

      // if modal was closed while the keyboard was up, reset scroll view on
      // next show since we can only resize it once it's visible
      var scrollCtrl = modalEl.data('$$ionicScrollController');
      scrollCtrl && scrollCtrl.resize();

      if (target && self.positionView) {
        self.positionView(target, modalEl);
        // set up a listener for in case the window size changes

        self._onWindowResize = function() {
          if (self._isShown) self.positionView(target, modalEl);
        };
        ionic.on('resize', self._onWindowResize, window);
      }

      modalEl.addClass('ng-enter active')
             .removeClass('ng-leave ng-leave-active');

      self._isShown = true;
      self._deregisterBackButton = $ionicPlatform.registerBackButtonAction(
        self.hardwareBackButtonClose ? angular.bind(self, self.hide) : noop,
        IONIC_BACK_PRIORITY.modal
      );

      ionic.views.Modal.prototype.show.call(self);

      $timeout(function() {
        if (!self._isShown) return;
        modalEl.addClass('ng-enter-active');
        ionic.trigger('resize');
        self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.shown', self);
        self.el.classList.add('active');
        self.scope.$broadcast('$ionicHeader.align');
      }, 20);

      return $timeout(function() {
        if (!self._isShown) return;
        //After animating in, allow hide on backdrop click
        self.$el.on('click', function(e) {
          if (self.backdropClickToClose && e.target === self.el) {
            self.hide();
          }
        });
      }, 400);
    },

    /**
     * @ngdoc method
     * @name ionicModal#hide
     * @description Hide this modal instance.
     * @returns {promise} A promise which is resolved when the modal is finished animating out.
     */
    hide: function() {
      var self = this;
      var modalEl = jqLite(self.modalEl);

      // on iOS, clicks will sometimes bleed through/ghost click on underlying
      // elements
      $ionicClickBlock.show(600);

      self.el.classList.remove('active');
      modalEl.addClass('ng-leave');

      $timeout(function() {
        if (self._isShown) return;
        modalEl.addClass('ng-leave-active')
               .removeClass('ng-enter ng-enter-active active');
      }, 20, false);

      self.$el.off('click');
      self._isShown = false;
      self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.hidden', self);
      self._deregisterBackButton && self._deregisterBackButton();

      ionic.views.Modal.prototype.hide.call(self);

      // clean up event listeners
      if (self.positionView) {
        ionic.off('resize', self._onWindowResize, window);
      }

      return $timeout(function() {
        $ionicBody.removeClass(self.viewType + '-open');
        self.el.classList.add('hide');
      }, self.hideDelay || 320);
    },

    /**
     * @ngdoc method
     * @name ionicModal#remove
     * @description Remove this modal instance from the DOM and clean up.
     * @returns {promise} A promise which is resolved when the modal is finished animating out.
     */
    remove: function() {
      var self = this;
      self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.removed', self);

      return self.hide().then(function() {
        self.scope.$destroy();
        self.$el.remove();
      });
    },

    /**
     * @ngdoc method
     * @name ionicModal#isShown
     * @returns boolean Whether this modal is currently shown.
     */
    isShown: function() {
      return !!this._isShown;
    }
  });

  var createModal = function(templateString, options) {
    // Create a new scope for the modal
    var scope = options.scope && options.scope.$new() || $rootScope.$new(true);

    options.viewType = options.viewType || 'modal';

    extend(scope, {
      $hasHeader: false,
      $hasSubheader: false,
      $hasFooter: false,
      $hasSubfooter: false,
      $hasTabs: false,
      $hasTabsTop: false
    });

    // Compile the template
    var element = $compile('<ion-' + options.viewType + '>' + templateString + '</ion-' + options.viewType + '>')(scope);

    options.$el = element;
    options.el = element[0];
    options.modalEl = options.el.querySelector('.' + options.viewType);
    var modal = new ModalView(options);

    modal.scope = scope;

    // If this wasn't a defined scope, we can assign the viewType to the isolated scope
    // we created
    if (!options.scope) {
      scope[ options.viewType ] = modal;
    }

    return modal;
  };

  return {
    /**
     * @ngdoc method
     * @name $ionicModal#fromTemplate
     * @param {string} templateString The template string to use as the modal's
     * content.
     * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method.
     * @returns {object} An instance of an {@link ionic.controller:ionicModal}
     * controller.
     */
    fromTemplate: function(templateString, options) {
      var modal = createModal(templateString, options || {});
      return modal;
    },
    /**
     * @ngdoc method
     * @name $ionicModal#fromTemplateUrl
     * @param {string} templateUrl The url to load the template from.
     * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method.
     * options object.
     * @returns {promise} A promise that will be resolved with an instance of
     * an {@link ionic.controller:ionicModal} controller.
     */
    fromTemplateUrl: function(url, options, _) {
      var cb;
      //Deprecated: allow a callback as second parameter. Now we return a promise.
      if (angular.isFunction(options)) {
        cb = options;
        options = _;
      }
      return $ionicTemplateLoader.load(url).then(function(templateString) {
        var modal = createModal(templateString, options || {});
        cb && cb(modal);
        return modal;
      });
    }
  };
}]);
<commit_msg>fix(modal): prevent ghost clicks on open<commit_after>/**
 * @ngdoc service
 * @name $ionicModal
 * @module ionic
 * @description
 *
 * Related: {@link ionic.controller:ionicModal ionicModal controller}.
 *
 * The Modal is a content pane that can go over the user's main view
 * temporarily.  Usually used for making a choice or editing an item.
 *
 * Put the content of the modal inside of an `<ion-modal-view>` element.
 *
 * **Notes:**
 * - A modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating
 * scope, passing in itself as an event argument. Both the modal.removed and modal.hidden events are
 * called when the modal is removed.
 *
 * - This example assumes your modal is in your main index file or another template file. If it is in its own
 * template file, remove the script tags and call it by file name.
 *
 * @usage
 * ```html
 * <script id="my-modal.html" type="text/ng-template">
 *   <ion-modal-view>
 *     <ion-header-bar>
 *       <h1 class="title">My Modal title</h1>
 *     </ion-header-bar>
 *     <ion-content>
 *       Hello!
 *     </ion-content>
 *   </ion-modal-view>
 * </script>
 * ```
 * ```js
 * angular.module('testApp', ['ionic'])
 * .controller('MyController', function($scope, $ionicModal) {
 *   $ionicModal.fromTemplateUrl('my-modal.html', {
 *     scope: $scope,
 *     animation: 'slide-in-up'
 *   }).then(function(modal) {
 *     $scope.modal = modal;
 *   });
 *   $scope.openModal = function() {
 *     $scope.modal.show();
 *   };
 *   $scope.closeModal = function() {
 *     $scope.modal.hide();
 *   };
 *   //Cleanup the modal when we're done with it!
 *   $scope.$on('$destroy', function() {
 *     $scope.modal.remove();
 *   });
 *   // Execute action on hide modal
 *   $scope.$on('modal.hidden', function() {
 *     // Execute action
 *   });
 *   // Execute action on remove modal
 *   $scope.$on('modal.removed', function() {
 *     // Execute action
 *   });
 * });
 * ```
 */
IonicModule
.factory('$ionicModal', [
  '$rootScope',
  '$ionicBody',
  '$compile',
  '$timeout',
  '$ionicPlatform',
  '$ionicTemplateLoader',
  '$$q',
  '$log',
  '$ionicClickBlock',
  '$window',
  'IONIC_BACK_PRIORITY',
function($rootScope, $ionicBody, $compile, $timeout, $ionicPlatform, $ionicTemplateLoader, $$q, $log, $ionicClickBlock, $window, IONIC_BACK_PRIORITY) {

  /**
   * @ngdoc controller
   * @name ionicModal
   * @module ionic
   * @description
   * Instantiated by the {@link ionic.service:$ionicModal} service.
   *
   * Be sure to call [remove()](#remove) when you are done with each modal
   * to clean it up and avoid memory leaks.
   *
   * Note: a modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating
   * scope, passing in itself as an event argument. Note: both modal.removed and modal.hidden are
   * called when the modal is removed.
   */
  var ModalView = ionic.views.Modal.inherit({
    /**
     * @ngdoc method
     * @name ionicModal#initialize
     * @description Creates a new modal controller instance.
     * @param {object} options An options object with the following properties:
     *  - `{object=}` `scope` The scope to be a child of.
     *    Default: creates a child of $rootScope.
     *  - `{string=}` `animation` The animation to show & hide with.
     *    Default: 'slide-in-up'
     *  - `{boolean=}` `focusFirstInput` Whether to autofocus the first input of
     *    the modal when shown.  Default: false.
     *  - `{boolean=}` `backdropClickToClose` Whether to close the modal on clicking the backdrop.
     *    Default: true.
     *  - `{boolean=}` `hardwareBackButtonClose` Whether the modal can be closed using the hardware
     *    back button on Android and similar devices.  Default: true.
     */
    initialize: function(opts) {
      ionic.views.Modal.prototype.initialize.call(this, opts);
      this.animation = opts.animation || 'slide-in-up';
    },

    /**
     * @ngdoc method
     * @name ionicModal#show
     * @description Show this modal instance.
     * @returns {promise} A promise which is resolved when the modal is finished animating in.
     */
    show: function(target) {
      var self = this;

      if (self.scope.$$destroyed) {
        $log.error('Cannot call ' + self.viewType + '.show() after remove(). Please create a new ' + self.viewType + ' instance.');
        return $$q.when();
      }

      // on iOS, clicks will sometimes bleed through/ghost click on underlying
      // elements
      $ionicClickBlock.show(600);

      var modalEl = jqLite(self.modalEl);

      self.el.classList.remove('hide');
      $timeout(function() {
        if (!self._isShown) return;
        $ionicBody.addClass(self.viewType + '-open');
      }, 400, false);

      if (!self.el.parentElement) {
        modalEl.addClass(self.animation);
        $ionicBody.append(self.el);
      }

      // if modal was closed while the keyboard was up, reset scroll view on
      // next show since we can only resize it once it's visible
      var scrollCtrl = modalEl.data('$$ionicScrollController');
      scrollCtrl && scrollCtrl.resize();

      if (target && self.positionView) {
        self.positionView(target, modalEl);
        // set up a listener for in case the window size changes

        self._onWindowResize = function() {
          if (self._isShown) self.positionView(target, modalEl);
        };
        ionic.on('resize', self._onWindowResize, window);
      }

      modalEl.addClass('ng-enter active')
             .removeClass('ng-leave ng-leave-active');

      self._isShown = true;
      self._deregisterBackButton = $ionicPlatform.registerBackButtonAction(
        self.hardwareBackButtonClose ? angular.bind(self, self.hide) : noop,
        IONIC_BACK_PRIORITY.modal
      );

      ionic.views.Modal.prototype.show.call(self);

      $timeout(function() {
        if (!self._isShown) return;
        modalEl.addClass('ng-enter-active');
        ionic.trigger('resize');
        self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.shown', self);
        self.el.classList.add('active');
        self.scope.$broadcast('$ionicHeader.align');
      }, 20);

      return $timeout(function() {
        if (!self._isShown) return;
        //After animating in, allow hide on backdrop click
        self.$el.on('click', function(e) {
          if (self.backdropClickToClose && e.target === self.el) {
            self.hide();
          }
        });
      }, 400);
    },

    /**
     * @ngdoc method
     * @name ionicModal#hide
     * @description Hide this modal instance.
     * @returns {promise} A promise which is resolved when the modal is finished animating out.
     */
    hide: function() {
      var self = this;
      var modalEl = jqLite(self.modalEl);

      // on iOS, clicks will sometimes bleed through/ghost click on underlying
      // elements
      $ionicClickBlock.show(600);

      self.el.classList.remove('active');
      modalEl.addClass('ng-leave');

      $timeout(function() {
        if (self._isShown) return;
        modalEl.addClass('ng-leave-active')
               .removeClass('ng-enter ng-enter-active active');
      }, 20, false);

      self.$el.off('click');
      self._isShown = false;
      self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.hidden', self);
      self._deregisterBackButton && self._deregisterBackButton();

      ionic.views.Modal.prototype.hide.call(self);

      // clean up event listeners
      if (self.positionView) {
        ionic.off('resize', self._onWindowResize, window);
      }

      return $timeout(function() {
        $ionicBody.removeClass(self.viewType + '-open');
        self.el.classList.add('hide');
      }, self.hideDelay || 320);
    },

    /**
     * @ngdoc method
     * @name ionicModal#remove
     * @description Remove this modal instance from the DOM and clean up.
     * @returns {promise} A promise which is resolved when the modal is finished animating out.
     */
    remove: function() {
      var self = this;
      self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.removed', self);

      return self.hide().then(function() {
        self.scope.$destroy();
        self.$el.remove();
      });
    },

    /**
     * @ngdoc method
     * @name ionicModal#isShown
     * @returns boolean Whether this modal is currently shown.
     */
    isShown: function() {
      return !!this._isShown;
    }
  });

  var createModal = function(templateString, options) {
    // Create a new scope for the modal
    var scope = options.scope && options.scope.$new() || $rootScope.$new(true);

    options.viewType = options.viewType || 'modal';

    extend(scope, {
      $hasHeader: false,
      $hasSubheader: false,
      $hasFooter: false,
      $hasSubfooter: false,
      $hasTabs: false,
      $hasTabsTop: false
    });

    // Compile the template
    var element = $compile('<ion-' + options.viewType + '>' + templateString + '</ion-' + options.viewType + '>')(scope);

    options.$el = element;
    options.el = element[0];
    options.modalEl = options.el.querySelector('.' + options.viewType);
    var modal = new ModalView(options);

    modal.scope = scope;

    // If this wasn't a defined scope, we can assign the viewType to the isolated scope
    // we created
    if (!options.scope) {
      scope[ options.viewType ] = modal;
    }

    return modal;
  };

  return {
    /**
     * @ngdoc method
     * @name $ionicModal#fromTemplate
     * @param {string} templateString The template string to use as the modal's
     * content.
     * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method.
     * @returns {object} An instance of an {@link ionic.controller:ionicModal}
     * controller.
     */
    fromTemplate: function(templateString, options) {
      var modal = createModal(templateString, options || {});
      return modal;
    },
    /**
     * @ngdoc method
     * @name $ionicModal#fromTemplateUrl
     * @param {string} templateUrl The url to load the template from.
     * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method.
     * options object.
     * @returns {promise} A promise that will be resolved with an instance of
     * an {@link ionic.controller:ionicModal} controller.
     */
    fromTemplateUrl: function(url, options, _) {
      var cb;
      //Deprecated: allow a callback as second parameter. Now we return a promise.
      if (angular.isFunction(options)) {
        cb = options;
        options = _;
      }
      return $ionicTemplateLoader.load(url).then(function(templateString) {
        var modal = createModal(templateString, options || {});
        cb && cb(modal);
        return modal;
      });
    }
  };
}]);
<|endoftext|>


<commit_before>'use strict';

var http  = require('http');
var https = require('https');
var url   = require('url');

module.exports = remoteTransportFactory;

function remoteTransportFactory() {
  transport.client = { name: 'electron-application' };
  transport.depth  = 6;
  transport.level  = false;
  transport.url    = null;
  transport.requestOptions = {};

  return transport;
}

function transport(msg) {
  if (!transport.url) return;

  var data = jsonDepth({
    client: transport.client,
    data: msg.data,
    date: msg.date.getTime(),
    level: msg.level,
    styles: msg.styles,
    variables: msg.variables
  }, transport.depth + 1);

  post(transport.url, data);
}

function post(serverUrl, data) {
  var urlObject = url.parse(serverUrl);
  var htTransport = urlObject.protocol === 'https:' ? https : http;

  var body = JSON.stringify(data);

  var options = {
    hostname: urlObject.hostname,
    port:     urlObject.port,
    path:     urlObject.path,
    method:   'POST',
    headers:  {
      'Content-Length': body.length,
      'Content-Type':   'application/json'
    }
  };

  Object.assign(options, transport.requestOptions);

  var request = htTransport.request(options);
  request.write(body);
  request.end();
}

function jsonDepth(json, depth) {
  if (depth < 1) {
    if (Array.isArray(json)) return '[array]';
    if (typeof json === 'object') return '[object]';

    return json;
  }

  if (Array.isArray(json)) {
    return json.map(function (child) {
      return jsonDepth(child, depth - 1);
    });
  }

  if (json && typeof json.getMonth === 'function') {
    return json;
  }

  if (json === null) {
    return null;
  }

  if (typeof json === 'object') {
    if (typeof json.toJSON === 'function') {
      json = json.toJSON();
    }

    var newJson = {};
    for (var i in json) {
      if (!Object.prototype.hasOwnProperty.call(json, i)) continue;
      newJson[i] = jsonDepth(json[i], depth - 1);
    }

    return newJson;
  }

  return json;
}
<commit_msg>Cosmetics<commit_after>'use strict';

var http  = require('http');
var https = require('https');
var url   = require('url');

module.exports = remoteTransportFactory;

function remoteTransportFactory() {
  transport.client         = { name: 'electron-application' };
  transport.depth          = 6;
  transport.level          = false;
  transport.requestOptions = {};
  transport.url            = null;

  return transport;
}

function transport(msg) {
  if (!transport.url) return;

  var data = jsonDepth({
    client: transport.client,
    data: msg.data,
    date: msg.date.getTime(),
    level: msg.level,
    styles: msg.styles,
    variables: msg.variables
  }, transport.depth + 1);

  post(transport.url, data);
}

function post(serverUrl, data) {
  var urlObject = url.parse(serverUrl);
  var htTransport = urlObject.protocol === 'https:' ? https : http;

  var body = JSON.stringify(data);

  var options = {
    hostname: urlObject.hostname,
    port:     urlObject.port,
    path:     urlObject.path,
    method:   'POST',
    headers:  {
      'Content-Length': body.length,
      'Content-Type':   'application/json'
    }
  };

  Object.assign(options, transport.requestOptions);

  var request = htTransport.request(options);
  request.write(body);
  request.end();
}

function jsonDepth(json, depth) {
  if (depth < 1) {
    if (Array.isArray(json)) return '[array]';
    if (typeof json === 'object') return '[object]';

    return json;
  }

  if (Array.isArray(json)) {
    return json.map(function (child) {
      return jsonDepth(child, depth - 1);
    });
  }

  if (json && typeof json.getMonth === 'function') {
    return json;
  }

  if (json === null) {
    return null;
  }

  if (typeof json === 'object') {
    if (typeof json.toJSON === 'function') {
      json = json.toJSON();
    }

    var newJson = {};
    for (var i in json) {
      if (!Object.prototype.hasOwnProperty.call(json, i)) continue;
      newJson[i] = jsonDepth(json[i], depth - 1);
    }

    return newJson;
  }

  return json;
}
<|endoftext|>


<commit_before>angular.module('roscc')
    .controller('SettingsController', function($scope, localStorageService) {
        $scope.add = function() {
            $scope.settings.push( JSON.parse(JSON.stringify(defaultSetting)) ); // Clone object
            $scope.selectedSettingIndex = String($scope.settings.length - 1);
        };

        $scope.remove = function() {
            $scope.settings.splice($scope.selectedSettingIndex, 1);
            $scope.selectedSettingIndex = '0';

            if (!$scope.settings.length) {
                $scope.add();
            }
        };

        $scope.selectedSettingIndex = localStorageService.get('selectedSettingIndex');
        $scope.settings = JSON.parse(localStorageService.get('settings'));

        var defaultSetting = {
            name: 'New Setting',
            address: '',
            port: '',
            log: '/rosout', imagePreview: { port: 0, quality: 70, width: 640, height: 480 },
            battery: true,
            batteryTopic: ''
        };

        if (!$scope.settings) {
            $scope.settings = [defaultSetting];
        }

        if (!$scope.selectedSettingIndex || $scope.selectedSettingIndex > $scope.settings.length) {
            $scope.selectedSettingIndex = '0';
        }

        $scope.$watch('selectedSettingIndex', function() {
            localStorageService.set('selectedSettingIndex', $scope.selectedSettingIndex);
        });

        $scope.$watch('settings', function() {
            localStorageService.set('settings', JSON.stringify($scope.settings));
        }, true);
    });
<commit_msg>Update defaultSetting with defaut rosbridge address<commit_after>angular.module('roscc')
    .controller('SettingsController', function($scope, localStorageService) {
        $scope.add = function() {
            $scope.settings.push( JSON.parse(JSON.stringify(defaultSetting)) ); // Clone object
            $scope.selectedSettingIndex = String($scope.settings.length - 1);
        };

        $scope.remove = function() {
            $scope.settings.splice($scope.selectedSettingIndex, 1);
            $scope.selectedSettingIndex = '0';

            if (!$scope.settings.length) {
                $scope.add();
            }
        };

        $scope.selectedSettingIndex = localStorageService.get('selectedSettingIndex');
        $scope.settings = JSON.parse(localStorageService.get('settings'));

        var defaultSetting = {
            name: 'New Setting',
            address: location.hostname,
            port: 9090,
            log: '/rosout', imagePreview: { port: 0, quality: 70, width: 640, height: 480 },
            battery: true,
            batteryTopic: ''
        };

        if (!$scope.settings) {
            $scope.settings = [defaultSetting];
        }

        if (!$scope.selectedSettingIndex || $scope.selectedSettingIndex > $scope.settings.length) {
            $scope.selectedSettingIndex = '0';
        }

        $scope.$watch('selectedSettingIndex', function() {
            localStorageService.set('selectedSettingIndex', $scope.selectedSettingIndex);
        });

        $scope.$watch('settings', function() {
            localStorageService.set('settings', JSON.stringify($scope.settings));
        }, true);
    });
<|endoftext|>


<commit_before>'use strict'

function ruleNotFound(ruleName) {
  throw new Error(`Unknown rule: ${ruleName}`)
}

function mapRules(sourceRules, ruleNames) {
  return ruleNames.reduce((mappedRules, ruleName) => ({
    ...mappedRules,
    [`vue/${ruleName}`]: sourceRules[ruleName] || ruleNotFound(ruleName),
  }), {})
}

module.exports = {
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
  },
  plugins: [ 'vue' ],
  settings: {
    'import/resolver': {
      node: {
        extensions: [
          ...require('./plugin-import').settings['import/resolver'].node.extensions,
          '.vue',
        ],
      },
    },
    'import/extensions': [
      ...require('./plugin-import').settings['import/extensions'],
      '.vue',
    ],
  },
  rules: {
    // These rules share the same options as their same-named core counterparts.
    // Not only avoided duplications, but also guaranteed their settings will be kept same.
    ...mapRules(require('./stylistic-issues').rules, [
      'array-bracket-spacing',
      'block-spacing',
      'brace-style',
      'camelcase',
      'comma-dangle',
      'key-spacing',
      'no-restricted-syntax',
      'object-curly-spacing',
      'space-infix-ops',
      'space-unary-ops',
    ]),
    ...mapRules(require('./best-practices').rules, [
      'eqeqeq',
    ]),
    ...mapRules(require('./ecmascript-6').rules, [
      'arrow-spacing',
    ]),
    'vue/attribute-hyphenation': [ 'error', 'always' ],
    'vue/attributes-order': 'error',
    'vue/comment-directive': 'error',
    'vue/component-name-in-template-casing': 'off',
    'vue/html-closing-bracket-newline': 'off',
    'vue/html-closing-bracket-spacing': [ 'error', {
      startTag: 'never',
      endTag: 'never',
      selfClosingTag: 'always',
    } ],
    'vue/html-end-tags': 'off',
    'vue/html-indent': [ 'error', 2, {
      attribute: 1,
      closeBracket: 1,
      alignAttributesVertically: false,
      ignores: [],
    } ],
    'vue/html-quotes': [ 'error', 'double' ],
    'vue/html-self-closing': 'error', // leave to defaults
    'vue/jsx-uses-vars': 'error',
    'vue/match-component-file-name': 'off',
    'vue/max-attributes-per-line': 'off',
    'vue/multiline-html-element-content-newline': 'error',
    'vue/mustache-interpolation-spacing': [ 'error', 'always' ],
    'vue/name-property-casing': 'off',
    'vue/no-async-in-computed-properties': 'error',
    'vue/no-boolean-default': 'off',
    'vue/no-dupe-keys': 'error', // leave to defaults
    'vue/no-duplicate-attributes': 'error',
    'vue/no-multi-spaces': 'error',
    'vue/no-parsing-error': 'error',
    'vue/no-reserved-keys': 'error', // leave to defaults
    'vue/no-shared-component-data': 'error',
    'vue/no-side-effects-in-computed-properties': 'error',
    'vue/no-spaces-around-equal-signs-in-attribute': 'error',
    'vue/no-template-key': 'error',
    'vue/no-template-shadow': 'error',
    'vue/no-textarea-mustache': 'error',
    'vue/no-unused-components': 'error',
    'vue/no-unused-vars': 'error',
    'vue/no-use-v-if-with-v-for': 'off',
    'vue/no-v-html': 'error',
    'vue/order-in-components': 'error',
    'vue/prop-name-casing': [ 'error', 'camelCase' ],
    'vue/require-component-is': 'error',
    'vue/require-default-prop': 'error',
    'vue/require-direct-export': 'error',
    'vue/require-prop-type-constructor': 'error',
    'vue/require-prop-types': 'error',
    'vue/require-render-return': 'error',
    'vue/require-v-for-key': 'error',
    'vue/require-valid-default-prop': 'error',
    'vue/return-in-computed-property': [ 'error', {
      treatUndefinedAsUnspecified: true,
    } ],
    'vue/script-indent': [ 'error', 2, {
      baseIndent: 1,
      switchCase: 0,
      ignores: [],
    } ],
    'vue/singleline-html-element-content-newline': 'off',
    'vue/this-in-template': [ 'error', 'never' ],
    'vue/use-v-on-exact': 'error',
    'vue/v-bind-style': [ 'error', 'shorthand' ],
    'vue/v-on-function-call': 'off',
    'vue/v-on-style': [ 'error', 'shorthand' ],
    'vue/valid-template-root': 'error',
    'vue/valid-v-bind': 'error',
    'vue/valid-v-cloak': 'error',
    'vue/valid-v-else': 'error',
    'vue/valid-v-else-if': 'error',
    'vue/valid-v-for': 'error',
    'vue/valid-v-html': 'error',
    'vue/valid-v-if': 'error',
    'vue/valid-v-model': 'error',
    'vue/valid-v-on': 'error',
    'vue/valid-v-once': 'error',
    'vue/valid-v-pre': 'error',
    'vue/valid-v-show': 'error',
    'vue/valid-v-text': 'error',
  },
}
<commit_msg>fix Vue compatibility issue<commit_after>'use strict'

function ruleNotFound(ruleName) {
  throw new Error(`Unknown rule: ${ruleName}`)
}

function mapRules(sourceRules, ruleNames) {
  return ruleNames.reduce((mappedRules, ruleName) => ({
    ...mappedRules,
    [`vue/${ruleName}`]: sourceRules[ruleName] || ruleNotFound(ruleName),
  }), {})
}

module.exports = {
  extends: 'plugin:vue/base',
  settings: {
    'import/resolver': {
      node: {
        extensions: [
          ...require('./plugin-import').settings['import/resolver'].node.extensions,
          '.vue',
        ],
      },
    },
    'import/extensions': [
      ...require('./plugin-import').settings['import/extensions'],
      '.vue',
    ],
  },
  rules: {
    // These rules share the same options as their same-named core counterparts.
    // These not only avoided duplications, these also guaranteed their settings will be kept same.
    ...mapRules(require('./stylistic-issues').rules, [
      'array-bracket-spacing',
      'block-spacing',
      'brace-style',
      'camelcase',
      'comma-dangle',
      'key-spacing',
      'no-restricted-syntax',
      'object-curly-spacing',
      'space-infix-ops',
      'space-unary-ops',
    ]),
    ...mapRules(require('./best-practices').rules, [
      'eqeqeq',
    ]),
    ...mapRules(require('./ecmascript-6').rules, [
      'arrow-spacing',
    ]),
    'vue/attribute-hyphenation': [ 'error', 'always' ],
    'vue/attributes-order': 'error',
    'vue/comment-directive': 'error',
    'vue/component-name-in-template-casing': 'off',
    'vue/html-closing-bracket-newline': 'off',
    'vue/html-closing-bracket-spacing': [ 'error', {
      startTag: 'never',
      endTag: 'never',
      selfClosingTag: 'always',
    } ],
    'vue/html-end-tags': 'off',
    'vue/html-indent': [ 'error', 2, {
      attribute: 1,
      closeBracket: 1,
      alignAttributesVertically: false,
      ignores: [],
    } ],
    'vue/html-quotes': [ 'error', 'double' ],
    'vue/html-self-closing': 'error', // leave to defaults
    'vue/jsx-uses-vars': 'error',
    'vue/match-component-file-name': 'off',
    'vue/max-attributes-per-line': 'off',
    'vue/multiline-html-element-content-newline': 'error',
    'vue/mustache-interpolation-spacing': [ 'error', 'always' ],
    'vue/name-property-casing': 'off',
    'vue/no-async-in-computed-properties': 'error',
    'vue/no-boolean-default': 'off',
    'vue/no-dupe-keys': 'error', // leave to defaults
    'vue/no-duplicate-attributes': 'error',
    'vue/no-multi-spaces': 'error',
    'vue/no-parsing-error': 'error',
    'vue/no-reserved-keys': 'error', // leave to defaults
    'vue/no-shared-component-data': 'error',
    'vue/no-side-effects-in-computed-properties': 'error',
    'vue/no-spaces-around-equal-signs-in-attribute': 'error',
    'vue/no-template-key': 'error',
    'vue/no-template-shadow': 'error',
    'vue/no-textarea-mustache': 'error',
    'vue/no-unused-components': 'error',
    'vue/no-unused-vars': 'error',
    'vue/no-use-v-if-with-v-for': 'off',
    'vue/no-v-html': 'error',
    'vue/order-in-components': 'error',
    'vue/prop-name-casing': [ 'error', 'camelCase' ],
    'vue/require-component-is': 'error',
    'vue/require-default-prop': 'error',
    'vue/require-direct-export': 'error',
    'vue/require-prop-type-constructor': 'error',
    'vue/require-prop-types': 'error',
    'vue/require-render-return': 'error',
    'vue/require-v-for-key': 'error',
    'vue/require-valid-default-prop': 'error',
    'vue/return-in-computed-property': [ 'error', {
      treatUndefinedAsUnspecified: true,
    } ],
    'vue/script-indent': [ 'error', 2, {
      baseIndent: 1,
      switchCase: 0,
      ignores: [],
    } ],
    'vue/singleline-html-element-content-newline': 'off',
    'vue/this-in-template': [ 'error', 'never' ],
    'vue/use-v-on-exact': 'error',
    'vue/v-bind-style': [ 'error', 'shorthand' ],
    'vue/v-on-function-call': 'off',
    'vue/v-on-style': [ 'error', 'shorthand' ],
    'vue/valid-template-root': 'error',
    'vue/valid-v-bind': 'error',
    'vue/valid-v-cloak': 'error',
    'vue/valid-v-else': 'error',
    'vue/valid-v-else-if': 'error',
    'vue/valid-v-for': 'error',
    'vue/valid-v-html': 'error',
    'vue/valid-v-if': 'error',
    'vue/valid-v-model': 'error',
    'vue/valid-v-on': 'error',
    'vue/valid-v-once': 'error',
    'vue/valid-v-pre': 'error',
    'vue/valid-v-show': 'error',
    'vue/valid-v-text': 'error',
  },
}
<|endoftext|>


<commit_before>var _, moment, path, Rat, Rescue, winston

_ = require( 'underscore' )
moment = require( 'moment' )
path = require( 'path' )
winston = require( 'winston' )

Rat = require( '../models/rat' )
Rescue = require( '../models/rescue' )

exports.get = function ( request, response ) {
  if ( request.isUnauthenticated() ) {
    response.redirect( '/login' )

  } else {
    request.user.populate( 'CMDRs', function( error ) {
      var rescueFinds

      rescueFinds = []

      if ( error ) {
        return winston.error( error )
      }

      request.user.CMDRs.forEach( function ( CMDR, index, CMDRs ) {
        rescueFinds.push( new Promise( function ( resolve, reject ) {
          CMDR.populate( 'rescues', function ( error, rescues ) {
            if ( error ) {
              return reject( error )
            }

            CMDR.rescues.forEach( function ( rescue, index, rescues ) {
              console.log( 'createdAt', rescue.createdAt )
              console.log( 'lastModified', rescue.lastModified )
              rescue.createdAt = moment( rescue.createdAt )
              rescue.lastModified = moment( rescue.lastModified )
            })

            CMDR.rescues = _.sortBy( CMDR.rescues, 'createdAt' ).reverse()

            resolve( rescues )
          })
        }))
      })

      Promise.all( rescueFinds )
      .then( function () {
        request.user.rescues = []

        request.user.CMDRs.forEach( function ( CMDR, index, CMDRs ) {
          _.union( request.user, CMDR.rescues )
        })

        response.render( 'welcome', request.user )
      })
      .catch( function ( error ) {
        winston.error( error )
      })
    })
  }
}
<commit_msg>Make welcome page eslint compliant<commit_after>'use strict'

var _, moment, winston

_ = require('underscore')
moment = require('moment')
winston = require('winston')

exports.get = function (request, response) {
  if (request.isUnauthenticated()) {
    response.redirect('/login')

  } else {
    request.user.populate('CMDRs', function (error) {
      var rescueFinds

      rescueFinds = []

      if (error) {
        return winston.error(error)
      }

      request.user.CMDRs.forEach(function (CMDR) {
        rescueFinds.push(new Promise(function (resolve, reject) {
          CMDR.populate('rescues', function (error, rescues) {
            if (error) {
              return reject(error)
            }

            CMDR.rescues.forEach(function (rescue) {
              rescue.createdAt = moment(rescue.createdAt)
              rescue.lastModified = moment(rescue.lastModified)
            })

            CMDR.rescues = _.sortBy(CMDR.rescues, 'createdAt').reverse()

            resolve(rescues)
          })
        }))
      })

      Promise.all(rescueFinds)
        .then(function () {
          request.user.rescues = []

          request.user.CMDRs.forEach(function (CMDR) {
            _.union(request.user, CMDR.rescues)
          })

          response.render('welcome', request.user)
        })
        .catch(function (error) {
          winston.error(error)
        })
    })
  }
}
<|endoftext|>