1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | $ = jQuery
|
13 |
|
14 |
|
15 | totalPlugins = 0
|
16 | callQueue = []
|
17 |
|
18 |
|
19 |
|
20 | class Li
|
21 |
|
22 | constructor: (el, settings) ->
|
23 | $el = $(el)
|
24 | @originalWidth = @width = $el.outerWidth(false)
|
25 | @originalHeight = @height = $el.height()
|
26 | @originalMargin = @margin = $el.outerWidth(true) - $el.outerWidth(false)
|
27 | $img = $el.find('img')
|
28 | @imgRatio = $img.width() / $img.height()
|
29 | @$el = $el
|
30 | @settings = settings
|
31 |
|
32 | setHeight: (h) ->
|
33 | @width = Math.round(h * (@width / @height))
|
34 | @height = h unless @settings.lockedHeight
|
35 |
|
36 | setWidth: (w) ->
|
37 | @height = Math.round(w * (@height / @width))
|
38 | @width = w
|
39 |
|
40 | decWidth: -> @setWidth @width - 1
|
41 |
|
42 | decHeight: -> @setHeight @height - 1
|
43 |
|
44 | incWidth: -> @setWidth @width + 1
|
45 |
|
46 | incHeight: -> @setHeight @height + 1
|
47 |
|
48 | updateDOM: ->
|
49 | @$el.css
|
50 | width : @width
|
51 | height : @height
|
52 | 'margin-right' : @margin
|
53 | @$el.find('img').height 'auto'
|
54 |
|
55 | reset: ->
|
56 | @width = @originalWidth
|
57 | @height = @originalHeight
|
58 | @margin = @originalMargin
|
59 | @$el.css
|
60 | width : @width
|
61 | height : @height
|
62 | 'margin-right' : @margin
|
63 |
|
64 | class Row
|
65 |
|
66 | constructor: (@frameWidth, @settings) ->
|
67 | @lis = []
|
68 |
|
69 | width: ->
|
70 | width = 0
|
71 | width += (li.width + li.margin) for li in @lis
|
72 | width
|
73 |
|
74 | updateDOM: ->
|
75 | li.updateDOM() for li in @lis
|
76 |
|
77 |
|
78 | reset: -> li.reset() for li in @lis
|
79 |
|
80 |
|
81 |
|
82 | landscapeGroups: ->
|
83 | landscapeGroups = []
|
84 | for i, ratio of @settings.landscapeRatios
|
85 | landscapes = (li for li in @lis when li.imgRatio >= ratio)
|
86 | landscapeGroups.push landscapes
|
87 | landscapeGroups
|
88 |
|
89 |
|
90 | resizeLandscapes: ->
|
91 | for landscapes in @landscapeGroups(@settings.landscapeRatios) when landscapes.length isnt 0
|
92 |
|
93 |
|
94 | for i in [0..@settings.resizeLandscapesBy]
|
95 | li.decHeight() for li in landscapes
|
96 | break if @width() <= @frameWidth
|
97 | break if @width() <= @frameWidth
|
98 | @
|
99 |
|
100 |
|
101 | adjustMargins: ->
|
102 | for i in [0..@settings.adjustMarginsBy]
|
103 | for li in @lis[0..@lis.length - 2]
|
104 | li.margin--
|
105 | break if @width() <= @frameWidth
|
106 | break if @width() <= @frameWidth
|
107 |
|
108 |
|
109 | resizeHeight: ->
|
110 | i = 0
|
111 | while @width() > @frameWidth and i < @settings.resizeRowBy
|
112 | i++
|
113 | li.decHeight() for li in @lis
|
114 |
|
115 |
|
116 | roundOff: ->
|
117 | li.setWidth(Math.floor li.width) for li in @lis
|
118 |
|
119 |
|
120 | fillLeftoverPixels: ->
|
121 | @roundOff()
|
122 | diff = => @frameWidth - @width()
|
123 |
|
124 | while diff() isnt 0
|
125 | randIndex = Math.round Math.random() * (@lis.length - 1)
|
126 | if diff() < 0
|
127 | @lis[randIndex].decWidth()
|
128 | else
|
129 | @lis[randIndex].incWidth()
|
130 |
|
131 |
|
132 | removeMargin: ->
|
133 | lastLi = @lis[@lis.length - 1]
|
134 | lastLi.margin = 0
|
135 |
|
136 |
|
137 | lockHeight: ->
|
138 | tallestLi = (@lis.sort (a, b) -> b.height - a.height)[0]
|
139 | tallestHeight = Math.ceil tallestLi.height
|
140 | li.height = tallestHeight for li in @lis
|
141 |
|
142 | # Go through the lis and hide them
|
143 | hide: -> li.$el.hide() for li in @lis
|
144 |
|
145 |
|
146 | show: -> li.$el.show() for li in @lis
|
147 |
|
148 |
|
149 |
|
150 | debounce = (func, wait) ->
|
151 | timeout = 0
|
152 | return ->
|
153 | args = arguments
|
154 | throttler = =>
|
155 | timeout = null
|
156 | func args
|
157 |
|
158 | clearTimeout timeout
|
159 | timeout = setTimeout(throttler, wait)
|
160 |
|
161 |
|
162 |
|
163 | methods =
|
164 |
|
165 |
|
166 | init: (settings) ->
|
167 |
|
168 |
|
169 | _defaults =
|
170 | resizeLandscapesBy: 200
|
171 | resizeRowBy: 30
|
172 | landscapeRatios: (i / 10 for i in [10..50] by 3).reverse()
|
173 | fillLastRow: false
|
174 | beforeFillWidth: null
|
175 | afterFillWidth: null
|
176 | @settings = $.extend _defaults, settings
|
177 |
|
178 | @each (i, el) =>
|
179 | $el = $(el)
|
180 | methods.initStyling.call @, $el
|
181 |
|
182 |
|
183 |
|
184 | initFillWidth = =>
|
185 | methods.fillWidth.call @, $el
|
186 |
|
187 |
|
188 | unless navigator.userAgent.match(/iPhone/i) or
|
189 | navigator.userAgent.match(/iPad/i) or
|
190 | navigator.userAgent.match(/iPod/i) or
|
191 | navigator.userAgent.match(/MSIE 8\.0/i)
|
192 | $(window).bind 'resize.fillwidth', debounce (=>
|
193 | callQueue.push (=> methods.fillWidth.call @, $el)
|
194 | if callQueue.length is totalPlugins
|
195 | fn() for fn in callQueue
|
196 | callQueue = []
|
197 | ), 300
|
198 | totalPlugins++
|
199 |
|
200 | $imgs = $el.find('img')
|
201 |
|
202 | if @settings.imageDimensions?
|
203 | initFillWidth()
|
204 | else
|
205 | imagesToLoad = $imgs.length
|
206 | $imgs.load ->
|
207 | imagesToLoad--
|
208 | initFillWidth() if imagesToLoad is 0
|
209 |
|
210 |
|
211 |
|
212 | initStyling: (el) ->
|
213 | $el = $ el
|
214 | $el.css
|
215 | 'list-style': 'none'
|
216 | padding: 0
|
217 | margin: 0
|
218 | $el.css @settings.initStyling if @settings.initStyling?
|
219 | $el.find('> li').css
|
220 | 'float': 'left'
|
221 | 'margin-left': 0
|
222 | $el.find('img').css
|
223 | 'max-width': '100%'
|
224 | 'max-height': '100%'
|
225 |
|
226 |
|
227 | if @settings and @settings.imageDimensions?
|
228 | $el.find('> li').each (i, el) =>
|
229 | $img = $(el).find('img').first()
|
230 | $img.width @settings.imageDimensions[i].width
|
231 | $img.height @settings.imageDimensions[i].height
|
232 |
|
233 |
|
234 | destroy: ->
|
235 | $(window).unbind 'resize.fillwidth'
|
236 | @each ->
|
237 | row.reset() for row in $(@).fillwidth('rowObjs')
|
238 | $(@).removeData('fillwidth.rows')
|
239 |
|
240 |
|
241 | fillWidth: (el) ->
|
242 | $el = $ el
|
243 | $el.trigger 'fillwidth.beforeFillWidth'
|
244 | @settings.beforeFillWidth() if @settings.beforeFillWidth?
|
245 |
|
246 |
|
247 | if @fillwidthRows
|
248 | row.reset() for row in @fillwidthRows
|
249 | $el.width 'auto'
|
250 |
|
251 | $el.trigger 'fillwidth.beforeNewRows'
|
252 | @settings.beforeNewRows() if @settings.beforeNewRows?
|
253 |
|
254 |
|
255 | @frameWidth = $el.width()
|
256 | rows = methods.breakUpIntoRows.call @, $el
|
257 | @fillwidthRows = rows
|
258 | $el.width @frameWidth
|
259 |
|
260 | $el.trigger 'fillwidth.afterNewRows'
|
261 | @settings.afterNewRows() if @settings.afterNewRows?
|
262 |
|
263 |
|
264 | for row in rows
|
265 | continue unless row.lis.length > 1
|
266 | row.removeMargin()
|
267 | row.resizeHeight()
|
268 | row.adjustMargins() if @settings.adjustMarginsBy?
|
269 | row.resizeLandscapes()
|
270 | row.fillLeftoverPixels() unless row is rows[rows.length - 1] and not @settings.fillLastRow
|
271 | row.lockHeight()
|
272 | row.updateDOM()
|
273 |
|
274 | $el.trigger 'fillwidth.afterFillWidth'
|
275 | @settings.afterFillWidth() if @settings.afterFillWidth?
|
276 |
|
277 |
|
278 | rowObjs: ->
|
279 | arr = []
|
280 | rows = @fillwidthRows
|
281 | @each ->
|
282 | arr.push rows
|
283 | arr = arr[0] if arr.length is 1
|
284 | arr
|
285 |
|
286 |
|
287 | rows: ->
|
288 | rows = methods.rowObjs.call @
|
289 | arr = []
|
290 | for row in rows
|
291 | arr.push (li.$el for li in row.lis)
|
292 | arr = arr[0] if arr.length is 1
|
293 | arr
|
294 |
|
295 |
|
296 |
|
297 |
|
298 | breakUpIntoRows: (el) ->
|
299 | $el = $ el
|
300 | i = 0
|
301 | rows = [new Row(@frameWidth, @settings)]
|
302 | $el.find('> li').each (j, li) =>
|
303 | return if $(li).is(':hidden')
|
304 | rows[i].lis.push new Li li, @settings
|
305 | if rows[i].width() >= $el.width() and j isnt $el.find('> li').length - 1
|
306 | rows.push new Row(@frameWidth, @settings)
|
307 | i++
|
308 | rows
|
309 |
|
310 |
|
311 | $.fn.fillwidth = (method) ->
|
312 | if methods[method]?
|
313 | methods[method].apply @, Array::slice.call(arguments, 1)
|
314 | else if typeof method is "object" or not method?
|
315 | methods.init.apply @, arguments
|
316 | else
|
317 | $.error "Method #{method} does not exist on jQuery.fillwidth"
|