]>
Commit | Line | Data |
---|---|---|
e3c38d61 CP |
1 | //MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License. |
2 | ||
3 | /* | |
4 | --- | |
5 | ||
6 | script: More.js | |
7 | ||
8 | name: More | |
9 | ||
10 | description: MooTools More | |
11 | ||
12 | license: MIT-style license | |
13 | ||
14 | requires: | |
15 | - Core/MooTools | |
16 | ||
17 | provides: [MooTools.More] | |
18 | ||
19 | ... | |
20 | */ | |
21 | ||
22 | MooTools.More = { | |
23 | 'version': '1.2.5.1', | |
24 | 'build': '254884f2b83651bf95260eed5c6cceb838e22d8e' | |
25 | }; | |
26 | ||
27 | ||
28 | /* | |
29 | --- | |
30 | ||
31 | script: Class.Binds.js | |
32 | ||
33 | name: Class.Binds | |
34 | ||
35 | description: Automagically binds specified methods in a class to the instance of the class. | |
36 | ||
37 | license: MIT-style license | |
38 | ||
39 | authors: | |
40 | - Aaron Newton | |
41 | ||
42 | requires: | |
43 | - Core/Class | |
44 | - /MooTools.More | |
45 | ||
46 | provides: [Class.Binds] | |
47 | ||
48 | ... | |
49 | */ | |
50 | ||
51 | Class.Mutators.Binds = function(binds){ | |
52 | return binds; | |
53 | }; | |
54 | ||
55 | Class.Mutators.initialize = function(initialize){ | |
56 | return function(){ | |
57 | $splat(this.Binds).each(function(name){ | |
58 | var original = this[name]; | |
59 | if (original) this[name] = original.bind(this); | |
60 | }, this); | |
61 | return initialize.apply(this, arguments); | |
62 | }; | |
63 | }; | |
64 | ||
65 | ||
66 | /* | |
67 | --- | |
68 | ||
69 | script: Element.Measure.js | |
70 | ||
71 | name: Element.Measure | |
72 | ||
73 | description: Extends the Element native object to include methods useful in measuring dimensions. | |
74 | ||
75 | credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" | |
76 | ||
77 | license: MIT-style license | |
78 | ||
79 | authors: | |
80 | - Aaron Newton | |
81 | ||
82 | requires: | |
83 | - Core/Element.Style | |
84 | - Core/Element.Dimensions | |
85 | - /MooTools.More | |
86 | ||
87 | provides: [Element.Measure] | |
88 | ||
89 | ... | |
90 | */ | |
91 | ||
92 | Element.implement({ | |
93 | ||
94 | measure: function(fn){ | |
95 | var vis = function(el) { | |
96 | return !!(!el || el.offsetHeight || el.offsetWidth); | |
97 | }; | |
98 | if (vis(this)) return fn.apply(this); | |
99 | var parent = this.getParent(), | |
100 | restorers = [], | |
101 | toMeasure = []; | |
102 | while (!vis(parent) && parent != document.body) { | |
103 | toMeasure.push(parent.expose()); | |
104 | parent = parent.getParent(); | |
105 | } | |
106 | var restore = this.expose(); | |
107 | var result = fn.apply(this); | |
108 | restore(); | |
109 | toMeasure.each(function(restore){ | |
110 | restore(); | |
111 | }); | |
112 | return result; | |
113 | }, | |
114 | ||
115 | expose: function(){ | |
116 | if (this.getStyle('display') != 'none') return $empty; | |
117 | var before = this.style.cssText; | |
118 | this.setStyles({ | |
119 | display: 'block', | |
120 | position: 'absolute', | |
121 | visibility: 'hidden' | |
122 | }); | |
123 | return function(){ | |
124 | this.style.cssText = before; | |
125 | }.bind(this); | |
126 | }, | |
127 | ||
128 | getDimensions: function(options){ | |
129 | options = $merge({computeSize: false},options); | |
130 | var dim = {}; | |
131 | var getSize = function(el, options){ | |
132 | return (options.computeSize)?el.getComputedSize(options):el.getSize(); | |
133 | }; | |
134 | var parent = this.getParent('body'); | |
135 | if (parent && this.getStyle('display') == 'none'){ | |
136 | dim = this.measure(function(){ | |
137 | return getSize(this, options); | |
138 | }); | |
139 | } else if (parent){ | |
140 | try { //safari sometimes crashes here, so catch it | |
141 | dim = getSize(this, options); | |
142 | }catch(e){} | |
143 | } else { | |
144 | dim = {x: 0, y: 0}; | |
145 | } | |
146 | return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height}); | |
147 | }, | |
148 | ||
149 | getComputedSize: function(options){ | |
150 | //legacy support for my stupid spelling error | |
151 | if (options && options.plains) options.planes = options.plains; | |
152 | ||
153 | options = $merge({ | |
154 | styles: ['padding','border'], | |
155 | planes: { | |
156 | height: ['top','bottom'], | |
157 | width: ['left','right'] | |
158 | }, | |
159 | mode: 'both' | |
160 | }, options); | |
161 | ||
162 | var size = {width: 0,height: 0}; | |
163 | switch (options.mode){ | |
164 | case 'vertical': | |
165 | delete size.width; | |
166 | delete options.planes.width; | |
167 | break; | |
168 | case 'horizontal': | |
169 | delete size.height; | |
170 | delete options.planes.height; | |
171 | break; | |
172 | } | |
173 | var getStyles = []; | |
174 | //this function might be useful in other places; perhaps it should be outside this function? | |
175 | $each(options.planes, function(plane, key){ | |
176 | plane.each(function(edge){ | |
177 | options.styles.each(function(style){ | |
178 | getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge); | |
179 | }); | |
180 | }); | |
181 | }); | |
182 | var styles = {}; | |
183 | getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this); | |
184 | var subtracted = []; | |
185 | $each(options.planes, function(plane, key){ //keys: width, height, planes: ['left', 'right'], ['top','bottom'] | |
186 | var capitalized = key.capitalize(); | |
187 | size['total' + capitalized] = size['computed' + capitalized] = 0; | |
188 | plane.each(function(edge){ //top, left, right, bottom | |
189 | size['computed' + edge.capitalize()] = 0; | |
190 | getStyles.each(function(style, i){ //padding, border, etc. | |
191 | //'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left] | |
192 | if (style.test(edge)){ | |
193 | styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5; | |
194 | size['total' + capitalized] = size['total' + capitalized] + styles[style]; | |
195 | size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style]; | |
196 | } | |
197 | //if width != width (so, padding-left, for instance), then subtract that from the total | |
198 | if (style.test(edge) && key != style && | |
199 | (style.test('border') || style.test('padding')) && !subtracted.contains(style)){ | |
200 | subtracted.push(style); | |
201 | size['computed' + capitalized] = size['computed' + capitalized]-styles[style]; | |
202 | } | |
203 | }); | |
204 | }); | |
205 | }); | |
206 | ||
207 | ['Width', 'Height'].each(function(value){ | |
208 | var lower = value.toLowerCase(); | |
209 | if(!$chk(size[lower])) return; | |
210 | ||
211 | size[lower] = size[lower] + this['offset' + value] + size['computed' + value]; | |
212 | size['total' + value] = size[lower] + size['total' + value]; | |
213 | delete size['computed' + value]; | |
214 | }, this); | |
215 | ||
216 | return $extend(styles, size); | |
217 | } | |
218 | ||
219 | }); | |
220 | ||
221 | /* | |
222 | --- | |
223 | ||
224 | script: Drag.js | |
225 | ||
226 | name: Drag | |
227 | ||
228 | description: The base Drag Class. Can be used to drag and resize Elements using mouse events. | |
229 | ||
230 | license: MIT-style license | |
231 | ||
232 | authors: | |
233 | - Valerio Proietti | |
234 | - Tom Occhinno | |
235 | - Jan Kassens | |
236 | ||
237 | requires: | |
238 | - Core/Events | |
239 | - Core/Options | |
240 | - Core/Element.Event | |
241 | - Core/Element.Style | |
242 | - Core/Element.Dimensions | |
243 | - /MooTools.More | |
244 | ||
245 | provides: [Drag] | |
246 | ... | |
247 | ||
248 | */ | |
249 | ||
250 | var Drag = new Class({ | |
251 | ||
252 | Implements: [Events, Options], | |
253 | ||
254 | options: {/* | |
255 | onBeforeStart: $empty(thisElement), | |
256 | onStart: $empty(thisElement, event), | |
257 | onSnap: $empty(thisElement) | |
258 | onDrag: $empty(thisElement, event), | |
259 | onCancel: $empty(thisElement), | |
260 | onComplete: $empty(thisElement, event),*/ | |
261 | snap: 6, | |
262 | unit: 'px', | |
263 | grid: false, | |
264 | style: true, | |
265 | limit: false, | |
266 | handle: false, | |
267 | invert: false, | |
268 | preventDefault: false, | |
269 | stopPropagation: false, | |
270 | modifiers: {x: 'left', y: 'top'} | |
271 | }, | |
272 | ||
273 | initialize: function(){ | |
274 | var params = Array.link(arguments, {'options': Object.type, 'element': $defined}); | |
275 | this.element = document.id(params.element); | |
276 | this.document = this.element.getDocument(); | |
277 | this.setOptions(params.options || {}); | |
278 | var htype = $type(this.options.handle); | |
279 | this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element; | |
280 | this.mouse = {'now': {}, 'pos': {}}; | |
281 | this.value = {'start': {}, 'now': {}}; | |
282 | ||
283 | this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown'; | |
284 | ||
285 | this.bound = { | |
286 | start: this.start.bind(this), | |
287 | check: this.check.bind(this), | |
288 | drag: this.drag.bind(this), | |
289 | stop: this.stop.bind(this), | |
290 | cancel: this.cancel.bind(this), | |
291 | eventStop: $lambda(false) | |
292 | }; | |
293 | this.attach(); | |
294 | }, | |
295 | ||
296 | attach: function(){ | |
297 | this.handles.addEvent('mousedown', this.bound.start); | |
298 | return this; | |
299 | }, | |
300 | ||
301 | detach: function(){ | |
302 | this.handles.removeEvent('mousedown', this.bound.start); | |
303 | return this; | |
304 | }, | |
305 | ||
306 | start: function(event){ | |
307 | if (event.rightClick) return; | |
308 | if (this.options.preventDefault) event.preventDefault(); | |
309 | if (this.options.stopPropagation) event.stopPropagation(); | |
310 | this.mouse.start = event.page; | |
311 | this.fireEvent('beforeStart', this.element); | |
312 | var limit = this.options.limit; | |
313 | this.limit = {x: [], y: []}; | |
314 | var styles = this.element.getStyles('left', 'right', 'top', 'bottom'); | |
315 | this._invert = { | |
316 | x: this.options.modifiers.x == 'left' && styles.left == 'auto' && | |
317 | !isNaN(styles.right.toInt()) && (this.options.modifiers.x = 'right'), | |
318 | y: this.options.modifiers.y == 'top' && styles.top == 'auto' && | |
319 | !isNaN(styles.bottom.toInt()) && (this.options.modifiers.y = 'bottom') | |
320 | }; | |
321 | ||
322 | var z, coordinates; | |
323 | for (z in this.options.modifiers){ | |
324 | if (!this.options.modifiers[z]) continue; | |
325 | ||
326 | var style = this.element.getStyle(this.options.modifiers[z]); | |
327 | ||
328 | // Some browsers (IE and Opera) don't always return pixels. | |
329 | if (style && !style.match(/px$/)){ | |
330 | if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent()); | |
331 | style = coordinates[this.options.modifiers[z]]; | |
332 | } | |
333 | ||
334 | if (this.options.style) this.value.now[z] = (style || 0).toInt(); | |
335 | else this.value.now[z] = this.element[this.options.modifiers[z]]; | |
336 | ||
337 | if (this.options.invert) this.value.now[z] *= -1; | |
338 | if (this._invert[z]) this.value.now[z] *= -1; | |
339 | ||
340 | this.mouse.pos[z] = event.page[z] - this.value.now[z]; | |
341 | ||
342 | if (limit && limit[z]){ | |
343 | for (var i = 2; i--; i){ | |
344 | if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])(); | |
345 | } | |
346 | } | |
347 | } | |
348 | ||
349 | if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid}; | |
350 | this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel}); | |
351 | this.document.addEvent(this.selection, this.bound.eventStop); | |
352 | }, | |
353 | ||
354 | check: function(event){ | |
355 | if (this.options.preventDefault) event.preventDefault(); | |
356 | var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); | |
357 | if (distance > this.options.snap){ | |
358 | this.cancel(); | |
359 | this.document.addEvents({ | |
360 | mousemove: this.bound.drag, | |
361 | mouseup: this.bound.stop | |
362 | }); | |
363 | this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element); | |
364 | } | |
365 | }, | |
366 | ||
367 | drag: function(event){ | |
368 | if (this.options.preventDefault) event.preventDefault(); | |
369 | this.mouse.now = event.page; | |
370 | for (var z in this.options.modifiers){ | |
371 | if (!this.options.modifiers[z]) continue; | |
372 | this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; | |
373 | if (this.options.invert) this.value.now[z] *= -1; | |
374 | if (this._invert[z]) this.value.now[z] *= -1; | |
375 | if (this.options.limit && this.limit[z]){ | |
376 | if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ | |
377 | this.value.now[z] = this.limit[z][1]; | |
378 | } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ | |
379 | this.value.now[z] = this.limit[z][0]; | |
380 | } | |
381 | } | |
382 | if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]); | |
383 | if (this.options.style) { | |
384 | this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); | |
385 | } else { | |
386 | this.element[this.options.modifiers[z]] = this.value.now[z]; | |
387 | } | |
388 | } | |
389 | this.fireEvent('drag', [this.element, event]); | |
390 | }, | |
391 | ||
392 | cancel: function(event){ | |
393 | this.document.removeEvent('mousemove', this.bound.check); | |
394 | this.document.removeEvent('mouseup', this.bound.cancel); | |
395 | if (event){ | |
396 | this.document.removeEvent(this.selection, this.bound.eventStop); | |
397 | this.fireEvent('cancel', this.element); | |
398 | } | |
399 | }, | |
400 | ||
401 | stop: function(event){ | |
402 | this.document.removeEvent(this.selection, this.bound.eventStop); | |
403 | this.document.removeEvent('mousemove', this.bound.drag); | |
404 | this.document.removeEvent('mouseup', this.bound.stop); | |
405 | if (event) this.fireEvent('complete', [this.element, event]); | |
406 | } | |
407 | ||
408 | }); | |
409 | ||
410 | Element.implement({ | |
411 | ||
412 | makeResizable: function(options){ | |
413 | var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options)); | |
414 | this.store('resizer', drag); | |
415 | return drag.addEvent('drag', function(){ | |
416 | this.fireEvent('resize', drag); | |
417 | }.bind(this)); | |
418 | } | |
419 | ||
420 | }); | |
421 | ||
422 | ||
423 | /* | |
424 | --- | |
425 | ||
426 | script: Slider.js | |
427 | ||
428 | name: Slider | |
429 | ||
430 | description: Class for creating horizontal and vertical slider controls. | |
431 | ||
432 | license: MIT-style license | |
433 | ||
434 | authors: | |
435 | - Valerio Proietti | |
436 | ||
437 | requires: | |
438 | - Core/Element.Dimensions | |
439 | - /Class.Binds | |
440 | - /Drag | |
441 | - /Element.Measure | |
442 | ||
443 | provides: [Slider] | |
444 | ||
445 | ... | |
446 | */ | |
447 | ||
448 | var Slider = new Class({ | |
449 | ||
450 | Implements: [Events, Options], | |
451 | ||
452 | Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'], | |
453 | ||
454 | options: {/* | |
455 | onTick: $empty(intPosition), | |
456 | onChange: $empty(intStep), | |
457 | onComplete: $empty(strStep),*/ | |
458 | onTick: function(position){ | |
459 | if (this.options.snap) position = this.toPosition(this.step); | |
460 | this.knob.setStyle(this.property, position); | |
461 | }, | |
462 | initialStep: 0, | |
463 | snap: false, | |
464 | offset: 0, | |
465 | range: false, | |
466 | wheel: false, | |
467 | steps: 100, | |
468 | mode: 'horizontal' | |
469 | }, | |
470 | ||
471 | initialize: function(element, knob, options){ | |
472 | this.setOptions(options); | |
473 | this.element = document.id(element); | |
474 | this.knob = document.id(knob); | |
475 | this.previousChange = this.previousEnd = this.step = -1; | |
476 | var offset, limit = {}, modifiers = {'x': false, 'y': false}; | |
477 | switch (this.options.mode){ | |
478 | case 'vertical': | |
479 | this.axis = 'y'; | |
480 | this.property = 'top'; | |
481 | offset = 'offsetHeight'; | |
482 | break; | |
483 | case 'horizontal': | |
484 | this.axis = 'x'; | |
485 | this.property = 'left'; | |
486 | offset = 'offsetWidth'; | |
487 | } | |
488 | ||
489 | this.full = this.element.measure(function(){ | |
490 | this.half = this.knob[offset] / 2; | |
491 | return this.element[offset] - this.knob[offset] + (this.options.offset * 2); | |
492 | }.bind(this)); | |
493 | ||
494 | this.setRange(this.options.range); | |
495 | ||
496 | this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset); | |
497 | modifiers[this.axis] = this.property; | |
498 | limit[this.axis] = [- this.options.offset, this.full - this.options.offset]; | |
499 | ||
500 | var dragOptions = { | |
501 | snap: 0, | |
502 | limit: limit, | |
503 | modifiers: modifiers, | |
504 | onDrag: this.draggedKnob, | |
505 | onStart: this.draggedKnob, | |
506 | onBeforeStart: (function(){ | |
507 | this.isDragging = true; | |
508 | }).bind(this), | |
509 | onCancel: function() { | |
510 | this.isDragging = false; | |
511 | }.bind(this), | |
512 | onComplete: function(){ | |
513 | this.isDragging = false; | |
514 | this.draggedKnob(); | |
515 | this.end(); | |
516 | }.bind(this) | |
517 | }; | |
518 | if (this.options.snap){ | |
519 | dragOptions.grid = Math.ceil(this.stepWidth); | |
520 | dragOptions.limit[this.axis][1] = this.full; | |
521 | } | |
522 | ||
523 | this.drag = new Drag(this.knob, dragOptions); | |
524 | this.attach(); | |
525 | if (this.options.initialStep != null) this.set(this.options.initialStep) | |
526 | }, | |
527 | ||
528 | attach: function(){ | |
529 | this.element.addEvent('mousedown', this.clickedElement); | |
530 | if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement); | |
531 | this.drag.attach(); | |
532 | return this; | |
533 | }, | |
534 | ||
535 | detach: function(){ | |
536 | this.element.removeEvent('mousedown', this.clickedElement); | |
537 | this.element.removeEvent('mousewheel', this.scrolledElement); | |
538 | this.drag.detach(); | |
539 | return this; | |
540 | }, | |
541 | ||
542 | set: function(step){ | |
543 | if (!((this.range > 0) ^ (step < this.min))) step = this.min; | |
544 | if (!((this.range > 0) ^ (step > this.max))) step = this.max; | |
545 | ||
546 | this.step = Math.round(step); | |
547 | this.checkStep(); | |
548 | this.fireEvent('tick', this.toPosition(this.step)); | |
549 | this.end(); | |
550 | return this; | |
551 | }, | |
552 | ||
553 | setRange: function(range, pos){ | |
554 | this.min = $pick(range[0], 0); | |
555 | this.max = $pick(range[1], this.options.steps); | |
556 | this.range = this.max - this.min; | |
557 | this.steps = this.options.steps || this.full; | |
558 | this.stepSize = Math.abs(this.range) / this.steps; | |
559 | this.stepWidth = this.stepSize * this.full / Math.abs(this.range); | |
560 | this.set($pick(pos, this.step).floor(this.min).max(this.max)); | |
561 | return this; | |
562 | }, | |
563 | ||
564 | clickedElement: function(event){ | |
565 | if (this.isDragging || event.target == this.knob) return; | |
566 | ||
567 | var dir = this.range < 0 ? -1 : 1; | |
568 | var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half; | |
569 | position = position.limit(-this.options.offset, this.full -this.options.offset); | |
570 | ||
571 | this.step = Math.round(this.min + dir * this.toStep(position)); | |
572 | this.checkStep(); | |
573 | this.fireEvent('tick', position); | |
574 | this.end(); | |
575 | }, | |
576 | ||
577 | scrolledElement: function(event){ | |
578 | var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0); | |
579 | this.set(mode ? this.step - this.stepSize : this.step + this.stepSize); | |
580 | event.stop(); | |
581 | }, | |
582 | ||
583 | draggedKnob: function(){ | |
584 | var dir = this.range < 0 ? -1 : 1; | |
585 | var position = this.drag.value.now[this.axis]; | |
586 | position = position.limit(-this.options.offset, this.full -this.options.offset); | |
587 | this.step = Math.round(this.min + dir * this.toStep(position)); | |
588 | this.checkStep(); | |
589 | }, | |
590 | ||
591 | checkStep: function(){ | |
592 | if (this.previousChange != this.step){ | |
593 | this.previousChange = this.step; | |
594 | this.fireEvent('change', this.step); | |
595 | } | |
596 | }, | |
597 | ||
598 | end: function(){ | |
599 | if (this.previousEnd !== this.step){ | |
600 | this.previousEnd = this.step; | |
601 | this.fireEvent('complete', this.step + ''); | |
602 | } | |
603 | }, | |
604 | ||
605 | toStep: function(position){ | |
606 | var step = (position + this.options.offset) * this.stepSize / this.full * this.steps; | |
607 | return this.options.steps ? Math.round(step -= step % this.stepSize) : step; | |
608 | }, | |
609 | ||
610 | toPosition: function(step){ | |
611 | return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset; | |
612 | } | |
613 | ||
614 | }); | |
615 | ||
616 | ||
617 | /* | |
618 | --- | |
619 | ||
620 | script: Color.js | |
621 | ||
622 | name: Color | |
623 | ||
624 | description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa. | |
625 | ||
626 | license: MIT-style license | |
627 | ||
628 | authors: | |
629 | - Valerio Proietti | |
630 | ||
631 | requires: | |
632 | - Core/Array | |
633 | - Core/String | |
634 | - Core/Number | |
635 | - Core/Hash | |
636 | - Core/Function | |
637 | - Core/$util | |
638 | ||
639 | provides: [Color] | |
640 | ||
641 | ... | |
642 | */ | |
643 | ||
644 | var Color = new Native({ | |
645 | ||
646 | initialize: function(color, type){ | |
647 | if (arguments.length >= 3){ | |
648 | type = 'rgb'; color = Array.slice(arguments, 0, 3); | |
649 | } else if (typeof color == 'string'){ | |
650 | if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true); | |
651 | else if (color.match(/hsb/)) color = color.hsbToRgb(); | |
652 | else color = color.hexToRgb(true); | |
653 | } | |
654 | type = type || 'rgb'; | |
655 | switch (type){ | |
656 | case 'hsb': | |
657 | var old = color; | |
658 | color = color.hsbToRgb(); | |
659 | color.hsb = old; | |
660 | break; | |
661 | case 'hex': color = color.hexToRgb(true); break; | |
662 | } | |
663 | color.rgb = color.slice(0, 3); | |
664 | color.hsb = color.hsb || color.rgbToHsb(); | |
665 | color.hex = color.rgbToHex(); | |
666 | return $extend(color, this); | |
667 | } | |
668 | ||
669 | }); | |
670 | ||
671 | Color.implement({ | |
672 | ||
673 | mix: function(){ | |
674 | var colors = Array.slice(arguments); | |
675 | var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50; | |
676 | var rgb = this.slice(); | |
677 | colors.each(function(color){ | |
678 | color = new Color(color); | |
679 | for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha)); | |
680 | }); | |
681 | return new Color(rgb, 'rgb'); | |
682 | }, | |
683 | ||
684 | invert: function(){ | |
685 | return new Color(this.map(function(value){ | |
686 | return 255 - value; | |
687 | })); | |
688 | }, | |
689 | ||
690 | setHue: function(value){ | |
691 | return new Color([value, this.hsb[1], this.hsb[2]], 'hsb'); | |
692 | }, | |
693 | ||
694 | setSaturation: function(percent){ | |
695 | return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb'); | |
696 | }, | |
697 | ||
698 | setBrightness: function(percent){ | |
699 | return new Color([this.hsb[0], this.hsb[1], percent], 'hsb'); | |
700 | } | |
701 | ||
702 | }); | |
703 | ||
704 | var $RGB = function(r, g, b){ | |
705 | return new Color([r, g, b], 'rgb'); | |
706 | }; | |
707 | ||
708 | var $HSB = function(h, s, b){ | |
709 | return new Color([h, s, b], 'hsb'); | |
710 | }; | |
711 | ||
712 | var $HEX = function(hex){ | |
713 | return new Color(hex, 'hex'); | |
714 | }; | |
715 | ||
716 | Array.implement({ | |
717 | ||
718 | rgbToHsb: function(){ | |
719 | var red = this[0], | |
720 | green = this[1], | |
721 | blue = this[2], | |
722 | hue = 0; | |
723 | var max = Math.max(red, green, blue), | |
724 | min = Math.min(red, green, blue); | |
725 | var delta = max - min; | |
726 | var brightness = max / 255, | |
727 | saturation = (max != 0) ? delta / max : 0; | |
728 | if(saturation != 0) { | |
729 | var rr = (max - red) / delta; | |
730 | var gr = (max - green) / delta; | |
731 | var br = (max - blue) / delta; | |
732 | if (red == max) hue = br - gr; | |
733 | else if (green == max) hue = 2 + rr - br; | |
734 | else hue = 4 + gr - rr; | |
735 | hue /= 6; | |
736 | if (hue < 0) hue++; | |
737 | } | |
738 | return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)]; | |
739 | }, | |
740 | ||
741 | hsbToRgb: function(){ | |
742 | var br = Math.round(this[2] / 100 * 255); | |
743 | if (this[1] == 0){ | |
744 | return [br, br, br]; | |
745 | } else { | |
746 | var hue = this[0] % 360; | |
747 | var f = hue % 60; | |
748 | var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255); | |
749 | var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255); | |
750 | var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255); | |
751 | switch (Math.floor(hue / 60)){ | |
752 | case 0: return [br, t, p]; | |
753 | case 1: return [q, br, p]; | |
754 | case 2: return [p, br, t]; | |
755 | case 3: return [p, q, br]; | |
756 | case 4: return [t, p, br]; | |
757 | case 5: return [br, p, q]; | |
758 | } | |
759 | } | |
760 | return false; | |
761 | } | |
762 | ||
763 | }); | |
764 | ||
765 | String.implement({ | |
766 | ||
767 | rgbToHsb: function(){ | |
768 | var rgb = this.match(/\d{1,3}/g); | |
769 | return (rgb) ? rgb.rgbToHsb() : null; | |
770 | }, | |
771 | ||
772 | hsbToRgb: function(){ | |
773 | var hsb = this.match(/\d{1,3}/g); | |
774 | return (hsb) ? hsb.hsbToRgb() : null; | |
775 | } | |
776 | ||
777 | }); | |
778 | ||
779 | ||
780 | /* | |
781 | --- | |
782 | ||
783 | script: Hash.Cookie.js | |
784 | ||
785 | name: Hash.Cookie | |
786 | ||
787 | description: Class for creating, reading, and deleting Cookies in JSON format. | |
788 | ||
789 | license: MIT-style license | |
790 | ||
791 | authors: | |
792 | - Valerio Proietti | |
793 | - Aaron Newton | |
794 | ||
795 | requires: | |
796 | - Core/Cookie | |
797 | - Core/JSON | |
798 | - /MooTools.More | |
799 | ||
800 | provides: [Hash.Cookie] | |
801 | ||
802 | ... | |
803 | */ | |
804 | ||
805 | Hash.Cookie = new Class({ | |
806 | ||
807 | Extends: Cookie, | |
808 | ||
809 | options: { | |
810 | autoSave: true | |
811 | }, | |
812 | ||
813 | initialize: function(name, options){ | |
814 | this.parent(name, options); | |
815 | this.load(); | |
816 | }, | |
817 | ||
818 | save: function(){ | |
819 | var value = JSON.encode(this.hash); | |
820 | if (!value || value.length > 4096) return false; //cookie would be truncated! | |
821 | if (value == '{}') this.dispose(); | |
822 | else this.write(value); | |
823 | return true; | |
824 | }, | |
825 | ||
826 | load: function(){ | |
827 | this.hash = new Hash(JSON.decode(this.read(), true)); | |
828 | return this; | |
829 | } | |
830 | ||
831 | }); | |
832 | ||
833 | Hash.each(Hash.prototype, function(method, name){ | |
834 | if (typeof method == 'function') Hash.Cookie.implement(name, function(){ | |
835 | var value = method.apply(this.hash, arguments); | |
836 | if (this.options.autoSave) this.save(); | |
837 | return value; | |
838 | }); | |
839 | }); |