/** empty log object (if querystring contains debug=xxx, then this variable will be overwritten by debug.ascx) **/ var log = { trace: function () { }, debug: function () { }, info: function () { }, warn: function () { }, error: function () { }, fatal: function () { } }; if (!window.console) console = {log: function() {}}; var EQuIS = new Object(); EQuIS.addFilters = function (sender, filter, fire) { // sub function that will fire the filter event into all applicable iframe contexts // FB.116299 - this event needs to fire in each applicable iframe context function fireAllFrames(sender, filter, filters, win) { // first fire for current window/iframe context (note that I have to use the current windows's jquery and also EQuIS objects) if (typeof win.EQuIS != 'undefined' || typeof win.$ != 'undefined') { // don't procede with this window if the EQuIS or jQuery objects are not defined. win.$(win.EQuIS).trigger('filter', [sender, filter, filters]); // then fire for any other applicable iframe contexts for (var i = 0; i < win.frames.length; i++) { // recurse on any applicable child iframes if (window != win.frames[i]) { // don't recurse on itself. // put in try/catch block because trying to access frame properties that are cross-origin can be blocked throwing an exception try { fireAllFrames(sender, filter, filters, win.frames[i]); } catch(ex){} } } } } try { var filters = EQuIS.getFilters(); if (!filters) return; $.extend(filters, filter); EQuIS.setFilters(filters); if (fire != false) { fireAllFrames(sender, filter, filters, top); } } catch (ex) { console.error(ex.message); } }; // Clears all filters for the current tab EQuIS.clearFilters = function (options) { try { var filters = EQuIS.getFilters(); var facilityId = filters.facility_id; sessionStorage.removeItem("equis-filters"); if (options && options.facility_id == false) { EQuIS.addFilters(EQuIS, { facility_id: facilityId }, false); } } catch (ex) { console.error(ex.message); } }; // Gets the filters object for the current tab EQuIS.getFilters = function () { try { // TODO: allow user to choose localStorage instead of sessionStorage? if (!sessionStorage) return null; var filters = sessionStorage.getItem("equis-filters"); if (filters) { filters = JSON.parse(filters); } else { filters = {}; } return filters; } catch (ex) { console.error(ex.message); return null; } } // Gets the filters object for the current tab EQuIS.setFilters = function (filters) { try { if (!sessionStorage) return null; sessionStorage.setItem("equis-filters", JSON.stringify(filters)); } catch (ex) { console.error(ex.message); return null; } } EQuIS.beginRequestHandler = function (sender, args) { try { var headers = args.get_request().get_headers(); headers["equis-filters"] = JSON.stringify(EQuIS.getFilters()); } catch (ex) { console.error(ex.message); } } EQuIS.endRequestHandler = function (sender, args) { try { if (EQuIS.refreshQueue.length > 0) { isDashboardAjaxCall = false; // this needs to be set false so the widget command can be added and not cancelled. var widgetId = EQuIS.refreshQueue.shift(); EQuIS.refreshWidget(widgetId); } } catch (ex) { console.error(ex.message); } } EQuIS.setupRequestHandlers = function() { try { //FB.93599: dashboard filters var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm !== null) { prm.add_beginRequest(EQuIS.beginRequestHandler); prm.add_endRequest(EQuIS.endRequestHandler); } $.ajaxSetup({ beforeSend: function (xhr, settings) { xhr.setRequestHeader("equis-filters", JSON.stringify(EQuIS.getFilters())); } }); } catch (ex) { console.error(ex.message); } } EQuIS.refreshQueue = []; EQuIS.refreshWidget = function (widgetId) { try { var id = widgetId.toString(); if (!id.startsWith("DashboardSurface_db_")) id = "DashboardSurface_db_" + id; // queue refresh request. (don't add if already in queue). if (EQuIS.refreshQueue.indexOf(id) == -1) { EQuIS.refreshQueue.push(id); } // don't send command if already dashboard ajax. if (isDashboardAjaxCall) { return; } // only send command if in queue var index = EQuIS.refreshQueue.indexOf(id); if (index > -1) { // remove from queue EQuIS.refreshQueue.splice(index, 1); // send refresh command doWidgetCmd(null, { "widgetId": id, "commandName": "refresh", "commandArg": {} }, null, null); } } catch (ex) { console.error(ex.message, ex); } }; EQuIS.dashboardId = function () { try { return $('[id$=DashboardInstanceKey]').val(); } catch (ex) { console.error(ex.message); return null; } }; EQuIS.facilityId = function (id) { try { var el = $('[id$=FacilityChooser_SelectedValue]'); if (typeof (id) === "undefined" || id == null) { return el.val(); } else { var scope = el.scope(); scope.generic.set_value(id); } } catch (ex) { console.error(ex.message); return null; } }; EQuIS.localizeDates = function (selector) { try { $(selector).each(function (i, el) { console.log('localizeDates: ' + selector); try { if (!$.isNumeric($(el).text())) return; var ticks = parseInt($(el).text()); //if (isNaN(ticks)) return; var dt = new Date(ticks); if (dt.getUTCFullYear() < 2000) return; //FB.95382 - fix to weed out erroneus dates from being displayed. //dt.toLocaleString() behaves differently on different browsers ... var str = $.datepicker.formatDate("yy-mm-dd ", dt) + dt.toLocaleTimeString(); $(el).text(str); } catch (ex) { console.log(ex.message); } }); } catch (ex) { console.log(ex.message); } }; EQuIS.showMask = function (message) { try { // always hide any existing mask before showing a new mask EQuIS.hideMask(); // use default message if not provided if (!message) message = 'Please wait ...'; // get mask target var maskTarget = document.getElementById('DashboardSurface'); if (maskTarget == null) return; setLoadMask(maskTarget, message); // this will prevent Kalitte's EndRequestHandler from automatically hiding the mask window.currentMask = null; ShowMasks(); } catch (ex) { console.error("showMask: " + ex.message); } }; EQuIS.hideMask = function () { try { KillMask('DashboardSurface'); } catch (ex) { console.debug("hideMask: " + ex.message); } }; EQuIS.submitDownload = function (action, data, outputType, callback, showMaskOpt) { if (typeof (showMaskOpt) === 'undefined') showMaskOpt = true; // FB.93039 need to call submitDownload without having the loading mask. so this sets a default value. try { //FB.95035,953836 show the mask while waiting for the download (FB.93039 - but don't show if called with showMaskOpt set to false). if (showMaskOpt) EQuIS.showMask(); // set the form data $('#download_data').val(data); $('#output_type').val(outputType); $('#equis-filters').val(JSON.stringify(EQuIS.getFilters())); // clear the download cookie try { document.cookie = "download=;expires=" + new Date(1000).toUTCString() + ";path=/"; $($('#downloadFrame').contents()[0].documentElement).empty(); } catch (ex) { console.debug("error clearing download info: " + ex.message); } // set action and submit var form = $('#download'); //form.attr('action', action); form.submit(); // start polling for download completion (inspired by http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/) var interval = 100; setTimeout(function () { EQuIS.checkDownload(0, interval, callback); }, interval); } catch (ex) { log.error('submitDownload: ' + ex.message); EQuIS.hideMask(); } }; // This value corresponds to Web.config/system.web/httpRuntime/executiontimeout // and is the number of seconds that checkDownload will wait before removing the wait mask. // This value will be overwritten by default.aspx based on the current setting in Web.config EQuIS.ExecutionTimeout = 240; EQuIS.checkDownload = function (counter, interval, callback) { try { // check for download cookie (set by download.aspx.cs) that indicates the download has completed if (document.cookie.indexOf("download=ok") != -1) { // invoke the callback if (typeof (callback) == 'function') { callback.call(); } // clear the download cookie document.cookie = "download=;expires=" + new Date(1000).toUTCString() + ";path=/"; // remove the mask EQuIS.hideMask(); return; } // check iframe for error message try { var contents = $('#downloadFrame').contents(); if (contents.length > 0 && contents[0].readyState == "complete") { var text = $(contents[0].documentElement).text().trim(); if (text.length > 0) { alert(text); // remove the mask EQuIS.hideMask(); return; } } } catch (ex) { console.debug(ex.message); } // check for counter expiration (interval is in milliseconds; ExecutionTimeout is in seconds) if (counter > ((1000 / interval) * EQuIS.ExecutionTimeout)) { // remove the mask EQuIS.hideMask(); return; } // if we get here, the download is not ready yet setTimeout(function () { EQuIS.checkDownload(++counter, interval, callback); }, interval); } catch (ex) { log.error('checkDownload: ' + ex.message); EQuIS.hideMask(); } }; EQuIS.echo = function(filename, mimetype, content) { try { var data = { 'filename': filename, 'mimetype': mimetype, 'content': content }; var action = 'explorer/echo'; this.submitDownload(action, JSON.stringify(data)); } catch(ex) { log.error('echo: ' + ex.message); } }; EQuIS.deleteDashboard = function () { try { if (confirm('Are you sure you want to delete the current dashboard and all of its sections, columns, and widgets?')) { return true; } else { return false; } } catch (ex) { log.error('deleteDashboard: ' + ex.message); } }; EQuIS.editDashboard = function () { try { var dashboardID = $('[id$=DashboardInstanceKey]').val(); var widget = { 'widgetConfig': { 'instanceKey': '$' + dashboardID} }; var props = { 'commandArg': { 'width': 0, 'height': 0, 'title': 'Dashboard Editor'} }; //asynchronously displays the window editorWindow(null, props, widget); } catch (ex) { log.error('editDashboard: ' + ex.message); } }; EQuIS.openDialog = function (options) { try { if (options == null || options.dialog == null || options.dialog.length == 0) return; var html = document.documentElement; var dialogHeight = html.clientHeight - 100; var dialogWidth = html.clientWidth - 100; if (options.width && options.width > 0) dialogWidth = options.width; if (options.height && options.height > 0) dialogHeight = options.height; var frameHeight = dialogHeight - 76.0; var frameWidth = dialogWidth - 36.0; // append the dialog dimensions to url var url = "dialog.aspx?dialog=" + encodeURIComponent(options.dialog) + "&h=" + frameHeight.toString() + "&w=" + frameWidth.toString(); // append filters var filters = EQuIS.getFilters(); if (Object.getOwnPropertyNames(filters).length > 0) url = url + "&equis-filters=" + encodeURIComponent(JSON.stringify(filters)); // create the IFRAME var iframe = $(""); var blankSrc = "about:blank"; iframe.appendTo("#equisDialog") .attr("frameborder", "0") .attr("height", frameHeight) .attr("width", frameWidth) .attr("src",blankSrc); // start with empty iframe. will set source to equis dialog later // create form with dialog params as values var optionsDiv = $('
'); if (options.params != null) { var keys = Object.keys(options.params); for (var i = 0; i < keys.length; i++) { // FB.107220 If parameters are large, they can cause the url string to be larger than 2K bytes, which in most systems will be longer than the max allowed. // Need to have a way to POST these parameters. The method below fails for the POST method in IE on a postback because there is a problems with the jQuery // library up to at least 1.11.1 where trying to access the iframe's contents in the iframe load method below after the first submit causes a "SCRIPT70: Permission Denied" // error in IE. Chrome and Firefox do not have this issue. This means that if the IWebDialog's Save method needs any of these parameters, it will not be available on that PostBack. // Currently, no implementation of the EQuIS Dialog has any large parameters to be Posted that that method, so everything will work by putting smaller parameters in // the URL, which will persist. See notes in case 107220. if ((keys[i] + options.params[keys[i]]).length > 100) { // if it is a large parameter, POST it to the iframe by putting it in a form input to be submitted. var inp = $('').appendTo(optionsDiv); inp.val(options.params[keys[i]]); } else { // it is a small parameter value, can just submit via GET as part of URL. if (options.params[keys[i]] && options.params[keys[i]].toString().length > 0) // don't add if value is empty or null url += "&" + keys[i] + "=" + encodeURIComponent(options.params[keys[i]]); } } } var optionsForm = $(''); var optionsDivCopy = $(optionsDiv.html()); // need a copy if this div that isn't inserted attached to the iframe to avoid the "SCRIPT70: Permission Denied" error in IE when trying to access iframe contents. optionsDiv.appendTo(optionsForm); // put form in iframe and submit it to call dialog with post parameters iframe.on("load", function () { if (iframe.contents().find('form#form1').length == 0) { // form#form1 not there, this is the blank iframe. Attach the parameter form and submit to blank iframe to load real url. $(this).contents().find('body').append(optionsForm); // only append one time optionsForm.submit(); } else { if (optionsDivCopy.find('input').length > 0) { // don't try to add anything if there are not parameters to add. $(this).contents().find('form#form1').append(optionsDiv); // attach the hidden fields so they are in the POST information on every postback. // this is assuming that the iframe contents will be based on the Dialog.aspx page which has a form#form1 element. } // FB.109575 weird bug in jquery in IE10 and IE11 that makes all text fields inaccessible in the iframe and on the dashbaord surface. This fixes the text fields in the iframe. $(this).contents('input[type=text]').first().focus(); } }); // save callbacks if (options.onsave && typeof (options.onsave) === "function") { iframe.bind("onsave", options.onsave); } if (options.oncancel && typeof (options.oncancel) === "function") { iframe.bind("oncancel", options.oncancel); } // set the data object (if applicable) if (options.data) { $("#equisDialog").data("data", options.data); } // show the dialog $("#equisDialog").dialog({ autoOpen: true, height: dialogHeight, width: dialogWidth, title: options.title, resizable: false, closeText: 'Close', dialogClass: 'ui-dialog', modal: true, stack: true, close: function (e, ui) { $(this).empty().hide(); // FB.109575 fix text fields on dashboard surface. blurring (loosing focus) to not have cursor in field after close. Just needed to fix weird bug. $("input[type=text]").not(':hidden').first().focus().blur(); } }); //NOTE cbp 09/05/2013: This was causing issues with jQuery Dialog. jQuery Dialog was trying to load its own sprite set for some reason. //I commented out this code, and modified the code for ui-dialog-help below // force the close button to look like the x-tool x-tool-close //$(".ui-dialog-titlebar-close") // .attr("class", "x-tool x-tool-close") // .css("background-color", "#DADBDD") // .css("background-image", "url(App_Themes/images/earthsoft/panel/tool-sprites.png)") // .mouseover(function () { // $(this).attr("class", "x-tool x-tool-close") // .css("background-color", "#DADBDD") // .css("background-image", "url(App_Themes/images/earthsoft/panel/tool-sprites.png)"); // }) // .empty(); var btn = $(".ui-dialog-help"); if (!btn.length) { btn = $("") //cbp 09/05/2013 TESTING //.css("background-color", "orange") .css("margin-right", "12px") .css("margin-top", "-2.5px") .css("width", "43px") .css("height", "32px") .css("float", "right") .attr("title", 'Click here for help using this screen.') .append("") .appendTo(".ui-dialog-titlebar"); } // FB.119728 - replacing old url with new context sensative help menu on the Dialog header var helpPopupOptions = { HelpContextType: 'equisDialog' }; btn.find('img').HelpPopup(helpPopupOptions); } catch (ex) { console.log('openDialog: ' + ex.message); } }; EQuIS.closeDialog = function (action, data, reload) { try { var dlg = $("#equisDialog"); // trigger callbacks var iframe = dlg.children("iframe:first"); if (action != null && action == "save") { iframe.trigger('onsave', data); } else { iframe.trigger('oncancel', data); } dlg.dialog('close'); dlg.empty(); if (reload) window.location.reload(); } catch (ex) { log.error('closeDialog: ' + ex.message); } }; EQuIS.addEditorHelpButton = function (helpTopic) { try { var btn = $(".x-window-tl > .x-window-tr > .x-window-tc > .x-window-header > .editor-window-help"); if (!btn.length) { btn = $('') .attr("title", 'Click here for help using this screen.'); //.append(""); var close = $(".x-window-tl > .x-window-tr > .x-window-tc > .x-window-header > .x-tool-close"); close.after(btn); } // FB.119728 - replacing old url with new context sensative help menu on widget and dashboard editor header var helpPopupOptions = { HelpContextType: 'widgetEditor' }; btn.HelpPopup(helpPopupOptions); } catch (ex) { console.log(ex.message); } }; /** function that is called after the dashboard is loaded (window.load and document.ready do not always work) **/ EQuIS.dashboardReady = function (permission) { try { if ($("#DashboardSurface_db").length == 0) console.log("DashboardSurface_db not ready"); /** Widget context menus **/ try { // FB.95900+101337+113624: Editor can modify widgets; Owner can add/remove widgets // for each widget in dashboard, create a context menu. $(".x-panel > .x-panel-tl").each(function (index) { var widgetId = $(this).parent().attr('id'); var header = $(this).find(".x-panel-tr > .x-panel-tc > .x-panel-header > .x-panel-header-text"); if (header.length > 0) header = header[0]; var headerElement = this; var contextMenuItems = [ // menu options for any user { label: 'View Documentation', icon: "assets/images/book_dark.svg", action: function () { // get help topic id for widget if it exists. var helpDocLink = 'help/index.htm'; var helpTopicId = ''; var widgetParent = $(headerElement).next('div.x-panel-bwrap').find('div.x-panel-body').children('div:first').children('div:first'); // try to find the topic id in the update panel var element = widgetParent.find('[Help-Context-Id]'); if (element.length > 0) { // found a div (update panel) with a "Help-Context-Id" attribute. helpTopicId = $(element[0]).attr('Help-Context-Id'); // just grab first (if more than one element have this attribute) } if (helpTopicId != '') helpDocLink += '?contextid=' + helpTopicId; // open url in new 'Help' window/tab window.open(helpDocLink, 'Help'); } }, { label: 'Contact Help Desk', icon: 'assets/images/eia_dark.svg', action: function(){ window.open('SupportRequest.aspx','Help'); } }, { label: 'Visit Community Center', icon: 'assets/images/earthsoft_earth_16.png', action: function () { window.open('http://community.earthsoft.com/default.aspx?d=200', 'Help'); } }, // need to still add link for customer support and for community center link. null, { label: 'Refresh Data', tooltip: 'Refresh this widget and its data (i.e. force refresh of cached report output).', icon: "assets/images/Viewer16.png", action: function () { doWidgetCmd(null, { "widgetId": widgetId, "commandName": "refresh", "commandArg": { "reportservice": "icacheablereport-force-expire" } }, null, null); } } ]; //FB.113624: only Owners can add/remove widgets if (permission == 1) { contextMenuItems.push( null, { label: 'Clone', icon: "assets/images/copy_gray.png", action: function () { //widgetId = "DashboardSurface_db_12345", so extract just the ID __doPostBack("cloneWidget", widgetId.substr(widgetId.lastIndexOf("_") + 1)); } }, null, { label: 'Delete', icon: "assets/images/delete_gray.png", cls: "ctx-tool-close", action: function () { doHostCommand(null, { "hostId": "DashboardSurface", "commandName": "close", "commandArg": { "widgetId": widgetId, "confirmClose": true } }); } }); } // Owners and Editors can modify existing widgets if (permission == 1 || permission == 2) { contextMenuItems.push( { label: 'Rename', action: function () { changeWidgetTitle(header, { "widgetId": widgetId }); } }, null, { label: 'Properties', icon: "assets/images/gear_gray.png", action: function () { doWidgetCmd(null, { "widgetId": widgetId, "commandName": "edit", "commandArg": { "height": 0, "width": 0, "title": header.innerHTML } }, null, null); } }); } // FB.100284 - The contextmenu event is being bound to the widget header multiple times. Need to remove before adding again. $(this).off('contextmenu'); $(this).contextPopup({ title: null, items: contextMenuItems, events: { beforeShow: function (e, menu) { try { //FB.101108: hide the delete button in the context menu if the x-tool-close button is hidden var tool = $(e.target).closest(".x-panel-header").find(".x-tool-close"); var display = "none"; if (tool.length > 0) display = tool.css("display"); var mn = $(menu).find(".ctx-tool-close"); mn.css("display", display); } catch (ex) { console.error(ex.message); } return true; } } }); }); } catch (ex) { console.log(ex.message); } /** Localize Widget Header Tools **/ try { $(".x-tool-gear").each(function (index) { this.title = cmd_Properties; }); $(".x-tool-refresh").each(function (index) { this.title = cmd_Refresh; }); $(".x-tool-maximize").each(function (index) { this.title = cmd_Maximize; }); $(".x-tool-close").each(function (index) { this.title = cmd_Close; if (permission != 1) $(this).hide(); }); $(".x-tool-help").each(function (index) { this.title = cmd_Help; var prev = $(this).prev(); if ($(prev).hasClass("x-tool-gear")) { $(this).insertBefore($(prev)); } }); // FB.119728 - context sensative help menu from clicking the widget header help button. var helpPopupOptions = { HelpContextType: 'widgetSurface' }; $(".x-tool-help").HelpPopup(helpPopupOptions); } catch (ex) { console.log(ex.message); } if (permission == 2) { $("a.action.dashboard_refresh").attr("style", "margin-right: 4px;"); } } catch (ex) { console.log(ex.message); } }; // This function takes a .net date format string and converts it to the jquery-ui datepicker format string. EQuIS.convertToDatePickerFormat = function(dformat) { try { var monthNameExp = new RegExp('M{3,3}'); // contains only 'MMM' - need to convert to 'M' var monthNumExp = new RegExp('M{1,2}'); // contains either 'M' or 'MM' - need to convert to same in lowercase if (monthNameExp.test(dformat)) dformat = dformat.replace(monthExpr, "M"); // replace 'MMM' with 'M' else if (monthNumExp.test(dformat)) dformat = dformat.replace(/M/g, "m"); // replace 'MM' or 'M' with 'mm' or 'm' var year2Exp = new RegExp('y{2,2}'); // contains only 'yy' - need to convert to single 'y' var year4Exp = new RegExp('y{4,4}'); // contains only 'yyyy' - need to convert to 'yy' if (year4Exp.test(dformat)) dformat = dformat.replace(year4Exp, "yy"); // replace 'yyyy' with 'yy' else if (year2Exp.test(dformat)) dformat = dformat.replace(year2Exp, "y"); // replace 'yy' with 'y' return dformat; } catch (ex) { console.log(ex.message); } } // this function will take a short date string format (i.e. en/us: 'MM/dd/yyyy') and replace the 'M's and 'd's and 'y's the the language specific character for Month, Day and Year. EQuIS.localizeDateFormat = function (dateFormat) { var M = 'M'; var y = 'y'; var d = 'd'; dateFormat.replace(/M/g, M); dateFormat.replace(/y/g, y); dateFormat.replace(/d/g, d); return dateFormat; } EQuIS.setCookie = function(name, value, secondsToLive) { var expires; if (secondsToLive) { var date = new Date(); date.setTime(date.getTime() + (secondsToLive * 1000)); expires = "; expires=" + date.toGMTString(); } else { expires = ""; } document.cookie = escape(name) + "=" + escape(value) + expires + "; path=/"; } EQuIS.getCookie = function (name) { var nameEQ = escape(name) + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) === ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) === 0) return unescape(c.substring(nameEQ.length, c.length)); } return null; } EQuIS.removeCookie = function(name) { EQuIS.createCookie(name, "", -1); } // Object for use date parameters tree functions EQuIS.dateMacros = { TD: 'Today', // Today TW: 'One week ago today', // One week ago today TY: 'One year ago today', // One year ago today FY: 'First day of the year', // First day of the year FQ: 'First day of the quarter', // First day of the quarter FM: 'First day of the month', // First day of the month FW: 'First day of the week', // First day of the week LW: 'Last day of the week', // Last day of the week LM: 'Last day of the month', // Last day of the month LQ: 'Last day of the quarter', // Last day of the quarter LY: 'Last day of the year', // Last day of the year EW: 'First day of the previous week', // First day of the previous week KW: 'Last day of the previous week', // Last day of the previous week EM: 'First day of the previous month', // First day of the previous month KM: 'Last day of the previous month', // Last day of the previous month EQ: 'First day of the previous quarter', // First day of the previous quarter KQ: 'Last day of the previous quarter' // Last day of the previous quarter }; // This function takes two digit code (from EQuIS.dateMacros above) representing a relative date and calculates and returns the evaluated javascript date. // *params* // macVal = two digit string dateMacro code // dformat = date format for returned date. (ex. M/d/yyyy). EQuIS.evalMacroDate = function(macVal, dformat) { try { var d = new Date(); // current date var dw = d.getDay(); // day of the week (0-6); var dt = d.getDate(); // day of the month (1-31) var mo = d.getMonth(); // month (0-11) var qtr; // current quarter (0-3) switch (mo) { case 0: case 1: case 2: qtr = 0; break; case 3: case 4: case 5: qtr = 1; break; case 6: case 7: case 8: qtr = 2; break; case 9: case 10: case 11: qtr = 3; break; } var yr = d.getFullYear(); // current year var inList = true; switch (macVal) { case 'TD': // today (d is already set to today), but need to catch so it won't be default. break; case 'TY': // one year ago today d.setFullYear(yr - 1); // change year to one less (or should this be 365 days less which is different?) break; case 'TW': // one week ago today d.setDate(dt - 7); break; case 'FY': // First day of the year d.setDate(1); d.setMonth(0); break; case 'FQ': // First day of the quarter d.setDate(1); d.setMonth(qtr * 3); break; case 'FM': // First day of the month d.setDate(1); break; case 'FW': // First day of the week d.setDate(dt - dw); break; case 'LW': // Last day of the week d.setDate(dt + (6 - dw)); break; case 'LM': // Last day of the month d.setMonth(mo + 1); d.setDate(0); break; case 'LQ': // Last day of the quarter d.setMonth((qtr + 1) * 3); d.setDate(0); break; case 'LY': // Last day of the year d.setMonth(11); d.setDate(31); break; case 'EW': // First Day of Previous Week d.setDate(dt - 7 - dw); break; case 'KW': // Last Day of Previous Week d.setDate(dt - dw - 1); break; case 'EM': // First Day of Previous Month d.setDate(1); d.setMonth(mo - 1); break; case 'KM': // Last Day of Previous Month d.setDate(0); break; case 'EQ': // First Day of Previous Quarter d.setDate(1); d.setMonth((qtr - 1) * 3); break; case 'KQ': // Last Day of Previous Quarter d.setMonth(qtr * 3); d.setDate(0); break; default: // not a macro code return ''; } return d; } catch (ex) { console.log(ex.message); return null; } } /** Object extension methods **/ String.prototype.endsWith = function (suffix) { return this.indexOf(suffix, this.length - suffix.length) !== -1; }; String.prototype.startsWith = function (prefix) { return this.substr(0, prefix.length) === prefix; }; String.prototype.getBytes = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes; }; String.prototype.isEmpty = function () { return (!this || 0 === this.length); } Date.prototype.toISOFriendlyString = function (format) { try { // "1997-03-15T00:00:00.000Z" var str = this.toISOString(); // remove ".000Z" str = str.substring(0, str.length - 5); str = str.replace("T", " "); // only date (truncate time) if (format == "d") str = str.substring(0, 10); // truncate zero-time if (format == "d+") str = str.replace(" 00:00:00", ""); return str; } catch (ex) { console.error(ex.message); return this.toISOString(); } }; /** JQuery extension methods **/ $.extend({ queryString: function (name) { if (typeof (name) === "undefined" || name == null) { var vars = [], hash; var hashes = window.location.search.slice(1).split('&'); for (var i = 0; i < hashes.length; i++) { if (hashes[i].length > 0) { hash = hashes[i].split('='); vars.push(hash[0]); vars[hash[0]] = decodeURIComponent(hash[1].replace(/\+/g, " ")); } } return vars; } else { var params = $.queryString(); return params[name]; } } });