Skip to content
This repository has been archived by the owner on Nov 19, 2018. It is now read-only.

Commit

Permalink
chore(dep-free): start of work to remove Polymer dependency
Browse files Browse the repository at this point in the history
TODO:
- Fix DOM mutation detection /validation code
- Fix custom events in IE
- finish converting tests

#55
  • Loading branch information
Ray Nicholus committed Apr 28, 2015
1 parent 37a7efd commit e746c43
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 510 deletions.
2 changes: 2 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@
"beforeEach",
"clearTimeout",
"console",
"CustomEvent",
"describe",
"document",
"expect",
"FormData",
"HTMLFormElement",
"it",
"setTimeout",
"window",
Expand Down
18 changes: 3 additions & 15 deletions ajax-form.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<link rel="import" href="../polymer/polymer.html">
<script src="ajax-form.js"></script>

<!--
Expand Down Expand Up @@ -86,19 +85,11 @@
will be preflighted as well, so your server must handle these correctly. [Read more about
CORS on Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS).
__Don't forget to [vulcanize](http://www.polymer-project.org/articles/concatenating-web-components.html)
your main/parent HTML file before deploying into production. This will ensure
that all of your HTML imports are concatenated into one file.__
@element ajax-form
@status beta
@homepage index.html
-->
<polymer-element name="ajax-form" extends="form" attributes="cookies headers">

<template>
<content></content>
</template>
<template id="ajax-form-template">
<content></content>

<script>
/**
Expand Down Expand Up @@ -262,8 +253,5 @@
* @type string
* @default 'GET'
*/

Polymer('ajax-form', ajaxForm);
</script>

</polymer-element>
</template>
159 changes: 90 additions & 69 deletions ajax-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
return Array.prototype.slice.call(pseudoArray);
},

// TODO fix for IE (see https://gist.github.com/james2doyle/7945320)
fire = function (node, type, _detail_) {
var detail = _detail_ === null || _detail_ === undefined ? {} : _detail_,
event = new CustomEvent(type, {
bubbles: true,
cancelable: true,
detail: detail
});
node.dispatchEvent(event);
return event;
},

getEnctype = function(ajaxForm) {
var enctype = ajaxForm.getAttribute('enctype');

Expand All @@ -19,6 +31,9 @@
}
},

// Note that _currentScript is a polyfill-specific convention
importDoc = document._currentScript.ownerDocument,

