1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5cr.define('options.internet', function() {
6  /** @const */ var EditableTextField = options.EditableTextField;
7
8  /**
9   * The regular expression that matches an IP address. String to match against
10   * should have all whitespace stripped already.
11   * @const
12   * @type {RegExp}
13   */
14  var singleIp_ = /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/;
15
16  /**
17   * Creates a new field specifically for entering IP addresses.
18   * @constructor
19   * @extends {options.EditableTextField}
20   */
21  function IPAddressField() {
22    var el = cr.doc.createElement('div');
23    IPAddressField.decorate(el);
24    return el;
25  }
26
27  /**
28   * Decorates an element as a inline-editable list item. Note that this is
29   * a subclass of IPAddressField.
30   * @param {!HTMLElement} el The element to decorate.
31   */
32  IPAddressField.decorate = function(el) {
33    el.__proto__ = IPAddressField.prototype;
34    el.decorate();
35  };
36
37  IPAddressField.prototype = {
38    __proto__: EditableTextField.prototype,
39
40    /** @override */
41    decorate: function() {
42      EditableTextField.prototype.decorate.call(this);
43    },
44
45    /**
46     * Indicates whether or not empty values are allowed.
47     * @type {boolean}
48     */
49    get allowEmpty() {
50      return this.hasAttribute('allow-empty');
51    },
52
53    /** @override */
54    get currentInputIsValid() {
55      if (!this.editField.value && this.allowEmpty)
56        return true;
57
58      // Make sure it's only got numbers and ".", there are the correct
59      // count of them, and they are all within the correct range.
60      var fieldValue = this.editField.value.replace(/\s/g, '');
61      var matches = singleIp_.exec(fieldValue);
62      var rangeCorrect = true;
63      if (matches != null) {
64        for (var i = 1; i < matches.length; ++i) {
65          var value = parseInt(matches[i], 10);
66          if (value < 0 || value > 255) {
67            rangeCorrect = false;
68            break;
69          }
70        }
71      }
72      return this.editField.validity.valid && matches != null &&
73          rangeCorrect && matches.length == 5;
74    },
75
76    /** @override */
77    get hasBeenEdited() {
78      return this.editField.value != this.model.value;
79    },
80
81    /**
82     * Overrides superclass to mutate the input during a successful commit. For
83     * the purposes of entering IP addresses, this just means stripping off
84     * whitespace and leading zeros from each of the octets so that they conform
85     * to the normal format for IP addresses.
86     * @override
87     * @param {string} value Input IP address to be mutated.
88     * @return {string} mutated IP address.
89     */
90    mutateInput: function(value) {
91      if (!value)
92        return value;
93
94      var fieldValue = value.replace(/\s/g, '');
95      var matches = singleIp_.exec(fieldValue);
96      var result = [];
97
98      // If we got this far, matches shouldn't be null, but make sure.
99      if (matches != null) {
100        // starting at one because the first match element contains the entire
101        // match, and we don't care about that.
102        for (var i = 1; i < matches.length; ++i)
103          result.push(parseInt(matches[i], 10));
104      }
105      return result.join('.');
106    },
107  };
108
109  return {
110    IPAddressField: IPAddressField,
111  };
112});
113