├── .gitignore ├── .gitmodules ├── CHANGELOG ├── MIT-LICENSE ├── README.rdoc ├── Rakefile ├── demos ├── basic.html ├── demos.css ├── hardware.html ├── images │ └── body.jpg └── morph.html ├── lib └── prototype.js ├── src ├── addons │ ├── helpers.js │ ├── slowmotion.js │ └── zoom.js ├── constants.yml ├── css.js ├── effects.js ├── effects │ ├── attribute.js │ ├── base.js │ ├── css_transitions.js │ ├── debugger.js │ ├── heartbeat.js │ ├── morph.js │ ├── operators │ │ ├── base.js │ │ ├── scroll.js │ │ └── style.js │ ├── parallel.js │ ├── queue.js │ ├── scroll.js │ ├── slide.js │ ├── style.js │ └── transitions │ │ ├── cubic-bezier.js │ │ ├── penner.js │ │ └── transitions.js ├── experimental.js ├── extensions │ ├── element.js │ └── misc.js ├── license.js ├── s2.js ├── ui.js └── ui │ ├── behaviors.js │ ├── behaviors │ ├── down.js │ ├── drag.js │ ├── focus.js │ ├── hover.js │ └── resize.js │ ├── controls.js │ ├── controls │ ├── accordion.js │ ├── autocompleter.js │ ├── base.js │ ├── button.js │ ├── button_set.js │ ├── button_with_menu.js │ ├── dialog.js │ ├── menu.js │ ├── overlay.js │ ├── progress_bar.js │ ├── slider.js │ └── tabs.js │ ├── dragdrop.js │ ├── manipulate.js │ ├── mixin.js │ ├── mixin │ ├── configurable.js │ ├── element.js │ ├── shim.js │ └── trackable.js │ └── util.js ├── templates └── html │ ├── assets │ ├── images │ │ ├── cc.png │ │ ├── class.png │ │ ├── class_method.png │ │ ├── constructor.png │ │ ├── demo.png │ │ ├── description.png │ │ ├── header-logo.png │ │ ├── instance_method.png │ │ ├── manipulate.png │ │ ├── method.png │ │ ├── namespace.png │ │ ├── section.png │ │ ├── subclass.png │ │ └── superclass.png │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ └── apidocs.css │ ├── helpers.rb │ ├── index.erb │ ├── item_index.js.erb │ ├── layout.erb │ ├── namespace.erb │ ├── partials │ ├── breadcrumbs.erb │ └── short_description.erb │ ├── section.erb │ └── utility.erb ├── test ├── functional │ ├── controls_accordion.html │ ├── controls_autocompleter.html │ ├── controls_buttons.html │ ├── controls_dialog.html │ ├── controls_overlay.html │ ├── controls_progress_bar.html │ ├── controls_slider.html │ ├── controls_tabs.html │ ├── css │ │ └── test.css │ ├── css_transitions.html │ ├── css_transitions_2.html │ ├── effects_units.html │ ├── images │ │ ├── header-logo-small.png │ │ ├── header-logo.png │ │ ├── manipulations_pan.jpg │ │ ├── manipulations_rotate.jpg │ │ └── manipulations_scale.jpg │ ├── index.html │ ├── manipulations_pan.html │ ├── manipulations_rotate.html │ ├── manipulations_scale.html │ └── navigation.html └── unit │ ├── addons_test.js │ ├── css_test.js │ ├── effects_test.js │ ├── extensions_test.js │ ├── fixtures │ ├── css.html │ ├── effects.html │ └── operators_style.html │ ├── heartbeat_test.js │ ├── operators_style_test.js │ ├── package_test.js │ └── templates │ └── default.erb ├── themes ├── default │ ├── images │ │ ├── accordion-header-active.png │ │ ├── button-active-default-middle.png │ │ ├── button-active-down-middle.png │ │ ├── button-active-hover-middle.png │ │ ├── button-default-middle.png │ │ ├── button-disabled-middle.png │ │ ├── button-down-middle.png │ │ ├── button-hover-middle.png │ │ ├── button-primary-default-middle.png │ │ ├── button-primary-down-middle.png │ │ ├── button-primary-hover-middle.png │ │ ├── header-active-middle.png │ │ ├── header-default-middle.png │ │ ├── header-down-middle.png │ │ ├── progress-bar-default.png │ │ ├── progress-bar-disabled.png │ │ ├── progress-bar-track-default.png │ │ ├── progress-bar-track-disabled.png │ │ ├── slider-handle-active.png │ │ ├── slider-handle-default.png │ │ ├── slider-handle-disabled.png │ │ ├── slider-range-default-horizontal.png │ │ ├── slider-range-default-vertical.png │ │ ├── slider-track-default-horizontal.png │ │ ├── slider-track-default-vertical.png │ │ ├── slider-track-disabled-horizontal.png │ │ ├── slider-track-disabled-vertical.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_2e83ff_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_888888_256x240.png │ │ ├── ui-icons_941010_256x240.png │ │ ├── ui-icons_f5f5f5_256x240.png │ │ └── widget-header.png │ ├── theme.css │ ├── ui.accordion.css │ ├── ui.all.css │ ├── ui.base.css │ ├── ui.button.css │ ├── ui.core.css │ ├── ui.datepicker.css │ ├── ui.dialog.css │ ├── ui.icons.css │ ├── ui.progressbar.css │ ├── ui.resizable.css │ ├── ui.slider.css │ └── ui.tabs.css └── test │ ├── images │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ └── ui-icons_ffffff_256x240.png │ └── theme.css └── vendor ├── google-compiler ├── COPYING ├── README └── compiler.jar └── yuicompressor ├── README └── yuicompressor-2.4.2.jar /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | pkg 3 | test/unit/tmp/* 4 | doc 5 | tmp 6 | dist/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/unittest_js"] 2 | path = vendor/unittest_js 3 | url = git://github.com/tobie/unittest_js.git 4 | [submodule "vendor/pdoc"] 5 | path = vendor/pdoc 6 | url = git://github.com/tobie/pdoc.git 7 | [submodule "vendor/sprockets"] 8 | path = vendor/sprockets 9 | url = git://github.com/sstephenson/sprockets.git 10 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | * Update to Prototype 1.7rc2 2 | 3 | * Fix S2.FX.Parallel and other non-element based effects 4 | 5 | * Properly detect Opera's CSS transition support 6 | 7 | *2.0.0 beta 1* (September 26, 2010) 8 | 9 | * Update to Prototype 1.7rc2 10 | 11 | *2.0.0 alpha 6* (March 30, 2010) 12 | 13 | * Tweak multi-touch behaviour support to new version of Nokia Starlight specs. 14 | 15 | * Add empty S2.FX.Base#update function to allow for ad-hoc effects using before/afterUpdate 16 | 17 | *2.0.0 alpha 5* (November 23, 2009) 18 | 19 | * Add UI Themeroller-compatible UI components 20 | 21 | *2.0.0 alpha 4* (October 14, 2009) 22 | 23 | * Add multi-touch behaviour support. 24 | 25 | *2.0.0 alpha 3* (September 29, 2009) 26 | 27 | * Reenable detection of WebKit CSS transition support. 28 | 29 | *2.0.0 alpha 2* (September 28, 2009) 30 | 31 | * WebKit CSS transition support and support for cubic-bezier easing (JS implementation of transition-timing-function) 32 | WebKit support is transparent - if running on a supported browser, and the morph requested can be made 33 | with CSS-based animation, it will automatically use the -webkit-transition-* CSS properties instead of the 34 | JavaScript-based engine. 35 | 36 | *2.0.0 alpha 1* (June 25, 2009) 37 | 38 | * Element#morph is now queueing automatically (Thomas Fuchs) 39 | 40 | * S2.FX.Base#cancel to abort effects in current state, S2.FX.Base#finish to instantaneously finish effects (Thomas Fuchs) 41 | 42 | * Effect options now recognize the following shortcuts: Strings "slow" and "fast" are mapped to { duration:1 } and { duration:.1 }, functions are mapped to { after: function }, and numbers are mapped to { duration:number }. [#1 state:resolved] (Thomas Fuchs, Radoslav Stankov) 43 | 44 | * Default effect length is now 0.2 seconds. (Thomas Fuchs) -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010 Thomas Fuchs 2 | http://script.aculo.us/thomas 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == scripty2: for a more delicious web 2 | 3 | scripty2 is an open source JavaScript framework for advanced HTML-based user interfaces. Or simply put, scripty2 helps you build a more delicious web: 4 | 5 | * Visual effects: scripty2's heartpiece is an versatile real-time effects framework 6 | * CSS utilities 7 | * UI components (experimental) 8 | 9 | And there's more coming! scripty2 is currently in alpha status, so APIs can change and 10 | there's still a lot more functionality planned. 11 | 12 | scripty2 is a complete rewrite and reimplementation of script.aculo.us, with 13 | are modular structure intended to ease the development of highly customized 14 | user interface effects and behaviours. 15 | 16 | Please use http://groups.google.com/group/scripty2 for any development questions 17 | for scripty2. Patches, tests, demos, updates and documentation are always welcome. 18 | 19 | = Build 20 | 21 | For building, development and testing, you need to have a working Ruby setup. 22 | You'll need the bluecloth, treetop and coderay gems installed. 23 | 24 | To build the distribution, run: 25 | 26 | rake && rake package 27 | 28 | This will build the documentation (in /doc) and provides ready-to-deploy JavaScript 29 | packages in /dist. 30 | 31 | The build process uses the YUI Compressor to build a minified version of the library 32 | file. This requires Java to be installed and available. 33 | 34 | After the build process is done, you'll find two files in /dist: 35 | 36 | * s2.js (for debugging) 37 | * s2.min.js (minified version for production use) 38 | 39 | Though scripty2 has been used to great effect on several high-volume websites, keep in mind that scripty2 effects are in beta. APIs are subject to change before final release. 40 | 41 | == Build with UI 42 | 43 | The scripty2 UI controls are under heavy development and are still in alpha. They're not included when you run the standard rake tasks. To build a distributable with UI controls included, run: 44 | 45 | rake dist:experimental 46 | 47 | There are several other *:experimental tasks corresponding to common actions. Run rake -T to see the list of tasks. 48 | 49 | = Usage 50 | 51 | scripty2 is dependent on the Prototype JavaScript framework. The download 52 | and source comes with a compatible version, or grab the latest version yourself 53 | from http://prototypejs.org/. 54 | 55 | Put prototype.js and s2.js in a folder of your website, and include them as follows: 56 | 57 | 58 | 59 | 60 | You're ready to go! Now look at the documentation and demos (see below!). 61 | 62 | = Documentation 63 | 64 | To build the documentation, run: 65 | 66 | rake doc 67 | 68 | The documentation is built with PDoc, which uses specially formatted 69 | source code comments to build a fully interactive HTML documentation set. 70 | 71 | Navigate a browser to /doc/index.html to view and browse the documentation. 72 | 73 | = Tests 74 | 75 | To run the unit tests, use: 76 | 77 | rake test 78 | 79 | You can run specific tests, or use only specific browsers: 80 | 81 | rake test BROWSERS=safari TESTS=css,heartbeat 82 | 83 | = License 84 | 85 | scripty2 is is licensed under the terms of the MIT License, see the included MIT-LICENSE file. -------------------------------------------------------------------------------- /demos/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | scripty2 Demos| Basic invocation 6 | 18 | 19 | 20 |

Basic demos

21 |

22 | Hello scripty2! (animate width, font-size) 23 |

24 |

25 | Hello scripty2! (animate width, background color, set duration to 2 seconds) 26 |

27 | 28 |

29 | Hello scripty2! (animate transparency) 30 |

31 |

32 | Hello scripty2! (animate border) 33 |

34 | 35 | 36 | -------------------------------------------------------------------------------- /demos/demos.css: -------------------------------------------------------------------------------- 1 | * { outline:none; } 2 | 3 | body { 4 | font:14px/18px "Helvetica Neue", Arial, sans-serif; 5 | overflow: hidden; 6 | } 7 | 8 | code { 9 | font-family: 'Panic Sans', Menlo, Monaco, 'Andale Mono', 'Lucida Console', monospace; 10 | } 11 | 12 | .panel { 13 | border: 3px solid #afe16d; 14 | background: #fff; 15 | padding: 13px 0; 16 | z-index: 1; 17 | -webkit-box-shadow: 0px 2px 3px rgba(0,0,0,0.5); 18 | -moz-box-shadow: 0px 2px 3px rgba(0,0,0,0.5); 19 | border-radius: 10px; 20 | -webkit-border-radius: 10px; 21 | -moz-border-radius: 10px; 22 | } 23 | 24 | .panel h1 { 25 | padding: 4px 0; 26 | margin: 0px 15px 5px 15px; 27 | font-size: 25px; 28 | color: #6c8f3f; 29 | font-weight: bold; 30 | } 31 | 32 | .panel h1 a { 33 | color: #6c8f3f; 34 | text-decoration: none; 35 | } 36 | 37 | .panel p { 38 | clear: both; 39 | margin: 0 15px 1.0em; 40 | font-size: 11px; 41 | line-height: 13px; 42 | color: #8a8a8a; 43 | } 44 | 45 | .panel pre { 46 | margin: 0 15px 1.0em; 47 | } 48 | 49 | .panel a { 50 | color: #6c8f3f; 51 | font-weight: bold; 52 | text-decoration: none; 53 | } 54 | 55 | .panel ul { 56 | margin: 15px 0; 57 | height: 15px; 58 | padding: 5px 15px 5px 10px; 59 | background: #afe16d; 60 | } 61 | 62 | .panel li { 63 | float: left; 64 | list-style-type: none; 65 | padding: 2px 4px 1px 4px; 66 | margin: 0 3px; 67 | font-weight: normal; 68 | font-size: 11px; 69 | line-height: 13px; 70 | cursor: pointer; 71 | color: #6c8f3f; 72 | background-color: #fff; 73 | -webkit-border-radius: 5px; 74 | -moz-border-radius: 5px; 75 | } 76 | 77 | .panel h6 { 78 | margin: 0 15px; 79 | font-size: 12px; 80 | color: #6c8f3f; 81 | } 82 | 83 | .panel strong { 84 | border-bottom: 1px solid #ccc; 85 | } 86 | 87 | .panel .warning { 88 | font-weight: bold; 89 | font-size: 15px !important; 90 | color: #900; 91 | } 92 | 93 | .panel .warning b { 94 | color: #900; 95 | } 96 | 97 | .panel button { 98 | float: right; 99 | background: #6c8f3f; 100 | color: #fff; 101 | -webkit-border-radius: 6px; 102 | -moz-border-radius: 6px; 103 | border-radius: 6px; 104 | padding: 5px 10px; 105 | font-size: 18px; 106 | border: 0; 107 | } 108 | 109 | 110 | .canvas { 111 | /*outline: 3px solid #3bf;*/ 112 | width: 900px; 113 | height: 500px; 114 | position: relative; 115 | } 116 | 117 | 118 | .panel.big { 119 | } 120 | 121 | .panel.big p { 122 | font-size: 16px; 123 | line-height: 1.2em; 124 | } 125 | 126 | .panel.big h6 { 127 | font-size: 19px; 128 | } 129 | 130 | #controls { 131 | position: absolute; 132 | left: 30px; 133 | top: 30px; 134 | width: 210px; 135 | } 136 | 137 | 138 | #demos { 139 | position: absolute; 140 | right: 30px; 141 | top: 30px; 142 | padding: 0; 143 | margin: 0; 144 | width: 130px; 145 | background: #fff; 146 | border: 3px solid #afe16d; 147 | border-radius: 10px; 148 | -webkit-border-radius: 10px; 149 | -moz-border-radius: 10px; 150 | z-index:1; 151 | -webkit-box-shadow:0px 2px 3px rgba(0,0,0,0.5); 152 | } 153 | 154 | #demos li { 155 | list-style-type: none; 156 | height: 108px; 157 | padding-top: 10px; 158 | font-size: 12px; 159 | font-weight: bold; 160 | color: #afe16d; 161 | text-align: center; 162 | } 163 | 164 | #demos li a { 165 | text-decoration: none; 166 | color: #6c8f3f; 167 | display: block; 168 | } 169 | 170 | #demos li a img { 171 | display: block; 172 | margin: 0 auto 3px; 173 | border: 0; 174 | } 175 | 176 | #demos li.title { 177 | height: auto; 178 | } 179 | 180 | #demos li.title h1 { 181 | padding: 4px 0; 182 | margin: 0; 183 | font-size: 18px; 184 | color: #6c8f3f; 185 | font-weight: normal; 186 | } 187 | 188 | #demos li.back { 189 | background: url(scripty2.png) 5px center no-repeat; 190 | width: 117px; 191 | height: 55px; 192 | padding: 10px 5px; 193 | text-align: center; 194 | } 195 | 196 | #demos li.back a { 197 | width: 117px; 198 | height: 50px; 199 | padding-top: 45px; 200 | font-weight: normal; 201 | } 202 | 203 | #demos li.active { 204 | background: #afe16d; 205 | } -------------------------------------------------------------------------------- /demos/images/body.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/demos/images/body.jpg -------------------------------------------------------------------------------- /demos/morph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | scripty2: demos 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | 23 | 24 |
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 | *

