25 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris…
26 |
27 |
28 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/addons/helpers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * S2.viewportOverlay() -> element
3 | *
4 | * Creates a new absolutely positioned DIV element with the dimensions of the viewport.
5 | * The element is not inserted into the DOM.
6 | *
7 | * This can be used for a quick overlay like this:
8 | *
9 | * $(document.body).insert(S2.viewportOverlay().setStyle('background:#000;opacity:0.5'));
10 | *
11 | **/
12 |
13 | S2.viewportOverlay = function(){
14 | var viewport = document.viewport.getDimensions(),
15 | offsets = document.viewport.getScrollOffsets();
16 | return new Element('div').setStyle({
17 | position: 'absolute',
18 | left: offsets.left + 'px', top: offsets.top + 'px',
19 | width: viewport.width + 'px', height: viewport.height + 'px'
20 | });
21 | };
--------------------------------------------------------------------------------
/src/addons/slowmotion.js:
--------------------------------------------------------------------------------
1 | S2.FX.Heartbeat.SlowMotion = Class.create(S2.FX.Heartbeat, {
2 | initialize: function($super, options) {
3 | $super(options);
4 | this.timebase = new Date().getTime();
5 | this.factor = 1;
6 |
7 | document.observe('keydown', this.onKeypress.bind(this));
8 | document.observe('keyup', this.onKeypress.bind(this));
9 | },
10 |
11 | generateTimestamp: function() {
12 | return (this.timebase + (new Date().getTime() - this.timebase) / this.factor).floor();
13 | },
14 |
15 | onKeypress: function(event) {
16 | if(event.shiftKey){
17 | if(this.factor == 5) return;
18 | this.timebase = new Date().getTime();
19 | this.factor = 5;
20 | } else {
21 | if(this.factor == 1) return;
22 | this.timebase = new Date().getTime();
23 | this.factor = 1;
24 | }
25 | }
26 | });
--------------------------------------------------------------------------------
/src/addons/zoom.js:
--------------------------------------------------------------------------------
1 | S2.FX.Helpers = {
2 | fitIntoRectangle: function(w, h, rw, rh){
3 | var f = w/h, rf = rw/rh; return f < rf ?
4 | [(rw - (w*(rh/h)))/2, 0, w*(rh/h), rh] :
5 | [0, (rh - (h*(rw/w)))/2, rw, h*(rw/w)];
6 | }
7 | };
8 |
9 | S2.FX.Operators.Zoom = Class.create(S2.FX.Operators.Style, {
10 | initialize: function($super, effect, object, options) {
11 | var viewport = document.viewport.getDimensions(),
12 | offsets = document.viewport.getScrollOffsets(),
13 | dims = object.getDimensions(),
14 | f = S2.FX.Helpers.fitIntoRectangle(dims.width, dims.height,
15 | viewport.width - (options.borderWidth || 0)*2,
16 | viewport.height - (options.borderWidth || 0)*2);
17 |
18 | Object.extend(options, { style: {
19 | left: f[0] + (options.borderWidth || 0) + offsets.left + 'px',
20 | top: f[1] + (options.borderWidth || 0) + offsets.top + 'px',
21 | width: f[2] + 'px', height: f[3] + 'px'
22 | }});
23 | $super(effect, object, options);
24 | }
25 | });
26 |
27 | S2.FX.Zoom = Class.create(S2.FX.Element, {
28 | setup: function() {
29 | this.clone = this.element.cloneWithoutIDs();
30 | this.element.insert({before:this.clone});
31 | this.clone.absolutize().setStyle({zIndex:9999});
32 |
33 | this.overlay = S2.viewportOverlay();
34 | if (this.options.overlayClassName)
35 | this.overlay.addClassName(this.options.overlayClassName)
36 | else
37 | this.overlay.setStyle({backgroundColor: '#000', opacity: '0.9'});
38 | $$('body')[0].insert(this.overlay);
39 |
40 | this.animate('zoom', this.clone, {
41 | borderWidth: this.options.borderWidth,
42 | propertyTransitions: this.options.propertyTransitions || { }
43 | });
44 | },
45 | teardown: function() {
46 | this.clone.observe('click', function() {
47 | this.overlay.remove();
48 | this.clone.morph('opacity:0', {
49 | duration: 0.2,
50 | after: function() {
51 | this.clone.remove();
52 | }.bind(this)
53 | })
54 | }.bind(this));
55 | }
56 | });
57 |
--------------------------------------------------------------------------------
/src/constants.yml:
--------------------------------------------------------------------------------
1 | SCRIPTY2_VERSION: 2.0.0_b1
2 |
--------------------------------------------------------------------------------
/src/effects.js:
--------------------------------------------------------------------------------
1 | //= require "effects/base"
2 | //= require "effects/heartbeat"
3 | //= require "effects/queue"
4 |
5 | //= require "effects/attribute"
6 | //= require "effects/style"
7 | //= require "effects/morph"
8 | //= require "effects/parallel"
9 | //= require "effects/scroll"
10 | //= require "effects/slide"
11 |
12 | //= require "effects/transitions/transitions"
13 | //= require "effects/transitions/penner"
14 | //= require "effects/css_transitions"
--------------------------------------------------------------------------------
/src/effects/attribute.js:
--------------------------------------------------------------------------------
1 | /** section: scripty2 fx
2 | * class S2.FX.Attribute < S2.FX.Base
3 | *
4 | * This effect can change an object property or call
5 | * a method with a numerical interpolation.
6 | **/
7 | S2.FX.Attribute = Class.create(S2.FX.Base, {
8 | initialize: function($super, object, from, to, options, method) {
9 | object = Object.isString(object) ? $(object) : object;
10 |
11 | this.method = Object.isFunction(method) ? method.bind(object) :
12 | Object.isFunction(object[method]) ? object[method].bind(object) :
13 | function(value) { object[method] = value };
14 |
15 | this.to = to;
16 | this.from = from;
17 |
18 | return $super(options);
19 | },
20 |
21 | update: function(position) {
22 | this.method(this.from.tween(this.to, position));
23 | }
24 | });
--------------------------------------------------------------------------------
/src/effects/debugger.js:
--------------------------------------------------------------------------------
1 | S2.FX.Debugger = Class.create({
2 | initialize: function() {
3 | this.buildQueueTimeline();
4 | this.spinnerPosition = 0;
5 | document.observe('effect:heartbeat', this.renderQueueTimeline.bind(this));
6 | },
7 |
8 | renderQueueTimeline: function() {
9 | var timestamp = s2.fx.getHeartbeat().getTimestamp();
10 | $('debug-timeline').innerHTML =
11 | this.nextSpinner() + ' ' +
12 | (new Date(timestamp)).toJSON().gsub(/"/,'') + '.' + (timestamp % 1000).toPaddedString(3) + ' ' +
13 | s2.fx.getQueues().length + ' queue(s), ' +
14 | s2.fx.getQueues().inject(0, function(memo, queue) {
15 | return memo + queue.getEffects().length
16 | }) + ' effect(s)' + ' ' +
17 | s2.fx.getQueues()[0].getEffects().map(function(effect){
18 | return effect.inspect().escapeHTML();
19 | }).join(' ');
20 | },
21 |
22 | buildQueueTimeline: function() {
23 | $$('body')[0].insert(
24 | new Element('div',{ id: 'debug-timeline' }).setStyle({
25 | position: 'fixed', bottom: '20px', left: '20px', zIndex: '100000', padding: '5px',
26 | background: '#000', opacity: '0.9', color: '#fff', font: '11px/13px sans-serif'
27 | })
28 | );
29 | },
30 |
31 | nextSpinner: function() {
32 | return $w('| / - \\')[this.spinnerPosition++ % 4];
33 | }
34 | });
35 |
36 | S2.FX.Heartbeat.Stepper = Class.create(S2.FX.Heartbeat, {
37 | initialize: function(stepSpeed) {
38 | this.stepSpeed = stepSpeed || 100;
39 | this.stepDirection = 1;
40 | this.timestamp = 0;
41 |
42 | document.observe('keypress', this.onKeypress.bind(this));
43 | },
44 |
45 | generateTimestamp: function() {
46 | return this.timestamp + (this.stepSpeed * this.stepDirection);
47 | },
48 |
49 | onKeypress: function(event) {
50 | if (event.keyCode == Event.KEY_LEFT)
51 | this.stepDirection = -1;
52 | else if (event.keyCode == Event.KEY_RIGHT)
53 | this.stepDirection = 1;
54 | else return;
55 | this.beat();
56 | },
57 |
58 | start: Prototype.emptyFunction,
59 | stop: Prototype.emptyFunction
60 | });
61 |
--------------------------------------------------------------------------------
/src/effects/heartbeat.js:
--------------------------------------------------------------------------------
1 | /** section: scripty2 fx
2 | * class S2.FX.Heartbeat
3 | *
4 | * The heartbeat class provides for effects timing. An instance of this class
5 | * is automatically created when the first effect on a page is instantiated.
6 | *
7 | * This class can be extended and replaced by your own implementation:
8 | *
9 | * // call before effects are created
10 | * var myHeartbeat = Class.create(S2.FX.Heartbeat, { ... });
11 | * S2.FX.initialize(new myHeartbeat());
12 | *
13 | * This can be used to implement customized debugging and more.
14 | **/
15 | S2.FX.Heartbeat = Class.create({
16 | /**
17 | * new S2.FX.Heartbeat([options])
18 | * - options (Object): options hash
19 | *
20 | * The following options are available:
21 | * * [[framerate]]: set (maximum) framerate for calls to [[S2.FX.beat]]/
22 | **/
23 | initialize: function(options) {
24 | this.options = Object.extend({
25 | framerate: Prototype.Browser.MobileSafari ? 20 : 60
26 | }, options);
27 | this.beat = this.beat.bind(this);
28 | },
29 |
30 | /**
31 | * S2.FX.Heartbeat#start() -> undefined
32 | *
33 | * This function is called by [[S2.FX]] whenever there's a new active effect queued
34 | * and there are no other effects running. This mechanism can be used to prevent
35 | * unnecessary timeouts/intervals from being active, as [[S2.FX.Hearbeat.beat]] is only
36 | * called when there are active effects that need to be rendered.
37 | **/
38 | start: function() {
39 | if (this.heartbeatInterval) return;
40 | this.heartbeatInterval =
41 | setInterval(this.beat, 1000/this.options.framerate);
42 | this.updateTimestamp();
43 | },
44 |
45 | /**
46 | * S2.FX.Heartbeat#stop() -> undefined
47 | *
48 | * Called when the last active effect is dequeued.
49 | **/
50 | stop: function() {
51 | if (!this.heartbeatInterval) return;
52 | clearInterval(this.heartbeatInterval);
53 | this.heartbeatInterval = null;
54 | this.timestamp = null;
55 | },
56 |
57 | /**
58 | * S2.FX.Heartbeat#beat() -> undefined
59 | *
60 | * This method fires an `effect:heartbeat` event which is in turn used by
61 | * [[S2.FX]] to render all active effect queues.
62 | *
63 | * Fires: effect:heartbeat
64 | **/
65 | beat: function() {
66 | this.updateTimestamp();
67 | document.fire('effect:heartbeat');
68 | },
69 |
70 | /**
71 | * S2.FX.Heartbeat#getTimestamp() -> Date
72 | *
73 | * Returns the current timestamp.
74 | **/
75 | getTimestamp: function() {
76 | return this.timestamp || this.generateTimestamp();
77 | },
78 |
79 | /**
80 | * S2.FX.Heartbeat#generateTimestamp() -> Date
81 | *
82 | * Returns the current date and time.
83 | **/
84 | generateTimestamp: function() {
85 | return new Date().getTime();
86 | },
87 |
88 | /**
89 | * S2.FX.Heartbeat#updateTimestamp() -> undefined
90 | *
91 | * Updates the current timestamp (sets it to the current date and time).
92 | *
93 | * If subclassed, this can be used to achieve special effects, for example all effects
94 | * could be sped up or slowed down.
95 | **/
96 | updateTimestamp: function() {
97 | this.timestamp = this.generateTimestamp();
98 | }
99 | });
--------------------------------------------------------------------------------
/src/effects/morph.js:
--------------------------------------------------------------------------------
1 | //= require "operators/style"
2 |
3 | /**
4 | * class S2.FX.Morph < S2.FX.Element
5 | *
6 | * "Morph" DOM elements to a new set of CSS style rules, while optionally
7 | * providing a new set of contents.
8 | *
9 | *
Preferred syntax
10 | *
11 | * It is recommended to use the shorthand syntax, for example:
12 | *
13 | * $('element_id').morph('width:300px;color:#fff', { duration: .7 });
14 | *
15 | *
Supported CSS properties
16 | *
17 | * The following CSS properties are supported by this effect:
18 | * `background-color (color)`, `border-bottom-color (color)`,
19 | * `border-bottom-width (length)`, `border-left-color (color)`,
20 | * `border-left-width (length)`, `border-right-color (color)`,
21 | * `border-right-width (length)`, `border-spacing (length)`,
22 | * `border-top-color (color)`, `border-top-width (length)`,
23 | * `bottom (length)`, `color (color)`, `font-size (length)`,
24 | * `font-weight (integer)`, `height (length)`, `left (length)`,
25 | * `letter-spacing (length)`, `line-height (length)`,
26 | * `margin-bottom (length)`, `margin-left (length)`, `margin-right (length)`,
27 | * `margin-top (length)`, `max-height (length)`, `max-width (length)`,
28 | * `min-height (length)`, `min-width (length)`, `opacity (number)`,
29 | * `outline-color (color)`, `outline-offset (length)`,
30 | * `outline-width (length)`, `padding-bottom (length)`,
31 | * `padding-left (length)`, `padding-right (length)`, `padding-top (length)`,
32 | * `right (length)`, `text-indent (length)`, `top (length)`, `width (length)`,
33 | * `word-spacing (length)`, `z-index (integer)` and `zoom (number)`.
34 | *
35 | * In addition, shorthand CSS properties for these also work:
36 | *
37 | * $('element_id').setStyle('border:2px solid #cba;border-bottom-width:100px');
38 | * $('element_id').morph('border:12px solid #abc', { duration: .7 });
39 | *
40 | * It is also possible to specify a [[S2.FX.Transition]] for some or all CSS properties
41 | * individually for complex animation effects:
42 | *
43 | * $('element_id').morph('top:20px;left:50px;background-color:#000',{
44 | * transition: 'easeInOutExpo',
45 | * propertyTransitions: {
46 | * top: 'spring', left: 'easeInOutCirc'
47 | * }
48 | * });
49 | *
50 | * These transitions are in addition to the main effect transition.
51 | *
52 | *
Try any combination of supported properties in this demo:
53 | *
54 | **/
55 | S2.FX.Morph = Class.create(S2.FX.Element, {
56 | setup: function() {
57 | if (this.options.change)
58 | this.setupWrappers();
59 | else if (this.options.style)
60 | this.animate('style', this.destinationElement || this.element, {
61 | style: this.options.style,
62 | propertyTransitions: this.options.propertyTransitions || { }
63 | });
64 | },
65 |
66 | teardown: function() {
67 | if (this.options.change)
68 | this.teardownWrappers();
69 | },
70 |
71 | setupWrappers: function() {
72 | var elementFloat = this.element.getStyle("float"),
73 | sourceHeight, sourceWidth,
74 | destinationHeight, destinationWidth,
75 | maxHeight;
76 |
77 | this.transitionElement = new Element('div').setStyle({ position: "relative", overflow: "hidden", 'float': elementFloat });
78 | this.element.setStyle({ 'float': "none" }).insert({ before: this.transitionElement });
79 |
80 | this.sourceElementWrapper = this.element.cloneWithoutIDs().wrap('div');
81 | this.destinationElementWrapper = this.element.wrap('div');
82 |
83 | this.transitionElement.insert(this.sourceElementWrapper).insert(this.destinationElementWrapper);
84 |
85 | sourceHeight = this.sourceElementWrapper.getHeight();
86 | sourceWidth = this.sourceElementWrapper.getWidth();
87 |
88 | this.options.change();
89 |
90 | destinationHeight = this.destinationElementWrapper.getHeight();
91 | destinationWidth = this.destinationElementWrapper.getWidth();
92 |
93 | this.outerWrapper = new Element("div");
94 | this.transitionElement.insert({ before: this.outerWrapper });
95 | this.outerWrapper.setStyle({
96 | overflow: "hidden", height: sourceHeight + "px", width: sourceWidth + "px"
97 | }).appendChild(this.transitionElement);
98 |
99 | maxHeight = Math.max(destinationHeight, sourceHeight), maxWidth = Math.max(destinationWidth, sourceWidth);
100 |
101 | this.transitionElement.setStyle({ height: sourceHeight + "px", width: sourceWidth + "px" });
102 | this.sourceElementWrapper.setStyle({ position: "absolute", height: maxHeight + "px", width: maxWidth + "px", top: 0, left: 0 });
103 | this.destinationElementWrapper.setStyle({ position: "absolute", height: maxHeight + "px", width: maxWidth + "px", top: 0, left: 0, opacity: 0, zIndex: 2000 });
104 |
105 | this.outerWrapper.insert({ before: this.transitionElement }).remove();
106 |
107 | this.animate('style', this.transitionElement, { style: 'height:' + destinationHeight + 'px; width:' + destinationWidth + 'px' });
108 | this.animate('style', this.destinationElementWrapper, { style: 'opacity: 1.0' });
109 | },
110 |
111 | teardownWrappers: function() {
112 | var destinationElement = this.destinationElementWrapper.down();
113 |
114 | if (destinationElement)
115 | this.transitionElement.insert({ before: destinationElement });
116 |
117 | this.transitionElement.remove();
118 | }
119 | });
--------------------------------------------------------------------------------
/src/effects/operators/base.js:
--------------------------------------------------------------------------------
1 | /**
2 | * S2.FX.Operators
3 | *
4 | * Effect operators are reusable interpolation functions.
5 | * Operators are used by [[S2.FX.Element]] and its subclasses.
6 | **/
7 | S2.FX.Operators = { };
8 |
9 | /**
10 | * class S2.FX.Operators.Base
11 | *
12 | * This is a skeleton base class which must be extended to be useful.
13 | **/
14 | S2.FX.Operators.Base = Class.create({
15 | /**
16 | * new S2.FX.Operators.Base(effect, object[, options])
17 | * - effect (S2.FX.Effect): The effect which uses this operator
18 | * - object (Object): A releatd object (mostly elements)
19 | * - options (Object): Additional options for the operator.
20 | *
21 | * This is a skeleton base class which must be extended to be useful.
22 | *
23 | * Options:
24 | * * `transition`: a [[S2.FX.Transition]] method, defaults to a linear transition
25 | **/
26 | initialize: function(effect, object, options) {
27 | this.effect = effect;
28 | this.object = object;
29 | this.options = Object.extend({
30 | transition: Prototype.K
31 | }, options);
32 | },
33 |
34 | /**
35 | * S2.FX.Operators.Base#inspect() -> String
36 | *
37 | * Returns the debug-oriented string representation of an S2.FX.Operator.
38 | **/
39 | inspect: function() {
40 | return "#";
41 | },
42 |
43 | /**
44 | * S2.FX.Operators.Base#setup() -> undefined
45 | *
46 | * Called when the operator is intialized.
47 | * Intended to be overridden by subclasses.
48 | **/
49 | setup: function() {
50 | },
51 |
52 | /**
53 | * S2.FX.Operators.Base#valueAt(position) -> Object
54 | * - position (Number): position between 0 (start of operator) and 1 (end of operator)
55 | *
56 | * Returns the value for a specific position.
57 | * Needs to be overridden by subclasses.
58 | **/
59 | valueAt: function(position) {
60 | },
61 |
62 | /**
63 | * S2.FX.Operators.Base#applyValue(value) -> undefined
64 | * - value (Object): value to be rendered
65 | *
66 | * Needs to be overridden by subclasses.
67 | **/
68 | applyValue: function(value) {
69 | },
70 |
71 | /**
72 | * S2.FX.Operators.Base#render() -> undefined
73 | *
74 | * Renders the Operator. This method is called by [[S2.FX.Element#animate]].
75 | **/
76 | render: function(position) {
77 | var value = this.valueAt(this.options.transition(position));
78 | this.applyValue(value);
79 | this.lastValue = value;
80 | }
81 | });
--------------------------------------------------------------------------------
/src/effects/operators/scroll.js:
--------------------------------------------------------------------------------
1 | //= require
2 |
3 | /**
4 | * class S2.FX.Operators.Scroll < S2.FX.Operators.Base
5 | *
6 | * Operator for scrolling the contents of an Element.
7 | **/
8 | S2.FX.Operators.Scroll = Class.create(S2.FX.Operators.Base, {
9 | initialize: function($super, effect, object, options) {
10 | $super(effect, object, options);
11 | this.start = object.scrollTop;
12 | this.end = this.options.scrollTo;
13 | },
14 |
15 | valueAt: function(position) {
16 | return this.start + ((this.end - this.start)*position);
17 | },
18 |
19 | applyValue: function(value){
20 | this.object.scrollTop = value.round();
21 | }
22 | });
--------------------------------------------------------------------------------
/src/effects/operators/style.js:
--------------------------------------------------------------------------------
1 | //= require
2 |
3 | /**
4 | * class S2.FX.Operators.Style < S2.FX.Operators.Base
5 | *
6 | * Operator for interpolating the CSS styles of an Element.
7 | **/
8 | S2.FX.Operators.Style = Class.create(S2.FX.Operators.Base, {
9 | initialize: function($super, effect, object, options) {
10 | $super(effect, object, options);
11 | this.element = $(this.object);
12 |
13 | this.style = Object.isString(this.options.style) ?
14 | S2.CSS.parseStyle(this.options.style) : this.options.style;
15 |
16 | var translations = this.options.propertyTransitions || {};
17 |
18 | this.tweens = [];
19 |
20 | for (var item in this.style) {
21 | var property = item.underscore().dasherize(),
22 | from = this.element.getStyle(property), to = this.style[item];
23 |
24 | if (from != to) {
25 | this.tweens.push([
26 | property,
27 | S2.CSS.interpolate.curry(property, from, to),
28 | item in translations ?
29 | Object.propertize(translations[item], S2.FX.Transitions) :
30 | Prototype.K
31 | ]);
32 | }
33 | }
34 | },
35 |
36 | valueAt: function(position) {
37 | return this.tweens.map( function(tween){
38 | return tween[0] + ':' + tween[1](tween[2](position));
39 | }).join(';');
40 | },
41 |
42 | applyValue: function(value) {
43 | if (this.currentStyle == value) return;
44 | this.element.setStyle(value);
45 | this.currentStyle = value;
46 | }
47 | });
--------------------------------------------------------------------------------
/src/effects/parallel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * class S2.FX.Parallel < S2.FX.Base
3 | *
4 | * Effect to execute several other effects in parallel.
5 | *
6 | * Instead of reitering what already exists for [[S2.FX]] and [[S2.FX.Base]], lets
7 | * just get down to business with a quick example!
8 | *
9 | *
Morphing 2 elements example
10 | *
11 | * new S2.FX.Parallel([ // the parallel effect itself
12 | * new S2.FX.Morph('element1_id', { // morph element1_id
13 | * after: function() // after execution function
14 | * {
15 | * $('element2_id').update('morphing!'); // write this after executing
16 | * },
17 | * delay: 0.1, // just a little starting delay
18 | * duration: 0.9, // duration should equal 1 sec w/ delay
19 | * position: 'parallel', // the queue position is 'parallel'
20 | * style: 'height: 150px; width: 350px;', // resize our first element from 0x0
21 | * transition: 'spring' // a transition for element morphing
22 | * }),
23 | * new S2.FX.Morph('element2_id', { // morph element2_id
24 | * after: function() // after execution function
25 | * {
26 | * $('element2_id').update('finished!'); // write this after executing
27 | * },
28 | * delay: 0.25, // delay this slightly behind above
29 | * duration: 0.75, // duration should equal 1 sec w/ delay
30 | * position: 'parallel', // the queue position is 'parallel'
31 | * style: 'opacity: 1; color: orange;', // morph the text we inserted
32 | * transition: 'easeInOutCubic' // a transition for the text morphing
33 | * }),
34 | * ],{
35 | * duration: 1 // the overall length of this effect
36 | * });
37 | *
38 | *
Notes
39 | *
40 | * It is recommended that you set any effects position to "parallel" to ensure
41 | * that it will be executed properly.
42 | *
43 | * As shown above, anything from [[S2.FX.Base]] can be applied to the parallel
44 | * effect itself.
45 | **/
46 | S2.FX.Parallel = Class.create(S2.FX.Base, {
47 | initialize: function($super, effects, options) {
48 | this.effects = effects || [];
49 | return $super(options || {});
50 | },
51 |
52 | setup: function() {
53 | this.effects.invoke('setup');
54 | },
55 |
56 | update: function(position) {
57 | this.effects.invoke('update', position);
58 | },
59 |
60 | cancel: function($super, after) {
61 | $super(after);
62 | this.effects.invoke('cancel', after);
63 | },
64 |
65 | start: function($super) {
66 | $super();
67 | this.effects.invoke('start');
68 | }
69 | });
--------------------------------------------------------------------------------
/src/effects/queue.js:
--------------------------------------------------------------------------------
1 | /**
2 | * class S2.FX.Queue
3 | *
4 | * Effect queues manage the execution of effects in parallel or
5 | * end-to-end over time.
6 | **/
7 | S2.FX.Queue = (function(){
8 | return function() {
9 | var instance = this;
10 | var effects = [];
11 |
12 | /**
13 | * S2.FX.Queue#getEffects() -> Array
14 | *
15 | * Returns an array of any effects currently running or queued up.
16 | **/
17 | function getEffects() {
18 | return effects;
19 | }
20 |
21 | /**
22 | * S2.FX.Queue#active() -> Boolean
23 | *
24 | * Returns whether there are any effects currently running or queued up.
25 | **/
26 | function active() {
27 | return effects.length > 0;
28 | }
29 |
30 | /**
31 | * S2.FX.Queue#add(effect) -> S2.FX.Queue
32 | * - effect (S2.FX.Base): Effect to be queued
33 | *
34 | * Add an effect to the queue. The effects' options can optionally
35 | * contain a `position` option that can be either `parallel`
36 | * (the effect will start immediately) or `end` (the effect will start
37 | * when the last of the currently-queued effects ends).
38 | * Returns the Queue.
39 | *
40 | * fires: effect:queued
41 | **/
42 | function add(effect) {
43 | calculateTiming(effect);
44 | effects.push(effect);
45 | document.fire('effect:queued', instance);
46 | return instance;
47 | }
48 |
49 | /**
50 | * S2.FX.Queue#remove(effect) -> S2.FX.Queue
51 | * - effect (S2.FX.Base): Effect to be removed from the Queue.
52 | *
53 | * Removes an effect from the Queue and destroys the effect.
54 | * Returns the Queue.
55 | *
56 | * fires: effect:dequeued
57 | **/
58 | function remove(effect) {
59 | effects = effects.without(effect);
60 | document.fire('effect:dequeued', instance);
61 | delete effect;
62 | return instance;
63 | }
64 |
65 | /**
66 | * S2.FX.Queue#render(timestamp) -> S2.FX.Queue
67 | * - timestamp (Date): Timestamp given to the individual effects' render methods.
68 | *
69 | * Renders all effects that are currently in the Queue.
70 | * Returns the Queue.
71 | **/
72 | function render(timestamp) {
73 | for (var i = 0, effect; effect = effects[i]; i++) {
74 | effect.render(timestamp);
75 | if (effect.state === 'finished') remove(effect);
76 | }
77 |
78 | return instance;
79 | }
80 |
81 | function calculateTiming(effect) {
82 | var position = effect.options.position || 'parallel',
83 | now = S2.FX.getHeartbeat().getTimestamp();
84 |
85 | var startsAt;
86 | if (position === 'end') {
87 | startsAt = effects.without(effect).pluck('endsAt').max() || now;
88 | if (startsAt < now) startsAt = now;
89 | } else {
90 | startsAt = now;
91 | }
92 |
93 | // If the user specified a delay, we convert it to ms and add it to the
94 | // `startsAt` time.
95 | var delay = (effect.options.delay || 0) * 1000;
96 | effect.startsAt = startsAt + delay;
97 |
98 | var duration = (effect.options.duration || 1) * 1000;
99 | effect.endsAt = effect.startsAt + duration;
100 | }
101 |
102 | Object.extend(instance, {
103 | getEffects: getEffects,
104 | active: active,
105 | add: add,
106 | remove: remove,
107 | render: render
108 | });
109 | }
110 | })();
--------------------------------------------------------------------------------
/src/effects/scroll.js:
--------------------------------------------------------------------------------
1 | //= require "operators/scroll"
2 |
3 | /**
4 | * class S2.FX.Scroll < S2.FX.Element
5 | *
6 | * Effect for scrolling an elements' contents.
7 | **/
8 | S2.FX.Scroll = Class.create(S2.FX.Element, {
9 | setup: function() {
10 | this.animate('scroll', this.element, { scrollTo: this.options.to });
11 | }
12 | });
--------------------------------------------------------------------------------
/src/effects/slide.js:
--------------------------------------------------------------------------------
1 | /**
2 | * class S2.FX.SlideDown < S2.FX.Element
3 | *
4 | * Effect to hide an element by animating its CSS `height`, `padding-top`,
5 | * and `padding-bottom` from their ordinary values to zero.
6 | **/
7 |
8 | S2.FX.SlideDown = Class.create(S2.FX.Element, {
9 | setup: function() {
10 | var element = this.destinationElement || this.element;
11 | var layout = element.getLayout();
12 |
13 | var style = {
14 | height: layout.get('height') + 'px',
15 | paddingTop: layout.get('padding-top') + 'px',
16 | paddingBottom: layout.get('padding-bottom') + 'px'
17 | };
18 |
19 | element.setStyle({
20 | height: '0',
21 | paddingTop: '0',
22 | paddingBottom: '0',
23 | overflow: 'hidden'
24 | }).show();
25 |
26 | this.animate('style', element, {
27 | style: style,
28 | propertyTransitions: {}
29 | });
30 | },
31 |
32 | teardown: function() {
33 | var element = this.destinationElement || this.element;
34 | element.setStyle({
35 | height: '',
36 | paddingTop: '',
37 | paddingBottom: '',
38 | overflow: 'visible'
39 | });
40 | }
41 | });
42 |
43 | S2.FX.SlideUp = Class.create(S2.FX.Morph, {
44 | setup: function() {
45 | var element = this.destinationElement || this.element;
46 | var layout = element.getLayout();
47 |
48 | var style = {
49 | height: '0px',
50 | paddingTop: '0px',
51 | paddingBottom: '0px'
52 | };
53 |
54 | element.setStyle({ overflow: 'hidden' });
55 |
56 | this.animate('style', element, {
57 | style: style,
58 | propertyTransitions: {}
59 | });
60 | },
61 |
62 | teardown: function() {
63 | var element = this.destinationElement || this.element;
64 | element.setStyle({
65 | height: '',
66 | paddingTop: '',
67 | paddingBottom: '',
68 | overflow: 'visible'
69 | }).hide();
70 | }
71 | });
--------------------------------------------------------------------------------
/src/effects/style.js:
--------------------------------------------------------------------------------
1 | /**
2 | * class S2.FX.Style < S2.FX.Element
3 | *
4 | * This effect is similiar to [[S2.FX.Morph]] but doesn't provide any
5 | * of the more advanced functionality, like content morphing.
6 | **/
7 | S2.FX.Style = Class.create(S2.FX.Element, {
8 | setup: function() {
9 | this.animate('style', this.element, { style: this.options.style });
10 | }
11 | });
--------------------------------------------------------------------------------
/src/effects/transitions/cubic-bezier.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * 1. Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | *
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * 3. Neither the name of the copyright holder(s) nor the names of any
15 | * contributors may be used to endorse or promote products derived from
16 | * this software without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 |
30 | (function(){
31 | // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/
32 | function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) {
33 | var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
34 | function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
35 | function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
36 | function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
37 | function solveEpsilon(duration) {return 1.0/(200.0*duration);};
38 | function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
39 | function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
40 | function solveCurveX(x,epsilon) {
41 | var t0,t1,t2,x2,d2,i;
42 | for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)t1) {return t1;}
44 | while(t0x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
45 | return t2; // Failure.
46 | };
47 | cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
48 | return solve(t, solveEpsilon(duration));
49 | }
50 | /**
51 | * S2.FX.cubicBezierTransition(x1, y1, x2, y2) -> Function
52 | *
53 | * Generates a transition easing function that is compatible
54 | * with WebKit's CSS transitions `-webkit-transition-timing-function`
55 | * CSS property.
56 | *
57 | * The W3C has more information about
58 | *
59 | * CSS3 transition timing functions.
60 | **/
61 | S2.FX.cubicBezierTransition = function(x1, y1, x2, y2){
62 | return (function(pos){
63 | return CubicBezierAtTime(pos,x1,y1,x2,y2,1);
64 | });
65 | }
66 | })();
67 |
68 | /**
69 | * S2.FX.Transitions.webkitCubic(pos) -> Number
70 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect)
71 | *
72 | * The default WebKit CSS transition easing function.
73 | *
74 | *
75 | **/
76 | S2.FX.Transitions.webkitCubic =
77 | S2.FX.cubicBezierTransition(0.25,0.1,0.25,1);
78 | /**
79 | * S2.FX.Transitions.webkitEaseInOut(pos) -> Number
80 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect)
81 | *
82 | * The WebKit CSS transition "ease-in-out" easing function.
83 | *
84 | *
85 | **/
86 | S2.FX.Transitions.webkitEaseInOut =
87 | S2.FX.cubicBezierTransition(0.42,0.0,0.58,1.0);
--------------------------------------------------------------------------------
/src/effects/transitions/transitions.js:
--------------------------------------------------------------------------------
1 | /**
2 | * S2.FX.Transitions
3 | *
4 | * Transitions can fine-tune how an effect evolves over time. All effects,
5 | * without the use of transitions, normally evolve linearily.
6 | *
7 | * All transitions take a `position` argument, which is between
8 | * 0 (start of effect) and 1 (end of effect). Transitions return a number,
9 | * which is a "translation" of `position` argument. The return value can,
10 | * depending on transition type, be above 1 or below 0.
11 | *
12 | * By using Transitions, it is easily possible to add movement easing,
13 | * pulsation, bouncing, reversal and other forms of special effects.
14 | *
15 | *
Default transition
Implementing your own transitions
21 | *
22 | * Transitions can easily be added, by using this template:
23 | *
24 | * Object.extend(S2.FX.Transitions, {
25 | * myTransition: function(pos) {
26 | * return pos; // do your calculations here!
27 | * }
28 | * });
29 | *
30 | * Transitions defined this way automatically become available to be used with
31 | * the shorthand syntax for the `options.transition` argument:
32 | *
33 | * $('some_element').morph('left:300px', { transition: 'myTransition' });
34 | *
35 | *
159 | EOS
160 | unless obj.children.empty?
161 | html << content_tag(:ul, obj.children.map { |n|menu(n) }.join("\n"))
162 | end
163 | content_tag(:li, html, :class => class_names)
164 | end
165 |
166 | def menu_class_name(obj)
167 | if !doc_instance
168 | nil
169 | elsif obj == doc_instance
170 | "current"
171 | elsif obj.descendants.include?(doc_instance)
172 | "current-parent"
173 | else
174 | nil
175 | end
176 | end
177 |
178 | def class_names_for(obj)
179 | classes = [obj.type.gsub(/\s+/, '-')]
180 | classes << "deprecated" if obj.deprecated?
181 | classes.join(" ")
182 | end
183 | end
184 | end
185 | end
186 | end
187 | end
188 |
--------------------------------------------------------------------------------
/templates/html/index.erb:
--------------------------------------------------------------------------------
1 | <% @title = "Home" %>
2 |
3 |
scripty2 API
4 |
5 |
6 |
Welcome to the scripty2 API Documentation.
7 |
8 |
9 | scripty2 is divided into three parts, core, fx, and ui,
10 | and supports IE6+, Safari 3+, Firefox 3+, Chrome, Opera 10 and most WebKit-based browsers.
11 |
12 |
13 |
14 | This rewrite of the script.aculo.us library is in beta. While we advise to proceed with caution,
15 | scripty2 is used in many live, production projects like twistori
16 | and freckle and it works great!
17 |
18 |
19 |
20 | Beta notice: scripty2 is currently in beta.
21 | The S2.UI API is not final and subject to change.
22 |
54 | scripty2 depends on Prototype 1.7 or later. For your convenience, a development copy
55 | and a minified version of Prototype is included in the distribution.
56 |
57 |
58 | To use scripty2, include this line in your HTML:
59 |
The scripty2 UI controls are under heavy development and are still in alpha. Consult the README for instructions on how to include these UI controls in the scripty2 distributable.
Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.
Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.
73 |
74 |
75 |
List item one
76 |
List item two
77 |
List item three
78 |
79 |
80 |
81 |
82 |
85 |
86 |
87 |
Standard accordion menu with all default options.
88 |
89 |
It should display exactly one pane at a time.
90 |
It should have an "active" state for the currently-selected accordion header.
91 |
It may have a "hover" state on accordion headers.
92 |
When a header is focused, using the arrow keys should switch focus between the headers.
93 |
Clicking on an inactive heading should trigger a transition that hides the active panel and shows the panel corresponding to the heading you clicked on.
94 |
Clicking on an active heading should do nothing, aside from giving focus to the heading.
Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.
Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.
116 |
117 |
118 |
List item one
119 |
List item two
120 |
List item three
121 |
122 |
123 |
124 |
125 |
128 |
129 |
130 |
Like the above, except the multiple option is now true.
131 |
132 |
It should be able to expand and collapse panes independently of other panes. Anywhere from zero to (all) panes can be open, or closed, at once.
The standard overlay Should "gray out" the viewport.
26 |
The standard overlay Should resize with the window.
27 |
The standard overlay Should not cause scrollbars to appear.
28 |
29 |
30 |
31 |
32 |
33 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
34 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
61 |
62 |
Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum.
63 |
Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.
64 |
65 |
66 |
69 |
70 |
71 |
A standard instance of S2.UI.Tabs with all the default options.
Movement along one axis. In environments where animation can be hardware-accelerated, example 1 should look like example 3. Both should appear much smoother than example 2.
53 |
54 |
55 |
56 |
57 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
58 |
59 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
60 |
61 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Movement along two axes. In environments where animation can be hardware-accelerated, example 1 should look like example 3. Both should appear much smoother than example 2.
54 |
55 |
56 |
57 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
58 |
59 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
60 |
61 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.