]> git.openstreetmap.org Git - rails.git/blob - public/javascripts/rails.js
Make more use of named scopes
[rails.git] / public / javascripts / rails.js
1 (function() {
2   // Technique from Juriy Zaytsev
3   // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4   function isEventSupported(eventName) {
5     var el = document.createElement('div');
6     eventName = 'on' + eventName;
7     var isSupported = (eventName in el);
8     if (!isSupported) {
9       el.setAttribute(eventName, 'return;');
10       isSupported = typeof el[eventName] == 'function';
11     }
12     el = null;
13     return isSupported;
14   }
15
16   function isForm(element) {
17     return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18   }
19
20   function isInput(element) {
21     if (Object.isElement(element)) {
22       var name = element.nodeName.toUpperCase()
23       return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24     }
25     else return false
26   }
27
28   var submitBubbles = isEventSupported('submit'),
29       changeBubbles = isEventSupported('change')
30
31   if (!submitBubbles || !changeBubbles) {
32     // augment the Event.Handler class to observe custom events when needed
33     Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34       function(init, element, eventName, selector, callback) {
35         init(element, eventName, selector, callback)
36         // is the handler being attached to an element that doesn't support this event?
37         if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38              (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39           // "submit" => "emulated:submit"
40           this.eventName = 'emulated:' + this.eventName
41         }
42       }
43     )
44   }
45
46   if (!submitBubbles) {
47     // discover forms on the page by observing focus events which always bubble
48     document.on('focusin', 'form', function(focusEvent, form) {
49       // special handler for the real "submit" event (one-time operation)
50       if (!form.retrieve('emulated:submit')) {
51         form.on('submit', function(submitEvent) {
52           var emulated = form.fire('emulated:submit', submitEvent, true)
53           // if custom event received preventDefault, cancel the real one too
54           if (emulated.returnValue === false) submitEvent.preventDefault()
55         })
56         form.store('emulated:submit', true)
57       }
58     })
59   }
60
61   if (!changeBubbles) {
62     // discover form inputs on the page
63     document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64       // special handler for real "change" events
65       if (!input.retrieve('emulated:change')) {
66         input.on('change', function(changeEvent) {
67           input.fire('emulated:change', changeEvent, true)
68         })
69         input.store('emulated:change', true)
70       }
71     })
72   }
73
74   function handleRemote(element) {
75     var method, url, params;
76
77     var event = element.fire("ajax:before");
78     if (event.stopped) return false;
79
80     if (element.tagName.toLowerCase() === 'form') {
81       method = element.readAttribute('method') || 'post';
82       url    = element.readAttribute('action');
83       params = element.serialize();
84     } else {
85       method = element.readAttribute('data-method') || 'get';
86       url    = element.readAttribute('href');
87       params = {};
88     }
89
90     new Ajax.Request(url, {
91       method: method,
92       parameters: params,
93       evalScripts: true,
94
95       onComplete:    function(request) { element.fire("ajax:complete", request); },
96       onSuccess:     function(request) { element.fire("ajax:success",  request); },
97       onFailure:     function(request) { element.fire("ajax:failure",  request); }
98     });
99
100     element.fire("ajax:after");
101   }
102
103   function handleMethod(element) {
104     var method = element.readAttribute('data-method'),
105         url = element.readAttribute('href'),
106         csrf_param = $$('meta[name=csrf-param]')[0],
107         csrf_token = $$('meta[name=csrf-token]')[0];
108
109     var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110     element.parentNode.insert(form);
111
112     if (method !== 'post') {
113       var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114       form.insert(field);
115     }
116
117     if (csrf_param) {
118       var param = csrf_param.readAttribute('content'),
119           token = csrf_token.readAttribute('content'),
120           field = new Element('input', { type: 'hidden', name: param, value: token });
121       form.insert(field);
122     }
123
124     form.submit();
125   }
126
127
128   document.on("click", "*[data-confirm]", function(event, element) {
129     var message = element.readAttribute('data-confirm');
130     if (!confirm(message)) event.stop();
131   });
132
133   document.on("click", "a[data-remote]", function(event, element) {
134     if (event.stopped) return;
135     handleRemote(element);
136     event.stop();
137   });
138
139   document.on("click", "a[data-method]", function(event, element) {
140     if (event.stopped) return;
141     handleMethod(element);
142     event.stop();
143   });
144
145   document.on("submit", function(event) {
146     var element = event.findElement(),
147         message = element.readAttribute('data-confirm');
148     if (message && !confirm(message)) {
149       event.stop();
150       return false;
151     }
152
153     var inputs = element.select("input[type=submit][data-disable-with]");
154     inputs.each(function(input) {
155       input.disabled = true;
156       input.writeAttribute('data-original-value', input.value);
157       input.value = input.readAttribute('data-disable-with');
158     });
159
160     var element = event.findElement("form[data-remote]");
161     if (element) {
162       handleRemote(element);
163       event.stop();
164     }
165   });
166
167   document.on("ajax:after", "form", function(event, element) {
168     var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169     inputs.each(function(input) {
170       input.value = input.readAttribute('data-original-value');
171       input.removeAttribute('data-original-value');
172       input.disabled = false;
173     });
174   });
175
176   Ajax.Responders.register({
177     onCreate: function(request) {
178       var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
179
180       if (csrf_meta_tag) {
181         var header = 'X-CSRF-Token',
182             token = csrf_meta_tag.readAttribute('content');
183
184         if (!request.options.requestHeaders) {
185           request.options.requestHeaders = {};
186         }
187         request.options.requestHeaders[header] = token;
188       }
189     }
190   });
191 })();