diff --git a/platform/features/events/src/DomainColumn.js b/platform/features/events/src/DomainColumn.js index c906b45624..5ea23fa804 100644 --- a/platform/features/events/src/DomainColumn.js +++ b/platform/features/events/src/DomainColumn.js @@ -35,6 +35,7 @@ define( * * @memberof platform/features/events * @constructor + * @implements {platform/features/events.EventsColumn} * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` * fields, respectively.) @@ -42,29 +43,21 @@ define( * formatting service, for making values human-readable. */ function DomainColumn(domainMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/events.DomainColumn# - */ - getTitle: function () { - return domainMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/events.DomainColumn# - */ - getValue: function (domainObject, data, index) { - return telemetryFormatter.formatDomainValue( - data.getDomainValue(index, domainMetadata.key) - ); - } - }; + this.domainMetadata = domainMetadata; + this.telemetryFormatter = telemetryFormatter; } + DomainColumn.prototype.getTitle = function () { + return this.domainMetadata.name; + }; + + DomainColumn.prototype.getValue = function (domainObject, data, index) { + var domainKey = this.domainMetadata.key; + return this.telemetryFormatter.formatDomainValue( + data.getDomainValue(index, domainKey) + ); + }; + return DomainColumn; } ); diff --git a/platform/features/events/src/EventListController.js b/platform/features/events/src/EventListController.js index c2247dde8c..dbb76712bd 100644 --- a/platform/features/events/src/EventListController.js +++ b/platform/features/events/src/EventListController.js @@ -135,6 +135,30 @@ define( } return EventListController; + + /** + * A description of how to display a certain column of data in an + * Events view. + * @interface platform/features/events.EventColumn + * @private + */ + /** + * Get the title to display in this column's header. + * @returns {string} the title to display + * @method platform/features/events.EventColumn#getTitle + */ + /** + * Get the text to display inside a row under this + * column. + * @param {DomainObject} domainObject the domain object associated + * with this row + * @param {TelemetrySeries} series the telemetry data associated + * with this row + * @param {number} index the index of the telemetry datum associated + * with this row + * @returns {string} the text to display + * @method platform/features/events.EventColumn#getValue + */ } ); diff --git a/platform/features/events/src/EventListPopulator.js b/platform/features/events/src/EventListPopulator.js index f9581e0890..fca5bea74d 100644 --- a/platform/features/events/src/EventListPopulator.js +++ b/platform/features/events/src/EventListPopulator.js @@ -35,129 +35,130 @@ define( * @param {Column[]} columns the columns to be populated */ function EventListPopulator(columns) { - /* - * Look up the most recent values from a set of data objects. - * Returns an array of objects in the order in which data - * should be displayed; each element is an object with - * two properties: - * - * * objectIndex: The index of the domain object associated - * with the data point to be displayed in that - * row. - * * pointIndex: The index of the data point itself, within - * its data set. - * - * @param {Array} datas an array of the most recent - * data objects; expected to be in the same order - * as the domain objects provided at constructor - * @param {number} count the number of rows to provide - */ - function getLatestDataValues(datas, count) { - var latest = [], - candidate, - candidateTime, - used = datas.map(function () { return 0; }); + this.columns = columns; + } - // This algorithm is O(nk) for n rows and k telemetry elements; - // one O(k) linear search for a max is made for each of n rows. - // This could be done in O(n lg k + k lg k), using a priority - // queue (where priority is max-finding) containing k initial - // values. For n rows, pop the max from the queue and replenish - // the queue with a value from the data at the same - // objectIndex, if available. - // But k is small, so this might not give an observable - // improvement in performance. + /* + * Look up the most recent values from a set of data objects. + * Returns an array of objects in the order in which data + * should be displayed; each element is an object with + * two properties: + * + * * objectIndex: The index of the domain object associated + * with the data point to be displayed in that + * row. + * * pointIndex: The index of the data point itself, within + * its data set. + * + * @param {Array} datas an array of the most recent + * data objects; expected to be in the same order + * as the domain objects provided at constructor + * @param {number} count the number of rows to provide + */ + function getLatestDataValues(datas, count) { + var latest = [], + candidate, + candidateTime, + used = datas.map(function () { return 0; }); - // Find the most recent unused data point (this will be used - // in a loop to find and the N most recent data points) - function findCandidate(data, i) { - var nextTime, - pointCount = data.getPointCount(), - pointIndex = pointCount - used[i] - 1; - if (data && pointIndex >= 0) { - nextTime = data.getDomainValue(pointIndex); - if (nextTime > candidateTime) { - candidateTime = nextTime; - candidate = { - objectIndex: i, - pointIndex: pointIndex - }; - } + // This algorithm is O(nk) for n rows and k telemetry elements; + // one O(k) linear search for a max is made for each of n rows. + // This could be done in O(n lg k + k lg k), using a priority + // queue (where priority is max-finding) containing k initial + // values. For n rows, pop the max from the queue and replenish + // the queue with a value from the data at the same + // objectIndex, if available. + // But k is small, so this might not give an observable + // improvement in performance. + + // Find the most recent unused data point (this will be used + // in a loop to find and the N most recent data points) + function findCandidate(data, i) { + var nextTime, + pointCount = data.getPointCount(), + pointIndex = pointCount - used[i] - 1; + if (data && pointIndex >= 0) { + nextTime = data.getDomainValue(pointIndex); + if (nextTime > candidateTime) { + candidateTime = nextTime; + candidate = { + objectIndex: i, + pointIndex: pointIndex + }; } } - - // Assemble a list of the most recent data points - while (latest.length < count) { - // Reset variables pre-search - candidateTime = Number.NEGATIVE_INFINITY; - candidate = undefined; - - // Linear search for most recent - datas.forEach(findCandidate); - - if (candidate) { - // Record this data point - it is the most recent - latest.push(candidate); - - // Track the data points used so we can look farther back - // in the data set on the next iteration - used[candidate.objectIndex] = used[candidate.objectIndex] + 1; - } else { - // Ran out of candidates; not enough data points - // available to fill all rows. - break; - } - } - - return latest; } + // Assemble a list of the most recent data points + while (latest.length < count) { + // Reset variables pre-search + candidateTime = Number.NEGATIVE_INFINITY; + candidate = undefined; - return { - /** - * Get the text which should appear in headers for the - * provided columns. - * @memberof platform/features/events.EventListPopulator - * @returns {string[]} column headers - */ - getHeaders: function () { - return columns.map(function (column) { - return column.getTitle(); - }); - }, - /** - * Get the contents of rows for the event list view. - * @param {TelemetrySeries[]} datas the data sets - * @param {DomainObject[]} objects the domain objects which - * provided the data sets; these should match - * index-to-index with the `datas` argument - * @param {number} count the number of rows to populate - * @memberof platform/features/events.EventListPopulator - * @returns {string[][]} an array of rows, each of which - * is an array of values which should appear - * in that row - */ - getRows: function (datas, objects, count) { - var values = getLatestDataValues(datas, count); + // Linear search for most recent + datas.forEach(findCandidate); - // Each value will become a row, which will contain - // some value in each column (rendering by the - // column object itself) - // Additionally, we want to display the rows in reverse - // order. (i.e. from the top to the bottom of the page) - return values.map(function (value) { - return columns.map(function (column) { - return column.getValue( - objects[value.objectIndex], - datas[value.objectIndex], - value.pointIndex - ); - }); - }).reverse(); + if (candidate) { + // Record this data point - it is the most recent + latest.push(candidate); + + // Track the data points used so we can look farther back + // in the data set on the next iteration + used[candidate.objectIndex] = used[candidate.objectIndex] + 1; + } else { + // Ran out of candidates; not enough data points + // available to fill all rows. + break; } - }; + } + + return latest; } + /** + * Get the text which should appear in headers for the + * provided columns. + * @memberof platform/features/events.EventListPopulator + * @returns {string[]} column headers + */ + EventListPopulator.prototype.getHeaders = function () { + return this.columns.map(function (column) { + return column.getTitle(); + }); + }; + + /** + * Get the contents of rows for the event list view. + * @param {TelemetrySeries[]} datas the data sets + * @param {DomainObject[]} objects the domain objects which + * provided the data sets; these should match + * index-to-index with the `datas` argument + * @param {number} count the number of rows to populate + * @memberof platform/features/events.EventListPopulator + * @returns {string[][]} an array of rows, each of which + * is an array of values which should appear + * in that row + */ + EventListPopulator.prototype.getRows = function (datas, objects, count) { + var values = getLatestDataValues(datas, count), + columns = this.columns; + + // Each value will become a row, which will contain + // some value in each column (rendering by the + // column object itself) + // Additionally, we want to display the rows in reverse + // order. (i.e. from the top to the bottom of the page) + return values.map(function (value) { + return columns.map(function (column) { + return column.getValue( + objects[value.objectIndex], + datas[value.objectIndex], + value.pointIndex + ); + }); + }).reverse(); + }; + return EventListPopulator; } diff --git a/platform/features/events/src/RangeColumn.js b/platform/features/events/src/RangeColumn.js index 56d9231a01..f31e1d9550 100644 --- a/platform/features/events/src/RangeColumn.js +++ b/platform/features/events/src/RangeColumn.js @@ -35,6 +35,7 @@ define( * * @memberof platform/features/events * @constructor + * @implements {platform/features/events.EventsColumn} * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` * fields, respectively.) @@ -42,29 +43,20 @@ define( * formatting service, for making values human-readable. */ function RangeColumn(rangeMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/events.RangeColumn# - */ - getTitle: function () { - return rangeMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/events.RangeColumn# - */ - getValue: function (domainObject, data, index) { - return telemetryFormatter.formatRangeValue( - data.getRangeValue(index, rangeMetadata.key) - ); - } - }; + this.rangeMetadata = rangeMetadata; + this.telemetryFormatter = telemetryFormatter; } + RangeColumn.prototype.getTitle = function () { + return this.rangeMetadata.name; + }; + RangeColumn.prototype.getValue = function (domainObject, data, index) { + var rangeKey = this.rangeMetadata.key; + return this.telemetryFormatter.formatRangeValue( + data.getRangeValue(index, rangeKey) + ); + }; + return RangeColumn; } ); diff --git a/platform/features/events/src/policies/MessagesViewPolicy.js b/platform/features/events/src/policies/MessagesViewPolicy.js index 1458b9d8eb..712992c0a2 100644 --- a/platform/features/events/src/policies/MessagesViewPolicy.js +++ b/platform/features/events/src/policies/MessagesViewPolicy.js @@ -33,44 +33,35 @@ define( * Policy controlling when the Messages view should be avaliable. * @memberof platform/features/events * @constructor + * @implements {Policy.} */ - function MessagesViewPolicy() { - - function hasStringTelemetry(domainObject) { - var telemetry = domainObject && - domainObject.getCapability('telemetry'), - metadata = telemetry ? telemetry.getMetadata() : {}, - ranges = metadata.ranges || []; + function MessagesViewPolicy() {} - return ranges.some(function (range) { - return range.format === 'string'; - }); - } - return { - /** - * Check whether or not a given action is allowed by this - * policy. - * @param {Action} action the action - * @param domainObject the domain object which will be viewed - * @returns {boolean} true if not disallowed - * @memberof platform/features/events.MessagesViewPolicy# - */ - allow: function (view, domainObject) { - // This policy only applies for the Messages view - if (view.key === 'messages') { - // The Messages view is allowed only if the domain - // object has string telemetry - if (!hasStringTelemetry(domainObject)) { - return false; - } - } - - // Like all policies, allow by default. - return true; - } - }; + function hasStringTelemetry(domainObject) { + var telemetry = domainObject && + domainObject.getCapability('telemetry'), + metadata = telemetry ? telemetry.getMetadata() : {}, + ranges = metadata.ranges || []; + + return ranges.some(function (range) { + return range.format === 'string'; + }); } + MessagesViewPolicy.prototype.allow = function (view, domainObject) { + // This policy only applies for the Messages view + if (view.key === 'messages') { + // The Messages view is allowed only if the domain + // object has string telemetry + if (!hasStringTelemetry(domainObject)) { + return false; + } + } + + // Like all policies, allow by default. + return true; + }; + return MessagesViewPolicy; } );