Automated SaltStack Master/Minion testrun on Ubuntu Linux
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

842 lines
31 KiB

6 years ago
  1. /*
  2. Simple work hour/payment javascript calculator
  3. Copyright (C) 2018 Pekka Helenius
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. /*
  17. KNOWN BUGS & ISSUES
  18. <begin- bugs & issues list>
  19. // TODO: Print output in reverse order so that the latest message is the first one (maybe this belongs to HTML part?)
  20. // TODO: Duplicate function calls of receiveCurrentDate() in parent functions clearMessages() & writeoutputMessage(). Better implementation needed?
  21. <end - bugs & issues list>
  22. */
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. // 1. BEGIN - CURRENT DATE
  25. //
  26. // Update date field by a new page (refresh page) or user input request
  27. // Used also later in this script code
  28. function receiveCurrentDate(current_dd, current_mm, current_year, dateint) {
  29. current_dd = new Date().getDate();
  30. current_mm = new Date().getMonth() + 1;
  31. current_year = new Date().getFullYear();
  32. if (current_dd < 10) {
  33. current_dd = "0" + current_dd;
  34. }
  35. if (current_mm < 10) {
  36. current_mm = "0" + current_mm;
  37. }
  38. dateint = current_year + current_mm + current_dd;
  39. return [current_dd, current_mm, current_year, dateint];
  40. }
  41. // 1. END - CURRENT DATE
  42. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  43. // 2. BEGIN - CLEAR OUTPUT MESSAGES
  44. //
  45. // Clear generated output messages
  46. // Reset clock and date fields
  47. // HTML output only (doesn't affect console log)
  48. function clearMessages() {
  49. var cur_datefield = receiveCurrentDate();
  50. document.getElementById("job_day").value = cur_datefield[0] + "." + cur_datefield[1] + "." + cur_datefield[2];
  51. document.getElementById("clock_start").value = "00:00";
  52. document.getElementById("clock_end").value = "00:00";
  53. document.getElementById("output").innerHTML = "";
  54. }
  55. // 2. END - CLEAR OUTPUT MESSAGES
  56. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. // 3. BEGIN - JOB TITLE
  58. //
  59. // Retrieve a job title from HTML document
  60. // Convert job title to upper case by calling function convertToUpperCase()
  61. // This function is called by onblur Event in attached HTML document
  62. // Equals to kasitteleTehtava() function described in the instruction
  63. function processJobTitle(jobtitle) {
  64. jobtitle = document.getElementById("job_title").value;
  65. // Leading and trailing non-alphabetical/numerical characters.
  66. // Better implementation? (\W and \w doesn't apply to scandinavian character set)
  67. var match = /^[^A-Za-z0-9_åÅäÄöÖ]+|[^A-Za-z0-9_åÅäÄöÖ]+$/g;
  68. // If incorrect characters used, clear the field
  69. if (jobtitle.match(match)) {
  70. jobtitle = jobtitle.replace(match, "");
  71. }
  72. // Declare new variable 'jobtitle_uppercase'.
  73. // Use value of 'jobtitle' as an input parameter for convertToUpperCase() function
  74. // Call convertToUpperCase() function
  75. var jobtitle_uppercase = convertToUpperCase(jobtitle);
  76. // Replace old job title value with a a converted one in HTML document
  77. document.getElementById("job_title").value = jobtitle_uppercase;
  78. return jobtitle_uppercase; // Return uppercase title
  79. }
  80. // 3. END - JOB TITLE
  81. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. // 4. BEGIN - JOB TITLE TO UPPERCASE
  83. //
  84. // Equals to kaikkiSuurella(merkkijono) function described in the instruction
  85. // Is not created as a child function to processJobTitle() because it may not be as described in the instruction
  86. function convertToUpperCase(jobstring) {
  87. // Convert received string to uppercase with toUpperCase() method
  88. // Remove leading and trailing whitespaces with trim() method
  89. jobstring = jobstring.toUpperCase().trim();
  90. return jobstring; // Returns jobstring
  91. }
  92. // 4. END - JOB TITLE TO UPPERCASE
  93. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  94. // 5. BEGIN - WRITE OUTPUT MESSAGE
  95. //
  96. // This function is triggered by user
  97. // This function handles input & output messages processing
  98. // Contains many child functions (tree structure)
  99. // Triggered by "Save" button in attached HTML file
  100. function writeoutputMessage() {
  101. ////////////////////////////////////////////////////////
  102. // 5.1. VARIOUS MESSAGE PARTS
  103. var cur_datefield = receiveCurrentDate(); // Yes, we declare it here and in clearMessages() function TODO
  104. var errorindex = new Array(14).fill(0); // New array size of 14 for error messages
  105. var worktime = workingTime(); // Work time function
  106. var getday = whichDay(); // Day parser function
  107. var outputparts = outputMsgParts(); // Combine output messages generated by child functions
  108. // 1. Retrieve variables
  109. outputparts; // Must be called before generateOutput() function to get variable values
  110. // 2. Generate output using checked variables
  111. generateOutput();
  112. ////////////////////////////////////////////////////////
  113. // 5.2. BEGIN - HTML OUTPUT MESSAGE
  114. //
  115. // This function generates HTML output message
  116. function generateOutput() {
  117. var outputmsg;
  118. var error_output = ""; // error output must be empty at this stage
  119. ////////////////////////////
  120. // 5.2.1. ERROR CHECK
  121. //
  122. // This part processes all console error messages
  123. // Get all index values of errorindex array and write them as an single output error string
  124. // Check for each errorindex array value
  125. for (var i = 0; i < errorindex.length; i++) {
  126. // Convert current errorindex value to string value for .match() method
  127. errorindex[i] = "" + errorindex[i];
  128. // If an errorindex value does not match 0
  129. // All errorindex values are 0 if there were no any error matches
  130. // If we check just value 0, any string containing 0 may pass this check
  131. //
  132. if (errorindex[i].match(/^[a-zA-Z]+/)) {
  133. // Write syntax: <all previous error strings> + <current erroneous string> + <newline>...
  134. error_output = error_output + errorindex[i] + "\n"
  135. }
  136. }
  137. ////////////////////////////
  138. // 5.2.2. VALID OUTPUT
  139. //
  140. // This is the output if no errors were found
  141. // Output if no errors
  142. if (error_output == "") {
  143. // Output message:
  144. // 1st line: Job title in uppercase, start-time - end-time, date (work day as a string)
  145. // 2nd line: Total working hours
  146. // 3rd line: Payment per hour
  147. // 4th line: Total payment of the work
  148. // 5th line: Job description (details)
  149. // 6th line: Separator
  150. //
  151. outputmsg = "<p>" + outputparts[0] + "<br><br>\n"
  152. + "Total work hours " + getday[3] + " " + worktime[3] + ".\n"
  153. + "<br>Work price per hour is " + outputparts[1] + " € on " + getday[0] + ".\n"
  154. + "<br>Work total price is " + outputparts[2] + " €.\n"
  155. + "<br><br>Description:<br>" + outputparts[3] + "\n"
  156. + "<br>----------------------------</p>";
  157. ////////////////////////////
  158. // 5.2.2. INVALID OUTPUT
  159. //
  160. // This is the output if errors were found
  161. // Output if errors
  162. } else {
  163. // Error output
  164. // Replace all new line symbols with <br> tags (globally in this scope)
  165. outputmsg = "<p>ERROR:<br>" + error_output.replace(/\n/g,"<br>") + "<br>----------------------------</p>"
  166. }
  167. // Get the previous value + add new value
  168. document.getElementById("output").innerHTML += outputmsg;
  169. // Throw all found error messages into console if error_output is not ""
  170. if (error_output != "") {
  171. throw new Error("\n" + error_output); // Stop javascript code execution here
  172. }
  173. }
  174. //-------------
  175. // ERROR MESSAGE STRINGS
  176. //
  177. // Error message definitions are as follows:
  178. /*
  179. errorindex[0] = Length of date string is incorrect
  180. errorindex[1] = Input date string is in incorrect format
  181. errorindex[2] = Accepted day value range is 1-31. User input value is 'input_dd'
  182. errorindex[3] = Accepted month value range is 1-12. User input value is 'input_mm'
  183. errorindex[4] = Input date value can't exceed the current day
  184. errorindex[5] = Input date is too far away in the past. Minimum limit is 'minimumdate'
  185. errorindex[6] = Length of clock start time input is incorrect
  186. errorindex[7] = Length of clock end time input is incorrect
  187. errorindex[8] = Hour value of start clock input string is not in range 0-23
  188. errorindex[9] = Hour value of end clock input string is not in range 0-23
  189. errorindex[10] = Minute value of start clock input string is not in range 0-59 (value is 'clock_min')
  190. errorindex[11] = Minute value of end clock input string is not in range 0-59 (value is 'clock_min')
  191. errorindex[12] = Erroneous start clock input value (value is 'clock')
  192. errorindex[13] = Erroneous end clock input value (value is 'clock')
  193. errorindex[14] = Starting time is greater than or equal to ending time
  194. */
  195. // 5.2. END - HTML OUTPUT MESSAGE
  196. ////////////////////////////////////////////////////////
  197. // 5.3. BEGIN - OUTPUT MESSAGE PARTS
  198. //
  199. // Variables defined in this part retrieve their values from child functions
  200. function outputMsgParts() {
  201. //-------------
  202. // 5.3.1. JOB TITLE
  203. // Generate uppercase job title with clock + day times in brackets
  204. var job = processJobTitle() + "<br>clock " + worktime[0] + " - " + worktime[1] + ", " + getday[2] + " (" + getday[0] + ")";
  205. //-------------
  206. // 5.3.2. PAYMENT-BY-DAY
  207. // Get payment-by-day value (72 or 48 euros)
  208. var payment_by_day = getday[1].toFixed(2).replace(".",",");
  209. //-------------
  210. // 5.3.3. TOTAL PAYMENT
  211. // Calculate total payment
  212. var totalpayment = (worktime[2] * getday[1]).toFixed(2).replace(".",",");
  213. //-------------
  214. // 5.3.4. JOB DESCRIPTION
  215. // Parse line breaks for output as described here:
  216. // https://stackoverflow.com/questions/863779/javascript-how-to-add-line-breaks-to-an-html-textarea
  217. //
  218. var description = document.getElementById("description").value.replace(/\r?\n/g, '<br />');
  219. // If "Kuvaus" text area is empty write the following string as output
  220. if (description == "") {
  221. description = "No description";
  222. }
  223. //-------------
  224. // Return of outputMsgParts() function
  225. return [job, payment_by_day, totalpayment, description];
  226. }
  227. // 5.3. END - OUTPUT MESSAGE PARTS
  228. ////////////////////////////////////////////////////////
  229. // 5.4. BEGIN - DAY STRING
  230. //
  231. function whichDay() {
  232. // Set new variable for parseDayString() function
  233. var parseday = parseDayString();
  234. ///////////////////////////////
  235. // 5.4.1. WORK DAY DEFINITION
  236. //
  237. // Retrieve needed values from parseday variable (function parseDayString())
  238. // Define work day as a human-readable string
  239. // Define work day as an index value
  240. // Returns day-based index value
  241. var datevalue = new Date(parseday[0]).getDay();
  242. // Define day-based index value strings
  243. var weekday = new Array(7);
  244. weekday[0] = "Sunday";
  245. weekday[1] = "Monday";
  246. weekday[2] = "Tuesday";
  247. weekday[3] = "Wednesday";
  248. weekday[4] = "Thursday";
  249. weekday[5] = "Friday";
  250. weekday[6] = "Saturday";
  251. // Workday human-readable string
  252. var workday = weekday[datevalue];
  253. ///////////////////////////////
  254. // 5.4.2. PAYMENT MULTIPLIER
  255. //
  256. // Define payment-per-hour multiplier according to parsed day index value
  257. var payment;
  258. // If is sunday
  259. if (datevalue == 0) {
  260. payment = 72; // Set payment multiplier
  261. // else it's not sunday
  262. } else {
  263. payment = 48; // Set payment multiplier
  264. }
  265. ///////////////////////////////
  266. // 5.4.3. BEGIN - PARSE DAY STRING
  267. //
  268. // Child function for whichDay() parent function
  269. //
  270. // Does as follows:
  271. //
  272. // A) Check input day string formatting
  273. // B) Prevent future days and limit minimum values
  274. // C) Handle erroneous situations
  275. //
  276. // D 1) Return checked day, month and year values (yyyy,mm,dd)
  277. // D 2) Return user Input Date string
  278. // D 3) Return string which defines is it today (on tänään) or was in the past (oli)
  279. function parseDayString() {
  280. var be_str;
  281. // User input from HTML document
  282. var inputdaystr = document.getElementById("job_day").value;
  283. // Consider this as a string for further .substr() method
  284. var minimumdate = "19000101"; // Min. threshold. Day 01.01.1900
  285. ///////////////
  286. // 5.4.3.1. CURRENT DATE VALUE
  287. //
  288. // Set maximum accepted date value from current day
  289. var currentday_int = cur_datefield[3];
  290. ///////////////
  291. // 5.4.3.2. SPLIT INPUT DATE
  292. //
  293. // Length & initial format check for input date value
  294. // Date string must be 8-10 chars long
  295. if (inputdaystr.length >= 8 || inputdaystr.length <= 10) {
  296. // Do format checking later, just get the array values now.
  297. // Create a new array, size of 3, fill with zeros
  298. var split_date = new Array(3).fill(0);
  299. // Split date string into another new array. Matching pattern is , . ; or :
  300. // First three values
  301. var daysplitter = inputdaystr.split(/[,.;:]/, 3);
  302. // Fill split_date array with the values of splitter array
  303. for (var i = 0; i < daysplitter.length; i++) {
  304. split_date[i] = daysplitter[i];
  305. }
  306. /* The logic and reason for above event "Create two arrays, fill the other with the values
  307. * of the second one" is that if we create just a new array with split() method and user
  308. * input consist of 2 values, the size of this new array would be 2. As we continue
  309. * executing this javascript code, the code assumes that all 3 array indexes have been
  310. * defined for split_date but that's not always the case (user error). Creating a new zero-filled
  311. * array is kind of "safe buffer" here, which we rely our code on. It is safer add day values
  312. * with split() method to this already existing array. Otherwise we may end up to situations
  313. * where no all expected split_date array indexes have not been defined and the code may misbehave.
  314. About empty values:
  315. Null (empty) array value is not considered as an empty string but actually as 0 value in javascript comparisons by default.
  316. For example, without any input value (split_date[1] is NULL) the null value is treated like this:
  317. split_date[1] == ""; // Returns false -> null is not an empty string
  318. split_date[1] == 0; // Returns true -> null is number 0
  319. We replace empty array value (null) with an empty string in the following loop. (read: replace method works only for 'null' pattern)
  320. */
  321. // Parse all 'split_date' array indexes
  322. for (var j = 0; j < split_date.length; j++) {
  323. // Returns NaN if contains any letters or symbols
  324. parseInt(split_date[j]);
  325. // Check for null, undefined, NaN etc values as explained here:
  326. // https://stackoverflow.com/questions/6003884/how-do-i-check-for-null-values-in-javascript
  327. //
  328. if (!split_date[j]) {
  329. // Based on the previous statement, replace all null values with empty strings
  330. split_date[j] = split_date[j].replace(null,"");
  331. }
  332. }
  333. // We may want to add "0" in cases the user input is in range 1-10.
  334. // Day value
  335. var input_dd;
  336. if (split_date[0] < 10 && split_date[0] > 0 && split_date[0].length != 2) {
  337. input_dd = "0" + split_date[0];
  338. } else {
  339. input_dd = split_date[0];
  340. }
  341. // Month value
  342. var input_mm;
  343. if (split_date[1] < 10 && split_date[1] > 0 && split_date[1].length != 2) {
  344. input_mm = "0" + split_date[1];
  345. } else {
  346. input_mm = split_date[1];
  347. }
  348. // Year value
  349. var input_year;
  350. // If user input is between 10-99, add prefix 20 so that output follows pattern 2012, 2035 etc.
  351. //
  352. if (split_date[2].length == 2 && split_date[2] >= 10 && split_date[2] <= 99) {
  353. input_year = "20" + split_date[2];
  354. // Years between 2000-2009
  355. } else if (split_date[2].length == 1 && split_date[2] < 10) {
  356. input_year = "200" + split_date[2];
  357. } else {
  358. input_year = split_date[2];
  359. }
  360. // If length of date input string is not 8-10
  361. } else {
  362. errorindex[0] = "Length of the input date value is invalid";
  363. }
  364. ///////////////
  365. // 5.4.3.2. CHECK INPUT DATE
  366. //
  367. // Check that input day, month and year values numbers
  368. // Check that characters 2 and 5 are . / : ;
  369. switch(true) {
  370. // date string does not consist of 3 different array values (dd.mm.yyyy)
  371. case split_date.length != 3:
  372. //Day:
  373. case input_dd.length != 2: // size of the first part of the date string (day) is not 2 (dd)
  374. case (input_dd.match(/^[0-9]+$/) == null): // it doesn't consist only on chars 0-9
  375. //Month:
  376. case input_mm.length != 2: // size of the second part of the date string (month) is not 2 (mm)
  377. case (input_mm.match(/^[0-9]+$/) == null): // it doesn't consist only on chars 0-9
  378. //Year:
  379. case input_year.length != 4: //size of the third part of the date string (year) is not 4 (yyyy)
  380. case (input_year.match(/^[0-9]+$/) == null): // it doesn't consist only on chars 0-9
  381. errorindex[1] = "Input date string (" + inputdaystr + ") is not in valid format (dd.mm.yyyy)";
  382. break;
  383. default: // None of the cases above match
  384. // Rearrange splitted date string
  385. // This is considered as a typeof "string" by default so these values are just stacked together
  386. // Example return value: 20150812 (yyyymmdd)
  387. //
  388. var inputday_int = input_year + input_mm + input_dd;
  389. //Is this current day or a day in the past?
  390. if (inputday_int == currentday_int) {
  391. be_str = "is today";
  392. } else {
  393. be_str = "was";
  394. }
  395. //----------------------
  396. // 5.4.3.2.1. CHECK RANGE OF INPUT DATE VALUES
  397. //
  398. // Check range of day, month and year values
  399. // For cases 3 and 4, the date value syntax is yyyymmdd (year-month-day)
  400. // Comparison example: 20171609 < 19000101
  401. // CASE 1
  402. // Input day value range is not in range 1-31
  403. if (input_dd < 1 || input_dd > 31) {
  404. errorindex[2] = "Accepted day value range is 1-31. Your input value is " + input_dd;
  405. }
  406. // CASE 2
  407. // Input month value range is not in range 1-12
  408. if (input_mm < 1 || input_mm > 12) {
  409. errorindex[3] = "Accepted month value range is 1-12. Your input value is " + input_mm;
  410. }
  411. // CASE 3
  412. // Input date is more than the current date
  413. // Check for erroneous day and month values (only "no errors" situation accepted)
  414. if (currentday_int < inputday_int && errorindex[2] == 0 && errorindex[3] == 0) {
  415. errorindex[4] = "Input date value can't exceed the current day";
  416. }
  417. // CASE 4
  418. // Input date value is less than the minimum date
  419. // Convert minimumdate to integer
  420. // Check for erroneous day and month values (only "no errors" situation accepted)
  421. if (inputday_int < Number(minimumdate) && errorindex[2] == 0 && errorindex[3] == 0) {
  422. // Here minimumdate is considered as a string again
  423. errorindex[5] = "Input date is too far away in the past. Minimum limit is " + minimumdate.substr(6, 2) + "." + minimumdate.substr(4, 2) + "." + minimumdate.substr(0, 4) + ".";
  424. }
  425. }
  426. ///////////////////////////////
  427. // Return for parseDayString() child function. Return date string in dd.mm.yyyy format
  428. return [(input_year + "," + input_mm + "," + input_dd),input_dd + "." + input_mm + "." + input_year,be_str];
  429. }
  430. // 5.4.3. END - PARSE DAY STRING
  431. //////////////////////////////
  432. // Return for whichDay() function
  433. return [workday,payment,parseday[1],parseday[2]];
  434. }
  435. // 5.4. END - DAY STRING
  436. ////////////////////////////////////////////////////////
  437. // 5.5. BEGIN - WORKING TIME
  438. //
  439. // Clock times (start & end)
  440. // Syntax is hh:mm (hours:minutes)
  441. function workingTime() {
  442. //////////////////////////////
  443. // 5.5.1. VARIABLES
  444. //
  445. // Define global variables inside workingTime() function
  446. // These variables can be called by any child function in workingTime() function's scope
  447. // These variables can't be called from outside workingTime() parent function
  448. var clock;
  449. // User input values for start & end times
  450. var begin = document.getElementById("clock_start").value;
  451. var end = document.getElementById("clock_end").value;
  452. //////////////////////////////
  453. // 5.5.2. PARSE CLOCK STRING LENGTHS
  454. //
  455. // Make sure lengths of clock start & end times are correct
  456. // If input length is 4 AND
  457. // If the first character is a number AND
  458. // If the second char is ": . , or ;" THEN
  459. // add 0 prefix.
  460. //
  461. // This is usually a case if user puts a clock value like 8:43 etc.
  462. //
  463. if (begin.length == 4 && begin.charAt(0).match(/[0-9]/) && begin.charAt(1).match(/[:.,;]/)) {
  464. begin = "0" + begin; // typeof is "String"
  465. }
  466. if (end.length == 4 && end.charAt(0).match(/[0-9]/) && end.charAt(1).match(/[:.,;]/)) {
  467. end = "0" + end; // typeof is "String"
  468. }
  469. // If user types in just one number (or two), we assume these numbers mean "hours"
  470. //
  471. if (begin.length == 1 && begin.charAt(0).match(/[0-9]/)) {
  472. begin = "0" + begin + ":00"; // typeof is "String"
  473. } else if (begin.length == 2 && begin.substr(0, 2).match(/[0-9]/)) {
  474. begin = begin + ":00"; // typeof is "String"
  475. }
  476. if (end.length == 1 && end.charAt(0).match(/[0-9]/)) {
  477. end = "0" + end + ":00"; // typeof is "String"
  478. } else if (end.length == 2 && end.substr(0, 2).match(/[0-9]/)) {
  479. end = end + ":00"; // typeof is "String"
  480. }
  481. //////////////////////////////
  482. // 5.5.3. SET START & END TIMES
  483. //
  484. // Define correct clock values for start & end times
  485. // Return hour and minute values for both times
  486. //----------------------
  487. // 5.5.3.1.
  488. // Parse start time
  489. clock = begin; // Set clock variable as 'begin'
  490. var begintime = checkTimes(); // Define begintime variable
  491. // Output as follows:
  492. // begintime[0] = begin hour
  493. // begintime[1] = begin minutes
  494. // begintime[2] = begin time error flag
  495. //----------------------
  496. // 5.5.3.2.
  497. // Parse end time
  498. clock = end; // Set clock variable as 'end'
  499. var endtime = checkTimes(); // Define endtime variable
  500. // Output as follows:
  501. // endtime[0] = end hour
  502. // endtime[1] = end minutes
  503. // endtime[2] = end time error flag
  504. //////////////////////////////
  505. // 5.5.4. BEGIN - START & END CLOCK TIMES FORMATTING
  506. //
  507. // Parse both start & end time values
  508. function checkTimes() {
  509. var clockerror = false; // Default value each time the function is called
  510. // INITIAL LENGTH CHECK
  511. // Clock input values must be 5 characters long before parsing them
  512. if (clock.length != 5) {
  513. if (clock == begin) {
  514. clockerror = true;
  515. errorindex[6] = "Length of the clock start time value is invalid";
  516. }
  517. if (clock == end) {
  518. clockerror = true;
  519. errorindex[7] = "Length of the clock end time value is invalid";
  520. }
  521. }
  522. // Split checked clock input value hh:mm into two parts
  523. //
  524. var clock_hour = clock.substr(0, 2); // Start from index value 0, length is 2
  525. var clock_min = clock.substr(3, 2); // Start from index value 3, length is 2
  526. var clock_separator = clock.charAt(2); // Separator character between hh:mm
  527. // FIRST CHECK
  528. // If both of splitted values contain only numbers and the symbol between them is :
  529. //
  530. if (!isNaN(clock_hour) && !isNaN(clock_min) && clock_separator.match(/[:,.;]/) ) {
  531. // SECOND CHECK PART 1 - HOURS
  532. // If the first part of clock input value is outside of range 0 and 23
  533. //
  534. if (Number(clock_hour) < 0 || Number(clock_hour) > 23) {
  535. // Distinguish error messages
  536. //
  537. // If we use same index value for both begin & end clock times and both of them are incorrect,
  538. // only the latter error would be shown in console log. This is because the previous string (error in begin value) has been overwritten by the latter one (error in end value)
  539. //
  540. if (clock == begin) {
  541. clockerror = true;
  542. errorindex[8] = "Hour value of the start clock input string is not in range 0-23 (value is " + clock_hour + ")";
  543. }
  544. if (clock = end) {
  545. clockerror = true;
  546. errorindex[9] = "Hour value of the end clock input string is not in range 0-23 (value is " + clock_hour + ")";
  547. }
  548. }
  549. // SECOND CHECK PART 2 - MINUTES
  550. // If the second part of clock input value is outside of range 0 and 59
  551. //
  552. if (Number(clock_min) < 0 || Number(clock_min) > 59) {
  553. // Distinguish error messages
  554. //
  555. // If we use same index value for both begin & end clock times and both of them are incorrect,
  556. // only the latter error would be shown in console log. This is because the previous string (error in begin value) has been overwritten by the latter one (error in end value)
  557. //
  558. if (clock == begin) {
  559. clockerror = true;
  560. errorindex[10] = "Minute value of the start clock input string is not in range 0-59 (value is " + clock_min + ")";
  561. }
  562. if (clock == end) {
  563. clockerror = true;
  564. errorindex[11] = "Minute value of the end clock input string is not in range 0-59 (value is " + clock_min + ")";
  565. }
  566. }
  567. // ELSE CONDITION FOR FIRST CHECK
  568. // If there is an general error in formatting of start or end clock string
  569. //
  570. } else {
  571. // Distinguish error messages
  572. //
  573. // If we use same index value for both begin & end clock times and both of them are incorrect,
  574. // only the latter error would be shown in console log. This is because the previous string (error in begin value) has been overwritten by the latter one (error in end value)
  575. //
  576. if (clock == begin) {
  577. clockerror = true;
  578. errorindex[12] = "Erroneous start clock value (value is " + clock + ")";
  579. }
  580. if (clock == end) {
  581. clockerror = true;
  582. errorindex[13] = "Erroneous end clock value (value is " + clock + ")";
  583. }
  584. }
  585. //----------------------
  586. // These are return values generated by child function checkTimes()
  587. return [Number(clock_hour), Number(clock_min), clockerror];
  588. }
  589. // 5.5.4. END - START & END CLOCK TIMES FORMATTING
  590. //////////////////////////////
  591. // 5.5.5. CALCULATE WORKING TIME
  592. //
  593. // Calculate working time from checked and parsed user input
  594. // If both start and end clock times are valid (don't return error)
  595. if (begintime[2] == false && endtime[2] == false) {
  596. var begin_min_total = (begintime[0] * 60) + begintime[1];
  597. var end_min_total = (endtime[0] * 60) + endtime[1];
  598. var totaltime = end_min_total - begin_min_total; // In minutes
  599. var totaltime_in_hours = (totaltime / 60).toFixed(2); // Force two decimals in any case for totaltime_hoursonly variable
  600. var totaltime_hoursonly = totaltime_in_hours.substr(0, totaltime_in_hours.indexOf("."));
  601. // Print this error message only if start clock time is greater than or equal to ending clock time
  602. //
  603. if (begin_min_total >= end_min_total) {
  604. errorindex[14] = "Starting time can't be greater than or equal to the ending time";
  605. }
  606. //////////////////////////////
  607. // 5.5.6. PARSE WORKING TIME TEXT STRING
  608. var totaltime_str;
  609. // If working time exceeds 60 minutes (hour), then we redefine how the total time should be displayed in HTML output.
  610. //
  611. if (totaltime >= 60 && (totaltime % 60 !== 0)) {
  612. totaltime_str = totaltime_hoursonly + " hours and " + ((totaltime_in_hours - totaltime_hoursonly) * 60).toFixed(0) + " minutes";
  613. } else if (totaltime < 60) {
  614. totaltime_str = totaltime + " minutes";
  615. } else if (totaltime == 60) {
  616. totaltime_str = totaltime_hoursonly + " hour";
  617. } else {
  618. totaltime_str = totaltime_hoursonly + " hours";
  619. }
  620. }
  621. //////////////////////////////
  622. // Return values of workingTime() function
  623. return [begin,end,totaltime_in_hours,totaltime_str];
  624. }
  625. // 5.5. END - WORKING TIME
  626. ////////////////////////////////////////////////////////
  627. }
  628. // 5. END - WRITE OUTPUT MESSAGE
  629. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////