InfoBoxViewModel.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*global define*/
  2. define([
  3. '../../Core/defaultValue',
  4. '../../Core/defined',
  5. '../../Core/defineProperties',
  6. '../../Core/Event',
  7. '../../Core/formatError',
  8. '../../Core/TaskProcessor',
  9. '../../ThirdParty/knockout',
  10. '../../ThirdParty/when'
  11. ], function(
  12. defaultValue,
  13. defined,
  14. defineProperties,
  15. Event,
  16. formatError,
  17. TaskProcessor,
  18. knockout,
  19. when) {
  20. "use strict";
  21. var cameraEnabledPath = 'M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4853444 22.104033 11.423165 24.0625 13.84375 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 8.975298 28.305952 7.03125 25.875 7.03125 L 13.84375 7.03125 z';
  22. var cameraDisabledPath = 'M 27.34375 1.65625 L 5.28125 27.9375 L 8.09375 30.3125 L 30.15625 4.03125 L 27.34375 1.65625 z M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4724893 20.232036 9.5676108 20.7379 9.75 21.21875 L 21.65625 7.03125 L 13.84375 7.03125 z M 28.21875 7.71875 L 14.53125 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 9.8371439 29.456025 8.4902779 28.21875 7.71875 z';
  23. /**
  24. * The view model for {@link InfoBox}.
  25. * @alias InfoBoxViewModel
  26. * @constructor
  27. */
  28. var InfoBoxViewModel = function() {
  29. this._sanitizer = undefined;
  30. this._descriptionRawHtml = '';
  31. this._descriptionSanitizedHtml = '';
  32. this._cameraClicked = new Event();
  33. this._closeClicked = new Event();
  34. /**
  35. * Gets or sets the maximum height of the info box in pixels. This property is observable.
  36. * @type {Number}
  37. */
  38. this.maxHeight = 500;
  39. /**
  40. * Gets or sets whether the camera tracking icon is enabled.
  41. * @type {Boolean}
  42. */
  43. this.enableCamera = false;
  44. /**
  45. * Gets or sets the status of current camera tracking of the selected object.
  46. * @type {Boolean}
  47. */
  48. this.isCameraTracking = false;
  49. /**
  50. * Gets or sets the visibility of the info box.
  51. * @type {Boolean}
  52. */
  53. this.showInfo = false;
  54. /**
  55. * Gets or sets the title text in the info box.
  56. * @type {String}
  57. */
  58. this.titleText = '';
  59. /**
  60. * Gets or sets the HTML for the loading indicator during sanitization of the raw description.
  61. * @type {String}
  62. */
  63. this.loadingIndicatorHtml = '<div class="cesium-infoBox-loadingContainer"><span class="cesium-infoBox-loading"></span></div>';
  64. knockout.track(this, ['showInfo', 'titleText', '_descriptionRawHtml', '_descriptionSanitizedHtml', 'maxHeight', 'enableCamera', 'isCameraTracking']);
  65. /**
  66. * Gets or sets the un-sanitized description HTML for the info box.
  67. * @type {String}
  68. */
  69. this.descriptionRawHtml = undefined;
  70. knockout.defineProperty(this, 'descriptionRawHtml', {
  71. get : function() {
  72. return this._descriptionRawHtml;
  73. },
  74. set : function(value) {
  75. if (this._descriptionRawHtml !== value) {
  76. this._descriptionRawHtml = value;
  77. this._descriptionSanitizedHtml = this.loadingIndicatorHtml;
  78. var that = this;
  79. when(this.sanitizer(value), function(sanitized) {
  80. // make sure the raw HTML still matches the input we sanitized,
  81. // in case it was changed again while we were sanitizing.
  82. if (that._descriptionRawHtml === value) {
  83. that._descriptionSanitizedHtml = sanitized;
  84. }
  85. }).otherwise(function(error) {
  86. /*global console*/
  87. console.log('An error occurred while sanitizing HTML: ' + formatError(error));
  88. });
  89. }
  90. }
  91. });
  92. /**
  93. * Gets the sanitized description HTML for the info box.
  94. * @type {String}
  95. */
  96. this.descriptionSanitizedHtml = undefined;
  97. knockout.defineProperty(this, 'descriptionSanitizedHtml', {
  98. get : function() {
  99. return this._descriptionSanitizedHtml;
  100. }
  101. });
  102. /**
  103. * Gets the SVG path of the camera icon, which can change to be "crossed out" or not.
  104. * @type {String}
  105. */
  106. this.cameraIconPath = undefined;
  107. knockout.defineProperty(this, 'cameraIconPath', {
  108. get : function() {
  109. return (this.enableCamera || this.isCameraTracking) ? cameraEnabledPath : cameraDisabledPath;
  110. }
  111. });
  112. knockout.defineProperty(this, '_bodyless', {
  113. get : function() {
  114. return !this._descriptionSanitizedHtml;
  115. }
  116. });
  117. };
  118. /**
  119. * Gets the maximum height of sections within the info box, minus an offset, in CSS-ready form.
  120. * @param {Number} offset The offset in pixels.
  121. * @returns {String}
  122. */
  123. InfoBoxViewModel.prototype.maxHeightOffset = function(offset) {
  124. return (this.maxHeight - offset) + 'px';
  125. };
  126. var sanitizerTaskProcessor;
  127. function defaultSanitizer(html) {
  128. if (!defined(sanitizerTaskProcessor)) {
  129. sanitizerTaskProcessor = new TaskProcessor('sanitizeHtml', Infinity);
  130. }
  131. return sanitizerTaskProcessor.scheduleTask(html);
  132. }
  133. /**
  134. * Gets or sets the default HTML sanitization function to use for all instances.
  135. * By default, the Google Caja HTML/CSS sanitizer is loaded in a worker.
  136. * A specific instance can override this property by setting its sanitizer property.
  137. *
  138. * @member
  139. * @type {InfoBoxViewModel~Sanitizer}
  140. */
  141. InfoBoxViewModel.defaultSanitizer = defaultSanitizer;
  142. defineProperties(InfoBoxViewModel.prototype, {
  143. /**
  144. * Gets an {@link Event} that is fired when the user clicks the camera icon.
  145. * @memberof InfoBoxViewModel.prototype
  146. * @type {Event}
  147. */
  148. cameraClicked : {
  149. get : function() {
  150. return this._cameraClicked;
  151. }
  152. },
  153. /**
  154. * Gets an {@link Event} that is fired when the user closes the info box.
  155. * @memberof InfoBoxViewModel.prototype
  156. * @type {Event}
  157. */
  158. closeClicked : {
  159. get : function() {
  160. return this._closeClicked;
  161. }
  162. },
  163. /**
  164. * Gets the HTML sanitization function to use for the selection description.
  165. * @memberof InfoBoxViewModel.prototype
  166. * @type {InfoBoxViewModel~Sanitizer}
  167. */
  168. sanitizer : {
  169. get : function() {
  170. return defaultValue(this._sanitizer, InfoBoxViewModel.defaultSanitizer);
  171. },
  172. set : function(value) {
  173. this._sanitizer = value;
  174. //Force resanitization of existing text
  175. var oldHtml = this._descriptionRawHtml;
  176. this._descriptionRawHtml = '';
  177. this.descriptionRawHtml = oldHtml;
  178. }
  179. }
  180. });
  181. /**
  182. * A function that sanitizes HTML from a potentially untrusted source, for display in the
  183. * info box.
  184. * @callback InfoBoxViewModel~Sanitizer
  185. *
  186. * @param {String} rawHTML Raw HTML to display.
  187. * @returns {String|Promise} Sanitized HTML, or a Promise for sanitized HTML.
  188. *
  189. * @see InfoBoxViewModel.defaultSanitizer
  190. */
  191. return InfoBoxViewModel;
  192. });