timesheet source code
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

963 lines
26KB

  1. (function ($) {
  2. $(function () {
  3. // http://davidwalsh.name/javascript-debounce-function
  4. function debounce(func, wait, immediate) {
  5. var timeout;
  6. return function () {
  7. var context = this, args = arguments;
  8. var later = function () {
  9. timeout = null;
  10. if (!immediate)
  11. func.apply(context, args);
  12. };
  13. var callNow = immediate && !timeout;
  14. clearTimeout(timeout);
  15. timeout = setTimeout(later, wait);
  16. if (callNow)
  17. func.apply(context, args);
  18. };
  19. };
  20. /*____________________________________________________________________________________*/
  21. class People{
  22. constructor(selector, template, data){
  23. this.selector = selector;
  24. this.data = data;
  25. this.template = template;
  26. // this.sample_people = {
  27. // login: '01515b52-6936-46b2-a000-9ad4cd7a5b50',
  28. // firstname: "first",
  29. // lastname: "last",
  30. // phone: '041122221',
  31. // email: 'abc@gmail.com',
  32. // pay: 0,
  33. // hour: 12,
  34. // OT: 3,
  35. // petrol: 50,
  36. // rating: 1,
  37. // };
  38. this.load_data(this.data);
  39. }
  40. load_data(data){
  41. var template = $(this.template).html();
  42. var html = Mustache.render(template, data);
  43. $(this.selector).html(html);
  44. //save it
  45. $(this.selector).data(data);
  46. //draw rating star
  47. this.set_ratings(this.data.rating);
  48. this.set_unconfirmed_job(this.data.unconfirmedjob);
  49. }
  50. set_ratings(num){
  51. for (var i=1; i<= 5; i++){
  52. if (i <=num){
  53. $(this.selector + " div[name='rating'] span:nth-child(" +i+ ")").addClass('checked');
  54. }else{
  55. $(this.selector + " div[name='rating'] span:nth-child(" +i+ ")").removeClass('checked');
  56. }
  57. }
  58. this.data.rating = num;
  59. }
  60. set_unconfirmed_job(num){
  61. if( num == 0 )
  62. $(this.selector + " span[name='badge']").hide();
  63. else
  64. $(this.selector + " span[name='badge']").show();
  65. this.data.unconfirmedjob = num;
  66. }
  67. }//end of class People
  68. function bts_staff_html(data){
  69. var template = $('#staff_item').html();
  70. var head = '<div class="peopleitem" id="p'+ data.login +'">';
  71. r = head + '</div>' ;
  72. return r;
  73. }
  74. function bts_client_html(data){
  75. var template = $('#client_item').html();
  76. var head = '<div class="peopleitem" id="p'+ data.login +'">';
  77. r = head + '</div>' ;
  78. return r;
  79. }
  80. function sample_staff(){
  81. for (var i=1; i<100; i++){
  82. var sample_people = {
  83. login: '01515b52-6936-46b2-a000-9ad4cd7a5b50' +i,
  84. firstname: "first"+i,
  85. lastname: "last",
  86. mobile: '041122221' +i,
  87. email: 'abc@gmail.com' + i,
  88. wages: 0,
  89. hour: i,
  90. OT: 3,
  91. petrol: 50 +i,
  92. rating: Math.floor(Math.random() * Math.floor(5)),
  93. unconfirmedjob: Math.floor(Math.random() * Math.floor(30)),
  94. };
  95. var html = bts_staff_html(sample_people);
  96. jQuery('div.stafflist').append(html);
  97. new People("#p" + sample_people.login, sample_people);
  98. }
  99. }
  100. function list_staff() {
  101. show_loading_staff();
  102. $('div.stafflist div.peopleitem').remove();
  103. $.post(bts().ajax_url, { // POST request
  104. _ajax_nonce: bts().nonce, // nonce
  105. action: "list_staff", // action
  106. }, function(response, status, xhr){
  107. if (response.status =='success'){
  108. hide_loading_staff();
  109. response.users.forEach(function(u){
  110. var html = bts_staff_html(u);
  111. jQuery('div.stafflist').append(html);
  112. new People("#p" + u.login,'#staff_item', u);
  113. });
  114. }else{
  115. alert('error getting staff list');
  116. }
  117. });
  118. }
  119. function list_clients() {
  120. show_loading_client();
  121. $('div.clientlist div.peopleitem').remove(); //clear it
  122. $.post(bts().ajax_url, { // POST request
  123. _ajax_nonce: bts().nonce, // nonce
  124. action: "list_client", // action
  125. }, function(response, status, xhr){
  126. if (response.status =='success'){
  127. response.users.forEach(function(u){
  128. hide_loading_client();
  129. var html = bts_client_html(u);
  130. jQuery('div.clientlist').append(html);
  131. new People("#p" + u.login, '#client_item' ,u);
  132. });
  133. }else{
  134. alert('error getting Client list');
  135. }
  136. });
  137. }
  138. function show_loading_staff(){
  139. jQuery('div.stafflist img').attr('src', bts().load_user_img).show();
  140. }
  141. function show_loading_client(){
  142. jQuery('div.clientlist img').attr('src', bts().load_user_img).show();
  143. }
  144. function hide_loading_staff(){
  145. jQuery('div.stafflist img').hide();;
  146. }
  147. function hide_loading_client(){
  148. jQuery('div.clientlist img').hide();
  149. }
  150. function xero(t){
  151. if (t)
  152. $('div.xero i').show();
  153. else
  154. $('div.xero i').hide();
  155. }
  156. function wifi(t){
  157. if (t)
  158. $('div.wifi i').show();
  159. else
  160. $('div.wifi i').hide();
  161. }
  162. function init_user_search(){
  163. $('div.b_search input').keyup(debounce(function(e){
  164. filter_user(e.target);
  165. }, 500));
  166. }
  167. function filter_user(input){
  168. var value = $(input).attr('value');
  169. value = value.toLowerCase();
  170. var selector = get_selector_for_filter_people(input);
  171. $.each( $(selector).find('div.peopleitem'), function(index, e){
  172. var html = $(e).find('div[name="title"] a').html();
  173. html = html.toLowerCase();
  174. if (-1 != html.indexOf(value)){//we find it;
  175. $(e).show();
  176. }else{
  177. $(e).hide();
  178. }
  179. });
  180. }
  181. function get_selector_for_filter_people(input){
  182. var selector='';
  183. var role = $(input).attr('placeholder');
  184. if (role == 'staff') //we filter staff
  185. selector = 'div.stafflist';
  186. else if (role = 'client')
  187. selector = 'div.clientlist';
  188. return selector;
  189. }
  190. function init_ts(){
  191. list_staff();
  192. list_clients();
  193. xero(false);
  194. wifi(false);
  195. init_user_search();
  196. ajax_earning_rate();
  197. }
  198. function ajax_earning_rate(){
  199. $.post(bts().ajax_url, { // POST request
  200. _ajax_nonce: bts().nonce, // nonce
  201. action: "earnings_rate", // action
  202. }, function(response, status, xhr){
  203. bts().earnings_rate = response;
  204. console.log("%o", bts().earnings_rate);
  205. });
  206. }
  207. init_ts();
  208. $(document).on('click', 'div.divTableHead.bdelete', function(){
  209. var o = new Job({empty:true});
  210. });
  211. $(document).on('click', 'div.copyprogress', function(){
  212. for (var i=1; i<10; i++){
  213. var o = new Job({empty:true});
  214. }
  215. });
  216. $(document).on('click', 'div.divTableCell.bdelete', function(){
  217. var job = $(this).closest('.divTable').data().job;
  218. var el = $(this).closest('div.divTable');
  219. if ( job.get_job_id() == '')
  220. el.remove();
  221. else{
  222. if (confirm('delete this job?')){
  223. $.post(bts().ajax_url, { // POST request
  224. _ajax_nonce: bts().nonce, // nonce
  225. action: "delete_job", // action
  226. jobid: job.data.id,
  227. }, function(response, status, xhr){
  228. if (response.status=='success'){
  229. el.addClass('blink_me');
  230. el.fadeOut(900);
  231. setTimeout(function(){
  232. el.remove();
  233. }, 900);
  234. }else{
  235. alert( 'error saving data, please check your network');
  236. }
  237. });
  238. }
  239. }
  240. });
  241. $(document).on('mouseenter', 'div.divTableCell', function(){
  242. $(this).closest('div.divTable').addClass('highlight');
  243. });
  244. $(document).on('mouseleave', 'div.divTableCell', function(){
  245. $(this).closest('div.divTable').removeClass('highlight');
  246. });
  247. $(document).on('click', 'span.ticon.ticon-save', function(){
  248. var table = $(this).closest('div.divTable')
  249. table.data().job.do_save_record();
  250. });
  251. class Job{ //save data for the record, and display it as GUI
  252. constructor(data){
  253. var html = jQuery("#job_item").html();
  254. this.el = $(html);
  255. jQuery('div.workspace').append(this.el);
  256. this.load_data(data);
  257. dtp_init();
  258. this.init_start_rating()
  259. }
  260. init_start_rating(){
  261. var self = this;
  262. this.el.find("div.brating span").click(function(){
  263. var r = $(this).attr('data-rating');
  264. self.mark_dirty();
  265. self.set_rating(r);
  266. })
  267. this.el.find("div.brating").mouseenter(function(){
  268. //change to all hollow star
  269. $(this).find('span').html('☆');
  270. });
  271. this.el.find("div.brating").mouseleave(function(){
  272. self.set_rating(self.data.rating);
  273. });
  274. }
  275. load_data(data)
  276. {
  277. this.set_job_id(data.id);
  278. this.set_tos(data.tos);
  279. this.set_start(data.start);
  280. this.set_finish(data.finish);
  281. this.set_rate(data.rate);
  282. this.set_staff(data.staff);
  283. this.set_client(data.client);
  284. this.set_ack(data.ack);
  285. this.set_rating(data.rating);
  286. //save to html element
  287. this.data = data;
  288. this.el.data({job:this, data:data});
  289. if (typeof(data.id) === 'undefined' || data.id == ''){
  290. this.mark_dirty();
  291. this.mark_new();
  292. }
  293. else{
  294. this.mark_saved();
  295. }
  296. }
  297. get_job_id(){
  298. return this.el.find('input[name="id"]').attr('value');
  299. }
  300. set_job_id(val){
  301. return this.el.find('input[name="id"]').attr('value', val);
  302. }
  303. get_tos()
  304. {
  305. return this.el.find('div.btos select').children("option:selected").val();
  306. }
  307. set_tos(val)
  308. {
  309. if (typeof(val) =="undefined")
  310. return;
  311. this.el.find('div.btos select option[value="'+val+'"]').prop('selected',true);
  312. }
  313. get_start(){
  314. return this.el.find('div.bstart input').attr('value');
  315. }
  316. set_start(val)
  317. {
  318. if (typeof(val) =="undefined")
  319. return;
  320. this.el.find('div.bstart input').attr('value', val);
  321. }
  322. get_finish()
  323. {
  324. return this.el.find('div.bfinish input').attr('value');
  325. }
  326. set_finish(val)
  327. {
  328. if (typeof(val) == "undefined")
  329. return;
  330. this.el.find('div.bfinish input').attr('value', val);
  331. }
  332. get_rate()
  333. {
  334. return this.el.find('div.brate select').children("option:selected").val();
  335. }
  336. set_rate(val)
  337. {
  338. if (typeof(val) =="undefined")
  339. return;
  340. this.el.find('div.brate select option[value="'+val+'"]').prop('selected',true);
  341. }
  342. get_staff()
  343. {
  344. return this.el.find('div.bstaff select').children("option:selected").val();
  345. }
  346. set_staff(val)
  347. {
  348. if (typeof(val) =="undefined")
  349. return;
  350. this.el.find('div.bstaff select option[value="'+val+'"]').prop('selected',true);
  351. }
  352. get_client()
  353. {
  354. return this.el.find('div.bclient select').children("option:selected").val();
  355. }
  356. set_client(val)
  357. {
  358. if (typeof(val) =="undefined")
  359. return;
  360. this.el.find('div.bclient select option[value="'+val+'"]').prop('selected',true);
  361. }
  362. get_ack()
  363. {
  364. return this.el.find('div.bconfirmed input:checked').length > 0;
  365. }
  366. set_ack(val)
  367. {
  368. if (typeof(val) =="undefined")
  369. return;
  370. return this.el.find('div.bconfirmed input').prop('checked', val!=0);
  371. }
  372. get_rating(){
  373. var count =0;
  374. this.el.find('div.brating span').each(function(i,e){
  375. if ($(e).html()=='★')
  376. count +=1;
  377. });
  378. return count;
  379. }
  380. set_rating(num){
  381. if (!(1 <= num && num <=5))
  382. return;
  383. this.el.find('div.brating span').each(function(i,e){
  384. var rating = $(e).attr('data-rating');
  385. var rating = parseInt(rating);
  386. if (rating <= num)
  387. $(e).html('★');
  388. else
  389. $(e).html('☆');
  390. });
  391. }
  392. get_record_from_ui(){
  393. var record = {};
  394. record.id = this.get_job_id();
  395. record.tos = this.get_tos();
  396. record.start = this.get_start();
  397. record.finish = this.get_finish();
  398. record.rate = this.get_rate();
  399. record.staff = this.get_staff();
  400. record.client = this.get_client();
  401. record.ack = this.get_ack();
  402. record.rating = this.get_rating();
  403. return record;
  404. }
  405. do_save_record(){
  406. var self = this;
  407. $.post(bts().ajax_url, { // POST request
  408. _ajax_nonce: bts().nonce, // nonce
  409. action: "save_job", // action
  410. record: this.get_record_from_ui(),
  411. }, function(response, status, xhr){
  412. if (response.status=='success'){
  413. self.load_data(response.newdata);
  414. self.mark_saved();
  415. self.mark_old();
  416. }else{
  417. alert( 'error saving data, please check your network');
  418. }
  419. });
  420. }
  421. mark_dirty() //need save
  422. {
  423. var d = this.el.find('.bsave');
  424. d.removeClass('saved');
  425. d.addClass('blink_me');
  426. setTimeout(function(){
  427. d.removeClass('blink_me');
  428. },1000);
  429. }
  430. mark_saved()
  431. {
  432. var d = this.el.find('.bsave');
  433. d.addClass('blink_me');
  434. setTimeout(function(){
  435. d.removeClass('blink_me');
  436. d.addClass('saved');
  437. },1000);
  438. }
  439. //newly created empty record
  440. mark_new()
  441. {
  442. this.el.addClass('emptyrecord');
  443. }
  444. mark_old()
  445. {
  446. this.el.removeClass('emptyrecord');
  447. }
  448. is_start_valid(){
  449. var s = this.get_start();
  450. return is_valid_date_str(s);
  451. }
  452. is_finish_valid(){
  453. var f = this.get_finish();
  454. if (!is_valid_date_str(f))
  455. return false;
  456. }
  457. is_finish_resonable(){
  458. var f = this.get_finish();
  459. if (!is_valid_date_str(f))
  460. return false;
  461. var s = this.get_start();
  462. s = new Date(s);
  463. f = new Date(f);
  464. return (s < f);
  465. }
  466. }//end of class Job
  467. //global GUI summary
  468. function get_wages()
  469. {
  470. var txt = $('div.wages div').html();
  471. return parseInt(txt);
  472. }
  473. function set_wages(num){
  474. $('div.wages div').html(num);
  475. }
  476. function set_working_hours(num){
  477. $('input#woh').attr('value', num);
  478. }
  479. function get_working_hours(){
  480. var txt = $('input#woh').attr('value');
  481. return parseFloat(txt);
  482. }
  483. //modal box
  484. function set_modal_title(selector, title){
  485. var s = 'div.bts_'+ selector +' .ult_modal-title';
  486. $(s).html(title);
  487. }
  488. function set_modal_content(selector, content){
  489. var s = 'div.bts_'+ selector +' div.ult_modal-body.ult-html';
  490. $(s).html(content);
  491. }
  492. function open_modal (selector){
  493. var s='div.bts_'+selector+'_button';
  494. $(s).trigger('click');
  495. }
  496. // setTimeout(function(){
  497. // set_modal_title('warning', 'suck title');
  498. // set_modal_content('warning', 'fucking details');
  499. // //open_modal('warning');
  500. // }, 1000);
  501. //
  502. // setTimeout(function(){
  503. // set_modal_title('error', 'error title');
  504. // set_modal_content('error', 'error details');
  505. // //open_modal('error');
  506. // }, 5000);
  507. $(document).on('mouseenter', 'div.week1 div', function(){
  508. $(this).addClass('blink_me');
  509. get_week2_partner(this).addClass('blink_me');
  510. blink_same_date_by_div(this);
  511. });
  512. $(document).on('mouseleave', 'div.week1 div', function(){
  513. $(this).removeClass('blink_me');
  514. get_week2_partner(this).removeClass('blink_me');
  515. unblink_all_date();
  516. });
  517. function get_week2_partner(div){
  518. var index = $(div).index()+1;
  519. return $('div.week2 div:nth-child('+index+')');
  520. }
  521. function init_weekdays(){
  522. var curr = new Date; // get current date
  523. // First day is the day of the month - the day of the week
  524. var first = curr.getDate() - curr.getDay() + 1; //+1 we want Mon as first
  525. var last = first + 6; // last day is the first day + 6
  526. //var firstday = new Date(curr.setDate(first)); //Mon
  527. //var lastday = new Date(curr.setDate(last)); //Sun
  528. var pos = 1; //first lot
  529. for (var i=first; i<=last; i++)
  530. {
  531. var d1 = new Date(curr.setDate(i));
  532. var d2 = new Date(curr.setDate(i+7));
  533. set_day_number(1,pos, d1); //week 1
  534. set_day_number(2,pos, d2); //week 2
  535. pos +=1;
  536. }
  537. }
  538. function set_day_number(week, index, date){
  539. var selector = 'span[name="w'+week+'d'+index+'"]';
  540. $(selector).html(date.getDate());
  541. $(selector).data({date:date});
  542. }
  543. function set_today(){
  544. var selector = 'div.sheettitle span[name="today"]';
  545. var curr = new Date;
  546. $(selector).html(format_date(curr));
  547. }
  548. Date.prototype.get_week_number = function(){
  549. var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
  550. var dayNum = d.getUTCDay() || 7;
  551. d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  552. var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
  553. return Math.ceil((((d - yearStart) / 86400000) + 1)/7)
  554. };
  555. function set_week_number(){
  556. var date = $('span[name="w1d1"]').data().date;
  557. //console.log("date %o", date);
  558. var num = date.get_week_number();
  559. $('div.weekly span[name="week1"]').html(num);
  560. $('div.weekly span[name="week2"]').html(num+1);
  561. }
  562. function number_of_unsaved_job(){
  563. var count =0;
  564. var total_job = $('div.bsave').length -1;//remove table header
  565. var total_saved = $('div.bsave.saved').length;
  566. var empty = $('div.emptyrecord').length;
  567. count = total_job - total_saved - empty;
  568. return count;
  569. }
  570. $('div.prevweek.left').click(function(){
  571. if (number_of_unsaved_job() > 0){
  572. alert ("you have unsaved jobs,please save it before proceed");
  573. return;
  574. }
  575. $('div.weekdays span.weekday').each(function(i, e){
  576. var date = $(e).data().date;
  577. var newdate = new Date(date.setDate(date.getDate() -7 ));
  578. $(e).html(newdate.getDate());
  579. $(e).data({data:newdate});
  580. });
  581. set_week_number();
  582. load_timesheet();
  583. });
  584. $('div.nextweek.right').click(function(){
  585. if (number_of_unsaved_job() > 0){
  586. alert ("you have unsaved jobs,please save it before proceed");
  587. return;
  588. }
  589. $('div.weekdays span.weekday').each(function(i, e){
  590. var date = $(e).data().date;
  591. var newdate = new Date(date.setDate(date.getDate() +7 ));
  592. $(e).html(newdate.getDate());
  593. $(e).data({data:newdate});
  594. });
  595. set_week_number();
  596. load_timesheet();
  597. });
  598. $('div.weekly div.weekname.prev').click(function(){
  599. if (!confirm ('copy entire week to next week? '))
  600. return;
  601. var jobs = [];
  602. $('div.week1 >div').each(function(i,e){
  603. var date = new Date($(e).find('span.weekday').data().date);
  604. var strDate = format_date(date); //yyyy-mm-dd
  605. $('div.bstart input').each(function(i,e){
  606. var value = $(e).attr('value');
  607. if( -1 != value.indexOf(strDate) ) //found
  608. {
  609. var j = $(e).closest('div.divTable').data().job;
  610. jobs.push(j);
  611. }
  612. });
  613. });
  614. jobs.forEach(function(e){
  615. clone_data_create_new_job(e.data);
  616. });
  617. });
  618. $('div.weekly div.weekname.next').click(function(){
  619. alert('you can only copy from past to future (left to right)');
  620. });
  621. $('div.week1 > div').click(function(){
  622. if ($('div.bstart input.blink_me').length == 0){
  623. alert("nothing to copy");
  624. return;
  625. }
  626. if (!confirm ('copy to next week'))
  627. return;
  628. $('div.bstart input.blink_me').each(function(i,e){
  629. copy_single_day_to_next_week(e);
  630. });
  631. unblink_all_date();
  632. });
  633. function copy_single_day_to_next_week(el){
  634. var j = $(el).closest('div.divTable').data().job;
  635. clone_data_create_new_job(j.data);
  636. }
  637. function clone_data_create_new_job(val){
  638. var data = $.extend(true, {}, val);//make a copy
  639. //reset
  640. data.id='';
  641. data.ack = 0;
  642. data.rating = 0;
  643. if (is_valid_date_str(data.start)){
  644. var s = new Date(data.start);
  645. var s1 = s.getDate() + 7;
  646. s = new Date(s.setDate(s1));
  647. data.start = format_date_time(s);
  648. }
  649. if (is_valid_date_str(data.finish)){
  650. var f = new Date(data.finish);
  651. var f1 = f.getDate() + 7;
  652. f = new Date(f.setDate(f1));
  653. data.finish = format_date_time(f);
  654. }
  655. new Job(data);
  656. }
  657. function is_valid_date_str(val){
  658. var d = new Date(val);
  659. if (d.toString()== 'Invalid Date')
  660. return false;
  661. return true;
  662. }
  663. function blink_same_date_by_div(div){
  664. var date = new Date($(div).find('span.weekday').data().date);
  665. blink_same_date(date);
  666. }
  667. function blink_same_date(date){
  668. var strDate = format_date(date); //yyyy-mm-dd
  669. var els=[];
  670. unblink_all_date();
  671. $('div.bstart input').each(function(i,e){
  672. var value = $(e).attr('value');
  673. if( -1 != value.indexOf(strDate) ) //found
  674. {
  675. els.push(e);
  676. $(e).addClass('blink_me');
  677. }
  678. });
  679. }
  680. function unblink_all_date(){
  681. $('div.bstart input').removeClass('blink_me');
  682. }
  683. $('div.sheettitle h1').click(function(){
  684. reset_title_to_today();
  685. })
  686. function reset_title_to_today(){
  687. set_today();
  688. init_weekdays();
  689. set_week_number();
  690. load_timesheet();
  691. }
  692. function load_timesheet()
  693. {
  694. clear_workspace();
  695. var first = $('span[name="w1d1"]').data().date;
  696. var last = $('span[name="w2d7"]').data().date;
  697. $.post(bts().ajax_url, { // POST request
  698. _ajax_nonce: bts().nonce, // nonce
  699. action: "list_job", // action
  700. start: format_date(first),
  701. finish: format_date(last),
  702. }, function(response, status, xhr){
  703. if (response.status =='success'){
  704. response.jobs.forEach(function(job){
  705. new Job(job);
  706. });
  707. //filter it if reqired
  708. do_filter_workspace();
  709. }else{
  710. alert('error loading job');
  711. }
  712. });
  713. }
  714. function format_date(date){
  715. var dd = date.getDate();
  716. var mm = date.getMonth() + 1; //January is 0!
  717. var yyyy = date.getFullYear();
  718. if (dd < 10) {
  719. dd = '0' + dd;
  720. }
  721. if (mm < 10) {
  722. mm = '0' + mm;
  723. }
  724. return yyyy + '-' + mm + '-' +dd ;
  725. }
  726. function format_date_time(date){
  727. var strdate = format_date(date);
  728. var hh = date.getHours();
  729. if (hh<10){
  730. hh= '0' + hh;
  731. }
  732. var mm = date.getMinutes();
  733. if (mm<10){
  734. mm='0' + mm;
  735. }
  736. return strdate + ' ' + hh + ":" + mm;
  737. }
  738. function clear_workspace()//clear all timesheet jobs
  739. {
  740. $('div.workspace > div.divTable').remove();
  741. //clear datetime picker
  742. $('div.xdsoft_datetimepicker').remove();
  743. }
  744. $('button[name="confirmschedule"]').click(function(){
  745. $('span.ticon.ticon-save').trigger('click');
  746. });
  747. $(document).on('click','div.userlist', debounce(do_filter_workspace));
  748. function do_filter_workspace(){
  749. var staffs =[];
  750. $('div.stafflist div.peopleitem :checked').each(function(i, e){
  751. var id = $(e).parent().attr('data-id');
  752. //console.log("%o, id=%s", e, id);
  753. staffs.push(id.substring(1));
  754. });
  755. var clients =[];
  756. $('div.clientlist div.peopleitem :checked').each(function(i, e){
  757. var id = $(e).parent().attr('data-id');
  758. //console.log("%o, id=%s", e, id);
  759. clients.push(id.substring(1));
  760. });
  761. console.log('staffs %o' , staffs);
  762. console.log('clients %o' , clients);
  763. filter_workspace(staffs, clients);
  764. }
  765. function filter_workspace(staffs, clients){
  766. //if both array is empty
  767. if( (staffs === undefined || staffs.length ==0) &&
  768. (clients===undefined || clients.length ==0)){
  769. //show all
  770. $('div.workspace div.divTable').show();
  771. return;
  772. }
  773. //filter some of them;
  774. $('div.workspace div.divTable').each(function(i,e){
  775. var job = $(e).data().job;
  776. var s = job.get_staff();
  777. var c = job.get_client();
  778. if (staffs.indexOf(s) ==-1 && clients.indexOf(c) ==-1)
  779. $(this).fadeOut();
  780. else
  781. $(this).fadeIn();
  782. });
  783. }
  784. function calculate_total_working_hour()
  785. {
  786. }
  787. function calculate_total_money()
  788. {
  789. }
  790. //visually hint whether start is correct;
  791. $(document).on('change','div.bstart input', function(){
  792. var str = $(this).attr('value');
  793. if ( ! is_valid_date_str(str) )
  794. $(this).css('background-color', 'orange');
  795. else
  796. $(this).css('background-color', 'white');
  797. });
  798. //visually hint whether finish date is correct;
  799. $(document).on('change','div.bfinish input', function(){
  800. var job = $(this).closest('div.divTable').data().job;
  801. var str = $(this).attr('value');
  802. if ( ! is_valid_date_str(str) ){
  803. $(this).css('background-color', 'orange');
  804. return;
  805. }else
  806. $(this).css('background-color', 'white');
  807. //must be later than start
  808. if (! job.is_finish_resonable()){
  809. alert('finish date should be bigger than start date');
  810. $(this).css('background-color', 'orange');
  811. }else{
  812. $(this).css('background-color', 'white');
  813. }
  814. });
  815. $(document).on('change', '.divTableRow select, .divTableRow input', function() {
  816. var job = $(this).closest('.divTable').data().job;
  817. job.mark_dirty();
  818. });
  819. reset_title_to_today();
  820. /*________________________________________________________________________*/
  821. });
  822. })(jQuery);
  823. /*______________scrolling______________________________________________*/
  824. jQuery(document).ready(function(){
  825. var timeoutid =0;
  826. jQuery('button.peoplelist[name="down"]').mousedown(function(){
  827. var button = this;
  828. timeoutid = setInterval(function(){
  829. //console.log("down scrotop %d ", jQuery(button).parent().find(".userlist").get(0).scrollTop );
  830. jQuery(button).parent().find(".userlist").get(0).scrollTop +=240;
  831. }, 100);
  832. }).on('mouseup mouseleave', function(){
  833. clearTimeout(timeoutid);
  834. });
  835. jQuery('button.peoplelist[name="up"]').mousedown(function(){
  836. var button = this;
  837. timeoutid = setInterval(function(){
  838. //console.log("up scrotop %d ", jQuery(button).parent().find(".userlist").get(0).scrollTop );
  839. jQuery(button).parent().find(".userlist").get(0).scrollTop -=240;
  840. }, 100);
  841. }).on('mouseup mouseleave', function(){
  842. clearTimeout(timeoutid);
  843. });
  844. });