Odyssey
cuissues_edit.prg
1 <?php
2 // File: cuissues_edit.v2 (partially replaces cuissues_report)
3 // This file expands the edit form to be better suited for the workflow design.
4 // SPB 10/6/2015-- Replaced previous cuissues_report for kendo upgrade and billing workflow expansion.
5 
6 $monLibrary = dirname(__FILE__) . "/../library";
7 $sharedLibrary = dirname(__FILE__) . "/../../shared/library";
8 require_once("$monLibrary/cu_top.i");
9 require_once("$monLibrary/ck_hticket.i");
10 require_once("$monLibrary/monitorView.i");
11 require_once("$sharedLibrary/commonJsFunctions.i");
12 
13  if (!CheckPerm($link, $Hu, basename($_SERVER['SCRIPT_NAME']), $_SERVER['REMOTE_ADDR'])) {
14  // ** Permissions failed
15  // ** redirect to new page
16  header("Location: /hcuadm/hcu_noperm.prg");
17  exit;
18  }
19 
20 // Globals
21 $listFile = "cuissues_report.prg";
22 $editFile = "cuissues_edit.prg";
23 $dataFile = "cuissues_data.prg";
24 
25 dms_import_v2($DATA_PARAMETERS, "TOP_LEVEL", array("user_name" => "string", "trackId" => "digits", "trackItemId" => "digits"));
26 $cu = trim($DATA_PARAMETERS["TOP_LEVEL"]["user_name"]);
27 $trackId = intval($DATA_PARAMETERS["TOP_LEVEL"]["trackId"]);
28 $trackItemId = intval($DATA_PARAMETERS["TOP_LEVEL"]["trackItemId"]);
29 
30 $backURL = "/hcuadm/$listFile";
31 if ($cu != "") {
32  $backURL .= "?user_name=$cu";
33 }
34 
35 $refreshURL = "/hcuadm/$editFile?";
36 if ($cu != "") {
37  $refreshURL .= "user_name=$cu";
38 }
39 
40 if ($trackId == 0) {
41  $saveURL = "/hcuadm/$dataFile?operation=saveIssueAdd";
42 } else {
43  $saveURL = "/hcuadm/$dataFile?operation=saveIssueEdit";
44 }
45 
46 $todayDateTime = new DateTime();
47 $today = $todayDateTime->format("m/d/Y");
48 
49 printMonitorPageTop("CU Job Tracking", $homecuKendoVersion, $cloudfrontDomainName);
50 ?>
51 
52 <style>
53  .popupForm .grid_12, .formContainer .grid_12 {
54  margin-bottom: 5px;
55  }
56 
57  fieldset {
58  border: 1px solid #cccccc;
59  border-radius: 10px;
60  margin: 5px;
61  vertical-align: top;
62  display: inline;
63  }
64 
65  #issueDiv {
66  width: 500px;
67  }
68 
69  #cuDiv {
70  width: 300px;
71  }
72 
73  #contactDiv, #oldCommentDiv {
74  width: 300px;
75  }
76 
77  #commentDiv {
78  width: 99%;
79  height: 200px;
80  overflow: auto;
81  }
82 
83  .otherFieldsets {
84  height: 200px;
85  }
86 
87  .otherFieldsets .grid_12 {
88  margin-top: 5px;
89  }
90 
91  legend {
92  padding: 5px;
93  }
94 
95  #commentsGrid .k-grid-delete {
96  min-width: 0px !important;
97  }
98 
99  #dateGroup {
100  width: 400px;
101  padding: 5px;
102  }
103 
104  #contactGroup, #topGroup {
105  width: 500px;
106  }
107 
108  #topGroup {
109  border: 0px solid black;
110  border-radius: 10px;
111  }
112 
113  #currentStatus {
114  position: fixed;
115  right: 20px;
116  top: 50px;
117  width: 250px;
118  padding: 10px;
119  z-index: 99;
120  }
121 
122  #btnDiv {
123  margin-top: 5px;
124  }
125 
126  #currentStatus, #currentStatus a {
127  display: block;
128  }
129 
130  #changesMadeLabel .top {
131  font-weight: bold;
132  display: block;
133  }
134 
135  #changesMadeLabel .bottom {
136  list-style:upper-roman inside none;
137  display:list-item;
138  margin-left: 5px;
139  }
140 
141  .k-context-menu .k-item, .k-context-menu {
142  width: 150px !important;
143  }
144 
145  .moveUnderLi ul, .moveUnderLi ul .k-item {
146  width: 300px !important;
147  text-overflow: ellipsis;
148  }
149 
150  .taskCommentPopupCircle.on {
151  background-color: blue;
152  border-radius: 5px;
153  width: 10px;
154  height: 10px;
155  }
156 
157  .taskCommentPopupCircle.off {
158  display:none;
159  }
160 
161  #taskCommentGrid .k-grid-header, .detailGrid .k-grid-header, #commentsGrid .k-grid-header {
162  display: none;
163  }
164 
165  .k-notification {
166  text-align: left;
167 
168  width: 350px;
169  }
170 
171  .k-notification-wrap {
172  white-space: normal !important;
173  text-overflow: ellipsis;
174  overflow: auto;
175  }
176 
177  #tasksGrid .k-detail-cell {
178  padding-left: 0px;
179  padding-right: 0px;
180  }
181 
182  .k-edit-form-container {
183  width: auto !important;
184  }
185 
186  #tasksGrid .k-grid-content tr, #commentsGrid .k-grid-content tr {
187  cursor: context-menu;
188  }
189 
190  #oldComments {
191  width: 96%;
192  height: 100px;
193  margin-left: 5px;
194  border-width: 0px;
195  background-color: #eeeeee;
196  }
197 
198  #taskContextMenu .k-link {
199  text-overflow: ellipsis;
200  overflow: auto;
201  }
202 </style>
203 
204 <script type="text/javascript">
205 
206 <?php
207 // Include common functions
208 getErrorsAreShownFunction();
209 getSetupDeleteConfirmDialogFunction();
210 getEscapeHTMLFunction();
211 getShowWaitFunctions();
212 getAddMinifiedActionStyleFunction();
213 getUseValidatorInGridFunction();
214 getSetupValidatorInGridFunction();
215 ?>
216 
217 <?php // Initializes a dialog for when completing an issue and there are still open tasks assigned to it. ?>
218 function OpenCompleteConfirm() {
219  var completeConfirm = $("#completeConfirmDialog").data("kendoWindow");
220  var statusDDL = $("#statusDDL").data("kendoDropDownList");
221 
222  if (completeConfirm == null) {
223  var completeConfirm = $("<div id='completeConfirmDialog'></div>").kendoWindow({
224  content: {template: $("#confirmCompleteTemplate").html()},
225  draggable: false,
226  visible: false,
227  actions: [],
228  modal: true,
229  title: "Confirm Completion",
230  width: 400,
231  resizable: false
232  }).data("kendoWindow");
233 
234  $("#completeConfirmDialog .okayBtn").click(function () {
235  ShowChanges("status", "Completed");
236  changed.changedStatus = "Y";
237 
238  completeConfirm.close();
239  return false;
240  });
241 
242  $("#completeConfirmDialog .cancelBtn").click(function () {
243  statusDDL.value(statusDDL.previousValue);
244 
245  completeConfirm.close();
246  return false;
247  });
248  }
249 
250  completeConfirm.open().center();
251 }
252 
253 
254 <?php // Initializes the whole page. ?>
255 function InitPage() {
256  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
257  var unattachedFeatureDetailsDDL = [];
258 
259  $("#mainForm").submit(function (e) {
260  e.preventDefault();
261  return false;
262  });
263 
264  var targetDatePicker = $("#targetDatePicker").kendoDatePicker({
265  change: function() {
266  ShowChanges("targetDate", kendo.toString(this.value(), "yyyy-MM-dd"));
267  changed.targetDateChanged = "Y";
268  changed.targetDateType = "";
269  }
270  }).data("kendoDatePicker");
271 
272  var dropDeadDatePicker = $("#dropDeadDatePicker").kendoDatePicker({
273  change: function() {
274  ShowChanges("dropDeadDate", kendo.toString(this.value(), "yyyy-MM-dd"));
275  changed.changedDropDeadDate = "Y";
276  }
277  }).data("kendoDatePicker");
278 
279  $("[name='targetDateType']").click(function () {
280  if ($(this).val() == "") {
281  targetDatePicker.enable(true);
282  $("#targetDatePicker").prop("required", true);
283  } else {
284  targetDatePicker.enable(false);
285  targetDatePicker.value(null);
286  $("#targetDatePicker").prop("required", false);
287  $(".k-invalid-msg[data-for='targetDate']").hide();
288  }
289 
290  ShowChanges("targetDate", null);
291  changed.targetDateChanged = "Y";
292  changed.targetDateType = $(this).val();
293  });
294 
295  var issueOwnerDDL = $("#issueOwnerDDL").kendoDropDownList({
296  dataSource: {
297  data:[],
298  schema: {
299  model: {
300  id: "value",
301  fields: {
302  value: {type: "string"},
303  text: {type: "string"},
304  filterNumber: {type: "number"}
305  }
306  }
307  },
308  filter: {field: "filterNumber", operator: "eq", value: 0}
309  },
310  dataTextField: "text",
311  dataValueField: "value",
312  filter: "startswith",
313  change: function() {
314  ShowChanges("owner", this.value());
315  changed.changedOwner = "Y";
316  }
317  }).data("kendoDropDownList");
318 
319  var statusDDL = $("#statusDDL").kendoDropDownList({
320  dataSource: {
321  data: [],
322  schema: {
323  id: "value",
324  fields: {
325  value: {type: "string"},
326  currentStatus: {type: "string"}
327  }
328  }
329  },
330  dataTextField: "value",
331  dataValueField: "value",
332  filter: "startswith",
333  change: function() {
334 
335  if (this.value() == "Completed") {
336  var taskData = $("#tasksGrid").data("kendoGrid").dataSource.data();
337  var hasIncompleteTasks = false;
338  for(var i = 0; i != taskData.length; i++) {
339  if (taskData[i].completedOn == null && taskData[i].statusId != 2) {
340  hasIncompleteTasks = true;
341  break;
342  }
343  }
344 
345  if (hasIncompleteTasks) {
346  OpenCompleteConfirm();
347  } else {
348  ShowChanges("status", this.value());
349  changed.changedStatus = "Y";
350  this.previousValue = this.value();
351  }
352  } else {
353  ShowChanges("status", this.value());
354  changed.changedStatus = "Y";
355  this.previousValue = this.value();
356  }
357  }
358  }).data("kendoDropDownList");
359 
360  var contactDDL = $("#contactDDL").kendoDropDownList({
361  dataSource: {
362  data: [],
363  schema: {
364  model: {
365  id: "contactId",
366  fields: {
367  contactId: {type: "string"},
368  text: {type: "string"},
369  fullName: {type: "string"},
370  email: {type: "string"},
371  phone: {type: "string"},
372  cu: {type: "string"},
373  sortNumber: {type: "number"}
374  }
375  }
376  },
377  sort: [{field: "sortNumber", dir: "asc"}, {field: "text", dir: "asc"}]
378  },
379  dataTextField: "text",
380  dataValueField: "contactId",
381  change: function () {
382  var dataItem = this.dataItem();
383 
384  if (dataItem.text == "SPECIAL") {
385  $("#contactName").text(dataItem.fullName);
386  $("#contactNameRow").show();
387  } else {
388  $("#contactNameRow").hide();
389  }
390  $("#contactPhone").text(dataItem.phone);
391  $("#contactEmail").text(dataItem.email);
392  ShowChanges("contactId", this.value());
393  changed.changedContactId = "Y";
394 
395  if (this.text() == "NEW") {
396  isSpecial = false;
397  OpenContactPopup();
398  } else if (this.text() == "SPECIAL") {
399  isSpecial = true;
400  OpenContactPopup();
401  } else {
402  this.previousValue = this.value();
403  }
404  }
405  }).data("kendoDropDownList");
406 
407  var filterDefinition = {
408  logic: "or",
409  filters: [
410  {field: "cu", operator: "eq", value: ""},
411  {field: "cu", operator: "eq", value: "<?php echo $cu; ?>"}
412  ]
413  };
414 
415  $("#issue").blur(function () {
416  ShowChanges("job", $(this).val());
417  changed.changedIssue = "Y";
418  });
419 
420  <?php if ($trackId == 0) { // If we are adding an issue, we will still need to get the data for the DDLs. ?>
421  $("#issueNumber").text("NEW");
422 
423  var menu = $("#topMenuBar").data("kendoMenu");
424 
425  $("#changesMenuItem").addClass("k-info-colored");
426  $("#changesMenuItem span").html("NEW job");
427  menu.enable("#saveMenuItem", true);
428 
429  var today = kendo.toString(new Date(), "MM/dd/yyyy");
430  $("#enteredDate").text(today);
431  $("#lastActivityDate").text(today);
432  $("#completedDate").text("N/A");
433 
434  showWaitWindow();
435  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=readIssueAdd", {cu: "<?php echo $cu; ?>"}, function (data) {
436  hideWaitWindow();
437  if (!errorsAreShown(data, "formValidateMainDiv")) {
438  issueOwnerDDL.dataSource.data(data.ownerDDL);
439  statusDDL.dataSource.data(data.statusDDL);
440 
441  // Force new status
442  statusDDL.enable(false);
443  issueOwnerDDL.value("<?php echo $Hu; ?>");
444  $("#currentIssueStatus").text("Active");
445 
446  contactDDL.dataSource.data(data.contactDDL);
447  contactDDL.previousValue = data.contactDDL;
448  SetupContactPopup(data.roleDDL, contactDDL);
449 
450  <?php if ($cu != "") { // For now, let's assume that if there is a CU, then issue is from the CU index versus the report page. ?>
451  $("#cu").text("<?php echo $cu; ?>");
452 
453  var dataItem = $.grep(data.cuDDL, function(n,i) {return n.value == "<?php echo $cu; ?>"})[0];
454  $("#cu").click(function() {
455  window.open("/hcuadm/cuindex.prg?action=fetch&rowid=" + dataItem.value.toLowerCase() + "&vc=" + dataItem.vendor + "&wc=" + dataItem.server);
456  return false;
457  });
458  $("#cuDDL").text(data.cuName);
459  $("#cuName").text(data.cuName);
460  contactDDL.dataSource.filter(filterDefinition);
461  contactDDL.select(0);
462  unattachedFeatureDetailsDDL = $.grep(data.unattachedFeatureDetailsDDL, function(n,i) {
463  return n.cu == "" || n.cu.toLowerCase() == $("#cu").text().toLowerCase();
464  });
465  AddAssociateBillingIdDDL(0, "Active", unattachedFeatureDetailsDDL);
466  <?php } else { ?>
467  var fullUnattachedFeatureDetailsDDL = data.unattachedFeatureDetailsDDL;
468  var fromBillingDDL = null;
469  var cuDDL = $("#cuDDL").kendoDropDownList({
470  dataSource: {
471  data: data.cuDDL,
472  schema: {
473  model: {
474  id: "value",
475  fields: {
476  value: {type: "string"},
477  text: {type: "string"},
478  server: {type: "string"},
479  vendor: {type: "string"}
480  }
481  }
482  }
483  },
484  dataTextField: "text",
485  dataValueField: "value",
486  filter: "startswith",
487  dataBound: function () {
488  filterDefinition.filters[1].value = this.value();
489  contactDDL.dataSource.filter(filterDefinition);
490  contactDDL.select(0);
491  var dataItem = contactDDL.dataItem();
492  $("#contactPhone").text(dataItem.phone);
493  $("#contactEmail").text(dataItem.email);
494  $("#cu").text(this.value());
495  $("#cuName").text(this.text());
496  unattachedFeatureDetailsDDL = $.grep(fullUnattachedFeatureDetailsDDL, function(n,i) {
497  return n.cu == "" || n.cu.toLowerCase() == $("#cu").text().toLowerCase();
498  });
499  AddAssociateBillingIdDDL(0, "Active", unattachedFeatureDetailsDDL);
500  fromBillingDDL = $("#fromBilling div").data("kendoDropDownList");
501  },
502  change: function () {
503  filterDefinition.filters[1].value = this.value();
504  contactDDL.dataSource.filter(filterDefinition);
505  contactDDL.select(0);
506  var dataItem = contactDDL.dataItem();
507  $("#contactPhone").text(dataItem.phone);
508  $("#contactEmail").text(dataItem.email);
509  $("#cu").text(this.value());
510  $("#cuName").text(this.text());
511  unattachedFeatureDetailsDDL = $.grep(fullUnattachedFeatureDetailsDDL, function(n,i) {
512  return n.cu == "" || n.cu.toLowerCase() == $("#cu").text().toLowerCase();
513  });
514  fromBillingDDL.dataSource.data(unattachedFeatureDetailsDDL);
515  fromBillingDDL.select(0);
516  }
517  }).data("kendoDropDownList");
518 
519  $("#cu").click(function() {
520  var dataItem = cuDDL.dataItem();
521  window.open("/hcuadm/cuindex.prg?action=fetch&rowid=" + dataItem.value.toLowerCase() + "&vc=" + dataItem.vendor + "&wc=" + dataItem.server);
522  return false;
523  });
524  <?php } ?>
525 
526  $("#oldCommentDiv textarea").hide();
527  $("#oldCommentDiv div").show();
528  InitComments("#commentsGrid");
529  $("#fromTemplate").text("No");
530  $("#billed").text("No");
531  }
532  });
533 
534  <?php } else { ?>
535  $("#issueNumber").text("<?php echo $trackId; ?>");
536 
537  showWaitWindow();
538  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=readIssueEdit", {trackId: "<?php echo $trackId; ?>"}, function(data) {
539  hideWaitWindow();
540  if (!errorsAreShown(data, "formValidateMainDiv")) {
541  $("#creditUnion input").val(data.record.cuName);
542 
543  if (data.record.targetDateType != "") {
544  if (data.record.targetDateType == "TBD") {
545  $("[name='targetDateType']:eq(1)").prop("checked", true);
546  } else if (data.record.targetDateType == "FLEX") {
547  $("[name='targetDateType']:eq(2)").prop("checked", true);
548  }
549  $("#targetDate").prop("required", false);
550  targetDatePicker.enable(false);
551  } else {
552  $("[name='targetDateType']:eq(0)").prop("checked", true);
553  $("#targetDate").prop("required", true);
554  targetDatePicker.enable(true);
555  }
556 
557  if (data.record.targetDate != "") {
558  var parts = data.record.targetDate.split("-");
559  targetDatePicker.value(new Date(parts[0], parts[1] - 1, parts[2]));
560  // new Date("2015-10-09") becomes 10/08/2015 18:00 on Chrome; new Date("10/09/2015") is different on Chrome and Firefox.
561  }
562 
563  if (data.record.dropDeadDate != "") {
564  var parts = data.record.dropDeadDate.split("-");
565  dropDeadDatePicker.value(new Date(parts[0], parts[1] - 1, parts[2]));
566  // new Date("2015-10-09") becomes 10/08/2015 18:00 on Chrome; new Date("10/09/2015") is different on Chrome and Firefox.
567  }
568 
569 
570  if (data.record.enteredOn == "") {
571  $("#enteredDate").text("Not Recorded");
572  } else {
573  var parts = data.record.enteredOn.split("-");
574  $("#enteredDate").text(kendo.toString(new Date(parts[0], parts[1] - 1, parts[2]), "MM/dd/yyyy"));
575  }
576 
577 
578  if (data.record.lastActivity == "") {
579  $("#lastActivityDate").text("Not Recorded");
580  } else {
581  var parts = data.record.lastActivity.split("-");
582  $("#lastActivityDate").text(kendo.toString(new Date(parts[0], parts[1] - 1, parts[2]), "MM/dd/yyyy"));
583  }
584 
585 
586  if (data.record.completedOn == "") {
587  $("#completedDate").text("N/A");
588  } else {
589  var parts = data.record.completedOn.split("-");
590  $("#completedDate").text(kendo.toString(new Date(parts[0], parts[1] - 1, parts[2]), "MM/dd/yyyy"));
591  }
592 
593  $("#cuDDL").text(data.record.cuName);
594  $("#cu").text(data.record.cu);
595  $("#cuName").text(data.record.cuName);
596  $("#cuServer").text(data.record.server);
597 
598  $("#cu").click(function() {
599  window.open("/hcuadm/cuindex.prg?action=fetch&rowid="+data.record.cu.toLowerCase() + "&vc=" + data.record.vendor + "&wc=" + data.record.server);
600  return false;
601  });
602 
603  statusDDL.dataSource.data(data.statusDDL);
604 
605  contactDDL.dataSource.data(data.contactDDL);
606  filterDefinition.filters[1].value = data.record.cu;
607  contactDDL.dataSource.filter(filterDefinition);
608 
609  if (data.selectSpecial) {
610  contactDDL.value("-1");
611  $("#contactName").text(data.record.contactName);
612  $("#contactNameRow").show();
613  } else if (data.record.contactId == "") {
614  contactDDL.select(0);
615  } else {
616  contactDDL.value(data.record.contactId);
617  }
618  contactDDL.previousValue = data.record.contactId;
619  SetupContactPopup(data.roleDDL, contactDDL);
620 
621  $("#currentIssueOwner").text(data.record.issueOwner);
622 
623  if (data.record.issueOwner.toLowerCase() == "<?php echo strtolower($Hu); ?>" || data.record.issueOwner == "") {
624  issueOwnerDDL.dataSource.data(data.ownerDDL);
625  issueOwnerDDL.value(data.record.issueOwner);
626  } else {
627  issueOwnerDDL.destroy();
628  $("#issueOwnerDiv").remove();
629  $("#currentIssueOwner").show();
630  }
631 
632  statusDDL.value(data.record.status);
633  statusDDL.dataSource.filter({field: "currentStatus", operator: "eq", value: data.record.status});
634  if (statusDDL.dataSource.view().length == 0) {
635  statusDDL.dataSource.filter({field: "currentStatus", operator: "eq", value: "Unrecognized"});
636  statusDDL.value("Unrecognized");
637  statusDDL.previousValue = "Unrecognized";
638  $("#currentIssueStatus").text("Unrecognized");
639  } else {
640  statusDDL.previousValue = data.record.status;
641  $("#currentIssueStatus").text(data.record.status);
642  }
643 
644  var dataItem = contactDDL.dataItem();
645  if (dataItem != null) {
646  $("#contactPhone").text(dataItem.phone);
647  $("#contactEmail").text(dataItem.email);
648  } else {
649  contactDDL.select(0);
650  }
651 
652  $("#issue").val(data.record.issue);
653 
654  commentData = data.comments;
655  InitComments("#commentsGrid");
656 
657  if (data.record.oldComments.trim() == "") {
658  $("#oldCommentDiv textarea").hide();
659  $("#oldCommentDiv div").show();
660  } else {
661  $("#oldComments").val(data.record.oldComments);
662  }
663 
664  var templateId = Number(data.record.templateId);
665  var billingFeatureId = Number(data.record.billingFeatureId);
666  $("#billingExists").text(Number(data.record.testId) == 0 ? "N" : "Y");
667  $("#fromTemplate").text(templateId == 0 ? "No" : "Yes");
668  $("#templateId").text(templateId);
669  $("#billed").text(data.record.billed == "Y" ? "Yes" : "No");
670  unattachedFeatureDetailsDDL= $.grep(data.unattachedFeatureDetailsDDL, function(n,i){
671  return n.cu == "" || n.cu.toLowerCase() == data.record.cu.toLowerCase();
672  });
673  AddAssociateBillingIdDDL(data.record.billingFeatureId, data.record.status, unattachedFeatureDetailsDDL);
674  InitTasks(data.ownerDDL, data.taskStatusDDL, data.comments);
675  }
676 
677  });
678  <?php } ?>
679 
680  $("#pageUpdateBtn").click(function () {
681  UpdatePage(true, unattachedFeatureDetailsDDL);
682  return false;
683  });
684 
685  $("#pageContinueBtn").click(function () {
686  UpdatePage(false, unattachedFeatureDetailsDDL);
687  return false;
688  });
689 
690  $("#pageCancelBtn").click(function () {
691  showWaitWindow();
692  window.location.href = "<?php echo $backURL; ?>";
693  return false;
694  });
695 }
696 
697 function AddAssociateBillingIdDDL(billingFeatureId, status, ddlData) {
698  var billingFeatureExists= $("#billingExists").text() == "Y";
699  if ((billingFeatureId != null && billingFeatureId != 0) || status == "Deleted") {
700  var fromBillingDDL = $("#fromBilling div").data("kendoDropDownList");
701  if (fromBillingDDL != null) {
702  fromBillingDDL.destroy();
703  }
704  $("#fromBilling").html(status == "Deleted" ? "No" : (billingFeatureExists ? "Yes" : "Feature doesn't exist"));
705  } else {
706  $("#fromBilling").empty();
707  $("#fromBilling").append("<div style='width:100%'></div>");
708  var fromBillingDDL = $("#fromBilling div").kendoDropDownList({
709  dataSource: {
710  data: ddlData,
711  schema: {
712  model: {
713  id: "value",
714  fields: {
715  value: {type: "string"},
716  text: {type: "string"},
717  cu: {type: "string"}
718  }
719  }
720  }
721  },
722  dataTextField: "text",
723  dataValueField: "value",
724  filter: "startswith",
725  change: function () {
726  ShowChanges("billingFeatureId", this.value());
727  }
728  }).data("kendoDropDownList");
729  fromBillingDDL.select(0);
730  }
731 }
732 
733 <?php // This will add whatever was changed to the list of things that were changed. This will also enable the save and save and return buttons. ?>
734 var changed = {};
735 function ShowChanges(key, value) {
736  <?php if ($trackId != 0) { ?>
737  var menu = $("#topMenuBar").data("kendoMenu");
738  if (["No Changes", "Changes were saved"].indexOf($("#changesMenuItem").text().trim()) != -1) {
739  $("#changesMenuItem").addClass("k-info-colored");
740  $("#changesMenuItem").removeClass("k-success-colored");
741  $("#changesMenuItem span").html("There are <span id='numChanges'>1</span> Changes");
742  menu.enable("#saveMenuItem", true);
743  }
744 
745  if (typeof(changed[key]) == "undefined") { // Add it to the list
746  menu.append({text: key, cssClass: "changedList"}, $("#changesMenuItem"));
747  }
748 
749  $("#numChanges").text($(".changedList").length);
750 
751  changed[key] = value;
752  <?php } ?>
753 }
754 
755 <?php // Prepares the page for saving and then does it. ?>
756 function UpdatePage(stayOnPage, ddlData) {
757  $.homecuValidator.validate();
758  if ($("#formValidateMainDiv li:visible").length == 0) {
759 
760  <?php if ($trackId == 0) { ?>
761  var parameters = {};
762  if ($("#targetDatePicker").data("kendoDatePicker").value() != null) {
763  parameters.targetDate = kendo.toString(new Date($("#targetDatePicker").data("kendoDatePicker").value()), "yyyy-MM-dd");
764  }
765  parameters.targetDateType = $("[name='targetDateType']:checked").val();
766  parameters.owner = $("#issueOwnerDDL").data("kendoDropDownList").value();
767  parameters.contactId = $("#contactDDL").data("kendoDropDownList").value();
768  parameters.contactName = $("#contactName").text();
769  parameters.contactPhone = $("#contactPhone").text();
770  parameters.contactEmail = $("#contactEmail").text();
771  parameters.comments = "";
772  <?php } else { ?>
773  var parameters = changed;
774  parameters.trackId = <?php echo intval($trackId); ?>;
775  parameters.owner = $("#currentIssueOwner").is(":visible") ? $("#currentIssueOwner").text() : $("#issueOwnerDDL").data("kendoDropDownList").value();
776  <?php } ?>
777  parameters.deletedCommentIds = kendo.stringify(deletedIds);
778  parameters.issue = $("#issue").val();
779  parameters.status = $("#statusDDL").data("kendoDropDownList").value();
780  parameters.cu = $("#cu").text(); // So it doesn't matter if it is set or if it is from the combobox.
781  parameters.cuName = $("#cuName").text();
782 
783  if (typeof(parameters.comments) != "undefined") {
784  var data = $("#commentsGrid").data("kendoGrid").dataSource.data();
785  var comments = [];
786  for (var i = 0; i != data.length; i++) {
787  if (typeof(data[i].thisRowDirty) != "undefined" && data[i].thisRowDirty) {
788  comments.push({commentId: data[i].commentId, subject: data[i].subject, text: data[i].text});
789  }
790  }
791  parameters.comments = kendo.stringify(comments);
792  }
793 
794  showWaitWindow();
795  $.post("<?php echo $saveURL; ?>", parameters, function (data) {
796  hideWaitWindow();
797  if (!errorsAreShown(data, "formValidateMainDiv")) {
798  if (!stayOnPage) {
799  showWaitWindow();
800  window.location.href = "<?php echo $backURL; ?>";
801  }
802  <?php if ($trackId == 0) { // If saving from a new issue, refreshing is necessary for functions that are only available to editing an issue. ?>
803  showWaitWindow();
804  window.location.href = "<?php echo $refreshURL; ?>&trackId=" + data.trackId;
805  <?php } else { ?>
806  $("#changesMenuItem").html('<span class="k-link">Changes were saved</span>');
807  $("#changesMenuItem").removeClass("k-info-colored");
808  $("#changesMenuItem").addClass("k-success-colored");
809  var menu = $("#topMenuBar").data("kendoMenu");
810  menu.enable("#saveMenuItem", false);
811  menu.close("#saveMenuItem");
812 
813  if (!$("#currentIssueOwner").is(":visible")) {
814  var issueOwnerDDL = $("#issueOwnerDDL").data("kendoDropDownList");
815  $("#currentIssueOwner").text(issueOwnerDDL.value());
816 
817  if ($("#currentIssueOwner").text() != "<?php echo $Hu; ?>") {
818  issueOwnerDDL.destroy();
819  $("#issueOwnerDiv").remove();
820  $("#currentIssueOwner").show();
821  }
822  }
823 
824  var statusDDL = $("#statusDDL").data("kendoDropDownList");
825  $("#currentIssueStatus").text(statusDDL.value());
826  statusDDL.dataSource.filter({field: "currentStatus", operator: "eq", value: statusDDL.value()});
827  if (statusDDL.value() == "Completed") {
828  $("#completedDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
829  } else {
830  $("#completedDate").text("N/A");
831  }
832  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
833 
834  var refreshTaskCommentGrids = typeof(changed["comments"]) != "undefined";
835  if (deletedIds.length > 0) {
836  commentData = $.grep(commentData, function(n,i) { return deletedIds.indexOf(n.commentId) == -1; });
837  refreshTaskCommentGrids = true;
838  deletedIds = [];
839  }
840 
841  if (refreshTaskCommentGrids) {
842  $(".taskCommentGrid:visible").each(function() {
843  $(this).data("kendoGrid").dataSource.read();
844  });
845  }
846 
847  if (parameters.billingFeatureId != null) {
848  $("#billingExists").text("Y"); // presumably
849  AddAssociateBillingIdDDL(parameters.billingFeatureId, parameters.status, ddlData);
850  } else if (parameters.changedStatus == "Y") {
851  AddAssociateBillingIdDDL(parameters.billingFeatureId, parameters.status, ddlData);
852  }
853 
854  changed = {}; // Clear out so that next save doesn't pick up previously changed stuff.
855  <?php } ?>
856  }
857  });
858  }
859 }
860 
861 <?php // This will setup all the stuff for the contact popup using the two DDLs needed. It is called once. ?>
862 var isSpecial = false;
863 function SetupContactPopup(roleDDL, contactDDL) {
864  var popup = $("<div id='contactPopup'></div>").kendoWindow({
865  content: {template: $("#contactPopupTemplate").html()},
866  draggable: false,
867  visible: false,
868  actions: [],
869  modal: true,
870  title: "Add Contact",
871  width: 400,
872  resizable: false,
873  autoFocus: false
874  }).data("kendoWindow");
875 
876  var roleDDL = $("#roleDDL").kendoDropDownList({
877  dataSource: {
878  data: roleDDL
879  },
880  dataTextField: "text",
881  dataValueField: "value",
882  filter: "startswith"
883  }).data("kendoDropDownList");
884 
885  var phoneMTB = $("[name='contactPhone']").kendoMaskedTextBox({
886  mask: "000-000-0000"
887  }).data("kendoMaskedTextBox");
888 
889  $("#contactPopup .updateBtn").click(function () {
890 
891  $.homecuValidator.validate();
892  if ($("#formValidateContactDiv li:visible").length == 0) {
893  var parameters = {};
894  parameters.cu = $("#cu").text();
895  parameters.firstName = $("[name='contactFirstName']").val();
896  parameters.lastName = $("[name='contactLastName']").val();
897  parameters.email = $("[name='contactEmail']").val();
898  parameters.comment = $("[name='contactComment']").val();
899  parameters.role = roleDDL.value();
900  parameters.phone = phoneMTB.value();
901  parameters.decider = $("[name='decider']").prop("checked") ? "Y" : "N";
902 
903  if(isSpecial) {
904  ShowChanges("contactId", -1);
905  ShowChanges("contactName", parameters.firstName);
906  ShowChanges("contactEmail", parameters.email);
907  ShowChanges("contactPhone", parameters.phone);
908 
909  $("#contactNameRow").show();
910  $("#contactName").text(parameters.firstName);
911  $("#contactEmail").text(parameters.email);
912  $("#contactPhone").text(parameters.phone);
913 
914  var ddlData = contactDDL.dataSource.data();
915 
916  // Update the "SPECIAL" record.
917  ddlData[2].fullName = parameters.firstName;
918  ddlData[2].email = parameters.email;
919  ddlData[2].phone = parameters.phone;
920  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
921  popup.close();
922  } else {
923  showWaitWindow();
924  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=addNewContact", parameters, function(data) {
925  hideWaitWindow();
926  if (!errorsAreShown(data, "formValidateContactDiv")) {
927  var ddlData = contactDDL.dataSource.data();
928  ddlData.push(data.newDDLRecord);
929  contactDDL.value(data.newDDLRecord.contactId);
930  $("#contactPhone").text(data.newDDLRecord.phone);
931  $("#contactEmail").text(data.newDDLRecord.email);
932  ShowChanges("contactId", data.newDDLRecord.contactId);
933  changed.changedContactId = "Y";
934  contactDDL.previousValue = data.newDDLRecord.contactId; // At this point, the change is done.
935  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
936  popup.close();
937  } else {
938  contactDDL.value(contactDDL.previousValue);
939  }
940  });
941  }
942  }
943  return false;
944  });
945 
946  $("#contactPopup .cancelBtn").click(function () {
947  if (contactDDL.previousValue == "") {
948  contactDDL.select(0);
949  } else {
950  contactDDL.value(contactDDL.previousValue); // Cancelled so contact is not attached.
951  var dataItem = contactDDL.dataItem();
952  $("#contactPhone").text(dataItem.phone);
953  $("#contactEmail").text(dataItem.email);
954 
955  if (dataItem.text == "SPECIAL") {
956  $("#contactNameRow").show();
957  $("#contactName").text(dataItem.fullName);
958  } else {
959  $("#contactNameRow").hide();
960  }
961 
962  }
963 
964  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
965  popup.close();
966  return false;
967  });
968 }
969 
970 <?php // Called everytime the user selects the NEW contact option. It will clear out the form and then open it. ?>
971 function OpenContactPopup() {
972 
973  $("#roleDDL").data("kendoDropDownList").select(0);
974  $("[name='contactComment']").val(null);
975  $("[name='decider']").prop("checked", false);
976  $("#contactPopup .k-invalid-msg").hide();
977  $("[name='contactLastName']").val(null);
978 
979  if (isSpecial) {
980  $("#contactRoleRow").hide();
981  $("#contactCommentRow").hide();
982  $("#commentDeciderRow").hide();
983  $("#contactLastNameRow").hide();
984  $("[name='contactLastName']").prop("required", false);
985  $("label[data-for='contactFirstName']").text("Full Name:");
986 
987  // Prepopulate
988  var dataItem = $("#contactDDL").data("kendoDropDownList").dataItem();
989  $("[name='contactFirstName']").val(dataItem.fullName);
990  $("[name='contactEmail']").val(dataItem.email);
991  $("[name='contactPhone']").data("kendoMaskedTextBox").value(dataItem.phone);
992  } else {
993  $("label[data-for='contactFirstName']").text("First Name:");
994  $("[name='contactFirstName']").val(null);
995  $("[name='contactEmail']").val(null);
996  $("[name='contactPhone']").data("kendoMaskedTextBox").value(null);
997  $("#contactRoleRow").show();
998  $("#contactCommentRow").show();
999  $("#commentDeciderRow").show();
1000  $("#contactLastNameRow").show();
1001  $("[name='contactLastName']").prop("required", true);
1002  }
1003 
1004  $.homecuValidator.setup({formValidate: "contactForm", formStatusField: "formValidateContactDiv"});
1005  $("#contactPopup").data("kendoWindow").open().center();
1006  $("[name='contactFirstName']").focus();
1007  setTimeout(function() { $("[name='contactFirstName']").focus();}, 400);
1008 }
1009 
1010 var showAllComments = true;
1011 var deletedIds = [];
1012 var commentIdToDelete = null;
1013 var commentData = [];
1014 var taskCommentGrids = [];
1015 var taskIdMap = {};
1016 <?php // Called once to set up the comment grid. ?>
1017 function InitComments(gridSelector) {
1018  var grid = $(gridSelector).data("kendoGrid");
1019 
1020  if (grid != null) {
1021  grid.destroy();
1022  $(gridSelector).empty();
1023  }
1024 
1025  var nextCommentId = commentData.length+1;
1026  var initialized = false;
1027  var definition = {
1028  dataSource: {
1029  transport: {
1030  read: function (options) {
1031  options.success(commentData);
1032  },
1033  create: function (options) {
1034  commentData.push(options.data);
1035  options.success(options.data);
1036  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
1037  },
1038  update: function (options) {
1039  for(var i=0; i!= commentData.length; i++) {
1040  if (commentData[i].commentId == options.data.commentId) {
1041  commentData[i] = options.data;
1042  }
1043  }
1044  options.success(options.data);
1045  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
1046  }
1047  },
1048  schema: {
1049  model: {
1050  id: "mockCommentId",
1051  fields: {
1052  commentId: {type: "number", editable: false},
1053  mockCommentId: {type: "number", editable: false},
1054  <?php // For kendo's isNew() function because comments are added without being saved immediately ?>
1055  author: {type: "string", editable: false},
1056  createdDate: {type: "date", editable: false},
1057  trackItemId: {type: "number", editable: false},
1058  trackItemName: {type: "string", editable: false},
1059  text: {type: "string"},
1060  thisRowDirty: {type: "boolean", editable: false},
1061  <?php // So that I can tell what is changed. Using the dirty flag doesn't work with popup because a "save" will set these to false. ?>
1062  groupId: {type: "number", editable: false}
1063  }
1064  }
1065  },
1066  sort: [{field: "createdDate", dir: "desc"}]
1067  },
1068  columns: [
1069  {field: "author", title: "Author", hidden: true, width: "75px"},
1070  {field: "createdDate", title: "Created Date", width: "75px", format: "{0:MM/dd/yy}"},
1071  {field: "text", title: "Text"}
1072  ],
1073  toolbar: [{name: "create", text: ""}, {name: "showAll", text: showAllComments ? "Hide Task Comments" : "Show All"}],
1074  editable: {
1075  mode: "popup",
1076  template: kendo.template($("#commentPopupTemplate").html()),
1077  window: {
1078  draggable: false,
1079  resizable: false,
1080  title: "",
1081  actions: [],
1082  width: 400,
1083  autoFocus: false
1084  }
1085  },
1086  edit: function (e) {
1087  setupValidatorInGrid(e);
1088  if (e.model.isNew()) {
1089  e.model.author = "<?php echo $Hu; ?>";
1090  e.model.createdDate = new Date();
1091  $(".k-window-title:visible").text("Add Comment");
1092 
1093  <?php // Change the text of the update so user knows it doesn't actually update yet. ?>
1094  e.model.thisRowDirty = true;
1095  $(e.container).find(".k-grid-update").html("<span class=\"k-icon k-i-plus\"></span>Add");
1096  } else {
1097  $(".k-window-title:visible").text("Edit Comment");
1098  $(e.container).find(".k-grid-update").html("<span class=\"k-icon k-i-edit\"></span>Modify");
1099  }
1100 
1101  $("[name='text']").blur(function () {
1102  e.model.thisRowDirty = true;
1103  })
1104 
1105  ShowChanges("comments", "");
1106 
1107  $("[name='text']").focus();
1108  setTimeout(function() { $("[name='text']").focus();}, 400);
1109  },
1110  save: function (e) {
1111  useValidatorInGrid(e);
1112 
1113  if (e.model.isNew()) {
1114  e.model.mockCommentId = nextCommentId++;
1115  }
1116  },
1117  dataBound: function () {
1118  var grid = this;
1119  if (!initialized) {
1120  addMinifiedActionStyle(gridSelector, true);
1121  initialized = true;
1122  }
1123 
1124  $(gridSelector).find(".k-grouping-row").each(function () {
1125  $(this).prev().find("td").css({borderBottom: "1px solid black"});
1126  $(this).next().find("td").css({borderTop: "1px solid black"});
1127  $(this).find("td").text($(this).find("td").text());
1128  });
1129 
1130  InitCommentContextMenu(this);
1131 
1132  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("mouseenter", function() {
1133  $(this).addClass("k-state-hover");
1134  });
1135 
1136  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("click", function () {
1137  grid.editRow($(this));
1138  });
1139 
1140  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("mouseleave", function () {
1141  $(this).removeClass("k-state-hover");
1142  });
1143 
1144  var rows = $(gridSelector).find(".k-grid-content tr");
1145  $(rows).mouseenter(function (thisEvent) {
1146  $(this).data("timer", setTimeout($.proxy(function() { ShowCommentNotification($(this))}, $(this)), 2000));
1147  });
1148  $(rows).mouseleave(function () {
1149  clearTimeout($(this).data("timer"));
1150  });
1151  $(rows).click(function () {
1152  ShowCommentNotification($(this));
1153  return false;
1154  });
1155  },
1156  cancel: function () {
1157  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("mouseenter", function() {
1158  $(this).addClass("k-state-hover");
1159  });
1160 
1161  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("click", function () {
1162  grid.editRow($(this));
1163  });
1164 
1165  $(gridSelector).find(".k-grid-content tr:not(.k-grouping-row)").on("mouseleave", function () {
1166  $(this).removeClass("k-state-hover");
1167  });
1168 
1169  var rows= $(gridSelector).find(".k-grid-content tr");
1170  $(rows).off("mouseenter mouseleave click");
1171  $(rows).mouseenter(function () {
1172  $(this).data("timer", setTimeout($.proxy(function() { ShowCommentNotification($(this))}, $(this)), 2000));
1173  });
1174  $(rows).mouseleave(function () {
1175  clearTimeout($(this).data("timer"));
1176  });
1177  $(rows).click(function () {
1178  ShowCommentNotification($(this));
1179  return false;
1180  });
1181  }
1182  };
1183 
1184  if (showAllComments) {
1185  definition.columns[0].hidden = false;
1186  definition.dataSource.group = {field: "groupId"};
1187  definition.columns.push({field: "groupId", hidden: true, groupHeaderTemplate: "# if (value == 0) { # Job Comments # } else { # Task Comments # } #"});
1188  } else {
1189  definition.dataSource.filter = [{field: "trackItemId", operator: "eq", value: 0}, {field: "author", operator: "eq", value: "<?php echo strtolower($Hu); ?>"}];
1190  }
1191 
1192  var commentsGrid = $(gridSelector).kendoGrid(definition).data("kendoGrid");
1193 
1194  $(gridSelector).find(".k-grid-showAll").click(function () {
1195  showAllComments = !showAllComments;
1196  InitComments(gridSelector);
1197  return false;
1198  });
1199 
1200 
1201 }
1202 
1203 <?php // This function sets up the context menu for the comment grid. ?>
1204 function InitCommentContextMenu(grid) {
1205  var contextMenu = $("#commentContextMenu").data("kendoContextMenu");
1206  var commentIdToDelete = null;
1207  var commentRowForMenu = null;
1208  var commentGridForMenu = null;
1209 
1210  if (contextMenu == null) {
1211  var contextMenu = $("<div id='commentContextMenu'></div>").kendoContextMenu({
1212  target: "body",
1213  filter: "#commentsGrid .k-grid-content tr:not(.k-grouping-row), .taskCommentGrid .k-grid-content tr",
1214  alignToAnchor: true,
1215  orientation: "vertical",
1216  popupCollision: false,
1217  open: function (e) {
1218  this.remove("li");
1219 
1220  var grid = $(e.event.target).closest(".k-grid").data("kendoGrid");
1221  var tr = $(e.event.target).parent();
1222  var dataItem = grid.dataItem($(tr));
1223 
1224  var options = dataItem.trackItemId != 0 ? [{text: "Show Task Info", cssClass: "showTaskInfoLi"}] : [];
1225  if (dataItem.author.toLowerCase() == "<?php echo strtolower($Hu); ?>") {
1226  options.push({text: "Edit", cssClass: "editLi"});
1227  options.push({text: "Delete", cssClass: "deleteLi"});
1228  }
1229  this.append(options);
1230  },
1231  select: function (e) {
1232  var item = $(e.item);
1233  var tr = $(e.target);
1234  var grid = $(e.target).closest(".k-grid").data("kendoGrid");
1235  var dataItem = grid.dataItem($(tr));
1236 
1237  if ($(item).hasClass("editLi")) {
1238  grid.editRow($(tr));
1239  } else if ($(item).hasClass("deleteLi")) {
1240  if (dataItem.commentId == 0) { // Comment has not been saved and then deleted.
1241  var data = grid.dataSource.data();
1242  data = $.grep(data, function (n,i) { return dataItem.uid != n.uid; });
1243  grid.dataSource.data(data);
1244  ShowChanges("comments", "");
1245  } else {
1246  commentIdToDelete = dataItem.commentId;
1247  commentRowForMenu = tr;
1248  commentGridForMenu = grid;
1249  deleteConfirm.open().center();
1250  }
1251  } else if ($(item).hasClass("showTaskInfoLi")) {
1252  ShowCommentNotification($(tr));
1253  }
1254  }
1255  }).data("kendoContextMenu");
1256 
1257  deleteConfirm = $("<div id='deleteCommentDialog'></div>").kendoWindow({
1258  content: {template: $("#deleteConfirmTemplate").html()},
1259  draggable: false,
1260  visible: false,
1261  actions: [],
1262  modal: true,
1263  title: "Confirm deletion",
1264  width: 400,
1265  height: 125,
1266  resizable: false
1267  }).data("kendoWindow");
1268 
1269  $("#deleteCommentDialog .deleteConfirmContinueBtn").click(function () {
1270  if ($(commentRowForMenu).closest(".taskCommentGrid").length > 0) {
1271  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=deleteTaskComment", {commentId: commentIdToDelete}, function (data) {
1272  if (!errorsAreShown(data, "formValidateMainDiv")) {
1273  var grid = commentGridForMenu;
1274  var data = grid.dataSource.data();
1275  data = $.grep(data, function(n,i) { return commentIdToDelete != n.commentId; });
1276  grid.dataSource.data(data);
1277 
1278  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
1279  }
1280  });
1281  } else {
1282  var grid = $("#commentsGrid").data("kendoGrid");
1283  var data = grid.dataSource.data();
1284  data = $.grep(data, function(n,i) { return commentIdToDelete != n.commentId; });
1285  grid.dataSource.data(data);
1286  ShowChanges("comments", "");
1287  deletedIds.push(commentIdToDelete);
1288  }
1289 
1290  commentData = $.grep(commentData, function(n,i) { return commentIdToDelete != n.commentId; });
1291 
1292  deleteConfirm.close();
1293  return false;
1294  });
1295 
1296  $("#deleteCommentDialog .deleteConfirmCancelBtn").click(function () {
1297  deleteConfirm.close();
1298  return false;
1299  });
1300 
1301 
1302  }
1303 }
1304 
1305 function ShowCommentNotification(tr) {
1306  clearTimeout($(tr).data("timer"));
1307  if ($(tr).data("hasNotification") == true) {
1308  return;
1309  }
1310 
1311  var top = mouse.y - $("body").scrollTop() - 5;
1312  var left = mouse.x - $("body").scrollLeft() - 5;
1313 
1314  var notification = $("<div></div>").kendoNotification({
1315  position: {
1316  pinned: false,
1317  top: top,
1318  left: left
1319  },
1320  autoHideAfter: 0,
1321  show: function () {
1322  $(tr).data("hasNotification", true);
1323  $(".k-notification:last .k-icon").remove();
1324  $(".k-notification:last").mouseleave(function () {
1325  notification.hide();
1326  });
1327  },
1328  hide: function () {
1329  $(tr).data("hasNotification", false);
1330  }
1331  }).data("kendoNotification");
1332 
1333  var dataItem = $("#commentsGrid").data("kendoGrid").dataItem($(tr));
1334  if (dataItem.trackItemId == 0) {
1335  notification.info("<b>Job Note</b>");
1336  } else {
1337  var foundTask = $.grep(taskData, function(n,i) { return n.taskId == dataItem.trackItemId; });
1338  if (foundTask.length == 0) {
1339  notification.warning("Task not found!");
1340  } else {
1341  var note = "<div class='container_12'><div class='grid_12'><div class='grid_4 alpha'><b><u>Task Note</b></u></div></div><div class='grid_12'>&nbsp;</div>";
1342  if (foundTask[0].parentTaskId == 0) {
1343  note += "<div class='grid_12'><div class='grid_4 alpha'><b>Task:</b></div><div class='grid_8 omega'>" + foundTask[0].title + "</div></div>";
1344  } else {
1345  var foundParent = $.grep(taskData, function(n,i) { return n.taskId == foundTask[0].parentTaskId; });
1346  var parentName = foundParent.length == 0 ? "No parent found!" : foundParent[0].title;
1347  note += "<div class='grid_12'><div class='grid_4 alpha'><b>Task:</b></div><div class='grid_8 omega'>" + parentName + "</div></div>";
1348  note += "<div class='grid_12'><div class='grid_4 alpha'><b>Sub Task:</b></div><div class='grid_8 omega'>" + foundTask[0].title + "</div></div>";
1349  }
1350  note += "<div class='grid_12'><div class='grid_4 alpha'><b>Status:</b></div><div class='grid_8 omega'>" + foundTask[0].statusName + "</div></div>";
1351  note += "<div class='grid_12'><div class='grid_4 alpha'><b>Owner:</b></div><div class='grid_8 omega'>" + foundTask[0].ownerId + "</div></div>";
1352  note += "</div>";
1353  notification.info(note);
1354  }
1355  }
1356 }
1357 
1358 <?php if ($trackId != 0) { ?>
1359 function InitTaskCommentWindow() {
1360  var commentWindow = $("#commentWindow").data("kendoWindow");
1361  var taskCommentGrid = $("#taskCommentGrid").data("kendoGrid");
1362  if (commentWindow == null) {
1363  commentWindow = $("<div id='commentWindow'></div>").kendoWindow({
1364  content: {template: $("#commentWindowTemplate").html()},
1365  draggable: false,
1366  visible: false,
1367  actions: [],
1368  modal: true,
1369  title: "Task Comments for <span class='taskName'></span>",
1370  width: 600,
1371  resizable: false
1372  }).data("kendoWindow");
1373 
1374  taskCommentGrid = $("#taskCommentGrid").kendoGrid({
1375  dataSource: {
1376  transport: {
1377  read: function(options) {
1378  options.success(commentData);
1379  },
1380  create: function(options) {
1381  var parameters = {text: options.data.text, taskId: options.data.trackItemId, issueId: $("#issueNumber").text(), cu: $("#cu").text()};
1382  showWaitWindow();
1383  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=addTaskComment", parameters, function (data) {
1384  hideWaitWindow();
1385  if (!errorsAreShown(data, "formValidatePopupDiv")) {
1386  data.record[0].trackItemName = taskCommentGrid.currentTrackItemName;
1387  data.record[0].createdDate = new Date();
1388  data.record[0].groupId = 1;
1389  data.record[0].mockCommentId = commentData.length + 1;
1390  commentData.push(data.record[0]);
1391  if ($("#commentsGrid .k-grid-showAll").text().trim() == "Hide Task Comments") {
1392  $("#commentsGrid").data("kendoGrid").dataSource.read();
1393  }
1394  options.success(data.record[0]);
1395  $(taskCommentGrid.popupCircle).removeClass("off").addClass("on");
1396  $.homecuValidator.setup({formValidate: "mainForm", formErrorTitle: 'The following errors were detected:', formStatusField: "formValidateMainDiv"});
1397 
1398  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
1399  } else {
1400  options.error(data.record[0]);
1401  }
1402  });
1403 
1404  }
1405  },
1406  schema: {
1407  model: {
1408  id: "commentId",
1409  fields: {
1410  commentId: {type: "number", editable: false},
1411  author: {type: "string", editable: false},
1412  createdDate: {type: "date", editable: false},
1413  trackItemId: {type: "number", editable: false},
1414  trackItemName: {type: "string", editable: false},
1415  text: {type: "string"}
1416  }
1417  }
1418  }
1419  },
1420  columns: [
1421  {field: "author", title: "Author", width: "75px"},
1422  {field: "createdDate", title: "Created Date", width: "75px", format: "{0:MM/dd/yy}"},
1423  {field: "text", title: "Text"}
1424  ],
1425  editable: {
1426  mode: "popup",
1427  template: kendo.template($("#commentPopupTemplate").html()),
1428  window: {
1429  draggable: false,
1430  resizable: false,
1431  title: "",
1432  actions: [],
1433  width: 400,
1434  autoFocus: false
1435  }
1436  },
1437  edit: function (e) {
1438  setupValidatorInGrid(e);
1439  if (e.model.isNew()) {
1440  e.model.author = "<?php echo $Hu; ?>";
1441  e.model.createdDate = new Date();
1442  e.model.trackItemId = taskCommentGrid.currentTaskId;
1443  e.model.trackItemName = taskCommentGrid.currentTaskName;
1444  $(".k-window-title:visible").text("Add Comment for \"" + taskCommentGrid.currentTaskName +"\"");
1445  }
1446 
1447  $("[name='text']").focus();
1448  setTimeout(function() { $("[name='text']").focus();}, 400);
1449  },
1450  save: function (e) {
1451  useValidatorInGrid(e);
1452 
1453  }
1454  }).data("kendoGrid");
1455 
1456  $("#commentWindow .okayBtn").click(function () {
1457  commentWindow.close();
1458  return false;
1459  });
1460  }
1461 }
1462 
1463 function OpenComments(popupCircle, gridSelector) {
1464  clearTimeout($(popupCircle).data("timer"));
1465  var dataItem = $(gridSelector).data("kendoGrid").dataItem($(popupCircle).parent().parent());
1466  $("#taskCommentGrid").data("kendoGrid").dataSource.filter({field: "trackItemId", operator: "eq", value: dataItem.taskId});
1467  $("#commentWindow").parent().find(".taskName").text(dataItem.title);
1468  $("#commentWindow").data("kendoWindow").open().center();
1469 }
1470 
1471 function InitTaskCommentDatabound(gridSelector) {
1472  var isMaster = $(gridSelector).closest(".detailGrid").length == 0;
1473 
1474  var popupCircles = null;
1475  if (isMaster) {
1476  popupCircles = $(gridSelector).find(".k-master-row .taskCommentPopupCircle").filter(function () { return $(this).closest(".detailGrid").length == 0; });
1477  } else {
1478  popupCircles = $(gridSelector).find(".k-grid-content tr .taskCommentPopupCircle");
1479  }
1480  $(popupCircles).mouseenter(function () {
1481  $(this).data("timer", setTimeout($.proxy(function() { OpenComments($(this), gridSelector)}, $(this)), 2000));
1482  });
1483  $(popupCircles).mouseleave(function () {
1484  clearTimeout($(this).data("timer"));
1485  });
1486  $(popupCircles).click(function () {
1487  if ($(this).hasClass("on") && !$(this).hasClass("off")) {
1488  OpenComments($(this), gridSelector);
1489  }
1490  return false;
1491  });
1492 }
1493 
1494 var showAllTasks = false;
1495 var detailGrids = {};
1496 var taskData = [];
1497 <?php // Sets up the task grid. ?>
1498 function InitTasks(ownerDDL, taskStatusDDL) {
1499  var initialized = false;
1500  var nextPosition = -1;
1501  var currentPosition = -1;
1502  var openDetails = {};
1503  var masterTasks = [];
1504 
1505  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=readTasks", {trackId: <?php echo $trackId; ?>}, function(data) {
1506  if (!errorsAreShown(data, "formValidateMainDiv")) {
1507  taskData = data.record;
1508  masterTasks = data.masterTasks;
1509  tasksGrid.dataSource.read();
1510 
1511  nextPosition = $.grep(taskData, function(n,i) { return n.parentTaskId == 0; }).length;
1512  }
1513  });
1514 
1515  var toolbar = [{name: "create", text: ""}, {name: "showAll", text: "Show N/A"}];
1516  if ($("#fromTemplate").text() == "Yes") {
1517  toolbar.push({name: "pullIn", text: "Get Unused from Master"});
1518  }
1519  var tasksGrid = $("#tasksGrid").kendoGrid({
1520  dataSource: {
1521  transport: {
1522  read: function (options) {
1523  options.success(taskData);
1524  },
1525  create: function (options) {
1526  var nextTaskItIs = IsNextTask(-1, 0) ? "Y" : "N";
1527  var isFirstTask = taskData.length == 0 ? "Y" : "N";
1528  var parameters = {issueId: <?php echo $trackId; ?>, title: options.data.title, description: options.data.description,
1529  ownerId: options.data.ownerId, parentTaskId: 0, position: nextPosition, issueOwnerId: $("#currentIssueOwner").text(),
1530  cu: $("#cu").text(), cuName: $("#cuName").text(), issue: $("#issue").val(), isNextTask: nextTaskItIs, isFirstTask: isFirstTask};
1531  nextPosition++;
1532  showWaitWindow();
1533  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=createTask", parameters, function(data) {
1534  hideWaitWindow();
1535 
1536  if (!errorsAreShown(data, "formValidatePopupDiv")) {
1537  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
1538  options.success(data.record);
1539  taskIdMap[data.record[0].taskId]= data.record[0].title;
1540  <?php // make sure that map is defined for new task when showing all comments. ?>
1541  taskData.push(data.record[0]);
1542  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
1543  <?php // Put validator focus back on main page. ?>
1544  } else {
1545  options.error(data.record);
1546  }
1547  });
1548  },
1549  update: function (options) {
1550  var nextTaskItIs = IsNextTask(options.data.taskId, 0) ? "Y" : "N";
1551  var parameters = {issueId: <?php echo $trackId; ?>, taskId: options.data.taskId, title: options.data.title,
1552  description: options.data.description, ownerId: options.data.ownerId, issueOwnerId: $("#currentIssueOwner").text(),
1553  previousOwnerId: options.data.previousOwnerId, cu: $("#cu").text(), isNextTask: nextTaskItIs,
1554  cuName: $("#cuName").text(), issue: $("#issue").val()};
1555 
1556  showWaitWindow();
1557  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=updateTask", parameters, function (data) {
1558  hideWaitWindow();
1559 
1560  if (!errorsAreShown(data, "formValidatePopupDiv")) {
1561  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
1562  data.record[0].position = currentPosition;
1563  options.success(data.record);
1564  for (var i = 0; i != taskData.length; i++) {
1565  if (data.record[0].taskId == taskData[i].taskId) {
1566  taskData[i] = data.record[0];
1567  }
1568  }
1569  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
1570  <?php // Put validator focus back on main page. ?>
1571  } else {
1572  options.error(data.record);
1573  }
1574  });
1575  }
1576  },
1577  schema: {
1578  model: {
1579  id: "taskId",
1580  fields: {
1581  title: {type: "string"},
1582  taskId: {type: "number"},
1583  description: {type: "string"},
1584  ownerId: {type: "string"},
1585  completedOn: {type: "date"},
1586  statusId: {type: "number", defaultValue: 1},
1587  statusName: {type: "string"},
1588  statusChangedDate: {type: "date"},
1589  parentTaskId: {type: "number"},
1590  position: {type: "number"},
1591  taskTemplateId: {type: "number"},
1592  billingItemId: {type: "number"}
1593  }
1594  }
1595  },
1596  sort: [{field: "viewOrder", dir: "asc"}, {field: "position", dir: "asc"}],
1597  filter: [{field: "parentTaskId", operator: "eq", value: 0}, {field: "statusId", operator: "neq", value: 2}]
1598  },
1599  columns: [
1600  {field: "statusId", hidden: true, menu: false},
1601  {title: "", attributes: {"class" : "commentPopupTD"}, width: "17px", menu: false},
1602  {field: "title", title: "Title", width: "200px"},
1603  {field: "description", title: "Description", width: "400px"},
1604  {field: "ownerId", title: "Owner", width: "50px", template: "# if (ownerId == '') { # (Job Owner) # } else { # #: ownerId # # } #"},
1605  {field: "completedOn", title: "Completed", format: "{0:d}", width: "50px"},
1606  {field: "statusName", title: "Status", hidden: true, width: "50px"},
1607  {field: "statusChangedDate", title: "Status Change Date", format: "{0:d}", hidden: true, width: "50px"},
1608  {field: "taskId", hidden: true, attributes: {"class" : "taskId"}, menu: false}
1609  ],
1610  columnMenu: true,
1611  autoBind: false,
1612  resizable: true,
1613  toolbar: toolbar,
1614  detailTemplate: "<div class=\"detailGrid\" style=\"width:100%\"></div>",
1615  detailInit: function(eOuter) {
1616  InitSubTasks(eOuter, ownerDDL, taskStatusDDL);
1617  },
1618  editable: {
1619  mode: "popup",
1620  template: kendo.template($("#popupTemplateTasks").html()),
1621  createAt: "bottom",
1622  window: {
1623  draggable: false,
1624  resizable: false,
1625  title: "<span id='taskPopupTitle'></span>",
1626  actions: [],
1627  width: 700,
1628  autoFocus: false
1629  }
1630  },
1631  edit: function (eOuter) {
1632  TaskEdit(eOuter, ownerDDL, true);
1633  },
1634  save: function (eOuter) {
1635  useValidatorInGrid(eOuter);
1636  eOuter.model.title = $("[name='title']").val(); <?php // Fixes safari's autofill problem. ?>
1637  eOuter.model.description = $("[name='description']").val();
1638 
1639  currentPosition = eOuter.model.position;
1640 
1641  },
1642  // To readd the click, mouseover, and mouseleave events to the row.
1643  cancel: function (eOuter) {
1644  this.cancelRow();
1645  var grid = this;
1646  var masterRows = $(this.tbody).find("tr.k-master-row");
1647 
1648  $(masterRows).off("mouseenter mouseleave");
1649  $(masterRows).on("mouseenter", function() {
1650  $(this).addClass("k-state-hover");
1651  });
1652 
1653  $(masterRows).on("mouseleave", function() {
1654  $(this).removeClass("k-state-hover");
1655  });
1656 
1657  $(masterRows).find("[role='gridcell']:not(.commentPopupTD)").off();
1658  $(masterRows).find("[role='gridcell']:not(.commentPopupTD)").on("click", function () {
1659  if ($("#currentIssueStatus").text() == "Active") {
1660  grid.editRow($(this).parent());
1661  }
1662  });
1663 
1664  // Color completed and N/As
1665  $(masterRows).each(function() {
1666  var dataItem = tasksGrid.dataItem($(this));
1667  if (dataItem.completedOn != null) {
1668  $(this).addClass("k-success-colored");
1669  } else if (dataItem.statusId == 2) {
1670  $(this).addClass("k-state-disabled");
1671  }
1672 
1673  var hasCommentsClass = $.grep(commentData, function(n,i) { return n.trackItemId == dataItem.taskId; }).length > 0 ? "on" : "off";
1674  $(this).find(".commentPopupTD").html("<div class='taskCommentPopupCircle " + hasCommentsClass + "'></div>");
1675  });
1676 
1677  InitTaskCommentDatabound("#tasksGrid");
1678 
1679  eOuter.preventDefault();
1680  return false;
1681  },
1682  dataBound: function (eOuter) {
1683  var masterRows = $(this.tbody).find("tr.k-master-row");
1684  var grid = this;
1685 
1686  <?php // Color completed and N/As ?>
1687  $(masterRows).each(function() {
1688  var dataItem = tasksGrid.dataItem($(this));
1689  if (dataItem.completedOn != null) {
1690  $(this).addClass("k-success-colored");
1691  } else if (dataItem.statusId == 2) {
1692  $(this).addClass("k-state-disabled");
1693  }
1694 
1695  grid.expandRow($(this));
1696 
1697  var hasCommentsClass = $.grep(commentData, function(n,i) { return n.trackItemId == dataItem.taskId; }).length > 0 ? "on" : "off";
1698  $(this).find(".commentPopupTD").html("<div class='taskCommentPopupCircle " + hasCommentsClass + "'></div>");
1699  });
1700 
1701  if (!initialized) {
1702  addMinifiedActionStyle(this, true);
1703  initialized = true;
1704 
1705  InitPullIn(masterTasks);
1706  InitTaskCompleteDialog(ownerDDL);
1707 
1708  <?php if ($trackItemId != 0) { // Find if there is a trackItemId and if there is, open it.?>
1709  var foundTask = false;
1710  var parentTaskId = 0;
1711  var tr = $(".taskId").filter(function(index) { return $(this).text() == <?php echo $trackItemId; ?>; }).parent();
1712  if ($(tr).length > 0) {
1713  $(tr).closest(".k-grid").data("kendoGrid").editRow($(tr));
1714  }
1715  <?php } ?>
1716  }
1717 
1718  InitTaskContextMenu(this);
1719 
1720  $(masterRows).on("mouseenter", function() {
1721  $(this).addClass("k-state-hover");
1722  });
1723 
1724  $(masterRows).on("mouseleave", function() {
1725  $(this).removeClass("k-state-hover");
1726  });
1727 
1728  $(masterRows).find("[role='gridcell']:not(.commentPopupTD)").on("click", function () {
1729  if ($("#currentIssueStatus").text() == "Active")
1730  grid.editRow($(this).parent());
1731  });
1732 
1733 
1734 
1735  InitTaskCommentDatabound("#tasksGrid");
1736  }
1737  }).data("kendoGrid");
1738 
1739  $("#tasksGrid .k-grid-showAll").click(function () {
1740  showAllTasks = !showAllTasks;
1741  if (showAllTasks) {
1742  tasksGrid.dataSource.filter({field: "parentTaskId", operator: "eq", value: 0});
1743  // Correct visible details
1744  $("#tasksGrid .detailGrid:visible").each(function () {
1745  var thisGrid = $(this).data("kendoGrid");
1746  var filter = thisGrid.dataSource.filter();
1747  filter.filters.splice(1,1);
1748  thisGrid.dataSource.filter(filter);
1749  });
1750  } else {
1751  tasksGrid.dataSource.filter([{field: "parentTaskId", operator: "eq", value: 0}, {field: "statusId", operator: "neq", value: 2}]);
1752  // Correct visible details
1753  $("#tasksGrid .detailGrid:visible").each(function () {
1754  var thisGrid = $(this).data("kendoGrid");
1755  var filter = thisGrid.dataSource.filter();
1756  filter.filters.push({field: "statusId", operator: "neq", value: 2});
1757  thisGrid.dataSource.filter(filter);
1758  });
1759  }
1760 
1761  $("#tasksGrid .k-grid-showAll").text(showAllTasks ? "Hide N/A" : "Show N/A");
1762  return false;
1763  });
1764 
1765  InitTaskCommentWindow();
1766 }
1767 
1768 function InitPullIn(masterTasks) {
1769  var pullInWindow = $("#pullInWindow").data("kendoWindow");
1770  var pullInGrid = $("#pullInGrid").data("kendoGrid");
1771  if (pullInWindow == null) {
1772  pullInWindow = $("<div id='pullInWindow'></div>").kendoWindow({
1773  content: {
1774  template: kendo.template($("#pullInTemplate").html())
1775  },
1776  modal: true,
1777  title: "Pull In Task Templates",
1778  visible: false,
1779  actions: [],
1780  draggable: false,
1781  resizable: false,
1782  width: 600
1783  }).data("kendoWindow");
1784 
1785  var pullInNoWindow = $("<div id='pullInNoWindow'></div>").kendoWindow({
1786  content: {
1787  template: kendo.template($("#pullInNoTemplates").html())
1788  },
1789  modal: true,
1790  title: "No Templates",
1791  visible: false,
1792  actions: [],
1793  draggable: false,
1794  resizable: false,
1795  width: 400
1796  }).data("kendoWindow");
1797 
1798  pullInGrid = $("#pullInGrid").kendoGrid({
1799  dataSource: {
1800  data: [],
1801  schema: {
1802  model: {
1803  id: "taskTemplateId",
1804  fields: {
1805  taskTemplateId: {type: "number"},
1806  title: {type: "string"}
1807  }
1808  }
1809  }
1810  },
1811  columns: [
1812  {field: "taskTemplateId", hidden: true},
1813  {title: "<input type='checkbox' id='allCheckbox'>", template: "<input type='checkbox' class='rowCheckbox'>", width: "35px"},
1814  {field: "title", title: "Task"}
1815  ],
1816  dataBound: function (e) {
1817  $(".rowCheckbox").click(function() {
1818  if ($(this).prop("checked")) {
1819  <?php // If all rowCheckboxes are now checked, then reflect that. ?>
1820  if ($(".rowCheckbox:not(:checked)").length == 0) {
1821  $("#allCheckbox").prop("checked", true);
1822  }
1823  } else {
1824  $("#allCheckbox").prop("checked", false);
1825  }
1826  });
1827  }
1828  }).data("kendoGrid");
1829 
1830  $("#allCheckbox").click(function() {
1831  if ($(this).prop("checked")) {
1832  $(".rowCheckbox").prop("checked", true);
1833  } else {
1834  $(".rowCheckbox").prop("checked", false);
1835  }
1836  });
1837 
1838  $("#tasksGrid .k-grid-pullIn").click(function () {
1839  <?php // Will need to do this everytime. Master tasks could have been deleted which means that they would be available in this list again. ?>
1840  var lookup = {};
1841  for (var i = 0; i != taskData.length; i++) {
1842  lookup[taskData[i].taskTemplateId] = true;
1843  }
1844  var unusedData = $.grep(masterTasks, function(n,i) { return typeof(lookup[n.taskTemplateId]) == "undefined"; });
1845 
1846  if (unusedData.length == 0) {
1847  pullInNoWindow.open().center();
1848  } else {
1849  pullInGrid.dataSource.data(unusedData);
1850  $("#allCheckbox").prop("checked", false);
1851  pullInWindow.open().center();
1852  }
1853  return false;
1854  });
1855 
1856  $("#pullInWindow .saveBtn").click(function () {
1857  var taskTemplateIds = [];
1858  $(".rowCheckbox:checked").each(function() {
1859  taskTemplateIds.push($(this).parent().prev().text());
1860  });
1861  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=pullInTaskTemplates",
1862  {taskTemplateIds: kendo.stringify(taskTemplateIds), trackId: <?php echo $trackId; ?>, taskLength: taskData.length, issueId: $("#templateId").text()},
1863  function (data) {
1864  if (!errorsAreShown(data, "formValidatePullInDiv")) {
1865  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
1866  for(var i = 0; i != data.record.length; i++) {
1867  taskData.push(data.record[i]);
1868  }
1869  $("#tasksGrid").data("kendoGrid").dataSource.read();
1870  pullInWindow.close();
1871  }
1872  });
1873 
1874  return false;
1875  });
1876 
1877  $("#pullInWindow .cancelBtn").click(function () {
1878  pullInWindow.close();
1879  return false;
1880  });
1881 
1882  $("#pullInNoWindow .okayBtn").click(function () {
1883  pullInNoWindow.close();
1884  return false;
1885  });
1886  }
1887 }
1888 
1889 function InitTaskCompleteDialog(taskOwnerDDLData) {
1890  taskCompleteDialog = $("<div id='taskCompleteDialog'></div>").kendoWindow({
1891  content: {
1892  template: kendo.template($("#taskCompleteDialogTemplate").html())
1893  },
1894  modal: true,
1895  title: "Complete Task",
1896  visible: false,
1897  actions: [],
1898  draggable: false,
1899  resizable: false,
1900  width: 400
1901  }).data("kendoWindow");
1902 
1903  var nextTaskOwnerDDL = $("#nextTaskOwnerDDL").kendoDropDownList({
1904  dataSource: {
1905  data: taskOwnerDDLData,
1906  schema: {
1907  model: {
1908  id: "value",
1909  fields: {
1910  value: {type: "string"},
1911  text: {type: "string"},
1912  filterNumber: {type: "number"}
1913  }
1914  }
1915  }
1916  },
1917  dataTextField: "text",
1918  dataValueField: "value"
1919  }).data("kendoDropDownList");
1920 
1921  var completeDatePicker = $("#completeDatePicker").kendoDatePicker({
1922  dataBound: function() {
1923  this.value(new Date());
1924  },
1925  change: function () {
1926  if (this.value() == null) {
1927  this.value(null);
1928  $("#completeDatePicker").val(null);
1929  }
1930  }
1931  }).data("kendoDatePicker");
1932 
1933  $("#taskCompleteDialog .saveBtn").click(function () {
1934 
1935  var currentTaskRecord = $("#taskCompleteDialog").data("currentTaskRecord");
1936  var nextTaskRecord = $("#taskCompleteDialog").data("nextTaskRecord");
1937 
1938  ChangeStatus(currentTaskRecord, 0, function(parameters) {
1939  if (nextTaskRecord != null) {
1940  if (nextTaskOwnerDDL.value().toLowerCase() != nextTaskRecord.ownerId.toLowerCase()) {
1941  parameters.nextTaskOwnerChanged = "Y";
1942  parameters.nextTaskOwner = nextTaskOwnerDDL.value().toLowerCase();
1943  nextTaskRecord.ownerId = parameters.nextTaskOwner;
1944  }
1945  parameters.nextTaskId = nextTaskRecord.taskId;
1946  }
1947 
1948  if ($("#completeNotes").val() != "") {
1949  parameters.completeNotes = $("#completeNotes").val();
1950  }
1951  parameters.forceEmail = $("#forceEmail:checked").length == 0 ? "N" : "Y";
1952  parameters.completeDate = $("#completeDatePicker").data("kendoDatePicker").value() == null ? null
1953  : kendo.toString($("#completeDatePicker").data("kendoDatePicker").value(), "yyyy-MM-dd");
1954  }, function(data) {
1955  // Update next task
1956  if (nextTaskRecord != null) {
1957  var nextTaskI = -1;
1958  for(var i = 0; i!= taskData.length; i++) {
1959  if (taskData[i].taskId == nextTaskRecord.taskId) {
1960  taskData[i].ownerId = nextTaskRecord.ownerId;
1961  break;
1962  }
1963  }
1964  }
1965 
1966  if (typeof(data.noteRecord) != "undefined") {
1967  data.noteRecord.createdDate = new Date();
1968  data.noteRecord.groupId = 1;
1969  commentData.push(data.noteRecord);
1970  $("#commentsGrid").data("kendoGrid").dataSource.read();
1971  $("#taskCommentGrid").data("kendoGrid").dataSource.read();
1972  }
1973 
1974  });
1975  taskCompleteDialog.close();
1976  return false;
1977  });
1978 
1979  $("#taskCompleteDialog .cancelBtn").click(function () {
1980  taskCompleteDialog.close();
1981  return false;
1982  });
1983 }
1984 
1985 function OpenTaskCompleteDialog(currentTaskRecord, nextTaskRecord, isNextTask) {
1986  var taskCompleteDialog = $("#taskCompleteDialog").data("kendoWindow");
1987  var nextTaskOwnerDDL = $("#nextTaskOwnerDDL").data("kendoDropDownList");
1988 
1989  $("#taskCompleteDialog").data("currentTaskRecord", currentTaskRecord);
1990  $("#taskCompleteDialog").data("nextTaskRecord", nextTaskRecord);
1991 
1992  $("#completingTaskTitle").text(currentTaskRecord.title);
1993 
1994  $("#completeDatePicker").data("kendoDatePicker").value(new Date());
1995 
1996  if (nextTaskRecord != null) {
1997  $(".nextTaskDiv").show();
1998  $("#jobSendMsgDiv").hide();
1999  $("#nextTaskTitle").text(nextTaskRecord.title);
2000 
2001  var filterNumber = nextTaskRecord.parentTaskId == 0 ? 1 : 2;
2002  var filter = {logic: "or", filters: [{field: "filterNumber", operator: "eq", value: 0}, {field: "filterNumber", operator: "eq", value: filterNumber}]};
2003  nextTaskOwnerDDL.dataSource.filter(filter);
2004 
2005  nextTaskOwnerDDL.value(nextTaskRecord.ownerId.toLowerCase());
2006  } else {
2007  $(".nextTaskDiv").hide();
2008  $("#jobSendMsgDiv").show();
2009  }
2010 
2011  $("#completeNotes").val(null);
2012  $("#forceEmail").prop("checked", false);
2013  taskCompleteDialog.open().center();
2014 }
2015 
2016 function IsNextTask(taskId, parentTaskId) {
2017  var nextTaskItIs = true;
2018  if (parentTaskId != 0) {
2019  var nextParentTask = $.grep(taskData, function(n,i) { return n.parentTaskId == 0 && n.completedOn == null && n.statusId != 2; });
2020  nextParentTask.sort(function(a,b) {
2021  var viewOrderSort = a.viewOrder - b.viewOrder;
2022  var positionSort = a.position - b.position;
2023  if (viewOrderSort != 0) {
2024  return viewOrderSort;
2025  } else {
2026  return positionSort;
2027  }
2028  });
2029  if (nextParentTask[0].taskId != parentTaskId) {
2030  nextTaskItIs = false;
2031  }
2032  }
2033 
2034  if (nextTaskItIs) {
2035  var nextTask = $.grep(taskData, function(n,i) { return n.parentTaskId == parentTaskId && n.completedOn == null && n.statusId != 2; });
2036  nextTask.sort(function(a,b) {
2037  var viewOrderSort = a.viewOrder - b.viewOrder;
2038  var positionSort = a.position - b.position;
2039  if (viewOrderSort != 0) {
2040  return viewOrderSort;
2041  } else {
2042  return positionSort;
2043  }
2044  });
2045  if ((taskId != -1 && nextTask[0].taskId != taskId) || (taskId == -1 && nextTask.length != 0)) {
2046  nextTaskItIs = false;
2047  }
2048  }
2049  return nextTaskItIs;
2050 }
2051 
2052 function GetNextTasks() {
2053  var sortFunction = function(a,b) {
2054  var viewOrderSort = a.viewOrder - b.viewOrder;
2055  var positionSort = a.position - b.position;
2056  if (viewOrderSort != 0) {
2057  return viewOrderSort;
2058  } else {
2059  return positionSort;
2060  }
2061  };
2062 
2063  var nextTasks = [];
2064  var parentTasks = $.grep(taskData, function(n) { return n.parentTaskId == 0 && n.completedOn == null && n.statusId != 2; });
2065  parentTasks.sort(function(a,b) { return sortFunction(a,b); });
2066  var getCount = 2;
2067  for(var i = 0; i != parentTasks.length; i++) {
2068  var subTasks = $.grep(taskData, function(n) { return n.parentTaskId == parentTasks[i].taskId && n.completedOn == null && n.statusId != 2; });
2069  subTasks.sort(function(a,b) { return sortFunction(a,b); });
2070  if (subTasks.length == 0) {
2071  nextTasks.push(parentTasks[i]);
2072  getCount--;
2073  } else {
2074  for(var j = 0; j != subTasks.length; j++) {
2075  nextTasks.push(subTasks[j]);
2076  getCount--;
2077  if (getCount == 0) {
2078  break;
2079  }
2080  }
2081  }
2082 
2083  if (getCount == 0) {
2084  break;
2085  }
2086  }
2087  return nextTasks;
2088 }
2089 
2090 <?php // Nearly the same as the top level. However, trying to get one function for both proved to be a big messy. ?>
2091 function InitSubTasks(eOuter, ownerDDL, taskStatusDDL) {
2092  var nextPosition = $.grep(taskData, function(n,i) { return n.parentTaskId == eOuter.data.taskId; }).length;
2093  var currentPosition = -1;
2094  var initialized = false;
2095  eOuter.detailRow.find(".detailGrid").data("parentTaskId", eOuter.data.taskId);
2096 
2097  var filter = [{field: "parentTaskId", operator: "eq", value: eOuter.data.taskId}];
2098  if ($("#tasksGrid .k-grid-showAll").text().trim() == "Show N/A")
2099  filter.push({field: "statusId", operator: "neq", value: 2});
2100 
2101  var detailGrid = eOuter.detailRow.find(".detailGrid").kendoGrid({
2102  dataSource: {
2103  transport: {
2104  read: function (options) {
2105  options.success(taskData);
2106  },
2107  create: function (options) {
2108  var parentRecord = $.grep(taskData, function(n,i) { return n.taskId == eOuter.data.taskId; });
2109  var parentOwner = parentRecord[0].ownerId;
2110 
2111  var nextTaskItIs = IsNextTask(-1, eOuter.data.taskId) ? "Y" : "N";
2112  var parameters = {issueId: <?php echo $trackId; ?>, title: options.data.title, description: options.data.description,
2113  ownerId: options.data.ownerId, parentTaskId: eOuter.data.taskId, position: nextPosition,
2114  issueOwnerId: $("#currentIssueOwner").text(), cu: $("#cu").text(), cuName: $("#cuName").text(),
2115  issue: $("#issue").val(), parentTaskOwnerId: parentOwner,
2116  isNextTask: nextTaskItIs};
2117  nextPosition++;
2118  showWaitWindow();
2119  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=createTask", parameters, function(data) {
2120  hideWaitWindow();
2121 
2122  if (!errorsAreShown(data, "formValidatePopupDiv")) {
2123  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2124  taskIdMap[data.record[0].taskId]= data.record[0].title;
2125  <?php // make sure that map is defined for new task when showing all comments. ?>
2126  taskData.push(data.record[0]);
2127  options.success(data.record);
2128  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
2129  } else {
2130  options.error(data.record);
2131  }
2132  });
2133  },
2134  update: function (options) {
2135  var nextTaskItIs = IsNextTask(options.data.taskId, eOuter.data.taskId) ? "Y" : "N";
2136  var parameters = {issueId: <?php echo $trackId; ?>, taskId: options.data.taskId, title: options.data.title,
2137  description: options.data.description, ownerId: options.data.ownerId, issueOwnerId: $("#currentIssueOwner").text(),
2138  previousOwnerId: options.data.previousOwnerId, isNextTask: nextTaskItIs, cu: $("#cu").text(), cuName: $("#cuName").text(),
2139  issue: $("#issue").val()};
2140 
2141  showWaitWindow();
2142  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=updateTask", parameters, function (data) {
2143  hideWaitWindow();
2144 
2145  if (!errorsAreShown(data, "formValidatePopupDiv")) {
2146  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2147  data.record[0].position = currentPosition;
2148  for (var i = 0; i != taskData.length; i++) {
2149  if (data.record[0].taskId == taskData[i].taskId) {
2150  taskData[i] = data.record[0];
2151  }
2152  }
2153  options.success(data.record);
2154  $.homecuValidator.setup({formValidate: "mainForm", formStatusField: "formValidateMainDiv"});
2155  } else {
2156  options.error(data.record);
2157  }
2158  });
2159  }
2160  },
2161  schema: {
2162  model: {
2163  id: "taskId",
2164  fields: {
2165  title: {type: "string"},
2166  taskId: {type: "number"},
2167  description: {type: "string"},
2168  ownerId: {type: "string"},
2169  completedOn: {type: "date"},
2170  statusId: {type: "number", defaultValue: 1},
2171  statusName: {type: "string"},
2172  statusChangedDate: {type: "date"},
2173  parentTaskId: {type: "number"},
2174  position: {type: "number"},
2175  taskTemplateId: {type: "number"}
2176  }
2177  },
2178  },
2179  sort: [{field: "viewOrder", dir: "asc"}, {field: "position", dir: "asc"}],
2180  filter: filter
2181  },
2182  columns: [
2183  {field: "statusId", hidden: true, menu: false},
2184  {title: "", attributes: {"class" : "commentPopupTD"}, width: "17px", menu: false},
2185  {field: "title", title: "Title", width: "200px"},
2186  {field: "description", title: "Description", width: "400px"},
2187  {field: "ownerId", title: "Owner", width: "50px", template: "# if (ownerId == '') { # (Parent Owner) # } else { # #: ownerId # # } #"},
2188  {field: "completedOn", title: "Completed", format: "{0:MM/dd/yy}", width: "50px"},
2189  {field: "statusName", title: "Status", hidden: true, width: "50px"},
2190  {field: "statusChangedDate", title: "Status Change Date", format: "{0:MM/dd/yy}", hidden: true, width: "50px"},
2191  {field: "taskId", hidden: true, attributes: {"class" : "taskId"}, menu: false}
2192  ],
2193  columnMenu: true,
2194  resizable: true,
2195  editable: {
2196  mode: "popup",
2197  template: kendo.template($("#popupTemplateTasks").html()),
2198  createAt: "bottom",
2199  window: {
2200  draggable: false,
2201  resizable: false,
2202  title: "<span id='taskPopupTitle'></span>",
2203  actions: [],
2204  width: 400,
2205  autoFocus: false
2206  }
2207  },
2208  edit: function (eInner) {
2209  TaskEdit(eInner, ownerDDL, false);
2210  },
2211  save: function (eInner) {
2212  useValidatorInGrid(eInner);
2213  currentPosition = eInner.model.position;
2214  eInner.model.title = $("[name='title']").val();
2215  eInner.model.description = $("[name='description']").val();
2216  },
2217  cancel: function (eInner) {
2218  this.cancelChanges();
2219  var grid = this;
2220  var detailRows = $(this.tbody).find("tr");
2221 
2222  $(detailRows).off("mouseenter mouseleave");
2223  $(detailRows).on("mouseenter", function() {
2224  $(this).addClass("k-state-hover");
2225  });
2226 
2227  $(detailRows).on("mouseleave", function() {
2228  $(this).removeClass("k-state-hover");
2229  });
2230 
2231  $(detailRows).find("[role='gridcell']:not(.commentPopupTD)").off();
2232  $(detailRows).find("[role='gridcell']:not(.commentPopupTD)").on("click", function () {
2233  if ($("#currentIssueStatus").text() == "Active") {
2234  grid.editRow($(this).parent());
2235  }
2236  });
2237 
2238  // Color completed and N/As
2239  $(detailRows).each(function() {
2240  var dataItem = grid.dataItem($(this));
2241  if (dataItem.completedOn != null) {
2242  $(this).addClass("k-success-colored");
2243  } else if (dataItem.statusId == 2) {
2244  $(this).addClass("k-state-disabled");
2245  }
2246 
2247  var taskId = Number($(this).find(".taskId").text());
2248  var hasCommentsClass = $.grep(commentData, function(n,i) { return n.trackItemId == taskId; }).length > 0 ? "on" : "off";
2249  $(this).find(".commentPopupTD").html("<div class='taskCommentPopupCircle " + hasCommentsClass + "'></div>");
2250  });
2251 
2252  InitTaskCommentDatabound(eOuter.detailRow.find(".detailGrid"));
2253 
2254  eInner.preventDefault();
2255  return false;
2256  },
2257  dataBound: function (eInner) {
2258  var detailRows = $(this.tbody).find("tr");
2259  var grid = this;
2260  if (!initialized) {
2261  addMinifiedActionStyle(this, true);
2262  initialized = true;
2263  }
2264 
2265  $(detailRows).on("mouseenter", function() {
2266  $(this).addClass("k-state-hover");
2267  });
2268 
2269  $(detailRows).on("mouseleave", function() {
2270  $(this).removeClass("k-state-hover");
2271  });
2272 
2273  $(detailRows).find("[role='gridcell']:not(.commentPopupTD)").on("click", function () {
2274  if ($("#currentIssueStatus").text() == "Active") {
2275  grid.editRow($(this).parent());
2276  }
2277  });
2278 
2279  // Color completed and N/As
2280  $(detailRows).each(function() {
2281  var dataItem = grid.dataItem($(this));
2282  if (dataItem.completedOn != null) {
2283  $(this).addClass("k-success-colored");
2284  } else if (dataItem.statusId == 2) {
2285  $(this).addClass("k-state-disabled");
2286  }
2287 
2288  var taskId = Number($(this).find(".taskId").text());
2289  var hasCommentsClass = $.grep(commentData, function(n,i) { return n.trackItemId == taskId; }).length > 0 ? "on" : "off";
2290  $(this).find(".commentPopupTD").html("<div class='taskCommentPopupCircle " + hasCommentsClass + "'></div>");
2291  });
2292 
2293  InitTaskCommentDatabound(eOuter.detailRow.find(".detailGrid"));
2294  }
2295  }).data("kendoGrid");
2296 
2297  detailGrids[eOuter.data.taskId+ ""] = detailGrid;
2298 }
2299 
2300 <?php // This is the edit function for both the top- and bottom- level tasks. ?>
2301 function TaskEdit(e, ownerDDL, isOuter) {
2302  setupValidatorInGrid(e);
2303 
2304  $("#popupForm").submit(function(e) {
2305  $(this).next().find(".k-grid-update").click();
2306  e.preventDefault();
2307  return false;
2308  });
2309 
2310  var filterNumber = isOuter ? 1 : 2;
2311  var filter = {logic: "or", filters: [{field: "filterNumber", operator: "eq", value: 0}, {field: "filterNumber", operator: "eq", value: filterNumber}]};
2312  var taskOwnerDDL = $("#taskOwnerDDL").kendoDropDownList({
2313  dataSource: {
2314  data: ownerDDL,
2315  schema: {
2316  model: {
2317  id: "value",
2318  fields: {
2319  value: {type: "string"},
2320  text: {type: "string"},
2321  filterNumber: {type: "number"}
2322  }
2323  }
2324  },
2325  filter: filter
2326  },
2327  dataTextField: "text",
2328  dataValueField: "value",
2329  change: function () {
2330  e.model.ownerId = this.value();
2331  e.model.dirty = true;
2332  }
2333  }).data("kendoDropDownList");
2334 
2335  if (e.model.isNew()) {
2336  e.container.parent().find('.k-window-title').text("Add Task");
2337  taskOwnerDDL.value("<?php echo $Hu; ?>");
2338  e.model.ownerId = "<?php echo $Hu; ?>";
2339  } else {
2340  e.container.parent().find('.k-window-title').text("Edit Task");
2341  e.model.previousOwnerId = e.model.ownerId;
2342  taskOwnerDDL.value(e.model.ownerId);
2343  }
2344 
2345  $("[name='title']").focus();
2346  setTimeout(function() { $("[name='title']").focus();}, 400);
2347 }
2348 
2349 function ChangeStatus(dataItem, newStatus, completeParameterFunction, completeUpdateFrontendFunction) {
2350  showWaitWindow();
2351 
2352  // Will now need the owner of the parent task in the case of user selecting "(Parent Task Owner)"
2353  var parentOwner = "";
2354  if (dataItem.parentTaskId != 0) {
2355  var parentRecord = $.grep(taskData, function(n,i) { return n.taskId == dataItem.parentTaskId; });
2356  parentOwner = parentRecord[0].ownerId;
2357  }
2358  var parameters = {taskId: dataItem.taskId, prevStatus: dataItem.statusId, newStatus: newStatus, issueId: <?php echo $trackId; ?>,
2359  issueOwnerId: $("#currentIssueOwner").text(), parentTaskId: dataItem.parentTaskId, parentTaskOwnerId: parentOwner,
2360  cu: $("#cu").text(), cuName: $("#cuName").text(), billingItemId: dataItem.billingItemId};
2361  if (typeof(completeParameterFunction) == "function") {
2362  (completeParameterFunction)(parameters);
2363  }
2364 
2365 
2366  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=changeTaskStatus", parameters,
2367  function (data){
2368  hideWaitWindow();
2369 
2370  <?php // If no errors, then remove record from the grid ?>
2371  if (!errorsAreShown(data, "formValidateMainDiv")) {
2372  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2373  var isParent = dataItem.parentTaskId == 0;
2374  var isReactivated = data.statusName == "TODO";
2375  var updateParent = true;
2376  var foundSibling = false;
2377  var parentI = -1;
2378  for (var i = 0; i != taskData.length; i++) {
2379  <?php // Children to N/A or Done ?>
2380  if (isParent && !isReactivated && taskData[i].parentTaskId == dataItem.taskId) {
2381  taskData[i].statusId = data.statusId;
2382  taskData[i].statusName = data.statusName;
2383  if (data.statusName == "Done") {
2384  taskData[i].completedOn = data.completeDate == "" ? new Date() : new Date(data.completeDate);
2385  }
2386  }
2387 
2388  <?php // The task ?>
2389  if (taskData[i].taskId == dataItem.taskId) {
2390  taskData[i].statusId = data.statusId;
2391  taskData[i].statusName = data.statusName;
2392  if (data.statusName == "Done") {
2393  taskData[i].completedOn = data.completeDate == "" ? new Date() : new Date(data.completeDate);
2394  } else {
2395  taskData[i].completedOn = null;
2396  }
2397  } else if (taskData[i].parentTaskId == dataItem.parentTaskId && taskData[i].statusId != 2 && taskData[i].completedOn == null) {
2398  updateParent = false;
2399  }
2400 
2401  // Parent of task
2402  if (!isParent && taskData[i].taskId == dataItem.parentTaskId) {
2403  parentI = i;
2404  }
2405  }
2406 
2407  // Parent update
2408  if (!isParent && parentI != -1) {
2409  if (isReactivated) {
2410  taskData[parentI].statusId = 1;
2411  taskData[parentI].statusName = "TODO";
2412  taskData[parentI].completedOn = null;
2413  } else if (updateParent) {
2414  taskData[parentI].statusId = 0;
2415  taskData[parentI].statusName = "Done";
2416  taskData[parentI].completedOn = data.completeDate == "" ? new Date() : new Date(data.completeDate);
2417  }
2418  }
2419 
2420  if (typeof(completeUpdateFrontendFunction) == "function") {
2421  (completeUpdateFrontendFunction)(data);
2422  }
2423 
2424  $("#tasksGrid").data("kendoGrid").dataSource.read();
2425  $("#tasksGrid .detailGrid:visible").each(function () {
2426  $(this).data("kendoGrid").dataSource.read();
2427  });
2428  }
2429  });
2430 }
2431 
2432 var taskDataItemForMenu = null;
2433 <?php // This will initialize a context menu for the task grid. Most options that you can do for tasks are in this menu. ?>
2434 function InitTaskContextMenu(grid) {
2435  var contextMenu = $("#taskContextMenu").data("kendoContextMenu");
2436  var taskGridForMenu = null;
2437  if (contextMenu == null) {
2438  var deleteConfirm= $("<div id='deleteTaskDialog'></div>").kendoWindow({
2439  content: {template: $("#deleteConfirmTemplate").html()},
2440  draggable: false,
2441  visible: false,
2442  actions: [],
2443  modal: true,
2444  title: "Confirm deletion",
2445  width: 400,
2446  height: 125,
2447  resizable: false
2448  }).data("kendoWindow");
2449 
2450  $("#deleteTaskDialog .deleteConfirmContinueBtn").click(function () {
2451  var deleteSubTasks = taskDataItemForMenu.parentTaskId != 0 || $.grep(taskData, function(n,i) {
2452  return n.parentTaskId == taskDataItemForMenu.taskId;
2453  }).length == 0 ? "N" : "Y";
2454  showWaitWindow();
2455  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=deleteTask", {taskId: taskDataItemForMenu.taskId, deleteSubTasks: deleteSubTasks,
2456  trackId: <?php echo $trackId; ?>, cu: $("#cu").text(), cuName: $("#cuName").text(), isNew: $("#currentIssueStatus").text() == "New" ? "Y" : "N"},
2457  function (data){
2458  hideWaitWindow();
2459 
2460  // If no errors, then remove record from the grid
2461  if (!errorsAreShown(data, "formValidateMainDiv")) {
2462  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2463  taskData = $.grep(taskData, function(n,i) { return n.taskId != taskDataItemForMenu.taskId && n.parentTaskId != taskDataItemForMenu.taskId; });
2464  grid.dataSource.read();
2465  }
2466  });
2467  deleteConfirm.close();
2468  return false;
2469  });
2470 
2471  $("#deleteTaskDialog .deleteConfirmCancelBtn").click(function () {
2472  deleteConfirm.close();
2473  return false;
2474  });
2475 
2476  var contextMenu = $("<div id='taskContextMenu'></div>").kendoContextMenu({
2477  target: "#tasksGrid",
2478  filter: ".k-master-row > [role='gridcell']:not(.commentPopupTD), .detailGrid tr td:not(.commentPopupTD)",
2479  alignToAnchor: true,
2480  orientation: "vertical",
2481  popupCollision: false,
2482  open: function (e) {
2483  <?php // Prevent this logic from occurring when a submenu is opened. is("[role='menubar']") refers to the main context menu. ?>
2484  if ($(e.item).is("[role='menuitem']")) {
2485  return;
2486  }
2487 
2488  this.remove("li");
2489 
2490  var options = [];
2491  var grid = $(e.event.target).closest(".k-grid").data("kendoGrid");
2492  var tr = $(e.event.target).parent();
2493  var dataItem = grid.dataItem($(tr));
2494 
2495  var issueOwner = $("#currentIssueOwner").text();
2496  <?php // This isn't the issueOwnerDDL value because the current owner could have changed that and haven't saved yet. ?>
2497  var issueStatus = $("#currentIssueStatus").text();
2498 
2499  if ($(grid.tbody).closest(".detailGrid").length > 0) {
2500  options.push({text: "Promote", cssClass: "promoteLi"});
2501  }
2502 
2503  var data= $("#tasksGrid .k-grid-showAll").text() == "Show All" ?
2504  $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.parentTaskId && n.statusId != 2; })
2505  : $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.parentTaskId; }); // Only go through the parent tasks.
2506  data.sort(function(a, b) {
2507  return a.position - b.position;
2508  });
2509  if (data.length >= 2) { // Will need at least two tasks for move before and move after to make sense.
2510  var moveBeforeChoices = [];
2511  var moveAfterChoices = [];
2512  this.taskIndex = -1;
2513  for (var i = 0; i != data.length; i++) {
2514  moveBeforeChoices.push({text: data[i].title, cssClass: "moveBeforeChoiceLi task_" + i});
2515  moveAfterChoices.push({text: data[i].title, cssClass: "moveAfterChoiceLi task_" + i});
2516  if (data[i].taskId == dataItem.taskId) {
2517  this.taskIndex = i;
2518  }
2519  }
2520 
2521  if (data.length == 2) {
2522  this.taskIndex == 0 ? moveBeforeChoices= [] : moveBeforeChoices.splice(this.taskIndex, 1);
2523  this.taskIndex == 1 ? moveAfterChoices= [] : moveAfterChoices.splice(this.taskIndex, 1);
2524  } else {
2525  moveBeforeChoices.splice(this.taskIndex, 2);
2526  this.taskIndex == 0 ? moveAfterChoices.splice(0, 1) : moveAfterChoices.splice(this.taskIndex - 1, 2);
2527  }
2528 
2529  if (moveBeforeChoices.length > 0) {
2530  options.push({text: "Move before...", items: moveBeforeChoices, cssClass: "moveBeforeLi"});
2531  }
2532  if (moveAfterChoices.length > 0) {
2533  options.push({text: "Move after...", items: moveAfterChoices, cssClass: "moveAfterLi"});
2534  }
2535  }
2536 
2537  if (issueStatus == "Active") {
2538  options.push({text: "Edit", cssClass: "editLi"});
2539 
2540  var canDelete = false;
2541  var canComplete = false;
2542 
2543  if ($(grid.tbody).closest(".detailGrid").length > 0) {
2544  $("#deleteTaskDialog #subTaskDeleteMsg").hide();
2545  canDelete = true;
2546  canComplete = true;
2547  } else { // Need more information
2548  if (dataItem.statusId != 2 && dataItem.completedOn == null) {
2549  options.push({text: "Add Subtask", cssClass: "subtaskLi"});
2550  }
2551  var details = $("#tasksGrid .k-grid-showAll").text() == "Show All"
2552  ? $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.taskId && n.statusId != 2 && n.completedOn == null; })
2553  : $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.taskId; });
2554  if (details.length == 0) {
2555  $("#deleteTaskDialog #subTaskDeleteMsg").hide();
2556  canDelete = true;
2557  canComplete = true;
2558  } else {
2559  $("#deleteTaskDialog #subTaskDeleteMsg").show();
2560  $("#deleteTaskDialog #subTaskDeleteMsg span").text(details.length);
2561 
2562  if (issueOwner.toLowerCase() == "<?php echo strtolower($Hu); ?>") {
2563  canDelete = true;
2564  canComplete = true;
2565  } else {
2566  canDelete = true;
2567  canComplete = true;
2568  for(var i = 0; i != details.length; i++) {
2569  if (details[i].ownerId != dataItem.ownerId) {
2570  canDelete = false;
2571  }
2572 
2573  if (details[i].statusId != 0) { // Subtask isn't completed. Therefore task cannot be completed.
2574  canComplete = false;
2575  }
2576 
2577  if (!canDelete && !canComplete) { // No further need for loop.
2578  break;
2579  }
2580  }
2581  }
2582  }
2583  }
2584 
2585  if (dataItem.statusId != 2 && dataItem.completedOn == null && canComplete) {
2586  options.push({text: "Mark Complete", cssClass: "statusLi completeLi"});
2587  } else if (dataItem.statusId == 0) {
2588  options.push({text: "Mark Active", cssClass: "statusLi todoLi"});
2589  }
2590  }
2591 
2592  {
2593  if (dataItem.statusId != 2 && dataItem.completedOn == null) {
2594  options.push({text: "Mark N/A", cssClass: "statusLi naLi"});
2595  } else if (dataItem.statusId == 2) {
2596  options.push({text: "Mark Active", cssClass: "statusLi todoLi"});
2597  }
2598  }
2599 
2600  options.push({text: "Add Note", cssClass: "noteLi"});
2601  options.push({text: "Show Notes", cssClass: "showNotesLi"});
2602 
2603  if (canDelete) {
2604  options.push({text: "Delete", cssClass: "deleteLi"});
2605  }
2606 
2607  this.append(options);
2608  },
2609  select: function (e) {
2610  var item = $(e.item);
2611  var tr = $(e.target).parent();
2612  var grid = $(e.target).closest(".k-grid").data("kendoGrid");
2613  var dataItem = grid.dataItem($(tr));
2614 
2615  if ($(item).hasClass("editLi")) {
2616  grid.editRow($(tr));
2617  } else if ($(item).hasClass("deleteLi")) {
2618  taskDataItemForMenu = dataItem;
2619  taskGridForMenu = grid;
2620  deleteConfirm.open().center();
2621  } else if ($(item).hasClass("completeLi")) {
2622  var newStatus = 0;
2623  var nextTasks = GetNextTasks();
2624  var isNextTask = false;
2625  var nextTaskRecord = null;
2626  if (nextTasks[0].taskId == dataItem.taskId) {
2627  isNextTask = true;
2628 
2629  if (nextTasks.length >= 2) {
2630  nextTaskRecord = nextTasks[1];
2631  }
2632  } else {
2633  nextTaskRecord = nextTasks[0];
2634  }
2635  OpenTaskCompleteDialog(dataItem, nextTaskRecord, isNextTask);
2636  } else if ($(item).hasClass("statusLi")) {
2637  var newStatus = null;
2638  if ($(item).hasClass("todoLi")) {
2639  newStatus = 1;
2640  } else if ($(item).hasClass("naLi")) {
2641  newStatus = 2;
2642  } else if ($(item).hasClass("completeLi")) {
2643  newStatus = 0;
2644  }
2645  ChangeStatus(dataItem, newStatus);
2646  } else if ($(item).hasClass("noteLi")) {
2647  taskDataItemForMenu = dataItem;
2648  var commentGrid = $("#taskCommentGrid").data("kendoGrid");
2649  commentGrid.currentTaskId = dataItem.taskId;
2650  commentGrid.currentTaskName = dataItem.title;
2651  commentGrid.popupCircle = $(tr).find(".taskCommentPopupCircle");
2652  commentGrid.addRow();
2653  } else if ($(item).hasClass("showNotesLi")) {
2654  $("#taskCommentGrid").data("kendoGrid").dataSource.filter({field: "trackItemId", operator: "eq", value: dataItem.taskId});
2655  $("#commentWindow .taskName").text(dataItem.title);
2656  $("#commentWindow").data("kendoWindow").open().center();
2657  } else if ($(item).hasClass("subtaskLi")) {
2658  var detailGrid = detailGrids[dataItem.taskId];
2659  if (detailGrid == null) {
2660  grid.expandRow($(tr));
2661  grid.collapseRow($(tr));
2662  }
2663  detailGrids[dataItem.taskId].addRow();
2664  } else if ($(item).hasClass("promoteLi")) {
2665  showWaitWindow();
2666  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=promoteTask",
2667  {parentTaskId: dataItem.parentTaskId, taskId: dataItem.taskId, trackId: <?php echo $trackId; ?>,
2668  cu: $("#cu").text(), cuName: $("#cuName").text()}, function (data) {
2669  hideWaitWindow();
2670 
2671  if (!errorsAreShown(data, "formValidateMainDiv")) {
2672  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2673  taskI = -1, parentTaskI = -1, parentPosition = -1;
2674  for(var i = 0; i != taskData.length; i++) {
2675  if (taskData[i].taskId == dataItem.taskId) {
2676  taskI = i;
2677  } else if (taskData[i].taskId == dataItem.parentTaskId) {
2678  parentTaskI = i;
2679  parentPosition = taskData[i].position;
2680  }
2681  if (taskI != -1 && parentTaskI != -1) {
2682  break;
2683  }
2684  }
2685  taskData[taskI].position = parentPosition + 0.5; <?php // Not real values but it will probably refresh soon. ?>
2686  taskData[taskI].parentTaskId = 0;
2687  $("#tasksGrid").data("kendoGrid").dataSource.read();
2688  }
2689  });
2690  } else if ($(item).hasClass("moveAfterChoiceLi") || $(item).hasClass("moveBeforeChoiceLi")) {
2691  var classes = $(item).attr("class").split(/\s+/);
2692  var moveTaskId = 0;
2693  for(var i = 0; i != classes.length; i++) {
2694  var parts = classes[i].split(/_/);
2695  if (parts[0].trim() == "task") {
2696  moveTaskId = Number(parts[1]);
2697  break;
2698  }
2699  }
2700 
2701  var data = $("#tasksGrid .k-grid-showAll").text() == "Show All" ?
2702  $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.parentTaskId && n.statusId != 2; })
2703  : $.grep(taskData, function(n,i) { return n.parentTaskId == dataItem.parentTaskId; });
2704  var theActualMoveTaskId = data[moveTaskId].taskId;
2705  var newLocation = $(item).hasClass("moveAfterChoiceLi") ? moveTaskId + 1 : moveTaskId;
2706 
2707  <?php // Do higher index first in order not to mess up the lower index. ?>
2708  if (newLocation >= this.taskIndex) {
2709  data.splice(newLocation, 0, dataItem);
2710  data.splice(this.taskIndex, 1);
2711  } else {
2712  data.splice(this.taskIndex, 1);
2713  data.splice(newLocation, 0, dataItem);
2714  }
2715 
2716  // Will need to remove the parent tasks and then readd them.
2717  taskData= $("#tasksGrid .k-grid-showAll").text() == "Show All" ?
2718  $.grep(taskData, function(n,i) { return n.parentTaskId != dataItem.parentTaskId || !(n.statusId != 2); })
2719  : $.grep(taskData, function(n,i) { return n.parentTaskId != dataItem.parentTaskId; });
2720 
2721  var taskIds = [];
2722  for (var i = 0; i != data.length; i++) {
2723  taskIds.push(data[i].taskId);
2724  data[i].position = i;
2725  taskData.push(data[i]);
2726  }
2727 
2728  <?php // Finally send the results to the database. ?>
2729  var isNew = $("#currentIssueStatus").text() == "New";
2730  showWaitWindow();
2731  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=reorderTasks",
2732  {taskIds: kendo.stringify(taskIds), issueId: <?php echo $trackId; ?>, isNew: isNew ? "Y" : "N",
2733  parentTaskId: dataItem.parentTaskId, cu: $("#cu").text(), cuName: $("#cuName").text(),
2734  taskId: dataItem.taskId, moveTaskId: theActualMoveTaskId, moveAfter: $(item).hasClass("moveAfterChoiceLi") ? "Y" : "N"},
2735  function (data) {
2736  $("#lastActivityDate").text(kendo.toString(new Date(), "MM/dd/yyyy"));
2737  hideWaitWindow();
2738  if (!errorsAreShown(data, "formValidateMainDiv")) {
2739  grid.dataSource.read();
2740  }
2741  });
2742 
2743  }
2744  }
2745  }).data("kendoContextMenu");
2746  }
2747 }
2748 
2749 <?php /* Started from http://jsfiddle.net/rusev/nmB69/ This will allow the reordering option. Subtasks can be moved to the parent level.
2750 There is logic to prevent user from moving record
2751 into its own detail list (because then the parent will be itself which is impossible in this context. */?>
2752 function InitTaskDropAndDrop() {
2753  var grid = $("#tasksGrid").data("kendoGrid");
2754  dataSource = grid.dataSource;
2755  grid.table.kendoDraggable({
2756  filter: "tr:not(.k-success-colored)",
2757  group: "taskGroup",
2758  hint: function(e) {
2759  var title = $(e).find("td:eq(2)").text();
2760  return $('<div class="k-grid k-widget draggableWidget"><b>Title: </b>' + title + '</div>');
2761  },
2762  dragstart: function(e) { // Prevent any task comments from being dragged.
2763  if ($(e.currentTarget).closest(".taskCommentGrid").length > 0) {
2764  e.preventDefault();
2765  return false;
2766  }
2767  }
2768  });
2769 
2770  grid.table.kendoDropTarget({
2771  group: "taskGroup",
2772 
2773  drop: function(e) {
2774  var targetTr = $(e.draggable.currentTarget);
2775  var destinationTr = $(e.target);
2776 
2777  if (destinationTr.hasClass("draggableWidget")) {
2778  $(".draggableWidget").hide();
2779  destinationTr = $(document.elementFromPoint(e.clientX, e.clientY)).parent();
2780  $(".draggableWidget").show();
2781  } else {
2782  destinationTr = $(destinationTr).parent();
2783  }
2784 
2785  var targetParent = Number($(targetTr).closest(".detailGrid").data("parentTaskId"));
2786  var destinationParent = Number($(destinationTr).closest(".detailGrid").data("parentTaskId"));
2787  var targetGrid = targetParent == 0 ? grid : detailGrids[targetParent + ""];
2788  var destinationGrid= destinationParent == 0 ? grid : detailGrids[destinationParent + ""];
2789  var target = targetGrid.dataItem($(targetTr));
2790  var destination = destinationGrid.dataItem($(destinationTr));
2791 
2792  if (typeof(destination) != "undefined"
2793  && target.taskId != destination.taskId && target.parentTaskId != destination.taskId && target.taskId != destination.parentTaskId
2794  && destination.statusId != 0) {
2795 
2796  var targetI = -1, destinationI = -1;
2797  target.parentTaskId = destination.parentTaskId;
2798  <?php // Get the indices for splicing the data. ?>
2799  for (var i = 0; i != taskData.length; i++) {
2800  if (taskData[i].taskId == target.taskId) {
2801  targetI = i;
2802  } else if (taskData[i].taskId == destination.taskId) {
2803  destinationI = i;
2804  }
2805  if (targetI != -1 && destinationI != -1) {
2806  break;
2807  }
2808  }
2809  <?php // Higher index done first to not mess up the index of the lower number. ?>
2810  if (destinationI > targetI) {
2811  taskData.splice(destinationI, 0, target);
2812  taskData.splice(targetI, 1);
2813  } else {
2814  taskData.splice(targetI, 1);
2815  taskData.splice(destinationI, 0, target);
2816  }
2817  <?php // Once the order is established, reset the position. ?>
2818  var taskIds = [];
2819  for (var i = 0; i != taskData.length; i++) {
2820  taskData[i].position = i;
2821  if (taskData[i].parentTaskId == destination.parentTaskId) {
2822  taskIds.push(taskData[i].taskId);
2823  }
2824  }
2825 
2826  $("#tasksGrid").data("kendoGrid").dataSource.read();
2827 
2828  var isNew = $("#currentIssueStatus").text() == "New";
2829  showWaitWindow();
2830  $.post("/hcuadm/<?php echo $dataFile; ?>?operation=reorderTasks",
2831  {taskIds: kendo.stringify(taskIds), issueId: <?php echo $trackId; ?>, isNew: isNew ? "Y" : "N",
2832  parentTaskId: destinationParent, cu: $("#cu").text(), cuName: $("#cuName").text()},
2833  function (data) {
2834  hideWaitWindow();
2835  errorsAreShown(data, "formValidateMainDiv");
2836  });
2837  }
2838  }
2839  });
2840 }
2841 <?php } ?>
2842 
2843 var mouse = {x: 0, y: 0};
2844 $(document).ready(function () {
2845  InitPage();
2846  $(this).mousemove(function (e) {
2847  mouse.x = e.pageX;
2848  mouse.y = e.pageY;
2849  });
2850 });
2851 
2852 </script>
2853 <script id="contactPopupTemplate" type="text/x-kendo-template">
2854 <div class="k-edit-form-container">
2855  <div id="formValidateContactDiv" class="homecu-formStatus k-block k-error-colored" style="display:none;"></div>
2856  <form id="contactForm" class="popupForm" data-role="validator" novalidate>
2857  <div class="container_12">
2858  <div class="grid_12">
2859  <div class="grid_4 alpha" id="contactFirstNameRow">
2860  <label data-for="contactFirstName">First Name:</label>
2861  </div>
2862  <div class="grid_7">
2863  <input type="text" class="k-input" name="contactFirstName" required data-required-msg="First Name is required" style="width:100%" maxlength="40">
2864  </div>
2865  <div class="grid_1 omega">
2866  <span data-for='contactFirstName' class='k-invalid-msg'></span>
2867  </div>
2868  </div>
2869  <div class="grid_12" id="contactLastNameRow">
2870  <div class="grid_4 alpha">
2871  <label data-for="contactLastName">Last Name:</label>
2872  </div>
2873  <div class="grid_7">
2874  <input type="text" class="k-input" name="contactLastName" required data-required-msg="Last Name is required" style="width:100%" maxlength="25">
2875  </div>
2876  <div class="grid_1 omega">
2877  <span data-for='contactLastName' class='k-invalid-msg'></span>
2878  </div>
2879  </div>
2880  <div class="grid_12" id="contactRoleRow">
2881  <div class="grid_4 alpha">
2882  <label data-for="role">Role:</label>
2883  </div>
2884  <div class="grid_7">
2885  <div id="roleDDL"></div>
2886  </div>
2887  <div class="grid_1 omega">
2888  &nbsp;
2889  </div>
2890  </div>
2891  <div class="grid_12">
2892  <div class="grid_4 alpha">
2893  <label data-for="contactPhone">Phone:</label>
2894  </div>
2895  <div class="grid_7">
2896  <input type="text" class="k-input" name="contactPhone" style="width:100%" homecu-match="phone"
2897  data-homecuCustomMatch-msg="Phone is not in a valid format">
2898  </div>
2899  <div class="grid_1 omega">
2900  <span data-for='contactPhone' class='k-invalid-msg'></span>
2901  </div>
2902  </div>
2903  <div class="grid_12">
2904  <div class="grid_4 alpha">
2905  <label data-for="contactEmail">Email:</label>
2906  </div>
2907  <div class="grid_7">
2908  <input type="text" class="k-input" name="contactEmail" style="width:100%" maxlength="50" homecu-match='email'
2909  data-homecuCustomMatch-msg='Email is not in a valid format'>
2910  </div>
2911  <div class="grid_1 omega">
2912  <span data-for='contactEmail' class='k-invalid-msg'></span>
2913  </div>
2914  </div>
2915  <div class="grid_12" id="contactCommentRow">
2916  <div class="grid_4 alpha">
2917  <label data-for="contactComment">Comment:</label>
2918  </div>
2919  <div class="grid_7">
2920  <textarea name="contactComment" row=15 col=40 style="width:100%" type="text" class="k-input"></textarea>
2921  </div>
2922  <div class="grid_1 omega">
2923  <span data-for='contactComment' class='k-invalid-msg'></span>
2924  </div>
2925  </div>
2926  <div class="grid_12" id="commentDeciderRow">
2927  <div class="grid_4 alpha">
2928  <label for="decider">Decider</label>
2929  </div>
2930  <div class="grid_6 prefix_1">
2931  <input type="checkbox" name="decider">
2932  </div>
2933  <div class="grid_1 omega">
2934  &nbsp;
2935  </div>
2936  </div>
2937  </div>
2938  </form>
2939  <div class="k-edit-buttons k-state-default">
2940  <a class="k-button k-button-icontext k-primary updateBtn" href="\#">
2941  <span class="k-icon k-i-check"></span>Update
2942  </a>
2943  <a class="k-button k-button-icontext cancelBtn" href="\#">
2944  <span class="k-icon k-i-cancel"></span>Cancel
2945  </a>
2946  </div>
2947 </div>
2948 </script>
2949 <script id="deleteConfirmTemplate" type="text/x-kendo-template">
2950  <div class="k-edit-form-container">
2951  <div class="container_12">
2952  <div class="grid_12 message">Are you sure that you want to delete?
2953  <span id="subTaskDeleteMsg" style="display:none;">This will also delete <span>1</span> subtask(s) as well.</div>
2954  </div>
2955  <div class="k-edit-buttons k-state-default">
2956  <a class="k-button k-button-icontext deleteConfirmContinueBtn" href="\#">
2957  <span class="k-icon k-i-check"></span>
2958  Continue
2959  </a>
2960  <a class="k-button k-button-icontext deleteConfirmCancelBtn" href="\#">
2961  <span class="k-icon k-i-cancel"></span>
2962  Cancel
2963  </a>
2964  </div>
2965  </div>
2966 </script>
2967 <script id="commentPopupTemplate" type="text/x-kendo-template">
2968  <div id="formValidatePopupDiv" class="homecu-formStatus k-block k-error-colored" style="display:none;"></div>
2969  <form id="popupForm" class="popupForm" data-role="validator" novalidate>
2970  <div class="container_12">
2971  <div class="grid_12">
2972  <div class="grid_4 alpha">
2973  <label data-for="text">Text:</label>
2974  </div>
2975  <div class="grid_7">
2976  <textarea name="text" row=15 col=40 style="width:100%; height: 100px;" type="text" class="k-input"
2977  required data-required-msg="Text is required."></textarea>
2978  </div>
2979  <div class="grid_1 omega">
2980  <span data-for='text' class='k-invalid-msg'></span>
2981  </div>
2982  </div>
2983  </div>
2984  </form>
2985 </script>
2986 <script id="popupTemplateTasks" type="text/x-kendo-template">
2987  <div id="formValidatePopupDiv" class="homecu-formStatus k-block k-error-colored" style="display:none;"></div>
2988  <form id="popupForm" class="popupForm" data-role="validator" novalidate>
2989  <div class="container_12">
2990  <div class="grid_12">
2991  <div class="grid_2 alpha">
2992  <label data-for="title">Title:</label>
2993  </div>
2994  <div class="grid_9">
2995  <input type="text" class="k-input" name="title" style="width:100%" required data-required-msg="Title is required.">
2996  </div>
2997  <div class="grid_1 omega">
2998  <span data-for='title' class='k-invalid-msg'></span>
2999  </div>
3000  </div>
3001  <div class="grid_12">
3002  <div class="grid_2 alpha">
3003  <label data-for="description">Description:</label>
3004  </div>
3005  <div class="grid_9">
3006  <textarea name="description" row=15 col=40 style="width:100%; height: 100px;" type="text" class="k-input"></textarea>
3007  </div>
3008  <div class="grid_1 omega">
3009  <span data-for='description' class='k-invalid-msg'></span>
3010  </div>
3011  </div>
3012  <div class="grid_12">
3013  <div class="grid_2 alpha">
3014  <label data-for="owner">Owner:</label>
3015  </div>
3016  <div class="grid_9">
3017  <div id="taskOwnerDDL"></div>
3018  </div>
3019  <div class="grid_1 omega">
3020  &nbsp;
3021  </div>
3022  </div>
3023  </div>
3024  </form>
3025 </script>
3026 <script id="confirmCompleteTemplate" type="text/x-kendo-template">
3027  <div class="k-edit-form-container">
3028  <div class="container_12">
3029  <div class="grid_12 message">Are you sure that you want to complete the job? There are some uncompleted tasks assigned to it.</div>
3030  </div>
3031  <div class="k-edit-buttons k-state-default">
3032  <a class="k-button k-button-icontext okayBtn" href="\#">
3033  <span class="k-icon k-i-check"></span>
3034  Okay
3035  </a>
3036  <a class="k-button k-button-icontext cancelBtn" href="\#">
3037  <span class="k-icon k-i-cancel"></span>
3038  Cancel
3039  </a>
3040  </div>
3041  </div>
3042 </script>
3043 <script id="commentWindowTemplate" type="text/x-kendo-template">
3044  <div>
3045  <div class="container_12">
3046  <div id="taskCommentGrid" style="width:100%"></div>
3047  </div>
3048  <hr>
3049  <a class="k-button k-button-icontext okayBtn" style="clear:both; float: right;" href="\#">
3050  <span class="k-icon k-i-check"></span>
3051  Okay
3052  </a>
3053  </div>
3054 </script>
3055 <script id="pullInTemplate" type="text/x-kendo-template">
3056  <div id="formValidatePullInDiv" class="homecu-formStatus k-block k-error-colored" style="display:none;"></div>
3057  <div class="container_12">
3058  <div id="pullInGrid" style="width:100%"></div>
3059  </div>
3060  <div class="k-edit-buttons k-state-default" style="float:right; margin-top:5px;">
3061  <a class="k-button k-button-icontext saveBtn" href="\#">
3062  <span class="k-icon k-i-check"></span>
3063  Save
3064  </a>
3065  <a class="k-button k-button-icontext cancelBtn" href="\#">
3066  <span class="k-icon k-i-cancel"></span>
3067  Cancel
3068  </a>
3069  </div>
3070 </script>
3071 <script id="taskCompleteDialogTemplate" type="text/x-kendo-template">
3072  <div id="formValidateCompleteDiv" class="homecu-formStatus k-block k-error-colored" style="display:none;"></div>
3073  <form id="completeForm" class="popupForm" data-role="validator" novalidate>
3074  <div class="container_12">
3075  <div class="grid_12">
3076  <div class="grid_4 alpha">
3077  <label data-for="completingTask">Completing:</label>
3078  </div>
3079  <div class="grid_7">
3080  <div id="completingTaskTitle"></div>
3081  </div>
3082  <div class="grid_1 omega">
3083  <span data-for='completingTask' class='k-invalid-msg'></span>
3084  </div>
3085  </div>
3086  <div class="grid_12">
3087  <div class="grid_4 alpha">
3088  <label data-for="completeDatePicker">On:</label>
3089  </div>
3090  <div class="grid_7">
3091  <input id="completeDatePicker">
3092  </div>
3093  <div class="grid_1 omega">
3094  <span data-for='completeDatePicker' class='k-invalid-msg'></span>
3095  </div>
3096  </div>
3097  <div class="grid_12 nextTaskDiv">
3098  <div class="grid_4 alpha">
3099  <label data-for="nextTaskTitle">Next Task:</label>
3100  </div>
3101  <div class="grid_7">
3102  <div id="nextTaskTitle"></div>
3103  </div>
3104  <div class="grid_1 omega">
3105  <span data-for='nextTaskTitle' class='k-invalid-msg'></span>
3106  </div>
3107  </div>
3108  <div class="grid_12 nextTaskDiv">
3109  <div class="grid_4 alpha">
3110  <label data-for="nextTaskOwner">Next Task Owner:</label>
3111  </div>
3112  <div class="grid_7">
3113  <div id="nextTaskOwnerDDL"></div>
3114  </div>
3115  <div class="grid_1 omega">
3116  <span data-for='nextTaskOwner' class='k-invalid-msg'></span>
3117  </div>
3118  </div>
3119  <div class="grid_12" id="jobSendMsgDiv">
3120  <b>This is the last active task. Any comments will be appended to the job almost complete email.</b>
3121  </div>
3122  <div class="grid_12">
3123  <div class="grid_4 alpha">
3124  <label data-for="completeNotes">Notes:</label>
3125  </div>
3126  <div class="grid_7">
3127  <textarea id="completeNotes" row=15 col=40 style="width:100%; height: 100px;" type="text" class="k-input"></textarea>
3128  </div>
3129  <div class="grid_1 omega">
3130  <span data-for='completeNotes' class='k-invalid-msg'></span>
3131  </div>
3132  </div>
3133  <div class="grid_12">
3134  <div class="grid_4 alpha">
3135  <label data-for="forceEmail">Force Email:</label>
3136  </div>
3137  <div class="grid_7">
3138  <input type="checkbox" id="forceEmail">
3139  </div>
3140  <div class="grid_1 omega">
3141  <span data-for='forceEmail' class='k-invalid-msg'></span>
3142  </div>
3143  </div>
3144  </div>
3145  </form>
3146  <div class="k-edit-buttons k-state-default" style="float:right; margin-top:5px;">
3147  <a class="k-button k-button-icontext saveBtn" href="\#">
3148  <span class="k-icon k-i-check"></span>
3149  Complete
3150  </a>
3151  <a class="k-button k-button-icontext cancelBtn" href="\#">
3152  <span class="k-icon k-i-cancel"></span>
3153  Cancel
3154  </a>
3155  </div>
3156 </script>
3157 <script id="pullInNoTemplates" type="text/x-kendo-template">
3158  <div class="k-edit-form-container">
3159  <div class="container_12">
3160  <div class="grid_12 message">There are no tasks to add.</div>
3161  </div>
3162  <div class="k-edit-buttons k-state-default">
3163  <a class="k-button k-button-icontext okayBtn" href="\#">
3164  <span class="k-icon k-i-check"></span>
3165  Okay
3166  </a>
3167  </div>
3168  </div>
3169 </script>
3170 
3171 <?php printMonitorPageMiddle("CU Job Tracking", array("Save: " => array("id" => "saveMenuItem", "disabled" => $trackId != 0,
3172  "list" => array("Save" => array("id" => "pageUpdateBtn"),
3173  "Save and Return" => array("id" => "pageContinueBtn"))), "No Changes" => array("id" => "changesMenuItem", "noA" => true),
3174  "REDIRECT" => array("list" => array("Current Jobs" => array("url" => $backURL))))); ?>
3175  <div id='hideSubmitWait' style='position:relative; left:-2000px;top:-2000px;'>
3176  <div id='homecuSubmitWait' class='k-block' >
3177  <div class='k-loading-image'></div>
3178  </div>
3179  </div>
3180 
3181  <input type="hidden" id="invalidRequestClientSide">
3182  <input type="hidden" id="invalidRequestServerSide">
3183  <div class="container_12">
3184  <div class="grid_12">
3185  <div id="sqlOutput"></div>
3186  </div>
3187  <div class="grid_12">
3188  <div id="formValidateMainDiv" class="k-block k-error-colored" style="display:none;"></div>
3189  </div>
3190  <div class="grid_12">
3191  <form id="mainForm" data-role="validator" novalidate>
3192  <fieldset>
3193  <fieldset id="issueDiv" class="otherFieldsets">
3194  <div class="grid_12">
3195  <div class="grid_3 alpha">Job Number:</div>
3196  <div class="grid_9 omega"><div id="issueNumber" style="width:100%"></div></div>
3197  </div>
3198  <div class="grid_12">
3199  <div class="grid_3 alpha">Job:</div>
3200  <div class="grid_8">
3201  <textarea class="k-input" type="text" id="issue" name="issue" row=15 col=40 style="width:100%"
3202  maxlength="90" required data-required-msg="Job is required"></textarea>
3203  </div>
3204  <div class="grid_1 omega">
3205  <span data-for='issue' class='k-invalid-msg'></span>
3206  </div>
3207  </div>
3208  <div class="grid_12">
3209  <div class="grid_3 alpha">Status:</div>
3210  <div class="grid_5 omega">
3211  <div id="currentIssueStatus" style="display:none;"></div>
3212  <div id="statusDDL" style="width:100%"></div></div>
3213  </div>
3214  <div class="grid_12">
3215  <div class="grid_3 alpha">Job Owner:</div>
3216  <div class="grid_5 omega">
3217  <div id="currentIssueOwner" style="display:none;"></div>
3218  <div id="issueOwnerDiv"><div id="issueOwnerDDL" style="width:100%"></div></div>
3219  </div>
3220  </div>
3221  <div class="grid_12">
3222  <div class="grid_3 alpha">From Template:</div>
3223  <div class="grid_5 omega">
3224  <div id="fromTemplate"></div>
3225  <div id="templateId" style="display:none;"></div>
3226  </div>
3227  </div>
3228  <div id="billingExists" style="display:none;"></div>
3229  <div class="grid_12">
3230  <div class="grid_3 alpha">From Billing:</div>
3231  <div class="grid_5 omega">
3232  <div id="fromBilling"></div>
3233  </div>
3234  </div>
3235  <div class="grid_12">
3236  <div class="grid_3 alpha">Billed:</div>
3237  <div class="grid_5 omega">
3238  <div id="billed"></div>
3239  </div>
3240  </div>
3241  </fieldset>
3242  <fieldset id="cuDiv" class="otherFieldsets">
3243  <div class="grid_12">
3244  <div class="grid_4 alpha">CU Name:</div>
3245  <div class="grid_8 omega">
3246  <div id="cuDDL" style="width:100%"></div>
3247  <div id="cuName" style="display:none;"></div>
3248  </div>
3249  </div>
3250  <div class="grid_12">
3251  <div class="grid_4 alpha">CU:</div>
3252  <div class="grid_8 omega">
3253  <a id="cu" href="#"></a>
3254  </div>
3255  </div>
3256  <div class="grid_12">
3257  <div class="grid_4 alpha">Entered on:</div>
3258  <div class="grid_8 omega"><div id="enteredDate"></div></div>
3259  </div>
3260  <div class="grid_12">
3261  <div class="grid_4 alpha">Target Date:</div>
3262  <div class="grid_7">
3263  <input type="radio" name="targetDateType" value="" checked>
3264  <input id="targetDatePicker" name="targetDate" homecu-match='date' style="width:85%"
3265  data-required-msg="Target Date is required" disabled="disabled"><br>
3266  <input type="radio" name="targetDateType" value="TBD" checked>&nbsp;TBD<br>
3267  <input type="radio" name="targetDateType" value="FLEX">&nbsp;FLEX
3268  </div>
3269  <div class="grid_1 omega">
3270  <span data-for='targetDate' class='k-invalid-msg'></span>
3271  </div>
3272  </div>
3273  <div class="grid_12">
3274  <div class="grid_4 alpha">Drop Dead Date:</div>
3275  <div class="grid_7">
3276  <input id="dropDeadDatePicker" name="dropDeadDate" homecu-match='date' style="width: 85%; left: 20px;">
3277  </div>
3278  <div class="grid_1 omega">
3279  <span data-for='dropDeadDate' class='k-invalid-msg'></span>
3280  </div>
3281  </div>
3282  <div class="grid_12">
3283  <div class="grid_4 alpha">Last Activity:</div>
3284  <div class="grid_8 omega"><div id="lastActivityDate"></div></div>
3285  </div>
3286  <div class="grid_12">
3287  <div class="grid_4 alpha">Completed on:</div>
3288  <div class="grid_8"><div id="completedDate"></div></div>
3289  </div>
3290  </fieldset>
3291  <fieldset id="contactDiv" class="otherFieldsets">
3292  <legend>CU Contact</legend>
3293  <div class="grid_12">
3294  <div class="grid_3 alpha">Contact:</div>
3295  <div class="grid_9 omega"><div id="contactDDL" style="width:100%"></div></div>
3296  </div>
3297  <div class="grid_12" id="contactNameRow" style="display:none;">
3298  <div class="grid_3 alpha">Name:</div>
3299  <div class="grid_9 omega"><div id="contactName" style="width:100%"></div></div>
3300  </div>
3301  <div class="grid_12">
3302  <div class="grid_3 alpha">Email:</div>
3303  <div class="grid_9 omega"><div id="contactEmail" style="width:100%"></div></div>
3304  </div>
3305  <div class="grid_12">
3306  <div class="grid_3 alpha">Phone:</div>
3307  <div class="grid_9 omega"><div id="contactPhone" style="width:100%"></div></div>
3308  </div>
3309  </fieldset>
3310  <fieldset id="oldCommentDiv" class="otherFieldsets">
3311  <legend>Old Comment</legend>
3312  <div style="display:none">No old comments found.</div>
3313  <textarea id="oldComments" row=15 col=40 type="text" class="k-input" readonly="readonly"></textarea>
3314  </fieldset>
3315  <fieldset id="commentDiv">
3316  <legend>Comments</legend>
3317  <div class="grid_12">
3318  <div id="commentNote"><b>Note:</b> Comments are not saved immediately. They are saved when the page saves.</div>
3319  </div>
3320  <div class="grid_12">
3321  <div id="commentsGrid"></div>
3322  </div>
3323  </fieldset>
3324  </fieldset>
3325  </form>
3326  </div>
3327 
3328  <?php if ($trackId != 0) { ?>
3329  <div class="grid_12"><hr></div>
3330  <div class="grid_12"><h3>Tasks</h3></div>
3331  <div class="grid_12"><div id="tasksGrid"></div></div>
3332  <?php } ?>
3333  </div>
3334 
3335 <?php printMonitorPageBottom(); ?>