Adding Chris DeBellis's feature additions:
authorChris Sharp <csharp@georgialibraries.org>
Mon, 8 May 2017 16:15:49 +0000 (12:15 -0400)
committerChris Sharp <csharp@georgialibraries.org>
Mon, 8 May 2017 16:15:49 +0000 (12:15 -0400)
- the user can now import report templates that use Year and Year-Month
  dates instead of actual dates
- The user can import report templates with 'contains matching substring'.

config/production.config.php
controllers/report.controller.php
controllers/schedule.controller.php
lib/site_v1.4.js [deleted file]
lib/site_v1.5.js [deleted file]
lib/site_v1.6.js [new file with mode: 0644]
views/page.view.php
views/report.view.php

index e0ceac0..f332fcb 100644 (file)
@@ -6,6 +6,7 @@ define ('QR_REPORT_OUTPUT_URL_PREFIX', 'https://next.gapines.org/reporter/');
 define ('QR_SITE_ROOT', '/report-creator/');
 //define ('QR_REPORT_OUTPUT_URL_PREFIX', 'https://reports-dev.gapines.org/reporter/');
 define ('QR_REPORT_OUTPUT_URL_SUFFIX', '/report-data.html');
+define ('QR_REPORT_TRANSFORM_START_YEAR', '2006');
 
 //page headings
 define ('QR_DEFAULT_LOGO_TEXT', 'Quick Reports');
index ee1af8f..0457d73 100644 (file)
@@ -131,7 +131,7 @@ class reportController {
        
        public function editQueuedReport($params) {
                //edit a queued report using data from reporter.schedule and reporter.report
-       
+               
                $defaultValues = new stdClass();
                        
                if (NULL == $params) {
@@ -251,9 +251,8 @@ class reportController {
                                $newParamName = $paramName;
                                
                                do {
-                                       
                                        if (strtolower($param->dataType) == 'timestamp') {
-                                               $dateField=$defaultValues->paramsDecoded->$paramName;
+                                               $dateField=$defaultValues->paramsDecoded->$paramName;                                   
                                                if (isset($dateField[$passes]->transform)) {
                                                        $field = $newParamName.'_type';
                                                        $defaultValues->paramsDecoded->$field = 'relative';
@@ -263,19 +262,29 @@ class reportController {
                                                else {
                                                        $field = $newParamName.'_type';
                                                        $defaultValues->paramsDecoded->$field = 'real';
-                                                       $field = $newParamName.'_date';                         
-                                                       $defaultValues->paramsDecoded->$field = $dateField[$passes];
-                                                       $defaultValues->paramsDecoded->$field = substr($dateField[$passes],5,2).'/'.substr($dateField[$passes],8,2).'/'.substr($dateField[$passes],0,4);
+                                                       
+                                                       switch (strtolower($param->transform)) {
+                                                               case 'date':    
+                                                                       $field = $newParamName.'_date';                         
+                                                                       $defaultValues->paramsDecoded->$field = substr($dateField[$passes],5,2).'/'.substr($dateField[$passes],8,2).'/'.substr($dateField[$passes],0,4);
+                                                               break;
+                                                               case 'month_trunc':
+                                                                       $field = $newParamName.'_date_year';
+                                                                       $defaultValues->paramsDecoded->$field = substr($dateField[$passes],0,4);
+                                                                       $field = $newParamName.'_date_month';
+                                                                       $defaultValues->paramsDecoded->$field = substr($dateField[$passes],5,2);
+                                                               break;
+                                                               case 'year_trunc':
+                                                                       $field = $newParamName.'_date_year';
+                                                                       $defaultValues->paramsDecoded->$field = substr($dateField[$passes],0,4);
+                                                               break;
+                                                       }       
                                                }
                                        }
                                                
-                                       if (strtolower($param->op) != 'between') break;         //op is not 'between' so no second pass needed
-                                       
-                                       //set up the range.
-                                       $newParamName.='_end';
-                                       
+                                       $newParamName.='_end';          //set up for a range.           
                                }
-                               while (++$passes < 2);
+                               while (++$passes < 2 && strtolower($param->op) == 'between');
                                
                                if (strtolower($param->dataType) == 'timestamp') unset($defaultValues->paramsDecoded->$unsetName);
                        }
index bd284b6..15129d2 100644 (file)
@@ -199,14 +199,15 @@ class scheduleController {
                                $lowerDataType = strtolower($userParam->dataType);
                                $lowerTransform = strtolower($userParam->transform);
                                        
-                               if ($lowerTransform == 'date') {
+                               if ($lowerTransform == 'date' || $lowerTransform == 'month_trunc' || $lowerTransform == 'year_trunc') {
                                        //process date field
        
                                        $range=false;
                                        $paramsOK = true;
-                                       $paramsErrorMessage = NULL;
                                        $dateParamString=NULL;
                                        $dateEndParamString=NULL;
+                                       $paramsErrorMessage = NULL;
+                                       $lowerTransformLabel=str_replace('_trunc', '', $lowerTransform);
                                        
                                        if (!isset($_POST[$paramName.'_type'])) {
                                                $paramsOK = false;
@@ -216,28 +217,58 @@ class scheduleController {
                                        if ($_POST[$paramName.'_type'] == 'relative') {
                                                if (!isset($_POST[$paramName.'_relative_value'])) {
                                                        $paramsOK = false;
-                                                       $paramsErrorMessage = "Missing date parameter $paramName";
+                                                       $paramsErrorMessage = "Missing relative date value $paramName";
                                                        break;
                                                }
-                                               $dateParam['transform'] = 'relative_'.$lowerTransform;
+                                               $dateParam['transform'] = 'relative_'.$lowerTransformLabel;
                                                $dateParam['params'] =  (array)$_POST[$paramName.'_relative_value'];
                                        }
                                        else {
-                                               if (!isset($_POST[$paramName.'_date'])) {
-                                                       $paramsOK = false;
-                                                       $paramsErrorMessage = "Missing date parameter $paramName";
+                                               switch ($lowerTransform) {
+                                                       case 'date':            
+                                                               if (!isset($_POST[$paramName.'_date'])) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = "Missing date value $paramName";
+                                                                       break;
+                                                               }
+                                                               $dateParamString = $this->convertDateFormat($_POST[$paramName.'_date']);
+                                                               if (NULL == $dateParamString) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = 'Date is not valid.';
+                                                               }
+                                                       break;
+                                                       
+                                                       case 'month_trunc':
+                                                               if (!isset($_POST[$paramName.'_date_month']) || !isset($_POST[$paramName.'_date_year'])) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = "Missing date year+month value $paramName";
+                                                                       break;
+                                                               }
+                                                               $dateParamString = $_POST[$paramName.'_date_year'].'-'.$_POST[$paramName.'_date_month'];
+                                                               if (NULL == $dateParamString) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = 'Year+Month is not valid.';
+                                                               }
+                                                       break;
+
+                                                       case 'year_trunc':
+                                                               if (!isset($_POST[$paramName.'_date_year'])) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = "Missing date year value $paramName";
+                                                                       break;
+                                                               }
+                                                               $dateParamString = $_POST[$paramName.'_date_year'];
+                                                               if (NULL == $dateParamString) {
+                                                                       $paramsOK = false;
+                                                                       $paramsErrorMessage = 'Year is not valid.';
+                                                               }
                                                        break;
-                                               }
-                                               $dateParamString = $this->convertDateFormat($_POST[$paramName.'_date']);
-                                               if (NULL == $dateParamString) {
-                                                       $paramsOK = false;
-                                                       $paramsErrorMessage = 'Date is not valid.';
                                                }
                                        }
                                
                                        if ($lowerOp == 'between') {
                                                //process between range         
-       
+
                                                $range = true;  
                                                if (!isset($_POST[$paramName.'_end_type'])) {
                                                        $paramsOK = false;
@@ -251,7 +282,7 @@ class scheduleController {
                                                                break;
                                                        }
                                                        $dateEndParam['transform'] = 'relative_'.$userParam->transform;
-                                                       $dateEndParam['params'] =  (array)$_POST[$paramName.'_end_relative_value'];
+                                                       $dateEndParam['params'] =  (array)$_POST[$paramName.'_end_relative_value'];                                                     
                                                }
                                                else {
                                                        if (!isset($_POST[$paramName.'_end_date'])) {
@@ -267,6 +298,8 @@ class scheduleController {
                                                }               
                                        }
                                        
+                                       
+                                       
                                        if (NULL != $dateParamString)
                                                $startDate = $dateParamString;          //real date string
                                        else
@@ -309,7 +342,7 @@ class scheduleController {
                                                        
                        }
                }
-               
+
                if (isset($_POST['pivotLabelColumn']) && isset($_POST['pivotDataColumn'])) {
                        $userParams['__pivot_label'] = $_POST['pivotLabelColumn'];
                        $userParams['__pivot_data'] = $_POST['pivotDataColumn'];
@@ -318,6 +351,7 @@ class scheduleController {
                if ($paramsOK) {
                        $reportParams = new stdClass();
                        $reportParams->data = json_encode($userParams);
+
                        if (NULL == $reportParams->data) {
                                new displayMessageView('JSON format error encoding report data.');
                                exit;
@@ -344,7 +378,7 @@ class scheduleController {
                                                                        
                        $scheduleObj = new schedule();
                        $result = $scheduleObj->submitReport($reportParams, $scheduleParams, $updateIDs);
-                       
+       
                        if ($result->success) {
                                if (NULL == $updateIDs)
                                        new displayMessageView('The report was sent to the scheduler.', true);
diff --git a/lib/site_v1.4.js b/lib/site_v1.4.js
deleted file mode 100644 (file)
index 95538df..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-var lastExpandedGroupName;
-var lastSelectAll = false;
-var lastSelectAllBills = false;
-var lastSelectAllHolds = false;
-var lastSelectAllPatrons = false;
-var lastSelectAllCollections = false;
-var lastSelectAllCirculations = false;
-
-function toggleReportShowHide(className, labelName) {
-       var list = document.getElementsByClassName(className);
-       if (list.length>0) {
-               for (var i = 0; i < list.length; i++) {
-                       if (reportFiltersState[className]) {
-                               list[i].style.display="table-row";      
-                       }
-                       else {
-                               list[i].style.display="none";
-                       }
-               }
-       }
-       reportFiltersState[className]=!reportFiltersState[className];   //toggle
-       if (reportFiltersState[className])
-               document.getElementById(labelName).innerHTML="+Show";
-       else
-               document.getElementById(labelName).innerHTML="-Hide";
-}
-
-function toggleRealRelativeDate(dateTypeElement, spanTagReal, spanTagRelative) {
-       if (dateTypeElement.value == "real") {
-               document.getElementById(spanTagReal).style.display = "";
-               document.getElementById(spanTagRelative).style.display = "none";
-       }
-       else {
-               document.getElementById(spanTagReal).style.display = "none";
-               document.getElementById(spanTagRelative).style.display = "";
-       }
-}
-
-function toggleCollapsibleSection(group) {
-       var rows;
-       var hide;
-       var spanPlusMinus = group + "_plus";
-       var rowName = group + "_row";
-
-       rows = document.getElementsByClassName(rowName);
-       if (!rows[0].className.match(/(?:^|\s)hideRow(?!\S)/) ) {
-               hide = true;
-               lastExpandedGroupName = undefined;
-               document.getElementById(spanPlusMinus).innerHTML = "+";
-       }
-       else {
-               hide = false;
-               if (typeof lastExpandedGroupName != 'undefined' && lastExpandedGroupName != group) toggleCollapsibleSection(lastExpandedGroupName);
-               lastExpandedGroupName = group;
-               document.getElementById(spanPlusMinus).innerHTML = "-";         
-       }
-       for(var i=0; i<rows.length; i++) {
-               if (hide)               
-                       rows[i].className += " hideRow ";
-               else
-                       rows[i].className = rows[i].className.replace("hideRow" , "");
-       }
-}
-
-function confirmDeleteReport(id, name, action, adminView, recurs, url) {
-       var message;
-       message = action + " the report "+name+"?";
-       if (recurs==1) message = message + "\r\nAll future recurrences will also be canceled.";
-       if (confirm(message)) {
-               url = url + "c/" + id + "/";
-               if (adminView) url = url + "a/";
-               window.location.href = url; 
-               return true;
-       } 
-       return false;
-}
-
-function showSelectChoices(list, span) {
-       var html='';
-       for (var i=0; i<list.length; i++) {
-               if (list[i].selected) html = html + list[i].label.trim() + "&nbsp;&nbsp;<br>";
-       }
-       document.getElementById(span).innerHTML=html;
-}
-
-function selectAllMultiselect(listName) {
-       var list = document.getElementById(listName);
-       for(var i=0; i<list.options.length; i++) {
-               list.options[i].selected = true; 
-       }
-       showSelectChoices(list, listName+"_selected");
-}
-
-function toggleAllCheckboxes(className) {
-
-       switch (className) {
-       case "executiveReportCheckbox":
-               toggleState = !lastSelectAll;
-               lastSelectAll = !lastSelectAll;
-               lastSelectAllBills = !lastSelectAllBills;
-               lastSelectAllHolds = !lastSelectAllHolds;
-               lastSelectAllPatrons = !lastSelectAllPatrons;
-               lastSelectAllCollections = !lastSelectAllCollections;
-               lastSelectAllCirculations = !lastSelectAllCirculations;
-               break;
-       case "holds":
-               lastSelectAllHolds = !lastSelectAllHolds;
-               toggleState = lastSelectAllHolds;
-               break;
-       case "bills":
-               lastSelectAllBills = !lastSelectAllBills;
-               toggleState = lastSelectAllBills;
-               break;
-       case "patrons": 
-               lastSelectAllPatrons = !lastSelectAllPatrons;
-               toggleState = lastSelectAllPatrons;
-               break;
-       case "collections":
-               lastSelectAllCollections = !lastSelectAllCollections;
-               toggleState = lastSelectAllCollections;
-               break;
-       case "circulations":
-               lastSelectAllCirculations = !lastSelectAllCirculations;
-               toggleState = lastSelectAllCirculations;
-               break;
-       }
-       
-       var list = document.getElementsByClassName(className);
-       for(var i=0; i<list.length; i++) {
-               list[i].checked = toggleState; 
-       }
-       
-       var newText = (toggleState) ? 'Clear All' : 'Select All';
-       if (className == "executiveReportCheckbox") document.getElementById("selectAllReportsLink").text = newText;
-       if (className == "executiveReportCheckbox" || className == "patrons") {
-               document.getElementById("patronsSelectAllReportsLink").text = newText;
-       }
-       if (className == "executiveReportCheckbox" || className == "bills") {
-               document.getElementById("billsSelectAllReportsLink").text = newText;
-       }
-       if (className == "executiveReportCheckbox" || className == "circulations") {
-               document.getElementById("circulationsSelectAllReportsLink").text = newText;
-       }
-       if (className == "executiveReportCheckbox" || className == "holds") {
-               document.getElementById("holdsSelectAllReportsLink").text = newText;
-       }
-       if (className == "executiveReportCheckbox" || className == "collections") {
-               document.getElementById("collectionsSelectAllReportsLink").text = newText;
-       }
-}
-
-function submitExecutiveReport() {
-       var numChecked = 0;
-       var reportList = document.getElementsByClassName("executiveReportCheckbox");
-       for (var i=0; i<reportList.length; i++) {
-               if (reportList[i].checked) {
-                       numChecked++;
-                       break;
-               }
-       }
-       if (0 == numChecked) {
-               alert("Please select one or more reports.");
-               return false;
-       }
-       return true;
-}
-
-function setExecutiveReportDate(offset) {
-       var today=new Date();
-       var thisYear=today.getFullYear();
-       var thisMonth=today.getMonth();
-       var reportMonth;
-       var reportYear;
-       var reportYearIndex;
-       
-       if (0 == offset) {
-               if (0 == thisMonth) {
-                       reportMonth = 11;
-                       reportYear = thisYear - 1;
-               }
-               else {
-                       reportMonth = thisMonth - 1;
-                       reportYearIndex = 0;
-               }
-       }
-       else {
-               reportMonth = document.getElementById("reportMonth").selectedIndex + offset;
-               reportYearIndex = document.getElementById("reportYear").selectedIndex;
-               if (reportMonth < 0 && reportYearIndex == document.getElementById("reportYear").length-1) return;
-               if (reportMonth > thisMonth-1 && reportYearIndex == 0) return;
-               if (reportMonth > 11) {
-                       reportMonth = 0;
-                       reportYearIndex -= 1;
-               }
-               else if (reportMonth < 0) {
-                       reportMonth = 11;
-                       reportYearIndex += 1;
-               }               
-       }
-       document.getElementById("reportMonth").selectedIndex = reportMonth;
-       document.getElementById("reportYear").selectedIndex = reportYearIndex;          
-}
-
-function submitReport(action) {
-
-       var userInputs;
-       var dateTypeName;
-       var colName;
-       
-       if (document.getElementById("name").value.length==0) {
-               alert("Please enter a report name.");
-               return false;
-       }
-       
-       if (action == 'save') { 
-               return true;
-       }
-
-       userInputs = document.getElementsByClassName('userInput');
-       for (var i=0; i<userInputs.length; i++) {
-               if (userInputs[i].classList.contains('userText') && userInputs[i].value=="") {
-                       if (userInputs[i].name.indexOf("_") != -1)
-                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
-                       else
-                               colName = columnNames[userInputs[i].name];
-                       alert("Please enter a value for " + colName);
-                       userInputs[i].focus();
-                       return false;
-               }
-               else if (userInputs[i].classList.contains('userInteger') && (userInputs[i].value=="" || !validateInteger(userInputs[i].value))) {
-                       if (userInputs[i].name.indexOf("_") != -1)
-                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
-                       else
-                               colName = columnNames[userInputs[i].name];
-                       alert("Please enter an integer for " + colName);
-                       userInputs[i].focus();
-                       return false;
-               }
-               else if (userInputs[i].classList.contains('userDate')) {
-                       dateTypeName = userInputs[i].name.replace("_date","_type");
-                       if (document.getElementById(dateTypeName).value == 'real' && !validDate(userInputs[i].value) ) {
-                               alert("You must specify a valid date for " + columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))]);
-                               userInputs[i].focus();
-                               return false;
-                       }
-               }
-               else if (userInputs[i].classList.contains('userSelect') && userInputs[i].selectedIndex==-1) {
-                       alert("Please select a value for " + columnNames[userInputs[i].name.replace("[]","")]);
-                       userInputs[i].focus();
-                       return false;                   
-               }
-       }
-       
-       if (!document.getElementById("intervalRadioOnce").checked && !document.getElementById("intervalRadioRecur").checked) {
-           alert("Please select the recurrence interval.");
-           return false;
-       }
-       if (document.getElementById("intervalRadioRecur").checked && (document.getElementById("interval").selectedIndex==0 || document.getElementById("intervalPeriod").selectedIndex==0)) {
-               alert("Please specify the recurrence frequency.");
-               return false;
-       }
-       
-       if (!document.getElementById("runTimeRadioASAP").checked && !document.getElementById("runTimeRadioScheduled").checked) {
-           alert("Please select the run time.");
-           return false;
-       }
-       if (document.getElementById("runTimeRadioScheduled").checked) {
-               if (document.getElementById("runDate").value=="") {
-                       alert("Please specify the scheduled run date.");
-                       return false;
-               }
-               if (!validDate(runDate.value)) {
-                       alert("Please specify a valid scheduled run date.");
-                       return false;                   
-               }
-       }
-       
-       if (!document.getElementById("excelOutput").checked && !document.getElementById("csvOutput").checked && !document.getElementById("htmlOutput").checked) {
-               alert("Please choose an output format.");
-               return false;
-       }
-       
-       return true;
-}
-
-function setDaysLabel(elem, spanTag){
-       if (elem.value == -1)
-               document.getElementById(spanTag).innerHTML = "Day";
-       else
-               document.getElementById(spanTag).innerHTML = "Days";
-}
-
-function validateInteger(n) {
-       if (isNaN(parseFloat(n)) || !isFinite(n)) return false;
-       return true;
-}
-
-function emptyString(s) {
-       return (s=="");
-}
-
-function validDate(date) {
-       var matches = /^(\d{2})[-\/](\d{2})[-\/](\d{4})$/.exec(date);
-    if (matches == null) return false;
-    var d = matches[2];
-    var m = matches[1];
-    var y = matches[3];
-    if (!validateInteger(y) || !validateInteger(m) || !validateInteger(d)) return false;
-    if (m < 1 || m > 12) return false;
-    if (d < 1 || d > 31) return false;
-    if ((m == 4 || m == 6 || m == 9 || m == 11) && d > 30) return false;
-       if (m ==2) {
-               if ((y % 400) == 0 || ((y % 4) == 0 && (y % 100) != 0)) {       //leap year
-                       if (d > 29) return false;
-               }       
-               else {  //not leap year
-                       if (d > 28) return false;
-               }
-       }
-    return true;
-}
-
-var win1=null;
-function openWindow(html) {
-       if (win1 != null && win1.open) win1.close();
-       win1=window.open('','win1','height=250,width=800,toolbar=no,location=no,menubar=no,titlebar=no,status=no,scrollbars=yes,resizable=yes,modal=yes');
-       win1.document.write("<pre>"+html+"</pre>");
-}
diff --git a/lib/site_v1.5.js b/lib/site_v1.5.js
deleted file mode 100644 (file)
index 4cd3f26..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-var lastExpandedGroupName;
-var lastSelectAll = false;
-var lastSelectAllState = [];
-function toggleReportShowHide(className, labelName) {
-       var list = document.getElementsByClassName(className);
-       if (list.length>0) {
-               for (var i = 0; i < list.length; i++) {
-                       if (reportFiltersState[className]) {
-                               list[i].style.display="table-row";      
-                       }
-                       else {
-                               list[i].style.display="none";
-                       }
-               }
-       }
-       reportFiltersState[className]=!reportFiltersState[className];   //toggle
-       if (reportFiltersState[className])
-               document.getElementById(labelName).innerHTML="+Show";
-       else
-               document.getElementById(labelName).innerHTML="-Hide";
-}
-
-function toggleRealRelativeDate(dateTypeElement, spanTagReal, spanTagRelative) {
-       if (dateTypeElement.value == "real") {
-               document.getElementById(spanTagReal).style.display = "";
-               document.getElementById(spanTagRelative).style.display = "none";
-       }
-       else {
-               document.getElementById(spanTagReal).style.display = "none";
-               document.getElementById(spanTagRelative).style.display = "";
-       }
-}
-
-function toggleCollapsibleSection(group) {
-       var rows;
-       var hide;
-       var spanPlusMinus = group + "_plus";
-       var rowName = group + "_row";
-
-       rows = document.getElementsByClassName(rowName);
-       if (!rows[0].className.match(/(?:^|\s)hideRow(?!\S)/) ) {
-               hide = true;
-               lastExpandedGroupName = undefined;
-               document.getElementById(spanPlusMinus).innerHTML = "+";
-       }
-       else {
-               hide = false;
-               if (typeof lastExpandedGroupName != 'undefined' && lastExpandedGroupName != group) toggleCollapsibleSection(lastExpandedGroupName);
-               lastExpandedGroupName = group;
-               document.getElementById(spanPlusMinus).innerHTML = "-";         
-       }
-       for(var i=0; i<rows.length; i++) {
-               if (hide)               
-                       rows[i].className += " hideRow ";
-               else
-                       rows[i].className = rows[i].className.replace("hideRow" , "");
-       }
-}
-
-function confirmDeleteReport(id, name, action, adminView, recurs, url) {
-       var message;
-       message = action + " the report "+name+"?";
-       if (recurs==1) message = message + "\r\nAll future recurrences will also be canceled.";
-       if (confirm(message)) {
-               url = url + "c/" + id + "/";
-               if (adminView) url = url + "a/";
-               window.location.href = url; 
-               return true;
-       } 
-       return false;
-}
-
-function showSelectChoices(list, span) {
-       var html='';
-       for (var i=0; i<list.length; i++) {
-               if (list[i].selected) html = html + list[i].label.trim() + "&nbsp;&nbsp;<br>";
-       }
-       document.getElementById(span).innerHTML=html;
-}
-
-function selectAllMultiselect(listName) {
-       var list = document.getElementById(listName);
-       for(var i=0; i<list.options.length; i++) {
-               list.options[i].selected = true; 
-       }
-       showSelectChoices(list, listName+"_selected");
-}
-
-function toggleAllCheckboxes(className) {
-       
-       if (className == "executiveReportCheckbox") {
-               toggleState = !lastSelectAll;
-               lastSelectAll = !lastSelectAll;
-               
-               for (var key in lastSelectAllState) {
-                       lastSelectAllState[key] = !lastSelectAllState[key]; 
-               }
-       }
-       else {
-               lastSelectAllState[className] = !lastSelectAllState[className];
-               toggleState = lastSelectAllState[className];
-       }
-       
-       var list = document.getElementsByClassName(className);
-       for (var i=0; i<list.length; i++) {
-               list[i].checked = toggleState;
-       }
-       
-       var newText = (toggleState) ? 'Clear All' : 'Select All';
-       if (className == "executiveReportCheckbox") document.getElementById("selectAllReportsLink").text = newText;
-       
-       for (var key in lastSelectAllState) {
-               if (className == "executiveReportCheckbox" || className == key) {
-                       document.getElementById(key+"SelectAllReportsLink").text = newText;
-               }
-       }
-}
-
-function submitExecutiveReport() {
-       var numChecked = 0;
-       var reportList = document.getElementsByClassName("executiveReportCheckbox");
-       for (var i=0; i<reportList.length; i++) {
-               if (reportList[i].checked) {
-                       numChecked++;
-                       break;
-               }
-       }
-       if (0 == numChecked) {
-               alert("Please select one or more reports.");
-               return false;
-       }
-       return true;
-}
-
-function setExecutiveReportDate(offset) {
-       var today=new Date();
-       var thisYear=today.getFullYear();
-       var thisMonth=today.getMonth();
-       var reportMonth;
-       var reportYear;
-       var reportYearIndex;
-       
-       if (0 == offset) {
-               if (0 == thisMonth) {
-                       reportMonth = 11;
-                       reportYear = thisYear - 1;
-               }
-               else {
-                       reportMonth = thisMonth - 1;
-                       reportYearIndex = 0;
-               }
-       }
-       else {
-               reportMonth = document.getElementById("reportMonth").selectedIndex + offset;
-               reportYearIndex = document.getElementById("reportYear").selectedIndex;
-               if (reportMonth < 0 && reportYearIndex == document.getElementById("reportYear").length-1) return;
-               if (reportMonth > thisMonth-1 && reportYearIndex == 0) return;
-               if (reportMonth > 11) {
-                       reportMonth = 0;
-                       reportYearIndex -= 1;
-               }
-               else if (reportMonth < 0) {
-                       reportMonth = 11;
-                       reportYearIndex += 1;
-               }               
-       }
-       document.getElementById("reportMonth").selectedIndex = reportMonth;
-       document.getElementById("reportYear").selectedIndex = reportYearIndex;          
-}
-
-function submitReport(action) {
-
-       var userInputs;
-       var dateTypeName;
-       var colName;
-       
-       if (document.getElementById("name").value.length==0) {
-               alert("Please enter a report name.");
-               return false;
-       }
-       
-       if (action == 'save') { 
-               return true;
-       }
-
-       userInputs = document.getElementsByClassName('userInput');
-       for (var i=0; i<userInputs.length; i++) {
-               if (userInputs[i].classList.contains('userText') && userInputs[i].value=="") {
-                       if (userInputs[i].name.indexOf("_") != -1)
-                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
-                       else
-                               colName = columnNames[userInputs[i].name];
-                       alert("Please enter a value for " + colName);
-                       userInputs[i].focus();
-                       return false;
-               }
-               else if (userInputs[i].classList.contains('userInteger') && (userInputs[i].value=="" || !validateInteger(userInputs[i].value))) {
-                       if (userInputs[i].name.indexOf("_") != -1)
-                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
-                       else
-                               colName = columnNames[userInputs[i].name];
-                       alert("Please enter an integer for " + colName);
-                       userInputs[i].focus();
-                       return false;
-               }
-               else if (userInputs[i].classList.contains('userDate')) {
-                       dateTypeName = userInputs[i].name.replace("_date","_type");
-                       if (document.getElementById(dateTypeName).value == 'real' && !validDate(userInputs[i].value) ) {
-                               alert("You must specify a valid date for " + columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))]);
-                               userInputs[i].focus();
-                               return false;
-                       }
-               }
-               else if (userInputs[i].classList.contains('userSelect') && userInputs[i].selectedIndex==-1) {
-                       alert("Please select a value for " + columnNames[userInputs[i].name.replace("[]","")]);
-                       userInputs[i].focus();
-                       return false;                   
-               }
-       }
-       
-       if (!document.getElementById("intervalRadioOnce").checked && !document.getElementById("intervalRadioRecur").checked) {
-           alert("Please select the recurrence interval.");
-           return false;
-       }
-       if (document.getElementById("intervalRadioRecur").checked && (document.getElementById("interval").selectedIndex==0 || document.getElementById("intervalPeriod").selectedIndex==0)) {
-               alert("Please specify the recurrence frequency.");
-               return false;
-       }
-       
-       if (!document.getElementById("runTimeRadioASAP").checked && !document.getElementById("runTimeRadioScheduled").checked) {
-           alert("Please select the run time.");
-           return false;
-       }
-       if (document.getElementById("runTimeRadioScheduled").checked) {
-               if (document.getElementById("runDate").value=="") {
-                       alert("Please specify the scheduled run date.");
-                       return false;
-               }
-               if (!validDate(runDate.value)) {
-                       alert("Please specify a valid scheduled run date.");
-                       return false;                   
-               }
-       }
-       
-       if (!document.getElementById("excelOutput").checked && !document.getElementById("csvOutput").checked && !document.getElementById("htmlOutput").checked) {
-               alert("Please choose an output format.");
-               return false;
-       }
-       
-       return true;
-}
-
-function setDaysLabel(elem, spanTag){
-       if (elem.value == -1)
-               document.getElementById(spanTag).innerHTML = "Day";
-       else
-               document.getElementById(spanTag).innerHTML = "Days";
-}
-
-function validateInteger(n) {
-       if (isNaN(parseFloat(n)) || !isFinite(n)) return false;
-       return true;
-}
-
-function emptyString(s) {
-       return (s=="");
-}
-
-function validDate(date) {
-       var matches = /^(\d{2})[-\/](\d{2})[-\/](\d{4})$/.exec(date);
-    if (matches == null) return false;
-    var d = matches[2];
-    var m = matches[1];
-    var y = matches[3];
-    if (!validateInteger(y) || !validateInteger(m) || !validateInteger(d)) return false;
-    if (m < 1 || m > 12) return false;
-    if (d < 1 || d > 31) return false;
-    if ((m == 4 || m == 6 || m == 9 || m == 11) && d > 30) return false;
-       if (m ==2) {
-               if ((y % 400) == 0 || ((y % 4) == 0 && (y % 100) != 0)) {       //leap year
-                       if (d > 29) return false;
-               }       
-               else {  //not leap year
-                       if (d > 28) return false;
-               }
-       }
-    return true;
-}
-
-var win1=null;
-function openWindow(html) {
-       if (win1 != null && win1.open) win1.close();
-       win1=window.open('','win1','height=250,width=800,toolbar=no,location=no,menubar=no,titlebar=no,status=no,scrollbars=yes,resizable=yes,modal=yes');
-       win1.document.write("<pre>"+html+"</pre>");
-}
-
diff --git a/lib/site_v1.6.js b/lib/site_v1.6.js
new file mode 100644 (file)
index 0000000..b13f0f5
--- /dev/null
@@ -0,0 +1,310 @@
+var lastExpandedGroupName;
+var lastSelectAll = false;
+var lastSelectAllState = [];
+function toggleReportShowHide(className, labelName) {
+       var list = document.getElementsByClassName(className);
+       if (list.length>0) {
+               for (var i = 0; i < list.length; i++) {
+                       if (reportFiltersState[className]) {
+                               list[i].style.display="table-row";      
+                       }
+                       else {
+                               list[i].style.display="none";
+                       }
+               }
+       }
+       reportFiltersState[className]=!reportFiltersState[className];   //toggle
+       if (reportFiltersState[className])
+               document.getElementById(labelName).innerHTML="+Show";
+       else
+               document.getElementById(labelName).innerHTML="-Hide";
+}
+
+function toggleRealRelativeDate(dateTypeElement, spanTagReal, spanTagRelative) {
+       if (dateTypeElement.value == "real") {
+               document.getElementById(spanTagReal).style.display = "";
+               document.getElementById(spanTagRelative).style.display = "none";
+       }
+       else {
+               document.getElementById(spanTagReal).style.display = "none";
+               document.getElementById(spanTagRelative).style.display = "";
+       }
+}
+
+function toggleCollapsibleSection(group) {
+       var rows;
+       var hide;
+       var spanPlusMinus = group + "_plus";
+       var rowName = group + "_row";
+
+       rows = document.getElementsByClassName(rowName);
+       if (!rows[0].className.match(/(?:^|\s)hideRow(?!\S)/) ) {
+               hide = true;
+               lastExpandedGroupName = undefined;
+               document.getElementById(spanPlusMinus).innerHTML = "+";
+       }
+       else {
+               hide = false;
+               if (typeof lastExpandedGroupName != 'undefined' && lastExpandedGroupName != group) toggleCollapsibleSection(lastExpandedGroupName);
+               lastExpandedGroupName = group;
+               document.getElementById(spanPlusMinus).innerHTML = "-";         
+       }
+       for(var i=0; i<rows.length; i++) {
+               if (hide)               
+                       rows[i].className += " hideRow ";
+               else
+                       rows[i].className = rows[i].className.replace("hideRow" , "");
+       }
+}
+
+function confirmDeleteReport(id, name, action, adminView, recurs, url) {
+       var message;
+       message = action + " the report "+name+"?";
+       if (recurs==1) message = message + "\r\nAll future recurrences will also be canceled.";
+       if (confirm(message)) {
+               url = url + "c/" + id + "/";
+               if (adminView) url = url + "a/";
+               window.location.href = url; 
+               return true;
+       } 
+       return false;
+}
+
+function showSelectChoices(list, span) {
+       var html='';
+       for (var i=0; i<list.length; i++) {
+               if (list[i].selected) html = html + list[i].label.trim() + "&nbsp;&nbsp;<br>";
+       }
+       document.getElementById(span).innerHTML=html;
+}
+
+function selectAllMultiselect(listName) {
+       var list = document.getElementById(listName);
+       for(var i=0; i<list.options.length; i++) {
+               list.options[i].selected = true; 
+       }
+       showSelectChoices(list, listName+"_selected");
+}
+
+function toggleAllCheckboxes(className) {
+       
+       if (className == "executiveReportCheckbox") {
+               toggleState = !lastSelectAll;
+               lastSelectAll = !lastSelectAll;
+               
+               for (var key in lastSelectAllState) {
+                       lastSelectAllState[key] = !lastSelectAllState[key]; 
+               }
+       }
+       else {
+               lastSelectAllState[className] = !lastSelectAllState[className];
+               toggleState = lastSelectAllState[className];
+       }
+       
+       var list = document.getElementsByClassName(className);
+       for (var i=0; i<list.length; i++) {
+               list[i].checked = toggleState;
+       }
+       
+       var newText = (toggleState) ? 'Clear All' : 'Select All';
+       if (className == "executiveReportCheckbox") document.getElementById("selectAllReportsLink").text = newText;
+       
+       for (var key in lastSelectAllState) {
+               if (className == "executiveReportCheckbox" || className == key) {
+                       document.getElementById(key+"SelectAllReportsLink").text = newText;
+               }
+       }
+}
+
+function submitExecutiveReport() {
+       var numChecked = 0;
+       var reportList = document.getElementsByClassName("executiveReportCheckbox");
+       for (var i=0; i<reportList.length; i++) {
+               if (reportList[i].checked) {
+                       numChecked++;
+                       break;
+               }
+       }
+       if (0 == numChecked) {
+               alert("Please select one or more reports.");
+               return false;
+       }
+       return true;
+}
+
+function setExecutiveReportDate(offset) {
+       var today=new Date();
+       var thisYear=today.getFullYear();
+       var thisMonth=today.getMonth();
+       var reportMonth;
+       var reportYear;
+       var reportYearIndex;
+       
+       if (0 == offset) {
+               if (0 == thisMonth) {
+                       reportMonth = 11;
+                       reportYear = thisYear - 1;
+               }
+               else {
+                       reportMonth = thisMonth - 1;
+                       reportYearIndex = 0;
+               }
+       }
+       else {
+               reportMonth = document.getElementById("reportMonth").selectedIndex + offset;
+               reportYearIndex = document.getElementById("reportYear").selectedIndex;
+               if (reportMonth < 0 && reportYearIndex == document.getElementById("reportYear").length-1) return;
+               if (reportMonth > thisMonth-1 && reportYearIndex == 0) return;
+               if (reportMonth > 11) {
+                       reportMonth = 0;
+                       reportYearIndex -= 1;
+               }
+               else if (reportMonth < 0) {
+                       reportMonth = 11;
+                       reportYearIndex += 1;
+               }               
+       }
+       document.getElementById("reportMonth").selectedIndex = reportMonth;
+       document.getElementById("reportYear").selectedIndex = reportYearIndex;          
+}
+
+function submitReport(action) {
+
+       var userInputs;
+       var dateTypeName;
+       var colName;
+       
+       if (document.getElementById("name").value.length==0) {
+               alert("Please enter a report name.");
+               return false;
+       }
+       
+       if (action == 'save') { 
+               return true;
+       }
+
+       userInputs = document.getElementsByClassName('userInput');
+       for (var i=0; i<userInputs.length; i++) {
+               if (userInputs[i].classList.contains('userText') && userInputs[i].value=="") {
+                       if (userInputs[i].name.indexOf("_") != -1)
+                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
+                       else
+                               colName = columnNames[userInputs[i].name];
+                       alert("Please enter a value for " + colName);
+                       userInputs[i].focus();
+                       return false;
+               }
+               else if (userInputs[i].classList.contains('userInteger') && (userInputs[i].value=="" || !validateInteger(userInputs[i].value))) {
+                       if (userInputs[i].name.indexOf("_") != -1)
+                               colName = columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))];
+                       else
+                               colName = columnNames[userInputs[i].name];
+                       alert("Please enter an integer for " + colName);
+                       userInputs[i].focus();
+                       return false;
+               }
+               else if (userInputs[i].classList.contains('userDate')) {
+                       dateTypeName = userInputs[i].name.replace("_date","_type");
+                       if (document.getElementById(dateTypeName).value == 'real' && !validDate(userInputs[i].value) ) {
+                               alert("You must specify a valid date for " + columnNames[userInputs[i].name.substring(0,userInputs[i].name.indexOf("_"))]);
+                               userInputs[i].focus();
+                               return false;
+                       }
+               }
+               else if (userInputs[i].classList.contains('userSelect') && userInputs[i].selectedIndex==-1) {
+                       alert("Please select a value for " + columnNames[userInputs[i].name.replace("[]","")]);
+                       userInputs[i].focus();
+                       return false;                   
+               }
+       }
+       
+       if (!document.getElementById("intervalRadioOnce").checked && !document.getElementById("intervalRadioRecur").checked) {
+           alert("Please select the recurrence interval.");
+           return false;
+       }
+       if (document.getElementById("intervalRadioRecur").checked && (document.getElementById("interval").selectedIndex==0 || document.getElementById("intervalPeriod").selectedIndex==0)) {
+               alert("Please specify the recurrence frequency.");
+               return false;
+       }
+       
+       if (!document.getElementById("runTimeRadioASAP").checked && !document.getElementById("runTimeRadioScheduled").checked) {
+           alert("Please select the run time.");
+           return false;
+       }
+       if (document.getElementById("runTimeRadioScheduled").checked) {
+               if (document.getElementById("runDate").value=="") {
+                       alert("Please specify the scheduled run date.");
+                       return false;
+               }
+               if (!validDate(runDate.value)) {
+                       alert("Please specify a valid scheduled run date.");
+                       return false;                   
+               }
+       }
+       
+       if (!document.getElementById("excelOutput").checked && !document.getElementById("csvOutput").checked && !document.getElementById("htmlOutput").checked) {
+               alert("Please choose an output format.");
+               return false;
+       }
+       
+       return true;
+}
+
+function setDaysLabel(elem, spanTag){
+       if (elem.value == -1)
+               document.getElementById(spanTag).innerHTML = "Day";
+       else
+               document.getElementById(spanTag).innerHTML = "Days";
+}
+
+function setMonthsLabel(elem, spanTag){
+       if (elem.value == -1)
+               document.getElementById(spanTag).innerHTML = "Month";
+       else
+               document.getElementById(spanTag).innerHTML = "Months";
+}
+
+function setYearsLabel(elem, spanTag){
+       if (elem.value == -1)
+               document.getElementById(spanTag).innerHTML = "Year";
+       else
+               document.getElementById(spanTag).innerHTML = "Years";
+}
+
+function validateInteger(n) {
+       if (isNaN(parseFloat(n)) || !isFinite(n)) return false;
+       return true;
+}
+
+function emptyString(s) {
+       return (s=="");
+}
+
+function validDate(date) {
+       var matches = /^(\d{2})[-\/](\d{2})[-\/](\d{4})$/.exec(date);
+    if (matches == null) return false;
+    var d = matches[2];
+    var m = matches[1];
+    var y = matches[3];
+    if (!validateInteger(y) || !validateInteger(m) || !validateInteger(d)) return false;
+    if (m < 1 || m > 12) return false;
+    if (d < 1 || d > 31) return false;
+    if ((m == 4 || m == 6 || m == 9 || m == 11) && d > 30) return false;
+       if (m ==2) {
+               if ((y % 400) == 0 || ((y % 4) == 0 && (y % 100) != 0)) {       //leap year
+                       if (d > 29) return false;
+               }       
+               else {  //not leap year
+                       if (d > 28) return false;
+               }
+       }
+    return true;
+}
+
+var win1=null;
+function openWindow(html) {
+       if (win1 != null && win1.open) win1.close();
+       win1=window.open('','win1','height=250,width=800,toolbar=no,location=no,menubar=no,titlebar=no,status=no,scrollbars=yes,resizable=yes,modal=yes');
+       win1.document.write("<pre>"+html+"</pre>");
+}
index 0bcb3c1..0153385 100644 (file)
@@ -17,8 +17,8 @@ class pageView {
        
                <link type="text/css" href="css/site_v1.6.css" rel="stylesheet">
                <?php if (QR_EXECUTIVE_REPORTS_ENABLED) echo '<link type="text/css" href="css/executiveReportMenu_v1.0.css" rel="stylesheet">'; ?>
-
-               <script type="text/JavaScript" src="lib/site_v1.5.js"></script> 
+               
+               <script type="text/JavaScript" src="lib/site_v1.6.js"></script> 
        </head>
        <body>
        <div id="page">
@@ -94,9 +94,8 @@ class pageView {
        <div id="footer">
        <br>  
        <?php 
-               echo '&copy; 2015-' . date('Y');
-               echo ' Georgia Public Library Service, a Unit of the University System of Georgia.<br/>';
-        echo '1800 Century Place Suite 150, Atlanta, GA 30345-4304 | 404-235-7200', QR_PAGE_FOOTER_TEXT;
+               echo '&#64; 2015-',date('Y');
+               echo 'Georgia Public Library Service, a Unit of the University System of Georgia.<br>', QR_PAGE_FOOTER_TEXT;
        ?>              
        <br><br>
        </div>
index 4bc66e1..abec704 100644 (file)
@@ -313,95 +313,98 @@ class reportView extends baseReportView {
 
        private function parseColumns($param) {
        
-               $p = $param;
-               if (is_array($p->param)) $p->param = implode(',', $p->param);   //if array convert it back to a string
+               if (is_array($param->param)) $param->param = implode(',', $param->param);       //if array convert it back to a string
 
-               $userParam = (substr($p->param,0,3) == '::P');                                  //user entered field or static
-               $lowerOp = strtolower($p->op);
-               $lowerParam = strtolower($p->param);
-               $lowerOpLabel = strtolower($p->opLabel);
-               $lowerDataType = strtolower($p->dataType);
-               $lowerTransform = strtolower($p->transform);
+               $userParam = (substr($param->param,0,3) == '::P');                                      //user entered field or static
+               $lowerOp = strtolower($param->op);
+               $lowerParam = strtolower($param->param);
+               $lowerOpLabel = strtolower($param->opLabel);
+               $lowerDataType = strtolower($param->dataType);
+               $lowerTransform = strtolower($param->transform);
        
                switch ($lowerOp) {
                        case '=':
-                               $p->opLabel='Equals';
+                               $param->opLabel='Equals';
                                break;
                        case 'between':
-                               $p->opLabel='Between';
+                               $param->opLabel='Between';
                                break;
                        case '<':
                                if ($lowerDataType == 'timestamp')
-                                       $p->opLabel='Before';
+                                       $param->opLabel='Before';
                                else
-                                       $p->opLabel='Less than';
+                                       $param->opLabel='Less than';
                                break;
                        case '<=':
                                if ($lowerDataType == 'timestamp')
-                                       $p->opLabel='On or before';
+                                       $param->opLabel='On or before';
                                else
-                                       $p->opLabel='Less than or equal to';
+                                       $param->opLabel='Less than or equal to';
                                break;                          
                        case '>':
                                if ($lowerDataType == 'timestamp')
-                                       $p->opLabel='After';
+                                       $param->opLabel='After';
                                else
-                                       $p->opLabel='Greater than';
+                                       $param->opLabel='Greater than';
                                break;
                        case '>=':
                                if ($lowerDataType == 'timestamp')
-                                       $p->opLabel='On or after';
+                                       $param->opLabel='On or after';
                                else
-                                       $p->opLabel='Greater than or equal to';
+                                       $param->opLabel='Greater than or equal to';
+                               break;
+                       case 'ilike':
+                               $param->opLabel='Substring Match<br>(ignore case)';
+                               break;
+                       case 'like':
+                               $param->opLabel='Substring Match<br>(case sensitive)';
                                break;
                        case 'in':
-                               $p->opLabel='In List';
+                               $param->opLabel='In List';
                                break;
                        case 'not in':
-                               $p->opLabel='Not In List';
+                               $param->opLabel='Not In List';
                                break;                  
                        case 'is':
-                               if (!$userParam && $lowerOpLabel == 'is null') {
-                                       $param->param = 'Null';
-                               }
-                               $p->opLabel='Is';
+                               if (!$userParam && $lowerOpLabel == 'is null') $param->param = 'Null';  //set displayed value
+                               $param->opLabel='Is';
                                break;
                        case 'is not':
-                               if (!$userParam && $lowerOpLabel == 'is not null') {
-                                       $param->param = 'Null';
-                               }
-                               $p->opLabel='Is Not';
+                               if (!$userParam && $lowerOpLabel == 'is not null') $param->param = 'Null';      //set displayed value
+                               $param->opLabel='Is Not';
                                break;
                        default:
-                               $p->opLabel='unknown action -'.$param->op;
+                               //Use opLabel - do not show error message
+                               if (substr($lowerOpLabel,0,3) == 'is ') {
+                                       $param->param = substr($param->opLabel,3);      //set displayed value
+                                       $param->opLabel='Is';                                   
+                               }       
                                break;
                }
        
                switch ($lowerTransform) {
                        case 'bare':
-                               $p->transformLabel = NULL;
+                               $param->transformLabel = NULL;
                                break;
                        case 'date':
-                               $p->transformLabel = NULL;
+                               $param->transformLabel = NULL;
                                break;
                }
        
                if (!$userParam && $lowerDataType == 'bool') {
-                       if ($lowerOp == '=') $p->opLabel='Is';
+                       if ($lowerOp == '=') $param->opLabel='Is';
                        if ($lowerParam == 't') {
-                               $p->param = 'True';
+                               $param->param = 'True';
                        }
                        else {  
-                               $p->param = 'False';
+                               $param->param = 'False';
                        }
                }
        
-               if ($userParam) {
-                       //generate user input fields
-                       $p->param = $this->generateUserInputFields($param);
-               }
+               //generate user input fields
+               if ($userParam) $param->param = $this->generateUserInputFields($param);
        
-               return $p;
+               return $param;
        }
        
        private function generateUserInputFields($param) {
@@ -444,22 +447,75 @@ class reportView extends baseReportView {
                                        case 'timestamp':
                                                $paramNameDate = $paramName.'_type';    //::Px_type - relative or real
                                                $dateType = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'real');
-                                               $cell .= '<span class="nowrap"><select name="'.$paramName.'_type" id="'.$paramName.'_type" onchange=\'toggleRealRelativeDate(this,"'.$paramName.'_calendar_span","'.$paramName.'_days_span");\'>';
+                                               $cell .= '<span class="nowrap"><select name="'.$paramName.'_type" id="'.$paramName.'_type" onchange=\'toggleRealRelativeDate(this,"'.$paramName.'_calendar_span","'.$paramName.'_period_span");\'>';
                                                $cell .= '<option '.(($dateType=='real')?' selected ':'').'value="real">Real Date</option><option '.(($dateType=='relative')?' selected ':'').'value="relative">Relative Date</option></select>&nbsp;';
                                                
-                                               $paramNameDate = $paramName.'_date';    //::Px_date value
-                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');
-                                               $cell .= '<span id="'.$paramName.'_calendar_span" '.(($dateType=='relative')?' style="display:none;"':'').'>
-                                               <input class="userDate userInput hasDatePicker" name="'.$paramName.'_date" id="'.$paramName.'_date" type="text" size="6" maxlength="10" value="'.$value.'"></span>
-                                               <script>
-                                               $(function() {$( "#'.$paramName.'_date" ).datepicker({});});
-                                               </script>';
+                                               switch ($lowerTransform) {
+                                                       case 'date':
+                                                               $paramNameDate = $paramName.'_date';    //::Px_date value
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');
+                                                               $cell .= '<span id="'.$paramName.'_calendar_span" '.(($dateType=='relative')?' style="display:none;"':'').'>
+                                                               <input class="userDate userInput hasDatePicker" name="'.$paramName.'_date" id="'.$paramName.'_date" type="text" size="6" maxlength="10" value="'.$value.'"></span>
+                                                               <script>
+                                                               $(function() {$( "#'.$paramName.'_date" ).datepicker({});});
+                                                               </script>';
+                                                                               
+                                                               $paramNameDate = $paramName.'_relative_value';  //::Px_relative_value (days)
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');                                                           
+                                                               $cell .= '<span id="'.$paramName.'_period_span" '.(($dateType=='real')?' style="display:none;"':'').'><select name="'.$paramName.'_relative_value" id="'.$paramName.'_relative_value" class="userInput" onchange="javascript:setDaysLabel(this, \''.$paramName.'_days_label\');">';
+                                                               for ($i = 1; $i <=90; $i++) $cell.='<option '.(($value == -$i)?' selected ':'').'value="-'.$i.'">'.$i.'</option>';
+                                                               $cell .= '</select> <span id="'.$paramName.'_days_label">Day'.(($value==-1)?'':'s').'</span> ago</span></span>';
+                                                       break;
+                                                       
+                                                       case 'month_trunc':
+                                                               $paramNameDate = $paramName.'_date_month';      //::Px_date_month value
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:date('m'));
+                                                               $cell .= '<span id="'.$paramName.'_calendar_span" '.(($dateType=='relative')?' style="display:none;"':'').'>
+                                                               <select name="'.$paramName.'_date_month" id="'.$paramName.'_date_month" type="text" class="userInput">';
+                                                               $cell.='<option '.(($value == '01')?' selected ':'').'value="01">Jan</option>';
+                                                               $cell.='<option '.(($value == '02')?' selected ':'').'value="02">Feb</option>';
+                                                               $cell.='<option '.(($value == '03')?' selected ':'').'value="03">Mar</option>';
+                                                               $cell.='<option '.(($value == '04')?' selected ':'').'value="04">Apr</option>';
+                                                               $cell.='<option '.(($value == '05')?' selected ':'').'value="05">May</option>';
+                                                               $cell.='<option '.(($value == '06')?' selected ':'').'value="06">Jun</option>';
+                                                               $cell.='<option '.(($value == '07')?' selected ':'').'value="07">Jul</option>';
+                                                               $cell.='<option '.(($value == '08')?' selected ':'').'value="08">Aug</option>';
+                                                               $cell.='<option '.(($value == '09')?' selected ':'').'value="09">Sep</option>';
+                                                               $cell.='<option '.(($value == '10')?' selected ':'').'value="10">Oct</option>';
+                                                               $cell.='<option '.(($value == '11')?' selected ':'').'value="11">Nov</option>';
+                                                               $cell.='<option '.(($value == '12')?' selected ':'').'value="12">Dec</option>';
+                                                               $cell .= '</select>&nbsp;';
+                                                               
+                                                               $paramNameDate = $paramName.'_date_year';       //::Px_date_year value
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:date('Y'));
+                                                               $cell .= '<select name="'.$paramName.'_date_year" id="'.$paramName.'_date_year" type="text" class="userInput">';
+                                                               for ($i = QR_REPORT_TRANSFORM_START_YEAR; $i <= date('Y'); $i++) $cell.='<option '.(($value == $i)?' selected ':'').'value="'.$i.'">'.$i.'</option>';
+                                                               $cell .= '</select></span>';
+                                                               
+                                                               //setup realtive values
+                                                               $paramNameDate = $paramName.'_relative_value';  //::Px_relative_value (months)
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');
+                                                               $cell .= '<span id="'.$paramName.'_period_span" '.(($dateType=='real')?' style="display:none;"':'').'><select name="'.$paramName.'_relative_value" id="'.$paramName.'_relative_value" class="userInput" onchange="javascript:setMonthsLabel(this, \''.$paramName.'_months_label\');">';
+                                                               for ($i = 1; $i <=48; $i++) $cell.='<option '.(($value == -$i)?' selected ':'').'value="-'.$i.'">'.$i.'</option>';
+                                                               $cell .= '</select> <span id="'.$paramName.'_months_label">Month'.(($value==-1)?'':'s').'</span> ago</span></span>';
+                                                       break;
+                                                               
+                                                       case 'year_trunc':                                                              
+                                                               $paramNameDate = $paramName.'_date_year';       //::Px_date_year value
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:date('Y'));
+                                                               $cell .= '<span id="'.$paramName.'_calendar_span" '.(($dateType=='relative')?' style="display:none;"':'').'>
+                                                               <select name="'.$paramName.'_date_year" id="'.$paramName.'_date_year" type="text" class="userInput">';
+                                                               for ($i = QR_REPORT_TRANSFORM_START_YEAR; $i <= date('Y'); $i++) $cell.='<option '.(($value == $i)?' selected ':'').'value="'.$i.'">'.$i.'</option>';
+                                                               $cell .= '</select></span>';
 
-                                               $paramNameDate = $paramName.'_relative_value';  //::Px_relative_value
-                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');
-                                               $cell .= '<span id="'.$paramName.'_days_span" '.(($dateType=='real')?' style="display:none;"':'').'><select name="'.$paramName.'_relative_value" id="'.$paramName.'_relative_value" class="userInput" onchange="javascript:setDaysLabel(this, \''.$paramName.'_days_label\');">';
-                                               for ($i = 1; $i <=90; $i++) $cell.='<option '.(($value == $i)?' selected ':'').'value="-'.$i.'">'.$i.'</option>';
-                                               $cell .= '</select> <span id="'.$paramName.'_days_label">Day</span> ago</span></span>';
+                                                               //setup realtive values
+                                                               $paramNameDate = $paramName.'_relative_value';  //::Px_relative_value (years)
+                                                               $value = (isset($this->defaultValues->paramsDecoded->$paramNameDate)?$this->defaultValues->paramsDecoded->$paramNameDate:'');
+                                                               $cell .= '<span id="'.$paramName.'_period_span" '.(($dateType=='real')?' style="display:none;"':'').'><select name="'.$paramName.'_relative_value" id="'.$paramName.'_relative_value" class="userInput" onchange="javascript:setYearsLabel(this, \''.$paramName.'_years_label\');">';
+                                                               for ($i = 1; $i <=10; $i++) $cell.='<option '.(($value == -$i)?' selected ':'').'value="-'.$i.'">'.$i.'</option>';
+                                                               $cell .= '</select> <span id="'.$paramName.'_years_label">Year'.(($value==-1)?'':'s').'</span> ago</span></span>';
+                                                       break;  
+                                               }       
                                                break;
        
                                        case 'text':