Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static/js/tracker/tracker-util.js b/static/js/tracker/tracker-util.js
new file mode 100644
index 0000000..040f8c1
--- /dev/null
+++ b/static/js/tracker/tracker-util.js
@@ -0,0 +1,166 @@
+/* Copyright 2016 The Chromium Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+ */
+
+/**
+ * This file contains JS utilities used by other JS files in Monorail.
+ */
+
+
+/**
+ * Add an indexOf method to all arrays, if this brower's JS implementation
+ * does not already have it.
+ * @param {Object} item The item to find
+ * @return {number} The index of the given item, or -1 if not found.
+ */
+if (Array.prototype.indexOf == undefined) {
+ Array.prototype.indexOf = function(item) {
+ for (let i = 0; i < this.length; ++i) {
+ if (this[i] == item) return i;
+ }
+ return -1;
+ };
+}
+
+
+/**
+ * This function works around a FF HTML layout problem. The table
+ * width is somehow rendered at 100% when the table contains a
+ * display:none element, later, when that element is displayed, the
+ * table renders at the correct width. The work-around is to have the
+ * element initiallye displayed so that the table renders properly,
+ * but then immediately hide the element until it is needed.
+ *
+ * TODO(jrobbins): Find HTML markup that FF can render more
+ * consistently. After that, I can remove this hack.
+ */
+function TKR_forceProperTableWidth() {
+ let e = $('confirmarea');
+ if (e) e.style.display='none';
+}
+
+
+function TKR_parseIssueRef(issueRef) {
+ issueRef = issueRef.trim();
+ if (!issueRef) {
+ return null;
+ }
+
+ let projectName = window.CS_env.projectName;
+ let localId = issueRef;
+ if (issueRef.includes(':')) {
+ const parts = issueRef.split(':', 2);
+ projectName = parts[0];
+ localId = parts[1];
+ }
+
+ return {
+ project_name: projectName,
+ local_id: localId};
+}
+
+
+function _buildFieldsForIssueDelta(issueDelta, valuesByName) {
+ issueDelta.field_vals_add = [];
+ issueDelta.field_vals_remove = [];
+ issueDelta.fields_clear = [];
+
+ valuesByName.forEach((values, key, map) => {
+ if (key.startsWith('op_custom_') && values == 'clear') {
+ const field_id = key.substring('op_custom_'.length);
+ issueDelta.fields_clear.push({field_id: field_id});
+ } else if (key.startsWith('custom_')) {
+ const field_id = key.substring('custom_'.length);
+ values = values.filter(Boolean);
+ if (valuesByName.get('op_' + key) === 'remove') {
+ values.forEach((value) => {
+ issueDelta.field_vals_remove.push({
+ field_ref: {field_id: field_id},
+ value: value});
+ });
+ } else {
+ values.forEach((value) => {
+ issueDelta.field_vals_add.push({
+ field_ref: {field_id: field_id},
+ value: value});
+ });
+ }
+ }
+ });
+}
+
+
+function _classifyPlusMinusItems(values) {
+ let result = {
+ add: [],
+ remove: []};
+ values = new Set(values);
+ values.forEach((value) => {
+ if (!value.startsWith('-') && value) {
+ result.add.push(value);
+ } else if (value.startsWith('-') && value.substring(1)) {
+ result.remove.push(value);
+ }
+ });
+ return result;
+}
+
+
+function TKR_buildIssueDelta(valuesByName) {
+ let issueDelta = {};
+
+ if (valuesByName.has('status')) {
+ issueDelta.status = valuesByName.get('status')[0];
+ }
+ if (valuesByName.has('owner')) {
+ issueDelta.owner_ref = {
+ display_name: valuesByName.get('owner')[0].trim().toLowerCase()};
+ }
+ if (valuesByName.has('cc')) {
+ const cc_usernames = _classifyPlusMinusItems(
+ valuesByName.get('cc')[0].toLowerCase().split(/[,;\s]+/));
+ issueDelta.cc_refs_add = cc_usernames.add.map(
+ (email) => ({display_name: email}));
+ issueDelta.cc_refs_remove = cc_usernames.remove.map(
+ (email) => ({display_name: email}));
+ }
+ if (valuesByName.has('components')) {
+ const components = _classifyPlusMinusItems(
+ valuesByName.get('components')[0].split(/[,;\s]/));
+ issueDelta.comp_refs_add = components.add.map(
+ (path) => ({path: path}));
+ issueDelta.comp_refs_remove = components.remove.map(
+ (path) => ({path: path}));
+ }
+ if (valuesByName.has('label')) {
+ const labels = _classifyPlusMinusItems(valuesByName.get('label'));
+ issueDelta.label_refs_add = labels.add.map(
+ (label) => ({label: label}));
+ issueDelta.label_refs_remove = labels.remove.map(
+ (label) => ({label: label}));
+ }
+ if (valuesByName.has('blocked_on')) {
+ const blockedOn = _classifyPlusMinusItems(valuesByName.get('blocked_on'));
+ issueDelta.blocked_on_refs_add = blockedOn.add.map(TKR_parseIssueRef);
+ issueDelta.blocked_on_refs_add = blockedOn.remove.map(TKR_parseIssueRef);
+ }
+ if (valuesByName.has('blocking')) {
+ const blocking = _classifyPlusMinusItems(valuesByName.get('blocking'));
+ issueDelta.blocking_refs_add = blocking.add.map(TKR_parseIssueRef);
+ issueDelta.blocking_refs_add = blocking.remove.map(TKR_parseIssueRef);
+ }
+ if (valuesByName.has('merge_into')) {
+ issueDelta.merged_into_ref = TKR_parseIssueRef(
+ valuesByName.get('merge_into')[0]);
+ }
+ if (valuesByName.has('summary')) {
+ issueDelta.summary = valuesByName.get('summary')[0];
+ }
+
+ _buildFieldsForIssueDelta(issueDelta, valuesByName);
+
+ return issueDelta;
+}