OSDN Git Service

7ceb089f466b9834af7f465ea31fd01663492cc6
[cloudmanganw/git_repo.git] / war / javascripts / spinelz / balloon.js
1 // Copyright (c) 2006 spinelz.org (http://script.spinelz.org/)
2 // 
3 // This code is substantially based on code from script.aculo.us which has the 
4 // following copyright and permission notice
5 //
6 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
7 // 
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
26
27 var Balloon = Class.create()
28 Balloon.classNames = {
29   tooltip:         'balloon_tooltip',
30   top:             'balloon_top',
31   topLeft:         'balloon_top_left',
32   topMiddle:       'balloon_top_middle',
33   topRight:        'balloon_top_right',
34   middle:          'balloon_middle',
35   middleLeft:      'balloon_middle_left',
36   middleRight:     'balloon_middle_right',
37   middleLeftRowT:  'balloon_middle_left_row',
38   middleLeftRowB:  'balloon_middle_left_row',
39   middleRightRowT: 'balloon_middle_right_row',
40   middleRightRowB: 'balloon_middle_right_row',
41   leftArrow:       'balloon_left_arrow',
42   rightArrow:      'balloon_right_arrow',
43   leftUpArrow:     'balloon_left_up_arrow',
44   leftDownArrow:   'balloon_left_down_arrow',
45   rightUpArrow:    'balloon_right_up_arrow',
46   rightDownArrow:  'balloon_right_down_arrow',
47   body:            'balloon_body',
48   bottom:          'balloon_bottom',
49   bottomLeft:      'balloon_bottom_left',
50   bottomMiddle:    'balloon_bottom_middle',
51   bottomRight:     'balloon_bottom_right'
52 }
53 Balloon.allBalloons = [];
54 Balloon.closeAll = function(){
55   Balloon.allBalloons.each(function(b){
56     b.close();
57   });
58 }
59 Balloon.eventSetting = false;
60 Balloon.prototype = {
61   initialize : function (target, message){
62     this.target = $(target);
63
64     this.options = Object.extend({
65       cssPrefix: 'custom_',
66       trigger:   this.target,
67       tipId:     this.target.id + '_balloon',
68       events:    ['click'],
69       width:     300,
70       height:    200
71     }, arguments[2] || {});
72     
73     var customCss = CssUtil.appendPrefix(this.options.cssPrefix, Balloon.classNames);
74     this.classNames = new CssUtil([Balloon.classNames, customCss]);
75
76     this.tipNode = this._buildTipNode(message);
77     Element.hide(this.tipNode);
78     this._setMessage(message);
79     document.body.appendChild(this.tipNode);
80     this._setEvent();
81     Balloon.allBalloons.push(this)
82     this._setSize();
83   },
84
85   _setEvent: function() {
86     var self = this;
87     this.options.events.each(function(e) {
88       Event.observe(self.options.trigger, e, self.open.bindAsEventListener(self));
89     });
90
91     Event.observe(this.tipNode, 'click', this.close.bind(this), true)    
92
93     if (!Balloon.eventSetting) {
94       Event.observe(document, 'click', Balloon.closeAll, true);
95       Balloon.eventSetting = true;
96     }
97   },
98
99   _buildTipNode : function() {
100     var tipNode = Builder.node('div', {id: this.options.tipId});
101     this.classNames.addClassNames(tipNode, 'tooltip');
102     tipNode.appendChild(this._buildTop());
103     tipNode.appendChild(this._buildMiddle());
104     tipNode.appendChild(this._buildBottom());
105     return tipNode;
106   },
107
108   _setMessage: function(message) {
109     var type = message.constructor;
110     if (type == String) {
111       this.body.innerHTML = message;
112     } else if (type == Object) {
113       this.body.appendChild(message);
114     }
115   },
116
117   _buildTop: function() {
118     return this._buildMulti('top', ['topLeft', 'topMiddle', 'topRight'], true);
119   },
120
121   _buildBottom: function() {
122     return this._buildMulti('bottom', ['bottomLeft', 'bottomMiddle', 'bottomRight'], true);
123   },
124
125   _buildMiddle: function() {
126     this.middle = Builder.node('div');
127     this.classNames.addClassNames(this.middle, 'middle');
128     this.middle.appendChild(
129       this._buildMulti('middleLeft', ['middleLeftRowT', 'leftArrow', 'middleLeftRowB'], true));
130     this.middle.appendChild(this._buildMulti('body', [], true));
131     this.middle.appendChild(
132       this._buildMulti('middleRight', ['middleRightRowT', 'rightArrow', 'middleRightRowB'], true));
133     return this.middle;
134   },
135
136   _buildMulti: function(main, subs, hold) {
137     var topNode = Builder.node('div');
138     this.classNames.addClassNames(topNode, main);
139     if (hold) this[main] = topNode;
140     var self = this;
141     var node = null;
142     subs.each(function(s) {
143       node = Builder.node('div');
144       self.classNames.addClassNames(node, s);
145       topNode.appendChild(node);
146       if (hold) self[s] = node;
147     });
148     return topNode;
149   },
150
151   _setPosition: function() {
152     var scrollPosition = Position.realOffset(this.tipNode);
153     var screenWidth = document.documentElement.clientWidth;
154     var screenHeight = document.documentElement.clientHeight;
155     
156     var positionList = Position.cumulativeOffset(this.target);
157     var dimension = Element.getDimensions(this.target);
158     var tipNodeLeft = Math.round(positionList[0] + dimension.width);
159     var tipDimension = Element.getDimensions(this.tipNode);
160     var tipNodeTop = Math.round(positionList[1] - tipDimension.height / 2);
161
162     var addLR = 'left';
163     var remLR = 'right';
164
165     if((tmpY = tipNodeTop - scrollPosition[1]) < 0) {
166       tipNodeTop -= tmpY;
167     }
168     if( (tipNodeLeft+tipDimension.width) > (screenWidth+scrollPosition[0]) ) {
169       tipNodeLeft = Math.round(positionList[0] - tipDimension.width);
170       addLR = 'right';
171       remLR = 'left';
172     }
173     
174     var y = positionList[1] - tipNodeTop;
175     this._setArrow(addLR, y);
176     this._unsetArrow(remLR);
177
178     Element.setStyle(this.tipNode, {
179       top: tipNodeTop + 'px',
180       left: tipNodeLeft + 'px',
181       zIndex: ZindexManager.getIndex()
182     });
183   },
184
185   _setArrow: function(lr, y) {
186     var headerH = (this.options.height - this.middleH) / 2;
187     var topH, bottomH, h, ud;
188     var minH = 10; // for ie
189     if (lr == 'left') {
190       h = this.middleH - this.leftArrowH;
191     } else {
192       h = this.middleH - this.rightArrowH;
193     }
194     if (headerH > y) {
195       topH = minH;
196       bottomH = h - topH;
197       ud = 'up';
198     } else if ((this.middleH + headerH) < y) {
199       bottomH = minH;
200       topH = h - bottomH;
201       ud = 'down';
202     } else {
203       topH = y - headerH;
204       topH = (topH < minH) ? minH : topH;
205       bottomH = h - topH;
206       ud = 'up';
207     }
208     if (lr == 'left') {
209       if (ud == 'up') {
210         this.classNames.refreshClassNames(this.leftArrow, 'leftUpArrow');
211         Element.setStyle(this.leftArrow, {height: this.leftArrowH + 'px'});
212         Element.setStyle(this.middleLeftRowT, {height: topH + 'px'});
213         Element.setStyle(this.middleLeftRowB, {height: bottomH + 'px'});
214       } else {
215         this.classNames.refreshClassNames(this.leftArrow, 'leftDownArrow');
216         Element.setStyle(this.leftArrow, {height: this.leftArrowH + 'px'});
217         Element.setStyle(this.middleLeftRowT, {height: topH + 'px'});
218         Element.setStyle(this.middleLeftRowB, {height: bottomH + 'px'});
219       }
220     } else {
221       if (ud == 'up') {
222         this.classNames.refreshClassNames(this.rightArrow, 'rightUpArrow');
223         Element.setStyle(this.rightArrow, {height: this.rightArrowH + 'px'});
224         Element.setStyle(this.middleRightRowT, {height: topH + 'px'});
225         Element.setStyle(this.middleRightRowB, {height: bottomH + 'px'});
226       } else {
227         this.classNames.refreshClassNames(this.rightArrow, 'rightDownArrow');
228         Element.setStyle(this.rightArrow, {height: this.rightArrowH + 'px'});
229         Element.setStyle(this.middleRightRowT, {height: topH + 'px'});
230         Element.setStyle(this.middleRightRowB, {height: bottomH + 'px'});
231       }
232     }
233   },
234
235   _unsetArrow: function(direction) {
236     if (direction == 'left') {
237       var h = (this.middleH - this.leftArrowH) / 2;
238       this.classNames.refreshClassNames(this.leftArrow, 'middleLeftRowB');
239       Element.setStyle(this.leftArrow, {height: this.leftArrowH + 'px'});
240       Element.setStyle(this.middleLeftRowT, {height: h + 'px'});
241       Element.setStyle(this.middleLeftRowB, {height: h + 'px'});
242     } else {
243       var h = (this.middleH - this.rightArrowH) / 2;
244       this.classNames.refreshClassNames(this.rightArrow, 'middleRightRowB');
245       Element.setStyle(this.rightArrow, {height: this.rightArrowH + 'px'});
246       Element.setStyle(this.middleRightRowT, {height: h + 'px'});
247       Element.setStyle(this.middleRightRowB, {height: h + 'px'});
248     }
249   },
250
251   _setSize: function() {
252     var width = this.options.width;
253     var height = this.options.height;
254     Element.setStyle(this.tipNode, {
255       width: width + 'px',
256       height: height + 'px'
257     });
258
259     var topH = parseInt(Element.getStyle(this.top, 'height'));
260     var bottomH = parseInt(Element.getStyle(this.bottom, 'height'));
261     var middleH = this.options.height - topH - bottomH;
262
263     var style = {height: middleH + 'px'};
264     Element.setStyle(this.middle, style);
265     Element.setStyle(this.middleLeft, style);
266     Element.setStyle(this.middleRight, style);
267     Element.setStyle(this.body, style);
268
269     this.leftArrowH = parseInt(Element.getStyle(this.leftArrow, 'height'));
270     this.rightArrowH = parseInt(Element.getStyle(this.rightArrow, 'height'));
271     this.middleH = middleH;
272   },
273
274   open : function() {
275     if (!Element.visible(this.tipNode)) {
276       this._setPosition();
277       Effect.Appear(this.tipNode);
278     }
279   },
280
281   close : function(){
282     if (Element.visible(this.tipNode)) {
283       this._setPosition();
284       Effect.Fade(this.tipNode);
285     }
286   }
287 }