2 * extensions/double-click.js
4 * Part of the jsMath package for mathematics on the web.
6 * This file allows users to double click on typeset mathematics
7 * to view the TeX source for the given expression. It will be loaded
8 * automatically when needed, or can be loaded by
10 * jsMath.Extension.Require('double-click');
12 * ---------------------------------------------------------------------
14 * Copyright 2005-2008 by Davide P. Cervone
16 * Licensed under the Apache License, Version 2.0 (the "License");
17 * you may not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
20 * http://www.apache.org/licenses/LICENSE-2.0
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
29 /********************************************************************/
31 if (jsMath.Click && jsMath.Click.styles)
32 {jsMath.Click.oldStyles = jsMath.Click.styles}
34 jsMath.Add(jsMath.Click,{
39 // Floating windows for displaying TeX source
41 position: 'absolute', top: '0px', left: '0px', 'z-index': '101',
42 'max-width': '80%', width: 'auto', height: 'auto',
43 padding: '0px', margin: '0px', 'font-size': '100%'
45 '#jsMath_float .drag': {
46 'background-color': '#DDDDDD',
47 border: 'outset 1px', padding: '0px', margin: '0px',
48 width: 'auto', height: '12px', 'font-size': '1px'
50 '#jsMath_float .close': {
51 'background-color': '#E6E6E6',
52 border: 'inset 1px', margin: '1px 2px', padding: '0px',
53 width: '8px', height: '8px'
55 '#jsMath_float .source': {
56 'background-color': '#E2E2E2',
57 border: 'outset 1px', margin: '0px', padding: '8px 15px',
58 width: 'auto', height: 'auto',
59 'font-family': 'courier, fixed', 'font-size': '90%'
64 * Create the hidden DIV used for the tex source window
67 if (this.oldStyles) {jsMath.Insert(this.styles,this.oldStyles)}
68 jsMath.Setup.Styles(this.styles);
69 this.source = jsMath.Setup.DIV("float",{display:'none'});
70 this.source.innerHTML =
71 '<div class="drag"><div class="close"></div></div>'
72 + '<div class="source"><span></span></div>';
73 this.drag = this.source.firstChild;
74 this.tex = this.drag.nextSibling.firstChild;
75 this.drag.firstChild.onclick = jsMath.Click.CloseSource;
76 this.drag.onmousedown = jsMath.Click.StartDragging;
77 this.drag.ondragstart = jsMath.Click.False;
78 this.drag.onselectstart = jsMath.Click.False;
79 this.source.onclick = jsMath.Click.CheckClose;
81 False: function () {return false},
84 * Handle a double-click on an equation
86 DblClick: function (data) {
87 var event = data[0]; var TeX = data[1];
88 var event = jsMath.Click.Event(event);
90 var source = jsMath.Click.source
91 var tex = jsMath.Click.tex;
93 source.style.visibility = 'hidden';
94 source.style.display = ''; source.style.width = '';
95 source.style.left = ''; source.style.top = '';
98 TeX = TeX.replace(/^\s+|\s+$/g,'');
99 TeX = TeX.replace(/&/g,'&');
100 TeX = TeX.replace(/</g,'<');
101 TeX = TeX.replace(/>/g,'>');
102 TeX = TeX.replace(/\n/g,'<br/>');
105 var h = source.offsetHeight; var w;
106 if (jsMath.Browser.msieDivWidthBug) {
107 tex.className = 'source'; // Work around MSIE bug where
108 w = tex.offsetWidth + 5; // DIV's don't collapse to
109 tex.className = ''; // their natural widths
111 w = source.offsetWidth;
113 w = Math.max(50,Math.min(w,.8*event.W,event.W-40));
114 var x = Math.floor(event.x-w/2); var y = Math.floor(event.y-h/2);
115 x = event.X + Math.max(Math.min(x,event.W-w-20),20);
116 y = event.Y + Math.max(Math.min(y,event.H-h-5),5);
118 source.style.left = x+'px'; source.style.top = y+'px';
119 source.style.width = w+'px';
120 source.style.visibility = '';
121 jsMath.Click.left = x + event.X; jsMath.Click.top = y + event.Y;
122 jsMath.Click.w = w; jsMath.Click.h = source.offsetHeight;
124 jsMath.Click.DeselectText(x,y);
129 * Get window width, height, and offsets plus
130 * position of pointer relative to the window
132 Event: function (event) {
133 var W = jsMath.window.innerWidth || jsMath.document.body.clientWidth;
134 var H = jsMath.window.innerHeight || jsMath.document.body.clientHeight;
135 var X = jsMath.window.pageXOffset; var Y = jsMath.window.pageYOffset;
137 X = jsMath.document.body.clientLeft;
138 Y = jsMath.document.body.clientTop;
140 var x = event.pageX; var y = event.pageY;
142 x = event.clientX; y = event.clientY;
143 if (jsMath.browser == 'MSIE' && jsMath.document.compatMode == 'CSS1Compat') {
144 X = jsMath.document.documentElement.scrollLeft;
145 Y = jsMath.document.documentElement.scrollTop;
146 W = jsMath.document.documentElement.clientWidth;
147 H = jsMath.document.documentElement.clientHeight;
149 X = jsMath.document.body.scrollLeft;
150 Y = jsMath.document.body.scrollTop;
152 } else {x -= X; y -= Y}
154 return {x: x, y: y, W: W, H: H, X: X, Y: Y};
158 * Unselect whatever text is selected (since double-clicking
159 * usually selects something)
161 DeselectText: function (x,y) {
162 if (jsMath.window.getSelection && jsMath.window.getSelection().removeAllRanges)
163 {jsMath.window.getSelection().removeAllRanges()}
164 else if (jsMath.document.getSelection && jsMath.document.getSelection().removeAllRanges)
165 {jsMath.document.getSelection().removeAllRanges()}
166 else if (jsMath.document.selection && jsMath.document.selection.empty)
167 {jsMath.document.selection.empty()}
169 /* Hack to deselect the text in Opera and Safari */
170 if (jsMath.browser == 'MSIE') return; // don't try it if MISE on Mac
171 jsMath.hiddenTop.innerHTML =
172 '<textarea style="visibility:hidden" rows="1" cols="1">a</textarea>';
173 jsMath.hiddenTop.firstChild.style.position = 'absolute';
174 jsMath.hiddenTop.firstChild.style.left = x+'px';
175 jsMath.hiddenTop.firstChild.style.top = y+'px';
176 setTimeout(jsMath.Click.SelectHidden,1);
179 SelectHidden: function () {
180 jsMath.hiddenTop.firstChild.focus();
181 jsMath.hiddenTop.firstChild.select();
182 jsMath.hiddenTop.innerHTML = '';
186 * Close the TeX source window
188 CloseSource: function () {
189 jsMath.Click.tex.innerHTML = '';
190 jsMath.Click.source.style.display = 'none';
191 jsMath.Click.source.style.visibility = 'hidden';
192 jsMath.Click.StopDragging();
195 CheckClose: function (event) {
196 if (!event) {event = jsMath.window.event}
197 if (event.altKey) {jsMath.Click.CloseSource(); return false}
201 * Set up for dragging the source panel
203 StartDragging: function (event) {
204 if (!event) {event = jsMath.window.event}
205 if (jsMath.Click.dragging) {jsMath.Click.StopDragging(event)}
206 var event = jsMath.Click.Event(event);
207 jsMath.Click.dragging = 1;
208 jsMath.Click.x = event.x + 2*event.X - jsMath.Click.left;
209 jsMath.Click.y = event.y + 2*event.Y - jsMath.Click.top;
210 jsMath.Click.oldonmousemove = jsMath.document.onmousemove;
211 jsMath.Click.oldonmouseup = jsMath.document.onmouseup;
212 jsMath.document.onmousemove = jsMath.Click.DragSource;
213 jsMath.document.onmouseup = jsMath.Click.StopDragging;
218 * Stop dragging the source window
220 StopDragging: function (event) {
221 if (jsMath.Click.dragging) {
222 jsMath.document.onmousemove = jsMath.Click.oldonmousemove;
223 jsMath.document.onmouseup = jsMath.Click.oldonmouseup;
224 jsMath.Click.oldonmousemove = null;
225 jsMath.Click.oldonmouseup = null;
226 jsMath.Click.dragging = 0;
232 * Move the source window (but stay within the browser window)
234 DragSource: function (event) {
235 if (!event) {event = jsMath.window.event}
236 if (jsMath.Browser.buttonCheck && !event.button) {return jsMath.Click.StopDragging(event)}
237 event = jsMath.Click.Event(event);
238 var x = event.x + event.X - jsMath.Click.x;
239 var y = event.y + event.Y - jsMath.Click.y;
240 x = Math.max(event.X,Math.min(event.W+event.X-jsMath.Click.w,x));
241 y = Math.max(event.Y,Math.min(event.H+event.Y-jsMath.Click.h,y));
242 jsMath.Click.source.style.left = x + 'px';
243 jsMath.Click.source.style.top = y + 'px';
244 jsMath.Click.left = x + event.X; jsMath.Click.top = y + event.Y;