~didrocks/+junk/face-detection-15.04

« back to all changes in this revision

Viewing changes to facedetection/www/bower_components/iron-form/iron-form.html

  • Committer: Didier Roche
  • Date: 2016-05-10 23:09:11 UTC
  • Revision ID: didier.roche@canonical.com-20160510230911-c7xr490zrj3yrzxd
New version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!--
 
2
@license
 
3
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 
4
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 
5
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 
6
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 
7
Code distributed by Google as part of the polymer project is also
 
8
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 
9
-->
 
10
 
 
11
<link rel="import" href="../polymer/polymer.html">
 
12
<link rel="import" href="../iron-ajax/iron-ajax.html">
 
13
 
 
14
<script>
 
15
/*
 
16
`<iron-form>` is an HTML `<form>` element that can validate and submit any custom
 
17
elements that implement `Polymer.IronFormElementBehavior`, as well as any
 
18
native HTML elements. For more information on which attributes are
 
19
available on the native form element, see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form
 
20
 
 
21
It supports both `get` and `post` methods, and uses an `iron-ajax` element to
 
22
submit the form data to the action URL.
 
23
 
 
24
  Example:
 
25
 
 
26
    <form is="iron-form" id="form" method="post" action="/form/handler">
 
27
      <paper-input name="name" label="name"></paper-input>
 
28
      <input name="address">
 
29
      ...
 
30
    </form>
 
31
 
 
32
By default, a native `<button>` element will submit this form. However, if you
 
33
want to submit it from a custom element's click handler, you need to explicitly
 
34
call the form's `submit` method.
 
35
 
 
36
  Example:
 
37
 
 
38
    <paper-button raised onclick="submitForm()">Submit</paper-button>
 
39
 
 
40
    function submitForm() {
 
41
      document.getElementById('form').submit();
 
42
    }
 
43
 
 
44
To customize the request sent to the server, you can listen to the `iron-form-presubmit`
 
45
event, and modify the form's[`iron-ajax`](https://elements.polymer-project.org/elements/iron-ajax)
 
46
object. However, If you want to not use `iron-ajax` at all, you can cancel the
 
47
event and do your own custom submission:
 
48
 
 
49
  Example of modifying the request, but still using the build-in form submission:
 
50
 
 
51
    form.addEventListener('iron-form-presubmit', function() {
 
52
      this.request.method = 'put';
 
53
      this.request.params = someCustomParams;
 
54
    });
 
55
 
 
56
  Example of bypassing the build-in form submission:
 
57
 
 
58
    form.addEventListener('iron-form-presubmit', function(event) {
 
59
      event.preventDefault();
 
60
      var firebase = new Firebase(form.getAttribute('action'));
 
61
      firebase.set(form.serialize());
 
62
    });
 
63
 
 
64
@demo demo/index.html
 
65
*/
 
