Parameter.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /* Copyright (c) Business Objects 2006. All rights reserved. */
  2. if (typeof bobj.crv.params == 'undefined') {
  3. bobj.crv.params = {};
  4. bobj.crv.params.DataTypes = {
  5. DATE: "d",
  6. DATE_TIME: "dt",
  7. TIME: "t",
  8. STRING: "s",
  9. NUMBER: "n",
  10. CURRENCY: "c",
  11. BOOLEAN: "b"
  12. };
  13. bobj.crv.params.RangeBoundTypes = {
  14. UNBOUNDED: 0,
  15. EXCLUSIVE: 1,
  16. INCLUSIVE: 2
  17. };
  18. bobj.crv.params.DefaultDisplayTypes = {
  19. Description: 0,
  20. DescriptionAndValue: 1
  21. };
  22. bobj.crv.params.CompareResults = {
  23. TOO_BIG: 1,
  24. TOO_SMALL: -1,
  25. EQUAL: 0
  26. };
  27. }
  28. /*
  29. ================================================================================
  30. Parameter
  31. ================================================================================
  32. */
  33. /**
  34. * Constructor.
  35. */
  36. bobj.crv.params.Parameter = function(paramInfo) {
  37. var PARAMS = bobj.crv.params;
  38. var displayTypes = PARAMS.DefaultDisplayTypes;
  39. MochiKit.Base.update(this, {
  40. paramName: null,
  41. reportName: null,
  42. description: null,
  43. valueDataType: null,
  44. value: null,
  45. modifiedValue: null,
  46. defaultValues: null,
  47. defaultDisplayType : displayTypes.DescriptionAndValue,
  48. maxValue: null,
  49. minValue: null,
  50. allowCustomValue: true,
  51. allowDiscreteValue: true,
  52. allowMultiValue: false,
  53. allowNullValue: false,
  54. allowRangeValue: false,
  55. editMask: null,
  56. isOptionalPrompt: false,
  57. isEditable: true,
  58. isHidden: false,
  59. isDataFetching: false,
  60. attributes: null
  61. }, paramInfo);
  62. this.valueCounter = new PARAMS.ValueCounter(this.value, this.valueDataType);
  63. };
  64. /**
  65. * IMPORTANT! Use getValue and setValue to access the value of the parameter, instead of the property itself.
  66. */
  67. bobj.crv.params.Parameter.prototype = {
  68. getTitle: function() {
  69. return (this.description || this.paramName);
  70. },
  71. hasLOV: function() {
  72. return (this.defaultValues && this.defaultValues.length);
  73. },
  74. isPassword: function() {
  75. return (this.editMask !== null && this.editMask.toLowerCase() == "password");
  76. },
  77. getValue: function() {
  78. this._initModifiedValue();
  79. return this.modifiedValue;
  80. },
  81. removeValueAt: function(index) {
  82. this._initModifiedValue();
  83. var value = this.modifiedValue[index];
  84. this.modifiedValue.splice(index, 1);
  85. this.valueCounter.reduceCount(value);
  86. },
  87. // setValue accepts either an array, or an int + an object.
  88. setValue: function (i, newValue) {
  89. this._initModifiedValue();
  90. if (arguments.length == 1 && bobj.isArray(arguments[0])) {
  91. var value= arguments[0];
  92. this.modifiedValue = value;
  93. this.valueCounter.resetValue(value);
  94. }
  95. else if (arguments.length == 2) {
  96. var oldValue = this.modifiedValue[i];
  97. this.modifiedValue[i] = newValue;
  98. this.valueCounter.reduceCount(oldValue);
  99. this.valueCounter.addCount(newValue);
  100. }
  101. },
  102. clearValue: function() {
  103. this._initModifiedValue();
  104. this.modifiedValue = [];
  105. },
  106. // commitValue will actually apply the changes made so far
  107. commitValue: function() {
  108. this._initModifiedValue();
  109. this.value = this.modifiedValue.slice(0);
  110. },
  111. _initModifiedValue: function() {
  112. if (!this.modifiedValue) {
  113. if (bobj.isArray(this.value)) {
  114. this.modifiedValue = this.value.slice(0); // make a deep copy of "value"
  115. }
  116. else {
  117. this.modifiedValue = [];
  118. }
  119. }
  120. },
  121. addDuplicateValuesCB: function(hasDuplicateCB,hasNoDuplicateCB) {
  122. this.valueCounter.addCallBacks(hasDuplicateCB,hasNoDuplicateCB);
  123. },
  124. isDCP: function () {
  125. if (this.attributes != null) {
  126. if (this.attributes['IsDCP'] === true) {
  127. return true;
  128. }
  129. }
  130. return false;
  131. }
  132. };
  133. /*
  134. ================================================================================
  135. Validator for Parameters
  136. ================================================================================
  137. */
  138. bobj.crv.params.Validator = function(){};
  139. bobj.crv.params.Validator.ValueStatus = {
  140. OK: 0,
  141. ERROR: 1,
  142. VALUE_MISSING: 2, // Required value is missing
  143. VALUE_INVALID_TYPE: 3, // Value has the wrong data type
  144. VALUE_TOO_LONG: 4, // Value's length is less than the minimum
  145. VALUE_TOO_SHORT: 5, // Value's length is greater than the maximum
  146. VALUE_TOO_BIG: 6, // Value is greater than the maximum
  147. VALUE_TOO_SMALL: 7, // Value is less than the minimum
  148. VALUE_DUPLICATE: 8
  149. };
  150. bobj.crv.params.Validator.getInstance = function(){
  151. if (!bobj.crv.params.Validator.__instance) {
  152. bobj.crv.params.Validator.__instance = new bobj.crv.params.Validator();
  153. }
  154. return bobj.crv.params.Validator.__instance;
  155. };
  156. bobj.crv.params.Validator.prototype = {
  157. /**
  158. * Validate a Parameter instance and return a status object
  159. */
  160. validateParameter: function(param) {
  161. var PARAMS = bobj.crv.params;
  162. if (!param) {return null;}
  163. var Status = PARAMS.Validator.ValueStatus;
  164. if (!bobj.isArray(param.value) || !param.value.length) {
  165. return {
  166. isValid: false,
  167. reason: Status.VALUE_MISSING
  168. };
  169. }
  170. var isValid = true;
  171. var statusList = [];
  172. for (var i = 0, len = param.values.length; i < len; ++i) {
  173. var status = PARAMS.validateValue(param, i);
  174. statusList.push(status);
  175. isValid = isValid && (status === ValueStatus.OK);
  176. }
  177. return {
  178. isValid: isValid,
  179. statusList: statusList
  180. };
  181. },
  182. /**
  183. * Validate a parameter value and return a status code
  184. */
  185. validateValue: function(param, value) {
  186. var Status = bobj.crv.params.Validator.ValueStatus;
  187. if (!param || !bobj.isArray(param.value) || (value === undefined)) {
  188. return Status.ERROR;
  189. }
  190. var validatorFunc = this._getTypeValidatorFunc(param.valueDataType);
  191. if (!validatorFunc) {
  192. return Status.ERROR;
  193. }
  194. return validatorFunc(param, value);
  195. },
  196. _getTypeValidatorFunc: function(type) {
  197. var Type = bobj.crv.params.DataTypes;
  198. switch (type) {
  199. case Type.STRING:
  200. return this._validateString;
  201. case Type.NUMBER:
  202. case Type.CURRENCY:
  203. return this._validateNumber;
  204. case Type.DATE:
  205. case Type.TIME:
  206. case Type.DATE_TIME:
  207. return this._validateDateTime;
  208. case Type.BOOLEAN:
  209. return this._validateBoolean;
  210. default:
  211. return null;
  212. }
  213. },
  214. _validateString: function(param, value) {
  215. var Status = bobj.crv.params.Validator.ValueStatus;
  216. if (!bobj.isString(value)) {
  217. return Status.VALUE_INVALID_TYPE;
  218. }
  219. var maxValue = param.maxValue;
  220. var minValue = param.minValue;
  221. if (bobj.isNumber(maxValue) && value.length > maxValue) {
  222. return Status.VALUE_TOO_LONG;
  223. }
  224. if (bobj.isNumber(minValue) && value.length < minValue) {
  225. return Status.VALUE_TOO_SHORT;
  226. }
  227. return Status.OK;
  228. },
  229. _validateNumber: function(param, value) {
  230. //the "value" passed in here is a number that has at most one decimal separator and no group separator
  231. var Status = bobj.crv.params.Validator.ValueStatus;
  232. var regNumber = /^(\+|-)?(\d+(\.\d+)?|\.\d+)$/;
  233. if(bobj.isString(value) && regNumber.test(value)) {
  234. value = parseFloat(value);
  235. }
  236. else if(!bobj.isNumber(value)) {
  237. return Status.VALUE_INVALID_TYPE;
  238. }
  239. var maxValue = param.maxValue;
  240. var minValue = param.minValue;
  241. if(maxValue !== null && value > maxValue) {
  242. return Status.VALUE_TOO_BIG;
  243. }
  244. else if(minValue !== null && value < minValue) {
  245. return Status.VALUE_TOO_SMALL;
  246. }
  247. else {
  248. return Status.OK;
  249. }
  250. },
  251. _validateDateTime: function(param, value) {
  252. var Result = bobj.crv.params.CompareResults;
  253. var Status = bobj.crv.params.Validator.ValueStatus;
  254. if (bobj.isObject(value)) {
  255. var isNumber = function(sel) {return bobj.isNumber(value[sel]);};
  256. if (MochiKit.Iter.every(['d','m', 'y', 'h', 'min', 's', 'ms'], isNumber)) {
  257. var compareFunc = bobj.crv.params.getDateCompareFunc(param.valueDataType);
  258. if(param.minValue && compareFunc(param.minValue,value) == Result.TOO_BIG) {
  259. return Status.VALUE_TOO_SMALL;
  260. }
  261. else if(param.maxValue && compareFunc(param.maxValue,value) == Result.TOO_SMALL) {
  262. return Status.VALUE_TOO_BIG;
  263. }
  264. else {
  265. return Status.OK;
  266. }
  267. }
  268. }
  269. return Status.VALUE_INVALID_TYPE;
  270. },
  271. _validateBoolean: function(param, value) {
  272. return bobj.crv.params.Validator.ValueStatus.OK;
  273. }
  274. };
  275. /*
  276. ================================================================================
  277. Utility Functions
  278. ================================================================================
  279. */
  280. /**
  281. * Get an object that represents a Date and can be serialized to a json string
  282. *
  283. * @param date [Date] The Date instance that should be represented as json
  284. *
  285. * @return [Object] Object representing the date with (key, value) pairs
  286. */
  287. bobj.crv.params.dateToJson = function(date) {
  288. return {
  289. d: date.getDate(),
  290. m: date.getMonth(),
  291. y: date.getFullYear(),
  292. h: date.getHours(),
  293. min: date.getMinutes(),
  294. s: date.getSeconds(),
  295. ms: date.getMilliseconds()
  296. };
  297. };
  298. bobj.crv.params.getDateCompareFunc = function(type) {
  299. var PARAMS = bobj.crv.params;
  300. var Type = PARAMS.DataTypes;
  301. switch (type) {
  302. case Type.DATE:
  303. return PARAMS.compareDate;
  304. case Type.TIME:
  305. return PARAMS.compareTime;
  306. case Type.DATE_TIME:
  307. return PARAMS.compareDateTime;
  308. default:
  309. return null;
  310. }
  311. };
  312. bobj.crv.params.compareDateTime = function(dateTimeA, dateTimeB) {
  313. var PARAMS = bobj.crv.params;
  314. var Result = PARAMS.CompareResults;
  315. var dateResult = PARAMS.compareDate(dateTimeA,dateTimeB);
  316. var timeResult = PARAMS.compareTime(dateTimeA,dateTimeB);
  317. if(dateResult == Result.EQUAL && timeResult == Result.EQUAL) {
  318. return Result.EQUAL;
  319. }
  320. if(dateResult != Result.EQUAL) {
  321. return dateResult;
  322. }
  323. else {
  324. return timeResult;
  325. }
  326. };
  327. /*
  328. * Compares two dates
  329. * @param dateA [JSON DateTime {y,m,d,h,m,s,ms}] first date value
  330. * @param dateB [JSON DateTime {y,m,d,h,m,s,ms}] second date value
  331. *
  332. * @return
  333. * 0: dateA = dateB
  334. * 1: dateA > dateB
  335. * -1: dateA < dateB
  336. */
  337. bobj.crv.params.compareDate = function(dateTimeA, dateTimeB) {
  338. var Result = bobj.crv.params.CompareResults;
  339. if( dateTimeA.d == dateTimeB.d && dateTimeA.m == dateTimeB.m && dateTimeA.y == dateTimeB.y){
  340. return Result.EQUAL;
  341. }
  342. if( dateTimeA.y > dateTimeB.y) {
  343. return Result.TOO_BIG;
  344. }
  345. else if(dateTimeA.y < dateTimeB.y) {
  346. return Result.TOO_SMALL;
  347. }
  348. if(dateTimeA.m > dateTimeB.m) {
  349. return Result.TOO_BIG;
  350. }
  351. else if(dateTimeA.m < dateTimeB.m) {
  352. return Result.TOO_SMALL;
  353. }
  354. if(dateTimeA.d > dateTimeB.d) {
  355. return Result.TOO_BIG;
  356. }
  357. else if(dateTimeA.d < dateTimeB.d) {
  358. return Result.TOO_SMALL;
  359. }
  360. };
  361. /*
  362. * Compares two times
  363. * @param timeA [JSON DateTime {y,m,d,h,m,s,ms}] first time value
  364. * @param timeB [JSON DateTime {y,m,d,h,m,s,ms}] second time value
  365. *
  366. * @return
  367. * 0: dateA = dateB
  368. * 1: dateA > dateB
  369. * -1: dateA < dateB
  370. */
  371. bobj.crv.params.compareTime = function(dateTimeA,dateTimeB) {
  372. var Result = bobj.crv.params.CompareResults;
  373. if(dateTimeA.h == dateTimeB.h && dateTimeA.min == dateTimeB.min && dateTimeA.s == dateTimeB.s && dateTimeA.ms == dateTimeB.ms) {
  374. return Result.EQUAL;
  375. }
  376. if(dateTimeA.h > dateTimeB.h) {
  377. return Result.TOO_BIG;
  378. }
  379. else if(dateTimeA.h < dateTimeB.h){
  380. return Result.TOO_SMALL;
  381. }
  382. if(dateTimeA.min > dateTimeB.min) {
  383. return Result.TOO_BIG;
  384. }
  385. else if(dateTimeA.min < dateTimeB.min) {
  386. return Result.TOO_SMALL;
  387. }
  388. if(dateTimeA.s > dateTimeB.s) {
  389. return Result.TOO_BIG;
  390. }
  391. else if(dateTimeA.s < dateTimeB.s) {
  392. return Result.TOO_SMALL;
  393. }
  394. if(dateTimeA.ms > dateTimeB.ms) {
  395. return Result.TOO_BIG;
  396. }
  397. else if(dateTimeA.ms < dateTimeB.ms){
  398. return Result.TOO_SMALL;
  399. }
  400. };
  401. /**
  402. * Get a Date instance from an object containing (key, value) pairs
  403. *
  404. * @param json [Object] Object with keys that match Date properties
  405. *
  406. * @return [Date] Returns a Date instance
  407. */
  408. bobj.crv.params.jsonToDate = function(json) {
  409. var date = new Date();
  410. if (json) {
  411. date.setFullYear(json.y || 0, json.m || 0, json.d || 1);
  412. date.setHours(json.h || 0);
  413. date.setMinutes(json.min || 0);
  414. date.setSeconds(json.s || 0);
  415. date.setMilliseconds(json.ms || 0);
  416. }
  417. return date;
  418. };
  419. bobj.crv.params.ValueCounter = function(initialValue,valueDataType) {
  420. this.values = {};
  421. this.valueDataType = valueDataType;
  422. this.valueHasDupCB = null;
  423. this.valueNoDupCB = null;
  424. this.resetValue(initialValue);
  425. };
  426. bobj.crv.params.ValueCounter.prototype = {
  427. addCallBacks: function(valueHasDupCB, valueNoDupCB) {
  428. this.valueHasDupCB = valueHasDupCB;
  429. this.valueNoDupCB = valueNoDupCB;
  430. },
  431. addCount : function(value) {
  432. if(value !== null && value !== undefined && value.beginValue === undefined) {
  433. var hashValue = bobj.getValueHashCode(this.valueDataType, value);
  434. if(this.values[hashValue] !== null && this.values[hashValue] !== undefined) {
  435. this.values[hashValue] += 1;
  436. if(this.valueHasDupCB && this.values[hashValue] > 1) {
  437. this.valueHasDupCB(value);
  438. }
  439. }
  440. else {
  441. this.values[hashValue] = 1;
  442. }
  443. }
  444. },
  445. reduceCount : function(value) {
  446. if(value !== null && value !== undefined && value.beginValue === undefined) {
  447. var hashValue = bobj.getValueHashCode(this.valueDataType, value);
  448. this.values[hashValue] -= 1;
  449. if(this.valueNoDupCB && this.values[hashValue] == 1) {
  450. this.valueNoDupCB(value);
  451. }
  452. }
  453. },
  454. resetValue : function(value) {
  455. if(this.valueNoDupCB) {
  456. this.valueNoDupCB(); // Removes all duplicate values warning when no value is passed to CB
  457. }
  458. for(var k in this.values) {
  459. if(this.values[k] > 0) {
  460. this.values[k] = 0;
  461. }
  462. }
  463. if(bobj.isArray(value)) {
  464. for(var i = 0, len = value.length; i < len; i++) {
  465. this.addCount(value[i]);
  466. }
  467. }
  468. else {
  469. this.addCount(value);
  470. }
  471. }
  472. };