JAL-1807 update
[jalviewjs.git] / site / js / JSmoljQueryExt.js
1 // JSmoljQueryExt.js
2 // 9/2/2013 7:43:12 AM BH Opera/Safari fix for binary file reading
3 // 3/11/2014 6:31:01 AM BH fix for MSIE not working locally
4
5 ;(function($) {
6
7         function createXHR(isMSIE) {
8                 try {
9                         return (isMSIE ? new window.ActiveXObject( "Microsoft.XMLHTTP" ) : new window.XMLHttpRequest());
10                 } catch( e ) {}
11         }
12
13  $.ajaxSettings.xhr = (window.ActiveXObject === undefined ? createXHR :  
14         function() {
15                 return (this.url == document.location || this.url.indexOf("http") == 0 || !this.isLocal) &&  // BH MSIE fix
16                         /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
17                         createXHR() || createXHR(1);
18         });
19
20
21 // Bind script tag hack transport
22                 $.ajaxTransport( "+script", function(s) {
23
24         // This transport only deals with cross domain requests
25         // BH: No! This is not compatible with Chrome
26         if ( true || s.crossDomain ) {
27
28                 var script,
29                         head = document.head || jQuery("head")[0] || document.documentElement;
30
31                 return {
32
33                         send: function( _, callback ) {
34                                 script = document.createElement("script");
35                                 //script.async = true;
36
37                                 if ( s.scriptCharset ) {
38                                         script.charset = s.scriptCharset;
39                                 }
40
41                                 script.src = s.url;
42
43                                 // Attach handlers for all browsers
44                                 script.onload = script.onreadystatechange = function( _, isAbort ) {
45
46                                         if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
47
48                                                 // Handle memory leak in IE
49                                                 script.onload = script.onreadystatechange = null;
50                                                 // Remove the script
51                                                 if ( script.parentNode ) {
52                                                         script.parentNode.removeChild( script );
53                                                 }
54
55                                                 // Dereference the script
56                                                 script = null;
57
58                                                 // Callback if not abort
59                                                 if ( !isAbort ) {
60                                                         callback( 200, "success" );
61                                                 }
62                                         }
63                                 };
64
65                                 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
66                                 // Use native DOM manipulation to avoid our domManip AJAX trickery
67                                 head.insertBefore( script, head.firstChild );
68                         },
69
70                         abort: function() {
71                                 if ( script ) {
72                                         script.onload( undefined, true );
73                                 }
74                         }
75                 };
76         }
77 });
78  
79         // incorporates jquery.iecors MSIE asynchronous cross-domain request for MSIE < 10
80
81         $.extend( $.support, { iecors: !!window.XDomainRequest });
82
83         if ($.support.iecors) {
84                 // source: https://github.com/dkastner/jquery.iecors
85                 // author: Derek Kastner dkastner@gmail.com http://dkastner.github.com    
86                 $.ajaxTransport(function(s) {
87                 
88                         return {
89                                 send: function( headers, complete ) {                           
90                                         // Note that xdr is not synchronous.
91                                         // This is only being used in JSmol for transport of java code packages.
92                                         var xdr = new window.XDomainRequest();
93                                         xdr.onload = function() {          
94                                                 var headers = { 'Content-Type': xdr.contentType };
95                                                 complete(200, 'OK', { text: xdr.responseText }, headers);
96                                         };
97                                         if ( s.xhrFields ) {
98                                                 xdr.onerror = s.xhrFields.error;
99                                                 xdr.ontimeout = s.xhrFields.timeout;
100                                         }
101                                         xdr.open( s.type, s.url );
102                                         xdr.send( ( s.hasContent && s.data ) || null );
103                                 },
104                                 abort: function() {        
105                                         xdr.abort();
106                                 }
107                         };
108                 });
109
110         } else {
111
112         // adds support for synchronous binary file reading
113
114                 $.ajaxSetup({
115                         accepts: { binary: "text/plain; charset=x-user-defined" },
116                         responseFields: { binary: "response" }
117                 })
118
119
120                 $.ajaxTransport('binary', function(s) {
121                 
122                         var callback;
123                         return {
124                                 // synchronous or asynchronous binary transfer only
125                                 send: function( headers, complete ) {        
126                                         var xhr = s.xhr();
127                                         console.log("xhr.open binary async=" + s.async + " url=" + s.url);
128                                         xhr.open( s.type, s.url, s.async );                                     
129                                         var isOK = false;
130                                         try {
131                                                 if (xhr.hasOwnProperty("responseType")) {
132                                                                 xhr.responseType = "arraybuffer";
133                                                                 isOK = true;
134                                                 } 
135                                         } catch(e) {
136                                           //
137                                         }
138                                         try {
139                                                 if (!isOK && xhr.overrideMimeType) {
140                                                         xhr.overrideMimeType('text/plain; charset=x-user-defined');
141                                                 }
142                                         } catch(e) {
143                                                         //
144                                         }
145                                         if ( !s.crossDomain && !headers["X-Requested-With"] ) {
146                                                 headers["X-Requested-With"] = "XMLHttpRequest";
147                                         }
148                                         try {
149                                                 for (var i in headers )
150                                                         xhr.setRequestHeader( i, headers[ i ] );
151                                         } catch(_) {}
152
153                                         xhr.send( ( s.hasContent && s.data ) || null );
154
155                                         // Listener
156                                         callback = function( _, isAbort ) {
157
158                                         var 
159                                                 status = xhr.status,
160                                                 statusText = "",
161                                                 responseHeaders = xhr.getAllResponseHeaders(),
162                                                 responses = {},
163                                                 xml;
164
165                                         try {
166
167                                                 // Firefox throws exceptions when accessing properties
168                                                 // of an xhr when a network error occured
169                                                 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
170                                                 // Was never called and is aborted or complete
171                                                 if ( callback && ( xhr.readyState === 4 ) ) {
172
173                                                         // Only called once
174                                                         callback = undefined;
175
176                                                         // When requesting binary data, IE6-9 will throw an exception
177                                                         // on any attempt to access responseText (#11426)
178                                                         try {
179                                                                 responses.text = (typeof xhr.responseText === "string" ? xhr.responseText : null);
180                                                         } catch( _ ) {
181                                                         }
182                                                         try {
183                                                                 responses.binary = xhr.response;
184                                                         } catch( _ ) {
185                                                         }
186
187                                                         // Firefox throws an exception when accessing
188                                                         // statusText for faulty cross-domain requests
189                                                         try {
190                                                                 statusText = xhr.statusText;
191                                                         } catch( _ ) {
192                                                                 // We normalize with Webkit giving an empty statusText
193                                                                 statusText = "";
194                                                         }
195                                                         // Filter status for non standard behaviors
196
197                                                         // If the request is local and we have data: assume a success
198                                                         // (success with no data won't get notified, that's the best we
199                                                         // can do given current implementations)
200                                                         if ( !status && s.isLocal && !s.crossDomain ) {
201                                                                 status = (responses.text ? 200 : 404);
202                                                         // IE - #1450: sometimes returns 1223 when it should be 204
203                                                         } else if ( status === 1223 ) {
204                                                                 status = 204;
205                                                         }
206                                                         complete( status, statusText, responses, responseHeaders );
207                                                 }
208                                         } catch( e ) {
209                                                 alert(e)
210                                                 complete( -1, e );
211                                         }
212                                         };
213                                         
214                                         if ( !s.async ) {
215                                                 // if we're in sync mode we fire the callback
216                                                 callback();
217                                         } else if ( xhr.readyState === 4 ) {
218                                                 // (IE6 & IE7) if it's in cache and has been
219                                                 // retrieved directly we need to fire the callback
220                                                 setTimeout( callback );
221                                         } else {
222                                                 // Add to the list of active xhr callbacks
223                                                 xhr.onreadystatechange = callback;
224                                         }
225                                         
226                                 },
227                                 abort: function() {}
228                         };
229                 });
230         }
231 })( jQuery );
232          
233 /*
234  * jQuery outside events - v1.1 - 3/16/2010
235  * http://benalman.com/projects/jquery-outside-events-plugin/
236  * 
237  * Copyright (c) 2010 "Cowboy" Ben Alman
238  * Dual licensed under the MIT and GPL licenses.
239  * http://benalman.com/about/license/
240  * 
241  * Modified by Bob Hanson for JSmol-specific events and to add parameter reference to actual jQuery event.
242  * Used for closing the pop-up menu.
243  *   
244  */
245
246 ;(function($,doc,eventList,id){  
247         // was 'click dblclick mousemove mousedown mouseup mouseover mouseout change select submit keydown keypress keyup'
248         $.map(
249                 eventList.split(' '),
250                 function( event_name ) { jq_addOutsideEvent( event_name ); }
251         );
252         jq_addOutsideEvent( 'focusin',  'focus' + id );
253         jq_addOutsideEvent( 'focusout', 'blur' + id );
254         function jq_addOutsideEvent( event_name, outside_event_name ) {
255                 outside_event_name = outside_event_name || event_name + id;
256                 var elems = $(),
257                         event_namespaced = event_name + '.' + outside_event_name + '-special-event';
258                 $.event.special[ outside_event_name ] = {    
259                         setup: function(){
260                                 elems = elems.add( this );
261                                 if ( elems.length === 1 ) {
262                                         $(doc).bind( event_namespaced, handle_event );
263                                 }
264                         },
265                         teardown: function(){
266                                 self.Jmol && Jmol._setMouseOwner(null);
267                                 elems = elems.not( this );
268                                 if ( elems.length === 0 ) {
269                                         $(doc).unbind( event_namespaced );
270                                 }
271                         },
272                         add: function( handleObj ) {
273                                 var old_handler = handleObj.handler;
274                                 handleObj.handler = function( event, elem ) {
275                                         event.target = elem;
276                                         old_handler.apply( this, arguments );
277                                 };
278                         }
279                 };
280                 function handle_event( event ) {
281                         $(elems).each(function(){
282                                 self.Jmol && (outside_event_name.indexOf("mouseup") >= 0 || outside_event_name.indexOf("touchend") >= 0) && Jmol._setMouseOwner(null);
283                                 var elem = $(this);
284                                 if ( this !== event.target && !elem.has(event.target).length ) {
285                                         //BH: adds event to pass that along to our handler as well.
286                                         elem.triggerHandler( outside_event_name, [ event.target, event ] );
287                                 }
288                         });
289                 };
290         };
291 })(jQuery,document,"click mousemove mouseup touchmove touchend", "outjsmol");