Notice

36 | * 37 | * The equations defined in penner.js are open source under the BSD License. 38 | * Easing Equations 39 | * © 2003 Robert Penner, 40 | * all rights reserved. 41 | **/ 42 | 43 | S2.FX.Transitions = { 44 | 45 | /** 46 | * S2.FX.Transitions.linear(pos) -> Number 47 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 48 | * 49 | * Basic linear transition, no easing or other alteration of the effect. 50 | *
51 | **/ 52 | linear: Prototype.K, 53 | 54 | /** 55 | * S2.FX.Transitions.sinusoidal(pos) -> Number 56 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 57 | * 58 | * Alters the effect timing to be aligned to a sine wave. 59 | *
60 | **/ 61 | sinusoidal: function(pos) { 62 | return (-Math.cos(pos*Math.PI)/2) + 0.5; 63 | }, 64 | 65 | /** 66 | * S2.FX.Transitions.reverse(pos) -> Number 67 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 68 | * 69 | * Effect is executed in a reverse linear fashion. 70 | *
71 | **/ 72 | reverse: function(pos) { 73 | return 1 - pos; 74 | }, 75 | 76 | /** 77 | * S2.FX.Transitions.mirror(pos[, transition]) -> Number 78 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 79 | * - transition (Function): a S2.FX.Transitions transition function 80 | * 81 | * The given transition is mirrored. Defaults to [[S2.FX.Transitions.sinusoidal]]. 82 | *
83 | * 84 | * You can use other transitions as per the following code sample: 85 | * 86 | * $('element_id').morph('font-size:200px', { 87 | * transition: function(pos){ 88 | * return S2.FX.Transitions.mirror(pos, S2.FX.Transitions.bounce); 89 | * } 90 | * }); 91 | * 92 | * If you plan to reuse such a mirrored transition often, define your own transition 93 | * function: 94 | * 95 | * S2.FX.Transitions.mirroredBounce = function(pos){ 96 | * return S2.FX.Transitions.mirror(pos, S2.FX.Transitions.bounce); 97 | * }); 98 | * 99 | * $('element_id').morph('font-size:200px', { transition: 'mirroredBounce' }); 100 | **/ 101 | mirror: function(pos, transition) { 102 | transition = transition || S2.FX.Transitions.sinusoidal; 103 | if(pos<0.5) 104 | return transition(pos*2); 105 | else 106 | return transition(1-(pos-0.5)*2); 107 | }, 108 | 109 | /** 110 | * S2.FX.Transitions.flicker(pos) -> Number 111 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 112 | * 113 | * Effect flickers along a sine wave. 114 | *
115 | **/ 116 | flicker: function(pos) { 117 | var pos = pos + (Math.random()-0.5)/5; 118 | return S2.FX.Transitions.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos); 119 | }, 120 | 121 | /** 122 | * S2.FX.Transitions.wobble(pos) -> Number 123 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 124 | * 125 | * Effect wobbles increasingly fast between start and end positions. 126 | *
127 | **/ 128 | wobble: function(pos) { 129 | return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; 130 | }, 131 | 132 | /** 133 | * S2.FX.Transitions.pulse(pos[, pulses]) -> Number 134 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 135 | * - pulses (Number): Number of pulses, defaults to 5 136 | * 137 | * Effect pulses along a sinusoidal transition. 138 | *
139 | **/ 140 | pulse: function(pos, pulses) { 141 | return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; 142 | }, 143 | 144 | /** 145 | * S2.FX.Transitions.blink(pos[, blinks]) -> Number 146 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 147 | * - pulses (Number): Number of blinks, defaults to 5 148 | * 149 | * Effect blinks on and off. 150 | *
151 | **/ 152 | blink: function(pos, blinks) { 153 | return Math.round(pos*(blinks||5)) % 2; 154 | }, 155 | 156 | /** 157 | * S2.FX.Transitions.spring(pos) -> Number 158 | * - pos (Number): position between 0 (start of effect) and 1 (end of effect) 159 | * 160 | * Alters the effect timing to a "spring". 161 | *
162 | **/ 163 | spring: function(pos) { 164 | return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); 165 | }, 166 | 167 | /** 168 | * S2.FX.Transitions.none() -> Number 169 | * 170 | * No transition, the effect stays in intial state (returns 0 regardless of input values). 171 | *
172 | **/ 173 | none: Prototype.K.curry(0), 174 | 175 | /** 176 | * S2.FX.Transitions.full() -> Number 177 | * 178 | * No transition, the effect is always in final state (returns 1 regardless of input values). 179 | *
180 | **/ 181 | full: Prototype.K.curry(1) 182 | }; 183 | 184 | //= require 185 | //= require -------------------------------------------------------------------------------- /src/experimental.js: -------------------------------------------------------------------------------- 1 | //= require "ui" 2 | -------------------------------------------------------------------------------- /src/extensions/misc.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 core 2 | * class Function 3 | * 4 | * Extensions to the built-in `Function` object. 5 | **/ 6 | 7 | /** 8 | * Function#optionize() -> Function 9 | * 10 | * Given a function whose last parameter is an object 11 | * of options, return a function that accepts a variable 12 | * number of arguments and always passes the last argument 13 | * that is an object to the options parameter. This way, 14 | * the function can be called with just options, leaving 15 | * the other parameters undefined. 16 | * 17 | * var logOptions = function(a, b, options){ 18 | * console.log(options); 19 | * }.optionize(); 20 | * logOptions({hello: "world"}) -> logs {hello: "world"} 21 | * logOptions(1, {hello: "world"}) -> logs {hello: "world"} 22 | * logOptions(1, 2, {hello: "world"}) -> logs {hello: "world"} 23 | * 24 | * But note that providing too many arguments will not work: 25 | * 26 | * logOptions(1,2,3, {hello: "world"}) -> logs 3 27 | **/ 28 | Function.prototype.optionize = function(){ 29 | var self = this, argumentNames = self.argumentNames(), optionIndex = this.length - 1; 30 | 31 | var method = function() { 32 | var args = $A(arguments); 33 | 34 | var options = (typeof args.last() === 'object') ? args.pop() : {}; 35 | var prefilledArgs = []; 36 | if (optionIndex > 0) { 37 | prefilledArgs = ((args.length > 0 ? args : [null]).inGroupsOf( 38 | optionIndex).flatten()).concat(options); 39 | } 40 | 41 | return self.apply(this, prefilledArgs); 42 | }; 43 | method.argumentNames = function() { return argumentNames; }; 44 | return method; 45 | }; 46 | 47 | Function.ABSTRACT = function() { 48 | throw "Abstract method. Implement in subclass."; 49 | }; 50 | 51 | /** section: scripty2 core 52 | * class Number 53 | * 54 | * Extensions to the built-in `Number` object. 55 | **/ 56 | Object.extend(Number.prototype, { 57 | /** 58 | * Number#constrain(min, max) -> Number 59 | * 60 | * Returns `min` if number is less than `min`, `max` if number is greater 61 | * than `max`. Returns itself otherwise. 62 | **/ 63 | constrain: function(n1, n2) { 64 | var min = (n1 < n2) ? n1 : n2; 65 | var max = (n1 < n2) ? n2 : n1; 66 | 67 | var num = Number(this); 68 | 69 | if (num < min) num = min; 70 | if (num > max) num = max; 71 | 72 | return num; 73 | }, 74 | 75 | /** 76 | * Number#nearer(n1, n2) -> Number 77 | * 78 | * Returns either `n1` or `n2` — whichever is closer to the number, in 79 | * absolute terms. 80 | **/ 81 | nearer: function(n1, n2) { 82 | var num = Number(this); 83 | 84 | var diff1 = Math.abs(num - n1); 85 | var diff2 = Math.abs(num - n2); 86 | 87 | return (diff1 < diff2) ? n1 : n2; 88 | }, 89 | 90 | /** 91 | * Number#tween(target, position) -> Number 92 | * - target (Number): tween target 93 | * - position (Number): position between 0 (start of tween) and (end of 94 | * tween); can also be < 0 and > 1. 95 | * 96 | * Returns the number that is a given percentage between this number and 97 | * a target number. 98 | * 99 | * (1).tween(2, 0.5) -> 1.5 100 | * (1).tween(2, 0) -> 1 101 | * (1).tween(2, 1) -> 2 102 | **/ 103 | tween: function(target, position) { 104 | return this + (target-this) * position; 105 | } 106 | }); 107 | 108 | /** section: scripty2 core 109 | * class Object 110 | * 111 | * Extensions to the built-in `Object` object. 112 | **/ 113 | 114 | /** 115 | * Object.propertize(property, object) -> Object 116 | * - property (String | Object): item or name of item 117 | * - object (Object): namespace in which to look for named item 118 | * 119 | * If `property` is a string, finds it in the provided `object`. 120 | * Otherwise returns `property`. 121 | * 122 | * Object.propertize(S2.FX.Transitions.sinusoidal, S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal 123 | * Object.propertize('sinusoidal', S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal 124 | * 125 | **/ 126 | Object.propertize = function(property, object){ 127 | return Object.isString(property) ? object[property] : property; 128 | }; -------------------------------------------------------------------------------- /src/license.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * script.aculo.us version <%= SCRIPTY2_VERSION %> 3 | * (c) 2005-2010 Thomas Fuchs 4 | * 5 | * script.aculo.us is freely distributable under the terms of an MIT-style license. 6 | *----------------------------------------------------------------------------------*/ 7 | -------------------------------------------------------------------------------- /src/s2.js: -------------------------------------------------------------------------------- 1 | //= require "license" 2 | 3 | /** 4 | * == scripty2 core == 5 | * 6 | * Core contains various JavaScript and DOM extensions used by scripty2 fx and scripty2 ui, 7 | * plus developer utility classes. 8 | **/ 9 | 10 | /** section: scripty2 core 11 | * S2 12 | * The S2 namespace is the main container for the various scripty2 frameworks 13 | * and also provides the libraries' version number and information about extensions. 14 | **/ 15 | var S2 = { 16 | /** 17 | * S2.Version = '<%= SCRIPTY2_VERSION %>' 18 | * 19 | * This constant lists the version of scripty2. 20 | **/ 21 | Version: '<%= SCRIPTY2_VERSION %>', 22 | 23 | /** 24 | * S2.Extensions 25 | * 26 | * Holds information about extension modules plugged into scripty2. 27 | **/ 28 | Extensions: {} 29 | }; 30 | 31 | //= require "extensions/misc" 32 | 33 | //= require "css" 34 | //= require "effects" 35 | 36 | //= require "extensions/element" 37 | //= require "addons/helpers" 38 | //= require "addons/zoom" -------------------------------------------------------------------------------- /src/ui.js: -------------------------------------------------------------------------------- 1 | /** 2 | * == scripty2 ui == 3 | * * [[S2.CSS]]: functions for CSS parsing, color normalization and CSS value interpolation. 4 | * * [[S2.UI]]: User interface patterns that can be used to build components and page behaviours on top of it. 5 | **/ 6 | 7 | /** section: scripty2 ui 8 | * S2.UI 9 | * This is the main user interface namespace. 10 | **/ 11 | 12 | S2.UI = {}; 13 | 14 | //= require "ui/mixin" 15 | //= require "ui/util" 16 | //= require "ui/behaviors" 17 | //= require "ui/controls" 18 | 19 | //= require "ui/manipulate" 20 | -------------------------------------------------------------------------------- /src/ui/behaviors.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior 3 | * 4 | * Abstract base class for assigning sets of events. 5 | * 6 | *

Usage

