Show:
  1. var JSONPRequest = Y.JSONPRequest,
  2. getByPath = Y.Object.getValue,
  3. noop = function () {};
  4. /**
  5. * Adds support for parsing complex callback identifiers from the jsonp url.
  6. * This includes callback=foo[1]bar.baz["goo"] as well as referencing methods
  7. * in the YUI instance.
  8. *
  9. * @module jsonp
  10. * @submodule jsonp-url
  11. * @for JSONPRequest
  12. */
  13. Y.mix(JSONPRequest.prototype, {
  14. /**
  15. * RegExp used by the default URL formatter to insert the generated callback
  16. * name into the JSONP url. Looks for a query param callback=. If a value
  17. * is assigned, it will be clobbered.
  18. *
  19. * @property _pattern
  20. * @type RegExp
  21. * @default /\bcallback=.*?(?=&|$)/i
  22. * @protected
  23. */
  24. _pattern: /\bcallback=(.*?)(?=&|$)/i,
  25. /**
  26. * Template used by the default URL formatter to add the callback function
  27. * name to the url.
  28. *
  29. * @property _template
  30. * @type String
  31. * @default "callback={callback}"
  32. * @protected
  33. */
  34. _template: "callback={callback}",
  35. /**
  36. * <p>Parses the url for a callback named explicitly in the string.
  37. * Override this if the target JSONP service uses a different query
  38. * parameter or url format.</p>
  39. *
  40. * <p>If the callback is declared inline, the corresponding function will
  41. * be returned. Otherwise null.</p>
  42. *
  43. * @method _defaultCallback
  44. * @param url {String} the url to search in
  45. * @return {Function} the callback function if found, or null
  46. * @protected
  47. */
  48. _defaultCallback: function (url) {
  49. var match = url.match(this._pattern),
  50. keys = [],
  51. i = 0,
  52. locator, path, callback;
  53. if (match) {
  54. // Strip the ["string keys"] and [1] array indexes
  55. locator = match[1]
  56. .replace(/\[(['"])(.*?)\1\]/g,
  57. function (x, $1, $2) {
  58. keys[i] = $2;
  59. return '.@' + (i++);
  60. })
  61. .replace(/\[(\d+)\]/g,
  62. function (x, $1) {
  63. /*jslint bitwise: true */
  64. keys[i] = parseInt($1, 10) | 0;
  65. return '.@' + (i++);
  66. })
  67. .replace(/^\./, ''); // remove leading dot
  68. // Validate against problematic characters.
  69. if (!/[^\w\.\$@]/.test(locator)) {
  70. path = locator.split('.');
  71. for (i = path.length - 1; i >= 0; --i) {
  72. if (path[i].charAt(0) === '@') {
  73. path[i] = keys[parseInt(path[i].substr(1), 10)];
  74. }
  75. }
  76. // First look for a global function, then the Y, then try the Y
  77. // again from the second token (to support "callback=Y.handler")
  78. callback = getByPath(Y.config.win, path) ||
  79. getByPath(Y, path) ||
  80. getByPath(Y, path.slice(1));
  81. }
  82. }
  83. return callback || noop;
  84. },
  85. /**
  86. * URL formatter that looks for callback= in the url and appends it
  87. * if not present. The supplied proxy name will be assigned to the query
  88. * param. Override this method by passing a function as the
  89. * &quot;format&quot; property in the config object to the constructor.
  90. *
  91. * @method _format
  92. * @param url { String } the original url
  93. * @param proxy {String} the function name that will be used as a proxy to
  94. * the configured callback methods.
  95. * @return {String} fully qualified JSONP url
  96. * @protected
  97. */
  98. _format: function (url, proxy) {
  99. var callbackRE = /\{callback\}/,
  100. callback, lastChar;
  101. if (callbackRE.test(url)) {
  102. return url.replace(callbackRE, proxy);
  103. }
  104. callback = this._template.replace(callbackRE, proxy);
  105. if (this._pattern.test(url)) {
  106. return url.replace(this._pattern, callback);
  107. } else {
  108. lastChar = url.slice(-1);
  109. if (lastChar !== '&' && lastChar !== '?') {
  110. url += (url.indexOf('?') > -1) ? '&' : '?';
  111. }
  112. return url + callback;
  113. }
  114. }
  115. }, true);