diff --git a/demo/demo.css b/demo/demo.css index ff0c798..87f5300 100644 --- a/demo/demo.css +++ b/demo/demo.css @@ -1,160 +1 @@ -/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ -html { - line-height: 1.15; - -webkit-text-size-adjust: 100%; -} - -body { - margin: 0; -} - -main { - display: block; -} - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -pre { - font-family: monospace, monospace; - font-size: 1em; -} - -a { - background-color: transparent; -} - -abbr[title] { - border-bottom: none; - text-decoration: underline; - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -b, strong { - font-weight: bolder; -} - -code, kbd, samp { - font-family: monospace, monospace; - font-size: 1em; -} - -small { - font-size: 80%; -} - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -img { - border-style: none; -} - -button, input, optgroup, select, textarea { - font-family: inherit; - font-size: 100%; - line-height: 1.15; - margin: 0; -} - -button, input { - overflow: visible; -} - -button, select { - text-transform: none; -} - -[type=button], [type=reset], [type=submit], button { - -webkit-appearance: button; -} - -[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner { - border-style: none; - padding: 0; -} - -[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring { - outline: 1px dotted ButtonText; -} - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -legend { - box-sizing: border-box; - color: inherit; - display: table; - max-width: 100%; - padding: 0; - white-space: normal; -} - -progress { - vertical-align: baseline; -} - -textarea { - overflow: auto; -} - -[type=checkbox], [type=radio] { - box-sizing: border-box; - padding: 0; -} - -[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button { - height: auto; -} - -[type=search] { - -webkit-appearance: textfield; - outline-offset: -2px; -} - -[type=search]::-webkit-search-decoration { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - -webkit-appearance: button; - font: inherit; -} - -details { - display: block; -} - -summary { - display: list-item; -} - -template { - display: none; -} - -[hidden] { - display: none; -} +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none} diff --git a/demo/demo.js b/demo/demo.js index f5535be..23b577a 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,3038 +1,6 @@ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ "./src/field-error.riot": -/*!******************************!*\ - !*** ./src/field-error.riot ***! - \******************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__ -/* harmony export */ }); -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ - 'css': null, - - 'exports': { - state: { - errors: [ - - ], - }, - - onMounted(props, state) { - - const parent = this.root.closest('.field') - const element = document.querySelector('[name="' + props.name + '"]') - const form = element.closest('form') - - // element and form set - if (element && form) { - element.addEventListener('keyup', function(event) { - - const fieldUpdateEvent = new CustomEvent('field-update', { - 'detail': { - 'name': props.name, - 'value': this.value - } - }) - - form.dispatchEvent(fieldUpdateEvent) - }) - } - - // add custom event to listen to form-validation - this.root.addEventListener('form-validation', (event) => { - - // if detail is set with element name, get errors - if (event.detail) { - this.state.errors = event.detail - parent.classList.add('field--error') - parent.classList.remove('field--valid') - } else { - this.state.errors = [] - parent.classList.remove('field--error') - parent.classList.add('field--valid') - } - - this.update() - }) - } - }, - - 'template': function( - template, - expressionTypes, - bindingTypes, - getComponent - ) { - return template( - '
', - [ - { - 'type': bindingTypes.IF, - - 'evaluate': function( - scope - ) { - return scope.state.errors.length > 0; - }, - - 'redundantAttribute': 'expr0', - 'selector': '[expr0]', - - 'template': template( - '', - [ - { - 'type': bindingTypes.EACH, - 'getKey': null, - 'condition': null, - - 'template': template( - ' ', - [ - { - 'expressions': [ - { - 'type': expressionTypes.TEXT, - 'childNodeIndex': 0, - - 'evaluate': function( - scope - ) { - return [ - scope.error - ].join( - '' - ); - } - } - ] - } - ] - ), - - 'redundantAttribute': 'expr1', - 'selector': '[expr1]', - 'itemName': 'error', - 'indexName': null, - - 'evaluate': function( - scope - ) { - return scope.state.errors; - } - } - ] - ) - } - ] - ); - }, - - 'name': 'field-error' -}); - -/***/ }), - -/***/ "./src/FormValidator.js": -/*!******************************!*\ - !*** ./src/FormValidator.js ***! - \******************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__ -/* harmony export */ }); -/* harmony import */ var validate_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! validate.js */ "./node_modules/validate.js/validate.js"); -/* harmony import */ var validate_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(validate_js__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var form_serialize__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! form-serialize */ "./node_modules/form-serialize/index.js"); -/* harmony import */ var form_serialize__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(form_serialize__WEBPACK_IMPORTED_MODULE_1__); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - - - -/** - * - * - * - */ - -var FormValidator = /*#__PURE__*/function () { - /** - * - * @param {[type]} formSelector [description] - * @param {[type]} constraits [description] - */ - function FormValidator(formSelector, constraits) { - var _this = this; - - _classCallCheck(this, FormValidator); - - this.errors = []; // getting selector to find form-element - - this.formSelector = formSelector; // constraits for validate.js - - this.constraits = constraits; // get form and elements - - this.form = document.querySelector(this.formSelector); - this.elements = this.form.querySelectorAll('field-error'); // adding submit event - - this.form.addEventListener('submit', function (event) { - _this.onSubmit(event); - }); // adding event if a element is updated - - this.form.addEventListener('field-update', function (event) { - _this.onFieldUpdate(event); - }); - } - /** - * - * @param {[type]} name [description] - * @return {[type]} [description] - */ - - - _createClass(FormValidator, [{ - key: "findElementByName", - value: function findElementByName(name) { - var result; - this.elements.forEach(function (element) { - if (element.attributes.name.nodeValue == name) { - result = element; - return false; - } - }); - return result; - } - /** - * - * @param {[type]} event [description] - * @return {[type]} [description] - */ - - }, { - key: "onSubmit", - value: function onSubmit(event) { - var _this2 = this; - - var errors = validate_js__WEBPACK_IMPORTED_MODULE_0___default()(form_serialize__WEBPACK_IMPORTED_MODULE_1___default()(event.target, { - hash: true - }), this.constraits); - - if (errors) { - event.preventDefault(); - this.elements.forEach(function (element) { - var elementErrors = false; - - if (errors[element.attributes.name.nodeValue]) { - elementErrors = errors[element.attributes.name.nodeValue]; - } - - _this2.dispatchCustomEvent(elementErrors, element); - }); - } - } - /** - * - * @param {[type]} event [description] - * @return {[type]} [description] - */ - - }, { - key: "onFieldUpdate", - value: function onFieldUpdate(event) { - var errors = validate_js__WEBPACK_IMPORTED_MODULE_0___default().single(event.detail.value, this.constraits[event.detail.name]); - var element = this.findElementByName(event.detail.name); - this.dispatchCustomEvent(errors, element); - } - /** - * - * @param {[type]} errors [description] - * @param {[type]} element [description] - * @return {[type]} [description] - */ - - }, { - key: "dispatchCustomEvent", - value: function dispatchCustomEvent(errors, element) { - var detail = false; - - if (errors) { - detail = errors; - } - - var formValidationEvent = new CustomEvent('form-validation', { - 'detail': detail - }); - element.dispatchEvent(formValidationEvent); - } - }]); - - return FormValidator; -}(); - -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (FormValidator); - -/***/ }), - -/***/ "./src/demo/demo.js": -/*!**************************!*\ - !*** ./src/demo/demo.js ***! - \**************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var riot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! riot */ "./node_modules/riot/riot.esm.js"); -/* harmony import */ var _FormValidator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./../FormValidator */ "./src/FormValidator.js"); -/* harmony import */ var _field_error_riot__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./../field-error.riot */ "./src/field-error.riot"); - - - -riot__WEBPACK_IMPORTED_MODULE_2__.register('field-error', _field_error_riot__WEBPACK_IMPORTED_MODULE_1__.default); -riot__WEBPACK_IMPORTED_MODULE_2__.mount('field-error'); -var formValidation = new _FormValidator__WEBPACK_IMPORTED_MODULE_0__.default('form', { - 'email': { - 'presence': true, - 'email': true - }, - 'password': { - 'presence': true - } -}); - -/***/ }), - -/***/ "./node_modules/form-serialize/index.js": -/*!**********************************************!*\ - !*** ./node_modules/form-serialize/index.js ***! - \**********************************************/ -/***/ ((module) => { - -// get successful control from form and assemble into object -// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2 - -// types which indicate a submit action and are not successful controls -// these will be ignored -var k_r_submitter = /^(?:submit|button|image|reset|file)$/i; - -// node names which could be successful controls -var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i; - -// Matches bracket notation. -var brackets = /(\[[^\[\]]*\])/g; - -// serializes form fields -// @param form MUST be an HTMLForm element -// @param options is an optional argument to configure the serialization. Default output -// with no options specified is a url encoded string -// - hash: [true | false] Configure the output type. If true, the output will -// be a js object. -// - serializer: [function] Optional serializer function to override the default one. -// The function takes 3 arguments (result, key, value) and should return new result -// hash and url encoded str serializers are provided with this module -// - disabled: [true | false]. If true serialize disabled fields. -// - empty: [true | false]. If true serialize empty fields -function serialize(form, options) { - if (typeof options != 'object') { - options = { hash: !!options }; - } - else if (options.hash === undefined) { - options.hash = true; - } - - var result = (options.hash) ? {} : ''; - var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize); - - var elements = form && form.elements ? form.elements : []; - - //Object store each radio and set if it's empty or not - var radio_store = Object.create(null); - - for (var i=0 ; i myString - */ - -function dashToCamelCase(string) { - return string.replace(/-(\w)/g, (_, c) => c.toUpperCase()); -} - -/** - * Get all the element attributes as object - * @param {HTMLElement} element - DOM node we want to parse - * @returns {Object} all the attributes found as a key value pairs - */ - -function DOMattributesToObject(element) { - return Array.from(element.attributes).reduce((acc, attribute) => { - acc[dashToCamelCase(attribute.name)] = attribute.value; - return acc; - }, {}); -} -/** - * Move all the child nodes from a source tag to another - * @param {HTMLElement} source - source node - * @param {HTMLElement} target - target node - * @returns {undefined} it's a void method ¯\_(ツ)_/¯ - */ -// Ignore this helper because it's needed only for svg tags - -function moveChildren(source, target) { - if (source.firstChild) { - target.appendChild(source.firstChild); - moveChildren(source, target); - } -} -/** - * Remove the child nodes from any DOM node - * @param {HTMLElement} node - target node - * @returns {undefined} - */ - -function cleanNode(node) { - clearChildren(node.childNodes); -} -/** - * Clear multiple children in a node - * @param {HTMLElement[]} children - direct children nodes - * @returns {undefined} - */ - -function clearChildren(children) { - Array.from(children).forEach(removeChild); -} -/** - * Remove a node - * @param {HTMLElement}node - node to remove - * @returns {undefined} - */ - -const removeChild = node => node && node.parentNode && node.parentNode.removeChild(node); -/** - * Insert before a node - * @param {HTMLElement} newNode - node to insert - * @param {HTMLElement} refNode - ref child - * @returns {undefined} - */ - -const insertBefore = (newNode, refNode) => refNode && refNode.parentNode && refNode.parentNode.insertBefore(newNode, refNode); -/** - * Replace a node - * @param {HTMLElement} newNode - new node to add to the DOM - * @param {HTMLElement} replaced - node to replace - * @returns {undefined} - */ - -const replaceChild = (newNode, replaced) => replaced && replaced.parentNode && replaced.parentNode.replaceChild(newNode, replaced); - -// Riot.js constants that can be used accross more modules -const COMPONENTS_IMPLEMENTATION_MAP = new Map(), - DOM_COMPONENT_INSTANCE_PROPERTY = Symbol('riot-component'), - PLUGINS_SET = new Set(), - IS_DIRECTIVE = 'is', - VALUE_ATTRIBUTE = 'value', - MOUNT_METHOD_KEY = 'mount', - UPDATE_METHOD_KEY = 'update', - UNMOUNT_METHOD_KEY = 'unmount', - SHOULD_UPDATE_KEY = 'shouldUpdate', - ON_BEFORE_MOUNT_KEY = 'onBeforeMount', - ON_MOUNTED_KEY = 'onMounted', - ON_BEFORE_UPDATE_KEY = 'onBeforeUpdate', - ON_UPDATED_KEY = 'onUpdated', - ON_BEFORE_UNMOUNT_KEY = 'onBeforeUnmount', - ON_UNMOUNTED_KEY = 'onUnmounted', - PROPS_KEY = 'props', - STATE_KEY = 'state', - SLOTS_KEY = 'slots', - ROOT_KEY = 'root', - IS_PURE_SYMBOL = Symbol.for('pure'), - PARENT_KEY_SYMBOL = Symbol('parent'), - ATTRIBUTES_KEY_SYMBOL = Symbol('attributes'), - TEMPLATE_KEY_SYMBOL = Symbol('template'); - -var globals = /*#__PURE__*/Object.freeze({ - __proto__: null, - COMPONENTS_IMPLEMENTATION_MAP: COMPONENTS_IMPLEMENTATION_MAP, - DOM_COMPONENT_INSTANCE_PROPERTY: DOM_COMPONENT_INSTANCE_PROPERTY, - PLUGINS_SET: PLUGINS_SET, - IS_DIRECTIVE: IS_DIRECTIVE, - VALUE_ATTRIBUTE: VALUE_ATTRIBUTE, - MOUNT_METHOD_KEY: MOUNT_METHOD_KEY, - UPDATE_METHOD_KEY: UPDATE_METHOD_KEY, - UNMOUNT_METHOD_KEY: UNMOUNT_METHOD_KEY, - SHOULD_UPDATE_KEY: SHOULD_UPDATE_KEY, - ON_BEFORE_MOUNT_KEY: ON_BEFORE_MOUNT_KEY, - ON_MOUNTED_KEY: ON_MOUNTED_KEY, - ON_BEFORE_UPDATE_KEY: ON_BEFORE_UPDATE_KEY, - ON_UPDATED_KEY: ON_UPDATED_KEY, - ON_BEFORE_UNMOUNT_KEY: ON_BEFORE_UNMOUNT_KEY, - ON_UNMOUNTED_KEY: ON_UNMOUNTED_KEY, - PROPS_KEY: PROPS_KEY, - STATE_KEY: STATE_KEY, - SLOTS_KEY: SLOTS_KEY, - ROOT_KEY: ROOT_KEY, - IS_PURE_SYMBOL: IS_PURE_SYMBOL, - PARENT_KEY_SYMBOL: PARENT_KEY_SYMBOL, - ATTRIBUTES_KEY_SYMBOL: ATTRIBUTES_KEY_SYMBOL, - TEMPLATE_KEY_SYMBOL: TEMPLATE_KEY_SYMBOL -}); - -const EACH = 0; -const IF = 1; -const SIMPLE = 2; -const TAG = 3; -const SLOT = 4; -var bindingTypes = { - EACH, - IF, - SIMPLE, - TAG, - SLOT -}; - -const ATTRIBUTE = 0; -const EVENT = 1; -const TEXT = 2; -const VALUE = 3; -var expressionTypes = { - ATTRIBUTE, - EVENT, - TEXT, - VALUE -}; - -/** - * Create the template meta object in case of