7 | * 8 | * Certain special functions in a behavior class are used directly as event 9 | * handlers. They follow one of two naming conventions: 10 | * 11 | * * `on` followed by an event name, as in `onscroll`; 12 | * * an arbitrary identifier, a slash (`/`), then the pattern above, as in 13 | * `panel/onscroll`. 14 | * 15 | * The former will be attached to the element assigned to `this.element`. 16 | * The latter will be attached to the element assigned to `this.foo`, where 17 | * `foo` is the part before the slash. 18 | * 19 | * Arbitrary properties (like `this.foo`) are designated by the `options` 20 | * argument of the constructor. 21 | * 22 | **/ 23 | S2.UI.Behavior = Class.create(S2.UI.Mixin.Configurable, { 24 | /** 25 | * new S2.UI.Behavior(element, options) 26 | **/ 27 | initialize: function(element, options) { 28 | this.element = element; 29 | this.setOptions(options); 30 | 31 | Object.extend(this, options); 32 | 33 | this._observers = {}; 34 | 35 | function isEventHandler(eventName) { 36 | return eventName.startsWith('on') || eventName.include('/on'); 37 | } 38 | 39 | var parts, element, name, handler; 40 | for (var eventName in this) { 41 | if (!isEventHandler(eventName)) continue; 42 | 43 | parts = eventName.split('/'); 44 | if (parts.length === 2) { 45 | element = this[parts.first()] || this.element; 46 | } else { 47 | element = this.element; 48 | } 49 | name = parts.last(); 50 | 51 | handler = this._observers[name] = this[eventName].bind(this); 52 | element.observe(name.substring(2), handler); 53 | } 54 | }, 55 | 56 | /** 57 | * S2.UI.Behavior#destroy() -> undefined 58 | * 59 | * Called when the behavior is removed from the element. 60 | **/ 61 | destroy: function() { 62 | var element = this.options.proxy || this.element; 63 | var handler; 64 | for (var eventName in this._observers) { 65 | handler = this._observers[eventName]; 66 | element.stopObserving(eventName.substring(2), handler); 67 | } 68 | } 69 | }); 70 | 71 | 72 | Object.extend(S2.UI, { 73 | /** 74 | * S2.UI.addBehavior(element, behaviorClass[, options]) -> undefined 75 | * - element (Element | Array): One or more elements on which to apply 76 | * the behavior. 77 | * - behaviorClass (Class | Array): One or more subclasses of 78 | * `UI.Behavior`. (Not instances!) 79 | * 80 | * Add a behavior. 81 | **/ 82 | addBehavior: function(element, behaviorClass, options) { 83 | var self = arguments.callee; 84 | if (Object.isArray(element)) { 85 | element.each( function(el) { self(el, behaviorClass, options); }); 86 | return; 87 | } 88 | 89 | if (Object.isArray(behaviorClass)) { 90 | behaviorClass.each( function(klass) { self(element, klass, options ); }); 91 | return; 92 | } 93 | 94 | var instance = new behaviorClass(element, options || {}); 95 | var behaviors = $(element).retrieve('ui.behaviors', []); 96 | behaviors.push(instance); 97 | }, 98 | 99 | /** 100 | * S2.UI.removeBehavior(element, behaviorClass) -> undefined 101 | * - element (Element | Array): One or more elements on which to remove 102 | * the behavior. 103 | * - behaviorClass (Class | Array): One or more subclasses of 104 | * `UI.Behavior`. (Not instances!) 105 | * 106 | * Remove a behavior. 107 | **/ 108 | removeBehavior: function(element, behaviorClass) { 109 | var self = arguments.callee; 110 | if (Object.isArray(element)) { 111 | element.each( function(el) { self(el, behaviorClass); }); 112 | return; 113 | } 114 | 115 | if (Object.isArray(behaviorClass)) { 116 | behaviorClass.each( function(klass) { self(element, klass); }); 117 | return; 118 | } 119 | 120 | var behaviors = $(element).retrieve('ui.behaviors', []); 121 | var shouldBeRemoved = []; 122 | for (var i = 0, behavior; behavior = behaviors[i]; i++) { 123 | if (!behavior instanceof behaviorClass) continue; 124 | behavior.destroy(); 125 | shouldBeRemoved.push(behavior); 126 | } 127 | $(element).store('ui.behaviors', behaviors.without(shouldBeRemoved)); 128 | }, 129 | 130 | 131 | /** 132 | * S2.UI.getBehavior(element, behaviorClass) -> S2.UI.Behavior 133 | **/ 134 | getBehavior: function(element, behaviorClass) { 135 | element = $(element); 136 | 137 | var behaviors = element.retrieve('ui.behaviors', []); 138 | for (var i = 0, l = behaviors.length, b; i < l; i++) { 139 | b = behaviors[i]; 140 | if (b.constructor === behaviorClass) return b; 141 | } 142 | 143 | return null; 144 | } 145 | }); 146 | 147 | //= require "behaviors/drag" 148 | //= require "behaviors/focus" 149 | //= require "behaviors/hover" 150 | //= require "behaviors/resize" 151 | //= require "behaviors/down" 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/ui/behaviors/down.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior.Down < S2.UI.Behavior 3 | * 4 | * Applies a down-state behavior. Adds a `ui-state-down` class to any 5 | * non-disabled element on mousedown, removing it on mouseup. 6 | * 7 | * Also applies these behaviors on keydown when the key is the space bar or 8 | * the return key (since browsers differ on whether mousedown/up handlers fire 9 | * in this situation). 10 | **/ 11 | S2.UI.Behavior.Down = Class.create(S2.UI.Behavior, { 12 | _isRelevantKey: function(event) { 13 | var code = event.keyCode; 14 | return (code === Event.KEY_RETURN || code === Event.KEY_SPACE); 15 | }, 16 | 17 | onkeydown: function(event) { 18 | if (!this._isRelevantKey(event)) return; 19 | this.onmousedown(event); 20 | }, 21 | 22 | onkeyup: function(event) { 23 | if (!this._isRelevantKey(event)) return; 24 | this.onmouseup(event); 25 | }, 26 | 27 | onmousedown: function(event) { 28 | this._down = true; 29 | if (this.element.hasClassName('ui-state-disabled')) return; 30 | this.element.addClassName('ui-state-down'); 31 | }, 32 | 33 | onmouseup: function(event) { 34 | this._down = false; 35 | if (this.element.hasClassName('ui-state-disabled')) return; 36 | this.element.removeClassName('ui-state-down'); 37 | }, 38 | 39 | // Handles a specific case: 40 | // mouse down on button, mouse up outside of button. 41 | onmouseleave: function(event) { 42 | return this.onmouseup(event); 43 | }, 44 | 45 | // Handles mousedown -> mouseleave -> mouseenter -> mouseup. 46 | onmouseenter: function(event) { 47 | if (this._down) { 48 | return this.onmousedown(event); 49 | } 50 | } 51 | }); -------------------------------------------------------------------------------- /src/ui/behaviors/drag.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior.Drag < S2.UI.Behavior 3 | * 4 | * Applies a drag behavior. Takes a `handle` option that points to the drag 5 | * handle; if omitted, the entire element will be draggable. 6 | **/ 7 | S2.UI.Behavior.Drag = Class.create(S2.UI.Behavior, { 8 | initialize: function($super, element, options) { 9 | this.__onmousemove = this._onmousemove.bind(this); 10 | $super(element, options); 11 | this.element.addClassName('ui-draggable'); 12 | }, 13 | 14 | destroy: function($super) { 15 | this.element.removeClassName('ui-draggable'); 16 | $super(); 17 | }, 18 | 19 | "handle/onmousedown": function(event) { 20 | var element = this.element; 21 | this._startPointer = event.pointer(); 22 | this._startPosition = { 23 | left: window.parseInt(element.getStyle('left'), 10), 24 | top: window.parseInt(element.getStyle('top'), 10) 25 | }; 26 | document.observe('mousemove', this.__onmousemove); 27 | }, 28 | 29 | "handle/onmouseup": function(event) { 30 | this._startPointer = null; 31 | this._startPosition = null; 32 | document.stopObserving('mousemove', this.__onmousemove); 33 | }, 34 | 35 | _onmousemove: function(event) { 36 | var pointer = event.pointer(); 37 | 38 | // Can sometimes happen if the pointer exited the window during 39 | // mousedown. 40 | if (!this._startPointer) return; 41 | 42 | var delta = { 43 | x: pointer.x - this._startPointer.x, 44 | y: pointer.y - this._startPointer.y 45 | }; 46 | 47 | var newPosition = { 48 | left: (this._startPosition.left + delta.x) + 'px', 49 | top: (this._startPosition.top + delta.y) + 'px' 50 | }; 51 | 52 | this.element.setStyle(newPosition); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /src/ui/behaviors/focus.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior.Focus < S2.UI.Behavior 3 | * 4 | * Applies a focus behavior. Adds a `ui-state-focus` class to any 5 | * non-disabled element when focused. 6 | **/ 7 | S2.UI.Behavior.Focus = Class.create(S2.UI.Behavior, { 8 | onfocus: function(event) { 9 | if (this.element.hasClassName('ui-state-disabled')) return; 10 | this.element.addClassName('ui-state-focus'); 11 | }, 12 | 13 | onblur: function(event) { 14 | if (this.element.hasClassName('ui-state-disabled')) return; 15 | this.element.removeClassName('ui-state-focus'); 16 | } 17 | }); -------------------------------------------------------------------------------- /src/ui/behaviors/hover.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior.Hover < S2.UI.Behavior 3 | * 4 | * Applies a hover behavior. Adds a `ui-state-hover` class to any 5 | * non-disabled element when hovered over. 6 | **/ 7 | S2.UI.Behavior.Hover = Class.create(S2.UI.Behavior, { 8 | onmouseenter: function(event) { 9 | if (this.element.hasClassName('ui-state-disabled')) return; 10 | this.element.addClassName('ui-state-hover'); 11 | }, 12 | 13 | onmouseleave: function(event) { 14 | if (this.element.hasClassName('ui-state-disabled')) return; 15 | this.element.removeClassName('ui-state-hover'); 16 | } 17 | }); -------------------------------------------------------------------------------- /src/ui/behaviors/resize.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * class S2.UI.Behavior.Resize < S2.UI.Behavior 3 | **/ 4 | S2.UI.Behavior.Resize = Class.create(S2.UI.Behavior, { 5 | initialize: function(element, options) { 6 | } 7 | }); -------------------------------------------------------------------------------- /src/ui/controls.js: -------------------------------------------------------------------------------- 1 | 2 | //= require "controls/base" 3 | 4 | //= require "controls/accordion" 5 | //= require "controls/button" 6 | //= require "controls/button_set" 7 | //= require "controls/button_with_menu" 8 | //= require "controls/tabs" 9 | //= require "controls/overlay" 10 | //= require "controls/dialog" 11 | //= require "controls/slider" 12 | //= require "controls/progress_bar" 13 | //= require "controls/menu" 14 | //= require "controls/autocompleter" -------------------------------------------------------------------------------- /src/ui/controls/base.js: -------------------------------------------------------------------------------- 1 | (function(UI) { 2 | 3 | /** section: scripty2 ui 4 | * class S2.UI.Base 5 | * includes S2.UI.Mixin.Configurable 6 | * 7 | * A base class for all UI widgets. 8 | **/ 9 | UI.Base = Class.create(UI.Mixin.Configurable, { 10 | NAME: "S2.UI.Base", 11 | 12 | initialize: Function.ABSTRACT, 13 | 14 | /** 15 | * S2.UI.Base#addObservers() -> undefined 16 | **/ 17 | addObservers: Function.ABSTRACT, 18 | 19 | /** 20 | * S2.UI.Base#removeObservers() -> undefined 21 | **/ 22 | removeObservers: function() { 23 | if (this.__observers) { 24 | this.__observers.invoke('stop'); 25 | this.__observers = null; 26 | } 27 | }, 28 | 29 | /** 30 | * S2.UI.Base#destroy() -> undefined 31 | **/ 32 | destroy: function() { 33 | this.removeObservers(); 34 | }, 35 | 36 | /** 37 | * S2.UI.Base#toElement() -> Element | null 38 | * 39 | * Returns the DOM element corresponding to this control. 40 | * 41 | * By default, this returns the instance's `element` property, but 42 | * widgets can override this behavior. 43 | **/ 44 | toElement: function() { 45 | return this.element || null; 46 | }, 47 | 48 | /** 49 | * S2.UI.Base#inspect() -> String 50 | * 51 | * Returns a debug-friendly string representation of the widget. 52 | **/ 53 | inspect: function() { 54 | return "#<#{NAME}>".interpolate(this); 55 | } 56 | }); 57 | 58 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/controls/button_set.js: -------------------------------------------------------------------------------- 1 | (function(UI) { 2 | 3 | UI.ButtonSet = Class.create(UI.Base, { 4 | NAME: "S2.UI.ButtonSet", 5 | 6 | initialize: function(element, options) { 7 | this.element = $(element); 8 | this.element.store('ui.buttonset', this); 9 | var opt = this.setOptions(options); 10 | 11 | this.element.addClassName('ui-buttonset'); 12 | this.refresh(); 13 | 14 | this.observers = { 15 | toggle: this._toggle.bind(this) 16 | }; 17 | this.addObservers(); 18 | }, 19 | 20 | addObservers: function() { 21 | this.element.observe('ui:button:toggle', this.observers.toggle); 22 | }, 23 | 24 | removeObservers: function() { 25 | this.element.stopObserving('ui:button:toggle', this.observers.toggle); 26 | }, 27 | 28 | destroy: function() { 29 | this.removeObservers(); 30 | this.element.removeClassName('ui-buttonset'); 31 | UI.removeClassNames(this.buttons, 'ui-corner-left ui-corner-right'); 32 | 33 | this.element.getStorage().unset('ui.buttonset'); 34 | }, 35 | 36 | _destroyButton: function(el) { 37 | var instance = el.retrieve('ui.button'); 38 | if (instance) instance.destroy(); 39 | }, 40 | 41 | _toggle: function(event) { 42 | var element = event.element(), instance = element.retrieve('ui.button'); 43 | if (!instance || instance.type !== 'radio') return; 44 | 45 | // If this is a set of radio buttons, enforce these rules: 46 | // * Can't toggle a button off by clicking on it while it's active. 47 | // * Only one button can be toggled on at any given time. 48 | if (instance.isActive()) { 49 | event.stop(); 50 | return; 51 | } 52 | 53 | // If we get this far, it means the button that has been clicked on is 54 | // non-active and will become active when we return from this handler. 55 | // So we ensure all other buttons in the set are inactive. The button's 56 | // own handler takes care of the rest. 57 | this.instances.each( function(b) { 58 | b._setActive(false); 59 | }); 60 | }, 61 | 62 | refresh: function() { 63 | // Ensure there is no space between adjacent buttons. 64 | this.element.cleanWhitespace(); 65 | 66 | this.buttons = []; 67 | 68 | this.element.descendants().each( function(el) { 69 | var isButton = false; 70 | if ($w('SELECT BUTTON A').include(el.nodeName.toUpperCase())) 71 | isButton = true; 72 | if (el.match('input') && el.type !== 'hidden') isButton = true; 73 | if (el.hasClassName('ui-button')) isButton = true; 74 | 75 | if (isButton) this.buttons.push(el); 76 | }, this); 77 | 78 | this.instances = this.buttons.map( function(el) { 79 | var instance = el.retrieve('ui.button'); 80 | if (!instance) instance = new UI.Button(el); 81 | return instance; 82 | }); 83 | 84 | this.instances.each( function(b) { 85 | UI.removeClassNames(b.toElement(), 86 | 'ui-corner-all ui-corner-left ui-corner-right'); 87 | }); 88 | 89 | if (this.instances.length > 0) { 90 | this.instances.first().toElement().addClassName('ui-corner-left'); 91 | this.instances.last().toElement().addClassName('ui-corner-right'); 92 | } 93 | } 94 | }); 95 | 96 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/controls/button_with_menu.js: -------------------------------------------------------------------------------- 1 | (function(UI) { 2 | 3 | UI.ButtonWithMenu = Class.create(UI.Button, { 4 | initialize: function($super, element, options) { 5 | $super(element, options); 6 | var opt = this.setOptions(options); 7 | 8 | this.menu = new UI.Menu(); 9 | this.element.insert({ after: this.menu }); 10 | 11 | if (opt.choices) { 12 | opt.choices.each(this.menu.addChoice, this.menu); 13 | } 14 | 15 | (function() { 16 | var iLayout = this.element.getLayout(); 17 | 18 | this.menu.setStyle({ 19 | left: iLayout.get('left') + 'px', 20 | top: (iLayout.get('top') + iLayout.get('margin-box-height')) + 'px' 21 | }); 22 | }).bind(this).defer(); 23 | 24 | Object.extend(this.observers, { 25 | clickForMenu: this._clickForMenu.bind(this), 26 | onMenuOpen: this._onMenuOpen.bind(this), 27 | onMenuClose: this._onMenuClose.bind(this), 28 | onMenuSelect: this._onMenuSelect.bind(this) 29 | }); 30 | 31 | this.observe('mousedown', this.observers.clickForMenu); 32 | 33 | this.menu.observe('ui:menu:after:open', this.observers.onMenuOpen ); 34 | this.menu.observe('ui:menu:after:close', this.observers.onMenuClose); 35 | this.menu.observe('ui:menu:selected', this.observers.onMenuSelect); 36 | }, 37 | 38 | _clickForMenu: function(event) { 39 | if (this.menu.isOpen()) { 40 | this.menu.close(); 41 | } else { 42 | this.menu.open(); 43 | } 44 | }, 45 | 46 | _onMenuOpen: function() { 47 | var menuElement = this.menu.element, buttonElement = this.toElement(); 48 | if (!this._clickOutsideMenuObserver) { 49 | this._clickOutsideMenuObserver = $(document.body).on('click', function(event) { 50 | var el = event.element(); 51 | if (el !== menuElement && !el.descendantOf(menuElement) && 52 | el !== buttonElement && !el.descendantOf(buttonElement)) { 53 | this.menu.close(); 54 | } 55 | }.bind(this)); 56 | } else { 57 | this._clickOutsideMenuObserver.start(); 58 | } 59 | }, 60 | 61 | _onMenuClose: function() { 62 | if (this._clickOutsideMenuObserver) 63 | this._clickOutsideMenuObserver.stop(); 64 | }, 65 | 66 | _onMenuSelect: function(event) { 67 | var element = event.element(); 68 | this.fire('ui:button:menu:selected', { 69 | instance: this, 70 | element: event.memo.element 71 | }); 72 | } 73 | }); 74 | 75 | 76 | Object.extend(UI.ButtonWithMenu, { 77 | DEFAULT_OPTIONS: { 78 | icons: { primary: 'ui-icon-bullet', secondary: 'ui-icon-triangle-1-s' } 79 | } 80 | }); 81 | 82 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/controls/overlay.js: -------------------------------------------------------------------------------- 1 | (function(UI) { 2 | 3 | /** section: scripty2 ui 4 | * class S2.UI.Overlay < S2.UI.Base 5 | * includes S2.UI.Mixin.Shim, S2.UI.Mixin.Trackable 6 | * 7 | * A class for display a modal overlay on screen. 8 | **/ 9 | 10 | UI.Overlay = Class.create( 11 | UI.Base, 12 | UI.Mixin.Trackable, 13 | UI.Mixin.Shim, { 14 | NAME: "S2.UI.Overlay", 15 | 16 | /** 17 | * new S2.UI.Overlay(options) 18 | **/ 19 | initialize: function(options) { 20 | this.setOptions(options); 21 | this.element = new Element('div', { 22 | 'class': 'ui-widget-overlay' 23 | }); 24 | 25 | this.register(); 26 | this.createShim(); 27 | this.adjustShim(); 28 | this.constructor.onResize(); 29 | }, 30 | 31 | destroy: function() { 32 | this.element.remove(); 33 | this.unregister(); 34 | }, 35 | 36 | toElement: function() { 37 | return this.element; 38 | } 39 | }); 40 | 41 | Object.extend(UI.Overlay, { 42 | onRegister: function() { 43 | if (this.instances.length !== 1) return; 44 | 45 | this._resizeObserver = this._resizeObserver || this.onResize.bind(this); 46 | Event.observe(window, 'resize', this._resizeObserver); 47 | Event.observe(window, 'scroll', this._resizeObserver); 48 | }, 49 | 50 | onUnregister: function() { 51 | if (this.instances.length !== 0) return; 52 | Event.stopObserving(window, 'resize', this._resizeObserver); 53 | Event.stopObserving(window, 'scroll', this._resizeObserver); 54 | }, 55 | 56 | onResize: function() { 57 | var vSize = document.viewport.getDimensions(); 58 | var offsets = document.viewport.getScrollOffsets(); 59 | this.instances.each( function(instance) { 60 | var element = instance.element; 61 | element.setStyle({ 62 | width: vSize.width + 'px', 63 | height: vSize.height + 'px', 64 | left: offsets.left + 'px', 65 | top: offsets.top + 'px' 66 | }); 67 | }); 68 | (function() { 69 | this.instances.invoke('adjustShim'); 70 | }).bind(this).defer(); 71 | } 72 | }); 73 | 74 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/controls/progress_bar.js: -------------------------------------------------------------------------------- 1 | (function(UI) { 2 | /** section: scripty2 ui 3 | * class S2.UI.ProgressBar < S2.UI.Base 4 | * 5 | * A progress bar. 6 | **/ 7 | UI.ProgressBar = Class.create(UI.Base, { 8 | NAME: "S2.UI.ProgressBar", 9 | 10 | /** 11 | * new S2.UI.ProgressBar(element, options) 12 | **/ 13 | initialize: function(element, options) { 14 | this.element = $(element); 15 | var opt = this.setOptions(options); 16 | 17 | UI.addClassNames(this.element, 'ui-progressbar ui-widget ' + 18 | 'ui-widget-content ui-corner-all'); 19 | 20 | // ARIA. 21 | this.element.writeAttribute({ 22 | 'role': 'progressbar', 23 | 'aria-valuemin': 0, 24 | 'aria-valuemax': 100, 25 | 'aria-valuenow': 0 26 | }); 27 | 28 | this.valueElement = new Element('div', { 29 | 'class': 'ui-progressbar-value ui-widget-header ui-corner-left' 30 | }); 31 | 32 | // Set the value before appending the element in order 33 | // to avoid a flicker. 34 | this.value = opt.value.initial; 35 | this._refreshValue(); 36 | 37 | this.element.insert(this.valueElement); 38 | this.element.store(this.NAME, this); 39 | }, 40 | 41 | destroy: function() { 42 | UI.removeClassNames(this.element, 'ui-progressbar ui-widget ' + 43 | 'ui-widget-content ui-corner-all'); 44 | UI.removeAttributes(this.element, 'role aria-valuemin aria-valuemax ' + 45 | 'aria-valuenow'); 46 | this.element.getData().unset(this.NAME); 47 | }, 48 | 49 | /** 50 | * S2.UI.ProgressBar#getValue() -> Number 51 | **/ 52 | getValue: function() { 53 | var value = this.value, v = this.options.value; 54 | if (value < v.min) value = v.min; 55 | if (value > v.max) value = v.max; 56 | return value; 57 | }, 58 | 59 | /** 60 | * S2.UI.ProgressBar#setValue() -> this 61 | **/ 62 | setValue: function(value) { 63 | this._oldValue = this.getValue(); 64 | this.value = value; 65 | this._refreshValue(); 66 | return this; 67 | }, 68 | 69 | /** 70 | * S2.UI.ProgressBar#undo() -> this 71 | * 72 | * Reverts the effect of the previous call to 73 | * [[S2.UI.ProgressBar#setValue]]. 74 | **/ 75 | undo: function() { 76 | this.undoing = true; 77 | this.setValue(this._oldValue); 78 | this.undoing = false; 79 | return this; 80 | }, 81 | 82 | _refreshValue: function() { 83 | var value = this.getValue(); 84 | if (!this.undoing) { 85 | // If the event is stopped, we undo the change. 86 | var result = this.element.fire('ui:progressbar:value:changed', { 87 | progressBar: this, 88 | value: value 89 | }); 90 | if (result.stopped) { 91 | this.undo(); 92 | return; 93 | } 94 | } 95 | if (value === this.options.value.max) { 96 | this.valueElement.addClassName('ui-corner-right'); 97 | } else { 98 | this.valueElement.removeClassName('ui-corner-right'); 99 | } 100 | 101 | 102 | var width = window.parseInt(this.element.getStyle('width'), 10); 103 | var newWidth = (width * value) / 100; 104 | var css = "width: #{0}px".interpolate([newWidth]); 105 | 106 | UI.makeVisible(this.valueElement, (value > this.options.value.min)); 107 | this.valueElement.morph(css, { duration: 0.7, transition: 'linear' }); 108 | this.element.writeAttribute('aria-valuenow', value); 109 | } 110 | }); 111 | 112 | Object.extend(UI.ProgressBar, { 113 | DEFAULT_OPTIONS: { 114 | value: { min: 0, max: 100, initial: 0 } 115 | } 116 | }); 117 | 118 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/controls/tabs.js: -------------------------------------------------------------------------------- 1 | 2 | (function(UI) { 3 | /** section: scripty2 ui 4 | * class S2.UI.Tabs < S2.UI.Base 5 | * 6 | * A set of tabs. 7 | **/ 8 | UI.Tabs = Class.create(UI.Base, { 9 | NAME: "S2.UI.Tabs", 10 | 11 | /** 12 | * new S2.UI.Tabs(element, options) 13 | **/ 14 | initialize: function(element, options) { 15 | this.element = $(element); 16 | UI.addClassNames(this.element, 17 | 'ui-widget ui-widget-content ui-tabs ui-corner-all'); 18 | 19 | this.setOptions(options); 20 | var opt = this.options; 21 | 22 | this.anchors = []; 23 | this.panels = []; 24 | 25 | this.list = this.element.down('ul'); 26 | this.list.cleanWhitespace(); 27 | this.nav = this.list; 28 | UI.addClassNames(this.nav, 29 | 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ' + 30 | 'ui-widget-header ui-corner-all'); 31 | 32 | this.tabs = this.list.select('li'); 33 | UI.addClassNames(this.tabs, 'ui-state-default ui-corner-top'); 34 | UI.addBehavior(this.tabs, [UI.Behavior.Hover, UI.Behavior.Down]); 35 | 36 | // ARIA. 37 | this.element.writeAttribute({ 38 | 'role': 'tablist', 39 | 'aria-multiselectable': 'false' 40 | }); 41 | 42 | // Look for an anchor inside each tab. If one exists and correlates 43 | // to a panel that exists in the document, add the anchor and panel 44 | // to their respective collections. 45 | this.tabs.each( function(li) { 46 | var anchor = li.down('a'); 47 | if (!anchor) return; 48 | 49 | var href = anchor.readAttribute('href'); 50 | if (!href.include('#')) return; 51 | 52 | var hash = href.split('#').last(), panel = $(hash); 53 | 54 | li.writeAttribute('tabIndex', '0'); 55 | 56 | if (panel) { 57 | panel.store('ui.tab', li); 58 | li.store('ui.panel', panel); 59 | 60 | this.anchors.push(anchor); 61 | this.panels.push(panel); 62 | } 63 | }, this); 64 | 65 | // ARIA. 66 | this.anchors.invoke('writeAttribute', 'role', 'tab'); 67 | this.panels.invoke('writeAttribute', 'role', 'tabpanel'); 68 | 69 | this.tabs.first().addClassName('ui-position-first'); 70 | this.tabs.last().addClassName('ui-position-last'); 71 | 72 | UI.addClassNames(this.panels, 73 | 'ui-tabs-panel ui-tabs-hide ui-widget-content ui-corner-bottom'); 74 | 75 | this.observers = { 76 | onKeyPress: this.onKeyPress.bind(this), 77 | onTabClick: this.onTabClick.bind(this) 78 | }; 79 | this.addObservers(); 80 | 81 | // Figure out which tab/panel should be active. 82 | var selectedTab; 83 | 84 | // If the URL hash points to one of our panels, that's the active one. 85 | var urlHash = window.location.hash.substring(1), activePanel; 86 | if (!urlHash.empty()) { 87 | activePanel = $(urlHash); 88 | } 89 | if (activePanel && this.panels.include(activePanel)) { 90 | selectedTab = activePanel.retrieve('ui.tab'); 91 | } else { 92 | // If not, we defer to the options, or otherwise the first tab. 93 | selectedTab = opt.selectedTab ? $(opt.selectedTab) : 94 | this.tabs.first(); 95 | } 96 | 97 | this.setSelectedTab(selectedTab); 98 | }, 99 | 100 | addObservers: function() { 101 | this.anchors.invoke('observe', 'click', this.observers.onTabClick); 102 | this.tabs.invoke('observe', 'keypress', this.observers.onKeyPress); 103 | }, 104 | 105 | _setSelected: function(id) { 106 | var panel = $(id), tab = panel.retrieve('ui.tab'); 107 | 108 | var oldTab = this.list.down('.ui-tabs-selected'); 109 | var oldPanel = oldTab ? oldTab.retrieve('ui.panel') : null; 110 | 111 | // Set the active tab. 112 | UI.removeClassNames(this.tabs, 'ui-tabs-selected ui-state-active'); 113 | UI.addClassNames(this.tabs, 'ui-state-default'); 114 | 115 | tab.removeClassName('ui-state-default').addClassName( 116 | 'ui-tabs-selected ui-state-active'); 117 | 118 | // Set the active panel. 119 | this.element.fire('ui:tabs:change', { 120 | from: { tab: oldTab, panel: oldPanel }, 121 | to: { tab: tab, panel: panel } 122 | }); 123 | this.options.panel.transition(oldPanel, panel); 124 | }, 125 | 126 | /** 127 | * S2.UI.Tabs#setSelectedTab(tab) -> undefined 128 | * - tab (Element): The tab to make active. 129 | **/ 130 | setSelectedTab: function(tab) { 131 | this.setSelectedPanel(tab.retrieve('ui.panel')); 132 | }, 133 | 134 | /** 135 | * S2.UI.Tabs#setSelectedPanel(panel) -> undefined 136 | * - panel (Element): The panel to make active. 137 | **/ 138 | setSelectedPanel: function(panel) { 139 | this._setSelected(panel.readAttribute('id')); 140 | }, 141 | 142 | onTabClick: function(event) { 143 | event.stop(); 144 | var anchor = event.findElement('a'), tab = event.findElement('li'); 145 | 146 | this.setSelectedTab(tab); 147 | }, 148 | 149 | onKeyPress: function(event) { 150 | if (UI.modifierUsed(event)) return; 151 | var tab = event.findElement('li'); 152 | var keyCode = event.keyCode || event.charCode; 153 | 154 | switch (keyCode) { 155 | case Event.KEY_SPACE: // fallthrough 156 | case Event.KEY_RETURN: 157 | this.setSelectedTab(tab); 158 | event.stop(); 159 | return; 160 | case Event.KEY_UP: // fallthrough 161 | case Event.KEY_LEFT: 162 | this._focusTab(tab, -1); 163 | return; 164 | case Event.KEY_DOWN: // fallthrough 165 | case Event.KEY_RIGHT: 166 | this._focusTab(tab, 1); 167 | return; 168 | } 169 | }, 170 | 171 | _focusTab: function(tab, delta) { 172 | // If delta is provided, move the specified number of slots. 173 | if (Object.isNumber(delta)) { 174 | var index = this.tabs.indexOf(tab); 175 | index = index + delta; 176 | if (index > (this.tabs.length - 1)) { 177 | index = this.tabs.length - 1; 178 | } else if (index < 0) { 179 | index = 0; 180 | } 181 | tab = this.tabs[index]; 182 | } 183 | (function() { tab.focus(); }).defer(); 184 | } 185 | }); 186 | 187 | Object.extend(UI.Tabs, { 188 | DEFAULT_OPTIONS: { 189 | panel: { 190 | transition: function(from, to) { 191 | if (from) { 192 | from.addClassName('ui-tabs-hide'); 193 | } 194 | to.removeClassName('ui-tabs-hide'); 195 | } 196 | } 197 | } 198 | }); 199 | })(S2.UI); -------------------------------------------------------------------------------- /src/ui/dragdrop.js: -------------------------------------------------------------------------------- 1 | //=require "dragdrop/draggable" 2 | //=require "dragdrop/droppable" -------------------------------------------------------------------------------- /src/ui/mixin.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * S2.UI.Mixin 3 | * 4 | * Reusable mixins for user interface elements. 5 | * 6 | * * [[S2.UI.Mixin.Configurable]] for hassle-free blending of 7 | * default options with user-defined options. 8 | * * [[S2.UI.Mixin.Trackable]] 9 | * * [[S2.UI.Mixin.Element]] provides convenience methods for widgets 10 | * that map easily to a single element. 11 | * * [[S2.UI.Mixin.Shim]] provides an implementation of a "shim" for Internet Explorer 6, 12 | * to avoid rendering z-order problems on that browser. 13 | * 14 | * Mixins can be easily added to your own controls. Here is some example code from 15 | * [[S2.UI.Button]]: 16 | * 17 | * S2.UI.Button = Class.create(S2.UI.Base, S2.UI.Mixin.Element, { 18 | * // ... 19 | * }); 20 | **/ 21 | S2.UI.Mixin = {}; 22 | 23 | //= require "mixin/configurable" 24 | //= require "mixin/trackable" 25 | //= require "mixin/element" 26 | 27 | //= require "mixin/shim" -------------------------------------------------------------------------------- /src/ui/mixin/configurable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Object.deepExtend(destination, source) -> Object 3 | * 4 | * A "deep" version of `Object.extend`. Performs a recursive deep extension. 5 | **/ 6 | 7 | Object.deepExtend = function(destination, source) { 8 | for (var property in source) { 9 | if (source[property] && source[property].constructor && 10 | source[property].constructor === Object) { 11 | destination[property] = destination[property] || {}; 12 | arguments.callee(destination[property], source[property]); 13 | } else { 14 | destination[property] = source[property]; 15 | } 16 | } 17 | return destination; 18 | }; 19 | 20 | /** section: scripty2 ui 21 | * mixin S2.UI.Mixin.Configurable 22 | * 23 | * A mixin for hassle-free blending of default options with user-defined 24 | * options. 25 | * 26 | * Expects default options to be defined in a `DEFAULT_OPTIONS` property 27 | * on the class itself. 28 | **/ 29 | S2.UI.Mixin.Configurable = { 30 | /** 31 | * S2.UI.Mixin.Configurable#setOptions(options) -> Object 32 | * - options (Object): A set of user-defined options that should override 33 | * the defaults. 34 | * 35 | * Sets options on the class. Can be called multiple times; will copy any 36 | * options defined in `options` onto an existing `this.options` property 37 | * (or will define that property if it does not exist). 38 | **/ 39 | setOptions: function(options) { 40 | if (!this.options) { 41 | this.options = {}; 42 | var constructor = this.constructor; 43 | if (constructor.superclass) { 44 | // Build the inheritance chain. 45 | var chain = [], klass = constructor; 46 | while (klass = klass.superclass) 47 | chain.push(klass); 48 | chain = chain.reverse(); 49 | 50 | for (var i = 0, l = chain.length; i < l; i++) 51 | Object.deepExtend(this.options, chain[i].DEFAULT_OPTIONS || {}); 52 | } 53 | 54 | Object.deepExtend(this.options, constructor.DEFAULT_OPTIONS || {}); 55 | } 56 | return Object.deepExtend(this.options, options || {}); 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /src/ui/mixin/element.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * mixin S2.UI.Mixin.Element 3 | * 4 | * Provides a few convenience methods for widgets that map easily to a 5 | * single element. 6 | * 7 | * The following methods are mapped from Prototype's `Element` API: 8 | * `observe`, `stopObserving`, `show`, `hide`, 9 | * `addClassName`, `removeClassName`, `hasClassName`, 10 | * `setStyle`, `getStyle`, `writeAttribute`, `readAttribute`, 11 | * `on`, and `fire`. 12 | * 13 | * See http://api.prototypejs.org/dom/element/ 14 | * for more information. 15 | **/ 16 | 17 | (function() { 18 | var METHODS = $w('observe stopObserving show hide ' + 19 | 'addClassName removeClassName hasClassName setStyle getStyle' + 20 | 'writeAttribute readAttribute fire'); 21 | 22 | var E = {}; 23 | 24 | METHODS.each( function(name) { 25 | E[name] = function() { 26 | var element = this.toElement(); 27 | return element[name].apply(element, arguments); 28 | }; 29 | }); 30 | 31 | E.on = function() { 32 | if (!this.__observers) this.__observers = []; 33 | var element = this.toElement(); 34 | var result = element.on.apply(element, arguments); 35 | this.__observers.push(result); 36 | }; 37 | 38 | window.S2.UI.Mixin.Element = E; 39 | })(); 40 | 41 | -------------------------------------------------------------------------------- /src/ui/mixin/shim.js: -------------------------------------------------------------------------------- 1 | /** section: scripty2 ui 2 | * mixin S2.UI.Mixin.Shim 3 | * 4 | * Provides an implementation of a "shim" for Internet Explorer 6. On that browser, 5 | * some elements (like SELECT boxes) do not adhere to vertical CSS order 6 | * rules or setting z-index, because they are rendered as an OS "window", 7 | * which is always above all other elements. 8 | * 9 | * The solution used to solve this problem is drawing an empty IFRAME element 10 | * in the background of the element that should be displayed above all other 11 | * elements, acting as a "shim". 12 | * 13 | * The shim will automatically adjust itself to any changes in the parent element's 14 | * size or position. A positioning and/or size change can also be forced manually 15 | * by calling `adjustShim`. 16 | **/ 17 | S2.UI.Mixin.Shim = { 18 | __SHIM_TEMPLATE: new Template( 19 | "" 27 | ), 28 | 29 | /** 30 | * S2.UI.Mixin.Shim#createShim([element]) -> undefined 31 | * - element (Element): Optional element to shim. If omitted, will assume 32 | * `this.element`. 33 | * 34 | * Create an IFRAME "shim" underneath the positioned element. 35 | * 36 | * Needed for IE6, which otherwise shows some UI controls (like SELECT 37 | * boxes) _above_ an element, regardless of its CSS z-index. 38 | * 39 | * Does nothing in other browsers. 40 | **/ 41 | createShim: function(element) { 42 | // Only needed for IE 6. 43 | this.__shim_isie6 = (Prototype.Browser.IE && 44 | (/6.0/).test(navigator.userAgent)); 45 | if (!this.__shim_isie6) return; 46 | 47 | element = $(element || this.element); 48 | if (!element) return; 49 | 50 | // The element we're sticking a shim underneath. 51 | this.__shimmed = element; 52 | 53 | var id = element.identify() + '_iframeshim', shim = $(id); 54 | 55 | // Clean up any shim that may exist already. 56 | if (shim) shim.remove(); 57 | 58 | element.insert({ 59 | top: this.__SHIM_TEMPLATE.evaluate([id]) 60 | }); 61 | 62 | this.__shim_id = id; 63 | }, 64 | 65 | /** 66 | * S2.UI.Mixin.Shim.adjustShim() -> undefined 67 | * 68 | * Reposition the shim, copying the dimensions and offsets of the target 69 | * element. 70 | * 71 | * Note that the [[S2.UI.Mixin.Shim]] mixin _attempts_ to do this 72 | * automatically by using IE6's proprietary CSS expressions. But because 73 | * such expressions can sometimes fail to update promptly, calling this 74 | * method yourself may be necessary. 75 | * 76 | * Once you've called `adjustShim`, the shim loses the ability to 77 | * dynamically update its position on its own. Subsequently, you'll have 78 | * to call `adjustShim` again each time you update the element's layout. 79 | **/ 80 | adjustShim: function() { 81 | if (!this.__shim_isie6) return; 82 | var shim = this.__shimmed.down('iframe#' + this.__shim_id); 83 | var element = this.__shimmed; 84 | if (!shim) return; 85 | 86 | shim.setStyle({ 87 | width: element.offsetWidth + 'px', 88 | height: element.offsetHeight + 'px' 89 | }); 90 | }, 91 | 92 | /** 93 | * S2.UI.Mixin.Shim#destroyShim() -> undefined 94 | * 95 | * Removes the shim. 96 | **/ 97 | destroyShim: function() { 98 | if (!this.__shim_isie6) return; 99 | var shim = this.__shimmed.down('iframe#' + this.__shim_id); 100 | if (shim) { 101 | shim.remove(); 102 | } 103 | 104 | this.__shimmed = null; 105 | } 106 | }; -------------------------------------------------------------------------------- /src/ui/mixin/trackable.js: -------------------------------------------------------------------------------- 1 | 2 | /** section: scripty2 ui 3 | * mixin S2.UI.Mixin.Trackable 4 | **/ 5 | S2.UI.Mixin.Trackable = { 6 | /** 7 | * S2.UI.Mixin.Trackable.register() -> undefined 8 | **/ 9 | register: function() { 10 | var klass = this.constructor; 11 | if (!klass.instances) { 12 | klass.instances = []; 13 | } 14 | if (!klass.instances.include(this)) { 15 | klass.instances.push(this); 16 | } 17 | 18 | if (Object.isFunction(klass.onRegister)) { 19 | klass.onRegister.call(klass, this); 20 | } 21 | }, 22 | 23 | /** 24 | * S2.UI.Mixin.Trackable.unregister() -> undefined 25 | **/ 26 | unregister: function() { 27 | var klass = this.constructor; 28 | klass.instances = klass.instances.without(this); 29 | if (Object.isFunction(klass.onRegister)) { 30 | klass.onUnregister.call(klass, this); 31 | } 32 | } 33 | }; -------------------------------------------------------------------------------- /templates/html/assets/images/cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/cc.png -------------------------------------------------------------------------------- /templates/html/assets/images/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/class.png -------------------------------------------------------------------------------- /templates/html/assets/images/class_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/class_method.png -------------------------------------------------------------------------------- /templates/html/assets/images/constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/constructor.png -------------------------------------------------------------------------------- /templates/html/assets/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/demo.png -------------------------------------------------------------------------------- /templates/html/assets/images/description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/description.png -------------------------------------------------------------------------------- /templates/html/assets/images/header-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/header-logo.png -------------------------------------------------------------------------------- /templates/html/assets/images/instance_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/instance_method.png -------------------------------------------------------------------------------- /templates/html/assets/images/manipulate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/manipulate.png -------------------------------------------------------------------------------- /templates/html/assets/images/method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/method.png -------------------------------------------------------------------------------- /templates/html/assets/images/namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/namespace.png -------------------------------------------------------------------------------- /templates/html/assets/images/section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/section.png -------------------------------------------------------------------------------- /templates/html/assets/images/subclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/subclass.png -------------------------------------------------------------------------------- /templates/html/assets/images/superclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/templates/html/assets/images/superclass.png -------------------------------------------------------------------------------- /templates/html/helpers.rb: -------------------------------------------------------------------------------- 1 | require 'coderay' 2 | class BlueCloth 3 | def transform_code_blocks( str, rs ) 4 | str.gsub( CodeBlockRegexp ) do |block| 5 | CodeRay.scan( outdent($1).rstrip, :javascript ).div + $2 6 | end 7 | end 8 | end 9 | 10 | module PDoc 11 | module Generators 12 | module Html 13 | module Helpers 14 | module BaseHelper 15 | def content_tag(tag_name, content, attributes = {}) 16 | "<#{tag_name}#{attributes_to_html(attributes)}>#{content}" 17 | end 18 | 19 | def img_tag(filename, attributes = {}) 20 | attributes.merge! :src => "#{path_prefix}images/#{filename}" 21 | tag(:img, attributes) 22 | end 23 | 24 | def tag(tag_name, attributes = {}) 25 | "<#{tag_name}#{attributes_to_html(attributes)} />" 26 | end 27 | 28 | def link_to(name, path, attributes={}) 29 | content_tag(:a, name, attributes.merge(:href => path)) 30 | end 31 | 32 | def htmlize(markdown) 33 | BlueCloth.new(markdown).to_html 34 | end 35 | 36 | # Gah, what an ugly hack. 37 | def inline_htmlize(markdown) 38 | htmlize(markdown).gsub(/^

