/*global define*/ define([ '../../Core/defaultValue', '../../Core/defined', '../../Core/defineProperties', '../../Core/Event', '../../Core/formatError', '../../Core/TaskProcessor', '../../ThirdParty/knockout', '../../ThirdParty/when' ], function( defaultValue, defined, defineProperties, Event, formatError, TaskProcessor, knockout, when) { "use strict"; 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'; 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'; /** * The view model for {@link InfoBox}. * @alias InfoBoxViewModel * @constructor */ var InfoBoxViewModel = function() { this._sanitizer = undefined; this._descriptionRawHtml = ''; this._descriptionSanitizedHtml = ''; this._cameraClicked = new Event(); this._closeClicked = new Event(); /** * Gets or sets the maximum height of the info box in pixels. This property is observable. * @type {Number} */ this.maxHeight = 500; /** * Gets or sets whether the camera tracking icon is enabled. * @type {Boolean} */ this.enableCamera = false; /** * Gets or sets the status of current camera tracking of the selected object. * @type {Boolean} */ this.isCameraTracking = false; /** * Gets or sets the visibility of the info box. * @type {Boolean} */ this.showInfo = false; /** * Gets or sets the title text in the info box. * @type {String} */ this.titleText = ''; /** * Gets or sets the HTML for the loading indicator during sanitization of the raw description. * @type {String} */ this.loadingIndicatorHtml = '
'; knockout.track(this, ['showInfo', 'titleText', '_descriptionRawHtml', '_descriptionSanitizedHtml', 'maxHeight', 'enableCamera', 'isCameraTracking']); /** * Gets or sets the un-sanitized description HTML for the info box. * @type {String} */ this.descriptionRawHtml = undefined; knockout.defineProperty(this, 'descriptionRawHtml', { get : function() { return this._descriptionRawHtml; }, set : function(value) { if (this._descriptionRawHtml !== value) { this._descriptionRawHtml = value; this._descriptionSanitizedHtml = this.loadingIndicatorHtml; var that = this; when(this.sanitizer(value), function(sanitized) { // make sure the raw HTML still matches the input we sanitized, // in case it was changed again while we were sanitizing. if (that._descriptionRawHtml === value) { that._descriptionSanitizedHtml = sanitized; } }).otherwise(function(error) { /*global console*/ console.log('An error occurred while sanitizing HTML: ' + formatError(error)); }); } } }); /** * Gets the sanitized description HTML for the info box. * @type {String} */ this.descriptionSanitizedHtml = undefined; knockout.defineProperty(this, 'descriptionSanitizedHtml', { get : function() { return this._descriptionSanitizedHtml; } }); /** * Gets the SVG path of the camera icon, which can change to be "crossed out" or not. * @type {String} */ this.cameraIconPath = undefined; knockout.defineProperty(this, 'cameraIconPath', { get : function() { return (this.enableCamera || this.isCameraTracking) ? cameraEnabledPath : cameraDisabledPath; } }); knockout.defineProperty(this, '_bodyless', { get : function() { return !this._descriptionSanitizedHtml; } }); }; /** * Gets the maximum height of sections within the info box, minus an offset, in CSS-ready form. * @param {Number} offset The offset in pixels. * @returns {String} */ InfoBoxViewModel.prototype.maxHeightOffset = function(offset) { return (this.maxHeight - offset) + 'px'; }; var sanitizerTaskProcessor; function defaultSanitizer(html) { if (!defined(sanitizerTaskProcessor)) { sanitizerTaskProcessor = new TaskProcessor('sanitizeHtml', Infinity); } return sanitizerTaskProcessor.scheduleTask(html); } /** * Gets or sets the default HTML sanitization function to use for all instances. * By default, the Google Caja HTML/CSS sanitizer is loaded in a worker. * A specific instance can override this property by setting its sanitizer property. * * @member * @type {InfoBoxViewModel~Sanitizer} */ InfoBoxViewModel.defaultSanitizer = defaultSanitizer; defineProperties(InfoBoxViewModel.prototype, { /** * Gets an {@link Event} that is fired when the user clicks the camera icon. * @memberof InfoBoxViewModel.prototype * @type {Event} */ cameraClicked : { get : function() { return this._cameraClicked; } }, /** * Gets an {@link Event} that is fired when the user closes the info box. * @memberof InfoBoxViewModel.prototype * @type {Event} */ closeClicked : { get : function() { return this._closeClicked; } }, /** * Gets the HTML sanitization function to use for the selection description. * @memberof InfoBoxViewModel.prototype * @type {InfoBoxViewModel~Sanitizer} */ sanitizer : { get : function() { return defaultValue(this._sanitizer, InfoBoxViewModel.defaultSanitizer); }, set : function(value) { this._sanitizer = value; //Force resanitization of existing text var oldHtml = this._descriptionRawHtml; this._descriptionRawHtml = ''; this.descriptionRawHtml = oldHtml; } } }); /** * A function that sanitizes HTML from a potentially untrusted source, for display in the * info box. * @callback InfoBoxViewModel~Sanitizer * * @param {String} rawHTML Raw HTML to display. * @returns {String|Promise} Sanitized HTML, or a Promise for sanitized HTML. * * @see InfoBoxViewModel.defaultSanitizer */ return InfoBoxViewModel; });