├── .gitignore
├── CHANGELOG
├── LICENSE
├── Nakefile
├── README.md
├── dist
├── header.js
├── header.olds.js
├── header.safe.js
├── header.server.js
├── layout.js
├── layout.olds.js
├── layout.safe.js
├── layout.server.js
└── lint.js
├── src
├── __init__.js
├── core
│ ├── class.js
│ ├── observer.js
│ ├── options.js
│ └── util.js
├── dom
│ ├── browser.js
│ ├── cookie.js
│ ├── document.js
│ ├── element.js
│ ├── element
│ │ ├── commons.js
│ │ ├── dimensions.js
│ │ ├── events.js
│ │ ├── structs.js
│ │ └── styles.js
│ ├── event.js
│ ├── event
│ │ ├── delegation.js
│ │ ├── focusin.js
│ │ └── mouseio.js
│ ├── form.js
│ ├── input.js
│ ├── ready.js
│ ├── selector.js
│ ├── string.js
│ ├── window.js
│ └── wrapper.js
├── fx
│ ├── element.js
│ ├── fx.js
│ ├── fx
│ │ ├── attr.js
│ │ ├── fade.js
│ │ ├── highlight.js
│ │ ├── morph.js
│ │ ├── scroll.js
│ │ ├── slide.js
│ │ └── twin.js
│ └── string.js
├── lang
│ ├── array.js
│ ├── function.js
│ ├── json.js
│ ├── math.js
│ ├── number.js
│ ├── object.js
│ ├── regexp.js
│ └── string.js
├── olds
│ ├── css.js
│ ├── events.js
│ ├── ie.js
│ ├── konq.js
│ └── loader.js
├── right.js
└── xhr
│ ├── element.js
│ ├── form.js
│ ├── xhr.js
│ └── xhr
│ ├── dummy.js
│ ├── iframed.js
│ └── jsonp.js
├── test
├── effects.html
├── form
│ ├── form-cancel-xhr.html
│ └── server.rb
├── index.html
├── mouseio.html
├── safe
│ ├── core_test.js
│ ├── dom_test.js
│ └── lang_test.js
├── tests.js
├── tests.safe.js
├── tests.server.js
├── ujs-test.html
└── unit
│ ├── core
│ ├── class_test.js
│ ├── observer_test.js
│ ├── options_test.js
│ └── util_test.js
│ ├── dom
│ ├── browser_test.js
│ ├── cookie_test.js
│ ├── element
│ │ ├── commons_test.js
│ │ ├── dimensions_test.js
│ │ ├── events_test.js
│ │ ├── structs_test.js
│ │ └── styles_test.js
│ ├── element_test.js
│ ├── event
│ │ ├── bubbling_test.js
│ │ └── delegation_test.js
│ ├── event_test.js
│ ├── form_test.js
│ ├── input_test.js
│ ├── ready_test.js
│ ├── selector_test.js
│ ├── window_test.js
│ └── wrapper_test.js
│ ├── fx
│ ├── fx
│ │ └── morph_test.js
│ └── fx_test.js
│ ├── lang
│ ├── array_test.js
│ ├── function_test.js
│ ├── json_test.js
│ ├── math_test.js
│ ├── number_test.js
│ ├── object_test.js
│ ├── regexp_test.js
│ └── string_test.js
│ └── xhr
│ ├── xhr
│ ├── iframed_test.js
│ └── jsonp_test.js
│ └── xhr_test.js
└── util
├── jslint.js
├── linter.js
├── nake.js
├── right-server.js
├── source.js
├── test-page.css
├── testcase.js
├── tools.js
└── ugly
├── parse-js.js
├── process.js
└── squeeze-more.js
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2007-2010 Nikolay V. Nemshilov
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome Home!
2 |
3 | RightJS is a fine JavaScript framework that's designed to make you happy.
4 | It lives over here , go check it, you won't regret!
5 |
6 |
7 | ## How To Build
8 |
9 | To build the core on your own, you'll need [NodeJS](http://nodejs.org) and
10 | if you also have [npm](http://npmjs.org) you might want to install the
11 | [nake](https://github.com/MadRabbit/Nake) tools
12 |
13 | npm install nake
14 |
15 | After that either run `nake`
16 |
17 | nake build
18 |
19 | or, if you don't have [npm](http://npmjs.org), just run the `Nakefile`
20 | directly with [NodeJS](http://nodejs.org)
21 |
22 | node Nakefile build
23 |
24 | Try, `-l` or `--list` key to see which other tasks are available
25 |
26 |
27 | ## Options
28 |
29 | You can switch off some modules from the core by using the `OPTIONS` key
30 |
31 | nake build OPTIONS=no-olds,no-fx
32 |
33 | The list of available options is the following
34 |
35 | * `no-form` - no advanced form features
36 | * `no-events` - no events delegation features
37 | * `no-cookie` - no cookies module
38 | * `no-xhr` - no ajax support
39 | * `no-fx` - no visual effects module
40 | * `no-olds` - puts the old browsers support in a separated file
41 |
42 |
43 | ## License
44 |
45 | The code released under terms of the MIT License
46 |
47 | Copyright (C) 2008-2011 Nikolay Nemshilov
--------------------------------------------------------------------------------
/dist/header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * RightJS v%{version} - http://rightjs.org
3 | * Released under the terms of MIT license
4 | *
5 | * Copyright (C) 2008-2012 Nikolay Nemshilov
6 | */
7 |
--------------------------------------------------------------------------------
/dist/header.olds.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The old browsers support module for RightJS
3 | *
4 | * Released under the terms of the MIT license
5 | * Visit http://rightjs.org for more details
6 | *
7 | * Copyright (C) 2008-2012 Nikolay Nemshilov
8 | */
9 |
--------------------------------------------------------------------------------
/dist/header.safe.js:
--------------------------------------------------------------------------------
1 | /**
2 | * RightJS v%{version} safe-mode, http://rightjs.org
3 | * Released under terms of the MIT license
4 | *
5 | * Copyright (C) 2008-2012 Nikolay Nemshilov
6 | */
7 |
--------------------------------------------------------------------------------
/dist/header.server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * RightJS v%{version} the server-side version
3 | * Released under terms of the MIT license
4 | * Visit http://rightjs.org for more details
5 | *
6 | * Copyright (C) 2008-2012 Nikolay Nemshilov
7 | */
8 |
9 |
--------------------------------------------------------------------------------
/dist/layout.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The basic layout for RightJS builds
3 | *
4 | * Copyright (C) 2008-2011 Nikolay Nemshilov
5 | */
6 | var RightJS = (function(window, document, Object, Array, String, Function, Number, Math, undefined) {
7 |
8 | %{source_code}
9 |
10 | // globalizing the top-level variables
11 | $ext(window, Object.without(RightJS, 'version', 'modules'));
12 |
13 | return RightJS;
14 | })(window, document, Object, Array, String, Function, Number, Math);
15 |
--------------------------------------------------------------------------------
/dist/layout.olds.js:
--------------------------------------------------------------------------------
1 | (function(RightJS) {
2 | %{source_code}
3 | })(RightJS);
--------------------------------------------------------------------------------
/dist/layout.safe.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The safe-mode layout
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | var RightJS = (function(window, src) {
7 | // premassaging the source code, swapping the document reference where needed
8 | src = src
9 | // the default document to the current one
10 | .replace(',document,', ',parent.document,')
11 |
12 | // building the inside types conversion methods
13 | + 'RightJS.$N=function(v){return new Number(v)};'
14 | + 'RightJS.$S=function(v){return new String(v)}';
15 |
16 | // building the frame sandbox
17 | var frame_id = '__rightjs_condom', document = window.document;
18 | if ('attachEvent' in window) {
19 | document.write('');
20 | } else {
21 | var frame = document.createElement('iframe');
22 | frame.name = frame_id;
23 | frame.style.display = 'none';
24 | document.documentElement.appendChild(frame);
25 | }
26 |
27 | // puttin the code into the frame
28 | var win = window.frames[frame_id];
29 |
30 | if ('execScript' in win) {
31 | win.execScript(src);
32 | } else {
33 | var doc = win.document;
34 | doc.open();doc.write(''); doc.close();
35 |
36 | var script = document.createElement('script');
37 | script.text = src;
38 | doc.body.appendChild(script);
39 | }
40 |
41 | // transferring the object references from the sandbox into local variable
42 | var RightJS = win.RightJS;
43 | RightJS.context = win;
44 | RightJS.safe = true;
45 |
46 | // building the access and types conversion proxy
47 | var proxy = function(value) {
48 | switch (typeof value) {
49 | case 'number': return RightJS.$N(value);
50 | case 'string': return RightJS.$S(value);
51 | case 'function': return RightJS.$ext(value, RightJS.Function.Methods);
52 | case 'object':
53 | if (RightJS.isArray(value))
54 | return RightJS.$A(value);
55 | }
56 |
57 | return value;
58 | };
59 |
60 | return RightJS.$ext(proxy, RightJS);
61 |
62 | })(window, %{source_code});
63 |
--------------------------------------------------------------------------------
/dist/layout.server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The server-side CommonJS builds layout
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | %{source_code}
7 |
8 | if (exports) {
9 | $ext(exports, RightJS);
10 | }
11 |
--------------------------------------------------------------------------------
/dist/lint.js:
--------------------------------------------------------------------------------
1 | /**
2 | * JSLint additional options
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | var options = {};
7 | var okays = [
8 | ' current_Document.win()._.execScript(text);',
9 | ' return value != null && value.nodeType === 1;',
10 | ' return value != null && value.nodeType != null;',
11 | ' value != null && value.hasOwnProperty != null;',
12 | " event.target != null && 'nodeType' in event.target && event.target.nodeType === 3 ?",
13 | ' if (object != null) {',
14 | ' return this == false;',
15 | 'Do not use Number as a constructor.',
16 | "Expected a 'break' statement before 'case'.",
17 | "The Function constructor is eval.",
18 | 'var RightJS = (function(window, document, Object, Array, String, Function, Number, Math, undefined) {'
19 | ];
--------------------------------------------------------------------------------
/src/__init__.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The source code initialization script
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | include_sources_by_modules({
7 | core: [
8 | 'right',
9 |
10 | // the core utils should be included before the language extentions
11 | 'core/util',
12 |
13 | 'lang/object',
14 | 'lang/math',
15 | 'lang/array',
16 | 'lang/string',
17 | 'lang/function',
18 | 'lang/number',
19 | 'lang/regexp',
20 | 'lang/json',
21 |
22 | 'core/class',
23 | 'core/options',
24 | 'core/observer'
25 | ],
26 |
27 | dom: [
28 | 'dom/browser',
29 | 'dom/wrapper',
30 |
31 | 'dom/document',
32 | 'dom/window',
33 |
34 | 'dom/event',
35 |
36 | 'dom/element',
37 | 'dom/element/structs',
38 | 'dom/element/styles',
39 | 'dom/element/commons',
40 | 'dom/element/dimensions',
41 | 'dom/element/events',
42 |
43 | 'dom/selector',
44 | 'dom/ready'
45 | ],
46 |
47 | form: [
48 | 'dom/form',
49 | 'dom/input'
50 | ],
51 |
52 | // NOTE: this one should be after the 'form' module!
53 | events: [
54 | 'dom/event/focusin',
55 | 'dom/event/mouseio',
56 | 'dom/event/delegation',
57 |
58 | 'dom/string'
59 | ],
60 |
61 | xhr: [
62 | 'xhr/xhr',
63 | 'xhr/form',
64 | 'xhr/element',
65 | 'xhr/xhr/dummy',
66 | 'xhr/xhr/iframed',
67 | 'xhr/xhr/jsonp'
68 | ],
69 |
70 | fx: [
71 | 'fx/fx',
72 | 'fx/string',
73 | 'fx/element',
74 | 'fx/fx/morph',
75 | 'fx/fx/highlight',
76 | 'fx/fx/twin',
77 | 'fx/fx/slide',
78 | 'fx/fx/fade',
79 | 'fx/fx/attr',
80 | 'fx/fx/scroll'
81 | ],
82 |
83 | cookie: [
84 | 'dom/cookie'
85 | ],
86 |
87 | // the old browsers support hacks
88 | olds: [
89 | 'olds/ie',
90 | 'olds/events',
91 | 'olds/konq',
92 | 'olds/css'
93 | ]
94 | });
95 |
--------------------------------------------------------------------------------
/src/core/options.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This is a simple mix-in module to be included in other classes
3 | *
4 | * Basically it privdes the setOptions method which processes
5 | * an instance options assigment and merging with the default options
6 | *
7 | * Credits:
8 | * The idea of the module is inspired by
9 | * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
10 | *
11 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
12 | */
13 | var Options = RightJS.Options = {
14 | /**
15 | * assigns the options by merging them with the default ones
16 | *
17 | * @param Object options
18 | * @return Object current instance
19 | */
20 | setOptions: function(opts) {
21 | var options = this.options = $ext($ext({},
22 | Object.clone(Class_findSet(this, 'Options'))), opts
23 | ), match, key;
24 |
25 | // hooking up the observer options
26 | if (isFunction(this.on)) {
27 | for (key in options) {
28 | if ((match = key.match(/on([A-Z][A-Za-z]+)/))) {
29 | this.on(match[1].toLowerCase(), options[key]);
30 | delete(options[key]);
31 | }
32 | }
33 | }
34 |
35 | return this;
36 | },
37 |
38 | /**
39 | * Cuts of an options hash from the end of the arguments list
40 | * assigns them using the #setOptions method and then
41 | * returns the list of other arguments as an Array instance
42 | *
43 | * @param mixed iterable
44 | * @return Array of the arguments
45 | */
46 | cutOptions: function(in_args) {
47 | var args = $A(in_args);
48 | this.setOptions(isHash(args.last()) ? args.pop() : {});
49 | return args;
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/src/dom/browser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this object will contain info about the current browser
3 | *
4 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5 | */
6 | var agent = navigator.userAgent,
7 | Browser_Opera = 'opera' in window,
8 | Browser_IE = 'attachEvent' in window && !Browser_Opera,
9 |
10 | Browser = RightJS.Browser = {
11 | IE: Browser_IE,
12 | Opera: Browser_Opera,
13 | WebKit: agent.include('AppleWebKit/'),
14 | Gecko: agent.include('Gecko') && !agent.include('KHTML'),
15 | MobileSafari: /Apple.*Mobile.*Safari/.test(agent),
16 | Konqueror: agent.include('Konqueror'),
17 |
18 | // internal marker for the browsers which require the olds module
19 | OLD: !document.querySelector,
20 | // internal marker for IE browsers version <= 8
21 | IE8L: false
22 | },
23 |
24 | IE8_OR_LESS = false,
25 | IE_OPACITY = !('opacity' in HTML.style) && ('filter' in HTML.style);
26 |
27 | try {
28 | // checking if that an IE version <= 8
29 | document.createElement('');
30 | Browser.OLD = Browser.IE8L = IE8_OR_LESS = true;
31 | } catch(e) {}
32 |
--------------------------------------------------------------------------------
/src/dom/cookie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this module handles the work with cookies
3 | *
4 | * Credits:
5 | * Most things in the unit are take from
6 | * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
7 | *
8 | * Copyright (C) 2008-2010 Nikolay V. Nemshilov
9 | */
10 | var Cookie = RightJS.Cookie = new Class({
11 | include: Options,
12 |
13 | extend: {
14 | // sets the cookie
15 | set: function(name, value, options) {
16 | return new this(name, options).set(value);
17 | },
18 | // gets the cookie
19 | get: function(name, options) {
20 | return new this(name, options).get();
21 | },
22 | // deletes the cookie
23 | remove: function(name, options) {
24 | return new this(name, options).remove();
25 | },
26 |
27 | // checks if the cookies are enabled
28 | enabled: function() {
29 | document.cookie = "__t=1";
30 | return document.cookie.indexOf("__t=1")!=-1;
31 | },
32 |
33 | // some basic options
34 | Options: {
35 | secure: false,
36 | document: document
37 | }
38 | },
39 |
40 | /**
41 | * constructor
42 | * @param String cookie name
43 | * @param Object options
44 | * @return void
45 | */
46 | initialize: function(name, options) {
47 | this.name = name;
48 | this.setOptions(options);
49 | },
50 |
51 | /**
52 | * sets the cookie with the name
53 | *
54 | * @param mixed value
55 | * @return Cookie this
56 | */
57 | set: function(data) {
58 | if (!isString(data)) { data = JSON.stringify(data); }
59 |
60 | var value = encodeURIComponent(data), options = this.options;
61 |
62 | if (options.domain) { value += '; domain=' + options.domain; }
63 | if (options.path) { value += '; path=' + options.path; }
64 | if (options.duration) {
65 | var date = new Date();
66 | date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000);
67 | value += '; expires=' + date.toGMTString();
68 | }
69 | if (options.secure) { value += '; secure'; }
70 | options.document.cookie = this.name + '=' + value;
71 | return this;
72 | },
73 |
74 | /**
75 | * searches for a cookie with the name
76 | *
77 | * @return mixed saved value or null if nothing found
78 | */
79 | get: function() {
80 | var value = this.options.document.cookie.match(
81 | '(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)'
82 | );
83 | if (value) {
84 | value = decodeURIComponent(value[1]);
85 | try { value = JSON.parse(value); }
86 | catch (e) {}
87 | }
88 | return value || null;
89 | },
90 |
91 | /**
92 | * removes the cookie
93 | *
94 | * @return Cookie this
95 | */
96 | remove: function() {
97 | this.options.duration = -1;
98 | return this.set('');
99 | }
100 | });
101 |
--------------------------------------------------------------------------------
/src/dom/document.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A simple document wrapper
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | var Document = RightJS.Document = new Class(Wrapper, {
7 | // returns the window reference
8 | win: function() {
9 | return wrap(this._.defaultView || this._.parentWindow);
10 | }
11 | }),
12 |
13 | // a common local wrapped document reference
14 | current_Document = wrap(document);
15 |
--------------------------------------------------------------------------------
/src/dom/element.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The DOM Element unit handling
3 | *
4 | * Copyright (C) 2008-2011 Nikolay Nemshilov
5 | */
6 |
7 | var Element = RightJS.Element = new Class(Wrapper, {
8 | /**
9 | * constructor
10 | *
11 | * NOTE: this constructor will dynamically typecast
12 | * the wrappers depending on the element tag-name
13 | *
14 | * @param String element tag name or an HTMLElement instance
15 | * @param Object options
16 | * @return Element element
17 | */
18 | initialize: function(element, options) {
19 | Element_initialize(this, element, options);
20 | }
21 |
22 | }, Element_Klass),
23 |
24 | Element_wrappers = Element.Wrappers = {},
25 | elements_cache = {},
26 |
27 | /**
28 | * bulds dom-elements
29 | *
30 | * @param String element tag name
31 | * @param Object options
32 | * @return HTMLElement
33 | */
34 | make_element = function (tag, options) {
35 | return (tag in elements_cache ? elements_cache[tag] : (
36 | elements_cache[tag] = document.createElement(tag)
37 | )).cloneNode(false);
38 | };
39 |
40 | //
41 | // IE 6,7,8 (not 9!) browsers have a bug with checkbox and radio input elements
42 | // it doesn't place the 'checked' property correctly, plus there are some issues
43 | // with clonned SELECT objects, so we are replaceing the elements maker in here
44 | //
45 | if (IE8_OR_LESS) {
46 | make_element = function(tag, options) {
47 | if (options !== undefined && (tag === 'input' || tag === 'button')) {
48 | tag = '<'+ tag +' name="'+ options.name +
49 | '" type="'+ options.type +'"'+
50 | (options.checked ? ' checked' : '') + ' />';
51 |
52 | delete(options.name);
53 | delete(options.type);
54 | }
55 |
56 | return document.createElement(tag);
57 | };
58 | }
59 |
60 | /**
61 | * Basic element's constructor
62 | *
63 | * @param Element wrapper instance
64 | * @param mixed raw dom element of a string tag name
65 | * @param Object options
66 | * @return void
67 | */
68 | function Element_initialize(inst, element, options) {
69 | if (typeof element === 'string') {
70 | inst._ = make_element(element, options);
71 |
72 | if (options !== undefined) {
73 | for (var key in options) {
74 | switch (key) {
75 | case 'id': inst._.id = options[key]; break;
76 | case 'html': inst._.innerHTML = options[key]; break;
77 | case 'class': inst._.className = options[key]; break;
78 | case 'on': inst.on(options[key]); break;
79 | default: inst.set(key, options[key]);
80 | }
81 | }
82 | }
83 | } else {
84 | inst._ = element;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/dom/element/commons.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Common DOM Element unit methods
3 | *
4 | * Credits:
5 | * Most of the naming system in the module inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | *
8 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
9 | */
10 | Element.include({
11 | /**
12 | * sets the element attributes
13 | *
14 | * @param String attr name or Object attributes hash
15 | * @param mixed attribute value
16 | * @return Element self
17 | */
18 | set: function(hash, value) {
19 | if (typeof(hash) === 'string') { var val = {}; val[hash] = value; hash = val; }
20 |
21 | var key, element = this._;
22 |
23 | for (key in hash) {
24 | if (key === 'style') {
25 | this.setStyle(hash[key]);
26 | } else {
27 | // some attributes are not available as properties
28 | if (!(key in element)) {
29 | element.setAttribute(key, ''+hash[key]);
30 | }
31 | if (key.substr(0,5) !== 'data-') {
32 | element[key] = hash[key];
33 | }
34 | }
35 | }
36 |
37 | return this;
38 | },
39 |
40 | /**
41 | * returns the attribute value for the name
42 | *
43 | * @param String attr name
44 | * @return mixed value
45 | */
46 | get: function(name) {
47 | var element = this._, value = element[name] || element.getAttribute(name);
48 | return value === '' ? null : value;
49 | },
50 |
51 | /**
52 | * checks if the element has that attribute
53 | *
54 | * @param String attr name
55 | * @return Boolean check result
56 | */
57 | has: function(name) {
58 | return this.get(name) !== null;
59 | },
60 |
61 | /**
62 | * erases the given attribute of the element
63 | *
64 | * @param String attr name
65 | * @return Element self
66 | */
67 | erase: function(name) {
68 | this._.removeAttribute(name);
69 | return this;
70 | },
71 |
72 | /**
73 | * checks if the elemnt is hidden
74 | *
75 | * NOTE: will check css level computed styles too
76 | *
77 | * @return boolean check result
78 | */
79 | hidden: function() {
80 | return this.getStyle('display') === 'none';
81 | },
82 |
83 | /**
84 | * checks if the element is visible
85 | *
86 | * @return boolean check result
87 | */
88 | visible: function() {
89 | return !this.hidden();
90 | },
91 |
92 | /**
93 | * hides the element
94 | *
95 | * @param String optional effect name
96 | * @param Object the optional effect options
97 | * @return Element self
98 | */
99 | hide: function(effect, options) {
100 | if (this.visible()) {
101 | this._d = this.getStyle('display');
102 | this._.style.display = 'none';
103 | }
104 |
105 | return this;
106 | },
107 |
108 | /**
109 | * shows the element
110 | *
111 | * @return Element self
112 | */
113 | show: function() {
114 | if (this.hidden()) {
115 | var element = this._, value = this._d, dummy;
116 |
117 | // trying to guess the default 'style.display' for this kind of elements
118 | if (!value || value === 'none') {
119 | dummy = $E(element.tagName).insertTo(HTML);
120 | value = dummy.getStyle('display');
121 | dummy.remove();
122 | }
123 |
124 | // failsafe in case the user been naughty
125 | if (value === 'none') {
126 | value = 'block';
127 | }
128 |
129 | element.style.display = value;
130 | }
131 |
132 | return this;
133 | },
134 |
135 | /**
136 | * toggles the visibility state of the element
137 | *
138 | * @return Element self
139 | */
140 | toggle: function() {
141 | return this[this.visible() ? 'hide' : 'show']();
142 | },
143 |
144 | /**
145 | * shows the element and hides all the sibligns
146 | *
147 | * @param String optional effect name
148 | * @param Object the optional effect options
149 | * @return Element self
150 | */
151 | radio: function(effect, options) {
152 | this.siblings().each('hide', effect, options);
153 | return this.show();
154 | },
155 |
156 | /**
157 | * Sets/gets the `data-smth` data attribute and
158 | * automatically converts everything in/out JSON
159 | *
160 | * @param String key name
161 | * @param mixed data or `undefined` to erase
162 | * @return mixed Element self or extracted data
163 | */
164 | data: function(key, value) {
165 | var name, result, match, attrs, attr, i;
166 |
167 | if (isHash(key)) {
168 | for (name in key) {
169 | value = this.data(name, key[name]);
170 | }
171 | } else if (value === undefined) {
172 | key = 'data-'+ (''+key).dasherize();
173 |
174 | for (result = {}, match = false, attrs = this._.attributes, i=0; i < attrs.length; i++) {
175 | value = attrs[i].value;
176 | try { value = JSON.parse(value); } catch (e) {}
177 |
178 | if (attrs[i].name === key) {
179 | result = value;
180 | match = true;
181 | break;
182 | } else if (attrs[i].name.indexOf(key) === 0) {
183 | result[attrs[i].name.substring(key.length+1).camelize()] = value;
184 | match = true;
185 | }
186 | }
187 |
188 | value = match ? result : null;
189 | } else {
190 | key = 'data-'+ (''+key).dasherize();
191 |
192 | if (!isHash(value)) { value = {'': value}; }
193 |
194 | for (name in value) {
195 | attr = name.blank() ? key : key+'-'+name.dasherize();
196 |
197 | if (value[name] === null) {
198 | this._.removeAttribute(attr);
199 | } else {
200 | this._.setAttribute(attr, isString(value[name]) ? value[name] : JSON.stringify(value[name]));
201 | }
202 | }
203 |
204 | value = this;
205 | }
206 |
207 | return value;
208 | }
209 | });
210 |
--------------------------------------------------------------------------------
/src/dom/element/dimensions.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this module contains the Element's part of functionality
3 | * responsible for the dimensions and positions getting/setting
4 | *
5 | * Copyright (C) 2008-2011 Nikolay Nemshilov
6 | */
7 | Element.include({
8 | /**
9 | * Returns the reference to this element document
10 | *
11 | * @return RightJS.Document
12 | */
13 | doc: function() {
14 | return wrap(this._.ownerDocument);
15 | },
16 |
17 | /**
18 | * Returns the reference to this elements window
19 | *
20 | * @return RightJS.Window
21 | */
22 | win: function() {
23 | return this.doc().win();
24 | },
25 |
26 | /**
27 | * Returns the element size as a hash
28 | *
29 | * @return Object {x: NNN, y: NNN}
30 | */
31 | size: function() {
32 | return { x: this._.offsetWidth, y: this._.offsetHeight };
33 | },
34 |
35 | /**
36 | * Returns the element absolute position
37 | *
38 | * NOTE: see the konq.js file for the manual version of the method
39 | *
40 | * @return Object {x: NNN, y: NNN}
41 | */
42 | position: function() {
43 | var rect = this._.getBoundingClientRect(),
44 | html = this.doc()._.documentElement,
45 | scrolls = this.win().scrolls();
46 |
47 | return {
48 | x: rect.left + scrolls.x - html.clientLeft,
49 | y: rect.top + scrolls.y - html.clientTop
50 | };
51 | },
52 |
53 | /**
54 | * Returns the element scrolls
55 | *
56 | * @return Object {x: NNN, y: NNN}
57 | */
58 | scrolls: function() {
59 | return { x: this._.scrollLeft, y: this._.scrollTop };
60 | },
61 |
62 | /**
63 | * returns the element dimensions hash
64 | *
65 | * @return Object dimensions (top, left, width, height, scrollLeft, scrollTop)
66 | */
67 | dimensions: function() {
68 | var size = this.size(),
69 | scrolls = this.scrolls(),
70 | position = this.position();
71 |
72 | return {
73 | top: position.y,
74 | left: position.x,
75 | width: size.x,
76 | height: size.y,
77 | scrollLeft: scrolls.x,
78 | scrollTop: scrolls.y
79 | };
80 | },
81 |
82 | /**
83 | * Checks if the element overlaps the given position
84 | *
85 | * @param Object position {x: NNN, y: NNN}
86 | * @return boolean check result
87 | */
88 | overlaps: function(target) {
89 | var pos = this.position(), size = this.size();
90 |
91 | return target.x > pos.x && target.x < (pos.x + size.x) &&
92 | target.y > pos.y && target.y < (pos.y + size.y);
93 | },
94 |
95 | /**
96 | * sets the width of the element in pixels
97 | *
98 | * NOTE: will double assign the size of the element, so it match the exact
99 | * size including any possible borders and paddings
100 | *
101 | * @param Integer width in pixels
102 | * @return Element self
103 | */
104 | setWidth: function(width_px) {
105 | var style = this._.style;
106 | style.width = width_px + 'px';
107 | style.width = (2 * width_px - this._.offsetWidth) + 'px';
108 | return this;
109 | },
110 |
111 | /**
112 | * sets the width of the element in pixels
113 | *
114 | * NOTE: will double assign the size of the element, so it match the exact
115 | * size including any possible borders and paddings
116 | *
117 | * @param Integer height in pixels
118 | * @return Element self
119 | */
120 | setHeight: function(height_px) {
121 | var style = this._.style;
122 | style.height = height_px + 'px';
123 | style.height = (2 * height_px - this._.offsetHeight) + 'px';
124 | return this;
125 | },
126 |
127 | /**
128 | * sets the size of the element in pixels
129 | *
130 | * NOTE: will double assign the size of the element, so it match the exact
131 | * size including any possible borders and paddings
132 | *
133 | * @param width Integer width in pixels or {x: 10, y: 20} like object
134 | * @param height Integer height
135 | * @return Element self
136 | */
137 | resize: function(width, height) {
138 | if (isHash(width)) {
139 | height = width.y;
140 | width = width.x;
141 | }
142 | return this.setWidth(width).setHeight(height);
143 | },
144 |
145 | /**
146 | * sets the element position (against the window corner)
147 | *
148 | * @param left Number left position in pixels or an object like {x: 10, y: 20}
149 | * @param top Number top position in pixels
150 | * @return Element self
151 | */
152 | moveTo: function(left, top) {
153 | if (isHash(left)) {
154 | top = left.y;
155 | left = left.x;
156 | }
157 |
158 | return this.setStyle({
159 | left: left + 'px',
160 | top: top + 'px'
161 | });
162 | },
163 |
164 | /**
165 | * sets the scroll position
166 | *
167 | * @param left Integer left scroll px or an object like {x: 22, y: 33}
168 | * @param top Integer top scroll px
169 | * @return Element self
170 | */
171 | scrollTo: function(left, top) {
172 | if (isHash(left)) {
173 | top = left.y;
174 | left = left.x;
175 | }
176 |
177 | this._.scrollLeft = left;
178 | this._.scrollTop = top;
179 |
180 | return this;
181 | },
182 |
183 | /**
184 | * makes the window be scrolled to the element
185 | *
186 | * @param Object fx options
187 | * @return Element self
188 | */
189 | scrollThere: function(options) {
190 | this.win().scrollTo(this, options);
191 | return this;
192 | }
193 | });
194 |
--------------------------------------------------------------------------------
/src/dom/element/events.js:
--------------------------------------------------------------------------------
1 | /**
2 | * DOM Element events handling methods
3 | *
4 | * Copyright (C) 2008-2011 Nikolay Nemshilov
5 | */
6 | [Element, Document, Window].each('include', $ext(Observer_create({}), {
7 | /**
8 | * The basic events handling attachment method
9 | * SEE Observer#on for more details about supported arguments
10 | *
11 | * @returnt this
12 | */
13 | on: function() {
14 | Observer_on(this, arguments, function(hash) {
15 |
16 | if (hash.e === 'mouseenter' || hash.e === 'mouseleave') {
17 | mouse_io_activate();
18 | hash.n = hash.e;
19 | hash.w = function() {};
20 | // NOTE: we don't attach this listener to the actual element!
21 | // so it didn't screw with IE's native enter/leave handlers
22 | } else {
23 | if (hash.e === 'contextmenu' && Browser.Konqueror) {
24 | hash.n = 'rightclick';
25 | } else if (hash.e === 'mousewheel' && Browser.Gecko) {
26 | hash.n = 'DOMMouseScroll';
27 | } else {
28 | hash.n = hash.e;
29 | }
30 |
31 | hash.w = function(event) {
32 | event = new Event(event, hash.t);
33 | if (hash.f.apply(hash.t, (hash.r?[]:[event]).concat(hash.a)) === false) {
34 | event.stop();
35 | }
36 | };
37 |
38 | if (IE8_OR_LESS) {
39 | hash.t._.attachEvent('on'+hash.n, hash.w);
40 | } else {
41 | hash.t._.addEventListener(hash.n, hash.w, false);
42 | }
43 | }
44 |
45 | return hash;
46 | });
47 |
48 | return this;
49 | },
50 |
51 | /**
52 | * Stops an event handling
53 | *
54 | * @param String event name or a function callback
55 | * @param function callback or nothing
56 | * @return this
57 | */
58 | stopObserving: function(event, callback) {
59 | Observer_stopObserving(this, event, callback, function(hash) {
60 | if (IE8_OR_LESS) {
61 | hash.t._.detachEvent('on'+ hash.n, hash.w);
62 | } else {
63 | hash.t._.removeEventListener(hash.n, hash.w, false);
64 | }
65 | });
66 |
67 | return this;
68 | },
69 |
70 | /**
71 | * Artificially trigers the event on the element
72 | *
73 | * @param string event name or an Event instance
74 | * @param Object options
75 | * @return this
76 | */
77 | fire: function(event, options) {
78 | var parent = this.parent && this.parent();
79 |
80 | if (!(event instanceof Event)) {
81 | event = new Event(event, $ext({target: this._}, options));
82 | }
83 |
84 | // setting up the currentTarget reference
85 | event.currentTarget = this;
86 |
87 | (this.$listeners || []).each(function(hash) {
88 | if (hash.e === event.type &&
89 | hash.f.apply(this, (hash.r?[]:[event]).concat(hash.a)) === false
90 | ) {
91 | event.stop();
92 | }
93 | }, this);
94 |
95 | // manually bypassing the event to the parent one if it should bubble
96 | if (parent && parent.fire && !event.stopped) {
97 | parent.fire(event);
98 | }
99 |
100 | return this;
101 | },
102 |
103 | /**
104 | * a simple events terminator method to be hooked like this.onClick('stopEvent');
105 | *
106 | * @return false
107 | */
108 | stopEvent: function() { return false; }
109 | }));
110 |
111 | // couple more shortcuts for the window
112 | Observer_createShortcuts(Window.prototype, $w('blur focus scroll resize load'));
113 |
114 | /**
115 | * Registers a list of event-binding shortcuts like
116 | * $(element).onClick
117 | * $(element).onMouseover
118 | *
119 | * @param String space separated event names
120 | * @return void
121 | */
122 | function Element_add_event_shortcuts(tokens) {
123 | tokens = $w(tokens);
124 | Event_delegation_shortcuts = Event_delegation_shortcuts.concat(tokens);
125 |
126 | Observer_createShortcuts(Element.prototype, tokens);
127 | Observer_createShortcuts(Document.prototype, tokens);
128 | }
129 |
130 | Element_add_event_shortcuts(
131 | 'click rightclick contextmenu mousedown mouseup '+
132 | 'mouseover mouseout mousemove keypress keydown keyup'
133 | );
134 |
--------------------------------------------------------------------------------
/src/dom/element/styles.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this module contains the element unit styles related methods
3 | *
4 | * Credits:
5 | * Some of the functionality is inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
8 | * - Dojo (www.dojotoolkit.org) Copyright (C) The Dojo Foundation
9 | *
10 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
11 | */
12 | Element.include({
13 | /**
14 | * assigns styles out of the hash to the element
15 | *
16 | * NOTE: the style keys might be camelized or dasherized, both cases should work
17 | *
18 | * @param Object styles list or String style name
19 | * @param String style value in case of the first param a string style name
20 | * @return Element self
21 | */
22 | setStyle: function(hash, value) {
23 | var key, c_key, style = {}, element_style = this._.style;
24 |
25 | if (value !== undefined) { style[hash] = value; hash = style; }
26 | else if(isString(hash)) {
27 | hash.split(';').each(function(option) {
28 | var els = option.split(':').map('trim');
29 | if (els[0] && els[1]) {
30 | style[els[0]] = els[1];
31 | }
32 | });
33 | hash = style;
34 | }
35 |
36 |
37 | for (key in hash) {
38 | c_key = key.indexOf('-') < 0 ? key : key.camelize();
39 |
40 | if (IE_OPACITY && key === 'opacity') {
41 | element_style.filter = 'alpha(opacity='+ hash[key] * 100 +')';
42 | } else if (key === 'float') {
43 | c_key = Browser_IE ? 'styleFloat' : 'cssFloat';
44 | }
45 |
46 | element_style[c_key] = hash[key];
47 | }
48 |
49 | return this;
50 | },
51 |
52 | /**
53 | * returns style of the element
54 | *
55 | * NOTE: will include the CSS level definitions
56 | *
57 | * @param String style key
58 | * @return String style value or null if not set
59 | */
60 | getStyle: function(key) {
61 | return clean_style(this._.style, key) || clean_style(this.computedStyles(), key);
62 | },
63 |
64 | /**
65 | * returns the hash of computed styles for the element
66 | *
67 | * @return Object/CSSDefinition computed styles
68 | */
69 | computedStyles: HTML.currentStyle ? function() {
70 | return this._.currentStyle || {};
71 | } : HTML.runtimeStyle ? function() {
72 | return this._.runtimeStyle || {};
73 | } : function() {
74 | return this._.ownerDocument.defaultView.getComputedStyle(this._, null);
75 | },
76 |
77 | /**
78 | * checks if the element has the given class name
79 | *
80 | * @param String class name
81 | * @return boolean check result
82 | */
83 | hasClass: function(name) {
84 | return (' '+this._.className+' ').indexOf(' '+name+' ') != -1;
85 | },
86 |
87 | /**
88 | * sets the whole class-name string for the element
89 | *
90 | * @param String class-name
91 | * @return Element self
92 | */
93 | setClass: function(class_name) {
94 | this._.className = class_name;
95 | return this;
96 | },
97 |
98 | /**
99 | * Returns the current class-name
100 | *
101 | * @return String class-name
102 | */
103 | getClass: function() {
104 | return this._.className;
105 | },
106 |
107 | /**
108 | * adds the given class name to the element
109 | *
110 | * @param String class name
111 | * @return Element self
112 | */
113 | addClass: function(name) {
114 | var testee = ' '+this._.className+' ';
115 | if (testee.indexOf(' '+name+' ') == -1) {
116 | this._.className += (testee === ' ' ? '' : ' ') + name;
117 | }
118 | return this;
119 | },
120 |
121 | /**
122 | * removes the given class name
123 | *
124 | * @param String class name
125 | * @return Element self
126 | */
127 | removeClass: function(name) {
128 | this._.className = (' '+this._.className+' ').replace(' '+name+' ', ' ').trim();
129 | return this;
130 | },
131 |
132 | /**
133 | * toggles the given class name on the element
134 | *
135 | * @param String class name
136 | * @return Element self
137 | */
138 | toggleClass: function(name) {
139 | return this[this.hasClass(name) ? 'removeClass' : 'addClass'](name);
140 | },
141 |
142 | /**
143 | * adds the given class-name to the element
144 | * and removes it from all the element siblings
145 | *
146 | * @param String class name
147 | * @return Element self
148 | */
149 | radioClass: function(name) {
150 | this.siblings().each('removeClass', name);
151 | return this.addClass(name);
152 | }
153 | });
154 |
155 | /**
156 | * cleans up a style value
157 | *
158 | * @param Object styles hash
159 | * @param String style-key
160 | * @return String clean style
161 | */
162 | function clean_style(style, key) {
163 | key = key.camelize();
164 |
165 | if (key === 'opacity') {
166 | return IE_OPACITY ? (
167 | (/opacity=(\d+)/i.exec(style.filter || '') ||
168 | ['', '100'])[1].toInt() / 100
169 | )+'' :style[key].replace(',', '.');
170 | }
171 |
172 | if (key === 'float') {
173 | key = Browser_IE ? 'styleFloat' : 'cssFloat';
174 | }
175 |
176 | var value = style[key];
177 |
178 | // Opera returns named colors with quotes
179 | if (Browser_Opera && /color/i.test(key) && value) {
180 | value = value.replace(/"/g, '');
181 | }
182 |
183 | return value;
184 | }
185 |
--------------------------------------------------------------------------------
/src/dom/event.js:
--------------------------------------------------------------------------------
1 | /**
2 | * represents some additional functionality for the Event class
3 | *
4 | * NOTE: there more additional functionality for the Event class in the rightjs-goods project
5 | *
6 | * Credits:
7 | * The additional method names are inspired by
8 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
9 | *
10 | * Copyright (C) 2008-2011 Nikolay Nemshilov
11 | */
12 | var Event = RightJS.Event = new Class(Wrapper, {
13 | // predefining the keys to spped up the assignments
14 | type: null,
15 |
16 | which: null,
17 | keyCode: null,
18 |
19 | target: null,
20 | currentTarget: null,
21 | relatedTarget: null,
22 |
23 | pageX: null,
24 | pageY: null,
25 |
26 | /**
27 | * the class constructor
28 | *
29 | * @param raw dom-event
30 | * @param HTMLElement the bound element
31 | * @return void
32 | */
33 | initialize: Event_Klass, // the actual initialization happens in the Klass function
34 |
35 | /**
36 | * Stops the event bubbling process
37 | *
38 | * @return RightJS.Event this
39 | */
40 | stopPropagation: function() {
41 | if (this._.stopPropagation) {
42 | this._.stopPropagation();
43 | } else {
44 | this._.cancelBubble = true;
45 | }
46 |
47 | this.stopped = true;
48 | return this;
49 | },
50 |
51 | /**
52 | * Prevents the default browser action on the event
53 | *
54 | * @return RightJS.Event this
55 | */
56 | preventDefault: function() {
57 | if (this._.preventDefault) {
58 | this._.preventDefault();
59 | } else {
60 | this._.returnValue = false;
61 | }
62 |
63 | return this;
64 | },
65 |
66 | /**
67 | * Fully stops the event
68 | *
69 | * @return RightJS.Event this
70 | */
71 | stop: function() {
72 | return this.stopPropagation().preventDefault();
73 | },
74 |
75 | /**
76 | * Returns the event position
77 | *
78 | * @return Object {x: ..., y: ...}
79 | */
80 | position: function() {
81 | return {x: this.pageX, y: this.pageY};
82 | },
83 |
84 | /**
85 | * Returns the event's offset relative to the target element
86 | *
87 | * @return Object {x: ..., y: ...} or null
88 | */
89 | offset: function() {
90 | if(this.target instanceof Element) {
91 | var element_position = this.target.position();
92 |
93 | return {
94 | x: this.pageX - element_position.x,
95 | y: this.pageY - element_position.y
96 | };
97 | }
98 |
99 | // triggered outside browser window (at toolbar etc.)
100 | return null;
101 | },
102 |
103 | /**
104 | * Finds the element between the event target
105 | * and the boundary element that matches the
106 | * css-rule
107 | *
108 | * @param String css-rule
109 | * @return Element element or null
110 | */
111 | find: function(css_rule) {
112 | if (this.target instanceof Wrapper && this.currentTarget instanceof Wrapper) {
113 | var target = this.target._,
114 | search = this.currentTarget.find(css_rule, true);
115 |
116 | while (target) {
117 | if (search.indexOf(target) !== -1) {
118 | return wrap(target);
119 | }
120 | target = target.parentNode;
121 | }
122 | }
123 |
124 | return undefined;
125 | }
126 | }, Event_Klass),
127 |
128 | Event_delegation_shortcuts = [];
129 |
--------------------------------------------------------------------------------
/src/dom/event/focusin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This module provides correct focus/blur events bubbling
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 |
7 | /**
8 | * Triggers a manual focus/blur events bubbling
9 | *
10 | * @param raw dom-event
11 | * @return void
12 | */
13 | function focus_boobler(raw_event) {
14 | var event = new Event(raw_event),
15 | target = event.target,
16 | parent = target.parent && target.parent();
17 |
18 | event.type = raw_event.type === 'focusin' || raw_event.type === 'focus' ? 'focus' : 'blur';
19 |
20 | if (parent) { parent.fire(event); }
21 | }
22 |
23 | /**
24 | * Hooking up the 'focus' and 'blur' events
25 | * at the document level and then rebooble them
26 | * manually like they were normal events
27 | *
28 | */
29 | if (IE8_OR_LESS) {
30 | document.attachEvent('onfocusin', focus_boobler);
31 | document.attachEvent('onfocusout', focus_boobler);
32 | } else {
33 | document.addEventListener('focus', focus_boobler, true);
34 | document.addEventListener('blur', focus_boobler, true);
35 | }
36 |
--------------------------------------------------------------------------------
/src/dom/event/mouseio.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Provides the mouse enter/leave events handling emulation
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | var mouse_io_index = [], mouse_io_inactive = true;
7 |
8 | /**
9 | * Fires the actual mouseenter/mouseleave event
10 | *
11 | * @param original event
12 | * @param raw dom element
13 | * @param integer uid
14 | * @param boolean mouseenter or mouseleave
15 | * @return void
16 | */
17 | function mouse_io_fire(raw, element, uid, enter) {
18 | var event = new Event(raw);
19 | event.type = enter === true ? 'mouseenter' : 'mouseleave';
20 | event.bubbles = false;
21 | event.stopped = true;
22 | event.target = wrap(element);
23 |
24 | // replacing the #find method so that UJS didn't
25 | // get broke with trying to find nested elements
26 | event.find = function(css_rule) {
27 | return $$(css_rule, true)
28 | .indexOf(this.target._) === -1 ?
29 | undefined : this.target;
30 | };
31 |
32 | event.target.fire(event);
33 | current_Document.fire(event);
34 | }
35 |
36 | /**
37 | * Figures out the enter/leave events by listening the
38 | * mouseovers in the document
39 | *
40 | * @param raw dom event
41 | * @return void
42 | */
43 | function mouse_io_handler(e) {
44 | var target = e.target || e.srcElement,
45 | from = e.relatedTarget || e.fromElement,
46 | element = target,
47 | passed = false,
48 | parents = [],
49 | uid, event;
50 |
51 | while (element.nodeType === 1) {
52 | uid = $uid(element);
53 |
54 | if (mouse_io_index[uid] === undefined) {
55 | mouse_io_fire(e, element, uid,
56 | mouse_io_index[uid] = true
57 | );
58 | }
59 |
60 | if (element === from) {
61 | passed = true;
62 | }
63 |
64 | parents.push(element);
65 |
66 | element = element.parentNode;
67 | }
68 |
69 | if (from && !passed) {
70 | while (from !== null && from.nodeType === 1 && parents.indexOf(from) === -1) {
71 | uid = $uid(from);
72 | if (mouse_io_index[uid] !== undefined) {
73 | mouse_io_fire(e, from, uid,
74 | mouse_io_index[uid] = undefined
75 | );
76 | }
77 |
78 | from = from.parentNode;
79 | }
80 | }
81 | }
82 |
83 | /**
84 | * Calling 'mouseleave' for all currently active elements on the page
85 | *
86 | * @return void
87 | */
88 | function mouse_io_reset(e) {
89 | mouse_io_index.each(function(value, uid) {
90 | if (value && Wrappers_Cache[uid]) {
91 | mouse_io_fire(e, Wrappers_Cache[uid]._, uid, false);
92 | }
93 | });
94 | }
95 |
96 | /**
97 | * Activating the mouse-io events emulation
98 | *
99 | * @return void
100 | */
101 | function mouse_io_activate() {
102 | if (mouse_io_inactive) {
103 | mouse_io_inactive = false;
104 |
105 | if (Browser_IE) {
106 | document.attachEvent('onmouseover', mouse_io_handler);
107 | window.attachEvent('blur', mouse_io_reset);
108 | } else {
109 | document.addEventListener('mouseover', mouse_io_handler, false);
110 | window.addEventListener('blur', mouse_io_reset, false);
111 | }
112 | }
113 | }
114 |
115 | Element_add_event_shortcuts('mouseenter mouseleave');
--------------------------------------------------------------------------------
/src/dom/form.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The form unit class and extensions
3 | *
4 | * Credits:
5 | * The basic principles of the module are inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | *
8 | * Copyright (C) 2009-2011 Nikolay Nemshilov
9 | */
10 |
11 | var Form = RightJS.Form = Element_wrappers.FORM = new Class(Element, {
12 | /**
13 | * constructor
14 | *
15 | * NOTE: this constructor can be called as a normal Element constructor
16 | * or with the options only, which will make a FORM element
17 | *
18 | * var form = new Form(raw_form_object_element);
19 | * var form = new Form({method: 'post', action: '/boo/hoo'});
20 | *
21 | * @param Object options or HTMLFormElement object
22 | * @return void
23 | */
24 | initialize: function(in_options) {
25 | var options = in_options || {}, remote = 'remote' in options, element = options;
26 |
27 | if (isHash(options) && !isElement(options)) {
28 | element = 'form';
29 | options = Object.without(options, 'remote');
30 | }
31 |
32 | this.$super(element, options);
33 |
34 | if (remote) {
35 | this.remotize();
36 | }
37 | },
38 |
39 | /**
40 | * returns the form elements as an array of extended units
41 | *
42 | * @return Array of elements
43 | */
44 | elements: function() {
45 | return this.find('input,button,select,textarea');
46 | },
47 |
48 | /**
49 | * returns the list of all the input elements on the form
50 | *
51 | * @return Array of elements
52 | */
53 | inputs: function() {
54 | return this.elements().filter(function(input) {
55 | return !['submit', 'button', 'reset', 'image', null].include(input._.type);
56 | });
57 | },
58 |
59 | /**
60 | * Accessing an input by name
61 | *
62 | * @param String name
63 | * @return Input field
64 | */
65 | input: function(name) {
66 | var input = this._[name];
67 |
68 | if ('tagName' in input) {
69 | input = wrap(input);
70 | } else { // a list of radio-buttons (coz they have all the same name)
71 | input = $A(input).map(wrap);
72 | }
73 |
74 | return input;
75 | },
76 |
77 | /**
78 | * focuses on the first input element on the form
79 | *
80 | * @return Form this
81 | */
82 | focus: function() {
83 | var element = this.inputs().first(function(input) {
84 | return input._.type !== 'hidden';
85 | });
86 |
87 | if (element) { element.focus(); }
88 |
89 | return this;
90 | },
91 |
92 | /**
93 | * removes focus out of all the form elements
94 | *
95 | * @return Form this
96 | */
97 | blur: function() {
98 | this.elements().each('blur');
99 | return this;
100 | },
101 |
102 | /**
103 | * disables all the elements on the form
104 | *
105 | * @return Form this
106 | */
107 | disable: function() {
108 | this.elements().each('disable');
109 | return this;
110 | },
111 |
112 | /**
113 | * enables all the elements on the form
114 | *
115 | * @return Form this
116 | */
117 | enable: function() {
118 | this.elements().each('enable');
119 | return this;
120 | },
121 |
122 | /**
123 | * returns the list of the form values
124 | *
125 | * @return Object values
126 | */
127 | values: function() {
128 | var values = {};
129 |
130 | this.inputs().each(function (element) {
131 | var input = element._,
132 | hash = values, key,
133 | keys = input.name.match(/[^\[]+/g);
134 |
135 | if (!input.disabled && input.name && (!(input.type === 'checkbox' || input.type === 'radio') || input.checked)) {
136 | // getting throught the smth[smth][smth][] in the name
137 | while (keys.length > 1) {
138 | key = keys.shift();
139 | if (key.endsWith(']')) {
140 | key = key.substr(0, key.length-1);
141 | }
142 | if (!hash[key]) {
143 | hash[key] = keys[0] === ']' ? [] : {};
144 | }
145 | hash = hash[key];
146 | }
147 |
148 | key = keys.shift();
149 | if (key.endsWith(']')) {
150 | key = key.substr(0, key.length-1);
151 | }
152 |
153 | if (key === '') { // an array
154 | hash.push(element.value());
155 | } else {
156 | hash[key] = element.value();
157 | }
158 | }
159 | });
160 |
161 | return values;
162 | },
163 |
164 | /**
165 | * returns the key/values organized ready to be sent via a get request
166 | *
167 | * @return String serialized values
168 | */
169 | serialize: function() {
170 | return Object.toQueryString(this.values());
171 | },
172 |
173 | /**
174 | * Delegating the submit method
175 | *
176 | * @return Form this
177 | */
178 | submit: function() {
179 | this._.submit();
180 | return this;
181 | },
182 |
183 | /**
184 | * Delegating the 'reset' method
185 | *
186 | * @return Form this
187 | */
188 | reset: function() {
189 | this._.reset();
190 | return this;
191 | }
192 | });
193 |
194 | // creating the event shortcuts
195 | Element_add_event_shortcuts('submit reset focus blur disable enable change');
196 |
--------------------------------------------------------------------------------
/src/dom/input.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The form input element class
3 | *
4 | * Copyright (C) 2010-2011 Nikolay Nemshilov
5 | */
6 | var Input = RightJS.Input =
7 |
8 | // retgistering the typecasted wrappers
9 | Element_wrappers.INPUT =
10 | Element_wrappers.BUTTON =
11 | Element_wrappers.SELECT =
12 | Element_wrappers.TEXTAREA =
13 | Element_wrappers.OPTGROUP =
14 |
15 | new Class(Element, {
16 | /**
17 | * Constructor
18 | *
19 | * NOTE: this constructor can be called in several ways
20 | *
21 | * Like normal Element
22 | * var input = new Input('texarea', {...});
23 | * var input = new Input(document.createElement('select'));
24 | *
25 | * Or with options only which will make an INPUT element by default
26 | * var input = new Input({type: 'password', name: 'password'});
27 | *
28 | * @param HTMLElement or a String tag name or Options for default 'input' tag
29 | * @param Object options
30 | * @return void
31 | */
32 | initialize: function(element, options) {
33 | // type to tag name conversion
34 | if (!element || (isHash(element) && !isElement(element))) {
35 | options = element || {};
36 |
37 | if (/textarea|select/.test(options.type || '')) {
38 | element = options.type;
39 | delete(options.type);
40 | } else {
41 | element = 'input';
42 | }
43 | }
44 |
45 | this.$super(element, options);
46 | },
47 |
48 | /**
49 | * Returns a reference to the input's form
50 | *
51 | * @return Form wrapped form
52 | */
53 | form: function() {
54 | return wrap(this._.form);
55 | },
56 |
57 | /**
58 | * Overloading the method to fix some issues with IE and FF
59 | *
60 | * @param mixed content
61 | * @param string optional position
62 | * @return Input this
63 | */
64 | insert: function(content, position) {
65 | this.$super(content, position);
66 |
67 | // manually resetting the selected option in here
68 | this.find('option').each(function(option) {
69 | option._.selected = !!option.get('selected');
70 | });
71 |
72 | return this;
73 | },
74 |
75 | /**
76 | * Overloading the method so it always called the '#insert' method
77 | *
78 | * @param mixed content
79 | * @return Input this
80 | */
81 | update: function(content) {
82 | return this.clean().insert(content);
83 | },
84 |
85 | /**
86 | * uniform access to the element values
87 | *
88 | * @return String element value
89 | */
90 | getValue: function() {
91 | if (this._.type == 'select-multiple') {
92 | return this.find('option').map(function(option) {
93 | return option._.selected ? option._.value : null;
94 | }).compact();
95 | } else {
96 | return this._.value;
97 | }
98 | },
99 |
100 | /**
101 | * uniform accesss to set the element value
102 | *
103 | * @param String value
104 | * @return Element this
105 | */
106 | setValue: function(value) {
107 | if (this._.type == 'select-multiple') {
108 | value = ensure_array(value).map(String);
109 | this.find('option').each(function(option) {
110 | option._.selected = value.include(option._.value);
111 | });
112 | } else {
113 | this._.value = value;
114 | }
115 | return this;
116 | },
117 |
118 | /**
119 | * Both ways getter/setter for the value parameter
120 | *
121 | * @param mixed value
122 | * @return mixed this or the value
123 | */
124 | value: function(value) {
125 | return this[value === undefined ? 'getValue' : 'setValue'](value);
126 | },
127 |
128 | /**
129 | * focuses on the first input element on the form
130 | *
131 | * @return Form this
132 | */
133 | focus: function() {
134 | this._.focus();
135 | this.focused = true;
136 | if (Browser_IE) { this.fire('focus', {bubbles: false}); }
137 | return this;
138 | },
139 |
140 | /**
141 | * removes focus out of all the form elements
142 | *
143 | * @return Form this
144 | */
145 | blur: function() {
146 | this._.blur();
147 | this.focused = false;
148 | if (Browser_IE) { this.fire('blur', {bubbles: false}); }
149 | return this;
150 | },
151 |
152 | /**
153 | * focuses on the element and selects its content
154 | *
155 | * @return Element this
156 | */
157 | select: function() {
158 | this._.select();
159 | return this.focus();
160 | },
161 |
162 | /**
163 | * disables all the elements on the form
164 | *
165 | * @return Form this
166 | */
167 | disable: function() {
168 | this._.disabled = true;
169 | return this.fire('disable');
170 | },
171 |
172 | /**
173 | * enables all the elements on the form
174 | *
175 | * @return Form this
176 | */
177 | enable: function() {
178 | this._.disabled = false;
179 | return this.fire('enable');
180 | },
181 |
182 | /**
183 | * A bidirectional method to set/get the disabled status of the input field
184 | *
185 | * @param boolean optional value
186 | * @return Input in setter mode boolean in getter
187 | */
188 | disabled: function(value) {
189 | return value === undefined ? this._.disabled : this[value ? 'disable' : 'enable']();
190 | },
191 |
192 | /**
193 | * A bidirectional method to set/get the checked status of the input field
194 | *
195 | * @param boolean optional value
196 | * @return Input in setter mode boolean in getter
197 | */
198 | checked: function(value) {
199 | if (value === undefined) {
200 | value = this._.checked;
201 | } else {
202 | this._.checked = value;
203 | value = this;
204 | }
205 |
206 | return value;
207 | }
208 | });
209 |
--------------------------------------------------------------------------------
/src/dom/ready.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The dom-ready event handling code
3 | *
4 | * Credits:
5 | * The basic principles of the module are originated from
6 | * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
7 | *
8 | * Copyright (C) 2009-2011 Nikolay Nemshilov
9 | */
10 | Document.include({
11 | on: function(name) {
12 | if (name === 'ready' && !this._iR) {
13 | var document = this._, ready = this.fire.bind(this, 'ready');
14 |
15 | // IE and Konqueror browsers
16 | if ('readyState' in document) {
17 | (function() {
18 | if (['loaded','complete'].include(document.readyState)) {
19 | ready();
20 | } else {
21 | arguments.callee.delay(50);
22 | }
23 | })();
24 | } else {
25 | document.addEventListener('DOMContentLoaded', ready, false);
26 | }
27 |
28 | this._iR = true;
29 | }
30 |
31 | return this.$super.apply(this, arguments);
32 | }
33 | });
34 |
35 | Observer_createShortcuts(Document.prototype, ['ready']);
--------------------------------------------------------------------------------
/src/dom/selector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The DOM elements selection handling
3 | *
4 | * NOTE: this module is just a wrap over the native CSS-selectors feature
5 | * see the olds/css.js file for the manual selector code
6 | *
7 | * Copyright (C) 2008-2011 Nikolay Nemshilov
8 | */
9 |
10 | [Element, Document].each('include', {
11 | /**
12 | * Extracts the first element matching the css-rule,
13 | * or just any first element if no css-rule was specified
14 | *
15 | * @param String css-rule
16 | * @return Element matching node or null
17 | */
18 | first: function(css_rule) {
19 | return wrap(
20 | css_rule === undefined && this._.firstElementChild !== undefined ?
21 | this._.firstElementChild : this._.querySelector(css_rule || '*')
22 | );
23 | },
24 |
25 | /**
26 | * Finds a list of matching nodes, or all the descendant nodes if no css-rule provided
27 | *
28 | * @param String css-rule
29 | * @param boolean raw-search
30 | * @return Array of elements
31 | */
32 | find: function(css_rule, raw) {
33 | var query = this._.querySelectorAll(css_rule || '*'), result, i=0, l = query.length;
34 |
35 | if (raw === true) {
36 | result = $A(query);
37 | } else {
38 | for (result = []; i < l; i++) {
39 | result[i] = wrap(query[i]);
40 | }
41 | }
42 |
43 | return result;
44 | },
45 |
46 | /**
47 | * checks if the element matches this css-rule
48 | *
49 | * NOTE: the element should be attached to the page
50 | *
51 | * @param String css-rule
52 | * @return Boolean check result
53 | */
54 | match: function(css_rule) {
55 | // finding the top parent element (the element might not be on the document)
56 | var element = this._, parent = element, result, faking = false;
57 |
58 | while (parent.parentNode !== null && parent.parentNode.nodeType !== 11) {
59 | parent = parent.parentNode;
60 | }
61 |
62 | // creating a fake context when needed
63 | if (element === parent) {
64 | parent = document.createElement('div');
65 | parent.appendChild(element);
66 | faking = true;
67 | }
68 |
69 | result = wrap(parent).find(css_rule, true).indexOf(element) !== -1;
70 |
71 | if (faking) {
72 | parent.removeChild(element);
73 | }
74 |
75 | return result;
76 | }
77 | });
78 |
--------------------------------------------------------------------------------
/src/dom/string.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Some String level shortcuts to handle collections of elements
3 | *
4 | * Copyright (C) 2011 Nikolay Nemshilov
5 | */
6 |
7 | /**
8 | * Some nice shortcuts for the document-level events delegation handling
9 | *
10 | * USAGE:
11 | *
12 | * "ul#main-menu li".on("click", function() { alert('clicked'); });
13 | * "ul#main-menu li".on("mouseover", "addClass", "hovered");
14 | * "ul#main-menu li".on("mouseout", "removeClass", "hovered");
15 | *
16 | * // or like that in a shash
17 | * "ul#main-menu li".on({
18 | * click: function() { alert('clicked'); },
19 | * mouseover: ['addClass', 'hovered'],
20 | * mouseout: ['removeClass', 'hovered'],
21 | * dblclick: 'hide'
22 | * });
23 | *
24 | *
25 | * "#css.rule".observes('click');
26 | * "#css.rule".observes('click', function() {});
27 | * "#css.rule".observes('click', 'method_name');
28 | * ....
29 | *
30 | * "#css.rule".stopObserving('click');
31 | * "#css.rule".stopObserving('click', function() {});
32 | * "#css.rule".stopObserving('click', 'method_name');
33 | * ....
34 | */
35 | Object.each({
36 | on: 'delegate',
37 | stopObserving: 'undelegate',
38 | observes: 'delegates'
39 | }, function(name, method) {
40 | String.prototype[name] = function() {
41 | var args = $A(arguments), result;
42 |
43 | args.splice(1,0,''+this);
44 | result = current_Document[method].apply(current_Document, args);
45 |
46 | return result === current_Document ? this : result;
47 | };
48 | });
49 | var old_on = String.prototype.on;
50 | String.prototype.on = function(hash) {
51 | if (isHash(hash)) {
52 | for (var key in hash) {
53 | old_on.apply(this, [key].concat([hash[key]]));
54 | }
55 | } else {
56 | old_on.apply(this, arguments);
57 | }
58 | return this;
59 | };
60 |
61 | /**
62 | * building the list of String#onEvent shortucts
63 | *
64 | * USAGE:
65 | *
66 | * "#css.rule".onClick(function() {...});
67 | * "#css.rule".onMouseover('method_name');
68 | */
69 | Event_delegation_shortcuts.each(function(name) {
70 | String.prototype['on'+name.capitalize()] = function() {
71 | return this.on.apply(this, [name].concat($A(arguments)));
72 | };
73 | });
74 |
75 | /**
76 | * The rest of the DOM methods access
77 | *
78 | * USAGE:
79 | * "#css.rule".addClass('boo-hoo');
80 | * "#css.rule".setStyle({color: 'red'});
81 | *
82 | */
83 | $w('Element Input Form').each(function(klass) {
84 | Object.each(klass in RightJS ? RightJS[klass].prototype : {}, function(name, method) {
85 | if (isFunction(method) && !(name in String.prototype)) {
86 | String.prototype[name] = function() {
87 | var nodes = $$(this, true), i=0, l = nodes.length, first=true, element, result;
88 | for (; i < l; i++) {
89 | element = wrap(nodes[i]);
90 | result = element[name].apply(element, arguments);
91 |
92 | // checking if that's a data-retrieving call
93 | if (first) {
94 | if (result !== element) {
95 | return result;
96 | }
97 | first = false;
98 | }
99 | }
100 |
101 | // don't return the string itself in here,
102 | // it will screw with data-retrieving calls on empty collections
103 | return null;
104 | };
105 | }
106 | });
107 | });
--------------------------------------------------------------------------------
/src/dom/window.js:
--------------------------------------------------------------------------------
1 | /**
2 | * the window object extensions
3 | *
4 | * Copyright (C) 2008-2011 Nikolay Nemshilov
5 | */
6 | var Window = RightJS.Window = new Class(Wrapper, {
7 | /**
8 | * Selfreference to have a common interface with the rest of the wrappers
9 | * in case of events handling
10 | *
11 | * @return Window
12 | */
13 | win: function() {
14 | return this;
15 | },
16 |
17 | /**
18 | * returns the inner-size of the window
19 | *
20 | * @return Object x: d+, y: d+
21 | */
22 | size: function() {
23 | var win = this._, html = win.document.documentElement;
24 | return win.innerWidth ? {x: win.innerWidth, y: win.innerHeight} :
25 | {x: html.clientWidth, y: html.clientHeight};
26 | },
27 |
28 | /**
29 | * returns the scrolls for the window
30 | *
31 | * @return Object x: d+, y: d+
32 | */
33 | scrolls: function() {
34 | var win = this._, doc = win.document, body = doc.body, html = doc.documentElement;
35 |
36 | return (win.pageXOffset || win.pageYOffset) ? {x: win.pageXOffset, y: win.pageYOffset} :
37 | (body && (body.scrollLeft || body.scrollTop)) ? {x: body.scrollLeft, y: body.scrollTop} :
38 | {x: html.scrollLeft, y: html.scrollTop};
39 | },
40 |
41 | /**
42 | * overloading the native scrollTo method to support hashes and element references
43 | *
44 | * @param mixed number left position, a hash position, element or a string element id
45 | * @param number top position
46 | * @param Object fx options
47 | * @return window self
48 | */
49 | scrollTo: function(left, top, fx_options) {
50 | var left_pos = left, top_pos = top,
51 | element = isNumber(left) ? null : $(left);
52 |
53 | if(element instanceof Element) {
54 | left = element.position();
55 | }
56 |
57 | if (isHash(left)) {
58 | top_pos = left.y;
59 | left_pos = left.x;
60 | }
61 |
62 | // checking if a smooth scroll was requested
63 | if (isHash(fx_options = fx_options || top) && RightJS.Fx) {
64 | new Fx.Scroll(this, fx_options).start({x: left_pos, y: top_pos});
65 | } else {
66 | this._.scrollTo(left_pos, top_pos);
67 | }
68 |
69 | return this;
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/src/dom/wrapper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The dom-wrapper main unit
3 | *
4 | * This unit is basically for the internal use
5 | * so that we could control the common functionality
6 | * among all the wrappers
7 | *
8 | * Copyright (C) 2010-2011 Nikolay Nemshilov
9 | */
10 |
11 | var Wrapper = RightJS.Wrapper = new Class({
12 | // predefining the property in the prototype
13 | _: undefined,
14 |
15 | /**
16 | * Default constructor
17 | *
18 | * @param mixed raw dom unit
19 | * @return void
20 | */
21 | initialize: function(raw_object) {
22 | this._ = raw_object;
23 | }
24 | });
25 |
26 | // exposing the cache so it could be manupulated externally
27 | Wrapper.Cache = Wrappers_Cache;
28 |
29 | // instantiating the actual class object for a wrapper
30 | function Wrapper_makeKlass() {
31 | /**
32 | * Default wrappers Klass function
33 | *
34 | * @param mixed the raw object
35 | * @param Object options
36 | * @return void
37 | */
38 | return function(object, options) {
39 | Class_checkPrebind(this);
40 |
41 | this.initialize.apply(this, arguments); // <- there might be a different number of args in a subclass
42 |
43 | var item = this._, uid = UID_KEY in item ? item[UID_KEY] :
44 | // NOTE we use positive indexes for dom-elements and negative for everything else
45 | (item[UID_KEY] = (item.nodeType === 1 ? 1 : -1) * UID++);
46 |
47 | Wrappers_Cache[uid] = this;
48 | };
49 | }
50 |
51 | /**
52 | * Element's own Klass function
53 | * we need that because it does some dynamic typecasting mumbo jumbo
54 | * plus we would like to optimize some stuff here and there
55 | *
56 | * @param raw dom element or the tag name
57 | * @param Object options
58 | * @return Element instance
59 | */
60 | function Element_Klass(element, options) {
61 | Element_initialize(this, element, options);
62 |
63 | var inst = this, raw = inst._, cast = Wrapper.Cast(raw),
64 | uid = UID_KEY in raw ? raw[UID_KEY] : (raw[UID_KEY] = UID++);
65 |
66 | if (cast !== undefined) {
67 | inst = new cast(raw, options);
68 | if ('$listeners' in this) {
69 | inst.$listeners = this.$listeners;
70 | }
71 | }
72 |
73 | Wrappers_Cache[uid] = inst;
74 |
75 | return inst;
76 | }
77 |
78 | // searches for a suitable class for dynamic typecasting
79 | Wrapper.Cast = function(unit) {
80 | return unit.tagName in Element_wrappers ? Element_wrappers[unit.tagName] : undefined;
81 | };
82 |
83 | /**
84 | * Event's own Klass function, we don't need to check
85 | * nothing in here, don't need to hit the wrappers cache and so one
86 | *
87 | * @param raw dom-event or a string event-name
88 | * @param bounding element or an object with options
89 | * @return void
90 | */
91 | function Event_Klass(event, bound_element) {
92 | if (typeof(event) === 'string') {
93 | event = $ext({type: event}, bound_element);
94 | this.stopped = event.bubbles === false;
95 |
96 | if (isHash(bound_element)) {
97 | $ext(this, bound_element);
98 | }
99 | }
100 |
101 | this._ = event;
102 | this.type = event.type;
103 |
104 | this.which = event.which;
105 | this.keyCode = event.keyCode;
106 |
107 | this.target = wrap(
108 | // Webkit throws events on textual nodes as well, gotta fix that
109 | event.target != null && 'nodeType' in event.target && event.target.nodeType === 3 ?
110 | event.target.parentNode : event.target
111 | );
112 |
113 | this.currentTarget = wrap(event.currentTarget);
114 | this.relatedTarget = wrap(event.relatedTarget);
115 |
116 | this.pageX = event.pageX;
117 | this.pageY = event.pageY;
118 |
119 | // making old IE attrs looks like w3c standards
120 | if (IE8_OR_LESS && 'srcElement' in event) {
121 | this.which = event.button === 2 ? 3 : event.button === 4 ? 2 : 1;
122 |
123 | this.target = wrap(event.srcElement) || bound_element;
124 | this.relatedTarget = this.target._ === event.fromElement ? wrap(event.toElement) : this.target;
125 | this.currentTarget = bound_element;
126 |
127 | var scrolls = this.target.win().scrolls();
128 |
129 | this.pageX = event.clientX + scrolls.x;
130 | this.pageY = event.clientY + scrolls.y;
131 | }
132 | }
133 |
134 |
135 | /**
136 | * Private quick wrapping function, unlike `$`
137 | * it doesn't search by ID and handle double-wrapps
138 | * just pure dom-wrapping functionality
139 | *
140 | * @param raw dom unit
141 | * @return Wrapper dom-wrapper
142 | */
143 | function wrap(object) {
144 | if (object != null) {
145 | var wrapper = UID_KEY in object ? Wrappers_Cache[object[UID_KEY]] : undefined;
146 |
147 | if (wrapper !== undefined) {
148 | return wrapper;
149 | } else if (object.nodeType === 1) {
150 | return new Element(object);
151 | } else if (object.nodeType === 9) {
152 | return new Document(object);
153 | } else if (object.window == object) {
154 | return new Window(object);
155 | } else if (isElement(object.target) || isElement(object.srcElement)) {
156 | return new Event(object);
157 | }
158 | }
159 |
160 | return object;
161 | }
--------------------------------------------------------------------------------
/src/fx/element.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This block contains additional Element shortcuts for effects easy handling
3 | *
4 | * Credits:
5 | * Some ideas are inspired by
6 | * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
7 | *
8 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
9 | */
10 | Element.include({
11 | /**
12 | * Stops all the visual effects on the element
13 | *
14 | * @return Element this
15 | */
16 | stop: function() {
17 | fx_cancel_all(this);
18 | return this;
19 | },
20 |
21 | /**
22 | * hides the element with given visual effect
23 | *
24 | * @param String fx name
25 | * @param Object fx options
26 | * @return Element this
27 | */
28 | hide: function(fx, options) {
29 | return (fx && this.visible()) ? call_fx(this, fx, ['out', options]) : this.$super();
30 | },
31 |
32 | /**
33 | * shows the element with the given visual effect
34 | *
35 | * @param String fx name
36 | * @param Object fx options
37 | * @return Element this
38 | */
39 | show: function(fx, options) {
40 | return (fx && !this.visible()) ? call_fx(this, fx, ['in', options]) : this.$super();
41 | },
42 |
43 | /**
44 | * Toggles the element state with visual effect
45 | *
46 | * @param String fx name
47 | * @param Object fx options
48 | * @return Element this
49 | */
50 | toggle: function(fx, options) {
51 | return fx ? call_fx(this, fx, ['toggle', options]) : this.$super();
52 | },
53 |
54 | /**
55 | * Removes the element out of the DOM structure
56 | *
57 | * @param String fx name
58 | * @param Object fx options
59 | * @return Element this
60 | */
61 | remove: function(fx, options) {
62 | return (fx && this.visible()) ? call_fx(this, fx, ['out', $ext(options || {}, {
63 | onFinish: this.$super.bind(this)
64 | })]) : this.$super();
65 | },
66 |
67 | /**
68 | * runs the Fx.Morth effect to the given style
69 | *
70 | * @param style Object style
71 | * @param options Object optional effect options
72 | * @return Element self
73 | */
74 | morph: function(style, options) {
75 | return call_fx(this, 'morph', [style, options || {}]); // <- don't replace with arguments
76 | },
77 |
78 | /**
79 | * highlights the element
80 | *
81 | * @param start String start color
82 | * @param end String optional end color
83 | * @param Object effect options
84 | * @return Element self
85 | */
86 | highlight: function() {
87 | return call_fx(this, 'highlight', arguments);
88 | },
89 |
90 | /**
91 | * runs the Fx.Fade effect on the element
92 | *
93 | * @param mixed fade direction 'in' 'out' or a float number
94 | * @return Element self
95 | */
96 | fade: function() {
97 | return call_fx(this, 'fade', arguments);
98 | },
99 |
100 | /**
101 | * runs the Fx.Slide effect on the element
102 | *
103 | * @param String 'in' or 'out'
104 | * @param Object effect options
105 | * @return Element self
106 | */
107 | slide: function() {
108 | return call_fx(this, 'slide', arguments);
109 | },
110 |
111 | /**
112 | * Starts the smooth scrolling effect
113 | *
114 | * @param position Object {x: NNN, y: NNN} where to scroll
115 | * @param options Object fx-options
116 | * @return Element this
117 | */
118 | scroll: function(value, options) {
119 | return call_fx(this, 'scroll', [value, options||{}]);
120 | },
121 |
122 | /**
123 | * wraps the old scroll to be able to run it with fxes
124 | *
125 | * If you send two hashes then will start a smooth scrolling
126 | * otherwise will just jump over with the usual method
127 | *
128 | * @return Element this
129 | */
130 | scrollTo: function(value, options) {
131 | return isHash(options) ? this.scroll(value, options) : this.$super.apply(this, arguments);
132 | }
133 | });
134 |
135 | /**
136 | * Calls the visual effect on the element
137 | *
138 | * @param Element context
139 | * @param String fx-name
140 | * @param Object fx-options
141 | * @return Element context
142 | */
143 | function call_fx(element, name, params) {
144 | var args = $A(params).compact(),
145 | options = isHash(args.last()) ? args.pop() : {},
146 | fx = new Fx[name.capitalize()](element, options);
147 |
148 | fx.start.apply(fx, args);
149 |
150 | return element;
151 | }
152 |
--------------------------------------------------------------------------------
/src/fx/fx/attr.js:
--------------------------------------------------------------------------------
1 | /**
2 | * An abstract attributes based Fx
3 | *
4 | * Copyright (C) 2010 Nikolay Nemshilov
5 | */
6 | Fx.Attr = new Class(Fx, {
7 |
8 | prepare: function(attrs) {
9 | this.before = {};
10 | this.after = attrs;
11 | var key, element = this.element._;
12 |
13 | for (key in attrs) {
14 | this.before[key] = element[key];
15 | }
16 | },
17 |
18 | render: function(delta) {
19 | var key, element = this.element._, before = this.before;
20 | for (key in before) {
21 | element[key] = before[key] + (this.after[key] - before[key]) * delta;
22 | }
23 | }
24 |
25 | });
--------------------------------------------------------------------------------
/src/fx/fx/fade.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The opacity effects wrapper
3 | *
4 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5 | */
6 | Fx.Fade = new Class(Fx.Twin, {
7 | prepare: function(how) {
8 | this.setHow(how);
9 |
10 | if (this.how === 'in') {
11 | // calling 'prototype' to prevent circular calls from subclasses
12 | Element.prototype.show.call(this.element.setStyle({opacity: 0}));
13 | }
14 |
15 | return this.$super({opacity: this.how === 'in' ? 1 : 0});
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/src/fx/fx/highlight.js:
--------------------------------------------------------------------------------
1 | /**
2 | * the elements hightlighting effect
3 | *
4 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5 | */
6 | Fx.Highlight = new Class(Fx.Morph, {
7 | extend: {
8 | Options: Object.merge(Fx.Options, {
9 | color: '#FF8',
10 | transition: 'Exp'
11 | })
12 | },
13 |
14 | // protected
15 |
16 | /**
17 | * starts the transition
18 | *
19 | * @param high String the hightlight color
20 | * @param back String optional fallback color
21 | * @return self
22 | */
23 | prepare: function(start, end) {
24 | var element = this.element,
25 | element_style = element._.style,
26 | style_name = 'backgroundColor',
27 | end_color = end || element.getStyle(style_name);
28 |
29 | if (is_transparent(end_color)) {
30 | this.onFinish(function() { element_style[style_name] = 'transparent'; });
31 |
32 | // trying to find the end color
33 | end_color = [element].concat(element.parents())
34 | .map('getStyle', style_name)
35 | .reject(is_transparent)
36 | .compact().first() || '#FFF';
37 | }
38 |
39 | element_style[style_name] = (start || this.options.color);
40 |
41 | return this.$super({backgroundColor: end_color});
42 | }
43 | });
44 |
--------------------------------------------------------------------------------
/src/fx/fx/scroll.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A smooth scrolling visual effect
3 | *
4 | * Copyright (C) 2009-2011 Nikolay Nemshilov
5 | */
6 | Fx.Scroll = new Class(Fx.Attr, {
7 |
8 | initialize: function(element, options) {
9 | element = $(element);
10 | // swapping the actual scrollable when it's the window
11 | this.$super(
12 | element instanceof Window ?
13 | element._.document[
14 | Browser.WebKit ? 'body' : 'documentElement'
15 | ] : element,
16 | options
17 | );
18 | },
19 |
20 | prepare: function(value) {
21 | var attrs = {};
22 |
23 | if ('x' in value) { attrs.scrollLeft = value.x; }
24 | if ('y' in value) { attrs.scrollTop = value.y; }
25 |
26 | this.$super(attrs);
27 | }
28 |
29 | });
30 |
--------------------------------------------------------------------------------
/src/fx/fx/slide.js:
--------------------------------------------------------------------------------
1 | /**
2 | * the slide effects wrapper
3 | *
4 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5 | */
6 | Fx.Slide = new Class(Fx.Twin, {
7 | extend: {
8 | Options: Object.merge(Fx.Options, {
9 | direction: 'top'
10 | })
11 | },
12 |
13 | // protected
14 | prepare: function(how) {
15 | this.setHow(how);
16 |
17 | // calling 'prototype' to prevent circular calls from subclasses
18 | var element = Element.prototype.show.call(this.element),
19 | element_style = element._.style,
20 | old_styles = Object.only(
21 | element_style,
22 | 'overflow', 'width', 'height',
23 | 'marginTop', 'marginLeft'
24 | );
25 |
26 | function restore_styles() {
27 | for (var key in old_styles) {
28 | element_style[key] = old_styles[key];
29 | }
30 | }
31 |
32 | this.onFinish(restore_styles).onCancel(restore_styles);
33 |
34 | element_style.overflow = 'hidden';
35 |
36 | return this.$super(fx_slide_prepare_styles(
37 | element_style,
38 | element.size(),
39 | this.options.direction,
40 | this.how
41 | ));
42 | }
43 | });
44 |
45 | function fx_slide_prepare_styles(element_style, size, direction, how) {
46 | var style = {},
47 | margin_left = element_style.marginLeft.toFloat() || 0,
48 | margin_top = element_style.marginTop.toFloat() || 0,
49 | to_right = direction === 'right',
50 | to_bottom = direction === 'bottom',
51 | vertical = direction === 'top' || to_bottom;
52 |
53 | if (how === 'out') {
54 | style[vertical ? 'height' : 'width'] = '0px';
55 |
56 | if (vertical) {
57 | element_style.height = size.y + 'px';
58 | } else {
59 | element_style.width = size.y + 'px';
60 | }
61 |
62 | if (to_right) {
63 | style.marginLeft = margin_left + size.x+'px';
64 | } else if (to_bottom) {
65 | style.marginTop = margin_top + size.y +'px';
66 | }
67 | } else {
68 | if (vertical) {
69 | style.height = size.y + 'px';
70 | element_style.height = '0px';
71 | } else {
72 | style.width = size.x + 'px';
73 | element_style.width = '0px';
74 | }
75 |
76 | if (to_right) {
77 | style.marginLeft = margin_left + 'px';
78 | element_style.marginLeft = margin_left + size.x + 'px';
79 | } else if (to_bottom) {
80 | style.marginTop = margin_top + 'px';
81 | element_style.marginTop = margin_top + size.y + 'px';
82 | }
83 | }
84 |
85 | return style;
86 | }
87 |
--------------------------------------------------------------------------------
/src/fx/fx/twin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this is a superclass for the bidirectional effects
3 | *
4 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
5 | */
6 | Fx.Twin = new Class(Fx.Morph, {
7 |
8 | /**
9 | * hides the element if it meant to be switched off
10 | *
11 | * @return Fx self
12 | */
13 | finish: function() {
14 | if (this.how === 'out') {
15 | // calling 'prototype' to prevent circular calls from subclasses
16 | Element.prototype.hide.call(this.element);
17 | }
18 |
19 | return this.$super();
20 | },
21 |
22 | // protected
23 |
24 | /**
25 | * assigns the direction of the effect in or out
26 | *
27 | * @param String 'in', 'out' or 'toggle', 'toggle' by default
28 | */
29 | setHow: function(how) {
30 | this.how = how || 'toggle';
31 |
32 | if (this.how === 'toggle') {
33 | this.how = this.element.visible() ? 'out' : 'in';
34 | }
35 | }
36 |
37 | });
38 |
--------------------------------------------------------------------------------
/src/fx/string.js:
--------------------------------------------------------------------------------
1 | /**
2 | * There are the String unit extensions for the effects library
3 | *
4 | * Copyright (C) 2008-2009 Nikolay V. Nemshilov
5 | */
6 | String.COLORS = {
7 | maroon: '#800000',
8 | red: '#ff0000',
9 | orange: '#ffA500',
10 | yellow: '#ffff00',
11 | olive: '#808000',
12 | purple: '#800080',
13 | fuchsia: '#ff00ff',
14 | white: '#ffffff',
15 | lime: '#00ff00',
16 | green: '#008000',
17 | navy: '#000080',
18 | blue: '#0000ff',
19 | aqua: '#00ffff',
20 | teal: '#008080',
21 | black: '#000000',
22 | silver: '#c0c0c0',
23 | gray: '#808080',
24 | brown: '#a52a2a'
25 | };
26 |
27 | String.include({
28 | /**
29 | * converts a #XXX or rgb(X, X, X) sring into standard #XXXXXX color string
30 | *
31 | * @return String hex color
32 | */
33 | toHex: function() {
34 | var match = /^#(\w)(\w)(\w)$/.exec(this);
35 |
36 | if (match) {
37 | match = "#"+ match[1]+match[1]+match[2]+match[2]+match[3]+match[3];
38 | } else if ((match = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.exec(this))) {
39 | match = "#"+ match.slice(1).map(function(bit) {
40 | bit = (bit-0).toString(16);
41 | return bit.length == 1 ? '0'+bit : bit;
42 | }).join('');
43 | } else {
44 | match = String.COLORS[this] || this;
45 | }
46 |
47 | return match;
48 | },
49 |
50 | /**
51 | * converts a hex string into an rgb array
52 | *
53 | * @param boolean flag if need an array
54 | * @return String rgb(R,G,B) or Array [R,G,B]
55 | */
56 | toRgb: function(array) {
57 | var match = /#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i.exec(this.toHex()||'');
58 |
59 | if (match) {
60 | match = match.slice(1).map('toInt', 16);
61 | match = array ? match : 'rgb('+match+')';
62 | }
63 |
64 | return match;
65 | }
66 | });
67 |
--------------------------------------------------------------------------------
/src/lang/function.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The Function class extentions
3 | *
4 | * Credits:
5 | * Some of the functionality inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | *
8 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
9 | */
10 | Function.include({
11 | /**
12 | * binds the function to be executed in the given scope
13 | *
14 | * @param Object scope
15 | * @param mixed optional curry (left) argument
16 | * ....
17 | * @return Function binded function
18 | */
19 | bind: function() {
20 | var args = $A(arguments), scope = args.shift(), func = this;
21 | return function() {
22 | return func.apply(scope,
23 | (args.length !== 0 || arguments.length !== 0) ?
24 | args.concat($A(arguments)) : args
25 | );
26 | };
27 | },
28 |
29 | /**
30 | * binds the function as an event listener to the given scope object
31 | *
32 | * @param Object scope
33 | * @param mixed optional curry (left) argument
34 | * .......
35 | * @return Function binded function
36 | */
37 | bindAsEventListener: function() {
38 | var args = $A(arguments), scope = args.shift(), func = this;
39 | return function(event) {
40 | return func.apply(scope, [event].concat(args).concat($A(arguments)));
41 | };
42 | },
43 |
44 | /**
45 | * allows you to put some curry in your cookery
46 | *
47 | * @param mixed value to curry
48 | * ....
49 | * @return Function curried function
50 | */
51 | curry: function() {
52 | return this.bind.apply(this, [this].concat($A(arguments)));
53 | },
54 |
55 | /**
56 | * The right side curry feature
57 | *
58 | * @param mixed value to curry
59 | * ....
60 | * @return Function curried function
61 | */
62 | rcurry: function() {
63 | var curry = $A(arguments), func = this;
64 | return function() {
65 | return func.apply(func, $A(arguments).concat(curry));
66 | };
67 | },
68 |
69 | /**
70 | * delays the function execution
71 | *
72 | * @param Integer delay ms
73 | * @param mixed value to curry
74 | * .....
75 | * @return Integer timeout marker
76 | */
77 | delay: function() {
78 | var args = $A(arguments), timeout = args.shift(),
79 | timer = new Number(setTimeout(this.bind.apply(this, [this].concat(args)), timeout));
80 |
81 | timer.cancel = function() { clearTimeout(this); };
82 |
83 | return timer;
84 | },
85 |
86 | /**
87 | * creates a periodical execution of the function with the given timeout
88 | *
89 | * @param Integer delay ms
90 | * @param mixed value to curry
91 | * ...
92 | * @return Ineger interval marker
93 | */
94 | periodical: function() {
95 | var args = $A(arguments), timeout = args.shift(),
96 | timer = new Number(setInterval(this.bind.apply(this, [this].concat(args)), timeout));
97 |
98 | timer.stop = function() { clearInterval(this); };
99 |
100 | return timer;
101 | },
102 |
103 | /**
104 | * Chains the given function after the current one
105 | *
106 | * @param Function the next function
107 | * @param mixed optional value to curry
108 | * ......
109 | * @return Function chained function
110 | */
111 | chain: function() {
112 | var args = $A(arguments), func = args.shift(), current = this;
113 | return function() {
114 | var result = current.apply(current, arguments);
115 | func.apply(func, args);
116 | return result;
117 | };
118 | }
119 | });
120 |
--------------------------------------------------------------------------------
/src/lang/json.js:
--------------------------------------------------------------------------------
1 | if (!window.JSON) {
2 | window.JSON = (function() {
3 | var
4 | // see the original JSON decoder implementation for descriptions http://www.json.org/json2.js
5 | cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
6 | specials = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
7 | quotables = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
8 |
9 |
10 | // quotes the string
11 | function quote(string) {
12 | return string.replace(quotables, function(chr) {
13 | return specials[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
14 | });
15 | }
16 |
17 | // adds the leading zero symbol
18 | function zerofy(num) {
19 | return (num < 10 ? '0' : '')+num;
20 | }
21 |
22 | return {
23 | stringify: function(value) {
24 | switch(typeof(value)) {
25 | case 'boolean': return String(value);
26 | case 'number': return String(value+0);
27 | case 'string': return '"'+ quote(value) + '"';
28 | case 'object':
29 | if (value === null) {
30 | return 'null';
31 | } else if (isArray(value)) {
32 | return '['+$A(value).map(JSON.stringify).join(',')+']';
33 |
34 | } else if (to_s.call(value) === '[object Date]') {
35 | return '"' + value.getUTCFullYear() + '-' +
36 | zerofy(value.getUTCMonth() + 1) + '-' +
37 | zerofy(value.getUTCDate()) + 'T' +
38 | zerofy(value.getUTCHours()) + ':' +
39 | zerofy(value.getUTCMinutes()) + ':' +
40 | zerofy(value.getUTCSeconds()) + '.' +
41 | zerofy(value.getMilliseconds()) + 'Z' +
42 | '"';
43 |
44 | } else {
45 | var result = [], key;
46 | for (key in value) {
47 | result.push('"'+key+'":'+JSON.stringify(value[key]));
48 | }
49 | return '{'+result.join(',')+'}';
50 | }
51 | }
52 | },
53 |
54 | parse: function(string) {
55 | if (isString(string) && string) {
56 | // getting back the UTF-8 symbols
57 | string = string.replace(cx, function (a) {
58 | return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
59 | });
60 |
61 | // checking the JSON string consistency
62 | if (/^[\],:{}\s]*$/.test(string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
63 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
64 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
65 | return new Function('return '+string)();
66 | }
67 | }
68 |
69 | throw "JSON parse error: "+string;
70 | }
71 | };
72 | })();
73 | }
--------------------------------------------------------------------------------
/src/lang/math.js:
--------------------------------------------------------------------------------
1 | /**
2 | * here are the starndard Math object extends
3 | *
4 | * Credits:
5 | * The idea of random mehtod is taken from
6 | * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
7 | *
8 | * Copyright (C) 2008-2010 Nikolay Nemshilov
9 | */
10 | var Math_old_random = Math.random;
11 |
12 | /**
13 | * the standard random method replacement, to make it more useful
14 | *
15 | * USE:
16 | * Math.random(); // original functionality, returns a float between 0 and 1
17 | * Math.random(10); // returns an integer between 0 and 10
18 | * Math.random(1,4); // returns an integer between 1 and 4
19 | *
20 | * @param min Integer minimum value if there's two arguments and maximum value if there's only one
21 | * @param max Integer maximum value
22 | * @return Float random between 0 and 1 if there's no arguments or an integer in the given range
23 | */
24 | Math.random = function(min, max) {
25 |
26 | if (arguments.length === 0) {
27 | return Math_old_random();
28 | } else if (arguments.length === 1) {
29 | max = min;
30 | min = 0;
31 | }
32 |
33 | return ~~(Math_old_random() * (max-min+1) + ~~min);
34 | };
35 |
--------------------------------------------------------------------------------
/src/lang/number.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The Number class extentions
3 | *
4 | * Credits:
5 | * Some methods inspired by
6 | * - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
7 | *
8 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
9 | */
10 | Number.include({
11 | /**
12 | * executes the given callback the given number of times
13 | *
14 | * @param Function callback
15 | * @param Object optional callback execution scope
16 | * @return void
17 | */
18 | times: function(callback, scope) {
19 | for (var i=0; i < this; i++) {
20 | callback.call(scope, i);
21 | }
22 | return this;
23 | },
24 |
25 | upto: function(number, callback, scope) {
26 | for (var i=this+0; i <= number; i++) {
27 | callback.call(scope, i);
28 | }
29 | return this;
30 | },
31 |
32 | downto: function(number, callback, scope) {
33 | for (var i=this+0; i >= number; i--) {
34 | callback.call(scope, i);
35 | }
36 | return this;
37 | },
38 |
39 | /**
40 | * Maps a list of numbers from current to given
41 | * or map a result of calls of the callback on those numbers
42 | *
43 | * @param {Number} end number
44 | * @param {Function} optional callback
45 | * @param {Object} optional callback scope
46 | * @return {Array} the result list
47 | */
48 | to: function(number, callback, scope) {
49 | var start = this + 0, end = number, result = [], i=start;
50 |
51 | callback = callback || function(i) { return i; };
52 |
53 | if (end > start) {
54 | for (; i <= end; i++) {
55 | result.push(callback.call(scope, i));
56 | }
57 | } else {
58 | for (; i >= end; i--) {
59 | result.push(callback.call(scope, i));
60 | }
61 | }
62 |
63 | return result;
64 | },
65 |
66 | abs: function() {
67 | return Math.abs(this);
68 | },
69 |
70 | round: function(size) {
71 | return size ? parseFloat(this.toFixed(size)) : Math.round(this);
72 | },
73 |
74 | ceil: function() {
75 | return Math.ceil(this);
76 | },
77 |
78 | floor: function() {
79 | return Math.floor(this);
80 | },
81 |
82 | min: function(value) {
83 | return this < value ? value : this + 0;
84 | },
85 |
86 | max: function(value) {
87 | return this > value ? value : this + 0;
88 | }
89 | });
90 |
--------------------------------------------------------------------------------
/src/lang/object.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The Object class extentions
3 | *
4 | * Credits:
5 | * Some functionality is inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | *
8 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
9 | */
10 | $ext(Object, {
11 | /**
12 | * extracts the list of the attribute names of the given object
13 | *
14 | * @param Object object
15 | * @return Array keys list
16 | */
17 | keys: function(object) {
18 | var keys = [], key;
19 | for (key in object) {
20 | keys.push(key);
21 | }
22 | return keys;
23 | },
24 |
25 | /**
26 | * extracts the list of the attribute values of the given object
27 | *
28 | * @param Object object
29 | * @return Array values list
30 | */
31 | values: function(object) {
32 | var values = [], key;
33 | for (key in object) {
34 | values.push(object[key]);
35 | }
36 | return values;
37 | },
38 |
39 | /**
40 | * Calls the function with every key/value pair on the hash
41 | *
42 | * @param in Object the data hash
43 | * @param Function the callback
44 | * @param scope Object an optional scope
45 | * @return Object the original hash
46 | */
47 | each: function(object, callback, scope) {
48 | for (var key in object) {
49 | callback.call(scope, key, object[key]);
50 | }
51 |
52 | return object;
53 | },
54 |
55 | /**
56 | * checks if the object-hash has no keys
57 | *
58 | * @param Object object
59 | * @return check result
60 | */
61 | empty: function(object) {
62 | for (var key in object) { return false; }
63 | return true;
64 | },
65 |
66 | /**
67 | * A simple cloning method
68 | * NOTE: does not clone the things recoursively!
69 | *
70 | * @param Object object
71 | * @return Object clone
72 | */
73 | clone: function(object) {
74 | return Object.merge(object);
75 | },
76 |
77 | /**
78 | * returns a copy of the object which contains
79 | * all the same keys/values except the key-names
80 | * passed the the method arguments
81 | *
82 | * @param Object object
83 | * @param String key-name to exclude
84 | * .....
85 | * @return Object filtered copy
86 | */
87 | without: function() {
88 | var filter = $A(arguments), object = filter.shift(), copy = {}, key;
89 |
90 | for (key in object) {
91 | if (!filter.include(key)) {
92 | copy[key] = object[key];
93 | }
94 | }
95 |
96 | return copy;
97 | },
98 |
99 | /**
100 | * returns a copy of the object which contains all the
101 | * key/value pairs from the specified key-names list
102 | *
103 | * NOTE: if some key does not exists in the original object, it will be just skipped
104 | *
105 | * @param Object object
106 | * @param String key name to exclude
107 | * .....
108 | * @return Object filtered copy
109 | */
110 | only: function() {
111 | var filter = $A(arguments), object = filter.shift(), copy = {},
112 | i=0, length = filter.length;
113 |
114 | for (; i < length; i++) {
115 | if (filter[i] in object) {
116 | copy[filter[i]] = object[filter[i]];
117 | }
118 | }
119 |
120 | return copy;
121 | },
122 |
123 | /**
124 | * merges the given objects and returns the result
125 | *
126 | * NOTE this method _DO_NOT_ change the objects, it creates a new object
127 | * which conatins all the given ones.
128 | * if there is some keys introspections, the last object wins.
129 | * all non-object arguments will be omitted
130 | *
131 | * @param first Object object
132 | * @param second Object mixing
133 | * ......
134 | * @return Object merged object
135 | */
136 | merge: function() {
137 | var object = {}, i=0, args=arguments, l=args.length, key;
138 | for (; i < l; i++) {
139 | if (isHash(args[i])) {
140 | for (key in args[i]) {
141 | object[key] = isHash(args[i][key]) && !(args[i][key] instanceof Class) ?
142 | Object.merge(key in object ? object[key] : {}, args[i][key]) : args[i][key];
143 | }
144 | }
145 | }
146 | return object;
147 | },
148 |
149 | /**
150 | * converts a hash-object into an equivalent url query string
151 | *
152 | * @param Object object
153 | * @return String query
154 | */
155 | toQueryString: function(object) {
156 | var entries = to_query_string_map(object), i=0, result = [];
157 |
158 | for (; i < entries.length; i++) {
159 | result.push(encodeURIComponent(entries[i][0]) + "=" + encodeURIComponent(''+entries[i][1]));
160 | }
161 |
162 | return result.join('&');
163 | }
164 | }, true);
165 |
166 | // private
167 |
168 | /**
169 | * pre-converts nested objects into a flat key-value structure
170 | *
171 | * @param {Object} data-hash
172 | * @param {String} key-prefix
173 | * @return {Array} key-value pairs
174 | */
175 | function to_query_string_map(hash, prefix) {
176 | var result = [], key, value, i;
177 |
178 | for (key in hash) {
179 | value = hash[key];
180 | if (prefix) {
181 | key = prefix + "["+ key + "]";
182 | }
183 |
184 | if (typeof(value) === 'object') {
185 | if (isArray(value)) {
186 | if (!key.endsWith('[]')) {
187 | key += "[]";
188 | }
189 | for (i=0; i < value.length; i++) {
190 | result.push([key, value[i]]);
191 | }
192 | } else if (value) { // assuming it's an object
193 | value = to_query_string_map(value, key);
194 | for (i=0; i < value.length; i++) {
195 | result.push(value[i]);
196 | }
197 | }
198 | } else {
199 | result.push([key, value]);
200 | }
201 | }
202 |
203 | return result;
204 | }
--------------------------------------------------------------------------------
/src/lang/regexp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The Regexp class extentions
3 | *
4 | * Credits:
5 | * Inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | *
8 | * Copyright (C) 2008-2010 Nikolay V. Nemshilov
9 | */
10 |
11 |
12 | /**
13 | * Escapes the string for safely use as a regular expression
14 | *
15 | * @param String raw string
16 | * @return String escaped string
17 | */
18 | RegExp.escape = function(string) {
19 | return (''+string).replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1');
20 | };
21 |
--------------------------------------------------------------------------------
/src/lang/string.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The String class extentions
3 | *
4 | * Credits:
5 | * Some of the functionality inspired by
6 | * - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
7 | * The trim function taken from work of Steven Levithan
8 | * - http://blog.stevenlevithan.com/archives/faster-trim-javascript
9 | *
10 | * Copyright (C) 2008-2011 Nikolay V. Nemshilov
11 | */
12 | String.include({
13 | /**
14 | * checks if the string is an empty string
15 | *
16 | * @return boolean check result
17 | */
18 | empty: function() {
19 | return this == '';
20 | },
21 |
22 | /**
23 | * checks if the string contains only white-spaces
24 | *
25 | * @return boolean check result
26 | */
27 | blank: function() {
28 | return this == false;
29 | },
30 |
31 | /**
32 | * removes trailing whitespaces
33 | *
34 | * @return String trimmed version
35 | */
36 | trim: String.prototype.trim || function() {
37 | var str = this.replace(/^\s\s*/, ''), i = str.length;
38 | while ((/\s/).test(str.charAt(--i))) {}
39 | return str.slice(0, i + 1);
40 | },
41 |
42 | /**
43 | * returns a copy of the string with all the tags removed
44 | * @return String without tags
45 | */
46 | stripTags: function() {
47 | return this.replace(/<\/?[^>]+>/ig, '');
48 | },
49 |
50 | /**
51 | * removes all the scripts declarations out of the string
52 | * @param mixed option. If it equals true the scrips will be executed,
53 | * if a function the scripts will be passed in it
54 | * @return String without scripts
55 | */
56 | stripScripts: function(option) {
57 | var scripts = '', text = this.replace(
58 | /
8 |
26 |
59 |
60 |
61 | Test Morph
62 |
63 |
66 |
72 | Run
73 | Reset
74 |
75 |
76 | Test Highlight
77 |
78 |
81 |
82 | Run
83 | Reset
84 |
85 |
86 | Test Fade
87 |
88 |
91 |
92 | Run
93 | Reset
94 |
95 |
96 | Test Slide
97 |
98 |
101 |
102 | Run
103 | Reset
104 |
105 |
106 | Test Scroll
107 |
108 |
111 |
115 | Run
116 | Reset
117 |
122 |
123 |
124 | Test Background Position
125 |
126 |
129 |
136 | Run
137 | Reset
138 |
139 |
140 | Test Stopping Fx
141 |
142 |
145 |
153 | Run
154 | Reset
155 |
156 |
157 |
158 |
159 |