var isBackend = false; var isDebug = false; var isIE = isBackend || true; var isIE9 = true; var isIE10 = true; var isIE11 = false; var isFirefox = false; var isNS = (!isBackend && document.addEventListener) ? true : false; (function(){ var isShoppingSession = false; /* The core NetSuite object */ (function(window) { /* Sandbox */ var document = window.document, location = window.location, navigator = window.navigator; var NS = window.NS || {}; window.NS = NS; NS.UI = { Preferences: { horizontalLabelsEnabled: typeof isShoppingSession === 'undefined' ? false : isShoppingSession // determines the behavior of setFieldLabelRequired } }; /* ******* * NetSuite namespace and common functions ****** */ NS.Core = (function() { var guid = 0; return { getWindow: function() { return window; }, getDocument: function() { return document; }, getLocation: function() { return location; }, getNavigator: function() { return navigator; }, isUndefined: function(val) { return (typeof val === "undefined"); }, getURLParameter: function(param) { var val = new RegExp('[?&]' + param + '=([^&]*)').exec(location.search); return (val != null) ? decodeURIComponent(val[1]) : null; }, getUniqueId: function() { return ++guid; } }; }()); /* ******** * Event bus * * Example 1: * NS.event.bind("my_event", function() { alert("Triggered"); }); // Bind event listener * NS.event.once("my_event", function() { alert("One-time listener"); }); // Listener that is triggered only once * NS.event.dispatch("my_event"); // Trigger event * * Example 2: * NS.event.bind("my_event", function(e, data) { // Bind listener * alert(data.value); // Output event parameters * if (data.value) { NS.event.unbind(e.name, e.fn); } // Conditional unbind * }); * NS.event.dispatch("my_event", { value: true }); // Trigger event with parameters * * NOTE: Please don't use "dispatch" in code that may run on the server, use "dispatchImmediate" instead. Rhino doesn't have a setTimeout function that * is essential for asynchronous event dispatching. * ******** */ NS.event = (function() { var eventListeners = {}; /* Event object. name: The name of the event that triggered the handler. fn : The handler function. */ function EventObject(name, fn) { this.name = name; this.fn = fn; } function ListenerObject(fn, condition, scope, once) { this.fn = fn; this.condition = condition; this.scope = scope; this.once = once; } function bindEvent(eventName, fn, condition, scope, once) { var listeners; if (!eventListeners[eventName]) { eventListeners[eventName] = {}; } listeners = eventListeners[eventName]; scope = scope || NS.Core.getWindow(); fn.nsEventGuid = fn.nsEventGuid || NS.Core.getUniqueId(); listeners[fn.nsEventGuid] = new ListenerObject(fn, condition, scope, once); } function listenerInvoker(eventName, listener, data) { return function () { var event = new EventObject(eventName, listener.fn); if (!listener.condition || listener.condition.call(listener.scope, event, data)) { listener.fn.call(listener.scope, event, data); } }; } function emptyFunction() { return undefined; } return { /* Attach a handler to an event. eventName: The name of the event. callback : Handler that is executed every time the event is triggered. The handler receives two parameters: EventObject and Data. EventObject contains information about the event that triggered the handler and reference to the handler itself. This information can be used, e.g., to unbind the handler. The Data object contains user data passed to the event. [scope] : Optional. The scope of the handler function. Global scope is used if not defined otherwise. */ bind: function(eventName, callback, scope) { bindEvent(eventName, callback, null, scope, false); }, /* Attach a handler to an event. The handler is executed at most once. eventName : The name of the event. callback : Handler that is executed when the event is triggered. [condition] : Optional. If defined the handler is executed only if the condition is true. If the condition returns false the handler remains registered and waits for the next occurence of the event. The condition function is executed with the same parameters as the handler. [scope] : Optional. The scope of the handler function. Global scope is used if not defined otherwise. */ once: function(eventName, callback, condition, scope) { bindEvent(eventName, callback, condition, scope, true); }, /* Execute all handlers attached to an event. Note that event dispatching is done asynchronously, i.e., the listeners are NOT executed immediately. eventName : The name of the event. data : Additional parameters that will be passed to each listener. doneHandler : Callback that is triggered when all event handlers sucesfully finish. May be undefined or null. errorHandler: Callback that is triggered when any of the listeners fails. It is run after all listners for the given event have been executed. May be undefined or null. */ dispatch: function(eventName, data, doneHandler, errorHandler) { var key, listeners, listener, invoker, wrapper; var listenersExecuted = 0, listenersFinished = 0, listenersTotal = 0; if (eventListeners[eventName]) { listeners = eventListeners[eventName]; listenersTotal = Object.keys(listeners).length; for (key in listeners) { if (listeners.hasOwnProperty(key)) { listener = listeners[key]; invoker = listenerInvoker(eventName, listener, data); if (listener.once) { delete listeners[key]; } wrapper = (function(inner) { return function() { listenersExecuted++; if (listenersExecuted === listenersTotal) { setTimeout(function () { var finalHandler = ((listenersFinished === listenersTotal) ? doneHandler : errorHandler) || emptyFunction; finalHandler(); }, 0); } inner(); listenersFinished++; } })(invoker); setTimeout(wrapper, 0); } } } if (listenersTotal === 0 && doneHandler) { setTimeout(doneHandler, 0); } }, /* Synchronous execution of all handlers attached to an event. eventName : The name of the event. data : Additional parameters that will be passed to each listener. doneHandler : Callback that is triggered when all event handlers sucesfully finish. May be undefined or null. errorHandler: Callback that is triggered when any of the listeners fails. It is run after all listners for the given event have been executed. May be undefined or null. */ dispatchImmediate: function(eventName, data, doneHandler, errorHandler) { var key, listeners, listener, invoker, errorEncountered = false; if (eventListeners[eventName]) { listeners = eventListeners[eventName]; for (key in listeners) { if (listeners.hasOwnProperty(key)) { try { listener = listeners[key]; if (listener.once) { delete listeners[key]; } invoker = listenerInvoker(eventName, listener, data); invoker(); } catch (err) { errorEncountered = true; if (typeof console !== 'undefined') { console.log(err); } } } } } if (!errorEncountered && doneHandler) { doneHandler(); } else if (errorEncountered && errorHandler) { errorHandler(); } }, /* Remove attached event handler. eventName: The name of the event. callback : The handler function. */ unbind: function(eventName, callback) { if (callback.nsEventGuid) { if (eventListeners[eventName]) { delete eventListeners[eventName][callback.nsEventGuid]; } } } }; }()); /* ******** * Supported event types ******** */ NS.event.type = { FORM_INITED: "formInited", FORM_CHANGED: "formChanged", FORM_VALID: "formValid", PAGE_INIT_FINISHED: "pageInitFinished", FIELD_CHANGED: "fieldChanged", RECORD_FIELD_CHANGED: "recordFieldChanged", // unlike FIELD_CHANGED above, this is dispatched immediately both UI and SSS SYNCTOTAL_FINISHED: "synctotal_finished", POST_PAGE_INIT: "post_page_init", ITEM_ITEM_CHANGED: "item_item_changed", ROW_UPDATE_BUTTONS: "row_update_buttons", ITEM_SYNC_LINE_FIELDS: 'item_sync_line_fields', ITEM_POST_PROCESS_LINE: 'item_post_process_line', ITEM_VALIDATE_DELETE: 'item_validate_delete' }; /* ******* * Form object ****** */ NS.form = (function() { // NS.Core.getWindow().isinited = false; // Make it undefined temporarily before Selenium tests are fixed NS.Core.getWindow().ischanged = false; NS.Core.getWindow().isvalid = true; return { isInited: function() { return (NS.Core.getWindow().isinited === true); }, setInited: function(val) { if (typeof val === "boolean" && this.isInited() !== val) { NS.Core.getWindow().isinited = val; NS.event.dispatch(NS.event.type.FORM_INITED, {value: val}); } }, isChanged: function() { return NS.Core.getWindow().ischanged; }, setChanged: function(val) { if (typeof val === "boolean" && this.isChanged() !== val) { NS.Core.getWindow().ischanged = val; NS.event.dispatch(NS.event.type.FORM_CHANGED, {value: val}); } }, isValid: function() { return NS.Core.getWindow().isvalid; }, setValid: function(val) { if (typeof val === "boolean" && this.isValid() !== val) { NS.Core.getWindow().isvalid = val; NS.event.dispatch(NS.event.type.FORM_VALID, {value: val}); } }, isEditMode: function() { return (NS.Core.getURLParameter("e") == "T"); }, isViewMode: function() { var recordId = NS.Core.getURLParameter("id") || "-1"; return (!this.isEditMode() && recordId != "-1"); }, isNewMode: function() { var recordId = NS.Core.getURLParameter("id") || "-1"; return (!this.isEditMode() && recordId == "-1"); } }; }()); NS.UIF = (function () { var Promise = window.Promise || function () {}; // Server-side script does not have a Promise var resolveLoad; var loadPromise = new Promise(function (resolve) { resolveLoad = resolve; }); function promisify(api, methods) { return function (args) { var promise = loadPromise.then(function (context) { return context.API[api](args); }); return methods.reduce(function (result, method) { result[method] = function () { var args = Array.prototype.slice.call(arguments); promise = promise.then(function (handle) { handle[method].apply(null, args); return handle; }); }; return result; }, {}); } } var UIF = { load: function () { return loadPromise; }, run: function (callback) { return loadPromise.then(callback); }, initialize: function (args) { resolveLoad(args); }, }; // The APIs should be available immediately even though UIF is loaded asynchronously. So we hide everything behind a promise. var apis = [ ['render', ['render', 'dispose']], ['openModal', ['showLoader', 'resize', 'close']], ['showBanner', ['show', 'hide']], ['showGrowl', ['show', 'hide']], ['showLoader', ['update', 'dispose']], ]; for (var i = 0; i < apis.length; i++) { var api = apis[i]; UIF[api[0]] = promisify(api[0], api[1]); } return UIF; }()); }(this)); /* Use 'this' instead of 'window' which is not available to server side javascript */ }).call(this); NS.Logger = { debugValue : false }; var NS = isBackend ? (NS || {}) : (window.NS || {}); NS.UI = NS.UI || {}; NS.UI.Util = NS.UI.Util || { isBackend: isBackend, isDebug: false, isIE: isBackend || true, isIE9: true, isIE10: true, isIE11: false, isFirefox: false, isChrome: false, isSafari: false, isNetscape: false, isMac: false, internationalPhoneNumbers: false, asianLang: false, pageMargin: 5, dateCutOff: -11636672400000 }; function amount_string(amount) { var cents = Math.floor((amount-Math.floor(amount))*100+0.5); var centstring = (cents < 10) ? '0'+cents.toString() : cents.toString(); var dollarstring = dollars_string(Math.floor(amount)); return dollarstring.charAt(0).toUpperCase() + dollarstring.substr(1) + 'and ' + centstring + '/100'; } function format_rate(a,p) { var returnMe; if (isNaN(parseFloat(a))) { returnMe= ''; } else { var precision = get_precision(); if (precision>1 || p) { var s=(a<0); if (s) a=-a; var d=Math.floor(a); var c=Math.floor((a-d)*(p?10:100)+0.5); if (a == d+c/(p?10:100)) { if (c==(p?10:100)) {d++;c=0;} var cs=p?c.toString():((c < 10)?'0'+c.toString():c.toString()); returnMe = (s?'-':'')+d.toString()+'.'+cs+(p?'%':''); } else returnMe = (s?'-':'')+a+(p?'%':''); } else if (precision==1) { var s=(a<0); if (s) a=-a; var cs = a.toString(); var n = cs.indexOf('.'); if (n==-1) cs = cs.toString() + '.0'; else if (n==0) cs = '0.' + cs.toString() ; else if (n==cs.length-1) cs = cs.toString() + '0' ; returnMe = (s?'-':'') + cs ; } else if (precision==0) { var s=(a<0); if (s) a=-a; var cs = a.toString(); var n = cs.indexOf('.'); if (n==0) cs = '0.' + cs.toString() ; else if (n==cs.length-1) cs = cs.substring(0, cs.length-2); returnMe = (s?'-':'') + cs ; } } return returnMe; } function get_precision() { var currencyPrecision = getFormElementViaFormName('main_form', 'currencyprecision'); var precision = 2; if (currencyPrecision != null) { var transactionPrecision = parseFloat(currencyPrecision.value); if (!isNaN(transactionPrecision)) { precision = transactionPrecision; } } return precision; } function round_currency(amount, numofdecimals, method) { var TEN_POWER_TABLE=[1.0000000000000001E-29, 1.0E-28, 1.0E-27, 1.0E-26, 1.0E-25, 1.0000000000000001E-24, 1.0E-23, 1.0E-22, 1.0000000000000001E-21, 1.0000000000000001E-20, 1.0E-19, 1.0E-18, 9.999999999999999E-18, 1.0E-16, 1.0E-15, 1.0E-14, 1.0E-13, 1.0E-12, 1.0000000000000001E-11, 1.0E-10, 1.0E-9, 1.0E-8, 1.0E-7, 1.0E-6, 9.999999999999999E-6, 1.0E-4, 0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0E7, 1.0E8, 1.0E9, 1.0E10, 1.0E11, 1.0E12, 1.0E13, 1.0E14, 1.0E15, 1.0E16, 1.0E17, 1.0E18, 1.0E19, 1.0E20, 1.0E21, 1.0E22, 1.0E23, 1.0E24, 1.0E25, 1.0E26, 1.0E27, 1.0E28, 1.0000000000000001E29]; function getTenPower (digits) { return TEN_POWER_TABLE[digits - -29]; } function shouldRoundUp (absNum, floor, ceil, tolerance, multiplicator, roundingMode) { switch (roundingMode) { case 'UP': return absNum > floor / multiplicator + tolerance; case 'DOWN': return absNum >= ceil / multiplicator - tolerance; default: return absNum >= (floor + 0.5) / multiplicator - tolerance; } } function roundDouble(num, digits, tolerance, roundingMode) { if (!isFinite (num)) return num; var signum = (num >= 0) ? +1 : -1 var absNum = Math.abs (num); var multiplicator = getTenPower(digits); var multipliedAbsNum = multiplicator * absNum; var floor = Math.floor (multipliedAbsNum); var ceil = Math.ceil (multipliedAbsNum); var roundUp = shouldRoundUp (absNum, floor, ceil, tolerance, multiplicator, roundingMode); var multipliedResult = (roundUp) ? ceil : floor; var result = signum * multipliedResult / multiplicator; return (result == -0.0) ? 0.0 : result; } var precision = numofdecimals; if (precision==null) precision = get_precision(); var tolerance = Math.min (5.0E-6 / getTenPower(precision), 5.0E-10) return roundDouble(amount, precision, tolerance, method); } function round_float(a) { return round_float_to_n_places(a,8); } function round_float_to_n_places(a,n) { var str = a + ''; if(str.indexOf('.') < 0) return a; if(str.length-str.indexOf('.')-1 <= n) return a; var b = Math.abs(a); b = b + 0.00000000000001; var factor = Math.pow(10,n); b = Math.floor((b * factor)+0.5) / factor; b = b * (a >= 0.0 ? 1.0 : -1.0); if( b == 0.0 ) return 0.0; return b; } function pad_to_atleast_two_decimal_places(a) { var s; if(a == null) { s = ''; } else { s = a.toString(); var n = s.indexOf('.'); if(n == -1) { s = s + '.00'; } else if(n == s.length-1) { s = s + '00'; } else if(n == s.length-2) { s = s + '0'; } if (n == 0) { s = '0' + s; } } return s; } function pad_decimal_places(a, noOfDecimalPlaces) { var s; if(a == null) { s = ''; } else { s = a.toString(); var n = s.indexOf('.'); if (noOfDecimalPlaces==0) { if(a == 0.0) { s = '0'; } else if(n > -1) { s = s.substring(0, n) ; } } else if (noOfDecimalPlaces==1) { if(n == -1) { s = s + '.0'; } else if(n == s.length-1) { s = s + '0'; } else if (n == 0) { s = '0' + s; } } else { if(n == -1) { s = s + '.00'; } else if(n == s.length-1) { s = s + '00'; } else if(n == s.length-2) { s = s + '0'; } if (n == 0) { s = '0' + s; } } } return s; } function format_currency(a, bDoNotRound, precision) { if(isNaN(a)) { return ''; } var noOfDecimalPlaces; if (precision === undefined) { var cp = getFormElementViaFormName('main_form', 'currencyprecision'); noOfDecimalPlaces = 2; if (cp != null) { noOfDecimalPlaces = parseFloat(cp.value); if (isNaN(noOfDecimalPlaces)) { noOfDecimalPlaces = 2; } } } else { noOfDecimalPlaces = precision; } var returnMe; if( !(bDoNotRound == true)) { returnMe = round_currency(a, noOfDecimalPlaces); } else { returnMe = a; } returnMe = pad_decimal_places(returnMe, noOfDecimalPlaces); return returnMe; } function format_currency2(n) { if(isNaN(n)) { return ''; } var returnMe; if( (n+'').indexOf('.') < 0 ) returnMe = n; else returnMe = round_float_to_n_places(n,8); var precision = get_precision(); if (precision == 2) { returnMe = pad_to_atleast_two_decimal_places(returnMe); } return returnMe; } function format_percent(p) { if(typeof p == 'string') p = parseFloat(p); return p+(p==Math.floor(p) ? '.0%' : '%'); } function process_currency_field_value(value, fieldType) { if (fieldType == null || fieldType.indexOf('currency') == -1) return value; if (isValEmpty(value) || ('' + value).indexOf('.') != -1 || isNaN(parseFloat(value))) return value; var precision = fieldType.indexOf('currency2') >= 0 ? 2 : get_precision(); return pad_decimal_places('' + value, precision); } function formatCurrencyTax(value, bDoNotRound, precision, method) { var currencyPrecision = precision || nlapiGetFieldValue('taxfractionunit') || 2; var roundingMethod = method || nlapiGetFieldValue('taxrounding') || null; return pad_decimal_places( bDoNotRound ? value : round_currency(value, currencyPrecision, roundingMethod), currencyPrecision ); } NLDate_months = ["January","February","March","April","May","June","July","August","September","October","November","December",""]; NLDate_short_months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""]; function nlGetFullYear(d) { if (window.navigator != null && window.navigator.appName == "Netscape") { if (d.getFullYear == "undefined") return d.getYear(); } return d.getFullYear(); } function nlSetFullYear(d,val) { if (window.navigator != null && window.navigator.appName == "Netscape") { if (d.setFullYear == "undefined") d.setYear(val); } d.setFullYear(val); } var year_char_cn = "年"; var month_char_cn = "月"; var day_char_cn = "日"; var weekday = new Array(7); weekday[0] = "Sunday"; weekday[1] = "Monday"; weekday[2] = "Tuesday"; weekday[3] = "Wednesday"; weekday[4] = "Thursday"; weekday[5] = "Friday"; weekday[6] = "Saturday"; function getdatestring(d, format) { // if dateformat is specified, use it from the format parameter // else use the window property (set from user preference) var dateformat; if (typeof(format) != "undefined") dateformat = format; else if (typeof(window.dateformat) != "undefined") dateformat = window.dateformat; else dateformat = "MM/DD/YYYY"; return oracleDateTimeFormatterFactory.getFormatter().formatDateTime(d, dateformat); } var reiwa_start_date = new Date(2019, 4, 1); var heisei_start_date = new Date(1989,0,8); var shouwa_start_date = new Date(1926,11,25); var taishou_start_date = new Date(1912,6,30); var meiji_start_date = new Date(1867,1,3); function get_japanese_imperial_era(d) { if (d >= reiwa_start_date) return "令和"; else if (d >= heisei_start_date) return "平成"; else if(d >= shouwa_start_date) return "昭和"; else if(d >= taishou_start_date) return "大正"; else return "明治"; } function get_short_japanese_imperial_era(d) { if (d >= reiwa_start_date) return "R"; else if (d >= heisei_start_date) return "H"; else if(d >= shouwa_start_date) return "S"; else if(d >= taishou_start_date) return "D"; else return "M"; } function get_japanese_imperial_year(d) { if (d >= reiwa_start_date) return nlGetFullYear(d) - 2018; else if (d >= heisei_start_date) return nlGetFullYear(d) - 1988; else if(d >= shouwa_start_date) return nlGetFullYear(d) - 1925; else if(d >= taishou_start_date) return nlGetFullYear(d) - 1911; else return nlGetFullYear(d) - 1867; } function get_gregorian_year(ja_imperial_year, era) { if (era == "令和" || era == "R") return ja_imperial_year + 2018; else if (era == "平成" || era == "H") return ja_imperial_year + 1988; else if(era == "昭和" || era == "S") return ja_imperial_year + 1925; else if(era == "大正" || era == "D") return ja_imperial_year + 1911; else return ja_imperial_year + 1867; } function getdefaultformatdatestring(d) { return (d.getMonth()+1)+"/"+d.getDate()+"/"+nlGetFullYear(d); } function gettimestring(time,amvar,pmvar) { return gettimestringwithformat(time, amvar, pmvar, window.timeformat); } function gettimestringwithformat(time, amvar, pmvar, format) { return oracleDateTimeFormatterFactory.getFormatter().formatDateTime(time, format); } function gettimewithsecondsstring(time,amvar,pmvar) { return oracleDateTimeFormatterFactory.getFormatter().formatDateTime(time, window.timeformatwithseconds); } function getdatetimestring(date) { return getdatestring(date) + " " + gettimestring(date); } function getdatetimetzstring(date) { return getdatestring(date) + " " + gettimewithsecondsstring(date); } /** * Convert date to MMYY string. * Should behave the same way as NLDateRangeFieldGroup.getInvTurnDate(). * The result must also be parsable by parseMMYYDateString. * * @param d * @param NLDate_short_months */ function getmmyydatestring(d, NLDate_short_months) { var dateformat = window.dateformat || "MM/DD/YYYY"; return oracleDateTimeFormatterFactory.getFormatter().formatMMYYDateString(d, dateformat); } function isoToDate(isoStr, type) { if (type == 'date') isoStr = isoStr + ' 00:00:00'; else if (type == 'timeofday') isoStr = getdatestring(new Date(), 'YYYY-MM-DD') + ' ' + isoStr; return new Date(isoStr); } /** * Parse year and month from a MMYY value. * Try to be as benevolent as possible, while keeping unambiguous. * Must parse anything produced by getmmyydatestring() * and NLDateRangeFieldGroup.getInvTurnDate(). * * @param value the string value */ function parseMMYYDateString(value) { var year, month; if(!/^[0-9-\/\.]+$/.test(value)) { // contains other chars than numerals and ./- => must contain month short name var c = value.split(/[\/-]/); if (c.length != 2) { return null; } month = getMonthIndex(c[0]); year = parseInt(c[1],10); } else { // split it by any of ./- var comps = value.split(/[\.\/-]/); if (comps.length == 1) { // without any separator - month is the first 1 or 2 chars, // the rest is year (2 or 4 chars) var l = value.length; month = parseInt(value.substr(0,2-l%2),10); year = parseInt(value.substr(2-l%2),10); } else { // first month then year month = parseInt(comps[0],10); year = parseInt(comps[1],10); } } // make the year full year if less then 100 if (year < 50) year += 2000; else if (year < 100) year += 1900; return { year: year, month: month }; } /** * Parse day and month from a DDMM value. * * @param value the string value */ function parseMMDDDateString(value) { var day, month; // format is fixed as MM/DD var c = value.split(/[\/]/); if (c.length != 2) { return null; } // first month then day month = parseInt(c[0],10)-1; day = parseInt(c[1],10); return { month: month, day: day }; } function stringtodate(arg, dateformat, returnNullIfInvalid, formattype) { var comps; var month, day, year; var year_char_index, month_char_index, day_char_index, era; var d = arg; // date string, assume it's the whole string for now if(dateformat == null) { if(typeof(window.dateformat) != "undefined") dateformat = window.dateformat; else dateformat = "MM/DD/YYYY"; } var datestring_length = arg.length; var end_string; //the end segment in date string (mainly used for date seg since year string's length is always 4) var year_length = 4; var returnValIfError = returnNullIfInvalid ? null : new Date(); dateformat = oracleDateTimeFormatterFactory.getFormatter().preprocessDateTimeFormat(dateformat); if(d.length > 0) { if(dateformat == "MM/DD/YYYY") { comps = d.split("/"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; month = parseInt(comps[0], 10) - 1; day = parseInt(comps[1], 10); year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD/MM/YYYY") { comps = d.split("/"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0], 10); month = parseInt(comps[1], 10) - 1; year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD-Mon-YYYY") { comps = d.split("-"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0], 10); month = getMonthIndex(comps[1]) - 1; year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD.MM.YYYY") { comps = d.split("."); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0], 10); month = parseInt(comps[1], 10) - 1; year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD-MONTH-YYYY") { comps = d.split("-"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0], 10); month = arrayIndexOf(NLDate_months, comps[1], true); year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "YYYY/MM/DD") { comps = d.split("/"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; end_string = comps[2].split(" ")[0]; day = parseInt(end_string, 10); month = parseInt(comps[1], 10) - 1; year = parseInt(comps[0], 10); datestring_length = comps[1].length + end_string.length + year_length + 2; } else if(dateformat == "YYYY-MM-DD") { comps = d.split("-"); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; end_string = comps[2].split(" ")[0]; day = parseInt(end_string, 10); month = parseInt(comps[1], 10) - 1; year = parseInt(comps[0], 10); datestring_length = comps[1].length + end_string.length + year_length + 2; } else if(dateformat == "EEYY年MM月DD日") { year_char_index = d.indexOf(year_char_cn); month_char_index = d.indexOf(month_char_cn); day_char_index = d.indexOf(day_char_cn); if(year_char_index < 0 || month_char_index < 0 || day_char_index < 0) return returnValIfError; day = parseInt(d.substring(month_char_index+1,day_char_index), 10); month = parseInt(d.substring(year_char_index+1,month_char_index), 10) - 1; era = d.substring(0, 2); year = get_gregorian_year(parseInt(d.substring(2,year_char_index), 10), era); datestring_length = day_char_index + 1; } else if(dateformat == "YYYY年MM月DD日") { year_char_index = d.indexOf(year_char_cn); month_char_index = d.indexOf(month_char_cn); day_char_index = d.indexOf(day_char_cn); if(year_char_index < 0 || month_char_index < 0 || day_char_index < 0) return returnValIfError; day = parseInt(d.substring(month_char_index+1,day_char_index), 10); month = parseInt(d.substring(year_char_index+1,month_char_index), 10) - 1; year = parseInt(d.substring(0,year_char_index), 10); datestring_length = day_char_index + 1; } else if(dateformat == "EYY.MM.DD") { comps = d.split("."); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; end_string = comps[2].split(" ")[0]; day = parseInt(end_string, 10); month = parseInt(comps[1], 10) - 1; era = comps[0].substring(0, 1); year = get_gregorian_year(parseInt(comps[0].substring(1,comps[0].length), 10), era); datestring_length = comps[0].length + comps[1].length + end_string.length + 2; } else if(dateformat == "DD. MON YYYY") { comps = d.split(" "); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0].substring(0, comps[0].length - 1), 10); month = arrayIndexOf(NLDate_short_months, comps[1]); year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD de MONTH de YYYY") { comps = d.split(" de "); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[0], 10); month = getMonthIndex(comps[1]) - 1; year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 8; } else if(dateformat == "YYYY년 MM월 DD일") { comps = d.split(" "); if(comps.length < 3) // the format can contains time hh:mm:ss or hh-mm-ss return returnValIfError; day = parseInt(comps[2].substring(0, comps[2].length-1), 10); month = parseInt(comps[1].substring(0, comps[1].length-1), 10) - 1; year = parseInt(comps[0].substring(0, comps[0].length-1), 10); var whitespaceChars = 3; datestring_length = comps[0].length + comps[1].length + comps[2].length + whitespaceChars; } else if(dateformat == "DD MONTH YYYY") { comps = d.split(" "); if(comps.length < 3) //the format could be "DD MONTH YYYY HH:MI:SS AM" . length =4 return returnValIfError; day = parseInt(comps[0], 10); month = arrayIndexOf(NLDate_months, comps[1], true); year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } else if(dateformat == "DD MONTH, YYYY") { comps = d.split(" "); if(comps.length < 3) //the format could be "DD MONTH YYYY HH:MI:SS PM" . length = 4 return returnValIfError; day = parseInt(comps[0], 10); month = arrayIndexOf(NLDate_months, comps[1].substring(0, comps[1].length-1), true); year = parseInt(comps[2].substring(0, year_length), 10); datestring_length = comps[0].length + comps[1].length + year_length + 2; } } if (!isvalidyearmonthday(year, month, day)) return returnValIfError; // now handle the time segment var result; var t = arg.substring(datestring_length); if (t != null && t.length > 0) { if (formattype == 'datetimetz') result = regexstringtotime(arg.substring(0,datestring_length),t, true); else if (formattype == 'datetime' || formattype == 'timeofday') result = regexstringtotime(arg.substring(0,datestring_length),t, false); else result = stringtotime(arg.substring(0,datestring_length),t); } else result = new Date(year,month,day); if (result != null && !isNaN(result)) { if (year < 50) nlSetFullYear(result, year + 2000); else if (year < 100) nlSetFullYear(result, year + 1900); } return isNaN(result) && returnNullIfInvalid ? null : result; } function isvalidyearmonthday(year, month, day) { if(isNaN(year) || year < 0 || isNaN(month) || month < 0 || month > 11 || isNaN(day) || day < 1 || day > 31) return false; else return true; } // we need this for sever side script function trimstring(str) { return str.replace(/^\s+/,"").replace(/\s+$/,""); } function regexstringtotime(date, time, includeSeconds) { var flddate = date != null ? stringtodate(date) : new Date(); if (time != null && new String(time).length != 0 && new String(time).search(/\S/) >= 0) { var hours, minutes, seconds; hours = NaN; minutes = NaN; seconds = NaN; var delimitors = null; time = trimstring(time); // remove all leading/trailing spaces var TIME_FORMAT_MAP = { "HH:MI:SS am": { rcase:0, hend:':', mend:':', send:' '}, "HH-MI-SS am": { rcase:0, hend:'-', mend:'-', send:' '}, "HH24:MI:SS": { rcase:0, hend:':', mend:':', send:null}, "HH24-MI-SS": { rcase:0, hend:'-', mend:'-', send:null}, "amHH時MI分SS秒": { rcase:1, hend:'時', mend:'分', send:'秒'}, "amHH点MI分SS秒": { rcase:1, hend:'点', mend:'分', send:'秒'}, "amHH시MI분SS초": { rcase:1, hend:'시', mend:'분', send:'초'}, "HH24時MI分SS秒": { rcase:2, hend:'時', mend:'分', send:'秒'}, "HH24点MI分SS秒": { rcase:2, hend:'点', mend:'分', send:'秒'}, "HH24시MI분SS초": { rcase:2, hend:'시', mend:'분', send:'초'}, "HH:MI am": { rcase:0, hend:':', mend:' ', send:null}, "HH-MI am": { rcase:0, hend:'-', mend:' ', send:null}, "HH24:MI": { rcase:0, hend:':', mend:null, send:null}, "HH24-MI": { rcase:0, hend:'-', mend:null, send:null}, "amHH時MI分": { rcase:1, hend:'時', mend:'分', send:null}, "amHH点MI分": { rcase:1, hend:'点', mend:'分', send:null}, "amHH시MI분": { rcase:1, hend:'시', mend:'분', send:null}, "HH24時MI分": { rcase:2, hend:'時', mend:'分', send:null}, "HH24点MI分": { rcase:2, hend:'点', mend:'分', send:null}, "HH24시MI분":{ rcase:2, hend:'시', mend:'분', send:null} } format = trimstring( oracleDateTimeFormatterFactory.getFormatter().preprocessDateTimeFormat( includeSeconds ? window.timeformatwithseconds : window.timeformat)); delimitors = TIME_FORMAT_MAP[format]; var m; var ampm = null; var hend = null, mend = null, send = null; var TIME_FORMAT_WITH_POSSIBLE_AMPM_SUFFIX = /^(\d+)(\D)(\d+)((\D)(\d+))?\s*(\S+)?/; var TIME_FORMAT_WITH_POSSIBLE_AMPM_PREFIX = /^(\D+)(\d+)(\D)(\d+)(\D)((\d+)(\D))?/; var TIME_FORMAT_WITH_ASIAN_FORMATTING = /^(\d+)(\D)(\d+)(\D)((\d+)(\D))?/; if (delimitors != null) { switch (delimitors.rcase) { case 0: { m = TIME_FORMAT_WITH_POSSIBLE_AMPM_SUFFIX.exec(time); if (m !== null) { hours = parseInt(m[1], 10); hend = m[2]; minutes = parseInt(m[3], 10); mend = m[5]; if (includeSeconds && m[4] != null) seconds = parseInt(m[6], 10); else seconds = 0; ampm = m[7]; } break; } case 1: { var ampmtime = time.replace(/午前|上午|오전/g, 'am') .replace(/午後|下午|오후/g, 'pm'); m = TIME_FORMAT_WITH_POSSIBLE_AMPM_PREFIX.exec(ampmtime); if (m !== null) { hours = parseInt(m[2], 10); hend = m[3]; minutes = parseInt(m[4], 10); mend = m[5]; if (includeSeconds && m[6] != null) { seconds = parseInt(m[7], 10); send = m[8]; } else seconds = 0; ampm = m[1]; } break; } case 2: { m = TIME_FORMAT_WITH_ASIAN_FORMATTING.exec(time); if (m !== null) { hours = parseInt(m[1], 10); hend = m[2]; minutes = parseInt(m[3], 10); mend = m[4]; if (includeSeconds && m[5] != null) { seconds = parseInt(m[6], 10); send = m[7]; } else seconds = 0; } break; } } if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) || hours >= 24 || hours < 0 || minutes >= 60 || minutes < 0 || seconds >= 60 || seconds < 0) return NaN; if (hend != delimitors.hend || (includeSeconds && (mend != null && mend != delimitors.mend) || (send != null && send != delimitors.send))) return NaN; if (ampm != null) { var is_pm = (ampm.toLowerCase() === 'pm'); if (!is_pm && hours == 12) hours = 0; else if (is_pm && hours < 12) hours += 12; } flddate.setHours(hours, minutes, seconds, 0); } else flddate = NaN; } return flddate; } function stringtotime(date, time) { var flddate = date != null ? stringtodate(date) : new Date(); if (time != null && new String(time).length != 0 && new String(time).search(/\S/) >= 0) { var hours, minutes, seconds, is_pm; var hour_char_index; var minute_char_index; format = oracleDateTimeFormatterFactory.getFormatter().preprocessDateTimeFormat(window.timeformat); if (format == "HH:MI am" || format == "HH-MI am" || format == "HH24:MI" || format == "HH24-MI") { var m = /^\s*(\d+)[-:](\d+)\s*(.*)/.exec(time); if (!m) return NaN; hours = parseInt(m[1], 10); minutes = parseInt(m[2], 10); if (format.substring(6) == "am") { is_pm = (m[3].toLowerCase() == window.datetime_pm_string); if (!is_pm && hours == 12) hours = 0; else if (is_pm && hours < 12) hours += 12; } } else if(format == "amHH時MI分" || format == "amHH点MI分" || format == "amHH시MI분") { hour_char_index = time.indexOf("時"); if(hour_char_index < 0) hour_char_index = time.indexOf("点"); if(hour_char_index < 0) hour_char_index = time.indexOf("시"); var hour_start_index = 0; is_pm = false; if(time.indexOf(window.datetime_am_string) == 0) hour_start_index = window.datetime_am_string.length; else if(time.indexOf(window.datetime_pm_string) == 0) { hour_start_index = window.datetime_pm_string.length; is_pm = true; } hours = parseInt(time.substring(hour_start_index, hour_char_index)); if (!is_pm && hours == 12) hours = 0; else if(is_pm && hours < 12) hours += 12; minutes = parseInt(time.substring(hour_char_index + 1, time.length - 1)); } else if(format == "HH24時MI分" || format == "HH24点MI分" || format == "HH24시MI분") { hour_char_index = time.indexOf("時"); if(hour_char_index < 0) hour_char_index = time.indexOf("点"); if(hour_char_index < 0) hour_char_index = time.indexOf("시"); hours = parseInt(time.substring(0, hour_char_index)); minutes = parseInt(time.substring(hour_char_index + 1, time.length - 1)); } if(isNaN(hours) || isNaN(minutes) || hours >= 24 || hours < 0 || minutes >= 60 || minutes < 0 || seconds >= 60 || seconds < 0) return NaN; flddate.setHours(hours, minutes, 0, 0); } return flddate; } function hhmmtotime( hhmm ) { return stringtotime( null, hhmmtotimestring( hhmm ) ); } // -- handle shorthand time notation i.e. 5p -> 5:00 pm, 18 -> 6:00 pm, 900 -> 9:00 am, 1433p -> 2:33 pm function hhmmtotimestring( hhmm ) { var fldvalue = hhmm; var hour, minute; if ( window.datetime_am_string.charAt(0) == window.datetime_pm_string.charAt(0) ) re = new RegExp("^[0-9]{1,4}("+window.datetime_am_string+"|"+window.datetime_pm_string+")*$", "i"); else re = new RegExp("^[0-9]{1,4}(["+window.datetime_am_string.charAt(0)+"|"+window.datetime_pm_string.charAt(0)+"]?)$","i"); if ( re.test(fldvalue) ) { var aorp = ''; if ( RegExp.$1 ) { if ( window.datetime_am_string.charAt(0) == window.datetime_pm_string.charAt(0) ) aorp = RegExp.$1.toLowerCase() == window.datetime_pm_string ? window.datetime_pm_string : window.datetime_am_string; else aorp = RegExp.$1.toLowerCase().charAt(0) == window.datetime_pm_string.charAt(0) ? window.datetime_pm_string : window.datetime_am_string; } if ( fldvalue.length < 3 || ( fldvalue.length == 3 && RegExp.$1 ) ) { var hh = RegExp.$1 ? fldvalue.substring(0,fldvalue.length-1) : fldvalue; hour = parseInt( hh, 10 ) == 0 ? 12 : ( parseInt( hh, 10 ) > 12 ? parseInt( hh, 10 ) % 12 : hh ) ; minute = 0; var ampm = RegExp.$1 ? aorp : ( parseInt( fldvalue, 10 ) > 11 ? window.datetime_pm_string : window.datetime_am_string ); } else if (fldvalue.length == 3 || (fldvalue.length == 4 && RegExp.$1) ) { var hh = fldvalue.substring(0,1) == "0" ? "12" : fldvalue.substring(0,1); hour = parseInt( hh, 10 ); var mm = RegExp.$1 ? fldvalue.substring(1,3) : fldvalue.substring(1); minute = parseInt( mm, 10 ); var ampm = RegExp.$1 ? aorp : window.datetime_am_string; } else { var hh = fldvalue.substring(0,2); hour = parseInt( hh, 10 ) == 0 ? 12 : ( parseInt( hh, 10 ) > 12 ? parseInt( hh, 10 ) % 12 : hh ); var mm = RegExp.$1 ? fldvalue.substring(2,4) : fldvalue.substring(2); minute = parseInt( mm, 10 ); var ampm = parseInt( fldvalue.substring(0,2), 10 ) > 11 ? window.datetime_pm_string : window.datetime_am_string; ampm = RegExp.$1 ? aorp : ampm; } if (ampm == window.datetime_am_string && hour == 12) hour = 0; else if(ampm == window.datetime_pm_string && hour != 12) hour = parseInt(hour) + 12; var time = new Date(); time.setHours(hour,minute,0,0); fldvalue = gettimestring(time, window.datetime_am_string, window.datetime_pm_string); } return fldvalue; } function adddays(d, daystoadd) { var d2 = new Date(d.getTime() + 86400 * daystoadd * 1000); if (d2.getHours() != d.getHours()) { if ((d.getHours() > 0 && d2.getHours() < d.getHours()) || (d.getHours() == 0 && d2.getHours() == 23)) d2.setTime(d2.getTime() + 3600*1000); else d2.setTime(d2.getTime() - 3600*1000); } d.setTime(d2.getTime()); return d; } function daysBetween(dEarly, dLate) // ignores time { return get_julian_date(dLate) - get_julian_date(dEarly); } function monthsBetween(dEarly, dLate) // ignores DOM and time { return 12*(dLate.getFullYear() - dEarly.getFullYear()) + (dLate.getMonth() - dEarly.getMonth()); } function isDOWIM(dDate, nDOWIM) { return (nDOWIM >= 1 && nDOWIM == (1 + Math.floor((dDate.getDate()-1)/7))) || ((nDOWIM == -1 || nDOWIM == 5) && daysBetween(dDate, addmonths(new Date(dDate.getFullYear(), dDate.getMonth(), 1), 1)) <= 7); } function isLeapYear(year) { return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); } MONTH_LENGTH = [[31,28,31,30,31,30,31,31,30,31,30,31],[31,29,31,30,31,30,31,31,30,31,30,31]]; function getMonthLength(year, month) { return MONTH_LENGTH[isLeapYear(year)?1:0][month]; } /** * setDateComponents: set the month and day of the given date. If noRollover is given and true, * the day will not exceed the last day of the final month and thus will not trigger a month rollover. */ function setDateComponents(theDate, monthsToAdd, theDay, noRollover) { var newDate = new Date(theDate); if (typeof(noRollover) != 'boolean') noRollover = false; addmonths(newDate,monthsToAdd); setDate(newDate, theDay, noRollover); return newDate; } function addmonths(d, mtoadd) { if (mtoadd != 0) { var year = nlGetFullYear(d); var dom = d.getDate(); var month = d.getMonth() + mtoadd; if (month < 0) { month += 1; year = year + Math.ceil(month / 12) - 1; nlSetFullYear(d, year); month = 11 + (month % 12); } else if (month > 11) { year = year + Math.floor(month / 12); nlSetFullYear(d, year); month %= 12; // JS rounds leap days up (2/29/2016 + 1 yr = 3/1/2017), // whereas Java rounds them down (2/29/2016 + 1 yr = 2/28/2017). // Make JS behave like Java to be consistent with server side. if(dom === 29) d.setDate(dom); //This only works because we're setting the month later } var eom = getMonthLength(year, month); if (dom > eom) d.setDate(eom); d.setMonth(month); } return d; } function addhours(d, hourstoadd, truncate) { var d2 = new Date(d.getTime() + 3600 * hourstoadd * 1000); d.setTime(d2.getTime()); if (truncate) { d.setMinutes(0); d.setSeconds(0); d.setMilliseconds(0); } return d; } function setDate(d, day, noRollover) { if (noRollover) { var eom = getMonthLength(nlGetFullYear(d), d.getMonth()); day = Math.min(eom, day); } d.setDate(day); } m_j_d = [[0,31,59,90,120,151,181,212,243,273,304,334],[0,31,60,91,121,152,182,213,244,274,305,335]]; function getMonthJulian(year, month) { return m_j_d[isLeapYear(year)?1:0][month]; } var j_d=new Array(); j_d[1970]=0; j_d[1971]=365; j_d[1972]=730; j_d[1973]=1096; j_d[1974]=1461; j_d[1975]=1826; j_d[1976]=2191; j_d[1977]=2557; j_d[1978]=2922; j_d[1979]=3287; j_d[1980]=3652; j_d[1981]=4018; j_d[1982]=4383; j_d[1983]=4748; j_d[1984]=5113; j_d[1985]=5479; j_d[1986]=5844; j_d[1987]=6209; j_d[1988]=6574; j_d[1989]=6940; j_d[1990]=7305; j_d[1991]=7670; j_d[1992]=8035; j_d[1993]=8401; j_d[1994]=8766; j_d[1995]=9131; j_d[1996]=9496; j_d[1997]=9862; j_d[1998]=10227; j_d[1999]=10592; j_d[2000]=10957; j_d[2001]=11323; j_d[2002]=11688; j_d[2003]=12053; j_d[2004]=12418; j_d[2005]=12784; j_d[2006]=13149; j_d[2007]=13514; j_d[2008]=13879; j_d[2009]=14245; j_d[2010]=14610; j_d[2011]=14975; j_d[2012]=15340; j_d[2013]=15706; j_d[2014]=16071; j_d[2015]=16436; j_d[2016]=16801; j_d[2017]=17167; j_d[2018]=17532; j_d[2019]=17897; j_d[2020]=18262; j_d[2021]=18628; j_d[2022]=18993; j_d[2023]=19358; j_d[2024]=19723; j_d[2025]=20089; j_d[2026]=20454; j_d[2027]=20819; j_d[2028]=21184; j_d[2029]=21550; j_d[2030]=21915; function get_julian_date(d) { return j_d[d.getFullYear()]+getMonthJulian(d.getFullYear(),d.getMonth())+d.getDate()-1; } function getMonthIndex(sMonth) { var m = -1; sMonth = String(sMonth).toUpperCase(); for ( var i=0; i < NLDate_short_months.length; i++ ) { if ( NLDate_short_months[i].toUpperCase() == sMonth ) { m = i + 1; break; } } if(m != -1) return m; for ( var i=0; i < NLDate_months.length; i++ ) { if ( NLDate_months[i].toUpperCase() == sMonth ) { m = i + 1; break; } } if(m != -1) return m; else { var ms = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; m = (ms.indexOf(sMonth)+3)/3; } return m; } function _hhmm_to_mins(time) { return time.hrs * 60 + time.mins; } function round_hhmm_nearest(hrs, mins, round_by) { var up_time = round_hhmm_up(hrs, mins, round_by); var down_time = round_hhmm_down(hrs, mins, round_by); orig_mins = _hhmm_to_mins({ hrs: hrs, mins: mins }); up_mins = _hhmm_to_mins(up_time); down_mins = _hhmm_to_mins(down_time); if (up_mins - orig_mins > orig_mins - down_mins) { return down_time; } else { return up_time; } } function round_hhmm_up(hrs, mins, round_by) { mins += (mins % round_by > 0 ? (round_by - (mins % round_by)) : 0); if (mins >= 60) { var _hhmm_delta = Math.floor(mins / 60); mins -= (_hhmm_delta * 60); hrs += _hhmm_delta; } return { hrs: hrs, mins: mins }; } function round_hhmm_down(hrs, mins, round_by) { mins -= (mins > 0 ? (mins % round_by) : 0); return { hrs: hrs, mins: mins }; } function round_hhmm(val, round_by, direction) { if (val == "") return val; var re = /^([0-9]+?):([0-9]+)$/; var result = re.exec(val); if (result == null) { result = format_hhmm(val); if (result == null) return val; } var hrs = parseFloat(result[1]); var mins = parseFloat(result[2]); var time; if (direction == 'UP') { time = round_hhmm_up(hrs, mins, round_by); } else if (direction == 'DOWN') { time = round_hhmm_down(hrs, mins, round_by); } else if (direction == 'NEAR') { time = round_hhmm_nearest(hrs, mins, round_by); } else { throw direction + ' is not vald direction: [UP,DOWN,NEAREST]'; } if (time.mins < 10) time.mins = '0' + time.mins; return time.hrs + ':' + time.mins; } function format_hhmm(val) { var hours; var minutes; var re = /([0-9][0-9]?)?(:[0-9][0-9]+)?/ var result = re.exec(val) if (result == null || result.index > 0 || result[0].length != val.length) { timeval = parseFloat(val); if (isNaN(timeval)) hours = -1; else { hours = Math.floor(timeval); minutes = Math.floor((timeval - hours) * 60 + 0.5); } } else { if (RegExp.$1.length > 0) hours = parseInt(RegExp.$1, 10); else hours = 0; if (typeof (RegExp.$2) != "undefined" && RegExp.$2.length > 0) { minutes = parseInt(RegExp.$2.substr(1), 10); // if the user entered a value >= 60 for minutes, add the extra hours to the hours var and reduce // minutes to be less than 60 if (minutes >= 60) { var hours_delta = Math.floor(minutes / 60); minutes -= (hours_delta * 60); hours += hours_delta; } } else minutes = 0; } if (hours >= 0 && minutes >= 0 && minutes < 60) { return [val, hours, minutes]; } } function hhmmtofloat(val) { if ((val == null) || (val == "")) return 0; var re = /^([0-9]+?):([0-9]+)$/; var result = re.exec(val); if (result == null) { result = format_hhmm(val); if (result == null) return 0; } var hrs = parseFloat(result[1]); var mins = parseFloat(result[2]); return 60*hrs + mins; } function parse_time(val) { if (val == null || val.trim().length == 0) return null; var time = {hours: 0, minutes: 0, negative: false}; var rexp = /^(\-?)(\d*)(:(\d+))?$/; var rexpRes = rexp.exec(val); if (rexpRes == null) { var timeval = parseFloat(val); if (isNaN(timeval)) { return null; } else { if (timeval < 0) { timeval = Math.abs(timeval); time.negative = true; } time.hours = Math.floor(timeval); time.minutes = Math.round((timeval - time.hours) * 60); } } else { if (typeof rexpRes[2] != "undefined" && rexpRes[2].trim().length > 0) { time.hours = parseInt(rexpRes[2], 10); } if (typeof rexpRes[4] != "undefined" && rexpRes[4].trim().length > 0) { time.minutes = parseInt(rexpRes[4], 10); // if the user entered a value >= 60 for minutes, add the extra hours to the hours var and reduce minutes to be less than 60 if (time.minutes >= 60) { var delta = Math.floor(time.minutes / 60); time.hours += delta; time.minutes -= delta * 60; } } if (rexpRes[1] == '-' && (time.hours > 0 || time.minutes > 0)) time.negative = true; } return time; } function round_hhmm2(val, round_by, direction) { var result = parse_time(val); if (result == null) { return val; } var hrs = result.hours; var mins = result.minutes; var time; if (direction == 'UP') { time = round_hhmm_up(hrs, mins, round_by); } else if (direction == 'DOWN') { time = round_hhmm_down(hrs, mins, round_by); } else if (direction == 'NEAR') { time = round_hhmm_nearest(hrs, mins, round_by); } else { throw direction + ' is not vald direction: [UP,DOWN,NEAREST]'; } if (time.mins < 10) time.mins = '0' + time.mins; return (result.negative ? '-' : '') + time.hrs + ':' + time.mins; } // copypasta from N/util/date.js for now function OracleDateTimeFormatter(settingsContainer, japaneseEraHandlers, shortMonthsMap, longMonthsMap) { var that = this; this.settingsContainer = settingsContainer; this.shortMonthsMap = shortMonthsMap === undefined ? settingsContainer.datetime_short_months : shortMonthsMap; this.longMonthsMap = longMonthsMap === undefined ? settingsContainer.datetime_months : longMonthsMap; this.getJapaneseImperialEra = japaneseEraHandlers.getJapaneseImperialEra; this.getShortJapaneseImperialEra = japaneseEraHandlers.getShortJapaneseImperialEra; this.getJapaneseImperialYear = japaneseEraHandlers.getJapaneseImperialYear; function DateTimeElementType(matchPattern, formatterFunction) { this.matchRegexp = new RegExp('^' + matchPattern, 'i'); this.formatterFunction = formatterFunction; } function DateTimeElement(elementType, value, isUnpadded, isStrict) { this.elementType = elementType; this.value = value; this.isUnpadded = isUnpadded; this.isStrict = isStrict; this.formatterFunction = elementType.formatterFunction; } this.padChar = function padChar(value, length, characterToPad) { while (value.length < length) { value = characterToPad + value; } return value; }; this.padZeros = function padZeros(value, length) { return that.padChar(value, length, '0'); }; this.padSpace = function padSpace(value, length) { return that.padChar(value, length, ' '); }; this.formatDateTimeElement = function formatDateTimeElement(element, valueFromDateObject, maxWidth) { var width = element.value.length; if (maxWidth !== undefined && width > maxWidth) { width = maxWidth; } var isUnpadded = element.isUnpadded; var padFunc = isNaN(valueFromDateObject) ? that.padSpace : that.padZeros; var valueAsString = valueFromDateObject.toString(); return isUnpadded ? valueAsString : padFunc(valueAsString, width); }; this.formatters = Object.freeze({ formatMeridian: function formatMeridian(dateTimeElement, dateObject) { //noinspection JSUnresolvedVariable var amvar = that.settingsContainer.datetime_am_string || ''; //noinspection JSUnresolvedVariable var pmvar = that.settingsContainer.datetime_pm_string || ''; var hours = dateObject.getHours(); return hours < 12 ? amvar : pmvar; }, formatDayOfMonth: function formatDayOfMonth(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getDate()) }, formatDayOfWeek: function formatDayOfWeek(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getDay()); }, formatLongEra: function formatLongEra(dateTimeElement, dateObject) { return that.getJapaneseImperialEra(dateObject); }, formatShortEra: function formatShortEra(dateTimeElement, dateObject) { return that.getShortJapaneseImperialEra(dateObject); }, format24Hour: function format24Hour(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getHours(), 2); }, format12Hour: function format12Hour(dateTimeElement, dateObject) { var valueIn12Hour = dateObject.getHours() % 12; // 00 in 24h corresponds to 12 am if (valueIn12Hour === 0) valueIn12Hour = 12; return that.formatDateTimeElement(dateTimeElement, valueIn12Hour, 2); }, formatISOYear: function formatISOYear(dateTimeElement, dateObject) { return this.formatYear(dateTimeElement, dateObject); }, formatMonth: function formatMonth(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getMonth() + 1); }, formatMinute: function formatMinute(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getMinutes()); }, formatLongMonthName: function formatLongMonthName(dateTimeElement, dateObject) { return that.longMonthsMap[dateObject.getMonth()]; }, formatShortMonthName: function formatShortMonthName(dateTimeElement, dateObject) { return that.shortMonthsMap[dateObject.getMonth()]; }, formatSeconds: function formatSeconds(dateTimeElement, dateObject) { return that.formatDateTimeElement(dateTimeElement, dateObject.getSeconds()); }, formatYear: function formatYear(dateTimeElement, dateObject) { var yearValue = that.getFullYear(dateObject); return that.formatDateTimeElement(dateTimeElement, yearValue); }, formatLastDigitOfYear: function formatLastDigitOfYear(dateTimeElement, dateObject) { var yearAsString = that.getFullYear(dateObject).toString(); return yearAsString.substr(-dateTimeElement.value.length); }, formatText: function formatText(dateTimeElement, dateObject) { return dateTimeElement.value.replace(/"/g, ""); }, formatAsIs: function formatAsIs(dateTimeElement, dateObject) { return dateTimeElement.value; } }); this.getFullYear = function getFullYearDefaultImpl(dateObject) { return dateObject.getFullYear(); }; this.dateTimeElementTypes = Object.freeze({ AD_INDICATOR: new DateTimeElementType('A\.D\.|AD'), MERIDIAN: new DateTimeElementType('[AP]\.M\.|[AP]M', that.formatters.formatMeridian), ERA_INDICATOR: new DateTimeElementType('B\.C\.|BC'), CENTURY: new DateTimeElementType('S?CC'), DAY_NAME: new DateTimeElementType('DAY'), ABBREV_DAY_NAME: new DateTimeElementType('DY'), DAY_OF_YEAR: new DateTimeElementType('DDD'), DAY_OF_MONTH: new DateTimeElementType('DD', that.formatters.formatDayOfMonth), SHORT_DATE: new DateTimeElementType('DS'), LONG_DATE: new DateTimeElementType('DL'), DAY_OF_WEEK: new DateTimeElementType('D', that.formatters.formatDayOfWeek), FULL_ERA: new DateTimeElementType('EE', that.formatters.formatLongEra), ABBREV_ERA: new DateTimeElementType('E', that.formatters.formatShortEra), FRACTIONAL_SECONDS: new DateTimeElementType('FF[1-9]'), HOUR_OF_DAY_24: new DateTimeElementType('HH24', that.formatters.format24Hour), HOUR_OF_DAY_12: new DateTimeElementType('HH(12)?', that.formatters.format12Hour), ISO_WEEK_OF_YEAR: new DateTimeElementType('IW'), ISO_YEAR: new DateTimeElementType('IY{0,3}', that.formatters.formatISOYear), JULIAN_DAY: new DateTimeElementType('J'), MINUTE: new DateTimeElementType('MI', that.formatters.formatMinute), MONTH: new DateTimeElementType('MM', that.formatters.formatMonth), LONG_MONTH_NAME: new DateTimeElementType('Month', that.formatters.formatLongMonthName), SHORT_MONTH_NAME: new DateTimeElementType('Mon', that.formatters.formatShortMonthName), QUARTER_OF_YEAR: new DateTimeElementType('Q'), ROMAN_NUMERAL_MONTH: new DateTimeElementType('RM'), LONG_ROUNDED_YEAR: new DateTimeElementType('RRRR'), SHORT_ROUNDED_YEAR: new DateTimeElementType('RR'), SECONDS_PAST_MIDNIGHT: new DateTimeElementType('SSSSS'), SECONDS: new DateTimeElementType('SS', that.formatters.formatSeconds), SHORT_TIME: new DateTimeElementType('TS'), TZ_DAYLIGHT_SAVING: new DateTimeElementType('TZD'), TZ_HOUR: new DateTimeElementType('TZH'), TZ_MINUTE: new DateTimeElementType('TZM'), TZ_REGION: new DateTimeElementType('TZR'), WEEK_OF_YEAR: new DateTimeElementType('WW'), WEEK_OF_MONTH: new DateTimeElementType('W'), LOCAL_RADIX: new DateTimeElementType('X'), FOUR_DIGIT_YEAR: new DateTimeElementType('S?YYYY', that.formatters.formatYear), SPELLED_OUT_YEAR: new DateTimeElementType('S?YEAR'), LAST_DIGIT_OF_YEAR: new DateTimeElementType('Y{1,3}', that.formatters.formatLastDigitOfYear), TEXT: new DateTimeElementType('"[^"]*"', that.formatters.formatText), PUNCTUATION: new DateTimeElementType('[-/,.;:]+', that.formatters.formatAsIs), WHITESPACE: new DateTimeElementType('\\s+', that.formatters.formatAsIs), UNPAD_MOD: new DateTimeElementType('fm'), STRICT_MOD: new DateTimeElementType('fx'), SINGLE_QUOTE: new DateTimeElementType('\'\'', that.formatters.formatAsIs) }); // Javascript does not guarantee ordering of object properties (obviously) // but we "resolve" parsing ambiguities by letting first match win // thus we have to explicitly order the element types to avoid parse aliasing this.matchOrder = [ this.dateTimeElementTypes.AD_INDICATOR, this.dateTimeElementTypes.MERIDIAN, this.dateTimeElementTypes.ERA_INDICATOR, this.dateTimeElementTypes.CENTURY, this.dateTimeElementTypes.DAY_NAME, this.dateTimeElementTypes.ABBREV_DAY_NAME, this.dateTimeElementTypes.DAY_OF_YEAR, this.dateTimeElementTypes.DAY_OF_MONTH, this.dateTimeElementTypes.SHORT_DATE, this.dateTimeElementTypes.LONG_DATE, this.dateTimeElementTypes.DAY_OF_WEEK, this.dateTimeElementTypes.FULL_ERA, this.dateTimeElementTypes.ABBREV_ERA, this.dateTimeElementTypes.FRACTIONAL_SECONDS, this.dateTimeElementTypes.HOUR_OF_DAY_24, this.dateTimeElementTypes.HOUR_OF_DAY_12, this.dateTimeElementTypes.ISO_WEEK_OF_YEAR, this.dateTimeElementTypes.ISO_YEAR, this.dateTimeElementTypes.JULIAN_DAY, this.dateTimeElementTypes.MINUTE, this.dateTimeElementTypes.MONTH, this.dateTimeElementTypes.LONG_MONTH_NAME, this.dateTimeElementTypes.SHORT_MONTH_NAME, this.dateTimeElementTypes.QUARTER_OF_YEAR, this.dateTimeElementTypes.ROMAN_NUMERAL_MONTH, this.dateTimeElementTypes.LONG_ROUNDED_YEAR, this.dateTimeElementTypes.SHORT_ROUNDED_YEAR, this.dateTimeElementTypes.SECONDS_PAST_MIDNIGHT, this.dateTimeElementTypes.SECONDS, this.dateTimeElementTypes.SHORT_TIME, this.dateTimeElementTypes.TZ_DAYLIGHT_SAVING, this.dateTimeElementTypes.TZ_HOUR, this.dateTimeElementTypes.TZ_MINUTE, this.dateTimeElementTypes.TZ_REGION, this.dateTimeElementTypes.WEEK_OF_YEAR, this.dateTimeElementTypes.WEEK_OF_MONTH, this.dateTimeElementTypes.LOCAL_RADIX, this.dateTimeElementTypes.FOUR_DIGIT_YEAR, this.dateTimeElementTypes.SPELLED_OUT_YEAR, this.dateTimeElementTypes.LAST_DIGIT_OF_YEAR, this.dateTimeElementTypes.TEXT, this.dateTimeElementTypes.PUNCTUATION, this.dateTimeElementTypes.WHITESPACE, this.dateTimeElementTypes.UNPAD_MOD, this.dateTimeElementTypes.STRICT_MOD, this.dateTimeElementTypes.SINGLE_QUOTE ]; this.numericalMonthTypes = [ this.dateTimeElementTypes.MONTH ]; this.textualMonthTypes = [ this.dateTimeElementTypes.SHORT_MONTH_NAME, this.dateTimeElementTypes.LONG_MONTH_NAME ]; this.yearTypes = [ this.dateTimeElementTypes.ISO_YEAR, this.dateTimeElementTypes.LAST_DIGIT_OF_YEAR, this.dateTimeElementTypes.FOUR_DIGIT_YEAR ]; this.separatorTypes = [ this.dateTimeElementTypes.PUNCTUATION, this.dateTimeElementTypes.WHITESPACE, this.dateTimeElementTypes.TEXT ]; this.parseDateTimeFormat = function parseDateTimeFormat(formatSpecifier) { if (formatSpecifier === undefined) { formatSpecifier = this.settingsContainer.dateformat; } var elements = []; var isUnpadded = false; var isStrict = false; var index = 0; var specifierLength = formatSpecifier.length; while (index < specifierLength) { var remainder = formatSpecifier.substring(index, specifierLength); var matchResult = null; if (matchResult = this.matchDateTimeElement(this.dateTimeElementTypes.UNPAD_MOD, remainder)) { isUnpadded = !isUnpadded; } else if (matchResult = this.matchDateTimeElement(this.dateTimeElementTypes.STRICT_MOD, remainder)) { isStrict = !isStrict; } else { for (var i = 0; i < this.matchOrder.length; i++) { var dateTimeElementType = this.matchOrder[i]; matchResult = this.matchDateTimeElement(dateTimeElementType, remainder); if (matchResult !== null) { elements.push(new DateTimeElement(dateTimeElementType, matchResult, isUnpadded, isStrict)); break; } } } if (matchResult === null) { throw "Failed to parse format specifier '"+ formatSpecifier + "': Unrecognized element at position " + index; } index += matchResult.length; } return elements; }; this.matchDateTimeElement = function matchDateTimeElement(dateTimeElementType, inputString) { var matchResult = dateTimeElementType.matchRegexp.exec(inputString); if (matchResult === null || matchResult.index !== 0) return null; return matchResult[0]; }; this.formatDateTime = function formatDateTime(date, formatSpecifier) { var elements = this.parseDateTimeFormat(formatSpecifier); // check if there is era among elements, if yes we have to reset the year getter to work with Japanese calendar var containsEra = elements.some(function (element) { return ( element.elementType === that.dateTimeElementTypes.FULL_ERA || element.elementType === that.dateTimeElementTypes.ABBREV_ERA ); }); if (containsEra) { this.getFullYear = this.getJapaneseImperialYear } return this.formatDateTimeFromElements(elements, date); }; this.formatDateTimeFromElements = function formatDateTimeFromElements(elements, dateObject) { return elements.map(function (element) { var formatterFunction = element.formatterFunction; if (formatterFunction === undefined) { throw "No formatting function associated with element type " + element.elementType.toString(); } return formatterFunction(element, dateObject); }).join(''); }; this.formatMMYYDateString = function formatMMYYDateString(dateObject, dateFormat) { var elements = this.extractMMYYElements(this.parseDateTimeFormat(dateFormat)); return this.formatDateTimeFromElements(elements, dateObject); }; this.extractMMYYElements = function extractMMYYElements(dateFormatElements) { var elementsLength = dateFormatElements.length; var index = 0; var monthElement = null, yearElement = null, separator = null; // this complex logic is needed to preserve the rules from the original code // namely long months are replaced by short month names and some separators (punctuation, whitespace) are replaced // by some long forgotten rules while (index < elementsLength && (monthElement === null || yearElement === null || separator === null)) { var currentElement = dateFormatElements[index]; var currentType = currentElement.elementType; var currentValue = currentElement.value; var currentIsUnpadded = currentElement.isUnpadded; var currentIsStrict = currentElement.isStrict; var nextElementType = index + 1 !== elementsLength ? dateFormatElements[index + 1].elementType : undefined; if (monthElement === null && this.numericalMonthTypes.indexOf(currentType) !== -1) { monthElement = currentElement; } else if (monthElement === null && this.textualMonthTypes.indexOf(currentType) !== -1) { monthElement = new DateTimeElement( this.dateTimeElementTypes.SHORT_MONTH_NAME, 'Mon', currentIsUnpadded, currentIsStrict); } else if (yearElement === null && this.yearTypes.indexOf(currentType) !== -1) { yearElement = currentElement; } else if (separator === null && this.separatorTypes.indexOf(currentType) !== -1) { if (currentValue === '-' || (currentValue === '.' && nextElementType !== this.dateTimeElementTypes.WHITESPACE)) { separator = currentElement; } else { separator = new DateTimeElement( this.dateTimeElementTypes.PUNCTUATION, '/', currentIsUnpadded, currentIsStrict); } } index++; } return [monthElement, separator, yearElement].filter(function (value) { return value !== null }); }; // strip the incoming datetime format of elements that may trip up the parsing functions define here this.preprocessDateTimeFormat = function preprocessDateTimeFormat(inputFormat) { return inputFormat.replace(/f[mx]|"/ig, ""); } } var oracleDateTimeFormatterFactory = (function() { var _instance = null; return { getFormatter: function () { if (_instance === null) { _instance = new OracleDateTimeFormatter( window, { getJapaneseImperialEra: get_japanese_imperial_era, getShortJapaneseImperialEra: get_short_japanese_imperial_era, getJapaneseImperialYear: get_japanese_imperial_year }, NLDate_short_months, NLDate_months ); } return _instance; } }; })(); var NLAlertContext_CREDIT_CARD_NUMBERS_MUST_CONTAIN_BETWEEN_13_AND_20_DIGITS = "Credit card numbers must contain between 13 and 20 digits."; var NLAlertContext_CREDIT_CARD_NUMBERS_MUST_CONTAIN_ONLY_DIGITS = "Credit card numbers must contain only digits."; var NLAlertContext_EMAIL_ADDRESSES_MUST_MATCH = "Email addresses must match."; var NLAlertContext_NETSUITE_DOES_NOT_ACCEPT_EMAIL_ADDRESSES_WITH_QUOTATION_MARKS_COMMAS_COLONS_SPACES_OR_GREATER_THAN_OR_LESS_THAN_SIGNS = "Please make sure there are no quotation marks, commas, colons, spaces, or greater than or less than signs."; var NLAlertContext_PASSWORDS_DONT_MATCHN = "Passwords don\'t match.\n"; var NLAlertContext_PASSWORDS_CANNOT_BE_EMPTYN = "Passwords cannot be empty.\n"; var NLAlertContext_PASSWORDS_MUST_BE_AT_LEAST_1_CHARACTERS_LONGN = "Passwords must be at least {1} characters long."; var NLAlertContext_PASSWORDS_MUST_CONTAIN_AT_LEAST_ONE_LETTER_AZN = "Passwords must contain at least one letter (A-Z).\n"; var NLAlertContext_PASSWORDS_MUST_CONTAIN_AT_LEAST_ONE_NUMBER_OR_SPECIAL_CHARACTERN = "Passwords must contain at least one number or special character.\n"; var NLAlertContext_PASSWORDS_MAY_CONTAIN_ONLY_LETTERS_NUMBERS_AND_SPECIAL_CHARACTERSN = "Passwords may contain only letters, numbers, and special characters.\n"; var NLAlertContext_OLD_AND_NEW_PASSWORDS_ARE_TOO_SIMILAR = "Old and new passwords are too similar."; var NLAlertContext_PASSWORD_MUST_NOT_BE_THE_SAME_AS_THE_EMAIL_ADDRESS = "Password must not be the same as the email address"; var NLAlertContext_CREDIT_CARD_NUMBER_IS_NOT_VALID__PLEASE_CHECK_THAT_ALL_DIGITS_WERE_ENTERED_CORRECTLY = "Credit card number is not valid. Please check that all digits were entered correctly."; var NLAlertContext_NETSUITE_DOES_NOT_ACCEPT_EMAIL_ADDRESSES_WITH_QUOTATION_MARKS_COMMAS_COLONS_SPACES_OR_GREATER_THAN_OR_LESS_THAN_SIGNS = "Please make sure there are no quotation marks, commas, colons, spaces, or greater than or less than signs."; var NLAlertContext_PLEASE_ENTER_A_VALID_EMAIL_ADDRESS = "Please enter a valid email address."; var NLValidationUtil_SIMPLE_EMAIL_PATTERN = /^[-a-zA-Z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-a-zA-Z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-zA-Z0-9]+(?:-+[a-zA-Z0-9]+)*\.)+(?:xn--[-a-zA-Z0-9]+|[a-zA-Z]{2,16})$/i; var NLAlertContext_THE_SPECFIED_ROUTING_NUMBER_FAILED_VALIDATION_FOR_ABA_ROUTING_NUMBERS = "The specified routing number failed validation for ABA Routing Numbers."; var NLAlertContext_ABA_ROUTING_NUMBERS_MUST_BE_NINE_CHARACTERS = "ABA Routing Numbers must be nine characters."; /** * check if the value is empty * @param val String being tested for whether it is empty (null or "") */ function isValEmpty(val) { if (val === null || val === undefined) return true; val = new String(val); return (val.length == 0) || !/\S/.test(val); } /** * isHTMLValEmpty() returns true if the given string is empty or contains only whitespace, ignoring HTML markup * @param val String being tested for whether it is empty (null or "") */ function isHTMLValEmpty(val) { if (isValEmpty(val)) return true; val = val.replace(/ |<(?!NL)[^>]*>/gi, ''); return !/\S/.test(val); } /* works just like the SQL NVL function */ function nvl(val,val2) { return val == null ? val2 : val; } // emptyIfNull(): return empty string if vall is null. function emptyIfNull(val) { return val == null ? '' : val; } // nullIfEmpty(): return null if val is null or empty. function nullIfEmpty(val) { return isValEmpty(val) ? null : val; } /* * Trims leading and trailing whitespace from a string. * Similar to Java's String.trim(), see corresponding doc there. */ function trim(str) { return str.replace(/^\s+/,"").replace(/\s+$/,""); } function onlydigitsandchars(str) { var re = new RegExp("([A-Za-z0-9]+)"); return (re.exec(str)!=null && RegExp.$1==str); } function onlydigits(str) { return /^[0-9]+$/.test(str); } /** * returns true if the value is null, empty, or evaluates to a math equivalent value of zero. * @param fieldval String being tested for whether it is empty or zero */ function isemptyorzero(fieldval) { var val = fieldval; var isempty = isValEmpty(val); var iszero = val==0; return (isempty || iszero); } /** * returns true if the value is null, empty, or evaluates to a math equivalent value of zero. * @param fieldval String being tested for whether it is empty or zero */ function isNewRecord() { var id = typeof nlapiGetField != undefined && nlapiGetField("id") != null ? nlapiGetFieldValue("id") : typeof document != undefined && document.forms['main_form'].elements['id'] != null ? document.forms['main_form'].elements['id'] : ""; return isValEmpty(id) || id == -1 } /** * returns true if the current record is an existing record */ function isExistingRecord() { return !isNewRecord(); } /** * returns true if the current record is an existing record */ function getEditFlag() { return isExistingRecord(); } /** * Perform mandatory field check * * @param fields Array of field names or field references (UI) * @param labels Array of field labels * @param values Array of field values (only used during dynamic scripting contexts) * @param type Sublist name if this is called for a machine (current line on an edit machine) * @param returnArray If true, return the labels as array, otherwise as comma separated string */ function checkMandatoryFields(fields, labels, values, type, returnArray) { var skipCheck = (type === 'item' && window.is_adding_multiple_items); var result = []; for (var i = 0; !skipCheck && i < fields.length; i++) { if (fields[i] == null) continue; var val = values != null ? values[i] : fields[i].value; if ((new String(val)).indexOf(String.fromCharCode(3)) != -1) { var nvarray = val.split(String.fromCharCode(4)); for (var j = 0; j < nvarray.length; j++) { var nv = nvarray[j].split(String.fromCharCode(3)); if (nv[1] == 'T' && nv[3].length == 0) result.push(nv[2]); } continue; } if (values != null) { if ((type != null && !Machine_isMandatoryOnThisLine(type, fields[i], nlapiGetCurrentLineItemIndex(type))) || (type == null && !nlapiGetFieldMandatory(fields[i]))) continue; if (isValEmpty(val)) result.push(labels[i]); } else { if (!getRequired(fields[i])) continue; if (isSelect(fields[i]) || isPopupSelect(fields[i])) { val = getSelectValue(fields[i]); if (isValEmpty(val)) result.push(labels[i]); } else if (window.getHtmlEditor != null && getHtmlEditor(fields[i].name) != null) { if (isValEmpty(fields[i].value.replace("
", ""))) result.push(labels[i]); } else { if (isempty(fields[i])) result.push(labels[i]); } } } if (returnArray) while (result[0] === '') result.shift(); // emulate faulty behavior of the legacy implementation return returnArray ? result : result.join(', '); } /** * Perform unique field validation on an edit machine (executed during validateLine) * * @param name machine name * @param uniquefields Array of field names for unique fields * @param uniquelabels Array of field labels for unique fields * * @return An array of the unique field labels if there is a validation error or null */ function checkUniqueFields(name, uniquefields, uniquelabels) { if ( uniquefields == null || uniquefields.length == 0 ) return null; for (var i=1; i<= nlapiGetLineItemCount(name)+1; i++) { if (i == nlapiGetCurrentLineItemIndex(name)) continue; var bAllEmpty = true, bMatch = true; for (var j=0; j < uniquefields.length; j++) { var f = uniquefields[j]; if (!isValEmpty(getEncodedValue(name,i,f))) bAllEmpty = false; if (getEncodedValue(name,i,f) != nlapiGetCurrentLineItemValue(name, uniquefields[j])) { bMatch = false; break; } } if (bAllEmpty || !bMatch) continue; var labels = new Array(); for (var k=0; k < uniquefields.length; k++) { labels.push(uniquelabels[k]); } return labels; } return null; } // checkccnumber(): check if value in form fld is valid credit card. If this is called from the UI (i.e. webstore) then fld is a DOM field // reference. Otherwise it is a String containing the name of the field (use SuiteScript API for setting field) // NOTE: this is not a perfect check by any means. it does // not check that amex is 15 and visa/other is 16. it also // doesn't do the visa checksum. // DJ11sep2000 -- I added code to do the luhn checksum check. // YF10Nov2008 -- moved to NLRecordUtil.js from NLUtil.js (please keep this in sync with NLValidationUtil.luhnCheck(s)) function checkccnumber(fld) { // Remove all spaces and dashes. // you must check for length 0 up front. if you don't // mac ie5 will crashes on the replace call below. var cardnum = typeof(fld) != "string" ? fld.value : nlapiGetFieldValue(fld); if(cardnum.length > 0) cardnum = cardnum.replace(/ /gi,''); if(cardnum.length > 0) cardnum = cardnum.replace(/-/gi,''); if (cardnum.length<13 || cardnum.length>20) { alert(NLAlertContext_CREDIT_CARD_NUMBERS_MUST_CONTAIN_BETWEEN_13_AND_20_DIGITS); return false; } if (!onlydigits(cardnum)) { alert(NLAlertContext_CREDIT_CARD_NUMBERS_MUST_CONTAIN_ONLY_DIGITS); return false; } // Perform Luhn check // http://www.ling.nwu.edu/~sburke/pub/luhn_lib.pl var no_digit = cardnum.length; var oddoeven = no_digit & 1; var sum = 0; for (var count = 0; count < no_digit; count++) { var digit = parseInt(cardnum.charAt(count),10); if (!((count & 1) ^ oddoeven)) { digit *= 2; if (digit > 9) digit -= 9; } sum += digit; } if (sum % 10 != 0) { alert(NLAlertContext_CREDIT_CARD_NUMBER_IS_NOT_VALID__PLEASE_CHECK_THAT_ALL_DIGITS_WERE_ENTERED_CORRECTLY); return false; } eval( typeof(fld) != "string" ? "fld.value = cardnum" : "nlapiSetFieldValue(fld, cardnum, false)" ); return true; } /** * Set preferred fields following the addition of a new line on an edit machine (executed after validateLine but before recalc) * * @param name sublist name * @param preferredfield preferred field name * @param linenum line number being added */ function setPreferredFields(name, preferredfield, preferredwithinfield, linenum) { if (getEncodedValue(name,linenum,preferredfield) == 'T') { for (var i=1; i <= getLineCount(name)+1; i++) { if (i != linenum && getEncodedValue(name,i,preferredfield) == 'T') { if(preferredwithinfield == null || getEncodedValue(name,linenum,preferredwithinfield) == getEncodedValue(name,i,preferredwithinfield)) setEncodedValue(name,i,preferredfield,'F'); } } } return true; } function escapeJSONChar(c) { if(c == "\"" || c == "\\") return "\\" + c; else if (c == "\b") return "\\b"; else if (c == "\f") return "\\f"; else if (c == "\n") return "\\n"; else if (c == "\r") return "\\r"; else if (c == "\t") return "\\t"; var hex = c.charCodeAt(0).toString(16); if(hex.length == 1) return "\\u000" + hex; else if(hex.length == 2) return "\\u00" + hex; else if(hex.length == 3) return "\\u0" + hex; else return "\\u" + hex; } function escapeJSONString(s) { /* The following should suffice but Safari's regex is b0rken (doesn't support callback substitutions) return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, escapeJSONChar) + "\""; */ /* Rather inefficient way to do it */ var parts = s.split(""); for(var i=0; i < parts.length; i++) { var c =parts[i]; if(c == '"' || c == '\\' || c.charCodeAt(0) < 32 || c.charCodeAt(0) >= 128) parts[i] = escapeJSONChar(parts[i]); } return "\"" + parts.join("") + "\""; } toJSON = function toJSON(o) { if (o == null) // note: if o is undefined, this statement is true return "null"; else if(o.constructor == String || o.constructor.name == "String") return escapeJSONString(o); else if(o.constructor == Number || o.constructor.name == "Number") return o.toString(); else if(o.constructor == Boolean || o.constructor.name == "Boolean") return o.toString(); else if(o.constructor == Date || o.constructor.name == "Date") return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; else if(o.constructor == Array || o.constructor.name == "Array" || o.length >= 0) { var v = []; for (var i = 0; i < o.length; i++) v.push(toJSON(o[i])); return "[" + v.join(", ") + "]"; } else { var v = []; for(attr in o) { if(o[attr] == null) v.push("\"" + attr + "\": null"); else if(typeof o[attr] == "function"); /* skip */ else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr])); } return "{" + v.join(", ") + "}"; } } // Used to parse quantity price schedules function getQtyRate(schedstr,qty,marginal) { var sched = schedstr.split(String.fromCharCode(5)); var i; var cum_amount=0; var rate; for (i=0;i < sched.length;i+=2) { if (qty >= parseFloat(sched[i]) && (i+2>=sched.length || qty < parseFloat(sched[i+2]))) { if (marginal && qty>0) { cum_amount+=(qty-parseFloat(sched[i]))*parseFloat(sched[i+1]); rate=cum_amount/qty; } else rate=sched[i+1]; break; } else if (marginal && qty > 0) cum_amount += (parseFloat(sched[i+2])-parseFloat(sched[i]))*parseFloat(sched[i+1]); } return rate; } function parseFloatOrZero(f) { var r=parseFloat(f); return isNaN(r) ? 0 : r; } function isValidUSZipCode(value) { var re = /^\d{5}([\-]\d{4})?$/; return (re.test(value)); } function checkemail(email,emptyok,alrt) { // mirrors Java's String.trim() - remove leading and trailing whitespace email = trim(email); return checkemail2(email,email,emptyok,alrt); } function checkemail2(email_1,email_2,emptyok,alrt) { var s_email = email_1; if (s_email != email_2) { alert(NLAlertContext_EMAIL_ADDRESSES_MUST_MATCH); return false; } if (emptyok && s_email.length==0) { return true; } return checkemailvalue(s_email,alrt); } function checkemailvalue(s_email,alrt) { alrt = true; if (/\s|[,":<>]/.test(s_email)) { if (alrt) { alert(NLAlertContext_PLEASE_ENTER_A_VALID_EMAIL_ADDRESS + " " + NLAlertContext_NETSUITE_DOES_NOT_ACCEPT_EMAIL_ADDRESSES_WITH_QUOTATION_MARKS_COMMAS_COLONS_SPACES_OR_GREATER_THAN_OR_LESS_THAN_SIGNS); } return false; } if (!NLValidationUtil_SIMPLE_EMAIL_PATTERN.test(s_email)) { if (alrt) { alert(s_email + ' ' + NLAlertContext_PLEASE_ENTER_A_VALID_EMAIL_ADDRESS); } return false; } return true; } function checkemailprefix(s_email) { /* Return true if string appears to be an email prefix (eg. wbailey@netl). Used by uber search. - Must have exactly one '@' preceded by one or more chars - Must not contain any of these chars: