17 $monLibrary= dirname(__FILE__) .
"/../library";
18 require_once(
"$monLibrary/cu_top.i");
19 require_once(
"$monLibrary/ck_hticket.i");
20 require_once(
"$monLibrary/cu_pass.i");
21 require_once(
"$monLibrary/monitorView.i");
23 if (!CheckPerm($link, $Hu, basename($_SERVER[
'SCRIPT_NAME']), $_SERVER[
'REMOTE_ADDR'])) {
25 header(
"Location: /hcuadm/hcu_noperm.prg");
29 printMonitorPageTop(
"CU Features", $homecuKendoVersion, $cloudfrontDomainName, $bootstrapVersion, $fontawesomeVersion,
true);
30 printMonitorPageMiddle(
"CU Features",
null);
33 <!-- JAVASCRIPT CONTENT -->
34 <script type=
"text/javascript">
36 var flGridSource =
null;
37 var flGridView =
null;
40 var flDropdownSource =
null;
41 var flDropdownAction =
null;
42 var flDropdownActionStack = [];
44 var flWindowObserve =
null;
45 var flWindowEditView =
null;
47 var flDialogChanges =
null;
48 var flDialogDelete =
null;
50 var flButtonAdd =
null;
51 var flValidator =
null;
54 function ClearFeatureInformation() {
57 flInfoBar.css(
"display",
"none");
60 function ShowFeatureInfo(info, sql, status) {
64 textInfo = info || [];
67 for (var i = 0; i < textInfo.length; i++) {
71 for (var i = 0; i < textSql.length; i++) {
75 if (text ==
"") {
return; }
78 flInfoBar.addClass(
"k-success-colored");
80 flInfoBar.addClass(
"k-error-colored");
84 flInfoBar.css(
"display",
"block");
87 function ValidateFeatureRequired(element) {
90 var reqrInput = $(element);
91 var reqrValue = reqrInput.val();
93 if (reqrValue.length == 0) { pass =
false; }
98 function ValidateFeatureDesc(element) {
101 var descInput = $(element);
102 var descValue = descInput.val();
103 descValue = descValue.trim();
105 if (descValue.length == 0) { pass =
false; }
110 function ValidateFeatureType(element) {
113 var typeInput = $(element);
114 var typeValue = typeInput.val();
116 if (typeValue ==
"") { pass =
false; }
121 function ValidateFeatureCode(element) {
124 var codeInput = $(element);
125 var codeValue = codeInput.val();
126 var sourceIndex = flWindowObserve.sourceIndex;
127 var sourceFeature = flWindowObserve.sourceFeature;
129 for (var i = 0; i < flGridData.length; i++) {
131 var feature = flGridData[i];
132 var featureCode = feature.featureCode;
134 if (i == sourceIndex) {
continue; }
135 if (featureCode == codeValue) { pass =
false;
break; }
141 function FeatureSort(data) {
143 if (data.length < 2) {
147 var middle = Math.floor(data.length / 2);
148 var right = data.slice(middle, data.length);
149 var left = data.slice(0, middle);
151 var leftSort = FeatureSort(left);
152 var rightSort = FeatureSort(right);
154 return FeaturSortMerge(leftSort, rightSort);
157 function FeaturSortMerge(left, right) {
161 while (left.length && right.length) {
162 if (left[0].featureCode < right[0].featureCode) {
163 merge.push(left.shift());
165 merge.push(right.shift());
169 while (left.length) {
170 merge.push(left.shift());
173 while (right.length) {
174 merge.push(right.shift());
180 function DataSourceFindFeature(
id) {
183 var dataId =
id.replace(/[
"']/g, ""); 185 for (var i = 0; i < flGridData.length; i++) { 187 if (flGridData[i].featureCode == dataId) { 197 function StackRemoveFeature(id) { 199 var featureCode = id.substring(4, id.length); 201 for (var i = 0; i < flDropdownActionStack.length; i++) { 203 var feature = flDropdownActionStack[i]; 204 if (feature.featureCode == featureCode) { 206 flDropdownActionStack.splice(i, 1); 212 function StackInsertFeature(id) { 214 var featureCode = id.substring(4, id.length); 215 var featureIndex = DataSourceFindFeature(featureCode); 216 var feature = flGridData[featureIndex]; 218 flDropdownActionStack.push(feature); 221 function ResetObserve() { 222 flWindowObserve.sourceFeature = null; 223 flWindowObserve.sourceDirty = false; 224 flWindowObserve.sourceIndex = null; 225 flWindowObserve.sourceField = false; 226 flWindowObserve.sourceLabel = false; 229 function EventEnableCheckboxes(enable) { 231 for (var i = 0; i < flDropdownActionStack.length; i++) { 233 var feature = flDropdownActionStack[i]; 234 var featureCode = feature.featureCode; 236 var boxId = "chk_
" + featureCode; 237 var box = $("input[
id=
" + boxId + "]
"); 239 box.prop("checked
", enable); 243 flDropdownActionStack = []; 247 function EventDeleteConfirm(e) { 251 function EventDeleteDeny(e) { 252 flDropdownAction.select(0); 255 function EventChangeConfirm(e) { 256 flWindowEditView.close(); 257 flGridView.dataSource.cancelChanges(); 260 function EventFeatureSave(e) { 262 if (flValidator.validate()) { 264 var feature = flWindowObserve.sourceFeature; 265 var featureCode = feature.featureCode; 266 var featureDescription = feature.featureDescription; 267 var featureLimit = feature.featureLimit; 268 var featureIndex = flWindowObserve.sourceIndex; 270 var requestFeature = { 271 featureCode: feature.featureCode, 272 featureDescription: feature.featureDescription, 273 featureLimit: feature.featureLimit 276 if (featureIndex == -1) { 277 requestFeature.action = "feature_create
"; 279 requestFeature.action = "feature_edit
"; 282 flGridSource.transport.options.read.type = "POST
"; 283 flGridSource.read(requestFeature); 285 flWindowEditView.close(); 289 function EventFeatureAdd(e) { 291 var dataItem = flGridView.dataSource.add(); 292 EventOpenEditWindow(dataItem, "Add
"); 295 function EventOpenEditWindow(data, action) { 297 var featureIndex = DataSourceFindFeature(data.featureCode); 299 flWindowObserve.set("sourceFeature
", data); 300 flWindowObserve.set("sourceDirty
", false); 301 flWindowObserve.set("sourceIndex
", featureIndex); 303 if (featureIndex == -1) { 304 flWindowObserve.sourceField = true; 305 flWindowObserve.sourceLabel = false; 307 flWindowObserve.sourceField = false; 308 flWindowObserve.sourceLabel = true; 311 kendo.bind("#wndFeatureMnt
", flWindowObserve); 312 kendo.bind("#wndFeatureConfirm
", flWindowObserve); 314 flWindowEditView.title(action + " Feature
"); 315 flWindowEditView.center(); 316 flWindowEditView.open(); 319 function EventUpdateFeatureActions() { 321 var showEnable = false; 322 var showDisable = false; 324 flDropdownSource.data([]); 325 if (flDropdownActionStack.length == 0) { 327 flDropdownAction.enable(false); 331 flDropdownAction.enable(true); 333 for (var i = 0; i < flDropdownActionStack.length; i++) { 335 var feature = flDropdownActionStack[i]; 336 var featureEnabled = feature.featureEnabled; 338 if (featureEnabled) { showDisable = true; } 339 else { showEnable = true; } 342 var featureActions = []; 343 featureActions.push({ text: "Select Action
", value: "" }); 344 if (showEnable && showDisable) { showEnable = false; showDisable = false; } 345 if (showEnable) { featureActions.push({ text: "Enable
", value: "feature_enable
" }); } 346 if (showDisable) { featureActions.push({ text: "Disable
", value: "feature_disable
" }); } 347 featureActions.push({ text: "Delete
", value: "feature_delete
" }); 349 flDropdownSource.data(featureActions); 350 flDropdownAction.select(0); 353 function EventFeatureActionChange(e) { 355 var featureAction = e.sender.value(); 356 var featureCodes = ""; 358 for (var i = 0; i < flDropdownActionStack.length; i++) { 360 featureCodes += flDropdownActionStack[i].featureCode; 361 if (i < flDropdownActionStack.length - 1) { 366 var requestUpdate = { 367 action: featureAction, 368 featureList: featureCodes 371 flGridSource.transport.options.read.type = "POST
"; 372 flGridSource.transport.options.read.data = requestUpdate; 375 if (featureAction == "feature_delete
") { 376 var fl_dialog_string = "<p>Your are about to
delete the following feature(s):</p><p>(
" + featureCodes + ")</p><p>Do you wish to
continue?</p>
"; 377 flDialogDelete.content(fl_dialog_string); 378 flDialogDelete.open(); 385 function EventFeatureActionClose(e) { 387 var elem = e.sender.element[0].parentElement.firstChild; 388 $(elem).removeClass("k-state-focused
"); 391 function EventCheckboxChange(e, source) { 394 var boxId = box.attr("id"); 395 var boxValue = box.prop("checked
"); 398 if (source == "BOX
") { 399 boxValue = !boxValue; 404 StackRemoveFeature(boxId); 407 StackInsertFeature(boxId); 410 box.prop("checked
", !boxValue); 411 EventUpdateFeatureActions(); 414 function EventGridDataBind(e) { 416 $("html .k-grid td
").css("border-right
", "0
"); 417 $("html .k-grid td
").css("border-left
", "0
"); 419 $("html .k-grid th
").css("border-right
", "0
"); 420 $("html .k-grid th
").css("border-left
", "0
"); 422 $("html .k-grid tr
").hover(function() { 423 $(this).css("cursor
", "pointer
"); 426 $('input[id^=chk_]').change(function(e) { 427 EventCheckboxChange(e.target, "BOX
"); 430 EventEnableCheckboxes(true); 433 function EventGridChange(e) { 435 var cell = this.select(); 436 var cellIndex = cell.index(); 438 if (cellIndex == 1) { 440 var box = cell.find("input[
id^=\
"chk_\"]")[0];
441 EventCheckboxChange(box,
"ROW");
444 var dataSource = this.dataSource;
445 var dataIndex = cell.closest(
"tr").index(
".k-master-row");
446 var dataItem = dataSource.view()[dataIndex];
448 EventOpenEditWindow(dataItem,
"Edit");
451 $(this.select()).removeClass(
'k-state-selected');
454 function InitDataActions() {
455 flDropdownAction = $(
"#drpActions").kendoDropDownList({
456 dataSource: flDropdownSource,
457 dataTextField:
"text",
458 dataValueField:
"value",
459 change: EventFeatureActionChange,
460 close: EventFeatureActionClose,
462 }).data(
"kendoDropDownList");
464 flButtonAdd = $(
"#btnAdd").kendoButton({
465 click: EventFeatureAdd
469 function InitDataViews() {
470 flGridView = $(
"#grdFeatureLst").kendoGrid({
477 featureCode: { type:
"string" },
478 featureDescription: { type:
"string" },
479 featureLimit: { type:
"string" },
480 featureEnabled: { type:
"boolean" }
485 rowTemplate: kendo.template($(
"#templateGridRow").html()),
486 dataBound: EventGridDataBind,
487 change: EventGridChange,
491 { title:
"", width:
"3px" },
492 { title:
"", width:
"25px" },
493 { title:
"Code", width:
"100px" },
494 { title:
"Description" },
495 { title:
"Limit Type", width:
"75px" }
497 }).data(
"kendoGrid");
499 flWindowObserve =
new kendo.observable({
506 { text:
"Choose Limit Type", value:
"" },
507 { text:
"Access Allowed", value:
"A" },
508 { text:
"Quantity", value:
"Q" },
509 { text:
"Dollar", value:
"D" },
510 { text:
"Quantity & Dollar", value:
"B" }
512 clickSave: EventFeatureSave,
513 changeCode:
function(e) { this.sourceDirty =
true;
514 var element = $(e.target);
515 var value = element.val();
516 value = value.toUpperCase();
518 if (RegExp(/[@#\\!$%^&*()+|~=`{}\[\]:
";'<>?,.\/]/).test(value)) { 519 value = value.slice(0, -1); 523 this.sourceFeature.featureCode = value; 525 changeDesc: function(e) { this.sourceDirty = true; }, 526 changeLimit: function(e) { this.sourceDirty = true; 528 var element = e.sender.element[0]; 533 flWindowEditView = $("#wndFeatureMnt
").kendoWindow({ 539 activate: function(e) { 540 $("#wndFeatureMnt span.k-tooltip-validation
").hide(); 541 $("#wndFeatureMnt #inpCode
").focus(); 545 if (e.userTriggered) { 547 if (flWindowObserve.sourceDirty) { 549 flDialogChanges.open(); 551 flGridView.dataSource.cancelChanges(); 552 flWindowEditView.close(); 557 }).data("kendoWindow
"); 559 flDialogDelete = $("#dialogDelete
").kendoDialog({ 560 title: "Delete Feature(s)
", 565 action: EventDeleteDeny 568 text: "Yes
", primary: true, 569 action: EventDeleteConfirm 572 }).data("kendoDialog
"); 574 flDialogChanges = $("#dialogChanges
").kendoDialog({ 575 title: "Discard Changes
", 576 content: "<p>Changes have been made to
this feature.</p><p>Do you wish to discard your changes?</p>
", 583 text: "Yes
", primary: true, 584 action: EventChangeConfirm 587 }).data("kendoDialog
"); 589 flValidator = $("#wndFeatureMnt
").kendoValidator({ 591 code: ValidateFeatureCode, 592 desc: ValidateFeatureDesc, 593 type: ValidateFeatureType, 594 required: ValidateFeatureRequired 596 }).data("kendoValidator
"); 598 flInfoBar = $("#featureInfoBar
"); 601 function InitDataSources() { 602 flDropdownSource = new kendo.data.DataSource({ 606 flGridSource = new kendo.data.DataSource({ 609 url: "mFeature.data
", 611 contentType: "application/x-www-form-urlencoded
", 614 action: "feature_read
" 619 requestStart: function(response) { 621 ClearFeatureInformation(); 623 requestEnd: function(response) { 626 if (response.hasOwnProperty("response
")) { 628 if (response.response.hasOwnProperty("Results
")) { 630 var results = response.response.Results; 631 if (results.hasOwnProperty("errors
")) { 633 throw results.errors; 636 ShowFeatureInfo(results.info, results.sql, true); 640 throw "Error Parsing Server
"; 644 throw "Error Parsing Server
"; 648 ShowFeatureInfo(error, null, false); 651 EventEnableCheckboxes(false); 652 EventUpdateFeatureActions(); 656 parse: function(response) { 657 var results = response.Results; 658 var resultData = results.data; 659 var resultAction = results.action; 661 if (resultData == undefined || resultData == null) { 665 if (results.hasOwnProperty("errors
")) { 669 if (resultAction == "feature_read
") { 671 flGridData = resultData; 674 for (var i = 0; i < resultData.length; i++) { 676 var feature = resultData[i]; 677 var featureCode = feature.featureCode; 678 var featureIndex = DataSourceFindFeature(featureCode); 680 if (resultAction == "feature_create
") { 681 flGridData.splice(0, 0, feature); 682 } else if (resultAction == "feature_delete
") { 683 flGridData.splice(featureIndex, 1); 685 flGridData.splice(featureIndex, 1, feature); 691 // SET DATA TO GRID IF NO ERRORS 692 flGridData = FeatureSort(flGridData); 693 flGridView.dataSource.data(flGridData); 702 $(document).ready(function() { 710 $(document).on('click', '.k-overlay', function() { 711 if (flWindowObserve.sourceDirty) { 712 flDialogChanges.open(); 714 flGridView.dataSource.cancelChanges(); 715 flWindowEditView.close(); 718 flDialogDelete.close(); 719 flDropdownAction.select(0); 723 <!-- HTML STYLING --> 724 <style type="text/css
"> 726 /* TOP/BOTTOM MARGIN */ 727 .hcu-container-margin { 744 background: rgb(255 , 215, 0); 752 .k-menu .k-item > .k-link { 753 padding: .5em 1.1em .4em; 760 .k-grid > table > tbody > tr:hover, 761 .k-grid-content > table > tbody > tr:hover { 762 background-color: #ddd; 767 <!-- HTML CONTENT --> 768 <div class="container-fluid hcu-max-width
"> 770 <!-- INFORMATION / ERROR --> 771 <div id="featureInfoBar
" class="well well-sm col-sm-12
" style="display: none; white-space: pre;
"> 778 <div class="well well-sm col-sm-12
"> 781 <div class="col-sm-12 hcu-no-padding
"> 782 <h3>Feature List</h3> 786 <div class="col-sm-12 hcu-no-padding hcu-container-margin
"> 788 <div class="col-sm-3
"> 789 <button id="btnAdd
" class="hcu-full-width
"> 790 <span class="fa fa-plus
"></span> 791 <span>Add Feature</span> 796 <div class="col-sm-3
"> 797 <input id="drpActions
" class="hcu-full-width
"> 801 <!-- LIST CONTENT --> 802 <div class="col-sm-12 hcu-container-margin
"> 805 <div id="grdFeatureLst
"></div> 811 <div id="homecuSubmitWait
"></div> 813 <!-- TEMPLATE: GRID ROW --> 814 <script type="text/x-kendo-
template" id="templateGridRow
"> 815 <tr class="k-master-row
" data-uid='#= uid #'> 816 # if (featureEnabled) { # 819 <td class="hcu-disabled
"></td> 823 <input type="checkbox
" id="chk_#= featureCode #
" 824 style="margin-top: -2px; cursor: pointer;
"> 826 <td>#= featureCode #</td> 827 <td>#= featureDescription #</td> 828 # if (featureLimit == 'B') { # 831 <td>#= featureLimit #</td> 836 <div id="wndFeatureMnt
" class="hcu-hidden
"> 838 <div class="well well-sm
"> 840 <div class="col-sm-12 hcu-no-padding hcu-container-margin
"> 841 <!-- FEATURE CODE --> 842 <div class="col-sm-12 hcu-no-padding
"> 844 <span class="k-invalid-msg
" data-for="inpCode
"></span> 846 <span data-bind="visible: sourceLabel, text: sourceFeature.featureCode
"></span> 849 <div class="col-sm-12 hcu-no-padding
"> 850 <input id="inpCode
" class="hcu-full-width k-textbox
" name="inpCode
" maxlength="10
" 851 data-bind="value: sourceFeature.featureCode,
852 visible: sourceField,
853 events: { input: changeCode}
" 855 data-code-msg="Feature Code Exists
" 856 data-required-msg="Feature Code is Empty
" 858 style="padding-left: 0px;
"> 862 <div class="col-sm-12 hcu-no-padding hcu-container-margin
"> 863 <!-- FEATURE DESCRIPTION --> 864 <div class="col-sm-12 hcu-no-padding
"> 865 <label>Description:</label> 866 <span class="k-invalid-msg
" data-for="inpDescription
"></span> 869 <div class="col-sm-12 hcu-no-padding
"> 870 <textarea id="inpDescription
" class="hcu-full-width k-textbox
" name="inpDescription
" 871 rows="5
" maxlength="100
" 872 data-bind="value: sourceFeature.featureDescription,
873 events: { input: changeDesc }
" 874 data-desc="#inpDescription
" 875 data-desc-msg="Feature Description is Empty
" 876 data-required-msg="Feature Description is Empty
" 878 style="padding-left: 10px;
"> 883 <div class="col-sm-12 hcu-no-padding hcu-container-margin
"> 884 <!-- FEATURE LIMIT TYPE --> 885 <div class="col-sm-12 hcu-no-padding
"> 886 <label>Limit Type:</label> 887 <span class="k-invalid-msg
" data-for="inpLimit
"></span> 890 <div class="col-sm-12 hcu-no-padding
"> 891 <input id="inpLimit
" class="hcu-full-width
" name="inpLimit
" 892 data-role="dropdownlist
" 893 data-text-field="text
" 894 data-value-field="value
" 895 data-bind="source: sourceLimits,
896 value: sourceFeature.featureLimit,
897 events: { change: changeLimit }
" 898 data-type="#inpLimit
" 899 data-type-msg="Choose Feature Limit Type
" 900 data-required-msg="Choose Feature Limit Type
" 905 <!-- CLEAR FOR POP UP WINDOW --> 906 <div style="clear: both;
"></div> 910 <div class="col-sm-3 hcu-no-padding
"></div> 911 <div class="col-sm-6 hcu-no-padding
"> 912 <button id="btnSave
" class="hcu-full-width k-button k-primary
" 913 data-bind="events: { click: clickSave }
"> 914 <span class="fa fa-check
"></span> 918 <div class="col-sm-3 hcu-no-padding
"></div> 921 <div id="wndFeatureConfirm
" class="hcu-hidden
"> 923 <div class="well well-sm
"> 925 <div class="col-sm-12 hcu-no-padding
"> 926 <span>This feature has been changed, do you wish to discard your changes?</span> 929 <!-- CLEAR FOR POP UP WINDOW --> 930 <div style="clear: both;
"></div> 934 <div class="col-sm-5 hcu-no-padding
"> 935 <button id="btnConfirm
" class="hcu-full-width k-button k-primary
" 936 data-bind="events: { click: clickConfirm }
"> 941 <div class="col-sm-2 hcu-no-padding
"></div> 944 <div class="col-sm-5 hcu-no-padding
"> 945 <button id="btnConfirm
" class="hcu-full-width k-button
" 946 data-bind="events: { click: clickDeny }
"> 952 <div id="dialogChanges
"></div> 953 <div id="dialogDelete
"></div> 956 printMonitorPageBottom();