1 // Copyright (c) 2006 spinelz.org (http://script.spinelz.org/)
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:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
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.
25 Object.extend(Element, {
27 getTagNodes: function(element, tree) {
28 return this.getElementsByNodeType(element, 1, tree);
31 getTextNodes: function(element, tree) {
32 return this.getElementsByNodeType(element, 3, tree);
35 getElementsByNodeType: function(element, nodeType, tree) {
37 element = ($(element) || document.body);
38 var nodes = element.childNodes;
41 for (var i = 0; i < nodes.length; i++) {
42 if (nodes[i].nodeType == nodeType)
43 result.push(nodes[i]);
44 if (tree && (nodes[i].nodeType == 1))
45 result = result.concat(this.getElementsByNodeType(nodes[i], nodeType, tree));
51 getParentByClassName: function(className, element) {
52 var parent = element.parentNode;
53 if (!parent || (parent.tagName == 'BODY'))
55 else if (!parent.className)
56 return Element.getParentByClassName(className, parent);
57 else if (Element.hasClassName(parent, className))
60 return Element.getParentByClassName(className, parent);
63 getParentByTagName: function(tagNames, element) {
65 var parent = element.parentNode;
66 if (parent.tagName == 'BODY')
69 var index = tagNames.join('/').toUpperCase().indexOf(parent.tagName.toUpperCase(), 0);
73 return Element.getParentByTagName(tagNames, parent);
76 getFirstElementByClassNames: function(element, classNames, tree) {
79 !((typeof(classNames) == 'object') && (classNames.constructor == Array))) {
83 element = (element || document.body);
84 var nodes = element.childNodes;
86 for (var i = 0; i < nodes.length; i++) {
87 for (var j = 0; j < classNames.length; j++) {
88 if (nodes[i].nodeType != 1) {
91 } else if (Element.hasClassName(nodes[i], classNames[j])) {
95 var result = this.getFirstElementByClassNames(nodes[i], classNames, tree);
96 if (result) return result;
104 getElementsByClassNames: function(element, classNames) {
107 !((typeof(classNames) == 'object') && (classNames.constructor == Array))) {
112 classNames.each(function(c) {
113 nodes = nodes.concat(document.getElementsByClassName(c, element));
119 getWindowHeight: function() {
121 if (window.innerHeight) {
122 return window.innerHeight; // Mozilla, Opera, NN4
123 } else if (document.documentElement && document.documentElement.offsetHeight){ // ?? IE
124 return document.documentElement.offsetHeight;
125 } else if (document.body && document.body.offsetHeight) {
126 return document.body.offsetHeight - 20;
131 getWindowWidth:function() {
133 if(window.innerWidth) {
134 return window.innerWidth; // Mozilla, Opera, NN4
135 } else if (document.documentElement && document.documentElement.offsetWidth){ // ?? IE
136 return document.documentElement.offsetWidth - 20;
137 } else if (document.body && document.body.offsetWidth){
138 return document.body.offsetWidth - 20;
143 getMaxZindex: function(element) {
144 element = $(element);
146 element = document.body;
148 if (element.nodeType != 1) return 0;
151 if (element.style) maxZindex = parseInt(Element.getStyle(element, "z-index"));
152 if (isNaN(maxZindex)) maxZindex = 0;
155 var elements = element.childNodes;
156 for (var i = 0; i < elements.length; i++) {
157 if (elements[i] && elements[i].tagName) {
158 tmpZindex = Element.getMaxZindex(elements[i]);
159 if (maxZindex < tmpZindex) maxZindex = tmpZindex;
166 select: function(element, value) {
167 $A($(element).options).each(function(opt) {
168 if (opt.value == value) {
171 opt.selected = false;
181 Object.extend(Array.prototype, {
182 insert : function(index, element) {
183 this.splice(index, 0 , element);
186 remove : function(index) {
187 this.splice(index, 1);
195 Object.extend(String.prototype, {
197 getPrefix: function(delimiter) {
199 if (!delimiter) delimiter = '_';
200 return this.split(delimiter)[0];
203 getSuffix: function(delimiter) {
205 if (!delimiter) delimiter = '_';
206 return this.split(delimiter).pop();
209 appendPrefix: function(prefix, delimiter) {
211 if (!delimiter) delimiter = '_';
212 return this + delimiter + prefix;
215 appendSuffix: function(suffix, delimiter) {
217 if (!delimiter) delimiter = '_';
218 return this + delimiter + suffix;
222 println: function() {
231 var CssUtil = Class.create();
233 CssUtil.appendPrefix = function(prefix, suffixes) {
235 $H(suffixes).each(function(pair) {
236 newHash[pair[0]] = prefix + suffixes[pair[0]];
241 CssUtil.getCssRules = function(sheet) {
242 return sheet.rules || sheet.cssRules;
245 CssUtil.getCssRuleBySelectorText = function(selector) {
247 $A(document.styleSheets).each(function(s) {
248 var rules = CssUtil.getCssRules(s);
249 rule = $A(rules).detect(function(r) {
250 if (!r.selectorText) return false;
251 return r.selectorText.toLowerCase() == selector.toLowerCase();
253 if (rule) throw $break;
259 CssUtil.require = function(file, attributes, parent) {
260 var links = document.getElementsByTagName('link');
261 var regex = /^.*\.css/;
262 var match = file.match(regex)
264 regex.compile(match);
266 $A(links).each(function(ln) {
267 if (ln.href.match(regex)) {
271 // attributes = Object.extend({
274 // rel: 'stylesheet',
275 // type: 'text/css'}, attributes);
276 // var node = Builder.node('link', attributes);
277 // if (!parent) parent = document.body;
278 // parent.appendChild(node);
283 CssUtil.prototype = {
285 initialize: function(styles) {
286 if (!((typeof(styles) == 'object') && (styles.constructor == Array))) {
287 throw 'CssUtil#initialize: argument must be a Array object!';
290 this.styles = styles;
293 getClasses: function(key) {
294 return this.styles.collect(function(s) {
299 joinClassNames: function(key) {
300 return this.getClasses(key).join(' ');
303 addClassNames: function(element, key) {
304 this.styles.each(function(s) {
305 Element.addClassName(element, s[key]);
309 removeClassNames: function(element, key) {
310 this.styles.each(function(s) {
311 Element.removeClassName(element, s[key]);
315 refreshClassNames: function(element, key) {
316 element.className = '';
317 this.addClassNames(element, key);
320 hasClassName: function(element, key) {
321 return this.styles.any(function(s) {
322 return Element.hasClassName(element, s[key]);
331 var Hover = Class.create();
334 initialize: function(element) {
335 this.options = Object.extend({
340 }, arguments[1] || {});
342 var element = $(element);
343 if (this.options.list) {
344 var nodes = element.childNodes;
345 for (var i = 0; i < nodes.length; i++) {
346 if (nodes[i].nodeType == 1) {
347 this.build(nodes[i]);
355 build: function(element) {
356 this.normal = this.getNormalClass(element);
357 this.hover = this.getHoverClass(this.normal);
359 if (this.options.cssUtil) {
360 this.normal = this.options.cssUtil.joinClassNames(normal);
361 this.hover = this.options.cssUtil.joinClassNames(hover);
363 this.setHoverEvent(element);
366 setHoverEvent: function(element) {
367 Event.observe(element, "mouseout", this.toggle.bindAsEventListener(this, element, this.normal));
368 Event.observe(element, "mouseover", this.toggle.bindAsEventListener(this, element, this.hover));
371 toggle: function(event, element, className) {
373 element.className = className;
376 getNormalClass: function(element) {
377 var className = (this.options.defaultClass || element.className);
378 return (className || '');
381 getHoverClass: function(defaultClass) {
382 var className = this.options.hoverClass;
384 className = defaultClass.split(' ').collect(function(c) {
396 Object.extend(Date.prototype, {
397 msPerDay: function() {
398 return 24 * 60 * 60 * 1000;
401 advance: function(options) {
402 return new Date(this.getTime() + this.msPerDay() * options.days);
406 var date = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
407 return Math.round(date.getTime() / this.msPerDay());
412 year: this.getFullYear(),
413 month: this.getMonth(),
415 hour: this.getHours(),
416 min: this.getMinutes(),
417 sec: this.getSeconds()
421 sameYear: function(date) {
422 return this.getFullYear() == date.getFullYear();
425 sameMonth: function(date) {
426 return this.sameYear(date) && this.getMonth() == date.getMonth();
429 sameDate: function(date) {
430 return this.sameYear(date) && this.sameMonth(date) && this.getDate() == date.getDate();
433 betweenDate: function(start, finish) {
434 var myDays = this.days();
435 return (start.days() <= myDays && myDays <= finish.days());
438 betweenTime: function(start, finish) {
439 var myTime = this.getTime();
440 return (start.getTime() <= myTime && myTime <= finish.getTime());
450 dayOfWeek: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
452 months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
454 daysOfMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
456 numberOfDays: function(start, finish) {
457 return finish.days() - start.days();
460 isLeapYear: function(year) {
461 if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
466 nextDate: function(date) {
467 return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
470 previousDate: function(date) {
471 return new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1);
474 afterDays: function(date, after) {
475 return new Date(date.getFullYear(), date.getMonth(), date.getDate() + after);
478 getLastDate: function(year, month) {
479 var last = this.daysOfMonth[month];
480 if ((month == 1) && this.isLeapYear(year)) {
481 return new Date(year, month, last + 1);
483 return new Date(year, month, last);
486 getFirstDate: function(year, month) {
487 if (year.constructor == Date) {
488 return new Date(year.getFullYear(), year.getMonth(), 1);
490 return new Date(year, month, 1);
493 getWeekTurn: function(date, firstDWeek) {
494 var limit = 6 - firstDWeek + 1;
496 while (limit < date) {
503 toDateString: function(date) {
504 return date.toDateString();
507 toLocaleDateString: function(date) {
508 return date.toLocaleDateString();
511 simpleFormat: function(formatStr) {
512 return function(date) {
513 var formated = formatStr.replace(/M+/g, DateUtil.zerofill((date.getMonth() + 1).toString(), 2));
514 formated = formated.replace(/d+/g, DateUtil.zerofill(date.getDate().toString(), 2));
515 formated = formated.replace(/y{4}/g, date.getFullYear());
516 formated = formated.replace(/y{1,3}/g, new String(date.getFullYear()).substr(2));
517 formated = formated.replace(/E+/g, DateUtil.dayOfWeek[date.getDay()]);
523 zerofill: function(date,digit){
525 if(date.length < digit){
526 var tmp = digit - date.length;
527 for(i=0; i < tmp; i++){
528 result = "0" + result;
534 toDate: function(hash) {
535 return new Date(hash.year, hash.month, hash.day, hash.hour, hash.min, hash.sec || 0);
543 var ZindexManager = {
546 getIndex: function(zIndex) {
549 zIndex = Element.getMaxZindex() + 1;
550 } else if (ZindexManager.zIndex > zIndex) {
551 zIndex = ZindexManager.zIndex;
554 zIndex = ZindexManager.zIndex;
556 ZindexManager.zIndex = zIndex + 1;
567 maskClass: 'modal_mask',
568 maskClassIE: 'modal_mask_ie',
572 resizeListener: null,
576 mask: function(excepted) {
577 var options = Object.extend({
578 cssPrefix: 'custom_',
580 }, arguments[1] || {});
583 Modal._snap(excepted);
584 Modal._rebuildMask();
587 Modal.excepteds = [];
588 Modal._buildMask(options.cssPrefix);
589 Modal.cover = new IECover(Modal.element, {transparent: true});
591 Modal._setZindex(excepted, options.zIndex);
592 Modal._setFullSize();
593 if (!Modal.hasExcepted(excepted)) Modal.excepteds.push(excepted);
598 if (Modal.snaps.length == 0) {
599 Element.hide(Modal.element);
600 Modal._removeEvent();
601 Modal.excepteds = [];
602 Element.remove(Modal.element);
603 Modal.element = null;
605 Element.setStyle(Modal.element, {zIndex: Modal.snaps.pop()});
606 Modal.excepteds.pop();
611 _addEvent: function() {
612 if (!Modal.listener) {
613 Modal.listener = Modal._handleEvent.bindAsEventListener();
614 Modal.resizeListener = Modal._onResize.bindAsEventListener();
616 Event.observe(document, "keypress", Modal.listener);
617 Event.observe(document, "keydown", Modal.listener);
618 Event.observe(document, "keyup", Modal.listener);
619 Event.observe(document, "focus", Modal.listener);
620 Event.observe(window, "resize", Modal.resizeListener);
623 _removeEvent: function() {
624 Event.stopObserving(document, "keypress", Modal.listener);
625 Event.stopObserving(document, "keydown", Modal.listener);
626 Event.stopObserving(document, "keyup", Modal.listener);
627 Event.stopObserving(document, "focus", Modal.listener);
628 Event.stopObserving(window, "resize", Modal.resizeListener);
631 _isMasked: function() {
632 return Modal.element && Element.visible(Modal.element);
635 _snap: function(excepted) {
636 var index = Element.getStyle(Modal.element, 'zIndex');
637 if (index && Modal._isMasked() && !Modal.hasExcepted(excepted)) Modal.snaps.push(index);
640 _setZindex: function(excepted, zIndex) {
641 zIndex = ZindexManager.getIndex(zIndex);
642 Element.setStyle(Modal.element, {zIndex: zIndex});
643 excepted = Element.makePositioned($(excepted));
644 Element.setStyle(excepted, {zIndex: ++zIndex});
647 _setFullSize: function() {
648 Modal.element.setStyle({
649 width: Element.getWindowWidth() + 'px',
650 height: Element.getWindowHeight() + 'px'
652 if (Modal.cover) Modal.cover.resetSize();
655 _buildMask: function(cssPrefix) {
656 var mask = Builder.node('div', {id: Modal.maskId});
657 Modal._setClassNames(mask, cssPrefix);
658 document.body.appendChild(mask);
659 Modal.element = mask;
663 _setClassNames: function(element, cssPrefix) {
664 var className = (UserAgent.isIE()) ? Modal.maskClassIE : Modal.maskClass;
665 Element.addClassName(element, className);
666 Element.addClassName(element, cssPrefix + className);
669 _rebuildMask: function() {
670 document.body.appendChild(Modal.element);
671 Element.show(Modal.element);
674 _isOutOfModal: function(src) {
675 var limit = Element.getStyle(Modal.element, 'zIndex');
677 while ((src = src.parentNode) && src != document.body) {
678 if (src.style && (zIndex = Element.getStyle(src, 'zIndex'))) {
679 if (zIndex > limit) {
689 _handleEvent: function (event) {
690 var src = Event.element(event);
691 if (!Modal._isOutOfModal(src)) {
696 _onResize: function(event) {
697 Modal._setFullSize();
700 hasExcepted: function(excepted) {
701 return Modal.excepteds && Modal.excepteds.include(excepted);
709 var IECover = Class.create();
710 IECover.src = '/blank.html';
711 IECover.prototype = {
714 initialize: function(parent) {
715 this.options = Object.extend({
718 }, arguments[1] || {});
722 this.id = parent.id.appendSuffix(this.idSuffix);
728 resetSize: function() {
730 var parent = this.element.parentNode;
731 var padding = this.options.padding;
732 this.element.width = parent.offsetWidth - padding + 'px';
733 this.element.height = Element.getHeight(parent) - padding + 'px';
737 _build: function(parent) {
738 var padding = this.options.padding / 2;
740 position : 'absolute',
741 top : padding + 'px',
742 left : padding + 'px'
744 if (this.options.transparent) styles.filter = 'alpha(opacity=0)';
745 this.element = Builder.node('iframe', {src: IECover.src, id: this.id, frameborder: 0});
746 Element.setStyle(this.element, styles);
747 var firstNode = Element.down(parent, 0);
748 if (firstNode) Element.makePositioned(firstNode);
749 parent.insertBefore(this.element, parent.firstChild);
757 getUserAgent: function() {
758 return navigator.userAgent;
761 if(document.all && this.getUserAgent().toLowerCase().indexOf('msie') != -1) {
766 if(document.all && this.getUserAgent().toLowerCase().indexOf('msie 7') != -1) {
775 var ShortcutManager = {
776 initialize: function() {
777 var defaultOptions = {
778 initialStarted: true,
781 this.options = Object.extend(defaultOptions, arguments[0] || {});
782 if(this.documentListener) {
783 Event.stopObserving(document, 'keydown', this.documentListener);
785 this.documentListener = this.eventKeydown.bindAsEventListener(this);
786 this.functions = new Object();
787 this.functions['a'] = new Object();
788 this.functions['ac'] = new Object();
789 this.functions['as'] = new Object();
790 this.functions['acs'] = new Object();
791 this.functions['c'] = new Object();
792 this.functions['cs'] = new Object();
793 this.functions['n'] = new Object();
794 this.functions['s'] = new Object();
884 if(this.options.initialStarted) {
889 Event.observe(document, 'keydown', this.documentListener);
891 add: function(shortcut, callback) {
892 this._add_or_remove_function(shortcut, callback);
894 destroy: function() {
895 Event.stopObserving(document, 'keydown', this.documentListener);
897 eventKeydown: function(event) {
898 if(this.executable) {
901 event = event || window.event;
915 code = this._mergeNumKey(event.keyCode);
916 if(this.functions[key][code]) {
917 this.functions[key][code]();
918 if(this.options.preventDefault) {
925 remove: function(shortcut) {
926 this._add_or_remove_function(shortcut);
929 this.executable = true;
932 this.executable = false;
934 _add_or_remove_function: function(shortcut, callback) {
935 var pressed_key_code;
936 var additional_keys = new Array();
938 $A(shortcut.toLowerCase().split("+")).each(
941 additional_keys.push('a');
942 } else if(key == 'ctrl') {
943 additional_keys.push('c');
944 } else if(key == 'shift') {
945 additional_keys.push('s');
947 pressed_key_code = self.keyCode[key];
951 var key = additional_keys.sortBy(function(value, index) {return value;}).join('');
956 this.functions[key][pressed_key_code] = callback;
958 this.functions[key][pressed_key_code] = null;
961 _mergeNumKey: function(code) {
962 return (this.numKeys[code]) ? this.numKeys[code] : code;
970 Function.prototype.callAfterLoading = function(object) {
971 object = object || this;
972 if (UserAgent.isIE() && document.readyState != 'complete') {
973 Event.observe(window, 'load', this.bind(object));