Elgg  Version 2.2
Ajax.js
Go to the documentation of this file.
1 define(function (require) {
2  var $ = require('jquery');
3  var elgg = require('elgg');
4  var spinner = require('elgg/spinner');
5 
6  var site_url = elgg.get_site_url(),
7  action_base = site_url + 'action/',
8  fragment_pattern = /#.*$/,
9  query_pattern = /\?.*$/,
10  leading_slash_pattern = /^\//,
11  slashes_pattern = /(^\/|\/$)/g;
12 
20  function Ajax(use_spinner) {
21 
22  use_spinner = elgg.isNullOrUndefined(use_spinner) ? true : !!use_spinner;
23 
24  var that = this;
25 
43  function fetch(options, hook_type) {
44  var orig_options,
45  params,
46  jqXHR,
47  metadata_extracted = false,
48  error_displayed = false;
49 
55  function extract_metadata(data) {
56  if (!metadata_extracted) {
57  var m = data._elgg_msgs;
58  if (m && m.error) {
59  elgg.register_error(m.error);
60  error_displayed = true;
61  data.status = -1;
62  } else {
63  data.status = 0;
64  }
65  m && m.success && elgg.system_message(m.success);
66  delete data._elgg_msgs;
67 
68  var deps = data._elgg_deps;
69  deps && deps.length && Ajax._require(deps);
70  delete data._elgg_deps;
71 
72  metadata_extracted = true;
73  }
74  }
75 
81  that._fetch_args = {
82  options: options,
83  hook_type: hook_type
84  };
85 
86  hook_type = hook_type || '';
87 
88  if (!$.isPlainObject(options)) {
89  throw new Error('options must be a plain object with key "url"');
90  }
91  if (!options.url && hook_type !== 'path:') {
92  throw new Error('options must be a plain object with key "url"');
93  }
94 
95  // ease hook filtering by making these keys always available
96  if (options.data === undefined) {
97  options.data = {};
98  }
99  if ($.isPlainObject(options.data)) {
100  options.data = options.data || {};
101  } else {
102  if (typeof options.data !== 'string') {
103  throw new Error('if defined, options.data must be a plain object or string');
104  }
105  }
106 
107  options.dataType = 'json';
108 
109  // copy of original options
110  orig_options = $.extend({}, options);
111 
112  params = {
113  options: options
114  };
115  if (hook_type && typeof options.data !== 'string') {
116  options.data = elgg.trigger_hook(Ajax.REQUEST_DATA_HOOK, hook_type, params, options.data);
117  }
118 
119  // we do this here because hook may have made data non-empty, in which case we'd need to
120  // default to POST
121  if (!options.method) {
122  options.method = 'GET';
123  if (options.data && !$.isEmptyObject(options.data)) {
124  options.method = 'POST';
125  }
126  }
127 
128  if (use_spinner) {
129  options.beforeSend = function () {
130  orig_options.beforeSend && orig_options.beforeSend.apply(null, arguments);
131  spinner.start();
132  };
133  options.complete = function () {
134  spinner.stop();
135  orig_options.complete && orig_options.complete.apply(null, arguments);
136  };
137  }
138 
139  if (!options.error) {
140  options.error = function (jqXHR, textStatus, errorThrown) {
141  if (!jqXHR.getAllResponseHeaders()) {
142  // user aborts (like refresh or navigate) do not have headers
143  return;
144  }
145 
146  try {
147  var data = $.parseJSON(jqXHR.responseText);
148  if ($.isPlainObject(data)) {
149  extract_metadata(data);
150  }
151  } catch (e) {
152  if (window.console) {
153  console.warn(e.message);
154  }
155  }
156 
157  if (!error_displayed) {
158  elgg.register_error(elgg.echo('ajax:error'));
159  }
160  };
161  }
162 
163  options.dataFilter = function (data, type) {
164  if (type !== 'json') {
165  return data;
166  }
167 
168  data = $.parseJSON(data);
169 
170  extract_metadata(data);
171 
172  var params = {
173  options: orig_options
174  };
175  if (hook_type) {
176  data = elgg.trigger_hook(Ajax.RESPONSE_DATA_HOOK, hook_type, params, data);
177  }
178 
179  jqXHR.AjaxData = data;
180 
181  return JSON.stringify(data.value);
182  };
183 
184  options.url = elgg.normalize_url(options.url);
185  options.headers = {
186  'X-Elgg-Ajax-API': '2'
187  };
188 
194  that._ajax_options = options;
195 
196  jqXHR = $.ajax(options);
197 
198  return jqXHR;
199  }
200 
210  this.path = function (path, options) {
211  elgg.assertTypeOf('string', path);
212 
213  // https://example.org/elgg/foo/?arg=1#bar => foo/?arg=1
214  if (path.indexOf(site_url) === 0) {
215  path = path.substr(site_url.length);
216  }
217  path = path.replace(fragment_pattern, '');
218 
219  assertNotUrl(path);
220 
221  options = options || {};
222  options.url = path;
223 
224  // /foo/?arg=1 => foo
225  path = path.replace(query_pattern, '').replace(slashes_pattern, '');
226 
227  return fetch(options, 'path:' + path);
228  };
229 
239  this.view = function (view, options) {
240  elgg.assertTypeOf('string', view);
241  if (view === '') {
242  throw new Error('view cannot be empty');
243  }
244 
245  assertNotUrl(view);
246 
247  options = options || {};
248  options.url = 'ajax/view/' + view;
249  options.method = options.method || 'GET';
250 
251  // remove query
252  view = view.replace(query_pattern, '').replace(slashes_pattern, '');
253 
254  return fetch(options, 'view:' + view);
255  };
256 
266  this.form = function (action, options) {
267  elgg.assertTypeOf('string', action);
268  if (action === '') {
269  throw new Error('action cannot be empty');
270  }
271 
272  action = action.replace(leading_slash_pattern, '').replace(fragment_pattern, '');
273 
274  assertNotUrl(action);
275 
276  options = options || {};
277  options.url = 'ajax/form/' + action;
278  options.method = options.method || 'GET';
279 
280  // remove query
281  action = action.replace(query_pattern, '').replace(slashes_pattern, '');
282 
283  return fetch(options, 'form:' + action);
284  };
285 
295  this.action = function (action, options) {
296  elgg.assertTypeOf('string', action);
297  if (action === '') {
298  throw new Error('action cannot be empty');
299  }
300 
301  // https://example.org/elgg/action/foo/?arg=1#bar => foo/?arg=1
302  if (action.indexOf(action_base) === 0) {
303  action = action.substr(action_base.length);
304  }
305  action = action.replace(leading_slash_pattern, '').replace(fragment_pattern, '');
306 
307  assertNotUrl(action);
308 
309  options = options || {};
310  options.data = options.data || {};
311 
312  // add tokens?
313  var m = action.match(/\?(.+)$/);
314  if (m && /(^|&)__elgg_ts=/.test(m[1])) {
315  // token will be in the URL
316  } else {
317  options.data = elgg.security.addToken(options.data);
318  }
319 
320  options.method = options.method || 'POST';
321  options.url = 'action/' + action;
322 
323  // /foo/?arg=1 => foo
324  action = action.replace(query_pattern, '').replace(slashes_pattern, '');
325 
326  return fetch(options, 'action:' + action);
327  };
328 
336  this.objectify = function (el) {
337  // http://stackoverflow.com/a/1186309/3779
338  var o = {};
339  var a = $(el).serializeArray();
340 
341  $.each(a, function() {
342  if (o[this.name] !== undefined) {
343  if (!o[this.name].push) {
344  o[this.name] = [o[this.name]];
345  }
346  o[this.name].push(this.value || '');
347  } else {
348  o[this.name] = this.value || '';
349  }
350  });
351 
352  return o;
353  };
354  }
355 
361  function assertNotUrl(arg) {
362  if (/^https?:/.test(arg)) {
363  throw new Error('elgg/Ajax cannot be used with external URLs');
364  }
365  }
366 
371  Ajax.REQUEST_DATA_HOOK = 'ajax_request_data';
372 
379  Ajax.RESPONSE_DATA_HOOK = 'ajax_response_data';
380 
384  Ajax._require = require;
385 
386  return Ajax;
387 });
elgg
Definition: install.js:23
$CONFIG view
The current view type.
Definition: config.php:149
elgg isPlainObject
Check if the value is a "plain" object (i.e., created by {} or new Object())
Definition: elgglib.js:75
a
Definition: admin.css.php:97
$CONFIG path
The full path where Elgg is installed.
Definition: config.php:16
list style type
Definition: admin.css.php:777
elgg river item form
elgg require
Throw an error if the required package isn't present.
Definition: elgglib.js:164
$site name
define(function(require){var $=require('jquery');$(document).on('change', '#elgg-river-selector', function(){var url=window.location.href;if(window.location.search.length){url=url.substring(0, url.indexOf('?'));}url+= '?'+$(this).val();window.location.href=url;});})
Initiates page reload when river selector value changes core/river/filter.
elgg action
Definition: ajax.js:200