/, '').gsub(/<\/p>$/, '') 39 | end 40 | 41 | def javascript_include_tag(*names) 42 | names.map do |name| 43 | attributes = { 44 | :src => "#{path_prefix}javascripts/#{name}.js", 45 | :type => "text/javascript", 46 | :charset => "utf-8" 47 | } 48 | content_tag(:script, "", attributes) 49 | end.join("\n") 50 | end 51 | 52 | def stylesheet_link_tag(*names) 53 | names.map do |name| 54 | attributes = { 55 | :href => "#{path_prefix}stylesheets/#{name}.css", 56 | :type => "text/css", 57 | :media => "screen, projection", 58 | :charset => "utf-8", 59 | :rel => "stylesheet" 60 | } 61 | tag(:link, attributes) 62 | end.join("\n") 63 | end 64 | 65 | private 66 | def attributes_to_html(attributes) 67 | attributes.map { |k, v| v ? " #{k}=\"#{v}\"" : "" }.join 68 | end 69 | end 70 | 71 | module LinkHelper 72 | def path_prefix 73 | "../" * depth 74 | end 75 | 76 | def path_to(obj) 77 | return path_to_section(obj) if obj.is_a?(Documentation::Section) 78 | path = path_prefix << [obj.section.name.downcase].concat(obj.namespace_string.downcase.split('.')).join("/") 79 | has_own_page?(obj) ? "#{path}/#{obj.id.downcase}.html" : "#{path}.html##{dom_id(obj)}" 80 | end 81 | 82 | def path_to_section(obj) 83 | "#{path_prefix}#{obj.id.gsub(/\s/, '_')}.html" 84 | end 85 | 86 | def section_from_name(name) 87 | root.sections.find { |section| section.name == name } 88 | end 89 | 90 | def auto_link(obj, short = true, attributes = {}) 91 | if obj.is_a?(String) && obj =~ /\ssection$/ 92 | obj = section_from_name(obj.gsub(/\ssection$/, '')) 93 | end 94 | obj = root.find_by_name(obj) || obj if obj.is_a?(String) 95 | return nil if obj.nil? 96 | return obj if obj.is_a?(String) 97 | name = short ? obj.name : obj.full_name 98 | link_to(name, path_to(obj), { :title => "#{obj.full_name} (#{obj.type})" }.merge(attributes)) 99 | end 100 | 101 | def auto_link_code(obj, short = true, attributes = {}) 102 | return "#{auto_link(obj, short, attributes)}" 103 | end 104 | 105 | def auto_link_content(content) 106 | content ||= '' 107 | content.gsub!(/\[\[([a-zA-Z]+)\s+section\]\]/) do |m| 108 | result = auto_link(section_from_name($1), false) 109 | result 110 | end 111 | content.gsub(/\[\[([a-zA-Z0-9$\.#]+)(?:\s+([^\]]+))?\]\]/) do |m| 112 | if doc_instance = root.find_by_name($1) 113 | $2 ? link_to($2, path_to(doc_instance)) : 114 | auto_link_code(doc_instance, false) 115 | else 116 | $1 117 | end 118 | end 119 | end 120 | 121 | def dom_id(obj) 122 | "#{obj.id}-#{obj.type.gsub(/\s+/, '_')}" 123 | end 124 | 125 | private 126 | def has_own_page?(obj) 127 | obj.is_a?(Documentation::Namespace) || obj.is_a?(Documentation::Utility) 128 | end 129 | end 130 | 131 | module CodeHelper 132 | def method_synopsis(object) 133 | if (object.is_a?(Documentation::Property)) 134 | return <<-EOS 135 |

#{ object.signature }
136 | EOS 137 | end 138 | 139 | if (object.is_a?(Documentation::InstanceMethod) && object.methodized?) 140 | return <<-EOS 141 |
#{ object.signature } -> #{ auto_link(object.returns, false) }
142 | #{ object.generic_signature } -> #{ auto_link(object.returns, false) }
143 | EOS 144 | end 145 | 146 | <<-EOS 147 |
#{ object.signature } -> #{ auto_link(object.returns, false) }
148 | EOS 149 | end 150 | end 151 | 152 | module MenuHelper 153 | def menu(obj) 154 | class_names = menu_class_name(obj) 155 | html = <<-EOS 156 | 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 |

23 |
24 | 25 | 26 |
27 |
28 |

Sections

29 |
30 | 31 |
32 |
    33 | <% @root.sections.each do |section| %> 34 |
  • 35 |

    36 | <%= section.name %> 37 |

    38 |

    <%= htmlize(section.short_description) %>

    39 |
  • 40 | <% end %> 41 |
42 |
43 |
44 | 45 |
46 |
47 |

Getting started

48 |
49 | 50 |
51 |
    52 |
  • 53 |

    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 |

    <script src="prototype.s2.min.js" type="text/javascript"></script>
    60 |

    61 |

    62 | For debugging, you can also include the libraries seperately: 63 |

    <script src="prototype.js" type="text/javascript"></script>
     64 | <script src="s2.js" type="text/javascript"></script>
    65 |

    66 |
  • 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |

UI Controls

75 |
76 | 77 |
78 |

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.

79 |
80 | 81 |
82 | 83 |
84 |
85 |

Tutorials & Demos

86 |
87 | 88 |
89 | 99 |
100 |
101 | 102 |
103 |
104 |

Help & Community

105 |
106 | 107 |
108 | 123 |
124 |
125 | -------------------------------------------------------------------------------- /templates/html/item_index.js.erb: -------------------------------------------------------------------------------- 1 | if (!window.PDoc) window.PDoc = {}; 2 | PDoc.elements = { 3 | <%= @root.map { |e, i| 4 | "'#{e.full_name}': { 'name': '#{e.full_name}', 'type': '#{e.type}', 'path': '#{path_to(e)}' }" }.join(",\n") 5 | %> 6 | }; -------------------------------------------------------------------------------- /templates/html/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | scripty2 API documentation | <%= @title %> 6 | <%= stylesheet_link_tag "apidocs" %> 7 | 8 | 9 |
10 | 11 |
12 |
13 | 14 |

scripty2

15 |
16 | 32 |
33 |
34 | 35 |
36 | <%= @content_for_layout %> 37 |
38 | 39 | 58 |
59 | 60 | <%= javascript_include_tag "prototype", "s2" %> 61 | <%= javascript_include_tag "application" %> 62 | <%= javascript_include_tag "item_index" %> 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /templates/html/namespace.erb: -------------------------------------------------------------------------------- 1 | <% d = @doc_instance %> 2 | <% @title = "#{d.full_name} #{d.type}" %> 3 | <%= include "partials/breadcrumbs", :object => d %> 4 | 5 |

6 | <%= d.type %> <%= d.full_name %> 7 |

8 | 9 | <% if d.description && !d.description.empty? %> 10 |
11 |
12 |

Description

13 |
14 |
15 | <%= htmlize(d.description) %> 16 |
17 |
18 | <% end %> 19 | 20 | <% if @doc_instance.is_a?(Documentation::Klass) %> 21 | <% if @doc_instance.superklass %> 22 |
23 |
24 |

Superclass

25 |
26 |
27 |

<%= auto_link_code(d.superklass, false) %>

28 |
29 |
30 | <% end %> 31 | 32 | <% unless @doc_instance.subklasses.empty? %> 33 |
34 |
35 |

Subclasses

36 |
37 |
38 |

<%= d.subklasses.map { |s| auto_link_code(s, false) }.join(', ') %>

39 |
40 |
41 | <% end %> 42 | <% end %> 43 | 44 | <% unless @doc_instance.mixins.empty? %> 45 |
46 |
47 |

Includes

48 |
49 |
50 |

<%= d.mixins.map { |m| auto_link_code(m, false) }.join(', ') %>

51 |
52 |
53 | <% end %> 54 | 55 | <% unless @doc_instance.related_utilities.empty? %> 56 |
57 |
58 |

Related utilities

59 |
60 |
61 |

<%= d.related_utilities.map { |u| auto_link_code(u, false) }.join(', ') %>

62 |
63 |
64 | <% end %> 65 | 66 | <% unless d.all_methods.empty? && d.mixins.empty? %> 67 |
68 |
69 |

Methods

70 |
71 |
72 |
    73 | <% d.all_methods.each do |method| %> 74 |
  • <%= auto_link_code(method, true, :class => class_names_for(method)) %>
  • 75 | <% end %> 76 |
77 | <% unless @doc_instance.mixins.empty? %> 78 | <% d.mixins.each do |mixin| %> 79 |

Inherited from <%= auto_link(mixin) %>

80 |
    81 | <% mixin.all_methods.each do |method| %> 82 |
  • <%= auto_link_code(method, true, :class => class_names_for(method)) %>
  • 83 | <% end %> 84 |
85 | <% end %> 86 | <% end %> 87 |
88 |
89 | <% end %> 90 | 91 | <% if d.is_a?(Documentation::Klass) && d.constructor %> 92 |
93 |
94 |

Constructor

95 |
96 |
97 |
<%= d.constructor.ebnf_expressions.join("\n").strip %>
98 | <% unless d.constructor.arguments.empty? %> 99 |
    100 | <% d.constructor.arguments.each do |arg| %> 101 |
  • 102 | <%= arg.name %> 103 | <% unless arg.types.empty? %> 104 | (<%= arg.types.map { |t| auto_link_code(t, false) }.join(' | ') %>) 105 | <% end %> 106 | <%= ' – ' + inline_htmlize(arg.description) unless arg.description.empty? %> 107 |
  • 108 | <% end %> 109 |
110 | <% end %> 111 |

<%= htmlize(d.constructor.description) %>

112 |
113 |
114 | <% end %> 115 | 116 | <% 117 | types = { 118 | :constants => "Constants", 119 | :klass_methods => "Class methods", 120 | :klass_properties => "Class properties", 121 | :instance_methods => "Instance methods", 122 | :instance_properties => "Instance properties" 123 | } 124 | %> 125 | 126 | <% types.each do |method, title| %> 127 | <% methods = d.send(method) %> 128 | <% unless methods.empty? %> 129 |
130 |
131 |

<%= title %>

132 |
133 |
134 |
    135 | <%= include "partials/short_description", :collection => methods %> 136 |
137 |
138 |
139 | <% end %> 140 | <% end %> -------------------------------------------------------------------------------- /templates/html/partials/breadcrumbs.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/html/partials/short_description.erb: -------------------------------------------------------------------------------- 1 |
  • 2 |

    <%= object.name %> 3 | #

    4 | 5 | <% if object.respond_to? :signature %> 6 | <%= method_synopsis(object) %> 7 | <% end %> 8 | 9 | <% if object.is_a?(Documentation::Method) %> 10 | <% unless object.arguments.empty? %> 11 |
      12 | <% object.arguments.each do |arg| %> 13 |
    • 14 | <%= arg.name %> 15 | <% unless arg.types.empty? %> 16 | (<%= arg.types.map { |t| auto_link_code(t, false) }.join(' | ') %>) 17 | <% end %> 18 | <%= ' – ' + inline_htmlize(arg.description) unless arg.description.empty? %> 19 |
    • 20 | <% end %> 21 |
    22 | <% end %> 23 | <% end %> 24 | 25 | <%= htmlize(object.description) %> 26 | 27 | <% unless object.aliases.empty? %> 28 |

    Aliased as: <%= object.aliases.map { |a| auto_link_code(a, false) }.join(', ') %>

    29 | <% end %> 30 | <% if object.alias? %> 31 |

    Alias of: <%= auto_link_code(object.alias_of, false) %>

    32 | <% end %> 33 | <% if object.is_a?(Documentation::Utility) && object.related_to %> 34 | 36 | <% end %> 37 | <% if object.is_a?(Documentation::Method) && object.methodized? %> 38 |

    This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.

    39 | <% end %> 40 |
  • 41 | -------------------------------------------------------------------------------- /templates/html/section.erb: -------------------------------------------------------------------------------- 1 | <% @title = "#{@doc_instance.full_name}" %> 2 | <% section = @doc_instance %> 3 | <%= include "partials/breadcrumbs", :object => section %> 4 | 5 |

    6 | Section <%= section.name %> 7 |

    8 | 9 |
    10 |
    11 |

    Description

    12 |
    13 |
    14 | <%= htmlize(section.description) %> 15 |
    16 |
    17 | 18 | <% utilities = section.utilities %> 19 | <% unless utilities.empty? %> 20 |
    21 |
    22 |

    Utilities

    23 |
    24 |
    25 |
      26 | <% utilities.each do |utility| %> 27 |
    • <%= auto_link_code(utility) %>
    • 28 | <% end %> 29 |
    30 |
    31 |
    32 | <% end %> 33 | 34 | <% namespaces = section.namespaces %> 35 | <% unless namespaces.empty? %> 36 |
    37 |
    38 |

    Namespaces

    39 |
    40 |
    41 |
      42 | <% namespaces.each do |namespace| %> 43 |
    • 44 |

      45 | <%= namespace.full_name %> 46 |

      47 | <% unless namespace.short_description.nil? %> 48 |

      <%= htmlize(namespace.short_description) %>

      49 | <% end %> 50 |
    • 51 | <% end %> 52 |
    53 |
    54 |
    55 | <% end %> 56 | 57 | <% klasses = section.klasses %> 58 | <% unless klasses.empty? %> 59 |
    60 |
    61 |

    Classes

    62 |
    63 |
    64 |
      65 | <% klasses.each do |klass| %> 66 |
    • 67 |

      68 | <%= klass.full_name %> 69 |

      70 | <% unless klass.short_description.nil? %> 71 |

      <%= htmlize(klass.short_description) %>

      72 | <% end %> 73 |
    • 74 | <% end %> 75 |
    76 |
    77 |
    78 | <% end %> -------------------------------------------------------------------------------- /templates/html/utility.erb: -------------------------------------------------------------------------------- 1 | <% d = @doc_instance %> 2 | <% @title = "#{@doc_instance.full_name} utility" %> 3 | <%= include "partials/breadcrumbs", :object => d %> 4 | 5 |

    6 | utility <%= @doc_instance.name %> 7 |

    8 | 9 |
    10 |
    11 |

    Description

    12 |
    13 | 14 |
    15 |
      16 | <%= include "partials/short_description", :collection => [@doc_instance] %> 17 |
    18 |
    19 |
    -------------------------------------------------------------------------------- /test/functional/controls_accordion.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
    23 | 34 |
    35 | 36 | 53 |

    Accordion Tests

    54 | 55 | 56 | 57 |

    Standard accordion

    58 | 59 |
    60 |

    Section 1

    61 |
    62 |

    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.

    63 |
    64 | 65 |

    Section 2

    66 |
    67 |

    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.

    68 |
    69 | 70 |

    Section 3

    71 |
    72 |

    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.
    • 95 |
    96 |
    97 | 98 | 99 | 100 |

    Multiple open at once

    101 | 102 |
    103 |

    Section 1

    104 |
    105 |

    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.

    106 |
    107 | 108 |

    Section 2

    109 |
    110 |

    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.

    111 |
    112 | 113 |

    Section 3

    114 |
    115 |

    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.
    • 133 |
    • Clicking on the active header should collapse it.
    • 134 |
    135 |
    136 | 137 | -------------------------------------------------------------------------------- /test/functional/controls_overlay.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

    Overlay Tests

    15 | 16 |

    Standard overlay

    17 | 18 |
    19 | 20 |
    (click the overlay to remove) 21 |
    22 | 23 |
    24 |
      25 |
    • 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 |

    35 | 36 | 45 | 46 | -------------------------------------------------------------------------------- /test/functional/controls_progress_bar.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 | 32 |
    33 | 34 | 51 |

    Progress Bar Tests

    52 | 53 |

    Standard progress bar

    54 | 55 |
    56 | 57 | 58 |
    59 | 60 |
    61 | 62 | 73 | 74 |
    75 |

    A standard progress bar with all the default options.

    76 |
    77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /test/functional/controls_tabs.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 | 32 |
    33 | 34 | 51 |

    Tabs Tests

    52 | 53 |

    Standard tabs

    54 |
    55 | 60 |
    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.

    72 | 73 |
    74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/functional/css/test.css: -------------------------------------------------------------------------------- 1 | body, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li { 2 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | } 4 | 5 | body { 6 | font-size: 0.8em; 7 | padding-top: 20px; 8 | } 9 | 10 | code, tt, kbd { 11 | /* ANYTHING BUT COURIER */ 12 | font-family: 'Panic Sans', 'Bitstream Vera Sans Mono', Menlo, Monaco, 'Andale Mono', 'Lucida Console', monospace; 13 | font-size: 12px; 14 | } 15 | 16 | h1 code, h2 code, h3 code { 17 | font-size: 100%; 18 | } 19 | 20 | kbd { 21 | color: #fff; 22 | background: #65450d; 23 | border: 1px solid #65450d; 24 | padding: 1px; 25 | } 26 | 27 | h1.logo { 28 | width: 175px; 29 | height: 54px; 30 | background: transparent url(../images/header-logo-small.png) no-repeat 50% 50%; 31 | margin: 0 auto; 32 | } 33 | 34 | h1.logo span { display: none; } 35 | 36 | .navigation { 37 | background: #6c8f3f; 38 | color: #fff; 39 | } 40 | 41 | .navigation h2 { 42 | text-align: center; 43 | margin: 0 0 10px; 44 | } 45 | 46 | .test-list { 47 | border: 5px solid #fff; 48 | -moz-border-radius: 5px; 49 | -webkit-border-radius: 5px; 50 | border-radius: 5px; 51 | 52 | -moz-box-shadow: 0 0 3px #000; 53 | -webkit-box-shadow: 0 0 3px #000; 54 | 55 | padding: 5px; 56 | background: #e3ffbe; 57 | color: #65450d; 58 | } 59 | 60 | .test-list h3 { 61 | color: #ff9c00; 62 | font-size: 23px; 63 | margin: 0 0 5px; 64 | } 65 | 66 | .test-list ul { 67 | list-style: none; 68 | margin: 0 0 10px; 69 | padding: 0 0 0 5px; 70 | } 71 | 72 | .test-list ul li { 73 | margin: 0 0 3px; 74 | } 75 | 76 | .test-list a { 77 | color: #65450d; 78 | } 79 | 80 | 81 | .description { 82 | margin: 10px 0; 83 | border: 5px solid #6c8f3f; 84 | -moz-border-radius: 5px; 85 | -webkit-border-radius: 5px; 86 | border-radius: 5px; 87 | 88 | padding: 5px; 89 | background: #e3ffbe; 90 | color: #65450d; 91 | } 92 | 93 | .description p { 94 | margin: 5px 0; 95 | } 96 | 97 | .description ul { 98 | margin: 10px 0; 99 | padding: 0 0 0 20px; 100 | } 101 | 102 | .description ul li { 103 | line-height: 140%; 104 | margin: 0 0 5px; 105 | } 106 | 107 | .description strong { 108 | text-transform: uppercase; 109 | background: #b6de78; 110 | padding: 0 2px; 111 | border: 1px solid #6c8f3f; 112 | border-radius: 4px; 113 | -webkit-border-radius: 4px; 114 | -moz-border-radius: 4px; 115 | white-space: nowrap; 116 | } 117 | 118 | #theme_switcher { 119 | position: fixed; 120 | top: 0; 121 | left: 0; 122 | right: 0; 123 | background-color: #444; 124 | padding: 5px 10px; 125 | z-index: 10; 126 | } 127 | 128 | #theme_switcher ul { 129 | list-style: none; 130 | padding: 0; 131 | margin: 0; 132 | font-size: 12px; 133 | } 134 | 135 | #theme_switcher li { 136 | float: left; 137 | padding-right: 10px; 138 | color: #eee; 139 | } 140 | 141 | #theme_switcher a, 142 | #theme_switcher a:link, 143 | #theme_switcher a:visited { 144 | color: #ccc; 145 | } 146 | 147 | 148 | .functional-test { 149 | padding: 0 15px; 150 | margin-bottom: 25px; 151 | border: 2px solid #ccc; 152 | -moz-border-radius: 15px; 153 | -webkit-border-radius: 15px; 154 | } 155 | 156 | fieldset { 157 | padding: 10px 15px; 158 | margin: 0 0 20px; 159 | -moz-border-radius: 6px; 160 | -webkit-border-radius: 6px; 161 | } 162 | 163 | legend { 164 | font-weight: bold; 165 | font-size: 14px; 166 | padding: 0 5px; 167 | } 168 | 169 | .test-element { 170 | width: 200px; 171 | height: 200px; 172 | background-color: red; 173 | } -------------------------------------------------------------------------------- /test/functional/css_transitions.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 46 | 47 | 48 | 49 | 50 | 51 |

    Effects test

    52 |

    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.

    62 | 63 |
    64 | 65 |
    66 | 67 | 68 | 69 | 70 | 71 | 72 | 75 |
    76 | 77 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /test/functional/css_transitions_2.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 47 | 48 | 49 | 50 | 51 | 52 |

    Effects test

    53 |

    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.

    62 | 63 |
    64 | 65 |
    66 | 67 | 68 | 69 | 70 | 71 | 72 | 75 |
    76 | 77 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /test/functional/effects_units.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

    Effects CSS unit tests

    21 | 22 |
    23 |
      24 |
    • Elements should double in width when clicked.
    • 25 |
    26 |
    27 | 28 |
    29 | 30 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/functional/images/header-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/test/functional/images/header-logo-small.png -------------------------------------------------------------------------------- /test/functional/images/header-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/test/functional/images/header-logo.png -------------------------------------------------------------------------------- /test/functional/images/manipulations_pan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/test/functional/images/manipulations_pan.jpg -------------------------------------------------------------------------------- /test/functional/images/manipulations_rotate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/test/functional/images/manipulations_rotate.jpg -------------------------------------------------------------------------------- /test/functional/images/manipulations_scale.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/test/functional/images/manipulations_scale.jpg -------------------------------------------------------------------------------- /test/functional/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | script.aculo.us functional tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <body> 16 | Heya, 1995! 17 | </body> 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/functional/manipulations_pan.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |

    Tests for Pan Manipulations

    24 | 25 |
    26 | Pan works with one finger, 2 fingers or dragging with the mouse. 27 |
    28 |
    29 |
      30 |
    • Pan should work with single finger
    • 31 |
    • Pan should work with 2 fingers
    • 32 |
    • Pan should work with mouse dragging
    • 33 |
    • Panning should trigger manipulate:update events
    • 34 |
    • Scrolling the page on touch devise should be possible
    • 35 |
    • Text selection on other elements should be possible
    • 36 |
    • If two fingers are used to drag, the panning should be relative to the mid point between those two touches.
    • 37 |
    38 |
    39 | 40 |
    41 | 42 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/functional/manipulations_rotate.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |

    Tests for Rotate Manipulations

    24 | 25 |
    26 | Rotate works with two fingers and making a rotation movement or dragging with the mouse while holding down the shift key. 27 |
    28 |
    29 |
      30 |
    • Rotate should work with two fingers making a rotation movement
    • 31 |
    • Rotate should work dragging with the mouse while holding down the SHIFT key
    • 32 |
    • Rotating should trigger manipulate:update events
    • 33 |
    • Scrolling the page on touch devise should be possible
    • 34 |
    • Text selection on other elements should be possible
    • 35 |
    36 |
    37 | 38 |
    39 | 40 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/functional/manipulations_scale.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |

    Tests for Scale Manipulations

    24 | 25 |
    26 | Scale works with two fingers and making a pinch or reverse-pinch (expand) movement or dragging with the mouse while holding down the shift key. 27 |
    28 |
    29 |
      30 |
    • Scale should work with two fingers and making a pinch or reverse-pinch (expand) movement
    • 31 |
    • Scale should work dragging with the mouse while holding down the SHIFT key
    • 32 |
    • Scaling should trigger manipulate:update events
    • 33 |
    • Scrolling the page on touch devise should be possible
    • 34 |
    • Text selection on other elements should be possible
    • 35 |
    36 |
    37 | 38 |
    39 | 40 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/functional/navigation.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | script.aculo.us functional tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

    script.aculo.us

    17 |

    Functional Tests

    18 | 19 |
    20 | 21 |

    Controls

    22 | 23 | 33 | 34 |

    Effects

    35 | 36 | 39 | 40 |

    Manipulations

    41 | 42 | 47 | 48 | 49 | 50 |
    51 | 52 |

    53 | script.aculo.us version
    54 | Prototype version 55 |

    56 | 57 |

    58 | 59 |

    60 | 61 | 62 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /test/unit/addons_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | testFitIntoRectangle: function(){ with(this) { 3 | var fits = [ 4 | [10, 10, 100, 100], 5 | [100, 100, 100, 100], 6 | [50, 100, 200, 100], 7 | [50, 100, 100, 200], 8 | [100, 50, 200, 100], 9 | [100, 50, 100, 200], 10 | [500, 100, 200, 100], 11 | [500, 100, 100, 200] 12 | ]; 13 | 14 | var solution = [ 15 | [0, 0, 100, 100], 16 | [0, 0, 100, 100], 17 | [75, 0, 50, 100], 18 | [0, 0, 100, 200], 19 | [0, 0, 200, 100], 20 | [0, 75, 100, 50], 21 | [0, 30, 200, 40], 22 | [0, 90, 100, 20] 23 | ]; 24 | 25 | fits.each( function(fit,index){ 26 | assertEnumEqual(solution[index], S2.FX.Helpers.fitIntoRectangle(fit[0], fit[1], fit[2], fit[3])); 27 | }); 28 | }} 29 | 30 | }); -------------------------------------------------------------------------------- /test/unit/css_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | 3 | testInterpolationMethods: function() { with(this) { 4 | // numbers 5 | assertEqual(1, S2.CSS.interpolateNumber(1, 3, 0)); 6 | assertEqual(3, S2.CSS.interpolateNumber(1, 3, 1)); 7 | assertEqual(2, S2.CSS.interpolateNumber(1, 3, 0.5)); 8 | assertEqual(4, S2.CSS.interpolateNumber(1, 3, 1.5)); 9 | assertEqual(-1, S2.CSS.interpolateNumber(1, 3, -1)); 10 | assertEqual(2, S2.CSS.interpolateNumber(0, 4, .5)); 11 | assertEqual(2, S2.CSS.interpolateNumber(undefined, 4, .5)); 12 | assertEqual(2, S2.CSS.interpolateNumber(null, 4, .5)); 13 | 14 | assertEqual(1, S2.CSS.interpolateInteger(1, 3, 0)); 15 | assertEqual(2, S2.CSS.interpolateInteger(1, 3, 0.5)); 16 | assertEqual(3, S2.CSS.interpolateInteger(1, 3, 1)); 17 | assertEqual(2, S2.CSS.interpolateInteger(1, 3, 0.25)); 18 | assertEqual(3, S2.CSS.interpolateInteger(1, 3, 0.75)); 19 | 20 | // lengths em|ex|px|in|cm|mm|pt|pc 21 | assertEqual('1px', S2.CSS.interpolateLength('1px', '3px', 0)); 22 | assertEqual('3ex', S2.CSS.interpolateLength('1ex', '3ex', 1)); 23 | assertEqual('2px', S2.CSS.interpolateLength('1px', '3px', 0.5)); 24 | assertEqual('4in', S2.CSS.interpolateLength('1in', '3in', 1.5)); 25 | assertEqual('-1cm', S2.CSS.interpolateLength('1cm', '3cm', -1)); 26 | assertEqual('-1mm', S2.CSS.interpolateLength('1mm', '3mm', -1)); 27 | assertEqual('-1pt', S2.CSS.interpolateLength('1pt', '3pt', -1)); 28 | assertEqual('-1pc', S2.CSS.interpolateLength('1pc', '3pc', -1)); 29 | assertEqual('-2.5cm', S2.CSS.interpolateLength('5cm', '-5cm', .75)); 30 | assertEqual('2px', S2.CSS.interpolateLength('', '4px', .5)); 31 | assertEqual('2px', S2.CSS.interpolateLength(null, '4px', .5)); 32 | assertEqual('2px', S2.CSS.interpolateLength(undefined, '4px', .5)); 33 | assertEqual('0px', S2.CSS.interpolateLength('0pt', '4px', 0)); 34 | assertEqual('2px', S2.CSS.interpolateLength('0pt', '4px', 0.5)); 35 | assertEqual('4px', S2.CSS.interpolateLength('0pt', '4px', 1)); 36 | 37 | // leave alone whitespace, we're only interested in replacing the value 38 | assertEqual(' -1 pc ', S2.CSS.interpolateLength(' 1 pc ', ' \n3 \t pc ', -1)); 39 | 40 | // precentages 41 | assertEqual('50%', S2.CSS.interpolateLength('0%', '100%', 0.5)); 42 | 43 | // colors 44 | assertEqual('#ffffff', S2.CSS.interpolateColor('#ffffff', '#000000', 0)); 45 | assertEqual('#000000', S2.CSS.interpolateColor('#ffffff', '#000000', 1)); 46 | 47 | // check that values are capped 48 | assertEqual('#ffffff', S2.CSS.interpolateColor('#ffffff', '#000000', -1)); 49 | assertEqual('#000000', S2.CSS.interpolateColor('#ffffff', '#000000', 2)); 50 | 51 | assertEqual('#111111', S2.CSS.interpolateColor('#000000', '#222222', .5)); 52 | assertEqual('#111111', S2.CSS.interpolateColor('#000', '#222', .5)); 53 | assertEqual('#444444', S2.CSS.interpolateColor('#000', '#222', 2)); 54 | assertEqual('#111111', S2.CSS.interpolateColor('rgb(0,0,0)', '#222', .5)); 55 | assertEqual('#111111', S2.CSS.interpolateColor('#000', 'rgb(34,34,34)', .5)); 56 | }}, 57 | 58 | testPropertyInterpolation: function() { with(this) { 59 | assertEqual('#111111', S2.CSS.interpolate('background-color','#000000','#222222',.5)); 60 | assertEqual('#111111', S2.CSS.interpolate('background-color','#000','#222222',.5)); 61 | assertEqual('#111111', S2.CSS.interpolate('backgroundColor','#000000','#222222',.5)); 62 | 63 | assertEqual('0px', S2.CSS.interpolate('margin-top','10px','0px',.99999)); 64 | assertEqual('10px', S2.CSS.interpolate('margin-top','10px','0px',.00001)); 65 | 66 | assertEqual('0.5', S2.CSS.interpolate('opacity',0,1,.5)); 67 | assertEqual('0.000', S2.CSS.interpolate('opacity',0,1,.00000001)); 68 | 69 | assertEqual('2', S2.CSS.interpolate('z-index','1','3',.5)); 70 | }}, 71 | 72 | testStyleParsing: function() { with(this) { 73 | assertEqual('12px', S2.CSS.parseStyle('font-size:12px').fontSize); 74 | assertEqual('12pt', S2.CSS.parseStyle('font-size:12pt').fontSize); 75 | assertEqual('12em', S2.CSS.parseStyle('font-size:12em').fontSize); 76 | assertEqual('12%', S2.CSS.parseStyle('font-size:12%').fontSize); 77 | assertEqual('12ex', S2.CSS.parseStyle('font-size:12ex').fontSize); 78 | assertEqual('12in', S2.CSS.parseStyle('font-size:12in').fontSize); 79 | assertEqual('12cm', S2.CSS.parseStyle('font-size:12cm').fontSize); 80 | assertEqual('12mm', S2.CSS.parseStyle('font-size:12mm').fontSize); 81 | assertEqual('12pc', S2.CSS.parseStyle('font-size:12pc').fontSize); 82 | 83 | assertEqual('12px', S2.CSS.parseStyle(' font-size: 12px').fontSize); 84 | assertEqual('12px', S2.CSS.parseStyle('\r\nfont-size: 12px\r\n').fontSize); 85 | assertEqual('12px', S2.CSS.parseStyle('font-size: 12px \t\t').fontSize); 86 | assertEqual('12px', S2.CSS.parseStyle('\t\tfont-size:\t12px').fontSize); 87 | 88 | assertEqual('12px', S2.CSS.parseStyle(' font-size: 11px;font-size: 12px').fontSize); 89 | assertEqual('12px', S2.CSS.parseStyle('line-height: 11px;\r\nfont-size: 12px\r\n').fontSize); 90 | assertEqual('12px', S2.CSS.parseStyle('font-size: 12px; \t\tline-height: 11px;').fontSize); 91 | assertEqual('12px', S2.CSS.parseStyle('line-height: 11px;\t\tfont-size:\t12px;color: white;').fontSize); 92 | 93 | assertIdentical(undefined, S2.CSS.parseStyle('').fontSize); 94 | assertIdentical(undefined, S2.CSS.parseStyle('font-size:12pxfont-size:12px').fontSize); 95 | }}, 96 | 97 | testGetStyles: function() { with(this) { 98 | assertEqual('12px', $('allStyles_1').getStyles().fontSize); 99 | assertEqual(1, parseFloat($('allStyles_1').getStyles().opacity)); 100 | assertEqual(0.5, parseFloat($('allStyles_2').getStyles().opacity)); 101 | assertEqual(0.5, parseFloat($('allStyles_3').getStyles().opacity)); 102 | }}, 103 | 104 | testColorParsing: function() { with(this) { 105 | assertEnumEqual([171, 206, 223], S2.CSS.normalizeColor('#abcedf')); 106 | assertEnumEqual([170, 187, 204], S2.CSS.normalizeColor('#abc')); 107 | assertEnumEqual([0, 0, 0], S2.CSS.normalizeColor('#000')); 108 | assertEnumEqual([0, 255, 0], S2.CSS.normalizeColor('rgb(0,255,0)')); 109 | 110 | assert(isNaN(S2.CSS.normalizeColor('#abcedfgh')[0])); 111 | assert(isNaN(S2.CSS.normalizeColor('#abcedfgh')[1])); 112 | assert(isNaN(S2.CSS.normalizeColor('#abcedfgh')[2])); 113 | 114 | assertEqual("#ffffff", S2.CSS.colorFromString("#fff")); 115 | assertEqual("#ffffff", S2.CSS.colorFromString("#ffffff")); 116 | assertEqual("#ffffff", S2.CSS.colorFromString("rgb(255,255,255)")); 117 | assertEqual("transparent", S2.CSS.colorFromString("transparent")); 118 | 119 | // rgba support not implemented. Should something with alpha 0 return "transparent"? 120 | //assertEqual("#ffffff", S2.CSS.colorFromString("rgba(255,255,255,0)")); 121 | //assertEqual("#000000", S2.CSS.colorFromString("rgba(0,0,0,0)")); 122 | }} 123 | 124 | }); 125 | -------------------------------------------------------------------------------- /test/unit/extensions_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | testNumberTween: function(){ with(this) { 3 | assertEqual(0, (0).tween(1, 0)); 4 | assertEqual(.5, (0).tween(1, .5)); 5 | assertEqual(1, (0).tween(1, 1)); 6 | 7 | assertEqual(25, (20).tween(30, .5)); 8 | 9 | assertEqual(50, (100).tween(0, .5)); 10 | assertEqual(33.33, (100).tween(0, 2/3).toFixed(2)); 11 | assertEqual(66.67, (100).tween(0, 1/3).toFixed(2)); 12 | 13 | assertEqual(Infinity, (0).tween(Infinity, 1)); 14 | assertEqual(Infinity, (0).tween(Infinity, 0.000001)); 15 | assert(isNaN((0).tween(Infinity, 0))); 16 | 17 | assert(isNaN(NaN, (0).tween(NaN, 0))); 18 | assert(isNaN(NaN, (NaN).tween(NaN, 0))); 19 | }}, 20 | 21 | testObjectPropertize: function(){ with(this) { 22 | var propertizeTransitions = function(prop) { 23 | return Object.propertize(prop, S2.FX.Transitions); 24 | }; 25 | assertEqual(propertizeTransitions('sinusoidal'), S2.FX.Transitions.sinusoidal); 26 | assertEqual(propertizeTransitions(S2.FX.Transitions.sinusoidal), S2.FX.Transitions.sinusoidal); 27 | }}, 28 | 29 | testFunctionOptionize: function(){ with(this) { 30 | var o = {a:1}, 31 | optionize = (function(a,b,options) { 32 | return options; 33 | }).optionize(); 34 | 35 | // options set to last object 36 | assertEqual(o, optionize(o)); 37 | assertEqual(o, optionize(1,o)); 38 | assertEqual(o, optionize(1,2,o)); 39 | 40 | // unless the argument is already filled in 41 | assertEqual(3, optionize(1,2,3,o)); 42 | }} 43 | }); 44 | -------------------------------------------------------------------------------- /test/unit/fixtures/css.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    8 |
    9 |
    -------------------------------------------------------------------------------- /test/unit/fixtures/effects.html: -------------------------------------------------------------------------------- 1 | 24 | 25 |
    Well
    26 |
    You know
    27 |
    Whoo-hoo!
    28 | 29 |
    ERROR MESSAGE
    30 |
    SECOND ERROR MESSAGE
    31 |
    THIRD ERROR MESSAGE
    32 | 33 |
      34 |
    • Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    • 35 |
    • sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    • 36 |
    • Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    • 37 |
    • nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    • 38 |
    • reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
    • 39 |
    40 | 41 |
    ROTFL
    42 | 43 |
    foo!
    44 | 45 |
    46 |
    -------------------------------------------------------------------------------- /test/unit/fixtures/operators_style.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    8 |
    9 |
    -------------------------------------------------------------------------------- /test/unit/heartbeat_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | setup: function(){ 3 | frameCounter = 0; 4 | }, 5 | 6 | testHeartbeat: function() { with(this) { 7 | var tmp = 0, tmp2 = 0; 8 | document.observe('effect:heartbeat', function(){ 9 | tmp++; 10 | }); 11 | assertEqual(0, tmp); 12 | wait(250, function(){ 13 | assertEqual(0, tmp); 14 | new S2.FX.Morph('sandbox',{style:'font-size:20px',duration:.5}).play(); 15 | wait(750, function(){ 16 | assert(tmp > 0); 17 | tmp2 = tmp; 18 | wait(100, function(){ 19 | assertEqual(tmp2, tmp, "heartbeats shouldn't continue when no fx running"); 20 | }); 21 | }); 22 | }); 23 | }}, 24 | 25 | testHeartbeatFramerate: function(){ with(this) { 26 | var oldHeartbeat = S2.FX.getHeartbeat(); 27 | oldHeartbeat.stop(); 28 | delete oldHeartbeat; 29 | 30 | var heartbeat = new S2.FX.Heartbeat({framerate:2}), frameCounter = 0; 31 | S2.FX.setHeartbeat(heartbeat); 32 | var o = function(){ frameCounter++; }; 33 | document.observe('effect:heartbeat', o); 34 | 35 | $('sandbox').morph('font-size:10px'); 36 | wait(1100, function(){ 37 | assertEqual(2, frameCounter); 38 | document.stopObserving('effect:heartbeat', o); 39 | heartbeat.stop(); 40 | delete heartbeat; 41 | }); 42 | }} 43 | }); -------------------------------------------------------------------------------- /test/unit/operators_style_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | testStyle: function(){ with(this) { 3 | var operator = new S2.FX.Operators.Style(null, 'style_test', { style: 'font-size:20px' }); 4 | assertMatch(/10px/, operator.valueAt(0)); 5 | assertMatch(/15px/, operator.valueAt(.5)); 6 | assertMatch(/20px/, operator.valueAt(1)); 7 | }}, 8 | 9 | testStyleSubvalues: function(){ with(this) { 10 | var operator = new S2.FX.Operators.Style(null, 'style_test_subvalues', 11 | { style: ' border-left-width: 10px ' } 12 | ); 13 | 14 | assertMatch(/30px/, operator.valueAt(0)); 15 | assertMatch(/20px/, operator.valueAt(.5)); 16 | assertMatch(/10px/, operator.valueAt(1)); 17 | }}, 18 | 19 | testStyleColors: function(){ with(this) { 20 | var operator = new S2.FX.Operators.Style(null, 'style_test_colors', 21 | { style: 'color:#987654; background-color: #fff ' } 22 | ); 23 | 24 | assertMatch(/color:#aabbcc/, operator.valueAt(0)); 25 | assertMatch(/color:#a19990/, operator.valueAt(.5)); 26 | assertMatch(/color:#987654/, operator.valueAt(1)); 27 | 28 | assertMatch(/background-color:#123456/, operator.valueAt(0)); 29 | assertMatch(/background-color:#899aab/, operator.valueAt(.5)); 30 | assertMatch(/background-color:#ffffff/, operator.valueAt(1)); 31 | }} 32 | }); -------------------------------------------------------------------------------- /test/unit/package_test.js: -------------------------------------------------------------------------------- 1 | new Test.Unit.Runner({ 2 | 3 | testS2Defined: function() { with(this) { 4 | assertNotUndefined(window['S2']); 5 | }} 6 | 7 | }); -------------------------------------------------------------------------------- /test/unit/templates/default.erb: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Unit test file | <%= title %> | <%= template_name %> template | <%= timestamp %> 6 | 7 | <%= lib_files %> 8 | <%= css_fixtures %> 9 | <%= js_fixtures %> 10 | 11 | <%= test_file %> 12 | 13 | 14 | 15 |
    16 |
    17 | 18 | <%= html_fixtures %> 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /themes/default/images/accordion-header-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/accordion-header-active.png -------------------------------------------------------------------------------- /themes/default/images/button-active-default-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-active-default-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-active-down-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-active-down-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-active-hover-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-active-hover-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-default-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-default-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-disabled-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-disabled-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-down-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-down-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-hover-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-hover-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-primary-default-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-primary-default-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-primary-down-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-primary-down-middle.png -------------------------------------------------------------------------------- /themes/default/images/button-primary-hover-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/button-primary-hover-middle.png -------------------------------------------------------------------------------- /themes/default/images/header-active-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/header-active-middle.png -------------------------------------------------------------------------------- /themes/default/images/header-default-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/header-default-middle.png -------------------------------------------------------------------------------- /themes/default/images/header-down-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/header-down-middle.png -------------------------------------------------------------------------------- /themes/default/images/progress-bar-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/progress-bar-default.png -------------------------------------------------------------------------------- /themes/default/images/progress-bar-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/progress-bar-disabled.png -------------------------------------------------------------------------------- /themes/default/images/progress-bar-track-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/progress-bar-track-default.png -------------------------------------------------------------------------------- /themes/default/images/progress-bar-track-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/progress-bar-track-disabled.png -------------------------------------------------------------------------------- /themes/default/images/slider-handle-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-handle-active.png -------------------------------------------------------------------------------- /themes/default/images/slider-handle-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-handle-default.png -------------------------------------------------------------------------------- /themes/default/images/slider-handle-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-handle-disabled.png -------------------------------------------------------------------------------- /themes/default/images/slider-range-default-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-range-default-horizontal.png -------------------------------------------------------------------------------- /themes/default/images/slider-range-default-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-range-default-vertical.png -------------------------------------------------------------------------------- /themes/default/images/slider-track-default-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-track-default-horizontal.png -------------------------------------------------------------------------------- /themes/default/images/slider-track-default-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-track-default-vertical.png -------------------------------------------------------------------------------- /themes/default/images/slider-track-disabled-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-track-disabled-horizontal.png -------------------------------------------------------------------------------- /themes/default/images/slider-track-disabled-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/slider-track-disabled-vertical.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_941010_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_941010_256x240.png -------------------------------------------------------------------------------- /themes/default/images/ui-icons_f5f5f5_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/ui-icons_f5f5f5_256x240.png -------------------------------------------------------------------------------- /themes/default/images/widget-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/default/images/widget-header.png -------------------------------------------------------------------------------- /themes/default/ui.accordion.css: -------------------------------------------------------------------------------- 1 | /* Accordion 2 | ----------------------------------*/ 3 | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } 4 | .ui-accordion .ui-accordion-li-fix { display: inline; } 5 | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } 6 | .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } 7 | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } 8 | .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } 9 | .ui-accordion .ui-accordion-content-active { display: block; } -------------------------------------------------------------------------------- /themes/default/ui.all.css: -------------------------------------------------------------------------------- 1 | @import "ui.base.css"; 2 | @import "ui.theme.css"; 3 | -------------------------------------------------------------------------------- /themes/default/ui.base.css: -------------------------------------------------------------------------------- 1 | @import url("ui.core.css"); 2 | @import url("ui.resizable.css"); 3 | @import url("ui.accordion.css"); 4 | @import url("ui.dialog.css"); 5 | @import url("ui.slider.css"); 6 | @import url("ui.tabs.css"); 7 | @import url("ui.datepicker.css"); 8 | @import url("ui.progressbar.css"); 9 | @import url("ui.button.css"); -------------------------------------------------------------------------------- /themes/default/ui.core.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI CSS Framework 3 | * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) 4 | * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. 5 | */ 6 | 7 | /* Layout helpers 8 | ----------------------------------*/ 9 | .ui-helper-hidden { display: none; } 10 | .ui-helper-hidden-accessible { position: absolute; left: -99999999px; } 11 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } 12 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } 13 | .ui-helper-clearfix { display: inline-block; } 14 | /* required comment for clearfix to work in Opera \*/ 15 | * html .ui-helper-clearfix { height:1%; } 16 | .ui-helper-clearfix { display:block; } 17 | /* end clearfix */ 18 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } 19 | 20 | 21 | /* Interaction Cues 22 | ----------------------------------*/ 23 | .ui-state-disabled { cursor: default !important; } 24 | 25 | 26 | /* Icons 27 | ----------------------------------*/ 28 | 29 | /* states and images */ 30 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } 31 | 32 | 33 | /* Misc visuals 34 | ----------------------------------*/ 35 | 36 | /* Overlays */ 37 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } -------------------------------------------------------------------------------- /themes/default/ui.datepicker.css: -------------------------------------------------------------------------------- 1 | /* Datepicker 2 | ----------------------------------*/ 3 | .ui-datepicker { width: 17em; padding: .2em .2em 0; } 4 | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } 5 | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } 6 | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } 7 | .ui-datepicker .ui-datepicker-prev { left:2px; } 8 | .ui-datepicker .ui-datepicker-next { right:2px; } 9 | .ui-datepicker .ui-datepicker-prev-hover { left:1px; } 10 | .ui-datepicker .ui-datepicker-next-hover { right:1px; } 11 | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } 12 | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } 13 | .ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } 14 | .ui-datepicker select.ui-datepicker-month-year {width: 100%;} 15 | .ui-datepicker select.ui-datepicker-month, 16 | .ui-datepicker select.ui-datepicker-year { width: 49%;} 17 | .ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } 18 | .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } 19 | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } 20 | .ui-datepicker td { border: 0; padding: 1px; } 21 | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } 22 | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } 23 | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } 24 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } 25 | 26 | /* with multiple calendars */ 27 | .ui-datepicker.ui-datepicker-multi { width:auto; } 28 | .ui-datepicker-multi .ui-datepicker-group { float:left; } 29 | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } 30 | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } 31 | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } 32 | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } 33 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } 34 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } 35 | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } 36 | .ui-datepicker-row-break { clear:both; width:100%; } 37 | 38 | /* RTL support */ 39 | .ui-datepicker-rtl { direction: rtl; } 40 | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } 41 | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } 42 | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } 43 | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } 44 | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } 45 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } 46 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } 47 | .ui-datepicker-rtl .ui-datepicker-group { float:right; } 48 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } 49 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } 50 | 51 | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ 52 | .ui-datepicker-cover { 53 | display: none; /*sorry for IE5*/ 54 | display/**/: block; /*sorry for IE5*/ 55 | position: absolute; /*must have*/ 56 | z-index: -1; /*must have*/ 57 | filter: mask(); /*must have*/ 58 | top: -4px; /*must have*/ 59 | left: -4px; /*must have*/ 60 | width: 200px; /*must have*/ 61 | height: 200px; /*must have*/ 62 | } -------------------------------------------------------------------------------- /themes/default/ui.dialog.css: -------------------------------------------------------------------------------- 1 | /* Dialog 2 | ----------------------------------*/ 3 | .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } 4 | .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } 5 | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } 6 | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } 7 | .ui-dialog .ui-dialog-titlebar-close span { display: block; } 8 | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { } 9 | .ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } 10 | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } 11 | .ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } 12 | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } 13 | .ui-draggable .ui-dialog-titlebar { cursor: move; } -------------------------------------------------------------------------------- /themes/default/ui.progressbar.css: -------------------------------------------------------------------------------- 1 | /* Progressbar 2 | ----------------------------------*/ 3 | .ui-progressbar { height:2em; text-align: left; } 4 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } -------------------------------------------------------------------------------- /themes/default/ui.resizable.css: -------------------------------------------------------------------------------- 1 | /* Resizable 2 | ----------------------------------*/ 3 | .ui-resizable { position: relative;} 4 | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} 5 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } 6 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } 7 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } 8 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } 9 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } 10 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } 11 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } 12 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } 13 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} -------------------------------------------------------------------------------- /themes/default/ui.slider.css: -------------------------------------------------------------------------------- 1 | /* Slider 2 | ----------------------------------*/ 3 | .ui-slider { position: relative; text-align: left; } 4 | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } 5 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } 6 | 7 | .ui-slider-horizontal { height: .8em; } 8 | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } 9 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } 10 | .ui-slider-horizontal .ui-slider-range-min { left: 0; } 11 | .ui-slider-horizontal .ui-slider-range-max { right: 0; } 12 | 13 | .ui-slider-vertical { width: .8em; height: 100px; } 14 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-top: -.6em; } 15 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } 16 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; } 17 | .ui-slider-vertical .ui-slider-range-max { top: 0; } -------------------------------------------------------------------------------- /themes/default/ui.tabs.css: -------------------------------------------------------------------------------- 1 | /* Tabs 2 | ----------------------------------*/ 3 | .ui-tabs { padding: .2em; zoom: 1; } 4 | .ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } 5 | .ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } 6 | .ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } 7 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } 8 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } 9 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ 10 | .ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } 11 | .ui-tabs .ui-tabs-hide { display: none !important; } 12 | -------------------------------------------------------------------------------- /themes/test/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /themes/test/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /themes/test/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /themes/test/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /themes/test/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /themes/test/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /themes/test/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/themes/test/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /vendor/google-compiler/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/vendor/google-compiler/compiler.jar -------------------------------------------------------------------------------- /vendor/yuicompressor/README: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | YUI Compressor 3 | ============================================================================== 4 | 5 | NAME 6 | 7 | YUI Compressor - The Yahoo! JavaScript and CSS Compressor 8 | 9 | SYNOPSIS 10 | 11 | Usage: java -jar yuicompressor-x.y.z.jar [options] [input file] 12 | 13 | Global Options 14 | -h, --help Displays this information 15 | --type Specifies the type of the input file 16 | --charset Read the input file using 17 | --line-break Insert a line break after the specified column number 18 | -v, --verbose Display informational messages and warnings 19 | -o Place the output into . Defaults to stdout. 20 | 21 | JavaScript Options 22 | --nomunge Minify only, do not obfuscate 23 | --preserve-semi Preserve all semicolons 24 | --disable-optimizations Disable all micro optimizations 25 | 26 | DESCRIPTION 27 | 28 | The YUI Compressor is a JavaScript compressor which, in addition to removing 29 | comments and white-spaces, obfuscates local variables using the smallest 30 | possible variable name. This obfuscation is safe, even when using constructs 31 | such as 'eval' or 'with' (although the compression is not optimal is those 32 | cases) Compared to jsmin, the average savings is around 20%. 33 | 34 | The YUI Compressor is also able to safely compress CSS files. The decision 35 | on which compressor is being used is made on the file extension (js or css) 36 | 37 | GLOBAL OPTIONS 38 | 39 | -h, --help 40 | Prints help on how to use the YUI Compressor 41 | 42 | --line-break 43 | Some source control tools don't like files containing lines longer than, 44 | say 8000 characters. The linebreak option is used in that case to split 45 | long lines after a specific column. It can also be used to make the code 46 | more readable, easier to debug (especially with the MS Script Debugger) 47 | Specify 0 to get a line break after each semi-colon in JavaScript, and 48 | after each rule in CSS. 49 | 50 | --type js|css 51 | The type of compressor (JavaScript or CSS) is chosen based on the 52 | extension of the input file name (.js or .css) This option is required 53 | if no input file has been specified. Otherwise, this option is only 54 | required if the input file extension is neither 'js' nor 'css'. 55 | 56 | --charset character-set 57 | If a supported character set is specified, the YUI Compressor will use it 58 | to read the input file. Otherwise, it will assume that the platform's 59 | default character set is being used. The output file is encoded using 60 | the same character set. 61 | 62 | -o outfile 63 | Place output in file outfile. If not specified, the YUI Compressor will 64 | default to the standard output, which you can redirect to a file. 65 | 66 | -v, --verbose 67 | Display informational messages and warnings. 68 | 69 | JAVASCRIPT ONLY OPTIONS 70 | 71 | --nomunge 72 | Minify only. Do not obfuscate local symbols. 73 | 74 | --preserve-semi 75 | Preserve unnecessary semicolons (such as right before a '}') This option 76 | is useful when compressed code has to be run through JSLint (which is the 77 | case of YUI for example) 78 | 79 | --disable-optimizations 80 | Disable all the built-in micro optimizations. 81 | 82 | NOTES 83 | 84 | + If no input file is specified, it defaults to stdin. 85 | 86 | + The YUI Compressor requires Java version >= 1.4. 87 | 88 | + It is possible to prevent a local variable, nested function or function 89 | argument from being obfuscated by using "hints". A hint is a string that 90 | is located at the very beginning of a function body like so: 91 | 92 | function fn (arg1, arg2, arg3) { 93 | "arg2:nomunge, localVar:nomunge, nestedFn:nomunge"; 94 | 95 | ... 96 | var localVar; 97 | ... 98 | 99 | function nestedFn () { 100 | .... 101 | } 102 | 103 | ... 104 | } 105 | 106 | The hint itself disappears from the compressed file. 107 | 108 | + C-style comments starting with /*! are preserved. This is useful with 109 | comments containing copyright/license information. For example: 110 | 111 | /*! 112 | * TERMS OF USE - EASING EQUATIONS 113 | * Open source under the BSD License. 114 | * Copyright 2001 Robert Penner All rights reserved. 115 | */ 116 | 117 | becomes: 118 | 119 | /* 120 | * TERMS OF USE - EASING EQUATIONS 121 | * Open source under the BSD License. 122 | * Copyright 2001 Robert Penner All rights reserved. 123 | */ 124 | 125 | AUTHOR 126 | 127 | The YUI Compressor was written and is maintained by: 128 | Julien Lecomte 129 | The CSS portion is a port of Isaac Schlueter's cssmin utility. 130 | 131 | COPYRIGHT 132 | 133 | Copyright (c) 2007-2009, Yahoo! Inc. All rights reserved. 134 | 135 | LICENSE 136 | 137 | All code specific to YUI Compressor is issued under a BSD license. 138 | YUI Compressor extends and implements code from Mozilla's Rhino project. 139 | Rhino is issued under the Mozilla Public License (MPL), and MPL applies 140 | to the Rhino source and binaries that are distributed with YUI Compressor. -------------------------------------------------------------------------------- /vendor/yuicompressor/yuicompressor-2.4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madrobby/scripty2/a65396e1a1ab5ff5e31b8c9c2c6e6feced3dadd8/vendor/yuicompressor/yuicompressor-2.4.2.jar --------------------------------------------------------------------------------