Source: utils.js

  1. /**
  2. * Utils module.
  3. * @module utils
  4. */
  5. define([
  6. 'exports',
  7. 'errors',
  8. 'settings'
  9. ], function(exports, errors, settings) {
  10. 'use strict';
  11. /**
  12. * Populates an object with defaults if the key is not yet defined.
  13. * Similar to _.defaults except this takes only a single defaults object.
  14. * @param {object} object - the object to populate defaults on
  15. * @param {object} defaults - the defaults to use
  16. * @returns {object}
  17. */
  18. exports.defaults = function(object, defaults) {
  19. object = object || {};
  20. Object.keys(defaults).forEach(function(key) {
  21. if (typeof object[key] === 'undefined') {
  22. object[key] = defaults[key];
  23. }
  24. });
  25. return object;
  26. };
  27. /**
  28. * Gets the app origin
  29. * @returns {string}
  30. */
  31. exports.getSelfOrigin = function(settingsObj) {
  32. settingsObj = settingsObj || settings;
  33. if (settingsObj.appSelf) {
  34. // This might be null for type:web packaged apps.
  35. // If that's a requirement, the caller should check for nulls.
  36. return settingsObj.appSelf.origin;
  37. } else {
  38. var win = settingsObj.window;
  39. if (win.location.origin) {
  40. return win.location.origin;
  41. } else {
  42. return win.location.protocol + '//' + win.location.hostname;
  43. }
  44. }
  45. };
  46. /**
  47. * Gets the the origin of the URL provided.
  48. * @param {string} url - the URL to introspect the origin from
  49. * @returns {string}
  50. */
  51. exports.getUrlOrigin = function(url) {
  52. var a = document.createElement('a');
  53. a.href = url;
  54. return a.origin || (a.protocol + '//' + a.host);
  55. };
  56. /**
  57. * Gets the center coordinates for a passed width and height.
  58. * Uses centering calcs that work on multiple monitors (bug 1122683).
  59. * @param {number} w - width
  60. * @param {number} h - height
  61. * @returns {list}
  62. */
  63. exports.getCenteredCoordinates = function(w, h) {
  64. var x = window.screenX +
  65. Math.max(0, Math.floor((window.innerWidth - w) / 2));
  66. var y = window.screenY +
  67. Math.max(0, Math.floor((window.innerHeight - h) / 2));
  68. return [x, y];
  69. };
  70. /**
  71. * Re-center an existing window.
  72. * @param {object} winRef - A reference to an existing window
  73. * @param {number} [w] - width
  74. * @param {number} [h] - height
  75. * @returns {undefined}
  76. */
  77. exports.reCenterWindow = function(winRef, w, h) {
  78. w = w || settings.winWidth;
  79. h = h || settings.winHeight;
  80. var xy = exports.getCenteredCoordinates(w, h);
  81. try {
  82. // Allow for the chrome as resizeTo args are the external
  83. // window dimensions not the internal ones.
  84. w = w + (winRef.outerWidth - winRef.innerWidth);
  85. h = h + (winRef.outerHeight - winRef.innerHeight);
  86. settings.log.log('width: ', w, 'height:', h);
  87. winRef.resizeTo(w, h);
  88. winRef.moveTo(xy[0], xy[1]);
  89. } catch(e) {
  90. settings.log.log("We don't have permission to resize this window");
  91. }
  92. };
  93. /**
  94. * Open a window
  95. * @param {object} [options] - the settings object
  96. * @param {string} [options.url] - the window url
  97. * @param {string} [options.title] - the window title
  98. * @param {number} [options.w] - the window width
  99. * @param {number} [options.h] - the window height
  100. * @returns {object} windowRef - a window reference.
  101. */
  102. exports.openWindow = function(options) {
  103. var defaults = {
  104. url: '',
  105. title: 'FxPay',
  106. w: settings.winWidth,
  107. h: settings.winHeight,
  108. };
  109. options = exports.defaults(options, defaults);
  110. var xy = exports.getCenteredCoordinates(options.w, options.h);
  111. var winOptString = 'toolbar=no,location=yes,directories=no,' +
  112. 'menubar=no,scrollbars=yes,resizable=no,copyhistory=no,' +
  113. 'width=' + options.w + ',height=' + options.h +
  114. ',top=' + xy[1] + ',left=' + xy[0];
  115. var windowRef = settings.window.open(options.url, options.title,
  116. winOptString);
  117. if (!windowRef) {
  118. settings.log.error('window.open() failed. URL:', options.url);
  119. }
  120. return windowRef;
  121. };
  122. /**
  123. * Get the App object returned from [`mozApps.getSelf()`](http://goo.gl/x4BDqs)
  124. * @param {module:utils~getAppSelfCallback} callback - the callback function.
  125. * @returns {undefined}
  126. */
  127. exports.getAppSelf = function getAppSelf(callback) {
  128. function storeAppSelf(appSelf) {
  129. if (appSelf === null) {
  130. throw new Error('cannot store a null appSelf');
  131. }
  132. settings.appSelf = appSelf;
  133. return appSelf;
  134. }
  135. if (settings.appSelf !== null) {
  136. // This means getAppSelf() has already run successfully so let's
  137. // return the value immediately.
  138. return callback(null, settings.appSelf);
  139. }
  140. if (!settings.mozApps) {
  141. settings.log.info(
  142. 'web platform does not define mozApps, cannot get appSelf');
  143. return callback(null, storeAppSelf(false));
  144. }
  145. var appRequest = settings.mozApps.getSelf();
  146. appRequest.onsuccess = function() {
  147. var appSelf = this.result;
  148. // In the case where we're in a Firefox that supports mozApps but
  149. // we're not running as an app, this could be falsey.
  150. settings.log.info('got appSelf from mozApps.getSelf()');
  151. callback(null, storeAppSelf(appSelf || false));
  152. };
  153. appRequest.onerror = function() {
  154. var errCode = this.error.name;
  155. settings.log.error('mozApps.getSelf() returned an error', errCode);
  156. // We're not caching an appSelf result here.
  157. // This allows nested functions to report errors better.
  158. callback(errors.InvalidApp('invalid application: ' + errCode,
  159. {code: errCode}), settings.appSelf);
  160. };
  161. };
  162. /**
  163. * The callback called by {@link module:utils.getAppSelf }
  164. * @callback module:utils~getAppSelfCallback
  165. * @param {object} error - an error object. Will be null if no error.
  166. * @param {object} appSelf - the [appSelf object](http://goo.gl/HilsmA)
  167. */
  168. /**
  169. * Log a deprecation message with some extra info.
  170. * @param {string} msg - log message
  171. * @param {string} versionDeprecated - the version when deprecated
  172. * @returns {undefined}
  173. */
  174. exports.logDeprecation = function(msg, versionDeprecated) {
  175. settings.log.warn(
  176. msg + '. This was deprecated in ' + versionDeprecated + '. ' +
  177. 'More info: https://github.com/mozilla/fxpay/releases/tag/' +
  178. versionDeprecated);
  179. };
  180. /**
  181. * Take an object of key value pairs and serialize it into a url-encoded
  182. * query string.
  183. * @example
  184. * // returns foo=bar&baz=zup
  185. * utils.serialize({"foo": "bar", "baz": "zup"});
  186. * @param {object} obj - object to serialize
  187. * @returns {string}
  188. */
  189. exports.serialize = function serialize(obj) {
  190. var str = [];
  191. for (var p in obj){
  192. if (obj.hasOwnProperty(p)) {
  193. str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
  194. }
  195. }
  196. return str.join("&");
  197. };
  198. });