forked from saabi/vminpoly
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vminpoly.coffee
288 lines (247 loc) · 8.13 KB
/
vminpoly.coffee
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
XMLHttpFactories = [
-> new XMLHttpRequest(),
-> new ActiveXObject("Msxml2.XMLHTTP"),
-> new ActiveXObject("Msxml3.XMLHTTP"),
-> new ActiveXObject("Microsoft.XMLHTTP")]
createXMLHTTPObject = ->
xmlhttp = false
i = 0
while i < XMLHttpFactories.length
try
xmlhttp = XMLHttpFactories[i++]()
catch e
continue
break
xmlhttp
##toCamelCase = (s) ->
## s.replace(/-([a-z])/g, (g) ->
## return g[1].toUpperCase()
ajax = (url, onload) ->
xmlhttp = createXMLHTTPObject()
xmlhttp.onreadystatechange = ->
unless xmlhttp.readyState is 4
return
unless xmlhttp.status is 200 || url.match(/^file:\/\/\//)
throw "Error!"
console.log "INFO: processing #{url}"
onload xmlhttp.responseText
return
try
xmlhttp.open "GET", url, true
xmlhttp.send()
catch e
console.log "ERROR: #{e.message} (#{e.type}) when accessing #{url}"
return
# get window dimensions, cross-browser compatible
# Thanks to: Stefano Gargiulo
getViewportSize = ->
x = 0
y = 0
if window.innerHeight # all except Explorer < 9
x = window.innerWidth
y = window.innerHeight
else if document.documentElement and document.documentElement.clientHeight
# Explorer 6 Strict Mode
x = document.documentElement.clientWidth
y = document.documentElement.clientHeight
else if document.body # other Explorers < 9
x = document.body.clientWidth
y = document.body.clientHeight
width: x
height: y
browserSupportsUnitsNatively = ->
# Append Test element
test_element = document.createElement('div')
test_element.id = "vminpolyTests"
body = document.getElementsByTagName('body')[0]
body.appendChild test_element
# Append test style block
style_block = document.createElement('style')
head = document.getElementsByTagName('head')[0]
head.appendChild style_block
test_results = testVWSupport(test_element, style_block) and testVWSupport(test_element, style_block) and testVMinSupport(test_element, style_block)
body.removeChild test_element
head.removeChild style_block
test_results
testElementStyle = (element) ->
if window.getComputedStyle
getComputedStyle(element, null)
else
element.currentStyle
applyStyleTest = (style_block, style) ->
new_style = "#vminpolyTests { #{style}; }"
if style_block.styleSheet
style_block.styleSheet.cssText = new_style
else
test_style = document.createTextNode new_style
style_block.appendChild test_style
clearStyleTests = (style_block) ->
if style_block.styleSheet
style_block.styleSheet.cssText = ''
else
style_block.innerHTML = ''
testVHSupport = (element, style_block) ->
# Set height of element
applyStyleTest(style_block, 'height: 50vh')
# Parse page height to compare
height = parseInt(window.innerHeight / 2, 10)
# Computed style
comp_style = parseInt(testElementStyle(element).height, 10)
# Remove current test style
clearStyleTests style_block
# return result
comp_style is height
testVWSupport = (element, style_block) ->
# Set width of element
applyStyleTest(style_block, 'width: 50vw')
# Parse page width to compare
width = parseInt(window.innerWidth / 2, 10)
# Computed style
comp_style = parseInt(testElementStyle(element).width, 10)
# Remove current test style
clearStyleTests style_block
# return result
comp_style is width
testVMinSupport = (element, style_block) ->
# Set width of the element
applyStyleTest(style_block, 'width: 50vmin')
# docElement has to be defined, can you believe it
docElement = document.documentElement
# find minimum calculation sizes
one_vw = docElement.clientWidth / 100
one_vh = docElement.clientHeight / 100
actual_vmin = parseInt(Math.min(one_vw, one_vh)*50,10)
# Computed width
comp_width = parseInt(testElementStyle(element).width, 10)
# Remove current test style
clearStyleTests style_block
# return result
actual_vmin is comp_width
initLayoutEngine = () ->
analyzeStyleRule = (rule) ->
declarations = []
for declaration in rule.value
hasDimension = false
for token in declaration.value
if token.tokenType is 'DIMENSION' and (token.unit is 'vmin' or token.unit is 'vh' or token.unit is 'vw')
hasDimension = true
if hasDimension
declarations.push declaration
rule.value = declarations
declarations
analyzeStylesheet = (sheet) ->
rules = []
for rule in sheet.value
switch rule.type
when 'STYLE-RULE'
decs = analyzeStyleRule rule
unless decs.length is 0
rules.push rule
when 'AT-RULE'
atRules = analyzeStylesheet rule
unless atRules.length is 0
rules.push rule
sheet.value = rules
rules
onresize = ->
vpDims = getViewportSize()
dims =
vh: vpDims.height / 100
vw: vpDims.width / 100
dims.vmin = Math.min dims.vh, dims.vw
vpAspectRatio = vpDims.width / vpDims.height
map = (a, f) ->
if a.map?
a.map f
else
a1 = []
for e in a
a1.push f e
a1
generateRuleCode = (rule) ->
declarations = []
ruleCss = (map rule.selector, (o) -> if o.toSourceString? then o.toSourceString() else '').join ''
ruleCss += "{"
for declaration in rule.value
ruleCss += declaration.name
ruleCss += ":"
for token in declaration.value
if token.tokenType is 'DIMENSION' and (token.unit is 'vmin' or token.unit is 'vh' or token.unit is 'vw')
ruleCss += "#{Math.floor(token.num*dims[token.unit])}px"
else
ruleCss += token.toSourceString()
ruleCss += ";"
ruleCss += "}\r"
ruleCss
generateSheetCode = (sheet) ->
sheetCss = ''
for rule in sheet.value
switch rule.type
when 'STYLE-RULE'
sheetCss += generateRuleCode rule
when 'AT-RULE'
if rule.name is 'media'
prelude = ''
mar = false
nums = []
for t in rule.prelude
if t.name is '('
prelude += '('
for t1 in t.value
source = if t1.toSourceString? then t1.toSourceString() else ''
if t1.tokenType is 'IDENT' and source is 'max-aspect-ratio'
mar = true
if t1.tokenType is 'NUMBER'
nums.push parseInt source
prelude += source
#prelude += (map t.value, (o) -> if o.toSourceString? then o.toSourceString() else '').join ''
#prelude += t.value.join ''
prelude += ')'
else
prelude += t.toSourceString()
if vpAspectRatio < nums[0] / nums[1]
sheetCss += generateSheetCode rule
else
prelude = ''
for t in rule.prelude
if t.name is '('
prelude += '('
prelude += (map t.value, (o) -> if o.toSourceString? then o.toSourceString() else '').join ''
#prelude += t.value.join ''
prelude += ')'
else
prelude += t.toSourceString()
sheetCss += "@#{rule.name} #{prelude} {"
sheetCss += generateSheetCode rule
sheetCss += '}\n'
sheetCss
css = ''
for url, sheet of sheets
css += generateSheetCode sheet
if styleElement.styleSheet?
styleElement.styleSheet.cssText = css
else
styleElement.innerHTML = css
sheets = {}
styleElement = document.createElement 'style'
head = document.getElementsByTagName('head')[0]
head.appendChild styleElement
links = document.getElementsByTagName 'link'
innerSheetCount = 0;
outerSheetCount = 0;
for i in links
unless i.rel is 'stylesheet'
continue
innerSheetCount++;
ajax i.href, (cssText) ->
tokenlist = tokenize cssText
sheet = parse tokenlist
analyzeStylesheet sheet
sheets[i.href] = sheet
outerSheetCount++
if outerSheetCount is innerSheetCount
window.onresize()
return
window.onresize = onresize
return
initLayoutEngine() unless browserSupportsUnitsNatively()