Odyssey
aProfileLst.prg
1 <?php
2 /**
3  * @package aProfileLst.prg
4  *
5  * Purpose: Handle display and user interface for the Profile/Profile Feature, feature in Admin/Monitor. Send data via AJAX as JSON
6  * encoded data.
7  *
8  * Display : Show list of profiles for the credit union along with a filtered list of limited features
9  * for those profiles.
10  * Actions : User interface actions available for creating/editting/deleting profiles and profile features
11  * - Add Profile : create new profile for use by the credit union
12  * - Edit Profile : edit existing profile descriptions
13  * - Delete Profile : delete a profile from use by the credit union
14  * - Add feature : create a feature limit for a selected profile
15  * - Edit feature : edit existing features in a selected profile
16  * - Delete feature : remove feature from an existing profile
17  */
18 define("FEATURE_LIMIT_MAX_VALUE", "Set to No Limit");
19 define("FEATURE_LIMIT_MIN_VALUE", "Set to 0");
20 ?>
21 
22 <!-- HTML STYLING -->
23 <style type="text/css">
24 /* TOP/BOTTOM MARGIN */
25 .local-hcu-container-margin {
26  margin: 15px 0;
27 }
28 
29 .local-hcu-no-padding {
30  padding: 0;
31 }
32 
33 .local-hcu-full-width {
34  width: 100%;
35 }
36 
37 .local-hcu-half-width {
38  width: 50%;
39 }
40 
41 .local-hcu-quarter-width {
42  width: 25%;
43 }
44 
45 .local-hcu-hidden {
46  display: none;
47 }
48 
49 .local-hcu-max-width {
50  max-width: 700px;
51  margin: auto;
52 }
53 
54 .local-hcu-nowrap {
55  white-space: nowrap;
56 }
57 
58 .local-hcu-nowrap br {
59  display: none;
60 }
61 
62 .k-grid-content {
63  max-height: 350px;
64 }
65 </style>
66 
67 <!-- GRID ROW TEMPLATE -->
68 <script type="text/x-kendo-template" id="templateGridRow">
69  <tr class="k-master-row">
70  # if (pId == 0) { #
71  <td><span class="fa fa-plus" style="background-color: transparent;"></span></td>
72  <td colspan="2">Add New Limit</td>
73  # } else { #
74  <td><input type="checkbox" class="feature-checkbox" id="chk_#=fCode#"></td>
75  <td>
76  <span class="local-hcu-nowrap">#= fDesc #</span>
77  </td>
78  <td>
79  <span class="local-hcu-nowrap">
80  # if (fType == "B" || fType == "D") { #
81  # if (fApt >= FEATURE_LIMIT_MAX_AMOUNT || fApt == null) { #
82  Amount per transaction: No Limit, <br>
83  # } else { #
84  Amount per transaction: #= kendo.toString(fApt, "c2") #, <br>
85  # } #
86 
87  # if (fApa >= FEATURE_LIMIT_MAX_AMOUNT || fApa == null) { #
88  Amount per account per day: No Limit, <br>
89  # } else { #
90  Amount per account per day: #= kendo.toString(fApa, "c2") #, <br>
91  # } #
92 
93  # if (fApd >= FEATURE_LIMIT_MAX_AMOUNT || fApd == null) { #
94  Amount per day: No Limit, <br>
95  # } else { #
96  Amount per day: #= kendo.toString(fApd, "c2") #, <br>
97  # } #
98 
99  # if (fApm >= FEATURE_LIMIT_MAX_AMOUNT || fApm == null) { #
100  Amount per month: No Limit, <br>
101  # } else { #
102  Amount per month: #= kendo.toString(fApm, "c2") #, <br>
103  # } #
104  # } #
105 
106  # if (fType == "B" || fType == "Q") { #
107  # if (fCpa >= FEATURE_LIMIT_MAX_COUNT || fCpa == null) { #
108  Count per account per day: No Limit, <br>
109  # } else { #
110  Count per account per day: #= kendo.toString(fCpa, "n0") #, <br>
111  # } #
112 
113  # if (fCpd >= FEATURE_LIMIT_MAX_COUNT || fCpd == null) { #
114  Count per day: No Limit, <br>
115  # } else { #
116  Count per day: #= kendo.toString(fCpd, "n0") #, <br>
117  # } #
118 
119  # if (fCpm >= FEATURE_LIMIT_MAX_COUNT || fCpm == null) { #
120  Count per month: No Limit, <br>
121  # } else { #
122  Count per month: #= kendo.toString(fCpm, "n0") #, <br>
123  # } #
124  # } #
125 
126  # if (fType == "A") { #
127  Access Allowed<br>
128  # } #
129 
130  # if (fType == "B" || fType == "D" ) { #
131  # if (fCfm) { #
132  Confirmation Required: Yes
133  # } else { #
134  Confirmation Required: No
135  # } #
136  # } #
137 
138  </span>
139  </td>
140  # } #
141  </tr>
142 </script>
143 
144 <!-- HTML CONTENT -->
145 <div class="container-fluid">
146 
147  <!-- CONTENT -->
148  <div class="well well-sm col-sm-12 local-hcu-container-margin" id="profileView" style="max-width: 768px;">
149 
150  <div class="col-sm-12 local-hcu-no-padding">
151  <h2>Profiles</h2>
152  </div>
153 
154  <div class="col-sm-9 local-hcu-no-padding">
155 
156  <div class="col-sm-6 local-hcu-container-margin">
157  <label>&nbsp;</label>
158 
159  <input class="local-hcu-full-width" id="inpProfileList" name="inpProfileList">
160  </div>
161 
162  <div class="col-sm-6 local-hcu-container-margin">
163  <label>Profile Code</label>
164  <input class="local-hcu-full-width k-textbox" id="inpProfileCode" name="inpProfileCode" maxlength="20"
165  data-pcode="#inpProfileCode"
166  data-pcode-msg="Profile Code already exists"
167  data-required-msg="Profile Code is required"
168  required>
169  </div>
170 
171  <div class="col-sm-12">
172  <label>Profile Description</label>
173  <input class="local-hcu-full-width k-textbox" id="inpProfileDesc" name="inpProfileDesc" maxlength="255"
174  data-required-msg="Profile Description is required"
175  required>
176  </div>
177  </div>
178 
179  <div class="col-sm-3 local-hcu-no-padding">
180 
181  <div class="col-sm-12 local-hcu-container-margin">
182  <label>&nbsp;</label>
183  <button class="local-hcu-full-width k-button k-primary" id="btnProfileSave">
184  <span class="fa fa-check"></span>
185  <span>&nbsp;Save</span>
186  </button>
187  </div>
188 
189  <div class="col-sm-12">
190  <label>&nbsp;</label>
191  <button class="local-hcu-full-width k-button" id="btnProfileDelete">
192  <span class="fa fa-times"></span>
193  <span>&nbsp;Delete</span>
194  </button>
195  </div>
196  </div>
197  </div>
198 
199  <div class="well well-sm col-sm-12 local-hcu-container-margin" style="max-width: 768px;">
200 
201  <!-- HEADER -->
202  <div class="col-sm-12 local-hcu-no-padding">
203  <h3>Profile Features</h3>
204  </div>
205 
206  <div class="col-sm-3 local-hcu-container-margin">
207  <button class="local-hcu-full-width k-button" id="btnLimitDelete">
208  <span class="fa fa-times"></span>
209  <span>&nbsp;Delete</span>
210  </button>
211  </div>
212 
213  <div class="col-sm-3 local-hcu-container-margin">
214  <button class="local-hcu-full-width k-button" id="btnLimitExpand">
215  <span class="fa fa-expand"></span>
216  <span> &nbsp;Expand All</span>
217  </button>
218  </div>
219 
220  <div class="col-sm-12 local-hcu-container-margin">
221  <div class="" id="grdProfileLimits"></div>
222  </div>
223  </div>
224 </div>
225 
226 <div class="local-hcu-hidden" id="wndProfileLimit">
227 
228  <div class="">
229  <input id="drpCodes" name="drpCodes" class="" style="min-width: 25%; width: auto;"
230  data-role="dropdownlist"
231  data-text-field="fDesc"
232  data-value-field="fCode"
233  data-bind="source: sourceFeatures,
234  visible: showDrop,
235  value: sourceLimit.eCode,
236  events: { change: changeFeature }"
237  >
238  </div>
239 
240  <br data-bind="visible: showDrop">
241 
242  <div class="well well-sm" id="viewAmount" data-bind="visible: showAmount">
243 
244  <div class="col-sm-12 local-hcu-no-padding">
245  <h3>Amount Limits Per</h3><br>
246  </div>
247 
248  <div class="col-sm-3">
249  <div class="">
250  <label><i>Transaction</i></label>
251  <span class="k-invalid-msg" data-for="inpApt"></span>
252  </div>
253  <div class="">
254  <input class="local-hcu-full-width" id="inpApt" name="inpApt" maxlength=""
255  data-role="numerictextbox"
256  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
257  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
258  data-format="c"
259  data-min="0"
260  data-max="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
261  data-step="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
262  data-bind="value: sourceLimit.eApt, events: { spin: spinLimit }">
263  </div>
264  </div>
265 
266  <div class="col-sm-3">
267  <div class="">
268  <label><i>Account / Day</i></label>
269  <span class="k-invalid-msg" data-for="inpApa"></span>
270  </div>
271  <div class="">
272  <input class="local-hcu-full-width" id="inpApa" name="inpApa" maxlength=""
273  data-role="numerictextbox"
274  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
275  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
276  data-format="c"
277  data-min="0"
278  data-max="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
279  data-step="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
280  data-bind="value: sourceLimit.eApa, events: { spin: spinLimit }">
281  </div>
282  </div>
283 
284  <div class="col-sm-3">
285  <div class="">
286  <label><i>Day</i></label>
287  <span class="k-invalid-msg" data-for="inpApd"></span>
288  </div>
289  <div class="">
290  <input class="local-hcu-full-width" id="inpApd" name="inpApd" maxlength=""
291  data-role="numerictextbox"
292  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
293  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
294  data-format="c"
295  data-min="0"
296  data-max="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
297  data-step="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
298  data-bind="value: sourceLimit.eApd, events: { spin: spinLimit }">
299  </div>
300  </div>
301 
302  <div class="col-sm-3">
303  <div class="">
304  <label><i>Month</i></label>
305  <span class="k-invalid-msg" data-for="inpApm"></span>
306  </div>
307  <div class="">
308  <input class="local-hcu-full-width" id="inpApm" name="inpApm" maxlength=""
309  data-role="numerictextbox"
310  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
311  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
312  data-format="c"
313  data-min="0"
314  data-max="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
315  data-step="<?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>"
316  data-bind="value: sourceLimit.eApm, events: { spin: spinLimit }">
317  </div>
318  </div>
319 
320  <div style="clear: both;">&nbsp;</div>
321  </div>
322 
323  <br data-bind="visible: showAmount" id="viewAmountBr">
324 
325  <div class="well well-sm" id="viewCount" data-bind="visible: showCount">
326 
327  <div class="col-sm-12 local-hcu-no-padding">
328  <h3>Count Limits Per</h3> <br>
329  </div>
330 
331  <div class="col-sm-3">
332  <div class=""> </div>
333  <div class=""> </div>
334  </div>
335 
336  <div class="col-sm-3">
337  <div class="">
338  <label><i>Account / Day</i></label>
339  <span class="k-invalid-msg" data-for="inpCpa"></span>
340  </div>
341  <div class="">
342  <input class="local-hcu-full-width" id="inpCpa" name="inpCpa" maxlength=""
343  data-role="numerictextbox"
344  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
345  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
346  data-format="n0"
347  data-min="0"
348  data-max="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
349  data-step="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
350  data-bind="value: sourceLimit.eCpa, events: { spin: spinLimit }">
351  </div>
352  </div>
353 
354  <div class="col-sm-3">
355  <div class="">
356  <label><i>Day</i></label>
357  <span class="k-invalid-msg" data-for="inpCpd"></span>
358  </div>
359  <div class="">
360  <input class="local-hcu-full-width" id="inpCpd" name="inpCpd" maxlength=""
361  data-role="numerictextbox"
362  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
363  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
364  data-format="n0"
365  data-min="0"
366  data-max="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
367  data-step="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
368  data-bind="value: sourceLimit.eCpd, events: { spin: spinLimit }">
369  </div>
370  </div>
371 
372  <div class="col-sm-3">
373  <div class="">
374  <label><i>Month</i></label>
375  <span class="k-invalid-msg" data-for="inpCpm"></span>
376  </div>
377  <div class="">
378  <input class="local-hcu-full-width" id="inpCpm" name="inpCpm" maxlength=""
379  data-role="numerictextbox"
380  data-up-arrow-text="<?php echo FEATURE_LIMIT_MAX_VALUE; ?>"
381  data-down-arrow-text="<?php echo FEATURE_LIMIT_MIN_VALUE; ?>"
382  data-format="n0"
383  data-min="0"
384  data-max="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
385  data-step="<?php echo FEATURE_LIMIT_MAX_COUNT; ?>"
386  data-bind="value: sourceLimit.eCpm, events: { spin: spinLimit }">
387  </div>
388  </div>
389 
390  <div style="clear: both;">&nbsp;</div>
391  </div>
392 
393  <br data-bind="visible: showCount" id="viewCountBr">
394 
395  <div class="well well-sm" id="viewConfirm" data-bind="visible: showConfirm">
396  <div class="row hcu-secondary">
397  <div class="col-sm-12 vsgSecondary">
398  <span>Checking this box will require confirmation from another group user to process a transaction.</span>
399  </div>
400  </div>
401  <div class="row">&nbsp;</div>
402  <div class="row">
403  <div class="col-sm-3">
404  <label data-bind="events: { click: changeLabel }">Confirmation Required</label>
405  </div>
406  <div class="col-sm-3">
407  <input type="checkbox" class="" id="inpCfm" name="inpCfm" style="margin-top: -2px;"
408  data-bind="checked: sourceLimit.eCfm,
409  events: { change: changeCheck }">
410  <span data-bind="events: { click: changeLabel }"> Yes</span>
411  </div>
412  </div>
413  </div>
414 
415  <br data-bind="visible: showAccess" id="viewAccessBr">
416 
417  <div class="well well-sm" id="viewAccess" data-bind="visible: showAccess">
418  <div class="col-sm-12 local-hcu-no-padding">
419  <div class="col-sm-3 local-hcu-no-padding">
420  <label data-bind="">Access Allowed</label>
421  </div>
422  <div class="col-sm-9 local-hcu-no-padding">
423  <input type="checkbox" class="" id="inpCfm" name="inpCfm" style="margin-top: -2px;"
424  checked="true" disabled="true">
425  &nbsp;
426  <span><i>To remove access to this feature, delete it from the profile.</i></span>
427  </div>
428  </div>
429  </div>
430 
431  <br>
432 
433  <div class="col-sm-4"></div>
434  <div class="col-sm-4">
435  <button id="btnLimitSave" class="local-hcu-full-width k-button k-primary"
436  data-bind="events: { click: saveLimit }">
437  <span class="fa fa-check"></span>
438  <span>Save</span>
439  </button>
440  </div>
441  <div class="col-sm-4"></div>
442 
443  <div style="clear: both;"></div>
444 </div>
445 
446 <div id="dialogDiscardProfile"></div>
447 <div id="dialogDeleteProfile"></div>
448 <div id="dialogDeleteLimit"></div>
449 <div id="dialogWarningLimit"></div>
450 <div id="dialogDiscardLimit"></div>
451 
452 <!-- JAVASCRIPT CONTENT -->
453 <script type="text/javascript">
454 <?php getShowWaitFunctions(); ?>
455 
456 var FEATURE_LIMIT_MAX_AMOUNT = <?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>;
457 var FEATURE_LIMIT_MAX_COUNT = <?php echo FEATURE_LIMIT_MAX_COUNT; ?>;
458 var FEATURE_LIMIT_MIN_VALUE = "<?php echo FEATURE_LIMIT_MIN_VALUE; ?>";
459 var FEATURE_LIMIT_MAX_VALUE = "<?php echo FEATURE_LIMIT_MAX_VALUE; ?>";
460 
461 var activeElement = null;
462 var prInfoBar = null;
463 var prDataSource = null;
464 
465 var prDataProfiles = null;
466 var prDataProfileSelect = null;
467 var prDataProfileNext = null;
468 var prViewProfileSelect = false;
469 var prViewProfileDropdown = null;
470 var prViewProfileSave = null;
471 var prViewProfileDelete = null;
472 var prViewProfileCode = null;
473 var prViewProfileDesc = null;
474 var prViewProfileValidator = null;
475 
476 var prDataLimits = null;
477 var prDataLimitStack = null;
478 var prDataFeatures = null;
479 var prDataFeaturesFiltered = null;
480 var prViewLimitGrid = null;
481 var prViewLimitDelete = null;
482 var prViewLimitExpand = null;
483 var prViewLimitExpanded = false;
484 var prViewLimitWindow = null;
485 var prViewLimitWindowOpen = false;
486 var prObserveLimit = null;
487 var prObserveLimitValidator = null;
488 var prViewLimitAmount = null;
489 var prViewLimitCount = null;
490 var prViewLimitAmountBr = null;
491 var prViewLimitCountBr = null;
492 var prViewLimitConfirm = null;
493 var prViewLimitAccess = null;
494 
495 var prDataWindowStack = null;
496 var prViewDialogDiscardProfile = null;
497 var prViewDialogDeleteProfile = null
498 var prViewDialogDeleteLimit = null;
499 var prViewDialogDiscardLimit = null;
500 var prViewDialogWarningLimit = null;
501 
502 <?php
503 /*
504  * StackInsertLimit: When a checkbox of a grid row is CHECKED, this function will add the
505  * corresponding limit to the stack ready for deleting.
506  *
507  * var id: the id of the limit to insert
508  */
509 ?>
510 function StackInsertLimit(id) {
511 
512  if (id == "chk_0") { return; }
513 
514  var limitCode = id.substring(4, id.length);
515  var limitIndex = DataSourceFindLimit(limitCode, prDataProfileSelect.pId);
516  var limit = prDataLimits[limitIndex];
517 
518  prDataLimitStack.push(limit);
519 }
520 
521 <?php
522 /*
523  * StackRemoveLimit: When a checkbox of a grid row is UN-CHECKED, this function will remove the
524  * corresponding limit from the stack ready for deleting.
525  *
526  * var id: the id of the limit to remove
527  */
528 ?>
529 function StackRemoveLimit(id) {
530 
531  var limitCode = id.substring(4, id.length);
532  for (var i = 0; i < prDataLimitStack.length; i++) {
533 
534  var limit = prDataLimitStack[i];
535  if (limit.fCode == limitCode) {
536 
537  prDataLimitStack.splice(i, 1);
538  break;
539  }
540  }
541 }
542 
543 <?php
544 /*
545  * ValidateProfileCode: validation for profile_code,
546  * This function will see if the new profile code already exists
547  */
548 ?>
549 function ValidateProfileCode(e) {
550 
551  var pass = true;
552  var input = $(e);
553  var value = input.val();
554  value = value.trim();
555  value = value.toUpperCase();
556 
557  for (var i = 0; i < prDataProfiles.length; i++) {
558 
559  var pCode = prDataProfiles[i].pCode;
560  if (pCode == value) { pass = false; break; }
561  }
562 
563  return pass;
564 }
565 
566 function ValidateProfileRequired(e) {
567  var pass = true;
568  var input = $(e);
569  var value = input.val();
570  value = value.trim();
571 
572  if (value == "") { pass = false; }
573 
574  return pass;
575 }
576 
577 <?php
578 /*
579  * DataSourceFindFeature: find the feature in the feature datasource,
580  *
581  * var fCode: code to find
582  */
583 ?>
584 function DataSourceFindFeature(fCode) {
585 
586  var idx = -1;
587  for (var i = 0; i < prDataFeatures.length; i++) {
588 
589  if (prDataFeatures[i].fCode == fCode) {
590  idx = i;
591  }
592  }
593 
594  return idx;
595 }
596 
597 <?php
598 /*
599  * DataSourceFilterFeatures: filter the features for a new limit creation,
600  * only show features that are not used by the selected profile.
601  */
602 ?>
603 function DataSourceFilterFeatures() {
604 
605  prDataFeaturesFiltered = [];
606 
607  prDataFeaturesFiltered.push({
608  fId: -1,
609  fCode: "",
610  fDesc: "Choose Feature",
611  fType: "N",
612  fEnabled: false
613  });
614 
615  for (var i = 0; i < prDataFeatures.length; i++) {
616 
617  var lidx = DataSourceFindLimit(prDataFeatures[i].fCode, prDataProfileSelect.pId);
618  if (lidx == -1) {
619 
620  prDataFeaturesFiltered.push(prDataFeatures[i]);
621  }
622  }
623 
624  <?php // Only features in the CU feature menu. Cannot filter at the data level because limits are dependent on that data for the feature type. ?>
625  prDataFeaturesFiltered = $.grep(prDataFeaturesFiltered, function(n, i) {
626  return n.cuexists || n.fDesc == "Choose Feature";
627  });
628 }
629 
630 <?php
631 /*
632  * DataSourceBuildFeatures: restructure the features datasource for use in javascript
633  *
634  * var data: source array of features from the database
635  */
636 ?>
637 function DataSourceBuildFeatures(data) {
638 
639  for (var i = 0; i < data.length; i++) {
640 
641  var newFeature = {
642  fId: i,
643  fCode: data[i].fcode.trim(),
644  fDesc: data[i].fdesc.trim(),
645  fType: data[i].ftype.trim(),
646  fEnabled: data[i].fenabled == "t" ? true : false,
647  cuexists: data[i].cuexists == "t" ? true : false
648  };
649 
650  prDataFeatures.push(newFeature);
651  }
652 }
653 
654 <?php
655 /*
656  * DataSourceBuildLimits: restructure the limits data source array for use in javascript functions
657  * and display.
658  * The function adds duplicate fields inorder to easily tell if changes have been made.
659  *
660  * f = original values
661  * e = edited value
662  *
663  * var data: source array of limit data from database
664  */
665 ?>
666 function DataSourceBuildLimits(data) {
667  for (var i = 0; i < data.length; i++) {
668 
669  var newLimit = {
670  pId: parseInt(data[i].pid),
671  fCode: data[i].fcode.trim(),
672  fDesc: data[i].fdesc.trim(),
673  fApt: data[i].fapt == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapt),
674  fApd: data[i].fapd == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapd),
675  fApm: data[i].fapm == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapm),
676  fApa: data[i].fapa == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapa),
677  fCpd: data[i].fcpd == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpd),
678  fCpm: data[i].fcpm == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpm),
679  fCpa: data[i].fcpa == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpa),
680  fCfm: data[i].fcfm == "t" ? true : false,
681  fType: data[i].ftype.trim(),
682  fDirty: false,
683  eCode: data[i].fcode.trim(),
684  eDesc: data[i].fdesc.trim(),
685  eApt: data[i].fapt == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapt),
686  eApd: data[i].fapd == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapd),
687  eApm: data[i].fapm == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapm),
688  eApa: data[i].fapa == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(data[i].fapa),
689  eCpd: data[i].fcpd == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpd),
690  eCpm: data[i].fcpm == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpm),
691  eCpa: data[i].fcpa == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(data[i].fcpa),
692  eCfm: data[i].fcfm == "t" ? true : false
693  };
694 
695  prDataLimits.push(newLimit);
696  }
697 
698  prDataLimits.push({
699  pId: 0,
700  fCode: "",
701  fDesc: "",
702  fApt: FEATURE_LIMIT_MAX_AMOUNT,
703  fApd: FEATURE_LIMIT_MAX_AMOUNT,
704  fApm: FEATURE_LIMIT_MAX_AMOUNT,
705  fApa: FEATURE_LIMIT_MAX_AMOUNT,
706  fCpd: FEATURE_LIMIT_MAX_COUNT,
707  fCpm: FEATURE_LIMIT_MAX_COUNT,
708  fCpa: FEATURE_LIMIT_MAX_COUNT,
709  fCfm: false,
710  fDirty: false,
711  fType: "",
712  eCode: "",
713  eDesc: "",
714  eApt: FEATURE_LIMIT_MAX_AMOUNT,
715  eApd: FEATURE_LIMIT_MAX_AMOUNT,
716  eApm: FEATURE_LIMIT_MAX_AMOUNT,
717  eApa: FEATURE_LIMIT_MAX_AMOUNT,
718  eCpd: FEATURE_LIMIT_MAX_COUNT,
719  eCpm: FEATURE_LIMIT_MAX_COUNT,
720  eCpa: FEATURE_LIMIT_MAX_COUNT,
721  eCfm: false
722  });
723 }
724 
725 <?php
726 /*
727  * DataSourceFindLimit: find a specific limit in the limit datasource
728  *
729  * var fCode: find limit by this code, multipl codes may be found
730  * var pId: find limit by the profile association to limit the result to sinlge entry
731  */
732 ?>
733 function DataSourceFindLimit(fCode, pId) {
734  var idx = -1;
735  for (var i = 0; i < prDataLimits.length; i++) {
736 
737  if (prDataLimits[i].fCode == fCode && prDataLimits[i].pId == pId) {
738  idx = i;
739  break;
740  }
741  }
742 
743  return idx;
744 }
745 
746 <?php
747 /*
748  * DataSourceInsertLimit: insert a new or edited limit into the limit datasource in alpha order
749  * New limits will be added without removing any others.
750  * Edited limits will be inserted by removing the old version and replaced with the edited version.
751  *
752  * var limit: limit to insert
753  * var remove: determine if limit will be inserted without removing the current placeholder
754  */
755 ?>
756 function DataSourceInsertLimit(limit, remove) {
757  var fidx = DataSourceFindFeature(limit.fcode);
758  var feature = prDataFeatures[fidx];
759 
760  var updLimit = {
761  pId: parseInt(limit.pid),
762  fCode: limit.fcode.trim(),
763  fDesc: feature.fDesc,
764  fType: feature.fType,
765  fApt: limit.fapt == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapt),
766  fApd: limit.fapd == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapd),
767  fApm: limit.fapm == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapm),
768  fApa: limit.fapa == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapa),
769  fCpd: limit.fcpd == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpd),
770  fCpm: limit.fcpm == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpm),
771  fCpa: limit.fcpa == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpa),
772  fCfm: limit.fcfm == "t" ? true : false,
773  fDirty: false,
774  eCode: limit.fcode.trim(),
775  eDesc: feature.fDesc,
776  eApt: limit.fapt == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapt),
777  eApd: limit.fapd == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapd),
778  eApm: limit.fapm == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapm),
779  eApa: limit.fapa == null ? FEATURE_LIMIT_MAX_AMOUNT : parseFloat(limit.fapa),
780  eCpd: limit.fcpd == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpd),
781  eCpm: limit.fcpm == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpm),
782  eCpa: limit.fcpa == null ? FEATURE_LIMIT_MAX_COUNT : parseInt(limit.fcpa),
783  eCfm: limit.fcfm == "t" ? true : false
784  };
785 
786  var idx = -1;
787  if (remove) {
788  idx = DataSourceFindLimit(updLimit.fCode, updLimit.pId);
789  } else {
790  for (var i = 0; i < prDataLimits.length; i++) {
791  if (limit.fCode < prDataLimits[i].fCode) {
792  idx = i;
793  break;
794  }
795  }
796  }
797 
798  prDataLimits.splice(idx, remove, updLimit);
799  prViewLimitGrid.dataSource.data(prDataLimits);
800 
801  if (prViewLimitExpanded) {
802  prViewLimitExpanded = false;
803  EventExpandLimit();
804  }
805 }
806 
807 <?php
808 /*
809  * DataSourceRemoveLimit: remove limit from limit datasource.
810  * After Deleting a limit from a profile.
811  *
812  * var limits: list of limits which have been removed from the database.
813  * Each limit is searched for and remove from the limit datasource.
814  */
815 ?>
816 function DataSourceRemoveLimit(limits) {
817 
818  for (var i = 0; i < limits.length; i++) {
819 
820  var rmvLimit = {
821  pId: limits[i].pid,
822  fCode: limits[i].fcode
823  };
824 
825  var idx = DataSourceFindLimit(rmvLimit.fCode, rmvLimit.pId);
826  prDataLimits.splice(idx, 1);
827  prViewLimitGrid.dataSource.data(prDataLimits);
828 
829  }
830 
831  if (prViewLimitExpanded) {
832  prViewLimitExpanded = false;
833  EventExpandLimit();
834  }
835 }
836 
837 <?php
838 /*
839  * DataSourceBuildProfiles: restructure the profiles datasource array for use in javascript/display.
840  * Each profile has duplicate values for editing purposes. This helps with determining if there are changes.
841  *
842  * p = original values
843  * e = edited values
844  *
845  * var data: data array containing original unstructured data
846  */
847 ?>
848 function DataSourceBuildProfiles(data) {
849  for (var i = 0; i < data.length; i++) {
850 
851  var newProfile = {
852  pId: parseInt(data[i].pid),
853  pCode: data[i].pcode.trim(),
854  pDesc: data[i].pdesc.trim(),
855  pText: data[i].pdesc.trim(),
856  pValue: parseInt(data[i].pid),
857  eCode: data[i].pcode.trim(),
858  eDesc: data[i].pdesc.trim(),
859  pDirty: false,
860  };
861 
862  prDataProfiles.push(newProfile);
863  }
864 
865  prDataProfiles.push({
866  pId: 0,
867  pCode: "",
868  pDesc: "",
869  pText: "+ Add Profile",
870  pValue: 0,
871  eCode: "",
872  eDesc: "",
873  pDirty: false,
874  });
875 }
876 
877 <?php
878 /*
879  * DataSourceFindProfile: find a specific profile in the profile datasource
880  *
881  * var pId: profile_id to find
882  */
883 ?>
884 function DataSourceFindProfile(pId) {
885  var idx = -1;
886  for (var i = 0; i < prDataProfiles.length; i++) {
887 
888  if (prDataProfiles[i].pId == pId) {
889  idx = i;
890  break;
891  }
892  }
893 
894  return idx;
895 }
896 
897 <?php
898 /*
899  * DataSourceRemoveProfile: remove profile from limit datasource.
900  * After Deleting a profile.
901  *
902  * var profile: profile which have been removed from the database.
903  */
904 ?>
905 function DataSourceRemoveProfile(profile) {
906  var rmvProfile = {
907  pId: parseInt(profile.pid)
908  };
909 
910  var pidx = DataSourceFindProfile(rmvProfile.pId);
911 
912  prDataProfiles.splice(pidx, 1);
913  prViewProfileDropdown.dataSource.data(prDataProfiles);
914  prViewProfileDropdown.select(0);
915  prViewProfileDropdown.trigger("select");
916  prViewProfileDropdown.trigger("change");
917 }
918 
919 <?php
920 /*
921  * DataSourceInsertProfile: insert a new or edited profile into the profile datasource in alpha order
922  * New profiles will be added without removing any others.
923  * Edited profiles will be inserted by removing the old version and replaced with the edited version.
924  *
925  * var profile: profile to insert
926  * var remove: determine if profile will be inserted without removing the current placeholder
927  */
928 ?>
929 function DataSourceInsertProfile(profile, remove) {
930  var updProfile = {
931  pId: parseInt(profile.pid),
932  pCode: profile.pcode.trim(),
933  pDesc: profile.pdesc.trim(),
934  pText: profile.pdesc.trim(),
935  pValue: parseInt(profile.pid),
936  eCode: profile.pcode.trim(),
937  eDesc: profile.pdesc.trim(),
938  pDirty: false,
939  };
940 
941  var pidx = -1;
942 
943  if (remove) {
944  pidx = DataSourceFindProfile(updProfile.pId);
945  prDataProfiles.splice(pidx, 1);
946  } else {
947  prDataProfiles[prDataProfiles.length-1].eCode = "";
948  prDataProfiles[prDataProfiles.length-1].eDesc = "";
949  }
950 
951  for (var i = 0; i < prDataProfiles.length; i++) {
952  var comp = prDataProfiles[i].pDesc.localeCompare(updProfile.pDesc);
953  if (comp == 1) {
954  pidx = i >= 0 ? i : 0;
955  break;
956  }
957 
958  if (i == prDataProfiles.length-1) {
959  pidx = i;
960  }
961  }
962 
963  prDataProfiles.splice(pidx, 0, updProfile);
964  prViewProfileDropdown.dataSource.data(prDataProfiles);
965  prViewProfileDropdown.select(pidx);
966  prViewProfileDropdown.trigger("select");
967  prViewProfileDropdown.trigger("change");
968 }
969 
970 <?php
971 /*
972  * ViewProfileEnable: used to disable or enable inputs fields in the profile section.
973  *
974  * var eView: html element to enable/disable
975  * var eDisabled: boolean to set disabled or enabled
976  */
977 ?>
978 function ViewProfileEnable(eView, eDisabled) {
979  eView.prop("disabled", eDisabled);
980 
981  if (eDisabled) { eView.addClass("k-state-disabled"); }
982  else { eView.removeClass("k-state-disabled"); }
983 }
984 
985 function ViewProfileNoLimit() {
986  <?php // when the window opens we must show "No Limit" values in "amount" input fields. ?>
987  if (prObserveLimit.showAmount) {
988  $("#inpApt, #inpApd, #inpApm, #inpApa").each(function() {
989  var input = $(this);
990  var child = $(input.parent()[0].firstChild);
991  var value = input.val();
992 
993  if (value >= FEATURE_LIMIT_MAX_AMOUNT || value == "") {
994  child.val("No Limit");
995  }
996  });
997  }
998 
999  <?php // when the window opens we must show "No Limit" values in "count" input fields. ?>
1000  if (prObserveLimit.showCount) {
1001  $("#inpCpd, #inpCpm, #inpCpa").each(function() {
1002  var input = $(this);
1003  var child = $(input.parent()[0].firstChild);
1004  var value = input.val();
1005 
1006  if (value >= FEATURE_LIMIT_MAX_COUNT || value == "") {
1007  child.val("No Limit");
1008  }
1009  });
1010  }
1011 }
1012 
1013 <?php
1014 /*
1015  * ViewProfileFocus: used to set the focus of input fields in the profile section.
1016  *
1017  * var eView: html element to focus
1018  * var eDisabled: boolean to set focued or blured.
1019  */
1020 ?>
1021 function ViewProfileFocus(eView, eFocus) {
1022  if (eFocus) { eView.focus(); }
1023  else { eView.blur(); }
1024 }
1025 
1026 <?php
1027 /*
1028  * ActionConfirmDiscardLimit: dialog function to discard any changes made to a limit in the
1029  * limit editor window.
1030  *
1031  * if any changes were detected this will reset the limit values and close both the dialog
1032  * and the editor window.
1033  */
1034 ?>
1035 function ActionConfirmDiscardLimit(e) {
1036  EventResetLimit();
1037  prViewDialogDiscardLimit.close();
1038  prViewLimitWindow.close();
1039 }
1040 
1041 <?php
1042 /*
1043  * ActionConfirmDeleteLimit: dialog function to send a delete request to the server.
1044  *
1045  * the data is gathered in a comma separated list, each element is an item of this sort:
1046  * "description:feature_code" to ensure the success message shows the descriptions instead
1047  * of the codes.
1048  */
1049 ?>
1050 function ActionConfirmDeleteLimit(e) {
1051  var codeString = "";
1052  for (var i = 0; i < prDataLimitStack.length; i++) {
1053 
1054  var fCode = prDataLimitStack[i].fCode;
1055  var fDesc = prDataLimitStack[i].fDesc;
1056  codeString += fDesc + ":" + fCode;
1057 
1058  if (i < prDataLimitStack.length -1) {
1059  codeString += ",";
1060  }
1061  }
1062 
1063  var limitRequest = {
1064  action: "limit_delete",
1065  pId: prDataProfileSelect.pId,
1066  fList: codeString
1067  }
1068 
1069  prDataSource.transport.options.read.type = "POST";
1070  prDataSource.read(limitRequest);
1071 }
1072 
1073 <?php
1074 /*
1075  * ActionConfirmDeleteProfile: dialog function to send a delete request to the server.
1076  * This functionwill delete a profile.
1077  */
1078 ?>
1079 function ActionConfirmDeleteProfile(e) {
1080  var profileRequest = {
1081  action: "profile_delete",
1082  pId: prDataProfileSelect.pId,
1083  pCode: prDataProfileSelect.eCode,
1084  pDesc: prDataProfileSelect.eDesc
1085  };
1086 
1087  prDataSource.transport.options.read.type = "POST";
1088  prDataSource.read(profileRequest);
1089 }
1090 
1091 <?php
1092 /*
1093  * ActionKeepProfileChanges: dialog function to save changes to a profile.
1094  * This function will save the data and send a request to the server to save the profile changes.
1095  */
1096 ?>
1097 function ActionKeepProfileChanges(e) {
1098 
1099 }
1100 
1101 <?php
1102 /*
1103  * ActionDiscardProfileChanges: dialog function to discard changes to a profile.
1104  *
1105  * Upone changing a profile description and changing the profile via the dropdown list;
1106  * this function will discard the changes.
1107  */
1108 ?>
1109 function ActionDiscardProfileChanges(e) {
1110 
1111  if (prDataProfileSelect) {
1112  prDataProfileSelect.eCode = prDataProfileSelect.pCode;
1113  prDataProfileSelect.eDesc = prDataProfileSelect.pDesc;
1114  prDataProfileSelect.pDirty = false;
1115  }
1116 
1117  var idx = DataSourceFindProfile(prDataProfileNext.pId);
1118  prViewProfileDropdown.select(idx);
1119  prViewProfileDropdown.trigger("select");
1120  prViewProfileDropdown.trigger("change");
1121 
1122  // remove any validation classes
1123  $("#inpProfileCode").removeClass("k-invalid");
1124  $("#inpProfileCode").css("border", "1px solid #ceced2");
1125  $("#inpProfileDesc").removeClass("k-invalid");
1126  $("#inpProfileDesc").css("border", "1px solid #ceced2");
1127 
1128  // hide messages
1129  $.homecuValidator.hideMessage();
1130 }
1131 
1132 <?php
1133 /*
1134  * EventCheckboxReset: this function is here to set checkbox values. when the user changes the profile,
1135  * or changes a limit in the limit popup window, the feature will be changed causing the grid to call its
1136  * DataBound function.
1137  *
1138  * There could be limits in the limit stack used for deleting limits, this is how we set any check boxes back
1139  * to checked when they reset.
1140  *
1141  * var enable: value to set boxes to
1142  */
1143 ?>
1144 function EventCheckboxReset(enable) {
1145  var count = 0;
1146  for (var i = 0; i < prDataLimitStack.length; i++) {
1147 
1148  var feature = prDataLimitStack[i].fCode;
1149  var box = $("input[id=chk_" + feature + "]");
1150  box.prop("checked", enable);
1151 
1152  count += 1;
1153  }
1154 
1155  prViewLimitDelete.prop("disabled", prDataLimitStack.length == 0);
1156  $("#chk_0").prop("checked", false);
1157 
1158  if (!enable) {
1159  prDataLimitStack = [];
1160  }
1161 }
1162 
1163 <?php
1164 /*
1165  * EventCheckboxChange: change event for checkboxes in the limit grid.
1166  *
1167  * var e: checkbx source element'
1168  * var source: this is used to determine where the event came from.
1169  *
1170  * If the source came from a row click the value is set AFTER the event.
1171  * If the source came from the box itself, the value is set BEFORE the event fires. Thus
1172  * we reset it previous then use the value.
1173  *
1174  * because of this we cannot just get the value and use it.
1175  */
1176 ?>
1177 function EventCheckboxChange(e, source) {
1178  var box = $(e);
1179  var boxId = box.attr("id");
1180  var boxValue = box.prop("checked");
1181 
1182  if (source == "BOX") {
1183  boxValue = !boxValue;
1184  }
1185 
1186  if (boxValue) {
1187  $("input[id=chk_0]").prop("checked", false);
1188  }
1189 
1190  if (boxId == "chk_0") {
1191 
1192  $(".feature-checkbox").each(function() {
1193 
1194  if (!this.checked && !boxValue) {
1195  StackInsertLimit(this.id);
1196  this.checked = true;
1197  } else if (this.checked && boxValue) {
1198  StackRemoveLimit(this.id);
1199  this.checked = false;
1200  }
1201 
1202  });
1203  } else {
1204 
1205  if (boxValue) {
1206  StackRemoveLimit(boxId);
1207  } else {
1208  StackInsertLimit(boxId);
1209  }
1210  }
1211 
1212  box.prop("checked", !boxValue);
1213 
1214  if (prDataLimitStack.length > 0) {
1215  prViewLimitDelete.prop("disabled", false);
1216  } else {
1217  prViewLimitDelete.prop("disabled", true);
1218  }
1219 }
1220 
1221 <?php
1222 /*
1223  * EventGridDataBound: DataBind event for thekendo grid.
1224  *
1225  * This function will set some css for the row hover as well as the event function for a checkbox change
1226  */
1227 ?>
1228 function EventGridDataBound(e) {
1229  $("html .k-grid tr").hover(function() {
1230  $(this).css("cursor", "pointer");
1231  });
1232 
1233  $('input[id^=chk_]').off();
1234  $('input[id^=chk_]').css("cursor", "pointer");
1235  $('input[id^=chk_]').css("margin-top", "-2px");
1236  $('input[id^=chk_]').change(function(e) {
1237  EventCheckboxChange(e.target, "BOX");
1238  });
1239 
1240  EventCheckboxReset(true);
1241 
1242  if (prViewLimitExpanded) {
1243  prViewLimitExpanded = false;
1244  EventExpandLimit();
1245  }
1246 }
1247 
1248 <?php
1249 /*
1250  * EventGridChange: Change event for the kendo grid.
1251  *
1252  * This function takes care of determining which grid cell was clicked. If the first cell is click,
1253  * the checkboxchanged function will be fired. Any other cell will result in displaying the row data
1254  * in the limit popup window.
1255  */
1256 ?>
1257 function EventGridChange(e) {
1258  var cell = this.select();
1259  var cellIndex = cell.index();
1260 
1261  var dataIndex = cell.closest("tr").index(".k-master-row");
1262  var dataSource = this.dataSource;
1263  var dataItem = dataSource.view()[dataIndex];
1264 
1265  if (cellIndex == 0 && dataItem.pId > 0) {
1266 
1267  var box = cell.find("input[id^=\"chk_\"]")[0];
1268  EventCheckboxChange(box, "ROW");
1269  } else {
1270  EventOpenLimit(dataItem);
1271  }
1272 
1273  $(this.select()).removeClass('k-state-selected');
1274 }
1275 
1276 <?php
1277 /*
1278  * EventChangeLimitFeature: DropDownList change event for the kendo dropdownlist in the limit window popup
1279  *
1280  * This function takes care of showing certain piece of the layout depening on the limit_type of the selected
1281  * feature in the dropdown list.
1282  */
1283 ?>
1284 function EventChangeLimitFeature(e) {
1285  var input = $(e.sender.element[0]);
1286  var value = input.val();
1287  var idx = DataSourceFindFeature(value);
1288  var feature = prDataFeatures[idx];
1289 
1290  if (feature != undefined) {
1291 
1292  var featureType = feature.fType;
1293  if (feature.fType == "B" || feature.fType == "D") {
1294  prViewLimitAmount.show();
1295  prViewLimitAmountBr.show();
1296  this.showAmount = true;
1297 
1298  prViewLimitConfirm.show();
1299  this.showConfirm = true;
1300  } else {
1301  prViewLimitAmount.hide();
1302  prViewLimitAmountBr.hide();
1303  this.showAmount = false;
1304 
1305  prViewLimitConfirm.hide();
1306  this.showConfirm = false;
1307  }
1308 
1309  if (feature.fType == "B" || feature.fType == "Q") {
1310  prViewLimitCount.show();
1311  prViewLimitCountBr.show();
1312  this.showCount = true;
1313  } else {
1314  prViewLimitCount.hide();
1315  prViewLimitCountBr.hide();
1316  this.showCount = false;
1317  }
1318 
1319  if (feature.fType == "A") {
1320  prViewLimitAccess.show();
1321  this.showAccess = true;
1322  } else {
1323  prViewLimitAccess.hide();
1324  this.showAccess = false;
1325  }
1326 
1327  this.sourceLimit.fDirty = true;
1328  ViewProfileEnable($("#btnLimitSave"), false);
1329  } else {
1330  prViewLimitConfirm.hide();
1331  this.showConfirm = false;
1332 
1333  prViewLimitCount.hide();
1334  prViewLimitCountBr.hide();
1335  this.showCount = false;
1336 
1337  prViewLimitAmount.hide();
1338  prViewLimitAmountBr.hide();
1339  this.showAmount = false;
1340 
1341  prViewLimitConfirm.hide();
1342  this.showConfirm = false;
1343 
1344  prViewLimitAccess.hide();
1345  this.showAccess = false;
1346 
1347  this.sourceLimit.fDirty = false;
1348  ViewProfileEnable($("#btnLimitSave"), true);
1349  }
1350 
1351  input.blur();
1352  input.removeClass("k-state-focused");
1353 
1354  ViewProfileNoLimit();
1355 }
1356 
1357 <?php
1358 /*
1359  * EventResetLimit: this function is used to reset limit values after discarding changed values.
1360  */
1361 ?>
1362 function EventResetLimit() {
1363  prObserveLimit.sourceLimit.eCode = prObserveLimit.sourceLimit.fCode;
1364  prObserveLimit.sourceLimit.eApt = prObserveLimit.sourceLimit.fApt;
1365  prObserveLimit.sourceLimit.eApd = prObserveLimit.sourceLimit.fApd;
1366  prObserveLimit.sourceLimit.eApm = prObserveLimit.sourceLimit.fApm;
1367  prObserveLimit.sourceLimit.eApa = prObserveLimit.sourceLimit.fApa;
1368  prObserveLimit.sourceLimit.eCpd = prObserveLimit.sourceLimit.fCpd;
1369  prObserveLimit.sourceLimit.eCpm = prObserveLimit.sourceLimit.fCpm;
1370  prObserveLimit.sourceLimit.eCpa = prObserveLimit.sourceLimit.fCpa;
1371  prObserveLimit.sourceLimit.eCfm = prObserveLimit.sourceLimit.fCfm;
1372  prObserveLimit.sourceLimit.fDirty = false;
1373 }
1374 
1375 <?php
1376 /*
1377  * EventCheckDirty: event for input fields in the limit popup window
1378  *
1379  * All limits have duplicate fields, one for original value and one for edited value. If these
1380  * differ from each other the limit is flagged dirty.
1381  */
1382 ?>
1383 function EventCheckDirty() {
1384  var limit = prObserveLimit.sourceLimit;
1385 
1386  if (limit.eCode != limit.fCode) { limit.fDirty = true; }
1387  else if (limit.eApt != limit.fApt) { limit.fDirty = true; }
1388  else if (limit.eApa != limit.fApa) { limit.fDirty = true; }
1389  else if (limit.eApd != limit.fApd) { limit.fDirty = true; }
1390  else if (limit.eApm != limit.fApm) { limit.fDirty = true; }
1391  else if (limit.eCpa != limit.fCpa) { limit.fDirty = true; }
1392  else if (limit.eCpd != limit.fCpd) { limit.fDirty = true; }
1393  else if (limit.eCpm != limit.fCpm) { limit.fDirty = true; }
1394  else if (limit.eCfm != limit.fCfm) { limit.fDirty = true; }
1395  else { limit.fDirty = false; }
1396 
1397  ViewProfileEnable($("#btnLimitSave"), !limit.fDirty);
1398 }
1399 
1400 <?php
1401 /*
1402  * EventBlurLimitCount: Blur event for "count" input fields in the limit popup window.
1403  *
1404  * If the value of the field is a maximum possible amount, the value will be viewed as "No Limit".
1405  */
1406 ?>
1407 function EventBlurLimitCount(e) {
1408  var input = $(this);
1409  var child = $(input.parent()[0].firstChild);
1410  var value = input.val();
1411  var id = input.attr("id");
1412  var field = id.substring(3, id.length);
1413 
1414  if (prObserveLimit.showCount) {
1415  if (value >= FEATURE_LIMIT_MAX_COUNT || value == "" || value == null) {
1416  value = FEATURE_LIMIT_MAX_COUNT;
1417  child.val("No Limit");
1418  }
1419 
1420  switch (field) {
1421  case "Cpa":
1422  prObserveLimit.sourceLimit.eCpa = parseInt(value);
1423  break;
1424  case "Cpd":
1425  prObserveLimit.sourceLimit.eCpd = parseInt(value);
1426  break;
1427  case "Cpm":
1428  prObserveLimit.sourceLimit.eCpm = parseInt(value);
1429  break;
1430  }
1431 
1432  input.val(value);
1433  EventCheckDirty();
1434  }
1435 }
1436 
1437 <?php
1438 /*
1439  * EventBlurLimitAmount: Blur event for "amount" input fields in the limit popup window.
1440  *
1441  * If the value of the field is a maximum possible amount, the value will be viewed as "No Limit".
1442  */
1443 ?>
1444 function EventBlurLimitAmount(e) {
1445  var input = $(this);
1446  var child = $(input.parent()[0].firstChild);
1447  var value = input.val();
1448  var id = input.attr("id");
1449  var field = id.substring(3, id.length);
1450 
1451  if (prObserveLimit.showAmount) {
1452  if (value >= FEATURE_LIMIT_MAX_AMOUNT || value == "") {
1453  value = FEATURE_LIMIT_MAX_AMOUNT;
1454  child.val("No Limit");
1455  }
1456 
1457  switch (field) {
1458  case "Apt":
1459  prObserveLimit.sourceLimit.eApt = parseFloat(value);
1460  break;
1461  case "Apa":
1462  prObserveLimit.sourceLimit.eApa = parseFloat(value);
1463  break;
1464  case "Apd":
1465  prObserveLimit.sourceLimit.eApd = parseFloat(value);
1466  break;
1467  case "Apm":
1468  prObserveLimit.sourceLimit.eApm = parseFloat(value);
1469  break;
1470  }
1471 
1472  input.val(value);
1473  EventCheckDirty();
1474  }
1475 }
1476 
1477 <?php
1478 /*
1479  * EventSpinLimit: Spin event for input fields in the limit popup window.
1480  *
1481  * This will call the blur events for the input fields so the user doesn't have to click away to
1482  * view "No Limit".
1483  */
1484 ?>
1485 function EventSpinLimit(e) {
1486  var input = $(e.sender.element[0]);
1487  input.blur();
1488 }
1489 
1490 <?php
1491 /*
1492  * EventOpenLimit: upon clicking a grid row, the limit data is passed into this function to setup
1493  * an observable for the ability to edit the limit in the limit editor popup window.
1494  */
1495 ?>
1496 function EventOpenLimit(limit) {
1497  if (prDataProfileSelect.pId == 0) {
1498  prViewDialogWarningLimit.open();
1499  return;
1500  }
1501 
1502  DataSourceFilterFeatures();
1503  var idx = DataSourceFindFeature(limit.fCode);
1504  var feature = prDataFeatures[idx];
1505 
1506  prObserveLimit.set("sourceLimit", limit);
1507  prObserveLimit.set("sourceFeatures", prDataFeaturesFiltered);
1508 
1509  if (limit.pId == 0) {
1510  prObserveLimit.set("showAmount", false);
1511  prObserveLimit.set("showCount", false);
1512  prObserveLimit.set("showConfirm", false);
1513  prObserveLimit.set("showDrop", true);
1514  prObserveLimit.set("showAccess", false);
1515  } else {
1516  prObserveLimit.set("showAmount", feature.fType == "B" || feature.fType == "D");
1517  prObserveLimit.set("showCount", feature.fType == "B" || feature.fType == "Q");
1518  prObserveLimit.set("showConfirm", feature.fType == "B" || feature.fType == "D");
1519  prObserveLimit.set("showAccess", feature.fType == "A");
1520  prObserveLimit.set("showDrop", false);
1521  }
1522 
1523  kendo.bind("#wndProfileLimit", prObserveLimit);
1524 
1525  var title = limit.pId == 0 ? "Add Feature Limit" : "Edit " + limit.fDesc;
1526  prViewLimitWindow.title(title);
1527  prViewLimitWindow.center();
1528  prViewLimitWindow.open();
1529 
1530  ViewProfileEnable($("#wndProfileLimit #btnLimitSave"), true);
1531  ViewProfileNoLimit();
1532 }
1533 
1534 <?php
1535 /*
1536  * EventSaveLimit: send request to server for saving changes to a limit
1537  */
1538 ?>
1539 function EventSaveLimit(e) {
1540  var limit = prObserveLimit.sourceLimit;
1541  var idx = DataSourceFindFeature(limit.eCode);
1542  var feature = prDataFeatures[idx];
1543 
1544  if (limit != undefined && limit.fDirty) {
1545 
1546  var limitRequest = {
1547  action: limit.pId == 0 ? "limit_create" : "limit_update",
1548  pId: prDataProfileSelect.pId,
1549  fType: feature.fType,
1550  fCode: limit.eCode,
1551  fApt: (feature.fType == "B" || feature.fType == "D") ? limit.eApt : null,
1552  fApa: (feature.fType == "B" || feature.fType == "D") ? limit.eApa : null,
1553  fApd: (feature.fType == "B" || feature.fType == "D") ? limit.eApd : null,
1554  fApm: (feature.fType == "B" || feature.fType == "D") ? limit.eApm : null,
1555  fCpa: (feature.fType == "B" || feature.fType == "Q") ? limit.eCpa : null,
1556  fCpd: (feature.fType == "B" || feature.fType == "Q") ? limit.eCpd : null,
1557  fCpm: (feature.fType == "B" || feature.fType == "Q") ? limit.eCpm : null,
1558  fCfm: limit.eCfm
1559  };
1560 
1561  prDataSource.transport.options.read.type = "POST";
1562  prDataSource.read(limitRequest);
1563  }
1564 
1565  EventResetLimit();
1566  prViewLimitWindow.close();
1567 }
1568 
1569 <?php
1570 /*
1571  * EventDeleteLimit: this function opens a dialog window displaying the selected limits to be deleted.
1572  * ActionConfirmDeleteLimit: this is the function that will carry out the server request.
1573  */
1574 ?>
1575 function EventDeleteLimit(e) {
1576 
1577  var codeString = "";
1578  codeString += "<p>You are about to delete the following limits:</p>";
1579  codeString += "<ul style=\"margin-left: 25px;\">";
1580  for (var i = 0; i < prDataLimitStack.length; i++) {
1581  var fDesc = prDataLimitStack[i].fDesc;
1582  codeString += "<li>" + fDesc + "</li>";
1583  }
1584  codeString += "</ul>";
1585  codeString += "<p>Do you wish to continue?</p>";
1586 
1587  if (codeString != "") {
1588  prViewDialogDeleteLimit.content(codeString);
1589  prViewDialogDeleteLimit.open();
1590  }
1591 }
1592 
1593 <?php
1594 /*
1595  * EventExpandLimit: Click event for the expand button. This function will alter the css of each
1596  * grid row to make visible the partial or full limit descriptions.
1597  */
1598 ?>
1599 function EventExpandLimit(e) {
1600  var btnText = "";
1601  if (prViewLimitExpanded) {
1602  btnText = "<span class=\"fa fa-expand\"></span> <span>Expand All</span>";
1603  $("html .k-grid td span").addClass("local-hcu-nowrap");
1604  prViewLimitExpanded = false;
1605  } else {
1606  btnText = "<span class=\"fa fa-expand\"></span> <span>Collapse All</span>";
1607  $("html .k-grid td span").removeClass("local-hcu-nowrap");
1608  prViewLimitExpanded = true;
1609  }
1610 
1611  prViewLimitExpand.html(btnText);
1612 }
1613 
1614 <?php
1615 /**
1616  * EventCheckLabel: when a checkbox has a label next to it, make sure the checkbox changes with the click of the label.
1617  */
1618 ?>
1619 function EventCheckLabel(e) {
1620  var chk = $("#inpCfm").prop("checked");
1621  $("#inpCfm").prop("checked", !chk);
1622 
1623  var dirt = prObserveLimit.sourceLimit.fDirty;
1624  prObserveLimit.sourceLimit.eCfm = !chk;
1625 
1626  EventCheckDirty();
1627 }
1628 
1629 <?php
1630 /*
1631  * EventSaveProfile: Click event for save profile button. This function takes care ofsending the
1632  * request to the server.
1633  */
1634 ?>
1635 function EventSaveProfile(e) {
1636  if ($.homecuValidator.validate()) {
1637  var profileRequest = {
1638  action: prDataProfileSelect.pId == 0 ? "profile_create" : "profile_update",
1639  pId: prDataProfileSelect.pId,
1640  pCode: prDataProfileSelect.eCode,
1641  pDesc: prDataProfileSelect.eDesc
1642  };
1643 
1644  prDataProfileSelect.pDirty = false;
1645 
1646  prDataSource.transport.options.read.type = "POST";
1647  prDataSource.read(profileRequest);
1648  }
1649 }
1650 
1651 <?php
1652 /*
1653  * EventDeleteProfile: Click event for delete profile button. This function opens the confirmation
1654  * dialog for deleting a profile.
1655  */
1656 ?>
1657 function EventDeleteProfile(e) {
1658  prViewDialogDeleteProfile.open();
1659 }
1660 
1661 <?php
1662 /*
1663  * EventChangeProfileInput: Input event for description and code input fields for profiles.
1664  *
1665  * This function will enable/disable the save button depending if any changes have been made.
1666  * Also it will keep an eye on the input in the profile code input field, only uppercase dashes and underscore
1667  * characters are allowed.
1668  */
1669 ?>
1670 function EventChangeProfileInput(e) {
1671  var target = $(e.target);
1672  var id = target.attr("id");
1673  var value = target.val();
1674  value = value.trim();
1675 
1676  if (id == "inpProfileCode") {
1677  value = value.toUpperCase();
1678  <?php // do not allow anything but alpha characters, underscore and dashes in the profile code. ?>
1679  <?php // any other characters found are removed. ?>
1680  if (RegExp(/[@#\\!$%^&*()+|~=`{}\[\]:";'<>?,.\/]/).test(value)) {
1681  value = value.slice(0, -1);
1682  }
1683  prDataProfileSelect.eCode = value;
1684  } else {
1685  prDataProfileSelect.eDesc = value;
1686  }
1687 
1688  if (prDataProfileSelect.pCode.trim() != prDataProfileSelect.eCode.trim() ||
1689  prDataProfileSelect.pDesc.trim() != prDataProfileSelect.eDesc.trim()) {
1690  ViewProfileEnable(prViewProfileSave, false);
1691  prDataProfileSelect.pDirty = true;
1692  } else {
1693  ViewProfileEnable(prViewProfileSave, true);
1694  prDataProfileSelect.pDirty = false;
1695  }
1696 }
1697 
1698 <?php
1699 /*
1700  * EventProfileSelect: on profile sleection, this function will stop the dropdown change event
1701  * if the profile has been changed. A dialog will appear asking for confirmation of discarding the
1702  * profile changes.
1703  *
1704  * The prViewprofileSelect is a flag variable. It is used to determine how many times the select
1705  * event has been called on the dropdown list. We need this because on change it is called once,
1706  * on blur it is called again. We want to avoid the second call or the data will be changed when the
1707  * confirmation dialog is open.
1708  */
1709 ?>
1710 function EventProfileSelect(e) {
1711 
1712  if (prDataProfileSelect && prDataProfileSelect.pDirty) {
1713  e.preventDefault();
1714 
1715  if (prViewProfileSelect) {
1716  prViewProfileSelect = false;
1717  } else {
1718  prViewProfileSelect = true;
1719  prDataProfileNext = e.dataItem;
1720  prViewDialogDiscardProfile.open();
1721  }
1722 
1723  } else {
1724  var value = e.dataItem == undefined ? parseInt(this.value()) : e.dataItem.pId;
1725  var idx = DataSourceFindProfile(value);
1726  var idx = (idx < 0) ? 0 : idx;
1727 
1728  prDataProfileSelect = prDataProfiles[idx];
1729  prViewProfileCode.val(prDataProfileSelect.eCode);
1730  prViewProfileDesc.val(prDataProfileSelect.eDesc);
1731  }
1732 }
1733 
1734 <?php
1735 /*
1736  * EventProfileChange: This function takes care of enabling the profile code/description and
1737  * save/delete buttons depening on which profile is selected. This function will also filter the
1738  * feature limit grid below depending on which profile is selected.
1739  */
1740 ?>
1741 function EventProfileChange(e) {
1742  switch (prDataProfileSelect.pId) {
1743  case -1:
1744  ViewProfileEnable(prViewProfileCode, true);
1745  ViewProfileEnable(prViewProfileDesc, true);
1746  ViewProfileEnable(prViewProfileDelete, true);
1747  break;
1748  case 0:
1749  ViewProfileEnable(prViewProfileCode, false);
1750  ViewProfileEnable(prViewProfileDesc, false);
1751  ViewProfileEnable(prViewProfileDelete, true);
1752  ViewProfileFocus(prViewProfileCode, true);
1753  break;
1754  default:
1755  ViewProfileEnable(prViewProfileCode, true);
1756  ViewProfileEnable(prViewProfileDesc, false);
1757  ViewProfileEnable(prViewProfileDelete, false);
1758  ViewProfileFocus(prViewProfileDesc, true);
1759  break;
1760  }
1761 
1762  ViewProfileEnable(prViewProfileSave, true);
1763 
1764  btnText = "<span class=\"fa fa-expand\"></span> <span>Expand All</span>";
1765  prViewLimitExpand.html(btnText);
1766  prViewLimitExpanded = false;
1767 
1768  EventCheckboxReset(false);
1769 
1770  var gridFilter = {
1771  logic: "or",
1772  filters: [
1773  { field: "pId", operator: "eq", value: prDataProfileSelect.pId },
1774  { field: "pId", operator: "eq", value: 0 }
1775  ]
1776  };
1777  prViewLimitGrid.dataSource.filter(gridFilter);
1778 }
1779 
1780 function EventOpenDialog(e) {
1781  prDataWindowStack.push(this);
1782 }
1783 
1784 function EventCloseDialog(e) {
1785  prDataWindowStack.pop();
1786 }
1787 
1788 <?php
1789 /*
1790  * InitDataActions: initialize all data actions like button click, input blur/focus and other events.
1791  */
1792 ?>
1793 function InitDataActions() {
1794  prViewProfileCode.on("input", EventChangeProfileInput);
1795  prViewProfileDesc.on("input", EventChangeProfileInput);
1796  prViewProfileSave.on("click", EventSaveProfile);
1797  prViewProfileDelete.on("click", EventDeleteProfile);
1798 
1799  prViewLimitDelete.on("click", EventDeleteLimit);
1800  prViewLimitDelete.prop("disabled", true);
1801  prViewLimitExpand.on("click", EventExpandLimit);
1802 
1803  $("#inpApt, #inpApa, #inpApd, #inpApm").on("blur", EventBlurLimitAmount);
1804  $("#inpCpa, #inpCpd, #inpCpm").on("blur", EventBlurLimitCount);
1805 
1806  <?php
1807  /*
1808  * kendo dropdownlists have a bug:
1809  * when the user opens the list, starts scrolling up or down, the list will
1810  * close when it reach the end or beginning of the list.
1811  *
1812  * this mouse event bind prevents this from happening. It wrks for the
1813  * profile dropdown and the feature dropdown in the popup window.
1814  *
1815  * for future reference; this is the source of the fix on Telerik.
1816  * http://docs.telerik.com/kendo-ui/controls/editors/dropdownlist/how-to/prevent-close-on-scroll.
1817  */
1818  ?>
1819  $(document).bind('mousewheel DOMMouseScroll', function(e) {
1820  var scrollTo = null;
1821  var element = null;
1822  var id = $(e.target).parent().attr("id");
1823 
1824  switch (id) {
1825  case "inpProfileList_listbox":
1826  element = prViewProfileDropdown.ul.parent();
1827  break;
1828  case "drpCodes_listbox":
1829  element = $("#drpCodes").data("kendoDropDownList").ul.parent();
1830  break;
1831  }
1832 
1833  if (element != null || element != undefined) {
1834  if (!$(activeElement).closest(".k-popup").length) {
1835  return;
1836  }
1837 
1838  if (e.type == 'mousewheel') {
1839  scrollTo = (e.originalEvent.wheelDelta * -1);
1840  }
1841  else if (e.type == 'DOMMouseScroll') {
1842  scrollTo = 40 * e.originalEvent.detail;
1843  }
1844 
1845  if (scrollTo) {
1846  e.preventDefault();
1847  element.scrollTop(scrollTo + element.scrollTop());
1848  }
1849  }
1850  });
1851 
1852  $(document).on('mouseover', function(e) {
1853  activeElement = e.target;
1854  });
1855 }
1856 
1857 <?php
1858 /*
1859  * InitDataViews: initialize all data views, set the variables holding the reference to the visible page elements.
1860  */
1861 ?>
1862 function InitDataViews() {
1863  prViewProfileCode = $("#inpProfileCode");
1864  prViewProfileCode.css("text-transform", "uppercase");
1865  prViewProfileDesc = $("#inpProfileDesc");
1866  prViewProfileSave = $("#btnProfileSave");
1867  prViewProfileDelete = $("#btnProfileDelete");
1868  prViewProfileDropdown = $("#inpProfileList").kendoDropDownList({
1869  dataValueField: "pValue",
1870  dataTextField: "pText",
1871  dataSource: { data: prDataProfiles },
1872  change: EventProfileChange,
1873  select: EventProfileSelect
1874  }).data("kendoDropDownList");
1875 
1876  prViewDialogDiscardProfile = $("#dialogDiscardProfile").kendoDialog({
1877  title: "Discard Changes",
1878  content: "<p>Changes have been made to this profile.</p><p>Do you wish to discard the changes?</p>",
1879  visible: false,
1880  resizable: false,
1881  actions: [
1882  { text: "No", action: ActionKeepProfileChanges },
1883  { text: "Yes", action: ActionDiscardProfileChanges, primary: true }
1884  ],
1885  show: EventOpenDialog,
1886  close: EventCloseDialog
1887  }).data("kendoDialog");
1888 
1889  prViewDialogDeleteProfile = $("#dialogDeleteProfile").kendoDialog({
1890  title: "Delete Profile",
1891  content: "<p>You are about to deleted this profile.</p><p>Do you wish to continue?</p>",
1892  visible: false,
1893  resizable: false,
1894  actions: [
1895  { text: "No" },
1896  { text: "Yes", action: ActionConfirmDeleteProfile, primary: true }
1897  ],
1898  show: EventOpenDialog,
1899  close: EventCloseDialog
1900  }).data("kendoDialog");
1901 
1902  prViewLimitDelete = $("#btnLimitDelete");
1903  prViewLimitExpand = $("#btnLimitExpand");
1904  prViewDialogDeleteLimit = $("#dialogDeleteLimit").kendoDialog({
1905  title: "Delete Limit",
1906  visible: false,
1907  resizable: false,
1908  actions: [
1909  { text: "No" },
1910  { text: "Yes", action: ActionConfirmDeleteLimit, primary: true }
1911  ],
1912  show: EventOpenDialog,
1913  close: EventCloseDialog
1914  }).data("kendoDialog");
1915 
1916  prViewDialogWarningLimit = $("#dialogWarningLimit").kendoDialog({
1917  title: "Profile Limit",
1918  content: "You may only create new limit for existing profiles.",
1919  visible: false,
1920  resizable: false,
1921  actions: [
1922  { text: "OK", primary: true }
1923  ],
1924  show: EventOpenDialog,
1925  close: EventCloseDialog
1926  }).data("kendoDialog");
1927 
1928  prViewDialogDiscardLimit = $("#dialogDiscardLimit").kendoDialog({
1929  title: "Discard Changes",
1930  content: "<p>Changes have been made to this feature.</p><p>Do you wish to discard these changes?</p>",
1931  visible: false,
1932  resizable: false,
1933  actions: [
1934  { text: "No" },
1935  { text: "Yes", action: ActionConfirmDiscardLimit, primary: true }
1936  ],
1937  show: EventOpenDialog,
1938  close: EventCloseDialog
1939  }).data("kendoDialog");
1940 
1941  prViewLimitGrid = $("#grdProfileLimits").kendoGrid({
1942  dataSource: {
1943  data: prDataLimits
1944  },
1945  rowTemplate: kendo.template($("#templateGridRow").html()),
1946  dataBound: EventGridDataBound,
1947  change: EventGridChange,
1948  selectable: "cell",
1949  columns: [
1950  { headerTemplate: "<input type=\"checkbox\" id=\"chk_0\">", width: "25px" },
1951  { title: "Feature", width: "150px"},
1952  { title: "Limits"}
1953  ]
1954  }).data("kendoGrid");
1955 
1956  prViewLimitAmount = $("#viewAmount");
1957  prViewLimitAmountBr = $("#viewAmountBr");
1958  prViewLimitCount = $("#viewCount");
1959  prViewLimitCountBr = $("#viewCountBr");
1960  prViewLimitConfirm = $("#viewConfirm");
1961  prViewLimitAccess = $("#viewAccess");
1962  prViewLimitWindow = $("#wndProfileLimit").kendoWindow({
1963  width: "750px",
1964  modal: true,
1965  visible: false,
1966  resizable: false,
1967  activate: EventOpenDialog,
1968  open: function(e) {
1969  this.wrapper.css({ top: 100 });
1970  },
1971  close: function(e) {
1972  if (prObserveLimit.sourceLimit.fDirty) {
1973  e.preventDefault();
1974  prViewDialogDiscardLimit.open();
1975  } else {
1976  prDataWindowStack.pop();
1977  kendo.unbind("#wndProfileLimit");
1978  EventResetLimit();
1979 
1980  if (prViewLimitExpanded) {
1981  prViewLimitExpanded = false;
1982  EventExpandLimit();
1983  }
1984  }
1985  }
1986  }).data("kendoWindow");
1987 
1988  prObserveLimit = new kendo.observable({
1989  sourceLimit: null,
1990  sourceFeatures: null,
1991  showDrop: false,
1992  showAmount: false,
1993  showCount: false,
1994  showConfirm: false,
1995  showAccess: false,
1996  saveLimit: EventSaveLimit,
1997  changeFeature: EventChangeLimitFeature,
1998  spinLimit: EventSpinLimit,
1999  changeLabel: EventCheckLabel,
2000  changeCheck: EventCheckDirty
2001  });
2002 
2003  prObserveLimitValidator = $("#wndProfileLimit").kendoValidator({
2004 
2005  }).data("kendoValidator");
2006 
2007  // init validator
2008  $.homecuValidator.setup({
2009  formStatusField: "formStatus",
2010  formValidate: "profileView",
2011  homecuCustomRules: {
2012  pcode: ValidateProfileCode,
2013  required: ValidateProfileRequired
2014  }
2015  });
2016 }
2017 
2018 <?php
2019 /*
2020  * InitDataSources: initialize all datasources and array which hold data.
2021  */
2022 ?>
2023 function InitDataSources() {
2024  prDataWindowStack = [];
2025  prDataProfiles = [];
2026  prDataLimits = [];
2027  prDataLimitStack = [];
2028  prDataFeatures = [];
2029  prDataFeaturesFiltered = [];
2030 
2031  prDataSource = new kendo.data.DataSource({
2032  transport: {
2033  read: {
2034  url: "main.prg",
2035  dataType: "json",
2036  contentType: "application/x-www-form-urlencoded",
2037  type: "GET",
2038  data: {
2039  ft: "51",
2040  action: "data_read"
2041  },
2042  cache: false
2043  }
2044  },
2045  requestStart: function(request) {
2046  showWaitWindow();
2047  },
2048  requestEnd: function(response) {
2049  setTimeout(hideWaitWindow, 500);
2050 
2051  if (response.hasOwnProperty("response")) {
2052  if (response.response.hasOwnProperty("Results")) {
2053  var results = response.response.Results;
2054 
2055  if (results.hasOwnProperty("error")) {
2056  $.homecuValidator.homecuResetMessage = true;
2057  $.homecuValidator.displayMessage(results.error, $.homecuValidator.settings.statusError);
2058  } else if (results.hasOwnProperty("info")) {
2059  $.homecuValidator.homecuResetMessage = true;
2060  $.homecuValidator.displayMessage(results.info, $.homecuValidator.settings.statusSuccess);
2061  }
2062  } else {
2063  $.homecuValidator.displayMessage("Error Parsing Server", $.homecuValidator.settings.statusError);
2064  }
2065  } else {
2066  $.homecuValidator.displayMessage("Error Parsing Server", $.homecuValidator.settings.statusError);
2067  }
2068  },
2069  schema: {
2070  parse: function(response) {
2071 
2072  var results = response.Results;
2073  var resultData = results.data;
2074  var resultAction = results.action;
2075 
2076  if (results.hasOwnProperty("errors")) {
2077  return [];
2078  }
2079 
2080  if (resultData == undefined || resultData == null) {
2081  return [];
2082  }
2083 
2084  if (resultAction == "data_read") {
2085  DataSourceBuildProfiles(resultData.profiles);
2086  DataSourceBuildLimits(resultData.limits);
2087  DataSourceBuildFeatures(resultData.features);
2088  } else {
2089  prDataLimitStack = [];
2090  if (resultAction == "profile_create") {
2091  DataSourceInsertProfile(resultData[0], 0);
2092  } else if (resultAction == "profile_update") {
2093  DataSourceInsertProfile(resultData[0], 1);
2094  } else if (resultAction == "profile_delete") {
2095  DataSourceRemoveProfile(resultData[0]);
2096  } else if (resultAction == "limit_create") {
2097  DataSourceInsertLimit(resultData[0], 0);
2098  } else if (resultAction == "limit_update") {
2099  DataSourceInsertLimit(resultData[0], 1);
2100  } else if (resultAction == "limit_delete") {
2101  DataSourceRemoveLimit(resultData);
2102  }
2103  }
2104 
2105  return [];
2106  }
2107  }
2108  });
2109 }
2110 
2111 $(document).ready(function() {
2112  prInfoBar = $("#prInfoBar");
2113 
2114  InitDataSources();
2115  prDataSource.read();
2116 
2117  setTimeout(function() {
2118  InitDataViews();
2119  InitDataActions();
2120 
2121  prViewProfileDropdown.select(0);
2122  prViewProfileDropdown.trigger("select");
2123  prViewProfileDropdown.trigger("change");
2124  }, 1000);
2125 });
2126 
2127 $(document).on('click', '.k-overlay', function() {
2128 
2129  if (prDataWindowStack.length > 0) {
2130  var wnd = prDataWindowStack[prDataWindowStack.length-1];
2131  wnd.close();
2132  }
2133 });
2134 </script>