-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInputField.coffee
More file actions
253 lines (204 loc) · 8.22 KB
/
InputField.coffee
File metadata and controls
253 lines (204 loc) · 8.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
################################################################################
# Created 07 Jan 2016 by Jordan Robert Dobson / @jordandobson / JordanDobson.com
################################################################################
#
# Valid & Tested InputField Types:
# "text", "email", "number", "number-only", "url", "tel", "password", "search"
# "time", "month", "date", "datetime-local", "file", "file-multiple", "file-image", "file-video"
#
# The time & date types REQUIRE the value property is in a correct format & IGNORE the placeholder property.
#
# Here's a few examples to use for the value: property when you create them:
#
# * time: "12:38"
# * month: "2016-01"
# * date: "2016-01-04"
# * datetime-local: "2016-01-04T12:44:31.192"
#
# NOTES /
# Some types work better than others on mobile or display differently than desktop.
# All properties will work with input type "text" but may not work with other types.
# Some events won't fire if you enter incorrect content for the field type: i.e. "hello" for input type "number".
# Find more patterns for Valid and Invalid events at http://html5pattern.com
#
################################################################################
class exports.InputField extends Layer
PATTERN_NUMBER = "[0-9]*"
INPUT_HIDE_PSUEDO_UI = "{ -webkit-appearance: none; display: none; }"
INPUT_SELECTOR_NUMBER = "input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button"
INPUT_SELECTOR_SEARCH = "input[type=search]::-webkit-search-cancel-button"
Events.Input = "InputField.OnInput"
Events.Focus = "InputField.OnFocus"
Events.Blur = "InputField.OnBlur"
Events.Valid = "InputField.OnValid"
Events.Invalid = "InputField.OnInvalid"
Events.Match = "InputField.OnMatch"
Events.FileData = "InputField.OnFileData"
@define "value",
get: ->
@input.value
set: (v) ->
return unless v
if @input
@changeInputValue v
constructor: (@options={}) ->
@isNumber = false
@isSearch = false
@isFile = false
@isEmpty = true
@isValid = null
@isFileMulti = false
@isFilePhoto = false
@isFileVideo = false
@originalTextColor = null
# Make sure we set the Checking Flag
@shouldCheckValidity = true if @options.pattern? or @options.match?
# Make sure this is in px
@options.lineHeight = "#{@options.lineHeight}px" if @options.lineHeight?
# Framer Layer Props
@options.name ?= "#{@options.type}Input"
@options.color ?= "#000"
@options.backgroundColor ?= ""
@options.borderRadius ?= 0
# Custom Layer Props
@options.type ?= "text"
@options.fontSize ?= 32
@options.fontWeight ?= 300
@options.fontFamily ?= "-apple-system, Helvetica Neue"
@options.lineHeight ?= 1.25
@options.indent ?= 0
@options.placeHolderFocus ?= null
@options.placeHolderColor ?= null
# Started work on file
if _.startsWith(@options.type, ["file"])
@options.fontSize = "inherit"
@options.fontWeight = 400
@options.lineHeight = 1
super @options
# Adjust a few things for various types
switch @options.type
when "search" then @isSearch = true
when "number" then @isNumber = true
when "numbers-only", "number-only"
@isNumber = true
@options.type = if @options.pattern? then "number" else "text"
@options.pattern = if @options.pattern? then @options.pattern else PATTERN_NUMBER
when "file", "file-multiple", "file-image", "file-video"
@isFile = true
@isFilePhoto = true if @options.type is "file-image"
@isFileVideo = true if @options.type is "file-video"
@isFileMulti = true if @options.type is "file-multiple"
@options.type = "file"
@html += switch
when @isNumber then "<style type='text/css'>#{INPUT_SELECTOR_NUMBER}#{INPUT_HIDE_PSUEDO_UI}</style>"
when @isSearch then "<style type='text/css'>#{INPUT_SELECTOR_SEARCH}#{INPUT_HIDE_PSUEDO_UI}</style>"
else ""
if @options.placeHolderColor?
@html += "<style type='text/css'>::-webkit-input-placeholder { color: #{@options.placeHolderColor}; } ::-moz-placeholder { color: #{@options.placeHolderColor}; } :-ms-input-placeholder { color: #{@options.placeHolderColor}; } ::-ms-input-placeholder { color: #{@options.placeHolderColor}; } :placeholder-shown { color: #{@options.placeHolderColor}; }</style>"
# Create The Input
@input = document.createElement "input"
# Text Type Adjustments
@input.type = @options.type
@input.value = @options.value if @options.value?
@input.placeholder = @options.placeHolder if @options.placeHolder?
@input.pattern = @options.pattern if @options.pattern?
@input.setAttribute("maxLength", @options.maxLength) if @options.maxLength?
@input.setAttribute("autocapitalize", (if @options.autoCapitalize is true then "on" else "off"))
@input.setAttribute("autocomplete", (if @options.autoComplete is true then "on" else "off"))
@input.setAttribute("autocorrect", (if @options.autoCorrect is true then "on" else "off"))
# File Type Adjustments
@input.setAttribute("multiple", "multiple") if @isFileMulti
@input.setAttribute("accept", "video/*" ) if @isFileVideo
@input.setAttribute("accept", "image/*" ) if @isFilePhoto
@_element.appendChild @input
# Setup Values
@isEmpty = !(@options.value?.length > 0)
@originalTextColor = @options.color
# Setup Input Style
inputStyle =
font: "#{@options.fontWeight} #{@options.fontSize}px/#{@options.lineHeight} #{@options.fontFamily}"
outline: "none"
textIndent: "#{@options.indent}px"
backgroundColor: "transparent"
height: "100%"
width: "100%"
margin: "0"
padding: "0"
verticalAlign: "top"
"-webkit-appearance": "none"
opacity: if @isFile then 0 else 1
pointerEvents: if @isFile then "all" else "auto"
@input.style[key] = val for key, val of inputStyle
@input.style.color = @options.color if @options.color?
@input.onfocus = =>
document.body.scrollTop = 0
@input.placeholder = @options.placeHolderFocus if @options.placeHolderFocus?
document.body.scrollTop = 0
@emit(Events.Focus, @input.value, @)
@input.onblur = =>
document.body.scrollTop = 0
unless @input.placeholder is @options.placeHolder or !@options.placeHolder?
@input.placeholder = @options.placeHolder
@emit(Events.Blur, @input.value, @)
@input.oninput = =>
@isEmpty = !( @input.value?.length > 0)
@emit(Events.Input, @input.value, @)
@checkValidity()
@input.addEventListener("change", @fileSelectHandler, false) if @isFile
@on Events.TouchEnd, -> @input.focus()
@on "change:color", -> @changeInputTextColor()
@wrapFileInputToParent()
# http://www.sitepoint.com/html5-javascript-open-dropped-files/
fileSelectHandler: (event) =>
return unless event # fix Check this better?
file = event.target.files[0]
if file.type.indexOf("image") == 0
reader = new FileReader()
reader.onload = (readEvent) =>
@emit(Events.FileData, readEvent.target.result, @)
console.log readEvent
console.log file
reader.readAsDataURL file
checkValidity: ->
return unless @shouldCheckValidity
if @options.pattern?
validity = @input.checkValidity()
@isEmpty = !( @input.value?.length > 0)
if @isValid isnt validity or @isEmpty
if @isEmpty or !validity
@isValid = false
@emit(Events.Invalid, @input.value, @)
else
@isValid = true
@emit(Events.Valid, @input.value, @)
if @checkMatch()
@isValid = true
@emit(Events.Match, @input.value, @)
checkMatch: ->
return false unless @options.match?
if Array.isArray(@options.match)
for match in @options.match
return true if @input.value.indexOf(match) > -1
else
return true if @input.value.indexOf(@options.match) > -1
return false
clear: ->
@input.value = ""
@isValid = null
@isEmpty = true
changeInputTextColor: ->
@input.style.color = @color.toHexString()
changeInputValue: (v) ->
@input.value = v
@input.oninput()
wrapFileInputToParent: ->
return unless @isFile
if @.parent
@.width = @.parent.frame.width
@.height = @.parent.frame.height
else
@input.style.opacity = 1
@input.style.lineHeight = "#{@.height}px"
@input.style.color = "#fff"
@input.style.textIndent = "1em"
@.backgroundColor = "#fff"