// NOTE: Safari doesn't have any visual indications when submit is blocked
interceptSubmit = function(ajaxForm) {
// Intercept submit event
Expand All @@ -44,7 +59,7 @@
ajaxForm.appendChild(fakeSubmitEl);
ajaxForm.submit = function() {
if (ajaxForm.checkValidity()) {
ajaxForm.fire('submit');
fire(ajaxForm, 'submit');
}
else {
fakeSubmitEl.click();
Expand Down Expand Up @@ -214,7 +229,7 @@
sendFormData = function(ajaxForm) {
var enctype = getEnctype(ajaxForm),
formData = parseForm(ajaxForm, enctype === 'multipart/form-data'),
submittingEvent = ajaxForm.fire('submitting', {formData: formData});
submittingEvent = fire(ajaxForm, 'submitting', {formData: formData});

formData = submittingEvent.detail.formData;

Expand Down Expand Up @@ -266,13 +281,14 @@

sendRequest({
body: formData,
contentType: getEnctype(ajaxForm),
form: ajaxForm
});
},

sendRequest = function(options) {
var xhr = new XMLHttpRequest(),
customHeaders = options.form.headers;
customHeaders = options.form.getAttribute('headers');

xhr.open(options.form.acceptableMethod, options.url || options.form.action);

Expand All @@ -292,7 +308,7 @@

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
options.form.fire('submitted', xhr);
fire(options.form, 'submitted', xhr);
}
};

Expand Down Expand Up @@ -339,72 +355,77 @@
},

watchForInvalidFields = function(ajaxForm, existingEventListeners) {
var initialFields = arrayOf(ajaxForm.querySelectorAll(':invalid, :valid')),
invalidFields = [],

listenForInvalidEvent = function(field) {
field.willValidate && field.addEventListener('invalid', function() {
invalidFields.push(field.customElementRef || field);

// In case another element is invalid and the event
// hasn't been triggered yet, hold off on firing the
// invalid event on the custom el.
clearTimeout(timer);
timer = setTimeout(function() {
ajaxForm.fire('invalid', invalidFields);
invalidFields = [];
console.error('Form submission blocked - constraints violation.');
}, 10);
});
},

// Be sure to observe any validatable form fields added in the future
mutationHandler = function(observer, records) {
records.forEach(function(record) {
if (record.addedNodes.length) {
arrayOf(record.addedNodes).forEach(function(addedNode) {
addedNode.willValidate && listenForInvalidEvent(addedNode);
});
}
});

ajaxForm.onMutation(ajaxForm, mutationHandler);
},

timer = null;

initialFields.forEach(function(field) {
listenForInvalidEvent(field);
});

ajaxForm.onMutation(ajaxForm, mutationHandler);
//var initialFields = arrayOf(ajaxForm.querySelectorAll(':invalid, :valid')),
// invalidFields = [],
//
// listenForInvalidEvent = function(field) {
// field.willValidate && field.addEventListener('invalid', function() {
// invalidFields.push(field.customElementRef || field);
//
// // In case another element is invalid and the event
// // hasn't been triggered yet, hold off on firing the
// // invalid event on the custom el.
// clearTimeout(timer);
// timer = setTimeout(function() {
// ajaxForm.fire('invalid', invalidFields);
// invalidFields = [];
// console.error('Form submission blocked - constraints violation.');
// }, 10);
// });
// },
//
// // Be sure to observe any validatable form fields added in the future
// mutationHandler = function(observer, records) {
// records.forEach(function(record) {
// if (record.addedNodes.length) {
// arrayOf(record.addedNodes).forEach(function(addedNode) {
// addedNode.willValidate && listenForInvalidEvent(addedNode);
// });
// }
// });
//
// ajaxForm.onMutation(ajaxForm, mutationHandler);
// },
//
// timer = null;
//
//initialFields.forEach(function(field) {
// listenForInvalidEvent(field);
//});
//
//ajaxForm.onMutation(ajaxForm, mutationHandler);
};

this.ajaxForm = {
/**
* Fired when a response is received.
*
* @event core-response
*/
cookies: false,

domReady: function() {
var ajaxForm = this;

// The method attribute set on the light-DOM `<form>`
// can't seem to be accessed as a property of this element,
// unlike other attributes. Perhaps due to the fact that
// we are extending a form and a "natural" form also has a
// method attr? Perhaps something special about this attr?
// Need to look into this further.
ajaxForm.acceptableMethod = getValidMethod(ajaxForm.getAttribute('method'));

if (!ajaxForm.acceptableMethod) {
throw new Error('Invalid method!');
}
document.registerElement('ajax-form', {
extends: 'form',
prototype: Object.create(HTMLFormElement.prototype, {
createdCallback: {
value: function () {
var template = importDoc.querySelector('#ajax-form-template'),
clone = document.importNode(template.content, true),
root = this.createShadowRoot();

root.appendChild(clone);

var ajaxForm = this;

// The method attribute set on the light-DOM `<form>`
// can't seem to be accessed as a property of this element,
// unlike other attributes. Perhaps due to the fact that
// we are extending a form and a "natural" form also has a
// method attr? Perhaps something special about this attr?
// Need to look into this further.
ajaxForm.acceptableMethod = getValidMethod(ajaxForm.getAttribute('method'));

if (!ajaxForm.acceptableMethod) {
throw new Error('Invalid method!');
}

watchForInvalidFields(ajaxForm);
interceptSubmit(ajaxForm);
}
};
watchForInvalidFields(ajaxForm);
interceptSubmit(ajaxForm);
fire(ajaxForm, 'ready');
}
}
})
});
}());
2 changes: 1 addition & 1 deletion demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

</head>

<body unresolved>
<body>

<h1><code>ajax-form</code> in action:</h1>

Expand Down
2 changes: 1 addition & 1 deletion gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module.exports = function(grunt) {
},
wctLocal: {
command: [
'wct --local all'
'wct --local chrome,firefox'
].join('&&')
},
wctSauce: {
Expand Down
Loading

0 comments on commit e746c43

Please sign in to comment.