1 // Generated by CoffeeScript 1.9.3 |
|
2 |
|
3 /* |
|
4 * Touch Splitter JQuery was created by Cole Lawrence(github:ZombieHippie) |
|
5 * This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 |
|
6 * Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/. |
|
7 */ |
|
8 |
|
9 (function() { |
|
10 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; |
|
11 |
|
12 (function(mod) { |
|
13 if (typeof exports === "object" && typeof module === "object") { |
|
14 return mod(require("jquery")); |
|
15 } else if (typeof define === "function" && define.amd) { |
|
16 return define(["jquery"], mod); |
|
17 } else { |
|
18 return mod(jQuery); |
|
19 } |
|
20 })(function(jQuery) { |
|
21 var $, TouchSplitter; |
|
22 $ = jQuery; |
|
23 $.fn.touchSplit = function(options) { |
|
24 if (options == null) { |
|
25 options = {}; |
|
26 } |
|
27 if (this[0].touchSplitter != null) { |
|
28 throw "Cannot make a splitter here! '" + this.selector + "' already has a splitter! Use $('" + this.selector + "')[0].touchSplitter.destroy(<optional side to remove>) to remove it!"; |
|
29 } |
|
30 if (this.children().length !== 2 && this.children().length !== 0) { |
|
31 throw "Cannot make a splitter here! Incorrect number of div children in '" + this.selector + "'"; |
|
32 } |
|
33 return this[0].touchSplitter = new TouchSplitter(this, options); |
|
34 }; |
|
35 return TouchSplitter = (function() { |
|
36 function TouchSplitter(element, options) { |
|
37 var barThick, firstdiv, inners, match, splitterHTML, testCalc, testEm, thickness, units; |
|
38 this.element = element; |
|
39 this.resize = bind(this.resize, this); |
|
40 this.onResize = bind(this.onResize, this); |
|
41 this.onResizeWindow = bind(this.onResizeWindow, this); |
|
42 this.getSecond = bind(this.getSecond, this); |
|
43 this.getFirst = bind(this.getFirst, this); |
|
44 this.stopDragging = bind(this.stopDragging, this); |
|
45 this.drag = bind(this.drag, this); |
|
46 this.startDragging = bind(this.startDragging, this); |
|
47 this.onTouchEnd = bind(this.onTouchEnd, this); |
|
48 this.onTouchMove = bind(this.onTouchMove, this); |
|
49 this.onTouchStart = bind(this.onTouchStart, this); |
|
50 this.onMouseDown = bind(this.onMouseDown, this); |
|
51 this.setPercentages = bind(this.setPercentages, this); |
|
52 this.setDock = bind(this.setDock, this); |
|
53 this.moveBar = bind(this.moveBar, this); |
|
54 this.on = bind(this.on, this); |
|
55 this.toggleDock = bind(this.toggleDock, this); |
|
56 this.setRatios = bind(this.setRatios, this); |
|
57 this.destroy = bind(this.destroy, this); |
|
58 this.element.addClass('TouchSplitter'); |
|
59 this.support = {}; |
|
60 testEm = $('<div class="test-em"></div>'); |
|
61 testEm.appendTo(this.element); |
|
62 barThick = testEm.width(); |
|
63 testEm.remove(); |
|
64 testCalc = $('<div class="test-calc"></div>'); |
|
65 testCalc.appendTo(this.element); |
|
66 this.support.calc = true; |
|
67 testCalc.remove(); |
|
68 if (options.orientation != null) { |
|
69 if (options.orientation === "vertical") { |
|
70 this.horizontal = false; |
|
71 } else if (options.orientation === "horizontal") { |
|
72 |
|
73 } else { |
|
74 console.log("Touch Splitter ERROR: orientation cannot be:'" + options.orientation + "' defaulted to 'horizontal'"); |
|
75 } |
|
76 } |
|
77 if (this.horizontal !== false) { |
|
78 this.horizontal = true; |
|
79 } |
|
80 this.element.addClass(this.horizontal ? "h-ts" : "v-ts"); |
|
81 this.firstMin = options.leftMin || options.topMin || options.firstMin || 0; |
|
82 this.firstMax = options.leftMax || options.topMax || options.firstMax || false; |
|
83 this.secondMin = options.rightMin || options.bottomMin || options.secondMin || 0; |
|
84 this.secondMax = options.rightMax || options.bottomMax || options.secondMax || false; |
|
85 if (this.firstMax && this.secondMax) { |
|
86 console.log("Touch Splitter ERROR: cannot set max bounds of both first and second sections!"); |
|
87 this.secondMax = false; |
|
88 } |
|
89 if (options.dock != null) { |
|
90 if (/both|left|top|first|right|bottom|second/i.test(options.dock)) { |
|
91 this.docks = (function() { |
|
92 switch (false) { |
|
93 case !/both/i.test(options.dock): |
|
94 return { |
|
95 first: true, |
|
96 second: true, |
|
97 name: "both" |
|
98 }; |
|
99 case !/left|top|first/i.test(options.dock): |
|
100 return { |
|
101 first: true, |
|
102 second: false, |
|
103 name: "first" |
|
104 }; |
|
105 case !/right|bottom|second/i.test(options.dock): |
|
106 return { |
|
107 first: false, |
|
108 second: true, |
|
109 name: "second" |
|
110 }; |
|
111 } |
|
112 })(); |
|
113 } |
|
114 } |
|
115 if (this.docks) { |
|
116 this.element.addClass('docks-' + this.docks.name); |
|
117 } else { |
|
118 this.docks = { |
|
119 first: false, |
|
120 second: false, |
|
121 name: false |
|
122 }; |
|
123 } |
|
124 if (options.thickness != null) { |
|
125 thickness = options.thickness; |
|
126 units = "px"; |
|
127 if (typeof thickness === 'string') { |
|
128 if (match = thickness.match(/^([\d\.]+)([a-zA-Z]+)$/)) { |
|
129 thickness = match[1]; |
|
130 units = match[2]; |
|
131 } |
|
132 thickness = parseFloat(thickness); |
|
133 } |
|
134 if (!thickness) { |
|
135 throw "Unable to parse given thickness: " + options.thickness; |
|
136 } else { |
|
137 thickness = (function() { |
|
138 switch (units) { |
|
139 case "px": |
|
140 return barThick = thickness; |
|
141 case "em": |
|
142 return barThick *= thickness; |
|
143 default: |
|
144 throw "Invalid unit used in given thickness: " + units; |
|
145 } |
|
146 })(); |
|
147 } |
|
148 } |
|
149 firstdiv = this.element.find(">div:first"); |
|
150 splitterHTML = "<div class=\"splitter-bar\">" + (this.docks.name && this.docks.name.match(/first|second/) ? '<div></div>' : '') + "</div>"; |
|
151 if (firstdiv.length === 0) { |
|
152 inners = this.element.html(); |
|
153 this.element.html("<div></div> " + splitterHTML + " <div></div>"); |
|
154 this.element.find(">div:first").html(inners); |
|
155 } else { |
|
156 firstdiv.after(splitterHTML); |
|
157 } |
|
158 this.barThicknessPx = barThick / 2; |
|
159 this.barThickness = .04; |
|
160 this.barPosition = options.barPosition || 0.5; |
|
161 this.dragging = false; |
|
162 this.initMouse = 0; |
|
163 this.initBarPosition = 0; |
|
164 this.resize(); |
|
165 this.element.on('resize', this.onResize); |
|
166 $(window).on('resize', this.onResizeWindow); |
|
167 $(window).on('mouseup', this.stopDragging); |
|
168 $(window).on('mousemove', this.drag); |
|
169 this.element.find('>.splitter-bar').on('mousedown', this.onMouseDown); |
|
170 this.element.find('>.splitter-bar').bind('touchstart', this.onTouchStart); |
|
171 this.element.on('touchmove', this.onTouchMove); |
|
172 this.element.on('touchend', this.onTouchEnd); |
|
173 this.element.on('touchleave', this.onTouchEnd); |
|
174 this.element.on('touchcancel', this.onTouchEnd); |
|
175 } |
|
176 |
|
177 TouchSplitter.prototype.destroy = function(side) { |
|
178 var toRemove; |
|
179 this.element.off('resize'); |
|
180 $(window).off('resize'); |
|
181 $(window).off('mouseup'); |
|
182 $(window).off('mousemove'); |
|
183 this.element.find('>.splitter-bar').off('mousedown'); |
|
184 this.element.find('>.splitter-bar').off('touchstart'); |
|
185 this.element.off('touchmove'); |
|
186 this.element.off('touchend'); |
|
187 this.element.off('touchleave'); |
|
188 this.element.off('touchcancel'); |
|
189 this.element.find('>.splitter-bar').remove(); |
|
190 this.element.removeClass('TouchSplitter h-ts v-ts docks-first docks-second docks-both'); |
|
191 if (side != null) { |
|
192 toRemove = (function() { |
|
193 switch (side) { |
|
194 case 'left': |
|
195 case 'top': |
|
196 return '>div:first'; |
|
197 case 'right': |
|
198 case 'bottom': |
|
199 return '>div:last'; |
|
200 case 'both': |
|
201 return '>div'; |
|
202 } |
|
203 })(); |
|
204 this.element.find(toRemove).remove(); |
|
205 } |
|
206 this.element.children().css({ |
|
207 width: "", |
|
208 height: "" |
|
209 }); |
|
210 return delete this.element[0].touchSplitter; |
|
211 }; |
|
212 |
|
213 TouchSplitter.prototype.setRatios = function() { |
|
214 var conv, ref, val; |
|
215 this.splitDistance = this.horizontal ? this.element.width() : this.element.height(); |
|
216 ref = { |
|
217 firstMin: this.firstMin, |
|
218 firstMax: this.firstMax, |
|
219 secondMin: this.secondMin, |
|
220 secondMax: this.secondMax |
|
221 }; |
|
222 for (conv in ref) { |
|
223 val = ref[conv]; |
|
224 if (val) { |
|
225 this[conv + 'Ratio'] = val / this.splitDistance; |
|
226 } |
|
227 } |
|
228 return this.moveBar(); |
|
229 }; |
|
230 |
|
231 TouchSplitter.prototype.toggleDock = function() { |
|
232 this.element.toggleClass('docked'); |
|
233 if (this.docked) { |
|
234 return this.setDock(false); |
|
235 } else { |
|
236 return this.setDock(this.docks.name); |
|
237 } |
|
238 }; |
|
239 |
|
240 TouchSplitter.prototype.on = function(eventName, fn) { |
|
241 return this.element.on(eventName, fn); |
|
242 }; |
|
243 |
|
244 TouchSplitter.prototype.moveBar = function(newX) { |
|
245 var cursorPos, cursorPos2; |
|
246 cursorPos = this.barPosition; |
|
247 if (newX != null) { |
|
248 cursorPos = this.initBarPosition + (newX - this.initMouse) / this.splitDistance; |
|
249 } |
|
250 cursorPos2 = 1 - cursorPos; |
|
251 if (this.docks.name) { |
|
252 switch (this.docked) { |
|
253 case 'first': |
|
254 if (cursorPos > this.firstMinRatio / 2) { |
|
255 this.setDock(false); |
|
256 } |
|
257 break; |
|
258 case 'second': |
|
259 if (cursorPos2 > this.secondMinRatio / 2) { |
|
260 this.setDock(false); |
|
261 } |
|
262 break; |
|
263 default: |
|
264 if (this.docks.first && cursorPos < this.firstMinRatio / 2) { |
|
265 this.setDock('first'); |
|
266 } |
|
267 if (this.docks.second && cursorPos2 < this.secondMinRatio / 2) { |
|
268 this.setDock('second'); |
|
269 } |
|
270 } |
|
271 } |
|
272 if (!this.docked) { |
|
273 this.barPosition = (function() { |
|
274 switch (false) { |
|
275 case !(this.firstMaxRatio && cursorPos > this.firstMaxRatio): |
|
276 return this.firstMaxRatio; |
|
277 case !(cursorPos < this.firstMinRatio): |
|
278 return this.firstMinRatio; |
|
279 case !(this.secondMaxRatio && cursorPos2 > this.secondMaxRatio): |
|
280 return 1 - this.secondMaxRatio; |
|
281 case !(cursorPos2 < this.secondMinRatio): |
|
282 return 1 - this.secondMinRatio; |
|
283 default: |
|
284 return cursorPos; |
|
285 } |
|
286 }).call(this); |
|
287 return this.setPercentages(); |
|
288 } |
|
289 }; |
|
290 |
|
291 TouchSplitter.prototype.setDock = function(val, lastpos) { |
|
292 if (lastpos == null) { |
|
293 lastpos = this.barPosition; |
|
294 } |
|
295 this.docked = val; |
|
296 this.barPosition = this.lastPosition; |
|
297 this.lastPosition = lastpos; |
|
298 return this.setPercentages(); |
|
299 }; |
|
300 |
|
301 TouchSplitter.prototype.setPercentages = function() { |
|
302 var attr, first, firstCss, pos, second, secondCss, shave; |
|
303 switch (this.docked) { |
|
304 case 'first': |
|
305 this.barPosition = 0; |
|
306 break; |
|
307 case 'second': |
|
308 this.barPosition = 1; |
|
309 } |
|
310 pos = this.barPosition; |
|
311 firstCss = secondCss = ""; |
|
312 if (!this.support.calc) { |
|
313 if (pos < this.barThickness) { |
|
314 pos = this.barThickness; |
|
315 } |
|
316 if (pos > 1 - this.barThickness) { |
|
317 pos = 1 - this.barThickness; |
|
318 } |
|
319 first = pos - this.barThickness; |
|
320 second = 1 - pos - this.barThickness; |
|
321 firstCss = (100 * first - this.barThickness) + "%"; |
|
322 secondCss = (100 * second - this.barThickness) + "%"; |
|
323 } else { |
|
324 shave = this.barThicknessPx; |
|
325 if (this.docked) { |
|
326 shave *= 2; |
|
327 } |
|
328 pos *= 100; |
|
329 firstCss = "calc(" + pos + "% - " + shave + "px)"; |
|
330 secondCss = "calc(" + (100 - pos) + "% - " + shave + "px)"; |
|
331 } |
|
332 attr = this.horizontal ? "width" : "height"; |
|
333 this.getFirst().css(attr, firstCss); |
|
334 return this.getSecond().css(attr, secondCss); |
|
335 }; |
|
336 |
|
337 TouchSplitter.prototype.onMouseDown = function(event) { |
|
338 event.preventDefault(); |
|
339 this.initMouse = this.horizontal ? event.clientX : event.clientY; |
|
340 return this.startDragging(event); |
|
341 }; |
|
342 |
|
343 TouchSplitter.prototype.onTouchStart = function(event) { |
|
344 var orig; |
|
345 orig = event.originalEvent; |
|
346 this.initMouse = this.horizontal ? orig.changedTouches[0].pageX : orig.changedTouches[0].pageY; |
|
347 return this.startDragging(event); |
|
348 }; |
|
349 |
|
350 TouchSplitter.prototype.onTouchMove = function(event) { |
|
351 var orig, page; |
|
352 if (!this.dragging) { |
|
353 return; |
|
354 } |
|
355 event.preventDefault(); |
|
356 orig = event.originalEvent; |
|
357 page = this.horizontal ? orig.changedTouches[0].pageX : orig.changedTouches[0].pageY; |
|
358 return this.moveBar(page); |
|
359 }; |
|
360 |
|
361 TouchSplitter.prototype.onTouchEnd = function(event) { |
|
362 return this.stopDragging(event); |
|
363 }; |
|
364 |
|
365 TouchSplitter.prototype.startDragging = function(event) { |
|
366 this.initBarPosition = this.barPosition; |
|
367 this.isToggler = !!event.target.parentNode.className.match(/\bsplitter-bar\b/); |
|
368 this.dragging = true; |
|
369 return this.element.trigger("dragstart"); |
|
370 }; |
|
371 |
|
372 TouchSplitter.prototype.drag = function(event) { |
|
373 var client, whichM; |
|
374 if (!this.dragging) { |
|
375 return; |
|
376 } |
|
377 whichM = typeof event.buttons !== 'undefined' ? event.buttons : event.which; |
|
378 if (whichM === 0) { |
|
379 this.stopDragging(); |
|
380 } |
|
381 client = this.horizontal ? event.clientX : event.clientY; |
|
382 return this.moveBar(client); |
|
383 }; |
|
384 |
|
385 TouchSplitter.prototype.stopDragging = function(event) { |
|
386 if (this.dragging) { |
|
387 this.dragging = false; |
|
388 this.element.trigger("dragstop"); |
|
389 if (this.isToggler) { |
|
390 return setTimeout((function(_this) { |
|
391 return function() { |
|
392 if ((_this.barPosition - _this.initBarPosition) === 0) { |
|
393 return _this.toggleDock(); |
|
394 } |
|
395 }; |
|
396 })(this), 0); |
|
397 } |
|
398 } |
|
399 }; |
|
400 |
|
401 TouchSplitter.prototype.getFirst = function() { |
|
402 return this.element.find('>div:first'); |
|
403 }; |
|
404 |
|
405 TouchSplitter.prototype.getSecond = function() { |
|
406 return this.element.find('>div:last'); |
|
407 }; |
|
408 |
|
409 TouchSplitter.prototype.onResizeWindow = function(event) { |
|
410 return this.resize(); |
|
411 }; |
|
412 |
|
413 TouchSplitter.prototype.onResize = function(event) { |
|
414 if (event != null) { |
|
415 event.stopPropagation(); |
|
416 if (!$(event.target).is(this.element)) { |
|
417 return; |
|
418 } |
|
419 } |
|
420 return this.resize(); |
|
421 }; |
|
422 |
|
423 TouchSplitter.prototype.resize = function() { |
|
424 var attr; |
|
425 this.setRatios(); |
|
426 attr = this.horizontal ? "width" : "height"; |
|
427 if (!this.support.calc) { |
|
428 this.barThickness = this.barThicknessPx / this.splitDistance; |
|
429 if (this.barThickness > 1) { |
|
430 this.barThickness = 1; |
|
431 } |
|
432 this.element.find('>.splitter-bar').css(attr, this.barThickness * 200 + '%'); |
|
433 } else { |
|
434 this.barThickness = 0; |
|
435 } |
|
436 return this.setPercentages(); |
|
437 }; |
|
438 |
|
439 return TouchSplitter; |
|
440 |
|
441 })(); |
|
442 }); |
|
443 |
|
444 }).call(this); |
|