66
  Polymer({
 
67
 
 
68
    is: 'iron-form',
 
69
 
 
70
    extends: 'form',
 
71
 
 
72
    properties: {
 
73
      /**
 
74
       * By default, the form will display the browser's native validation
 
75
       * UI (i.e. popup bubbles and invalid styles on invalid fields). You can
 
76
       * manually disable this; however, if you do, note that you will have to
 
77
       * manually style invalid *native* HTML fields yourself, as you are
 
78
       * explicitly preventing the native form from doing so.
 
79
       */
 
80
      disableNativeValidationUi: {
 
81
        type: Boolean,
 
82
        value: false
 
83
      },
 
84
 
 
85
      /**
 
86
      * Set the withCredentials flag when sending data.
 
87
      */
 
88
      withCredentials: {
 
89
        type: Boolean,
 
90
        value: false
 
91
      },
 
92
 
 
93
      /**
 
94
       * Content type to use when sending data. If the `contentType` property
 
95
       * is set and a `Content-Type` header is specified in the `headers`
 
96
       * property, the `headers` property value will take precedence.
 
97
       * If Content-Type is set to a value listed below, then
 
98
       * the `body` (typically used with POST requests) will be encoded accordingly.
 
99
       *
 
100
       *    * `content-type="application/json"`
 
101
       *      * body is encoded like `{"foo":"bar baz","x":1}`
 
102
       *    * `content-type="application/x-www-form-urlencoded"`
 
103
       *      * body is encoded like `foo=bar+baz&x=1`
 
104
       */
 
105
      contentType: {
 
106
        type: String,
 
107
        value: "application/x-www-form-urlencoded"
 
108
      },
 
109
 
 
110
      /**
 
111
      * HTTP request headers to send.
 
112
      *
 
113
      * Note: setting a `Content-Type` header here will override the value
 
114
      * specified by the `contentType` property of this element.
 
115
      */
 
116
      headers: {
 
117
        type: Object,
 
118
        value: function() {
 
119
          return {};
 
120
        }
 
121
      },
 
122
 
 
123
      /**
 
124
      * iron-ajax request object used to submit the form.
 
125
      */
 
126
      request: {
 
127
        type: Object,
 
128
      }
 
129
    },
 
130
 
 
131
    /**
 
132
     * Fired if the form cannot be submitted because it's invalid.
 
133
     *
 
134
     * @event iron-form-invalid
 
135
     */
 
136
 
 
137
    /**
 
138
     * Fired before the form is submitted.
 
139
     *
 
140
     * @event iron-form-presubmit
 
141
     */
 
142
 
 
143
    /**
 
144
     * Fired after the form is submitted.
 
145
     *
 
146
     * @event iron-form-submit
 
147
     */
 
148
 
 
149
     /**
 
150
      * Fired after the form is reset.
 
151
      *
 
152
      * @event iron-form-reset
 
153
      */
 
154
 
 
155
    /**
 
156
    * Fired after the form is submitted and a response is received. An
 
157
    * IronRequestElement is included as the event.detail object.
 
158
    *
 
159
    * @event iron-form-response
 
160
    */
 
161
 
 
162
    /**
 
163
     * Fired after the form is submitted and an error is received. An
 
164
     * IronRequestElement is included as the event.detail object.
 
165
     *
 
166
     * @event iron-form-error
 
167
     */
 
168
    listeners: {
 
169
      'iron-form-element-register': '_registerElement',
 
170
      'iron-form-element-unregister': '_unregisterElement',
 
171
      'submit': '_onSubmit',
 
172
      'reset': '_onReset'
 
173
    },
 
174
 
 
175
    registered: function() {
 
176
      // Dear reader: I apologize for what you're about to experience. You see,
 
177
      // Safari does not respect `required` on input elements, so it never
 
178
      // has any browser validation bubbles to show. And we have to feature
 
179
      // detect that, since we rely on the form submission to do the right thing.
 
180
      // See http://caniuse.com/#search=required.
 
181
 
 
182
      // Create a fake form, with an invalid input. If it gets submitted, it's Safari.
 
183
      var form = document.createElement('form');
 
184
      var input = document.createElement('input');
 
185
      input.setAttribute('required', 'true');
 
186
      form.appendChild(input);
 
187
 
 
188
      // If you call submit(), the form doesn't actually fire a submit event,
 
189
      // so you can't intercept it and cancel it. The event is only fired
 
190
      // from the magical button click submission.
 
191
      // See http://wayback.archive.org/web/20090323062817/http://blogs.vertigosoftware.com/snyholm/archive/2006/09/27/3788.aspx.
 
192
      var button = document.createElement('input');
 
193
      button.setAttribute('type', 'submit');
 
194
      form.appendChild(button);
 
195
 
 
196
      Polymer.clientSupportsFormValidationUI = true;
 
197
      form.addEventListener('submit', function(event) {
 
198
        // Oh good! We don't handle `required` correctly.
 
199
        Polymer.clientSupportsFormValidationUI = false;
 
200
        event.preventDefault();
 
201
      });
 
202
      button.click();
 
203
    },
 
204
 
 
205
    ready: function() {
 
206
      // Object that handles the ajax form submission request.
 
207
      this.request = document.createElement('iron-ajax');
 
208
      this.request.addEventListener('response', this._handleFormResponse.bind(this));
 
209
      this.request.addEventListener('error', this._handleFormError.bind(this));
 
210
 
 
211
      // Holds all the custom elements registered with this form.
 
212
      this._customElements = [];
 
213
      // Holds the initial values of the custom elements registered with this form.
 
214
      this._customElementsInitialValues = [];
 
215
    },
 
216
 
 
217
    /**
 
218
     * Submits the form.
 
219
     */
 
220
    submit: function() {
 
221
      if (!this.noValidate && !this.validate()) {
 
222
        // In order to trigger the native browser invalid-form UI, we need
 
223
        // to do perform a fake form submit.
 
224
        if (Polymer.clientSupportsFormValidationUI && !this.disableNativeValidationUi) {
 
225
          this._doFakeSubmitForValidation();
 
226
        }
 
227
        this.fire('iron-form-invalid');
 
228
        return;
 
229
      }
 
230
 
 
231
      var json = this.serialize();
 
232
 
 
233
      // Native forms can also index elements magically by their name (can't make
 
234
      // this up if I tried) so we need to get the correct attributes, not the
 
235
      // elements with those names.
 
236
      this.request.url = this.getAttribute('action');
 
237
      this.request.method = this.getAttribute('method');
 
238
      this.request.contentType = this.contentType;
 
239
      this.request.withCredentials = this.withCredentials;
 
240
      this.request.headers = this.headers;
 
241
 
 
242
      if (this.method.toUpperCase() === 'POST') {
 
243
        this.request.body = json;
 
244
      } else {
 
245
        this.request.params = json;
 
246
      }
 
247
 
 
248
      // Allow for a presubmit hook
 
249
      var event = this.fire('iron-form-presubmit', {}, {cancelable: true});
 
250
      if(!event.defaultPrevented) {
 
251
        this.request.generateRequest();
 
252
        this.fire('iron-form-submit', json);
 
253
      }
 
254
    },
 
255
 
 
256
    /**
 
257
     * Handler that is called when the native form fires a `submit` event
 
258
     *
 
259
     * @param {Event} event A `submit` event.
 
260
     */
 
261
    _onSubmit: function(event) {
 
262
      this.submit();
 
263
 
 
264
      // Don't perform a page refresh.
 
265
      if (event) {
 
266
        event.preventDefault();
 
267
      }
 
268
 
 
269
      return false;
 
270
    },
 
271
 
 
272
    /**
 
273
     * Handler that is called when the native form fires a `reset` event
 
274
     *
 
275
     * @param {Event} event A `reset` event.
 
276
     */
 
277
    _onReset: function(event) {
 
278
      this._resetCustomElements();
 
279
    },
 
280
 
 
281
    /**
 
282
     * Returns a json object containing name/value pairs for all the registered
 
283
     * custom components and native elements of the form. If there are elements
 
284
     * with duplicate names, then their values will get aggregated into an
 
285
     * array of values.
 
286
     *
 
287
     * @return {!Object}
 
288
     */
 
289
    serialize: function() {
 
290
      var json = {};
 
291
 
 
292
      function addSerializedElement(name, value) {
 
293
        // If the name doesn't exist, add it. Otherwise, serialize it to
 
294
        // an array,
 
295
        if (!json[name]) {
 
296
          json[name] = value;
 
297
        } else {
 
298
          if (!Array.isArray(json[name])) {
 
299
            json[name] = [json[name]];
 
300
          }
 
301
          json[name].push(value);
 
302
        }
 
303
      }
 
304
 
 
305
      // Go through all of the registered custom components.
 
306
      for (var el, i = 0; el = this._customElements[i], i < this._customElements.length; i++) {
 
307
        // If this custom element is inside a custom element that has already
 
308
        // registered to this form, skip it.
 
309
        if (!this._isChildOfRegisteredParent(el) && this._useValue(el)) {
 
310
          addSerializedElement(el.name, el.value);
 
311
        }
 
312
      }
 
313
 
 
314
      // Also go through the form's native elements.
 
315
      for (var el, i = 0; el = this.elements[i], i < this.elements.length; i++) {
 
316
        // If this native element is inside a custom element that has already
 
317
        // registered to this form, skip it.
 
318
        if (this._isChildOfRegisteredParent(el) || !this._useValue(el)) {
 
319
          continue;
 
320
        }
 
321
 
 
322
        // A <select multiple> has an array of values.
 
323
        if (el.tagName.toLowerCase() === 'select' && el.multiple) {
 
324
          for (var o = 0; o < el.options.length; o++) {
 
325
            if (el.options[o].selected) {
 
326
              addSerializedElement(el.name, el.options[o].value);
 
327
            }
 
328
          }
 
329
        } else {
 
330
          addSerializedElement(el.name, el.value);
 
331
        }
 
332
      }
 
333
 
 
334
      return json;
 
335
    },
 
336
 
 
337
    _handleFormResponse: function (event) {
 
338
      this.fire('iron-form-response', event.detail);
 
339
    },
 
340
 
 
341
    _handleFormError: function (event) {
 
342
      this.fire('iron-form-error', event.detail);
 
343
    },
 
344
 
 
345
    _registerElement: function(e) {
 
346
      // Get the actual element that fired the event
 
347
      var element = Polymer.dom(e).rootTarget;
 
348
 
 
349
      element._parentForm = this;
 
350
      this._customElements.push(element);
 
351
 
 
352
      // Save the original value of this input.
 
353
      this._customElementsInitialValues.push(
 
354
          this._usesCheckedInsteadOfValue(element) ? element.checked : element.value);
 
355
    },
 
356
 
 
357
    _unregisterElement: function(e) {
 
358
      var target = e.detail.target;
 
359
      if (target) {
 
360
        var index = this._customElements.indexOf(target);
 
361
        if (index > -1) {
 
362
          this._customElements.splice(index, 1);
 
363
          this._customElementsInitialValues.splice(index, 1);
 
364
        }
 
365
      }
 
366
    },
 
367
 
 
368
    /**
 
369
     * Validates all the required elements (custom and native) in the form.
 
370
     * @return {boolean} True if all the elements are valid.
 
371
     */
 
372
    validate: function() {
 
373
      var valid = true;
 
374
 
 
375
      // Validate all the custom elements.
 
376
      var validatable;
 
377
      for (var el, i = 0; el = this._customElements[i], i < this._customElements.length; i++) {
 
378
        if (el.required && !el.disabled) {
 
379
          validatable = /** @type {{validate: (function() : boolean)}} */ (el);
 
380
          // Some elements may not have correctly defined a validate method.
 
381
          if (validatable.validate)
 
382
            valid = !!validatable.validate() && valid;
 
383
        }
 
384
      }
 
385
 
 
386
      // Validate the form's native elements.
 
387
      for (var el, i = 0; el = this.elements[i], i < this.elements.length; i++) {
 
388
        // Custom elements that extend a native element will also appear in
 
389
        // this list, but they've already been validated.
 
390
        if (!el.hasAttribute('is') && el.willValidate && el.checkValidity) {
 
391
          valid = el.checkValidity() && valid;
 
392
        }
 
393
      }
 
394
 
 
395
      return valid;
 
396
    },
 
397
 
 
398
    /**
 
399
     * Returns whether the given element is a radio-button or a checkbox.
 
400
     * @return {boolean} True if the element has a `checked` property.
 
401
     */
 
402
    _usesCheckedInsteadOfValue: function(el) {
 
403
      if (el.type == 'checkbox' ||
 
404
          el.type == 'radio' ||
 
405
          el.getAttribute('role') == 'checkbox' ||
 
406
          el.getAttribute('role') == 'radio' ||
 
407
          el['_hasIronCheckedElementBehavior']) {
 
408
        return true;
 
409
      }
 
410
      return false;
 
411
    },
 
412
 
 
413
    _useValue: function(el) {
 
414
      // Skip disabled elements or elements that don't have a `name` attribute.
 
415
      if (el.disabled || !el.name) {
 
416
        return false;
 
417
      }
 
418
 
 
419
      // Checkboxes and radio buttons should only use their value if they're
 
420
      // checked. Custom paper-checkbox and paper-radio-button elements
 
421
      // don't have a type, but they have the correct role set.
 
422
      if (this._usesCheckedInsteadOfValue(el))
 
423
        return el.checked;
 
424
      return true;
 
425
    },
 
426
 
 
427
    _doFakeSubmitForValidation: function() {
 
428
      var fakeSubmit = document.createElement('input');
 
429
      fakeSubmit.setAttribute('type', 'submit');
 
430
      fakeSubmit.style.display = 'none';
 
431
      this.appendChild(fakeSubmit);
 
432
 
 
433
      fakeSubmit.click();
 
434
 
 
435
      this.removeChild(fakeSubmit);
 
436
    },
 
437
 
 
438
    /**
 
439
     * Resets all non-disabled form custom elements to their initial values.
 
440
     */
 
441
    _resetCustomElements: function() {
 
442
      // Reset all the registered custom components. We need to do this after
 
443
      // the native reset, since programmatically changing the `value` of some
 
444
      // native elements (iron-input in particular) does not notify its
 
445
      // parent `paper-input`, which will now display the wrong value.
 
446
      this.async(function() {
 
447
        for (var el, i = 0; el = this._customElements[i], i < this._customElements.length; i++) {
 
448
          if (el.disabled)
 
449
            continue;
 
450
 
 
451
          if (this._usesCheckedInsteadOfValue(el)) {
 
452
            el.checked = this._customElementsInitialValues[i];
 
453
          } else {
 
454
            el.value = this._customElementsInitialValues[i];
 
455
 
 
456
            // In the shady DOM, the native form is all-seeing, and will
 
457
            // reset the nested inputs inside <paper-input> and <paper-textarea>.
 
458
            // In particular, it resets them to what it thinks the default value
 
459
            // is (i.e. "", before the bindings have ran), and since this is
 
460
            // a programmatic update, it also doesn't fire any events.
 
461
            // Which means we need to manually update the native element's value.
 
462
            if (el.inputElement) {
 
463
              el.inputElement.value = el.value;
 
464
            } else if (el.textarea) {
 
465
              el.textarea.value = el.value;
 
466
            }
 
467
          }
 
468
          el.invalid = false;
 
469
        }
 
470
 
 
471
        this.fire('iron-form-reset');
 
472
      }, 1);
 
473
    },
 
474
 
 
475
    /**
 
476
     * Returns true if `node` is in the shadow DOM of a different element,
 
477
     * that has also implemented IronFormElementBehavior and is registered
 
478
     * to this form.
 
479
     */
 
480
    _isChildOfRegisteredParent: function(node) {
 
481
      var parent = node;
 
482
 
 
483
      // At some point going up the tree we'll find either this form or the document.
 
484
      while (parent && parent !== document && parent != this) {
 
485
        // Use logical parentnode, or native ShadowRoot host.
 
486
        parent = Polymer.dom(parent).parentNode || parent.host;
 
487
 
 
488
        // Check if the parent was registered and submittable.
 
489
        if (parent && parent.name && parent._parentForm === this) {
 
490
          return true;
 
491
        }
 
492
      }
 
493
      return false;
 
494
    }
 
495
 
 
496
  });
 
497
 
 
498
</script>