ratchet_design 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/images/ratchet/favicon.ico +0 -0
- data/app/assets/javascripts/ratchet/base/form.js +117 -8
- data/app/assets/javascripts/ratchet/base/mobilemenu.js +50 -12
- data/app/assets/javascripts/ratchet/base/validation.js +263 -0
- data/app/assets/javascripts/ratchet/core.js +78 -57
- data/app/assets/javascripts/ratchet/enhancement/_collapse.js +6 -3
- data/app/assets/javascripts/ratchet/enhancement/_lightbox.js +93 -0
- data/app/assets/javascripts/ratchet/enhancement/_swap.js +7 -3
- data/app/assets/javascripts/ratchet/{utility → enhancement}/loader.js +8 -15
- data/app/assets/javascripts/ratchet/enhancement/notice.js +3 -8
- data/app/assets/javascripts/ratchet/enhancement/sticky.js +35 -18
- data/app/assets/javascripts/ratchet/enhancement/waypoints.js +162 -125
- data/app/assets/javascripts/ratchet/shim/classlist.js +234 -0
- data/app/assets/javascripts/ratchet/shim/object.assign.js +30 -0
- data/app/assets/javascripts/ratchet/utility/ajax.js +122 -0
- data/app/assets/javascripts/ratchet/utility/compile_data.js +40 -0
- data/app/assets/javascripts/ratchet/utility/from_top.js +14 -0
- data/app/assets/javascripts/ratchet/utility/full_stop.js +55 -0
- data/app/assets/javascripts/ratchet/utility/get_closest.js +20 -0
- data/app/assets/javascripts/ratchet/utility/get_next.js +17 -0
- data/app/assets/javascripts/ratchet/utility/matches.js +15 -0
- data/app/assets/javascripts/ratchet/utility/scroll_to.js +74 -0
- data/app/assets/javascripts/ratchet/utility/throttle.js +25 -0
- data/app/assets/javascripts/ratchet/utility/timeout.js +45 -0
- data/app/assets/javascripts/ratchet/utility/unhover.js +56 -0
- data/app/assets/javascripts/ratchet/utility/word_count.js +15 -0
- data/app/assets/stylesheets/ratchet/_core.scss +2 -4
- data/app/assets/stylesheets/ratchet/base/_button.scss +1 -1
- data/app/assets/stylesheets/ratchet/base/_form.scss +50 -61
- data/app/assets/stylesheets/ratchet/base/_text.scss +8 -8
- data/app/assets/stylesheets/ratchet/{utility → enhancement}/_loader.scss +1 -1
- data/app/assets/stylesheets/ratchet/enhancement/_tooltip.scss +1 -6
- data/app/assets/stylesheets/ratchet/utility/_global.scss +12 -2
- data/app/helpers/ratchet/application_helper.rb +2 -28
- data/app/views/layouts/ratchet/default.html.slim +4 -5
- data/app/views/shared/ratchet/_footer.html.slim +2 -3
- data/app/views/shared/ratchet/_header.html.slim +1 -1
- data/lib/ratchet_design/version.rb +1 -1
- data/lib/ratchet_design.rb +0 -1
- data/public/assets/ratchet/core-0.1.6.js +105 -0
- data/public/assets/ratchet/core-0.1.6.js.gz +0 -0
- data/public/assets/ratchet/core-0.1.6.map.json +1 -0
- data/public/assets/ratchet/{fonts-woff-0.1.5.css → fonts-woff-0.1.6.css} +0 -0
- data/public/assets/ratchet/{fonts-woff-0.1.5.css.gz → fonts-woff-0.1.6.css.gz} +0 -0
- data/public/assets/ratchet/{fonts-woff2-0.1.5.css → fonts-woff2-0.1.6.css} +0 -0
- data/public/assets/ratchet/{fonts-woff2-0.1.5.css.gz → fonts-woff2-0.1.6.css.gz} +0 -0
- metadata +28 -47
- data/app/assets/images/ratchet/safari-pinned-tab.svg +0 -1
- data/app/assets/javascripts/ratchet/base/sync-input-value.js +0 -30
- data/app/assets/javascripts/ratchet/enhancement/lightbox.js +0 -165
- data/app/assets/javascripts/ratchet/shim/scope.js +0 -94
- data/app/assets/stylesheets/ratchet/base/_multistep-form.scss +0 -64
- data/app/assets/stylesheets/ratchet/enhancement/_lightbox.scss +0 -98
- data/app/helpers/ratchet/form_helper.rb +0 -140
- data/public/assets/ratchet/core-0.1.5.js +0 -133
- data/public/assets/ratchet/core-0.1.5.js.gz +0 -0
- data/public/assets/ratchet/core-0.1.5.map.json +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 800a6bcc6a8a10f42a0684bb4dda1d88dfb52cd7
|
4
|
+
data.tar.gz: 78ba7b72667ec3c73de93bc91b6eab8d269fac17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a573756a5d39a85e1e890ae4b3c72669146fbc77d820a7a3594fb132af7774b7f7926d56bfa8caaa8f35fd13428d56c898d3f8da831f4e92abd1a99516aa26d7
|
7
|
+
data.tar.gz: 5239ca2ac035a0dd1144b11247f4b9bc38582cc387ddb795a4c8a6a9903df512fe912305c73af4c0c6d97990f8f005f4ec69c14af576da5ee6470f4b84db247a
|
Binary file
|
@@ -5,13 +5,14 @@
|
|
5
5
|
* @license MIT
|
6
6
|
**/
|
7
7
|
|
8
|
-
|
8
|
+
// Dependencies
|
9
|
+
var evt = require( 'compose-event' );
|
9
10
|
|
10
11
|
// Public API function
|
11
12
|
var form = function( element, settings ) {
|
12
13
|
|
13
14
|
// Overridable defaults
|
14
|
-
var defaults = {}
|
15
|
+
var defaults = {};
|
15
16
|
|
16
17
|
// Parameter variables
|
17
18
|
var selector = document.querySelector( element ) || document.querySelector( 'form' );
|
@@ -20,22 +21,22 @@ var form = function( element, settings ) {
|
|
20
21
|
if ( !selector ) return false;
|
21
22
|
|
22
23
|
// Scoped variables
|
23
|
-
var options =
|
24
|
+
var options = Object.assign( {}, defaults, settings ),
|
24
25
|
rangeEls = document.querySelectorAll( 'input[type=range]' ),
|
25
26
|
tickEls = document.querySelectorAll( 'input[type=checkbox], input[type=radio]' ),
|
26
27
|
docBody = document.body;
|
27
28
|
|
28
29
|
// Prevent non-numeric characters in number fields
|
29
|
-
|
30
|
+
docBody.addEventListener( 'keypress', keyHandler, false );
|
30
31
|
|
31
32
|
// Run delegated `on input` listener
|
32
|
-
|
33
|
+
docBody.addEventListener( 'input', rangeHandler, true );
|
33
34
|
|
34
35
|
// Loop over any range inputs that are present
|
35
36
|
for ( var rangeIndex = 0; rangeIndex < rangeEls.length; rangeIndex++ ) {
|
36
37
|
|
37
38
|
// And run their handler function explicitly at runtime
|
38
|
-
rangeHandler( rangeEls[ rangeIndex ] )
|
39
|
+
rangeHandler( rangeEls[ rangeIndex ] );
|
39
40
|
|
40
41
|
}
|
41
42
|
|
@@ -74,9 +75,14 @@ var form = function( element, settings ) {
|
|
74
75
|
}
|
75
76
|
|
76
77
|
// Keydown handler function
|
77
|
-
function
|
78
|
+
function keyHandler( event ) {
|
78
79
|
|
79
|
-
//
|
80
|
+
// Only run on number inputs
|
81
|
+
if ( event.target.type !== 'number' ) {
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
|
85
|
+
// If user enters non-numeric characters
|
80
86
|
if ( event.which < 48 || event.which > 57 ) {
|
81
87
|
|
82
88
|
// Supress them
|
@@ -105,6 +111,109 @@ var form = function( element, settings ) {
|
|
105
111
|
|
106
112
|
}
|
107
113
|
|
114
|
+
// Rangetouch 0.0.9 - https://github.com/selz/rangetouch
|
115
|
+
function rangeTouch( size ) {
|
116
|
+
|
117
|
+
// Bail if not a touch device
|
118
|
+
if ( !( 'ontouchstart' in document.documentElement ) ) {
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
|
122
|
+
// Scoped variables
|
123
|
+
var rangeInputs = document.querySelectorAll( '[type=range]' ),
|
124
|
+
thumbSize = size || 20;
|
125
|
+
|
126
|
+
// Set touchAction to prevent delays
|
127
|
+
for ( var i = rangeInputs.length - 1; i >= 0; i-- ) {
|
128
|
+
rangeInputs[ i ].style.touchAction = 'manipulation';
|
129
|
+
rangeInputs[ i ].style.webkitUserSelect = 'none';
|
130
|
+
}
|
131
|
+
|
132
|
+
// Listen for events
|
133
|
+
docBody.addEventListener( 'touchstart', setValue, false );
|
134
|
+
docBody.addEventListener( 'touchmove', setValue, false );
|
135
|
+
docBody.addEventListener( 'touchend', setValue, false );
|
136
|
+
|
137
|
+
// Get the number of decimal places
|
138
|
+
function getDecimalPlaces( value ) {
|
139
|
+
var match = ( '' + value ).match( /( ?:\.( \d+ ) )?( ?:[eE]( [+-]?\d+ ) )?$/ );
|
140
|
+
if ( !match ) {
|
141
|
+
return 0;
|
142
|
+
}
|
143
|
+
return Math.max( 0, ( match[ 1 ] ? match[ 1 ].length : 0 ) - ( match[ 2 ] ? +match[ 2 ] : 0 ) );
|
144
|
+
}
|
145
|
+
|
146
|
+
// Round to the nearest step
|
147
|
+
function roundToStep( number, step ) {
|
148
|
+
if ( step < 1 ) {
|
149
|
+
var places = getDecimalPlaces( parseInt( step ) );
|
150
|
+
return parseFloat( number.toFixed( places ) );
|
151
|
+
}
|
152
|
+
return ( Math.round( number / step ) * step );
|
153
|
+
}
|
154
|
+
|
155
|
+
// Get the value based on touch position
|
156
|
+
function getValue( event ) {
|
157
|
+
|
158
|
+
// Scoped variables
|
159
|
+
var input = event.target,
|
160
|
+
touch = event.changedTouches[ 0 ],
|
161
|
+
min = parseFloat( input.getAttribute( 'min' ) ) || 0,
|
162
|
+
max = parseFloat( input.getAttribute( 'max' ) ) || 100,
|
163
|
+
step = parseFloat( input.getAttribute( 'step' ) ) || 1,
|
164
|
+
delta = max - min;
|
165
|
+
|
166
|
+
// Calculate percentage
|
167
|
+
var percent,
|
168
|
+
clientRect = input.getBoundingClientRect(),
|
169
|
+
thumbWidth = ( ( ( 100 / clientRect.width ) * ( thumbSize / 2 ) ) / 100 );
|
170
|
+
|
171
|
+
// Determine left percentage
|
172
|
+
percent = ( ( 100 / clientRect.width ) * ( touch.clientX - clientRect.left ) );
|
173
|
+
|
174
|
+
// Don't allow outside bounds
|
175
|
+
if ( percent < 0 ) {
|
176
|
+
percent = 0;
|
177
|
+
} else if ( percent > 100 ) {
|
178
|
+
percent = 100;
|
179
|
+
}
|
180
|
+
|
181
|
+
// Factor in the thumb offset
|
182
|
+
if ( percent < 50 ) {
|
183
|
+
percent -= ( ( 100 - ( percent * 2 ) ) * thumbWidth );
|
184
|
+
} else if ( percent > 50 ) {
|
185
|
+
percent += ( ( ( percent - 50 ) * 2 ) * thumbWidth );
|
186
|
+
}
|
187
|
+
|
188
|
+
// Find the closest step to the mouse position
|
189
|
+
return min + roundToStep( delta * ( percent / 100 ), step );
|
190
|
+
|
191
|
+
}
|
192
|
+
|
193
|
+
// Update range value based on position
|
194
|
+
function setValue( event ) {
|
195
|
+
|
196
|
+
// Bail if not a range slider
|
197
|
+
if ( event.target.type !== 'range' ) {
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
|
201
|
+
// Prevent text highlight on iOS
|
202
|
+
event.preventDefault();
|
203
|
+
|
204
|
+
// Set value
|
205
|
+
event.target.value = getValue( event );
|
206
|
+
|
207
|
+
// Trigger input event
|
208
|
+
evt.fire( event.target, ( event.type === 'touchend' ? 'change' : 'input' ) );
|
209
|
+
|
210
|
+
}
|
211
|
+
|
212
|
+
}
|
213
|
+
|
214
|
+
// Initialize RangeTouch
|
215
|
+
rangeTouch();
|
216
|
+
|
108
217
|
};
|
109
218
|
|
110
219
|
// Public API
|
@@ -6,31 +6,69 @@
|
|
6
6
|
**/
|
7
7
|
|
8
8
|
// Dependencies
|
9
|
-
var
|
9
|
+
var matches = require( '../utility/matches' );
|
10
10
|
|
11
11
|
// Public API function
|
12
|
-
var mobileMenu = function( settings ) {
|
12
|
+
var mobileMenu = function( element, settings ) {
|
13
13
|
|
14
14
|
// Overridable defaults
|
15
15
|
var defaults = {
|
16
16
|
initWidth : '700px',
|
17
17
|
openClass : 'menu-open',
|
18
|
-
|
19
|
-
button : '.mobile-menu-button'
|
18
|
+
menuButton : '.mobile-menu-button'
|
20
19
|
},
|
21
20
|
|
22
21
|
// Scoped variables
|
23
|
-
options =
|
24
|
-
selector =
|
22
|
+
options = Object.assign( {}, defaults, settings ),
|
23
|
+
selector = document.querySelector( element ),
|
24
|
+
widthQuery = window.matchMedia( '(max-width: ' + options.initWidth + ')' ),
|
25
25
|
docBody = document.body;
|
26
26
|
|
27
27
|
// Attach listeners
|
28
|
-
|
29
|
-
// Toggle body class
|
30
|
-
docBody.classList.toggle( options.openClass )
|
31
|
-
})
|
28
|
+
if ( selector ) {
|
32
29
|
|
33
|
-
|
30
|
+
// Call listener function explicitly at run time
|
31
|
+
queryHandler( widthQuery );
|
32
|
+
|
33
|
+
// Attach listener function to listen in on state changes
|
34
|
+
widthQuery.addListener( queryHandler );
|
35
|
+
|
36
|
+
}
|
37
|
+
|
38
|
+
// Click handler function
|
39
|
+
function clickHandler( event ) {
|
40
|
+
|
41
|
+
// Combine element selector with anchor links
|
42
|
+
var toggleSelector = options.menuButton + ', .' + options.openClass + ' ' + element + ' a[href^="#"]';
|
43
|
+
|
44
|
+
// Only run on menu button
|
45
|
+
if ( matches( event.target, toggleSelector ) ) {
|
46
|
+
|
47
|
+
// Toggle body class
|
48
|
+
docBody.classList.toggle( options.openClass );
|
49
|
+
|
50
|
+
}
|
51
|
+
|
52
|
+
}
|
53
|
+
|
54
|
+
// Media query handler function
|
55
|
+
function queryHandler( condition ) {
|
56
|
+
|
57
|
+
// If media query matches
|
58
|
+
if ( condition.matches ) {
|
59
|
+
|
60
|
+
// Click function listener
|
61
|
+
selector.addEventListener( 'click', clickHandler, false );
|
62
|
+
|
63
|
+
} else {
|
64
|
+
|
65
|
+
// Remove click listener
|
66
|
+
selector.removeEventListener( 'click', clickHandler, false );
|
67
|
+
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
};
|
34
72
|
|
35
73
|
// Public API
|
36
|
-
module.exports = mobileMenu
|
74
|
+
module.exports = mobileMenu;
|
@@ -0,0 +1,263 @@
|
|
1
|
+
/**
|
2
|
+
* Validation 0.0.6
|
3
|
+
* Compose form validation module
|
4
|
+
* @author Kyle Foster (@hkfoster)
|
5
|
+
* @license MIT
|
6
|
+
**/
|
7
|
+
|
8
|
+
// Dependencies
|
9
|
+
var matches = require( '../utility/matches' ),
|
10
|
+
getClosest = require( '../utility/get_closest' ),
|
11
|
+
wordCount = require( '../utility/word_count' );
|
12
|
+
|
13
|
+
// Public API function
|
14
|
+
var validation = function( element, settings ) {
|
15
|
+
|
16
|
+
// Overridable defaults
|
17
|
+
var defaults = {};
|
18
|
+
|
19
|
+
// Parameter variables
|
20
|
+
var selector = document.querySelector( element ) || document.querySelector( '[required]' );
|
21
|
+
|
22
|
+
// Only run if selector exists & validation is supported
|
23
|
+
if ( !selector || typeof document.createElement( 'input' ).checkValidity !== 'function' ) return false;
|
24
|
+
|
25
|
+
// Scoped variables
|
26
|
+
var options = Object.assign( {}, defaults, settings ),
|
27
|
+
docBody = document.body;
|
28
|
+
|
29
|
+
// Suppress default message bubbles
|
30
|
+
docBody.addEventListener( 'invalid', function( event ) {
|
31
|
+
event.preventDefault();
|
32
|
+
}, true );
|
33
|
+
|
34
|
+
// Run delegated `on blur` validation checks
|
35
|
+
docBody.addEventListener( 'blur', blurHandler, true );
|
36
|
+
|
37
|
+
// Run delegated `on submit` validation checks
|
38
|
+
docBody.addEventListener( 'click', submissionHandler, false );
|
39
|
+
|
40
|
+
// Blur validation handler
|
41
|
+
function blurHandler( event ) {
|
42
|
+
|
43
|
+
// Only run on non-submit inputs
|
44
|
+
if ( !matches( event.target, 'input:not([type=submit]), textarea' ) ) return false;
|
45
|
+
|
46
|
+
// Scoped variables
|
47
|
+
var element = event.target,
|
48
|
+
minWords = element.dataset.minWords,
|
49
|
+
maxWords = element.dataset.maxWords,
|
50
|
+
indicator = getClosest( element, 'label' ) || element,
|
51
|
+
validity;
|
52
|
+
|
53
|
+
// If element only contains whitespace, strip value
|
54
|
+
if ( element.value && !element.value.replace( /\s/g, '' ).length ) {
|
55
|
+
element.value = '';
|
56
|
+
}
|
57
|
+
|
58
|
+
// Remove pre-existing validation message
|
59
|
+
messageHandler( 'hide', element );
|
60
|
+
|
61
|
+
// If element has `data-min-words` attribute
|
62
|
+
if ( minWords ) {
|
63
|
+
|
64
|
+
// Run respective validation function
|
65
|
+
validateWords( 'min', element, minWords );
|
66
|
+
|
67
|
+
}
|
68
|
+
|
69
|
+
// If element has `data-min-words` attribute
|
70
|
+
if ( maxWords ) {
|
71
|
+
|
72
|
+
// Run respective validation function
|
73
|
+
validateWords( 'max', element, maxWords );
|
74
|
+
|
75
|
+
}
|
76
|
+
|
77
|
+
// Check validity
|
78
|
+
validity = element.checkValidity();
|
79
|
+
|
80
|
+
// If the element has a value but is invalid
|
81
|
+
if ( element.value && !validity ) {
|
82
|
+
|
83
|
+
// Set invalid state
|
84
|
+
indicator.classList.remove( 'valid' );
|
85
|
+
indicator.classList.add( 'invalid' );
|
86
|
+
|
87
|
+
// If the element has a value and is valid
|
88
|
+
} else if ( element.value && validity ) {
|
89
|
+
|
90
|
+
// Set valid state
|
91
|
+
indicator.classList.remove( 'invalid' );
|
92
|
+
indicator.classList.add( 'valid' );
|
93
|
+
|
94
|
+
// If the element has no value
|
95
|
+
} else if ( !element.value ) {
|
96
|
+
|
97
|
+
// Set neutral state
|
98
|
+
indicator.classList.remove( 'valid' );
|
99
|
+
indicator.classList.remove( 'invalid' );
|
100
|
+
|
101
|
+
}
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
// Submission validation handler function
|
106
|
+
function submissionHandler( event ) {
|
107
|
+
|
108
|
+
// Only run on submission
|
109
|
+
if ( !matches( event.target, 'input[type=submit], button[type=submit]' ) ) return;
|
110
|
+
|
111
|
+
// Scoped variables
|
112
|
+
var invalidForm = getClosest( event.target, 'form' ),
|
113
|
+
invalidElem = invalidForm.querySelector( 'input:invalid, textarea:invalid' ),
|
114
|
+
indicator;
|
115
|
+
|
116
|
+
// If invalid element found
|
117
|
+
if ( invalidElem ) {
|
118
|
+
|
119
|
+
// Set indicator to parent label if it exists
|
120
|
+
indicator = getClosest( invalidElem, 'label' ) || invalidElem;
|
121
|
+
|
122
|
+
// If credit card field is invalid
|
123
|
+
if ( matches( invalidElem, '[data-stripe=number]' ) ) {
|
124
|
+
|
125
|
+
// Strip it of non-number characters
|
126
|
+
invalidElem.value = invalidElem.value.replace( /[^0-9 -]/g, '' );
|
127
|
+
|
128
|
+
// Evaluate form validity again
|
129
|
+
invalidElem = invalidForm.querySelector( 'input:invalid, textarea:invalid' );
|
130
|
+
|
131
|
+
// And return if valid
|
132
|
+
if ( !invalidElem ) return;
|
133
|
+
|
134
|
+
}
|
135
|
+
|
136
|
+
// Prevent default behavior
|
137
|
+
event.preventDefault();
|
138
|
+
|
139
|
+
// If invalid is not hidden
|
140
|
+
if ( invalidElem.style.display !== 'none' ) {
|
141
|
+
|
142
|
+
// Focus it
|
143
|
+
invalidElem.focus();
|
144
|
+
|
145
|
+
// Otherwise
|
146
|
+
} else {
|
147
|
+
|
148
|
+
// Focus its immediate sibling (mostly used for upload buttons)
|
149
|
+
invalidElem.nextSibling.focus();
|
150
|
+
|
151
|
+
}
|
152
|
+
|
153
|
+
// Toggle classes
|
154
|
+
indicator.classList.remove( 'valid' );
|
155
|
+
indicator.classList.add( 'invalid' );
|
156
|
+
|
157
|
+
// Show validation message
|
158
|
+
messageHandler( 'show', invalidElem );
|
159
|
+
|
160
|
+
// Prevent Safari submission
|
161
|
+
return false;
|
162
|
+
|
163
|
+
}
|
164
|
+
|
165
|
+
}
|
166
|
+
|
167
|
+
// Validation message handler function
|
168
|
+
function messageHandler( action, element ) {
|
169
|
+
|
170
|
+
// Scoped variables
|
171
|
+
var parentForm = getClosest( element, 'form' ),
|
172
|
+
oldMessage = parentForm.querySelector( '.validation-message' ),
|
173
|
+
newMessage = element.validationMessage,
|
174
|
+
|
175
|
+
// Hide old message
|
176
|
+
hideMessage = function() {
|
177
|
+
oldMessage.parentNode.removeChild( oldMessage );
|
178
|
+
},
|
179
|
+
|
180
|
+
// Show new message
|
181
|
+
showMessage = function() {
|
182
|
+
|
183
|
+
// Find the element's parent label
|
184
|
+
var labelParent = getClosest( element, 'label' );
|
185
|
+
|
186
|
+
// If it doesn't exist, abort
|
187
|
+
if ( !labelParent ) return false;
|
188
|
+
|
189
|
+
// Otherwise, create and append the validation message
|
190
|
+
labelParent.insertAdjacentHTML( 'beforeend', '<aside class="validation-message"><p>' + newMessage + '</p></aside>' );
|
191
|
+
|
192
|
+
};
|
193
|
+
|
194
|
+
// If a `data-message` attribute exists, use it in message
|
195
|
+
if ( element.dataset.message ) newMessage = element.dataset.message;
|
196
|
+
|
197
|
+
// If hide action is passed hide old message
|
198
|
+
if ( oldMessage && action === 'hide' ) hideMessage();
|
199
|
+
|
200
|
+
// If show action is passed and no old message exists
|
201
|
+
if ( action === 'show' && !oldMessage ) {
|
202
|
+
|
203
|
+
// Show new message
|
204
|
+
showMessage();
|
205
|
+
|
206
|
+
// If show action is passed and old message exists
|
207
|
+
} else if ( action === 'show' && oldMessage ) {
|
208
|
+
|
209
|
+
// Make sure old message is not on currently invalid element
|
210
|
+
if ( oldMessage.parentNode !== element.parentNode ) {
|
211
|
+
|
212
|
+
// Hide old message
|
213
|
+
hideMessage();
|
214
|
+
|
215
|
+
// And show new message
|
216
|
+
showMessage();
|
217
|
+
|
218
|
+
// Otherwise
|
219
|
+
} else {
|
220
|
+
|
221
|
+
// Update message text on currently invalid element
|
222
|
+
oldMessage.childNodes[ 0 ].textContent = newMessage;
|
223
|
+
|
224
|
+
}
|
225
|
+
|
226
|
+
}
|
227
|
+
|
228
|
+
}
|
229
|
+
|
230
|
+
// Min- or max-words validation function
|
231
|
+
function validateWords( type, element, goal ) {
|
232
|
+
|
233
|
+
// Defaults settings to min-words
|
234
|
+
var value = element.value,
|
235
|
+
condition = wordCount( value ) < goal,
|
236
|
+
verbiage = 'at least ';
|
237
|
+
|
238
|
+
// Overwrite defaults in case of max-words
|
239
|
+
if ( type === 'max' ) {
|
240
|
+
condition = wordCount( value ) > goal;
|
241
|
+
verbiage = 'no more than ';
|
242
|
+
}
|
243
|
+
|
244
|
+
// If value exists and it meets invalid condition
|
245
|
+
if ( value && condition ) {
|
246
|
+
|
247
|
+
// Set a custom error message
|
248
|
+
element.setCustomValidity( 'Please write ' + verbiage + goal + ' words.' );
|
249
|
+
|
250
|
+
// Otherwise
|
251
|
+
} else {
|
252
|
+
|
253
|
+
// Default to normal error messaging
|
254
|
+
element.setCustomValidity( '' );
|
255
|
+
|
256
|
+
}
|
257
|
+
|
258
|
+
}
|
259
|
+
|
260
|
+
};
|
261
|
+
|
262
|
+
// Public API
|
263
|
+
module.exports = validation;
|