timesheet source code
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

1012 lines
27KB

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