{"version":3,"file":"app-2500ebb2.47e839c4edc29ae0ca22.bundle.js","mappings":";;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AClHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;ACHA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;ACHA;AACA;AAGA;AACA;AAAA;AAAA;AAKA;AACA;AACA;AAEA;AACA;AACA;AARA;AAAA;;AAAA;AAJA;AADA;AAEA;AADA;AAaA;AAAA;AAbA;;;;;;;;;;;;;;;;;;;;;;;;;;ACJA;AAEA;AAGA;AACA;AAMA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAGA;AACA;AAGA;AAtBA;AACA;AACA;AACA;AAuBA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;;;AALA;AAQA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AA9CA;AAAA;;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAcA;AAAA;AAKA;AAAA;AAFA;AAvCA;AADA;;AACA;AA8DA;AAAA;AA9DA;AAgEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAKA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1FA;AACA;AAGA;AAGA;AACA;AAAA;AAAA;AAAA;AAMA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAQA;AAeA;AA4MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AA5QA;AACA;AACA;AACA;AAqBA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;;AACA;AAEA;AAEA;AAYA;AACA;AACA;AAIA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAGA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AALA;AASA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAuBA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;;;AAAA;AAEA;AACA;AAAA;AACA;AACA;AArSA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AADA;AACA;AAAA;AACA;AAAA;;AAAA;AAEA;AADA;;AACA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AADA;;AACA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AA6QA;AAAA;;;AAIA;AAzSA;AADA;AAEA;AADA;AA+SA;AAAA;AA/SA;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AAMA;AAAA;AAEA;AADA;AAAA;;AAAA;AADA;AAHA;AACA;AACA;AACA;AAEA;AAAA;AAFA;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AAKA;AAAA;AACA;AACA;AASA;AALA;AACA;AACA;AACA;AACA;AATA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAJA;AAHA;AACA;AACA;AACA;AAWA;AAAA;AAXA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAIA;AAAA;AACA;AACA;AADA;AASA;AAEA;AACA;AAIA;AAGA;AAOA;;AAxBA;AA8BA;AACA;AACA;AACA;AACA;AAEA;;;;;AACA;;AAAA;AACA;AACA;;;;AAEA;;AAAA;AACA;;;;AAEA;;;AAEA;AACA;;;;AAIA;AACA;AACA;;;;;;AAEA;AAEA;;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAGA;;;;;AACA;AACA;AACA;AACA;AACA;;AAAA;AACA;;;;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAvHA;AADA;AACA;AAAA;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAkBA;AAFA;AACA;AACA;;AAAA;AA/BA;AAFA;AACA;AAEA;AADA;AA8HA;AAAA;AA9HA;AAgIA;AAAA;AAEA;AAmBA;AAoCA;AAlCA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAtDA;AADA;;AACA;AAGA;AADA;;AACA;AAGA;AADA;;AACA;AAGA;AADA;;AACA;AAGA;AADA;;AACA;AAIA;AAFA;AACA;;AACA;AAGA;AADA;;AACA;AAoCA;AAAA;AAzDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7IA;AACA;AAIA;AAAA;AAAA;;AACA;;AACA;AADA;AAAA;;AAAA;AADA;AAFA;AACA;AACA;AAEA;AAAA;AAFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AADA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAxBA;AA2BA;AAAA;AACA;AACA;;AAAA;;AAAA;;;AAAA;AACA;;AAAA;;AAAA;;;AAAA;AACA;;AAAA;;AAAA;;;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA/CA;AAFA;AACA;AACA;AAAA;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AApBA;AAFA;AACA;AAEA;AADA;AAuDA;AAAA;AAvDA;AAyDA;AACA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgCA;AAqCA;AAGA;AArFA;AACA;AAcA;AAAA;AAGA;AACA;;;AAAA;AAoEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;;;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;;;AAAA;AAEA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;AAAA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlKA;AAAA;AACA;;;AAGA;AAGA;AADA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAGA;AADA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAIA;AAFA;AACA;;AACA;AAKA;AAHA;AACA;AACA;AACA;AAAA;AAGA;AADA;;AACA;AAEA;AAAA;AACA;;;AAOA;AAEA;AAAA;AACA;;;AAOA;AAEA;AAAA;AACA;;;AAWA;AA2DA;AAAA;AApLA;AAsLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjRA;AACA;AAEA;AACA;AAIA;AAAA;AAAA;;AACA;AAEA;;AAcA;AAZA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAfA;AAAA;;AAAA;AADA;AAFA;AACA;AACA;AAiBA;AAAA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AACA;AAIA;AAAA;AAAA;;AACA;AAKA;AAEA;AACA;AACA;;AAuEA;AArEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AA/EA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AANA;AAFA;AACA;AACA;AAiFA;AAAA;AAjFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAEA;AAOA;AANA;AACA;AACA;AACA;AACA;AACA;AAOA;AAGA;AACA;AAEA;AAEA;AACA;;AAdA;AAgBA;AAAA;AACA;AAGA;AACA;AACA;AAEA;;;;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;AACA;AAEA;;AA+CA;AAAA;AAEA;;AACA;AACA;AACA;AACA;AACA;AACA;;;AACA;AACA;;;;;AAxDA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;;AAAA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAcA;;AAAA;;;;;AACA;AAEA;;;;;;;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;;AACA;AACA;AACA;AACA;AACA;;AACA;AACA;;AACA;AACA;AACA;AACA;AAEA;;AACA;AACA;;AACA;;AACA;AACA;AACA;;AAxBA;AA0BA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;AAGA;;;;;AAEA;AAEA;AACA;AACA;AAEA;;;;;AACA;AACA;AACA;AACA;;AAAA;;;;;AACA;AAEA;AAAA;;AAAA;;;;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAAA;;;;;AACA;AAEA;;;AACA;AAEA;AACA;AACA;;;;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;;;AAAA;AAEA;AAAA;AAAA;AAEA;AACA;;;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AArPA;AAAA;;AAAA;AASA;AAAA;;AAAA;AAsNA;AAAA;;;AAGA;AAEA;AAAA;;;AAGA;AAnPA;AAFA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AARA;AAkQA;AAAA;AAlQA;AAoQA;AAAA;AAMA;AALA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxRA;AACA;AACA;AAIA;AAAA;AAUA;AAEA;AADA;AATA;AACA;AACA;AAIA;;AAKA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;;AAZA;AAAA;AAaA;AACA;AAEA;AACA;AACA;AACA;AACA;AA3CA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAAA;AAJA;AAFA;AACA;AAYA;AAXA;AA6CA;AAAA;AA7CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AAIA;AAAA;AAAA;;AAEA;AACA;AACA;;AAaA;AATA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AAfA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAAA;AAJA;AAFA;AACA;AACA;AAiBA;AAAA;AAjBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AACA;AAIA;AAAA;AAAA;;AACA;;AACA;AADA;AAAA;;AAAA;AADA;AAFA;AACA;AACA;AAEA;AAAA;AAFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAAA;;AACA;AACA;AAEA;AAEA;;AAcA;AAZA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAlBA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AAJA;AAFA;AACA;AACA;AAoBA;AAAA;AApBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AAIA;AAAA;AAAA;;AACA;AACA;AACA;AACA;AACA;AACA;;AAoCA;AAlCA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;;;AAAA;AAxCA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAgCA;AAAA;;;AAGA;AAzCA;AAFA;AACA;AACA;AA0CA;AAAA;AA1CA;;;;;;;;;;;;;;;;ACNA;AACA;AAOA;AAmBA;AAFA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAEA;AAGA;AAEA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAEA;AACA;AAGA;AACA;AAKA;AACA;AACA;AACA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;ACpMA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAWA;AAgBA;AAVA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvCA;AAGA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;ACjGA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAGA;AAAA;AASA;AACA;AATA;AACA;AACA;AAQA;AACA;AACA;AACA;;AACA;AAEA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAGA;AAEA;AACA;AAGA;AACA;AAGA;AAEA;AAEA;AAEA;AAEA;AACA;AAIA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AAEA;AACA;AAKA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACpMA;AAMA;AA0BA;AArBA;AAGA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AAGA;AAEA;AACA;AACA;AAIA;AAIA;AAGA;AAGA;AACA;AAIA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAUA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAhIA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAGA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AAmHA;AAAA;AAzIA;;;;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AACA;AASA;AAAA;AAuGA;AAtGA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAIA;AACA;AAEA;AACA;AAGA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;AClHA;AAAA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;ACAA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;ACwCA;AAiBA;AAhBA;AACA;AACA;AAEA;AAIA;AAEA;AAEA;AAKA;AACA;AAGA;AACA;AAEA;AACA;;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzJA;AACA;AAIA;AACA;AACA;AAGA;AACA;AACA;AACA;AAcA;AA+CA;AApCA;AACA;AACA;AAaA;AAMA;AAIA;AACA;AACA;AAGA;AAqBA;AA8DA;AA5EA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAGA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AACA;AACA;AACA;;;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;;;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;;;AAAA;AA1IA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAGA;AAAA;;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;AAAA;;AAAA;AAKA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAEA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAIA;AAAA;;AAAA;AACA;AAAA;;AAAA;AACA;AAAA;;AAAA;AAGA;AAAA;;AAAA;AAmFA;AAAA;;AAAA;AA5HA;AAZA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAgDA;AA/CA;AAsJA;AAAA;AAtJA;AAuJA;AACA;AACA;AACA","sources":["webpack://client-app/./src/resources/elements/form-button/form-button.scss","webpack://client-app/./src/resources/elements/form-input-address/form-input-address.scss","webpack://client-app/./src/resources/elements/form-input-bool/form-input-bool.scss","webpack://client-app/./src/resources/elements/form-input-file/form-input-file.scss","webpack://client-app/./src/resources/elements/form-input-multiple/form-input-multiple.scss","webpack://client-app/./src/resources/elements/form-input-radio/form-input-radio.scss","webpack://client-app/./src/resources/elements/form-input-telephone/form-input-telephone.scss","webpack://client-app/./src/resources/elements/grid/grid.scss","webpack://client-app/./src/resources/dialogs/prompt.html","webpack://client-app/./src/resources/elements/crisp-input-radio/crisp-input-radio.html","webpack://client-app/./src/resources/elements/crisp-picker/crisp-picker.html","webpack://client-app/./src/resources/elements/ex-icon/control.html","webpack://client-app/./src/resources/elements/form-button/control.html","webpack://client-app/./src/resources/elements/form-input-address/form-input-address.html","webpack://client-app/./src/resources/elements/form-input-bool/form-input-bool.html","webpack://client-app/./src/resources/elements/form-input-contact/form-input-contact.html","webpack://client-app/./src/resources/elements/form-input-country/form-input-country.html","webpack://client-app/./src/resources/elements/form-input-date/form-input-date.html","webpack://client-app/./src/resources/elements/form-input-file/form-input-file.html","webpack://client-app/./src/resources/elements/form-input-multiple/form-input-multiple.html","webpack://client-app/./src/resources/elements/form-input-radio/form-input-radio.html","webpack://client-app/./src/resources/elements/form-input-readonly/form-input-readonly.html","webpack://client-app/./src/resources/elements/form-input-telephone/form-input-telephone.html","webpack://client-app/./src/resources/elements/form-input-text/form-input-text.html","webpack://client-app/./src/resources/elements/grid/grid.html","webpack://client-app/./src/resources/dialogs/prompt.ts","webpack://client-app/./src/resources/elements/crisp-input-radio/crisp-input-radio.ts","webpack://client-app/./src/resources/elements/crisp-picker/crisp-picker.ts","webpack://client-app/./src/resources/elements/ex-icon/control.ts","webpack://client-app/./src/resources/elements/form-button/control.ts","webpack://client-app/./src/resources/elements/form-input-address/form-input-address.ts","webpack://client-app/./src/resources/elements/form-input-bool/form-input-bool.ts","webpack://client-app/./src/resources/elements/form-input-contact/form-input-contact.ts","webpack://client-app/./src/resources/elements/form-input-country/form-input-country.ts","webpack://client-app/./src/resources/elements/form-input-date/form-input-date.ts","webpack://client-app/./src/resources/elements/form-input-file/form-input-file.ts","webpack://client-app/./src/resources/elements/form-input-multiple/form-input-multiple.ts","webpack://client-app/./src/resources/elements/form-input-radio/form-input-radio.ts","webpack://client-app/./src/resources/elements/form-input-readonly/form-input-readonly.ts","webpack://client-app/./src/resources/elements/form-input-telephone/form-input-telephone.ts","webpack://client-app/./src/resources/elements/form-input-text/form-input-text.ts","webpack://client-app/./src/resources/elements/grid/grid-builder.ts","webpack://client-app/./src/resources/elements/grid/grid-column.ts","webpack://client-app/./src/resources/elements/grid/grid-delegate-source.ts","webpack://client-app/./src/resources/elements/grid/grid-icons.ts","webpack://client-app/./src/resources/elements/grid/grid-local-source.ts","webpack://client-app/./src/resources/elements/grid/grid-pager.ts","webpack://client-app/./src/resources/elements/grid/grid-parser.ts","webpack://client-app/./src/resources/elements/grid/grid-row.ts","webpack://client-app/./src/resources/elements/grid/grid-selection.ts","webpack://client-app/./src/resources/elements/grid/grid-source.ts","webpack://client-app/./src/resources/elements/grid/grid.ts"],"sourcesContent":["// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `form-button button.with-icon {\n padding: 14px 40px 14px 24px;\n}\nform-button button:disabled {\n cursor: not-allowed;\n}\nform-button .icon-ctr {\n position: relative;\n display: inline-block;\n width: 28px;\n height: 10px;\n}\nform-button .icon-ctr ex-icon {\n position: absolute;\n font-size: 1.6em;\n color: #666;\n top: -8px;\n left: 0;\n}\nform-button.red {\n margin-left: 10px;\n}\nform-button.red button:hover {\n background-color: rgb(255, 110, 110);\n color: #fff;\n}\nform-button.red button:hover ex-icon {\n color: #fff;\n}\nform-button.small {\n font-size: 0.85em;\n}\nform-button.small button {\n padding: 14px 25px;\n border-radius: 6px;\n}\nform-button.small button.with-icon {\n padding: 14px 20px 14px 5px;\n}\nform-button.small ex-icon {\n top: -4px;\n left: 7px;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-button/form-button.scss\"],\"names\":[],\"mappings\":\"AAEI;EACE,4BAAA;AADN;AAKE;EACE,mBAAA;AAHJ;AAME;EACE,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,YAAA;AAJJ;AAMI;EACE,kBAAA;EACA,gBAAA;EACA,WAAA;EACA,SAAA;EACA,OAAA;AAJN;AAQE;EACE,iBAAA;AANJ;AASM;EACE,oCAAA;EACA,WAAA;AAPR;AASQ;EACE,WAAA;AAPV;AAaE;EACE,iBAAA;AAXJ;AAaI;EACE,kBAAA;EACA,kBAAA;AAXN;AAaM;EACE,2BAAA;AAXR;AAeI;EACE,SAAA;EACA,SAAA;AAbN\",\"sourcesContent\":[\"form-button {\\r\\n button {\\r\\n &.with-icon {\\r\\n padding: 14px 40px 14px 24px;\\r\\n }\\r\\n }\\r\\n\\r\\n button:disabled{\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n .icon-ctr {\\r\\n position: relative;\\r\\n display: inline-block;\\r\\n width: 28px;\\r\\n height:10px;\\r\\n\\r\\n ex-icon {\\r\\n position: absolute;\\r\\n font-size: 1.6em;\\r\\n color: #666;\\r\\n top:-8px;\\r\\n left:0;\\r\\n }\\r\\n }\\r\\n\\r\\n &.red {\\r\\n margin-left: 10px;\\r\\n\\r\\n button {\\r\\n &:hover {\\r\\n background-color: rgb(255, 110, 110);\\r\\n color: #fff;\\r\\n\\r\\n ex-icon {\\r\\n color: #fff;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n &.small {\\r\\n font-size: 0.85em;\\r\\n\\r\\n button {\\r\\n padding: 14px 25px;\\r\\n border-radius: 6px;\\r\\n\\r\\n &.with-icon {\\r\\n padding: 14px 20px 14px 5px;\\r\\n }\\r\\n }\\r\\n\\r\\n ex-icon {\\r\\n top:-4px;\\r\\n left:7px;\\r\\n }\\r\\n }\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.search-results {\n margin: 0 0 10px 0;\n max-height: 320px;\n overflow: auto;\n overflow-x: hidden;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n}\n.search-results div {\n background: #fff;\n padding: 15px;\n margin: 3px;\n cursor: pointer;\n}\n.search-results div:hover {\n background: #fefefe;\n}\n\nh4 span {\n font-weight: normal;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-address/form-input-address.scss\"],\"names\":[],\"mappings\":\"AAAA;EACI,kBAAA;EACA,iBAAA;EACA,cAAA;EACA,kBAAA;EACA,gBAAA;EACA,iCAAA;AACJ;AACI;EACI,gBAAA;EACA,aAAA;EACA,WAAA;EACA,eAAA;AACR;AACQ;EACI,mBAAA;AACZ;;AAIA;EACE,mBAAA;AADF\",\"sourcesContent\":[\".search-results {\\r\\n margin: 0 0 10px 0;\\r\\n max-height: 320px;\\r\\n overflow: auto;\\r\\n overflow-x: hidden;\\r\\n overflow-y: auto;\\r\\n -webkit-overflow-scrolling: touch;\\r\\n\\r\\n div {\\r\\n background: #fff;\\r\\n padding: 15px;\\r\\n margin: 3px;\\r\\n cursor: pointer;\\r\\n\\r\\n &:hover {\\r\\n background: #fefefe;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\nh4 span {\\r\\n font-weight: normal;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `form-input-bool .answer-val {\n padding-right: 70px;\n}\nform-input-bool .answer-disabled {\n background-color: rgb(235, 235, 228);\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-bool/form-input-bool.scss\"],\"names\":[],\"mappings\":\"AACE;EACE,mBAAA;AAAJ;AAGE;EACE,oCAAA;AADJ\",\"sourcesContent\":[\"form-input-bool {\\r\\n .answer-val {\\r\\n padding-right: 70px;\\r\\n }\\r\\n\\r\\n .answer-disabled {\\r\\n background-color: rgb(235, 235, 228)\\r\\n }\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `input[type=file] {\n width: 0;\n height: 1px;\n}\n\n.existing-files {\n overflow: auto;\n overflow-y: hidden;\n overflow-x: auto;\n white-space: nowrap;\n -webkit-overflow-scrolling: touch;\n}\n.existing-files .no-results {\n font-size: 0.9em;\n margin-top: 10px;\n}\n\n.filebox {\n cursor: pointer;\n display: inline-block;\n position: relative;\n width: 90px;\n height: 90px;\n background: #fff;\n border: solid 1px #ccc;\n border-radius: 5px;\n margin: 5px 5px 5px 0;\n}\n.filebox .file-icon {\n font-size: 2em;\n color: #eee;\n position: absolute;\n top: 25px;\n left: 0;\n right: 0;\n text-align: center;\n}\n.filebox .download-icon, .filebox .remove-icon, .filebox .select-icon {\n font-size: 1.3em;\n color: #fff;\n position: absolute;\n top: 5px;\n right: 5px;\n}\n.filebox .download-icon {\n left: 5px;\n right: auto;\n}\n.filebox .filename {\n position: absolute;\n font-size: 0.8em;\n line-height: 1.1em;\n bottom: 5px;\n left: 5px;\n right: 5px;\n max-height: 56px;\n overflow: hidden;\n white-space: pre-wrap; /* CSS3 */\n white-space: -moz-pre-wrap; /* Firefox */\n white-space: -pre-wrap; /* Opera <7 */\n white-space: -o-pre-wrap; /* Opera 7 */\n word-wrap: break-word; /* IE */\n}\n.filebox:hover {\n background: #ddd;\n}\n\n.upload-indicator {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n background: rgba(0, 255, 0, 0.2);\n}\n\n.dropzone {\n background: #fff;\n border: dotted 2px #ccc;\n border-radius: 5px;\n text-align: center;\n padding: 30px 0;\n margin: 15px 0;\n}\n.dropzone small {\n pointer-events: none;\n}\n.dropzone form-button.secondary button {\n margin-top: 8px;\n padding-left: 0;\n padding-right: 0;\n}\n.dropzone form-button.secondary button label {\n padding: 14px 25px 14px 15px;\n cursor: pointer;\n}\n.dropzone label form-button span {\n padding: 14px 25px 14px 15px;\n}\n.dropzone.dragover {\n background: #efefef;\n}\n.dropzone.dragover form-button {\n pointer-events: none;\n}\n.dropzone.dragover form-button button {\n background: #efefef;\n opacity: 0.5;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-file/form-input-file.scss\"],\"names\":[],\"mappings\":\"AAAA;EACI,QAAA;EACA,WAAA;AACJ;;AAEA;EACI,cAAA;EACA,kBAAA;EACA,gBAAA;EACA,mBAAA;EACA,iCAAA;AACJ;AACI;EACI,gBAAA;EACA,gBAAA;AACR;;AAGA;EACI,eAAA;EACA,qBAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,gBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;AAAJ;AAEI;EACI,cAAA;EACA,WAAA;EACA,kBAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,kBAAA;AAAR;AAGI;EACI,gBAAA;EACA,WAAA;EACA,kBAAA;EACA,QAAA;EACA,UAAA;AADR;AAII;EACI,SAAA;EACA,WAAA;AAFR;AAKI;EACI,kBAAA;EACA,gBAAA;EACA,kBAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,gBAAA;EACA,gBAAA;EACA,qBAAA,EAAA,SAAA;EACA,0BAAA,EAAA,YAAA;EACA,sBAAA,EAAA,aAAA;EACA,wBAAA,EAAA,YAAA;EACA,qBAAA,EAAA,OAAA;AAHR;AAMI;EACI,gBAAA;AAJR;;AAQA;EACI,kBAAA;EACA,MAAA;EACA,SAAA;EACA,OAAA;EACA,gCAAA;AALJ;;AAQA;EACI,gBAAA;EACA,uBAAA;EACA,kBAAA;EACA,kBAAA;EACA,eAAA;EACA,cAAA;AALJ;AAOI;EACI,oBAAA;AALR;AAQI;EACI,eAAA;EACA,eAAA;EACA,gBAAA;AANR;AAQQ;EACI,4BAAA;EACA,eAAA;AANZ;AAYY;EACI,4BAAA;AAVhB;AAeI;EACI,mBAAA;AAbR;AAeQ;EACI,oBAAA;AAbZ;AAeY;EACI,mBAAA;EACA,YAAA;AAbhB\",\"sourcesContent\":[\"input[type=\\\"file\\\"] {\\r\\n width: 0;\\r\\n height: 1px;\\r\\n}\\r\\n\\r\\n.existing-files {\\r\\n overflow: auto;\\r\\n overflow-y: hidden;\\r\\n overflow-x: auto;\\r\\n white-space: nowrap;\\r\\n -webkit-overflow-scrolling: touch;\\r\\n\\r\\n .no-results {\\r\\n font-size: 0.9em;\\r\\n margin-top: 10px;\\r\\n }\\r\\n}\\r\\n\\r\\n.filebox {\\r\\n cursor: pointer;\\r\\n display: inline-block;\\r\\n position: relative;\\r\\n width: 90px;\\r\\n height: 90px;\\r\\n background: #fff;\\r\\n border: solid 1px #ccc;\\r\\n border-radius: 5px;\\r\\n margin: 5px 5px 5px 0;\\r\\n\\r\\n .file-icon {\\r\\n font-size: 2em;\\r\\n color: #eee;\\r\\n position: absolute;\\r\\n top: 25px;\\r\\n left: 0;\\r\\n right: 0;\\r\\n text-align: center;\\r\\n }\\r\\n\\r\\n .download-icon, .remove-icon, .select-icon {\\r\\n font-size: 1.3em;\\r\\n color: #fff;\\r\\n position: absolute;\\r\\n top: 5px;\\r\\n right: 5px;\\r\\n }\\r\\n\\r\\n .download-icon {\\r\\n left: 5px;\\r\\n right: auto;\\r\\n }\\r\\n\\r\\n .filename {\\r\\n position: absolute;\\r\\n font-size: 0.8em;\\r\\n line-height: 1.1em;\\r\\n bottom: 5px;\\r\\n left: 5px;\\r\\n right: 5px;\\r\\n max-height: 56px;\\r\\n overflow: hidden;\\r\\n white-space: pre-wrap; /* CSS3 */\\r\\n white-space: -moz-pre-wrap; /* Firefox */\\r\\n white-space: -pre-wrap; /* Opera <7 */\\r\\n white-space: -o-pre-wrap; /* Opera 7 */\\r\\n word-wrap: break-word; /* IE */\\r\\n }\\r\\n\\r\\n &:hover {\\r\\n background: #ddd;\\r\\n }\\r\\n}\\r\\n\\r\\n.upload-indicator {\\r\\n position: absolute;\\r\\n top:0;\\r\\n bottom:0;\\r\\n left:0;\\r\\n background: rgba(0,255,0,0.2);\\r\\n}\\r\\n\\r\\n.dropzone {\\r\\n background: #fff;\\r\\n border: dotted 2px #ccc;\\r\\n border-radius: 5px;\\r\\n text-align: center;\\r\\n padding: 30px 0;\\r\\n margin: 15px 0;\\r\\n\\r\\n small {\\r\\n pointer-events: none;\\r\\n }\\r\\n\\r\\n form-button.secondary button {\\r\\n margin-top: 8px;\\r\\n padding-left: 0;\\r\\n padding-right: 0;\\r\\n \\r\\n label {\\r\\n padding: 14px 25px 14px 15px;\\r\\n cursor: pointer;\\r\\n }\\r\\n }\\r\\n\\r\\n label {\\r\\n form-button {\\r\\n span {\\r\\n padding: 14px 25px 14px 15px;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n &.dragover {\\r\\n background: #efefef;\\r\\n\\r\\n form-button {\\r\\n pointer-events: none;\\r\\n\\r\\n button {\\r\\n background: #efefef;\\r\\n opacity: 0.5;\\r\\n }\\r\\n }\\r\\n }\\r\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `form-input-multiple .answer-val {\n padding-right: 70px;\n}\nform-input-multiple .answer-val a.change {\n margin-right: -55px;\n}\nform-input-multiple .answer-disabled {\n background-color: rgb(235, 235, 228);\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-multiple/form-input-multiple.scss\"],\"names\":[],\"mappings\":\"AACE;EACE,mBAAA;AAAJ;AAEI;EACE,mBAAA;AAAN;AAME;EACE,oCAH6B;AADjC\",\"sourcesContent\":[\"form-input-multiple {\\r\\n .answer-val {\\r\\n padding-right: 70px;\\r\\n\\r\\n a.change {\\r\\n margin-right: -55px;\\r\\n }\\r\\n }\\r\\n\\r\\n $form-input-multiple-bg-color: rgb(235, 235, 228);\\r\\n\\r\\n .answer-disabled {\\r\\n background-color: $form-input-multiple-bg-color\\r\\n }\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `form-input-radio .answer-val {\n padding-right: 70px;\n}\nform-input-radio .answer-val a.change {\n margin-right: -55px;\n}\nform-input-radio .answer-disabled {\n background-color: rgb(235, 235, 228);\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-radio/form-input-radio.scss\"],\"names\":[],\"mappings\":\"AACE;EACE,mBAAA;AAAJ;AAEI;EACE,mBAAA;AAAN;AAIE;EACE,oCAAA;AAFJ\",\"sourcesContent\":[\"form-input-radio {\\r\\n .answer-val {\\r\\n padding-right: 70px;\\r\\n\\r\\n a.change {\\r\\n margin-right: -55px;\\r\\n }\\r\\n }\\r\\n\\r\\n .answer-disabled {\\r\\n background-color: rgb(235, 235, 228)\\r\\n }\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `input[type=text].tel {\n display: inline-block;\n width: calc(50% - 14px);\n}\n\nselect.tel {\n display: inline-block;\n width: 50%;\n margin-right: 9px;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/resources/elements/form-input-telephone/form-input-telephone.scss\"],\"names\":[],\"mappings\":\"AAAA;EACI,qBAAA;EACA,uBAAA;AACJ;;AACA;EACI,qBAAA;EACA,UAAA;EACA,iBAAA;AAEJ\",\"sourcesContent\":[\"input[type=\\\"text\\\"].tel {\\r\\n display: inline-block;\\r\\n width:calc(50% - 14px);\\r\\n}\\r\\nselect.tel {\\r\\n display: inline-block;\\r\\n width:50%;\\r\\n margin-right: 9px;\\r\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, ``, \"\",{\"version\":3,\"sources\":[],\"names\":[],\"mappings\":\"\",\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Module\nvar code = \"\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","// Module\nvar code = \"\\r\\n\";\n// Exports\nexport default code;","import { DialogController } from 'aurelia-dialog';\r\nimport { autoinject, observable } from 'aurelia-framework';\r\n \r\n@autoinject()\r\nexport class PromptDialog {\r\n constructor(private controller: DialogController) { }\r\n\r\n title: string;\r\n @observable sharedComputer: boolean;\r\n\r\n activate(title: string) {\r\n this.title = title;\r\n }\r\n\r\n sharedComputerChanged(newValue: boolean) {\r\n this.controller.ok(newValue);\r\n }\r\n}\r\n","import { bindable, bindingMode, customElement, computedFrom } from \"aurelia-framework\";\r\n\r\nlet _counter: number = 0;\r\n\r\n@customElement('crisp-input-radio')\r\nexport class CrispInputRadio {\r\n constructor() {\r\n _counter += 1;\r\n this.counter = _counter;\r\n this.id = \"crisp-input-radio-group-\" + this.counter;\r\n }\r\n\r\n yesNoOptions = [\r\n { id: true, description: 'Yes', },\r\n { id: false, description: 'No', }\r\n ];\r\n\r\n counter: number = 0;\r\n id: string;\r\n\r\n @bindable label: string;\r\n @bindable items: Array = null;\r\n @bindable descriptionField: string = 'description';\r\n @bindable valueField;\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) value: any;\r\n @bindable enabled = true;\r\n @bindable yesNoItems: boolean = false;\r\n @bindable error: string;\r\n\r\n radioOptions: Array = null;\r\n\r\n private _selected: RadioOption;\r\n\r\n yesNoItemsChanged() {\r\n if (this.yesNoItems == true && !this.items) {\r\n this.items = this.yesNoOptions;\r\n this.valueField = \"id\";\r\n this.itemsChanged(this.items, null)\r\n }\r\n }\r\n\r\n @computedFrom('_selected')\r\n get selected(): RadioOption {\r\n return this._selected;\r\n }\r\n\r\n set selected(selectedOption: RadioOption) {\r\n this._selected = selectedOption;\r\n this.value = selectedOption.value;\r\n }\r\n\r\n\r\n itemsChanged(n, o) {\r\n if (this.items) {\r\n this.radioOptions = this.items.map(x => {\r\n return new RadioOption(x, this.descriptionField, this.valueField);\r\n });\r\n this._selected = this.radioOptions.find(x => x.value === this.value);\r\n }\r\n }\r\n\r\n /// if the bound value changes we need to update _selected so it's reflected in the radio buttons\r\n valueChanged(n, o) {\r\n if (this.radioOptions) {\r\n this._selected = this.radioOptions.find(x => x.value === this.value);\r\n }\r\n }\r\n}\r\n\r\nlet _optionCounter: number = 0;\r\nexport class RadioOption {\r\n constructor(choice: any, labelProperty: string, valueProperty: string) {\r\n if (typeof choice === \"object\") {\r\n this.label = choice[labelProperty];\r\n } else {\r\n this.label = choice;\r\n }\r\n\r\n if (typeof choice === \"object\" && valueProperty) {\r\n this.value = choice[valueProperty];\r\n } else {\r\n this.value = choice;\r\n }\r\n\r\n _optionCounter += 1;\r\n this.id = \"crisp-input-radio-group-\" + _counter + \"-option-\" + _optionCounter;\r\n }\r\n\r\n id: string;\r\n label: string;\r\n value: any;\r\n}\r\n","import { children } from 'aurelia-framework';\r\nimport { bindable, observable, bindingMode, inject, TaskQueue, autoinject } from 'aurelia-framework';\r\nimport { BindingEngine, computedFrom } from 'aurelia-binding';\r\n\r\ndeclare var $;\r\nlet _counter: number = 0;\r\n\r\n@autoinject\r\nexport class CrispPicker {\r\n constructor(private bindingEngine: BindingEngine, private taskQueue: TaskQueue) {\r\n _counter += 1;\r\n this.counter = _counter;\r\n this.id = 'crisp-picker-' + this.counter;\r\n }\r\n\r\n counter: number = 0;\r\n id: string;\r\n @bindable label = '';\r\n @bindable items = [];\r\n @observable({ changeHandler: 'createSelect' })\r\n private select: Element;\r\n @bindable multiple = false;\r\n @bindable({ defaultBindingMode: bindingMode.twoWay })\r\n selected = null;\r\n @bindable idField = 'id';\r\n @bindable descriptionField = 'description';\r\n @bindable valueField;\r\n @bindable({ changeHandler: 'createSelect' })\r\n enabled = true;\r\n @bindable canClear: boolean = false;\r\n\r\n @bindable valid = true;\r\n @bindable error = '';\r\n\r\n attached() {\r\n this.createSelect();\r\n }\r\n\r\n // when we bind in a new array from outside the change event stops working, so instead here\r\n // when we detect an array change (a new array) we setup an observer of our own\r\n _itemsSubscription = null;\r\n itemsChanged(n, o) {\r\n if (this._itemsSubscription) {\r\n this._itemsSubscription.dispose();\r\n }\r\n if (n !== undefined && n !== null) {\r\n this._itemsSubscription = this.bindingEngine.collectionObserver(n).subscribe(_ => {\r\n this.createSelect();\r\n });\r\n }\r\n this.createSelect();\r\n }\r\n\r\n // we need to watch the selected aray using the observer\r\n // to catch any changes made, so we can update the text label\r\n _selectionSubscription = null;\r\n selectedChanged(n, o) {\r\n if (n === undefined || n === null) {\r\n $(this.select).val(null);\r\n this.getInnerInput().val(null);\r\n return;\r\n }\r\n if (this._selectionSubscription) {\r\n this._selectionSubscription.dispose();\r\n }\r\n if (n instanceof Array) {\r\n this._selectionSubscription = this.bindingEngine.collectionObserver(n).subscribe(_ => {\r\n this.updateMulti(this.selected);\r\n });\r\n this.updateMulti(this.selected);\r\n } else {\r\n // if somehow no items - clear the selected text\r\n if (this.items === undefined || this.items === null) {\r\n console.warn(`there are no items in the collection - label = ${this.label}`);\r\n this.getInnerInput().val('');\r\n return;\r\n }\r\n const value = this.valueField ? n : this.getId(n) || '';\r\n $(this.select).val(value.toString());\r\n let description = '';\r\n if (this.valueField) {\r\n const item = this.items.find(i => i[this.valueField] === n);\r\n if (item) description = item[this.descriptionField].toString();\r\n } else {\r\n description = n.description;\r\n }\r\n this.getInnerInput().val(description);\r\n }\r\n }\r\n\r\n private updateMulti(newVals: any[]) {\r\n let valsAndDescs: any[];\r\n if (this.items === undefined || this.items === null) {\r\n console.warn(`there are no items in the collection - label = ${this.label}`);\r\n valsAndDescs = [];\r\n } else {\r\n if (this.valueField) {\r\n valsAndDescs = newVals.map(x => {\r\n const itemIndex = this.items.findIndex(item => item[this.valueField] === x);\r\n const item = this.items[itemIndex];\r\n return {\r\n index: itemIndex,\r\n val: x.toString(),\r\n desc: item ? item[this.descriptionField] : ''\r\n };\r\n });\r\n } else {\r\n valsAndDescs = newVals\r\n .map(x => {\r\n const id = this.getId(x);\r\n const itemIndex = this.items.findIndex(item => this.getId(item) === id);\r\n const item = this.items[itemIndex];\r\n return {\r\n index: itemIndex,\r\n val: id,\r\n desc: item ? item[this.descriptionField] : '-unrecognised-'\r\n };\r\n })\r\n .filter(x => x != null);\r\n }\r\n }\r\n\r\n const innerInput = this.getInnerInput();\r\n\r\n // update the select so the listed value are correct\r\n $(this.select).val(valsAndDescs.map(x => x.val));\r\n innerInput.val(\r\n valsAndDescs\r\n .map(x => x.desc)\r\n .join(', ')\r\n .trim()\r\n );\r\n\r\n // update the checkboxes internal to th ul so the checked reflect the selected correctly\r\n const lis = innerInput.siblings('ul').children();\r\n innerInput\r\n .siblings('ul')\r\n .find(\"input[type='checkbox']\")\r\n .prop('checked', function(i, val) {\r\n return valsAndDescs.findIndex(m => m.index === i) !== -1;\r\n });\r\n }\r\n\r\n detached() {\r\n if (this._itemsSubscription) {\r\n this._itemsSubscription.dispose();\r\n }\r\n if (this._selectionSubscription) {\r\n this._selectionSubscription.dispose();\r\n }\r\n }\r\n\r\n createSelect() {\r\n this.taskQueue.queueTask({\r\n call: () => {\r\n const $select = $(this.select);\r\n $select.material_select('destroy');\r\n\r\n if (this.enabled) $select.removeClass('disabled').removeAttr('disabled');\r\n else $select.addClass('disabled').prop('disabled', true);\r\n\r\n $select.material_select();\r\n\r\n const innerInput = this.getInnerInput();\r\n\r\n // HACK: This only affects single selection. The event below in materialize closes the dropdown before the 'click' event\r\n // when we position the drop down list. So here we remove the event, then in itemsSelected() we manually call the 'close' event\r\n // when a single item is selected.\r\n //\r\n // $newSelect.on('blur', function() {\r\n // if (!multiple) {\r\n // $(this).trigger('close');\r\n // }\r\n // ...\r\n // });\r\n if (!this.multiple) {\r\n innerInput.off('blur');\r\n }\r\n\r\n // so that the popup window that displays the list does not show inside it's parent container and cause that container to overflow\r\n // we instead move the popup to the body for display.\r\n innerInput.on('open', () => {\r\n const popupList = innerInput.siblings('ul');\r\n // store the current instance id against the popup list so we can\r\n // match it back later when trying to move it back\r\n popupList.data('id', this.id);\r\n\r\n const currentPosition = innerInput.offset();\r\n const body = $('body');\r\n\r\n const dropdownHeight = 300;\r\n const bottomEdge = body.innerHeight();\r\n\r\n // detect if we will go offscreen at the bottom - in which case make the options appear above\r\n if (currentPosition.top + dropdownHeight > bottomEdge) {\r\n // going offscreen at bottom;\r\n if (currentPosition.top - dropdownHeight < 0) {\r\n // still going offscreen if we flow up - so resize instead;\r\n popupList.css('max-height', bottomEdge - currentPosition.top);\r\n } else {\r\n // flow upwards;\r\n currentPosition.top = currentPosition.top - dropdownHeight + innerInput.height();\r\n }\r\n }\r\n\r\n popupList.css('display', 'none');\r\n body.append(popupList);\r\n\r\n setTimeout(\r\n () =>\r\n popupList.css({\r\n position: 'absolute',\r\n left: currentPosition.left,\r\n top: currentPosition.top,\r\n display: 'block'\r\n }),\r\n 200\r\n );\r\n\r\n $select.on('change.crisp-picker-' + this.id, () => {\r\n this.itemsSelected($select.val());\r\n });\r\n $select.on('blur.crisp-picker-' + this.id, () => {\r\n this.itemsSelected($select.val());\r\n });\r\n\r\n // we need to move the popup back to its original position in the tree when user clicks away\r\n $(document).on('click.crisp-picker-' + this.id, x => {\r\n this.tryMovePopupListFromBodyBackToInput();\r\n });\r\n });\r\n\r\n innerInput.on('close', () => {\r\n // we need to move the popup back to it's original position in the tree when user makes a selection\r\n this.tryMovePopupListFromBodyBackToInput();\r\n $select.off('.crisp-picker-' + this.id);\r\n });\r\n\r\n this.selectedChanged(this.selected, null);\r\n }\r\n });\r\n }\r\n\r\n tryMovePopupListFromBodyBackToInput() {\r\n // if the dropdown for this instance is currently open\r\n // get it and move it back. if a different ul is there leave it alone\r\n const existing = $('body>ul.select-dropdown')\r\n .toArray()\r\n .map(f => $(f))\r\n .find(f => f.data('id') === this.id);\r\n if (!!existing) {\r\n this.getInnerInput()\r\n .parent()\r\n .append(existing.css({ position: 'absolute', display: 'none' }));\r\n // once we have moved it back we aren't going to need the event watcher so remove it\r\n $(document).off('click.crisp-picker-' + this.id);\r\n }\r\n }\r\n\r\n itemsSelected = (selected: string | string[]) => {\r\n if (!selected) {\r\n this.selected = this.multiple ? [] : null;\r\n return;\r\n }\r\n if (typeof selected === 'string') {\r\n this.selected = this.getValue(this.items.find(x => this.getId(x).toString() === selected));\r\n } else {\r\n this.selected = this.items\r\n .filter(x => selected.indexOf(this.getId(x).toString()) >= 0)\r\n .map(x => this.getValue(x));\r\n }\r\n\r\n // HACK: see comment in createSelect() to see why we need this\r\n if (!this.multiple) {\r\n this.getInnerInput().trigger('close');\r\n }\r\n\r\n this.select.dispatchEvent(new CustomEvent('selected', { bubbles: true, detail: this.selected }));\r\n };\r\n\r\n getId(item) {\r\n if (!item) return item;\r\n if (this.idField) return item[this.idField];\r\n return item;\r\n }\r\n\r\n getDescription(item) {\r\n if (!item) return item;\r\n return item[this.descriptionField];\r\n }\r\n\r\n getValue(item) {\r\n if (!item) return item;\r\n if (this.valueField) return item[this.valueField];\r\n return item;\r\n }\r\n\r\n private getInnerInput() {\r\n return $(this.select).siblings('input.select-dropdown');\r\n }\r\n\r\n @computedFrom('selected', 'multiple', 'canClear')\r\n get showClear() {\r\n if ((this.selected !== 0 && !!this.selected === false) || this.multiple === true) return false;\r\n return this.canClear === true;\r\n }\r\n\r\n clear() {\r\n if (this.multiple === true) return;\r\n this.selected = null;\r\n }\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\n\r\n@customElement('ex-icon')\r\n@useView(PLATFORM.moduleName('./control.html'))\r\n@autoinject()\r\nexport class Icon{\r\n @bindable public icon: string;\r\n}\r\n","import { customElement, useView, autoinject, PLATFORM, bindable } from 'aurelia-framework';\r\n\r\n@customElement('form-button')\r\n@useView(PLATFORM.moduleName('./control.html'))\r\n@autoinject()\r\nexport class FormButton {\r\n @bindable public label: string = \"\";\r\n @bindable disabled = false;\r\n @bindable icon: string;\r\n @bindable clickAction: any;\r\n\r\n clicked() {\r\n if (this.clickAction && !this.disabled) {\r\n this.clickAction();\r\n }\r\n }\r\n}\r\n","import { customElement, bindable, bindingMode, autoinject, observable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { PostcodeLookupClient, AddressDtoResult } from 'application/gql/postcodeLookup.tsgql';\r\nimport { validate, ValidateNested, IsNotEmpty, IsOptional, IsPostcode, ValidateIf } from \"validation\";\r\nimport { FormInputText } from '../form-input-text/form-input-text';\r\nimport { AddressDtoInput, CountryCodeType } from 'application/gql/createUpdateApplication.tsgql';\r\nimport { Update } from '../../../updateService';\r\nimport { Helpers } from 'application/helpers';\r\nimport { FormInputCountry } from '../form-input-country/form-input-country';\r\nimport { Enums } from '../../../application/enums';\r\n\r\n@customElement('form-input-address')\r\n@autoinject()\r\nexport class FormInputAddress extends InputBase
{\r\n constructor(private postcodeLookupClient: PostcodeLookupClient) {\r\n super();\r\n }\r\n\r\n @ValidateNested()\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: Address;\r\n\r\n @bindable label: string;\r\n @bindable sameAs: Address;\r\n @bindable sameAsText = \"Same as the property address\";\r\n\r\n @bindable disabled: boolean = false;\r\n @bindable addressRequired: boolean = true;\r\n\r\n manual: boolean;\r\n addressConfirmed: boolean;\r\n searchResults: AddressDtoResult[] = [];\r\n noResults: boolean;\r\n\r\n countryCodes = Enums.countryCodes;\r\n\r\n address1VM: FormInputText;\r\n townVM: FormInputText;\r\n postcodeVM: FormInputText;\r\n countryVM: FormInputCountry;\r\n\r\n searching = false;\r\n\r\n @IsPostcode({ message: \"Please enter a valid postcode\" })\r\n @ValidateIf((o: FormInputAddress) => o.addressRequired || !!o.lookupPostcode)\r\n @observable lookupPostcode: string;\r\n\r\n bind() {\r\n if (!!this.value && this.value.address1 && this.value.town && this.value.postcode && this.value.country) {\r\n this.addressConfirmed = true;\r\n }\r\n }\r\n\r\n async lookupPostcodeChanged() {\r\n const errors = await validate(this);\r\n if (this.lookupPostcode && !errors.some(x => x.property === 'lookupPostcode')) {\r\n this.searching = true;\r\n try {\r\n const result = await this.postcodeLookupClient.postcodeLookup(this.lookupPostcode);\r\n this.searchResults = result.postcodeLookup;\r\n } catch {\r\n this.searchResults = [];\r\n } finally {\r\n this.noResults = !this.searchResults || this.searchResults.length === 0;\r\n this.searching = false;\r\n }\r\n }\r\n else {\r\n this.searching = false;\r\n this.searchResults = [];\r\n this.noResults = false;\r\n }\r\n }\r\n\r\n getCountryCodeDescription(countryCode: CountryCodeType) {\r\n return countryCode && this.countryCodes.find(c => c.id === countryCode)?.description;\r\n }\r\n\r\n getAddressString(address: AddressDtoResult) {\r\n return [address.address1, address.address2, address.address3, address.town, address.postcode, this.getCountryCodeDescription(address.country)].filter(x => !!x).join(', ');\r\n }\r\n\r\n selectAddress(address: AddressDtoResult) {\r\n this.value.address1 = address.address1;\r\n this.value.address2 = address.address2;\r\n this.value.address3 = address.address3;\r\n this.value.town = address.town;\r\n this.value.postcode = address.postcode;\r\n this.value.country = address.country;\r\n this.addressConfirmed = true;\r\n }\r\n\r\n public confirmAddress() {\r\n this.manual = true;\r\n\r\n // timeout ensures vm's are available\r\n setTimeout(async () => {\r\n this.address1VM.markVisited();\r\n this.townVM.markVisited();\r\n this.postcodeVM.markVisited();\r\n this.countryVM.markVisited();\r\n const errors = await validate(this.value);\r\n this.addressConfirmed = errors.length === 0; \r\n }, 0);\r\n }\r\n\r\n reset(manualMode: boolean) {\r\n this.searchResults = [];\r\n this.manual = manualMode;\r\n }\r\n\r\n searchResultKeyup(event: KeyboardEvent, address: AddressDtoResult) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.selectAddress(address));\r\n }\r\n\r\n changeAddressKeydown(event: KeyboardEvent) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.addressConfirmed = false);\r\n }\r\n\r\n enterManuallyKeydown(event: KeyboardEvent) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.reset(true));\r\n }\r\n\r\n searchByPostcodeKeydown(event: KeyboardEvent) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.manual = false);\r\n }\r\n\r\n setAddressToSameAs() {\r\n if (!this.value) {\r\n this.value = new Address();\r\n }\r\n \r\n this.value.address1 = this.sameAs.address1;\r\n this.value.address2 = this.sameAs.address2;\r\n this.value.address3 = this.sameAs.address3;\r\n this.value.town = this.sameAs.town;\r\n this.value.postcode = this.sameAs.postcode;\r\n this.value.country = this.sameAs.country;\r\n this.confirmAddress();\r\n }\r\n}\r\n\r\nexport class Address {\r\n @Update.IgnoreUpdates()\r\n sameAsPropertyAddress = false;\r\n\r\n @IsNotEmpty({ message: \"Please enter address line 1\" })\r\n address1: string;\r\n \r\n @IsOptional()\r\n address2: string;\r\n \r\n @IsOptional()\r\n address3: string;\r\n \r\n @IsNotEmpty({ message: \"Please enter a town\" })\r\n town: string;\r\n \r\n @IsPostcode({ message: \"Please enter a valid postcode\" })\r\n @ValidateIf((a: Address) => a.country === CountryCodeType.UNITEDKINGDOM)\r\n postcode: string;\r\n \r\n @IsNotEmpty({ message: \"Please select a country\" })\r\n country: CountryCodeType = CountryCodeType.UNITEDKINGDOM;\r\n\r\n static fromDto(address: AddressDtoResult) {\r\n const result = new Address();\r\n\r\n if (address) {\r\n result.address1 = address.address1;\r\n result.address2 = address.address2;\r\n result.address3 = address.address3;\r\n result.town = address.town;\r\n result.postcode = address.postcode;\r\n result.country = address.country;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n toDto() {\r\n const result = new AddressDtoInput();\r\n result.address1 = this.address1;\r\n result.address2 = this.address2;\r\n result.address3 = this.address3;\r\n result.town = this.town;\r\n result.postcode = this.postcode;\r\n result.country = this.country;\r\n return result;\r\n }\r\n\r\n equals(address: Address) {\r\n return this.address1 === address.address1 &&\r\n this.address2 === address.address2 &&\r\n this.address3 === address.address3 &&\r\n this.town === address.town &&\r\n this.postcode === address.postcode &&\r\n this.country === address.country;\r\n }\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM, observable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\n\r\n@customElement('form-input-bool')\r\n@autoinject()\r\nexport class FormInputBool extends InputBase {\r\n @bindable disabled: boolean = false;\r\n}\r\n","import { customElement, bindable, bindingMode, autoinject, computedFrom, Disposable, BindingEngine } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { IsNotEmpty, ValidateIf, IsEmail, ValidateNested, IsOptional, ValidationArguments, Validate, IsNotBlank, ValidationOptions, registerDecorator, Validator, EqualsPropertyConstraint, validate, isPhoneNumber } from 'validation';\r\nimport { Address, FormInputAddress } from '../form-input-address/form-input-address';\r\nimport { Update } from 'updateService';\r\nimport { CountryCodeType } from 'application/gql/retrieveApplication.tsgql';\r\nimport { Lists } from 'application/lists';\r\nimport { Helpers } from 'application/helpers';\r\nimport { ContactDtoInput } from 'application/gql/createUpdateApplication.tsgql';\r\nimport { CurrentUser } from 'user';\r\n\r\n@customElement('form-input-contact')\r\n@autoinject()\r\nexport class FormInputContact extends InputBase {\r\n constructor(private user: CurrentUser, private bindingEngine: BindingEngine) {\r\n super();\r\n }\r\n\r\n @Update.UpdateNested()\r\n @ValidateNested()\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: Contact;\r\n \r\n @bindable contactTypeLabel = 'Company or a private individual?';\r\n @bindable contactNumberLabel = 'Contact number';\r\n @bindable reporter: boolean = false;\r\n @bindable policyholder: boolean = false;\r\n @bindable additionalPolicyholder: boolean = false;\r\n @bindable captureRelationship: boolean = false;\r\n @bindable captureAddress: boolean = false;\r\n @bindable saved: boolean = false;\r\n @bindable representative: boolean = false;\r\n @bindable isFreeholder: boolean = false;\r\n @bindable isManagingAgent: boolean = false;\r\n @bindable disabled: boolean = false;\r\n\r\n titles = Lists.titles;\r\n relationships = Lists.relationships;\r\n additionalPolicyholderRelationships = Lists.additionalPolicyholderRelationships;\r\n representativeRelationships = Lists.representativeRelationships;\r\n familyRelationships = Lists.familyRelationships;\r\n subscriptions: Disposable[] = [];\r\n addressVM: FormInputAddress;\r\n\r\n attached() {\r\n if (this.isManagingAgent) {\r\n this.subscriptions.push(this.bindingEngine.propertyObserver(this.value, 'telephone').subscribe(async () => { await validate(this.addressVM); }));\r\n this.subscriptions.push(this.bindingEngine.propertyObserver(this.value, 'email').subscribe(async () => { await validate(this.addressVM); }));\r\n this.subscriptions.push(this.bindingEngine.propertyObserver(this.value.address, 'postcode').subscribe(async () => { await validate(this); }));\r\n }\r\n }\r\n\r\n detached() {\r\n this.subscriptions.forEach(x => x.dispose());\r\n }\r\n\r\n bind() {\r\n if (this.value) {\r\n this.value.reporter = this.reporter;\r\n this.value.policyholder = this.policyholder;\r\n this.value.additionalPolicyholder = this.additionalPolicyholder;\r\n this.value.captureRelationship = this.captureRelationship;\r\n this.value.captureAddress = this.captureAddress;\r\n this.value.representative = this.representative;\r\n this.value.admin = this.user.isAdmin;\r\n this.value.isFreeholder = this.isFreeholder;\r\n this.value.isManagingAgent = this.isManagingAgent;\r\n }\r\n }\r\n}\r\n\r\nexport class Contact {\r\n constructor(leadClaimant: boolean = null) {\r\n this.isLeadClaimant = leadClaimant;\r\n }\r\n\r\n id: string;\r\n editing = true;\r\n reporter = false;\r\n policyholder = false;\r\n additionalPolicyholder = false;\r\n captureRelationship = false;\r\n captureAddress = false;\r\n representative = false;\r\n isFreeholder = false;\r\n isManagingAgent = false;\r\n admin = false;\r\n\r\n @Update.IgnoreUpdates()\r\n @computedFrom('title', 'titleOther', 'firstname', 'surname')\r\n get name() {\r\n return `${this.title === 'Other' ? this.titleOther : this.title || ''} ${this.firstname || ''} ${this.surname || ''}`.trim();\r\n }\r\n\r\n @IsNotEmpty({ message: \"Please select Company or Private Individual\" })\r\n contactType: string;\r\n\r\n @IsNotEmpty({ message: \"Please enter title\" })\r\n @ValidateIf((o: Contact) => o.contactType === \"Private Individual\" || o.reporter || o.representative)\r\n title: string;\r\n\r\n @IsNotBlank({ message: \"Please enter title\" })\r\n @ValidateIf((o: Contact) => (o.contactType === \"Private Individual\" || o.reporter || o.representative) && o.title === \"Other\")\r\n titleOther: string;\r\n\r\n @IsNotBlank({ message: \"Please enter first name\" })\r\n @ValidateIf((o: Contact) => o.contactType === \"Private Individual\" || o.reporter || o.representative)\r\n firstname: string;\r\n \r\n @IsNotBlank({ message: \"Please enter surname\" })\r\n @ValidateIf((o: Contact) => o.contactType === \"Private Individual\" || o.reporter || o.representative)\r\n surname: string;\r\n \r\n @IsNotBlank({ message: \"Please enter company name\" })\r\n @ValidateIf((o: Contact) => o.contactType === \"Company\")\r\n companyName: string;\r\n \r\n @IsOptional()\r\n telephoneCountryCode: CountryCodeType = CountryCodeType.UNITEDKINGDOM;\r\n\r\n @IsTelephone({ message: \"Please enter a valid phone number\" })\r\n @ValidateIf((o: Contact) => o.telephoneRequired || !!o.telephone)\r\n telephone: string;\r\n \r\n @IsEmail({}, { message: \"Please enter a valid email address\" })\r\n @ValidateIf((o: Contact) => o.emailRequired || !!o.email)\r\n email: string;\r\n\r\n @Validate(EqualsPropertyConstraint, ['email'], { message: \"Email addresses do not match\" })\r\n @ValidateIf((o: Contact) => o.reporter && o.correspondenceMethod !== \"Post\")\r\n emailConfirmation: string;\r\n \r\n @IsNotEmpty({ message: \"Please select Yes or No\" })\r\n @ValidateIf((o: Contact) => o.reporter)\r\n isLeadClaimant: boolean;\r\n\r\n @IsNotEmpty({ message: \"Please select relationship type\" })\r\n @ValidateIf((o: Contact) => o.captureRelationship && !!o.contactType && !o.isLeadClaimant)\r\n relationshipToLeadClaimant: string;\r\n \r\n @IsNotEmpty({ message: \"Please enter relationship type\" })\r\n @ValidateIf((o: Contact) => o.captureRelationship && !!o.contactType && !o.isLeadClaimant && o.relationshipToLeadClaimant === \"Other\")\r\n relationshipToLeadClaimantOther: string;\r\n \r\n @IsNotEmpty({ message: \"Please select relationship type\" })\r\n @ValidateIf((o: Contact) => o.captureRelationship && !!o.contactType && !o.isLeadClaimant && o.relationshipToLeadClaimant === \"Family Member\")\r\n relationshipToLeadClaimantFamilyMember: string;\r\n \r\n @IsNotEmpty({ message: \"Please enter relationship type\" })\r\n @ValidateIf((o: Contact) => o.captureRelationship && !!o.contactType && !o.isLeadClaimant && o.relationshipToLeadClaimantFamilyMember === \"Other\")\r\n relationshipToLeadClaimantFamilyMemberOther: string;\r\n\r\n @Update.UpdateNested()\r\n @ValidateNested()\r\n @ValidateIf((o: Contact) => o.addressRequired)\r\n address: Address = new Address();\r\n\r\n @IsNotEmpty({ message: \"Please select Email or Post\" })\r\n correspondenceMethod: string = \"Email\";\r\n\r\n @Update.IgnoreUpdates()\r\n @computedFrom('reporter', 'policyholder', 'additionalPolicyholder', 'representative', 'isManagingAgent', 'telephone', 'email', 'address.postcode')\r\n get telephoneRequired() {\r\n if (this.isManagingAgent) {\r\n return (!this.email && !this.address.postcode) || !!this.telephone;\r\n }\r\n\r\n return this.reporter || this.policyholder || this.additionalPolicyholder || this.representative;\r\n }\r\n\r\n @Update.IgnoreUpdates()\r\n @computedFrom('reporter', 'correspondenceMethod', 'representative', 'isManagingAgent', 'telephone', 'email', 'address.postcode')\r\n get emailRequired() {\r\n if (this.isManagingAgent) {\r\n return (!this.telephone && !this.address.postcode) || !!this.email;\r\n }\r\n\r\n return (this.reporter && this.correspondenceMethod !== \"Post\") || this.representative;\r\n }\r\n \r\n @Update.IgnoreUpdates()\r\n @computedFrom('captureAddress', 'admin', 'correspondenceMethod', 'isFreeholder', 'isManagingAgent', 'telephone', 'email', 'address.postcode')\r\n get addressRequired() {\r\n if (this.isFreeholder) {\r\n return false;\r\n }\r\n\r\n if (this.isManagingAgent) {\r\n return (!this.telephone && !this.email) || !!this.address.postcode;\r\n }\r\n\r\n return this.captureAddress || (this.admin && this.correspondenceMethod === \"Post\");\r\n }\r\n\r\n static fromDto(contact: any, additionalPolicyholder = false, representative = false) {\r\n const result = new Contact();\r\n\r\n if (contact) {\r\n result.id = contact.id;\r\n result.contactType = contact.contactType;\r\n result.email = contact.email;\r\n result.emailConfirmation = contact.email;\r\n result.contactType = contact.contactType;\r\n result.title = Helpers.handleOther(Lists.titles, contact.title);\r\n result.titleOther = Helpers.handleOther(Lists.titles, contact.title, true);\r\n result.firstname = contact.firstname;\r\n result.surname = contact.surname;\r\n result.companyName = contact.companyName;\r\n result.telephoneCountryCode = contact.telephoneCountryCode;\r\n result.telephone = contact.telephone;\r\n result.isLeadClaimant = contact.isLeadClaimant;\r\n result.address = Address.fromDto(contact.address);\r\n result.correspondenceMethod = contact.correspondenceMethod;\r\n \r\n if (!!contact.relationshipToLeadClaimant) {\r\n const relationships = additionalPolicyholder ? Lists.additionalPolicyholderRelationships :\r\n representative ? Lists.representativeRelationships : Lists.relationships;\r\n\r\n result.relationshipToLeadClaimant = Helpers.handleOther(relationships, contact.relationshipToLeadClaimant);\r\n result.relationshipToLeadClaimantOther = Helpers.handleOther(relationships, contact.relationshipToLeadClaimant, true);\r\n }\r\n\r\n if (!!contact.relationshipToLeadClaimantFamilyMember) {\r\n const familyRelationships = additionalPolicyholder || representative ? [] : Lists.familyRelationships;\r\n\r\n result.relationshipToLeadClaimantFamilyMember = Helpers.handleOther(familyRelationships, contact.relationshipToLeadClaimantFamilyMember);\r\n result.relationshipToLeadClaimantFamilyMemberOther = Helpers.handleOther(familyRelationships, contact.relationshipToLeadClaimantFamilyMember, true);\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n toDto() {\r\n const result = new ContactDtoInput();\r\n result.id = this.id;\r\n result.email = this.email;\r\n result.contactType = this.contactType;\r\n result.title = this.title === \"Other\" ? this.titleOther : this.title;\r\n result.firstname = this.firstname;\r\n result.surname = this.surname;\r\n result.companyName = this.companyName;\r\n result.telephoneCountryCode = this.telephoneCountryCode;\r\n result.telephone = this.telephone;\r\n result.isLeadClaimant = this.isLeadClaimant;\r\n result.relationshipToLeadClaimant = this.relationshipToLeadClaimant === \"Other\" ? this.relationshipToLeadClaimantOther : this.relationshipToLeadClaimant;\r\n result.relationshipToLeadClaimantFamilyMember = this.relationshipToLeadClaimantFamilyMember === \"Other\" ? this.relationshipToLeadClaimantFamilyMemberOther : this.relationshipToLeadClaimantFamilyMember;\r\n result.address = this.address.toDto();\r\n result.correspondenceMethod = this.correspondenceMethod;\r\n return result;\r\n }\r\n}\r\n\r\nexport function IsTelephone(validationOptions?: ValidationOptions) {\r\n return function (object: Object, propertyName: string) {\r\n registerDecorator({\r\n name: \"isTelephone\",\r\n target: object.constructor,\r\n propertyName: propertyName,\r\n constraints: [],\r\n options: validationOptions,\r\n validator: {\r\n validate(value: string, args: ValidationArguments) {\r\n const contact = args.object as Contact;\r\n if (contact.telephoneCountryCode === CountryCodeType.UNITEDKINGDOM) {\r\n return isPhoneNumber(value, 'GB');\r\n }\r\n else {\r\n return value && /^[0-9 ]+$/.test(value.trim());\r\n }\r\n }\r\n }\r\n });\r\n };\r\n}\r\n","import { customElement, bindable, autoinject } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { CountryCodeType } from 'application/gql/createUpdateApplication.tsgql';\r\nimport { Helpers } from 'application/helpers';\r\nimport { Enums } from 'application/enums';\r\n\r\n@customElement('form-input-country')\r\n@autoinject()\r\nexport class FormInputCountry extends InputBase {\r\n @bindable disabled: boolean = false;\r\n\r\n countryCodes = Enums.countryCodes;\r\n\r\n onKeydown(e: KeyboardEvent) {\r\n if (Helpers.isNavigationOrSelectionKey(e) || Helpers.isSpaceKey(e)) {\r\n return true;\r\n }\r\n\r\n if (!Helpers.isNumberKey(e)) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM, observable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport * as moment from 'moment'\r\nimport { Helpers } from 'application/helpers';\r\n\r\n@customElement('form-input-date')\r\n@autoinject()\r\nexport class FormInputDate extends InputBase {\r\n @bindable showDay = true;\r\n @observable day: string;\r\n @observable month: string;\r\n @observable year: string;\r\n\r\n @bindable disabled: boolean = false;\r\n \r\n bound = false;\r\n focusMonth = false;\r\n focusYear = false;\r\n\r\n dayChanged() {\r\n if (this.bound) {\r\n if (this.day && !isNaN(Number(this.day)) && this.day.length === 2) {\r\n this.focusMonth = true;\r\n }\r\n \r\n this.dateChanged();\r\n }\r\n }\r\n\r\n monthChanged() {\r\n if (this.bound) {\r\n if (this.month && !isNaN(Number(this.month)) && this.month.length === 2) {\r\n this.focusYear = true;\r\n }\r\n \r\n this.dateChanged();\r\n }\r\n }\r\n\r\n yearChanged() {\r\n if (this.bound) {\r\n this.dateChanged();\r\n }\r\n }\r\n\r\n dateChanged() {\r\n if (this.year && this.year.length === 4 && !isNaN(Number(this.day)) && !isNaN(Number(this.month)) && !isNaN(Number(this.year))) {\r\n const d = this.day.length === 1 ? `0${this.day}` : this.day;\r\n const m = this.month.length === 1 ? `0${this.month}` : this.month;\r\n const dateString = `${this.year}-${m}-${d}T00:00:00.000Z`;\r\n const date = moment(dateString);\r\n if (date.isValid()) {\r\n this.value = date.toDate();\r\n return;\r\n }\r\n }\r\n \r\n this.value = null;\r\n }\r\n\r\n bind() {\r\n if (!!this.value) {\r\n const date = moment(this.value);\r\n this.day = date.format('DD');\r\n this.month = date.format('MM');\r\n this.year = date.format('YYYY');\r\n }\r\n else {\r\n this.day = !this.showDay ? '01' : '';\r\n this.month = '';\r\n this.year = '';\r\n }\r\n\r\n this.bound = true;\r\n }\r\n\r\n onKeydown(e: KeyboardEvent) {\r\n if (Helpers.isNavigationOrSelectionKey(e)) {\r\n return true;\r\n }\r\n\r\n if (!Helpers.isNumberKey(e)) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n","import { customElement, bindable, bindingMode, autoinject, observable, computedFrom, BindingEngine } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { Document } from '../../../application/components/evidence-item';\r\nimport { BindingSignaler } from 'aurelia-templating-resources';\r\nimport { HttpClient, Interceptor, HttpResponseMessage, RequestMessage } from 'aurelia-http-client';\r\nimport { Router } from 'aurelia-router';\r\nimport { validate } from 'validation';\r\nimport { EventAggregator } from 'aurelia-event-aggregator';\r\nimport { Helpers } from 'application/helpers';\r\nimport { DocumentDownloadService } from '../../../services/documentDownloadService';\r\nimport { TokenService } from '../../../services/tokenService';\r\n\r\n@customElement('form-input-file')\r\n@autoinject()\r\nexport class FormInputFile extends InputBase {\r\n\r\n constructor(\r\n private bindingSignaler: BindingSignaler,\r\n private httpClient: HttpClient,\r\n private router: Router,\r\n private aggregator: EventAggregator,\r\n private documentDownloadService: DocumentDownloadService,\r\n private tokenService: TokenService) {\r\n super();\r\n }\r\n\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) existingFiles: Document[];\r\n fileInputFiles: FileList;\r\n fileInputValue: any;\r\n dragOver = false;\r\n searchText: string;\r\n parent: any;\r\n fileSelectionError: string = '';\r\n showExisting: boolean = false;\r\n\r\n @bindable disabled: boolean = false;\r\n\r\n readonly acceptedFileTypes = '.pdf, .doc, .docx, .xlsx, .xls, .pptx, .ppt, .jpg, .jpeg, .tif, .tiff, .gif, .bmp, .png, .dwg, .mpg, .mov, .avi, .mp4, .html, .msg, .txt, .m4a, .mp3, .wav';\r\n readonly maxFileSize = 1073741824; // 1GB\r\n\r\n bind(bindingContext: any) {\r\n this.parent = bindingContext;\r\n\r\n // remove invalid files which may have been partially uploaded in the last session for example\r\n var invalidFiles = this.value.filter(x => !x.fileId || x.fileId === \"00000000-0000-0000-0000-000000000000\");\r\n invalidFiles.forEach(file => this.remove(null, file));\r\n }\r\n\r\n async fileInputFilesChanged() {\r\n if (this.fileInputFiles.length > 0) {\r\n this.fileSelectionError = '';\r\n }\r\n\r\n for (let i = 0; i < this.fileInputFiles.length; i++) {\r\n const file = this.fileInputFiles.item(i);\r\n this.selectAndUploadFile(file);\r\n }\r\n\r\n if (this.fileInputFiles.length > 0) {\r\n this.fileInputFiles = null;\r\n this.fileInputValue = null;\r\n }\r\n }\r\n\r\n async selectAndUploadFile(file: File) {\r\n if (file.size > this.maxFileSize) {\r\n this.showFileSelectionError(`File too large: \"${file.name}\"`);\r\n return;\r\n }\r\n\r\n const dotIx = file.name.lastIndexOf('.');\r\n if (dotIx === -1) {\r\n this.showFileSelectionError(`Unsupported file type: \"${file.name}\"`);\r\n return;\r\n }\r\n\r\n const extension = file.name.substr(dotIx).toLowerCase();\r\n if (!this.acceptedFileTypes.split(', ').includes(extension)) {\r\n this.showFileSelectionError(`Unsupported file type: \"${file.name}\"`);\r\n return;\r\n }\r\n\r\n // check file hasn't already been uploaded\r\n const alreadyInValue = this.value.some(x => x.fileName === file.name && x.fileSize === file.size && x.fileType === file.type);\r\n if (alreadyInValue) {\r\n return;\r\n }\r\n\r\n const existing = this.existingFiles.find(x => x.fileName === file.name && x.fileSize === file.size && x.fileType === file.type);\r\n if (existing) {\r\n this.selectExisting(existing);\r\n return;\r\n }\r\n\r\n const doc = new Document();\r\n doc.fileName = file.name;\r\n doc.fileType = file.type;\r\n doc.fileSize = file.size;\r\n\r\n // moved these 2 lines back to before the upload as it broke progress indicator and didn't solve the intermittent issue with saving\r\n this.value.push(doc);\r\n this.existingFiles.push(doc);\r\n\r\n const fileId = await this.upload(file, doc);\r\n\r\n if (fileId) {\r\n trySetFileId();\r\n } else {\r\n this.remove(null, doc, false);\r\n }\r\n\r\n function trySetFileId() {\r\n // ensure add to collection has fired and returned with an id before setting file id\r\n setTimeout(async () => {\r\n if (!doc.id) {\r\n trySetFileId();\r\n }\r\n else {\r\n doc.fileId = fileId;\r\n }\r\n }, 100);\r\n }\r\n\r\n await validate(this.parent);\r\n }\r\n\r\n async upload(file: File, doc: Document): Promise {\r\n try {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n\r\n const result = await this.httpClient.createRequest('api/file/upload')\r\n .asPost()\r\n .withContent(formData)\r\n .withProgressCallback((e: ProgressEvent) => { this.uploadProgress(doc, e); })\r\n .withInterceptor({\r\n request: async (request: RequestMessage) => {\r\n const token = this.tokenService.getToken();\r\n if (token) {\r\n request.headers.add('Authorization', 'Bearer ' + token);\r\n }\r\n return request;\r\n },\r\n response: async (response: HttpResponseMessage) => {\r\n if (response.statusCode === 503) {\r\n window['offline'] = true;\r\n window.location.reload();\r\n }\r\n\r\n return response;\r\n },\r\n responseError: async (response: HttpResponseMessage) => {\r\n return response;\r\n }\r\n } as Interceptor)\r\n .send();\r\n\r\n if (result.isSuccess) {\r\n return result.response.replace(/\\\"/g, \"\");\r\n } else {\r\n if (result.statusCode === 400) {\r\n this.showFileSelectionError(result.response);\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n\r\n uploadProgress(doc: Document, e: ProgressEvent) {\r\n doc.percentUploaded = Math.round((e.loaded / e.total) * 100);\r\n }\r\n\r\n async selectExisting(file: Document) {\r\n this.fileSelectionError = '';\r\n this.value.push(file);\r\n this.bindingSignaler.signal('refresh-existing');\r\n await validate(this.parent);\r\n }\r\n\r\n async remove(event: Event, doc: Document, removeError: boolean = true) {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n\r\n if (removeError) {\r\n this.fileSelectionError = '';\r\n }\r\n\r\n const ix = this.value.indexOf(doc);\r\n this.value.splice(ix, 1);\r\n\r\n if (!doc.fileId || doc.fileId === \"00000000-0000-0000-0000-000000000000\") {\r\n const existingIx = this.existingFiles.indexOf(doc);\r\n this.existingFiles.splice(existingIx, 1);\r\n }\r\n\r\n this.bindingSignaler.signal('refresh-existing');\r\n await validate(this.parent);\r\n }\r\n\r\n async download(doc: Document) {\r\n this.fileSelectionError = '';\r\n\r\n if (doc.fileId) {\r\n this.documentDownloadService.download(doc.id);\r\n }\r\n }\r\n\r\n onDragOver(event: Event) {\r\n event.preventDefault();\r\n this.dragOver = true;\r\n return true;\r\n }\r\n\r\n onDragLeave(event: Event) {\r\n event.preventDefault();\r\n this.dragOver = false;\r\n return true;\r\n }\r\n\r\n onDrop(event: any) {\r\n this.dragOver = false;\r\n event.preventDefault();\r\n this.fileSelectionError = '';\r\n\r\n if (event.dataTransfer.items) {\r\n for (let i = 0; i < event.dataTransfer.items.length; i++) {\r\n if (event.dataTransfer.items[i].kind === 'file') {\r\n const file = event.dataTransfer.items[i].getAsFile();\r\n this.selectAndUploadFile(file);\r\n }\r\n }\r\n } else {\r\n for (let i = 0; i < event.dataTransfer.files.length; i++) {\r\n this.selectAndUploadFile(event.dataTransfer.files[i]);\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n getFileIcon(file: Document) {\r\n return Helpers.getFileIcon(file);\r\n }\r\n\r\n @computedFrom('existingFiles.length', 'value.length')\r\n get anyExistingFiles() {\r\n return this.existingFiles.some(x => !this.value.some(y => y.fileId === x.fileId && y.fileName === x.fileName));\r\n }\r\n\r\n @computedFrom('searchText')\r\n get showNoSearchResults() {\r\n return !!this.searchText && !this.existingFiles.some(x => !this.value.some(y => y.fileId === x.fileId && y.fileName === x.fileName) && x.fileName.toLowerCase().includes(this.searchText.toLowerCase()));\r\n }\r\n\r\n showFileSelectionError(message: string) {\r\n this.fileSelectionError += message + '\\n';\r\n setTimeout(() => { this.fileSelectionError = ''; }, 5000);\r\n }\r\n\r\n toggleExistingKeydown(event: KeyboardEvent) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.showExisting = !this.showExisting);\r\n }\r\n\r\n callUploadDialog() {\r\n const input = document.getElementById(this.fieldName as string);\r\n input.click();\r\n }\r\n}\r\n\r\nexport class FilterValueConverter {\r\n toView(allItems: Document[], params: { selectedItems: Document[], search: string }) {\r\n const result = allItems.filter(x => !params.selectedItems.some(y => y.fileId === x.fileId && y.fileName === x.fileName));\r\n if (params.search === \"\" || params.search === undefined) return result;\r\n return result.filter((item) => item.fileName.toLowerCase().includes(params.search.toLowerCase()));\r\n }\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM, observable, BindingEngine } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { Helpers } from 'application/helpers';\r\n\r\n@customElement('form-input-multiple')\r\n@autoinject()\r\nexport class FormInputMultiple extends InputBase {\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: string[];\r\n @bindable dual = false;\r\n @bindable options: Array = null;\r\n @bindable disabled = false;\r\n\r\n elem: HTMLElement;\r\n\r\n values: object = {};\r\n\r\n constructor(\r\n private bindingEngine: BindingEngine) {\r\n super();\r\n }\r\n\r\n bind() {\r\n if (this.value === null || this.value === undefined) {\r\n this.value = [];\r\n } else {\r\n this.value.forEach(v => {\r\n this.values[v] = true;\r\n })\r\n }\r\n\r\n for (let i = 0; i < this.options.length; i++) {\r\n const optionName = this.options[i];\r\n this.bindingEngine\r\n .propertyObserver(this.values, optionName)\r\n .subscribe((newValue, oldValue) => {\r\n const set = new Set(this.value);\r\n if (newValue) {\r\n set.add(optionName);\r\n } else {\r\n set.delete(optionName);\r\n }\r\n this.value = Array.from(set);\r\n });\r\n }\r\n }\r\n\r\n valueChanged(newVal: string, oldVal: string) {\r\n if (newVal != oldVal && !!this.elem) {\r\n Helpers.scrollToElement(this.elem);\r\n }\r\n }\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM, observable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { Helpers } from 'application/helpers';\r\n\r\n@customElement('form-input-radio')\r\n@autoinject()\r\nexport class FormInputRadio extends InputBase {\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: string;\r\n @bindable dual = false;\r\n @bindable options: Array = null;\r\n @bindable disabled = false;\r\n\r\n elem: HTMLElement;\r\n\r\n valueChanged(newVal: string, oldVal: string) {\r\n if (newVal != oldVal && !!this.elem) {\r\n Helpers.scrollToElement(this.elem);\r\n }\r\n }\r\n\r\n changeKeydown(event: KeyboardEvent) {\r\n return Helpers.keypressEnterOrSpace(event, () => this.value = '');\r\n }\r\n}\r\n","import { customElement, autoinject, bindable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\n\r\n@customElement('form-input-readonly')\r\n@autoinject()\r\nexport class FormInputText extends InputBase {\r\n @bindable disabled: boolean = false;\r\n}\r\n","import { customElement, bindable, useView, bindingMode, autoinject, containerless, PLATFORM, observable } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { CountryCodeType } from 'application/gql/createUpdateApplication.tsgql';\r\nimport { Helpers } from 'application/helpers';\r\nimport { Enums } from 'application/enums';\r\n\r\n@customElement('form-input-telephone')\r\n@autoinject()\r\nexport class FormInputTelephone extends InputBase {\r\n @bindable placeholder = 'Landline or Mobile';\r\n @bindable({ defaultBindingMode: bindingMode.twoWay }) countryCode: CountryCodeType = CountryCodeType.UNITEDKINGDOM;\r\n\r\n @bindable disabled: boolean = false;\r\n\r\n countryCodes = Enums.countryCodes;\r\n\r\n onKeydown(e: KeyboardEvent) {\r\n if (Helpers.isNavigationOrSelectionKey(e) || Helpers.isSpaceKey(e)) {\r\n return true;\r\n }\r\n\r\n if (!Helpers.isNumberKey(e)) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n","import { customElement, bindable, autoinject, computedFrom } from 'aurelia-framework';\r\nimport { InputBase } from '../inputBase';\r\nimport { Helpers } from 'application/helpers';\r\n\r\n@customElement('form-input-text')\r\n@autoinject()\r\nexport class FormInputText extends InputBase {\r\n @bindable placeholder = '';\r\n @bindable disabled = false;\r\n @bindable disablePaste = false;\r\n @bindable multiline = false;\r\n @bindable currency = false;\r\n @bindable preventSpace = false;\r\n \r\n onPaste(e: any) {\r\n if (this.disablePaste) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n onKeydown(e: KeyboardEvent) {\r\n if (this.preventSpace && Helpers.isSpaceKey(e)) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n\r\n if (this.currency) {\r\n // allow comma and dot\r\n if (Helpers.isNavigationOrSelectionKey(e) || e.keyCode === 188 || e.keyCode === 190 || e.keyCode === 110 || e.key === \"£\" || e.key === \"$\" || e.key === \"€\") {\r\n return true;\r\n }\r\n \r\n if (!Helpers.isNumberKey(e)) {\r\n e.preventDefault();\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n @computedFrom('placeholder')\r\n get placeholderText() {\r\n return Helpers.isIE() ? '' : this.placeholder;\r\n }\r\n}","import {bindable, inject, BindingEngine, customElement, processContent, TargetInstruction, createOverrideContext} from 'aurelia-framework';\r\nimport {ViewCompiler, ViewSlot, ViewResources, Container} from 'aurelia-framework';\r\n\r\n/** Builds the Grid based on the existing template - maybe we can replace this in the future */\r\n/** Currently this builds based on Bootstrap grid template */\r\nimport {Grid} from './grid';\r\nimport {GridTemplate} from './grid-parser';\r\n\r\nexport class GridBuilder {\r\n\tprivate grid: Grid;\r\n\tprivate template: GridTemplate;\r\n\tprivate viewCompiler: ViewCompiler;\r\n\tprivate viewResources: ViewResources;\r\n\tprivate bindingEngine: BindingEngine;\r\n\tprivate container: Container;\r\n\r\n\tprivate element: any;\r\n\r\n\tprivate rowsViewSlot: ViewSlot;\r\n\tprivate rowTemplate: any;\r\n\r\n\tprivate headersViewSlots: ViewSlot[];\r\n\r\n\tprivate pagerViewSlot: ViewSlot;\r\n\r\n\tprivate scrollBarWidth: number = 16;\r\n\r\n\tconstructor(grid: Grid, element: any) {\r\n\t\tthis.grid = grid;\r\n\t\tthis.element = element;\r\n\t\tthis.template = this.grid.template;\r\n\r\n\t\tthis.viewCompiler = this.grid.viewCompiler;\r\n\t\tthis.viewResources = this.grid.viewResources;\r\n\t\tthis.bindingEngine = this.grid.bindingEngine;\r\n\t\tthis.container = this.grid.container;\r\n\t}\r\n\r\n\tbuild() {\r\n\t\t// Listen for window resize so we can re-flow the grid layout\r\n\t\tthis.resizeListener = window.addEventListener('resize', this.headersSyncColumnHeadersWithColumns.bind(this));\r\n\r\n\t\tthis.buildHeadingTemplate();\r\n\t\tthis.buildRowTemplate();\r\n\t\tthis.buildPagerTemplate();\r\n\t}\r\n\r\n\tprivate buildHeadingTemplate(){\r\n\t\tthis.headersViewSlots = [];\r\n\r\n\t\tvar theadTr = this.element.querySelector(\"table.grid-header-table>thead>tr.grid-headings\");\r\n\r\n\t\t// Create the columns headers\r\n\t\tthis.template.columns.forEach(c => {\r\n\t\t\t// each TH has it's own viewSlot so they have different bindings\r\n\t\t\tvar fragment = document.createDocumentFragment();\r\n\r\n\t\t\tvar th = document.createElement(\"th\");\r\n\t\t\tth.setAttribute(\"class\", \"grid-column ${$column.headerClass} ${($column.canSort && $grid.columnsCanSort) ? 'grid-column-sortable': 'grid-column-non-sortable'} ${ $column.class !== '' ? $column.class : '' }\");\r\n\t\t\t\r\n\t\t\tth.innerHTML = c.headingTemplate;\r\n\r\n\t\t\tfragment.appendChild(th);\r\n\r\n\t\t\tvar view = this.viewCompiler.compile(fragment, this.viewResources).create(this.container);\r\n\t\t\tlet bindingContext = {\r\n\t\t\t\t'$grid' : this.grid,\r\n\t\t\t\t'$column' : c,\r\n\t\t\t\t'$p': this.grid.bindingContext\r\n\t\t\t}\r\n\r\n\t\t\tvar context = createOverrideContext(bindingContext, this.grid.bindingContext);\r\n\t\t\tview.bind(this.grid, context);\r\n\r\n\t\t\tvar columnSlot = new ViewSlot(theadTr, true);\r\n\t\t\tcolumnSlot.add(view);\r\n\t\t\tcolumnSlot.attached();\r\n\r\n\t\t\tc.slot = columnSlot;\r\n\t\t\tc.view = view;\r\n\r\n\t\t\tthis.headersViewSlots.push(columnSlot);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate buildRowTemplate() {\r\n\t\t// The table body element will host the rows\r\n\t\tvar tbody = this.element.querySelector(\"table>tbody\");\r\n\t\tthis.rowsViewSlot = new ViewSlot(tbody, true);\r\n\r\n\t\t// Get the row template too and add a repeater/class\r\n\t\tvar row = tbody.querySelector(\"tr\");\r\n\r\n\t\tthis.rowTemplate = document.createDocumentFragment();\r\n\t\tthis.rowTemplate.appendChild(row);\r\n\r\n\t\t// builds \r\n\t\trow.setAttribute(\"repeat.for\", \"$item of source.items\");\r\n\t\trow.setAttribute(\"class\", \"${ $item === $grid.selectedItem ? 'info' : '' }\");\r\n\r\n\t\t// TODO: Do we allow the user to customise the row template or just\r\n\t\t// provide a callback?\r\n\t\t// Copy any user specified row attributes to the row template\r\n\t\tfor (var prop in this.template.rowAttributes) {\r\n\t\t\tif (this.template.rowAttributes.hasOwnProperty(prop)) {\r\n\t\t\t\trow.setAttribute(prop, this.template.rowAttributes[prop]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Create a fragment we will manipulate the DOM in\r\n\t\tvar rowTemplate = this.rowTemplate.cloneNode(true);\r\n\t\tvar row = rowTemplate.querySelector(\"tr\");\r\n\r\n\t\t// Create the columns\r\n\t\tthis.template.columns.forEach(col => {\r\n\t\t\tvar td = document.createElement(\"td\");\r\n\r\n\t\t\ttd.innerHTML = col[\"template\"];\r\n\t\t\ttd.className = col[\"class\"];\r\n\t\t\t\r\n\t\t\trow.appendChild(td);\r\n\t\t});\r\n\r\n\t\t// Now compile the row template\r\n\t\tvar view = this.viewCompiler.compile(rowTemplate, this.viewResources).create(this.container);\r\n\r\n\t\tlet bindingContext = { \r\n\t\t\t'$grid': this.grid,\r\n\t\t\t'$p': this.grid.bindingContext\r\n\t\t};\r\n\r\n\t\tvar context = createOverrideContext(bindingContext, this.grid.bindingContext);\r\n\t\tview.bind(this.grid, context);\r\n\r\n\t\tthis.rowsViewSlot.add(view);\r\n\t\tthis.rowsViewSlot.attached();\r\n\t}\r\n\r\n\tprivate buildPagerTemplate(){\r\n\t\t// build the custom template for the pager (if it exists)\r\n\t\t// otherwise the default template will be shown\r\n\t\tvar thost = this.element.querySelector(\"div.grid-footer-custom-container\");\r\n\t\tif(!this.grid.pager.template)\r\n\t\t{\r\n\t\t\t// todo - remove the thost somehow\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.pagerViewSlot = new ViewSlot(thost, true);\r\n\t\tvar template = document.createDocumentFragment();\r\n\t\tvar templateValue = document.createElement('div');\r\n\t\ttemplate.appendChild(templateValue);\r\n\t\ttemplateValue.innerHTML = this.grid.pager.template;\r\n\r\n\t\tvar view = this.viewCompiler.compile(template, this.viewResources).create(this.container);\r\n\t\tlet bindingContext = {\r\n\t\t\t// I'm having problem if I try to use $parent. The template never seems to see that\r\n\t\t\t'$parent': this.grid,\r\n\t\t\t'$grid' : this.grid,\r\n\t\t\t'$pager' : this.grid.pager,\r\n\t\t\t'$source': this.grid.source\r\n\t\t};\r\n\r\n\t\tvar context = createOverrideContext(bindingContext, this.grid.bindingContext);\r\n\t\tview.bind(this.grid, context);\r\n\r\n\t\tthis.pagerViewSlot.add(view);\r\n\t\tthis.pagerViewSlot.attached();\r\n\t}\r\n\r\n\tprivate resizeListener: any;\r\n\tunbind(){\r\n\t\twindow.removeEventListener('resize', this.resizeListener);\r\n\t}\r\n\r\n\theadersSyncColumnHeadersWithColumns() {\r\n\t\t// Get the first row from the data if there is one...\r\n\t\tvar cells = this.element.querySelectorAll(\"table>tbody>tr:first-child>td\");\r\n\r\n\t\tfor (var i = this.grid.gridHeaders.length - 1; i >= 0; i--) {\r\n\t\t\tvar header = this.grid.gridHeaders[i];\r\n\t\t\tvar filter = this.grid.gridFilters[i];\r\n\t\t\tvar cell = cells[i];\r\n\r\n\t\t\tif(cell && header && filter) {\r\n\t\t\t\tvar overflow = this.isBodyOverflowing();\r\n\t\t\t\tvar tgtWidth = cell.offsetWidth + (i == this.grid.gridHeaders.length - 1 && overflow ? this.scrollBarWidth : 0);\r\n\r\n\t\t\t\t// Make the header the same width as the cell...\r\n\t\t\t\theader.setAttribute(\"style\", \"width: \" + tgtWidth + \"px\");\r\n\t\t\t\tfilter.setAttribute(\"style\", \"width: \" + tgtWidth + \"px\");\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tisBodyOverflowing(): boolean {\r\n\t\tvar container = this.grid.gridContainer;\r\n\t\treturn container.offsetHeight < container.scrollHeight || container.offsetWidth < container.scrollWidth;\r\n\t}\r\n}","import {ViewSlot, View} from 'aurelia-framework';\r\n\r\n/** All Attributes on tr */\r\n\ttemplate: any;\r\n\r\n\t/** Full HTML template for the heading - either read from ... or build from the heading attribute */\r\n\theadingTemplate: any;\r\n\r\n\t/** Full HTML template for footers (tfoot) */\r\n\tfooterTemplate: any;\r\n\t\t\r\n\tsorting: string = \"\";\t// asc|desc\r\n\t\r\n\t// internal use\r\n\tslot: ViewSlot;\r\n\tview: View;\r\n\t\r\n\tinit(){\r\n\t\t// we can accept the field to be null if the column has no sorting enabled\r\n\t\tif(this.canSort){\r\n\t\t\tif(!this.field){\r\n\t\t\t\tthrow new Error(`field is required for column ${this.heading} if the column is sortable.`);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif(this.canFilter && !this.filterPlaceholder)\r\n\t\t\tthis.filterPlaceholder = \"filter...\";\r\n\t}\r\n}","import { Grid } from './grid';\r\nimport { GridColumn } from './grid-column';\r\n\r\nimport { IGridDataSource, IGridData, IDataInfo, IDataSortInfo, GridDataSource } from './grid-source';\r\n\r\n/** Remote Source of Grid Data via a function */\r\nexport class DelegateGridData extends GridDataSource {\r\n\tprivate dataRead: (event: IDataInfo) => Promise;\r\n\r\n\tconstructor(grid: Grid) {\r\n\t\tsuper(grid);\r\n\t\tthis.dataRead = grid.sourceRead;\r\n\t\tif (!this.dataRead) {\r\n\t\t\tthrow new Error(\"'data-read.call' is not defined on the grid.\");\r\n\t\t}\r\n\r\n\t\tthis.supportsPagination = this.grid.sourceSupportsPagination;\r\n\t\tthis.supportsSorting = this.grid.sourceSupportsSorting;\r\n\t\tthis.supportsMultiColumnSorting = this.grid.sourceSupportsMultiColumnSorting;\r\n\t}\r\n\r\n\trefresh() {\r\n\r\n\t\tthis.loading = true;\r\n\t\tvar sort = this.sorting.map(s => {\r\n\t\t\treturn { field: s.field, sorting: s.sorting };\r\n\t\t});\r\n\r\n\t\tvar requestInfo = {\r\n\t\t\tpage: this.page,\r\n\t\t\tpageSize: this.pageSize,\r\n\t\t\tsort: sort\r\n\t\t};\r\n\r\n\t\tif (sort && sort.length > 0) {\r\n\t\t\t// add the default sort field and sort to the default requestInfo\r\n\t\t\tvar s0 = sort[0];\r\n\t\t\trequestInfo[\"field\"] = s0[\"field\"];\r\n\t\t\trequestInfo[\"sorting\"] = s0[\"sorting\"];\r\n\t\t}\r\n\r\n\t\tvar d = this.dataRead(requestInfo);\r\n\r\n\t\tif (!d) {\r\n\t\t\t// uh - no result\r\n\t\t\tthis.count = 0;\r\n\t\t\tthis.items = [];\r\n\t\t\tthis.loading = false;\r\n\t\t\tthis.onData();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (d.then) {\r\n\t\t\td.then(result => {\r\n\t\t\t\tthis.handleResult(result);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t}).catch(error => {\r\n\t\t\t\tif (this.grid.sourceReadError)\r\n\t\t\t\t\tthis.grid.sourceReadError(error);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tif (Array.isArray(d)) {\r\n\t\t\t\tthis.handleResult(d, true);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t} else {\r\n\t\t\t\tthis.handleResult(d, false);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate handleResult(result: any, isArray: boolean = false) {\r\n\t\tvar r: IGridData;\r\n\t\tif (this.grid.sourceTransform)\r\n\t\t\tr = this.grid.sourceTransform(result);\r\n\t\telse {\r\n\t\t\tif (isArray) {\r\n\t\t\t\tr = { data: result, count: result.length };\r\n\t\t\t} else {\r\n\t\t\t\tr = result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (r) {\r\n\t\t\tthis.count = r.count || 0;\r\n\t\t\tthis.items = r.data || [];\r\n\t\t} else{\r\n\t\t\tthis.count = 0;\r\n\t\t\tthis.items = [];\r\n\t\t}\r\n\t\tif(this.count == 0){\r\n\t\t\tthis.page = 1;\r\n\t\t\tthis.pageCount = 0;\r\n\t\t}\r\n\t\tthis.onData();\r\n\t}\r\n}","export class GridIcons{\r\n\trefresh: string = \"fa fa-refresh\";\r\n\t\r\n\tsortingAsc: string = \"fa fa-sort-asc text-primary\";\r\n\tsortingDesc: string = \"fa fa-sort-desc text-primary\";\r\n\t\r\n\tfirstPage: string = \"fa fa-step-backward\";\r\n\tfirstPageTitle: string = \"First page\";\r\n\t\r\n\tprevPage: string = \"fa fa-caret-left\";\r\n\tprevPageTitle: string = \"Previous page\";\r\n\r\n\tnextPage: string = \"fa fa-caret-right\";\r\n\tnextPageTitle: string = \"Next page\";\r\n\r\n\tlastPage: string = \"fa fa-step-forward\";\r\n\tlastPageTitle: string = \"Last page\";\r\n}","import {Grid} from './grid';\r\nimport {GridColumn} from './grid-column';\r\n\r\nimport {IGridDataSource, IGridData, IDataInfo, GridDataSource} from './grid-source';\r\n\r\n/** Local Source of Grid Data - In Memory Paging and Sorting */\r\nexport class LocalGridData extends GridDataSource {\r\n\tsupportsPagination: boolean = true;\r\n\tsupportsSorting: boolean = true;\r\n\tsupportsMultiPageSorting: boolean = true;\r\n\t\r\n\tprivate dataRead: (event: IDataInfo) => Promise;\r\n\tprivate cache: any[];\r\n\tprivate allItems: any[];\r\n\r\n\tconstructor(grid: Grid) {\r\n\t\tsuper(grid);\r\n\t\tthis.dataRead = grid.sourceRead;\r\n\t\tif (!this.dataRead) {\r\n\t\t\tthrow new Error(\"'data-read.call' is not defined on the grid.\");\r\n\t\t}\r\n\t}\r\n\t\r\n\trefresh() {\r\n\t\tthis.loading = true;\r\n\t\tvar d = this.dataRead(null);\r\n \r\n\t\tif (d.then) {\r\n\t\t\td.then(result=> {\r\n\t\t\t\tthis.handleResult(result);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t}).catch(error=> {\r\n\t\t\t\tif (this.grid.sourceReadError)\r\n\t\t\t\t\tthis.grid.sourceReadError(error);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tif (Array.isArray(d)) {\r\n\t\t\t\tthis.handleResult(d, true);\r\n\t\t\t\tthis.loading = false;\r\n\t\t\t} else {\r\n this.handleResult(d, false);\r\n this.loading = false;\r\n }\r\n\t\t};\r\n\t}\r\n\r\n\t/** ============ New Data ============== */\r\n\tprivate handleResult(result: any, isArray: boolean = false) {\r\n\t\tvar r: IGridData;\r\n\t\tif (this.grid.sourceTransform)\r\n\t\t\tr = this.grid.sourceTransform(result);\r\n\t\telse {\r\n\t\t\tif (isArray) {\r\n\t\t\t\tr = { data: result, count: result.length };\r\n\t\t\t} else {\r\n\t\t\t\tr = result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (r) {\r\n\t\t\tthis.allItems = r.data;\r\n\t\t\tthis.cache = this.allItems;\r\n\t\t\tthis.count = r.count;\r\n\r\n\t\t\tthis.filterAndSortLocalData();\r\n\t\t}\r\n\t\tthis.onData();\r\n\t}\r\n\r\n\tprivate filterAndSortLocalData() {\r\n\t\t// Applies filter, sort then page\r\n\t\t// 1. First filter the data down to the set we want, if we are using local data\r\n\t\tvar tempData = this.allItems;\r\n\r\n\t\tif (this.grid.columnsCanFilter)\r\n\t\t\ttempData = this.applyFilter(tempData);\r\n\r\n\t\t// 2. Now sort the data\r\n\t\tif (this.grid.columnsCanSort)\r\n\t\t\ttempData = this.applySort(tempData);\r\n\r\n\t\t// 3. Now apply paging\r\n\t\ttempData = this.applyPage(tempData);\r\n\r\n\t\tthis.items = tempData;\r\n\r\n\t\tthis.updatePager();\r\n\r\n\t\tthis.watchForChanges();\r\n\r\n\t\tsetTimeout(() => this.grid.builder.headersSyncColumnHeadersWithColumns.bind(this), 0);\r\n\t}\r\n\r\n\r\n\t/** ============ Filtering ============== */\r\n\tprivate applyFilter(data: any[]): any[] {\r\n\t\treturn data.filter((row) => {\r\n\t\t\tvar include = true;\r\n\r\n\t\t\tfor (var i = this.grid.template.columns.length - 1; i >= 0; i--) {\r\n\t\t\t\tvar col = this.grid.template.columns[i];\r\n\r\n\t\t\t\tif (col.filterValue !== \"\" && row[col.field].toString().indexOf(col.filterValue) === -1) {\r\n\t\t\t\t\tinclude = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn include;\r\n\t\t});\r\n\t}\r\n\r\n\tprivate getFilterColumns() {\r\n\t\tvar cols = {};\r\n\r\n\t\tfor (var i = this.grid.template.columns.length - 1; i >= 0; i--) {\r\n\t\t\tvar col = this.grid.template.columns[i];\r\n\r\n\t\t\tif (col.filterValue !== \"\")\r\n\t\t\t\tcols[col.field] = col.filterValue;\r\n\t\t}\r\n\r\n\t\treturn cols;\r\n\t}\r\n\r\n\r\n\tprivate applySort(data: any[]): any[] {\r\n\t\t//Format the sort fields\r\n\t\tvar fields = [];\r\n\r\n\t\t// Get the fields in the \"sortingORder\"\r\n\t\tfor (var i = 0; i < this.sorting.length; i++) {\r\n\t\t\tvar col = this.sorting[i];\r\n\t\t\tfields.push(col.sorting === \"asc\" ? (col.field) : (\"-\" + col.field));\r\n\t\t};\r\n\r\n\t\tif (this.sorting.length > 0)\r\n\t\t\treturn this.allItems.sort(this.fieldSorter(fields));\r\n\t\telse\t// don't go through sort as it messses up data\r\n\t\t\treturn data;\r\n\t}\r\n\r\n\tprivate fieldSorter(fields) {\r\n\t\treturn function(a, b) {\r\n\t\t\treturn fields\r\n\t\t\t\t.map(function(o) {\r\n\t\t\t\t\tvar dir = 1;\r\n\t\t\t\t\tif (o[0] === '-') {\r\n\t\t\t\t\t\tdir = -1;\r\n\t\t\t\t\t\to = o.substring(1);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (a[o] > b[o]) return dir;\r\n\t\t\t\t\tif (a[o] < b[o]) return -(dir);\r\n\t\t\t\t\treturn 0;\r\n\t\t\t\t})\r\n\t\t\t\t.reduce(function firstNonZeroValue(p, n) {\r\n\t\t\t\t\treturn p ? p : n;\r\n\t\t\t\t}, 0);\r\n\t\t};\r\n\t}\r\n\r\n\t/** ============ Pagination ============== */\r\n\tprivate applyPage(data: any[]): any[] {\r\n\t\tvar start = (Number(this.page) - 1) * Number(this.pageSize);\r\n\r\n\t\tdata = data.slice(start, start + Number(this.pageSize));\r\n\r\n\t\treturn data;\r\n\t}\r\n\r\n\t/** ============ Monitoring ============== */\r\n\tprivate subscription: any;\r\n\t/** Watch for changes to the data */\r\n\tprivate watchForChanges() {\r\n\t\tthis.dontWatchForChanges();\r\n\r\n\t\tif (!this.grid.unbinding) {\r\n\t\t\t// We can update the pager automagically\r\n\t\t\tthis.subscription = this.grid.bindingEngine\r\n\t\t\t\t.collectionObserver(this.cache)\r\n\t\t\t\t.subscribe((splices) => {\r\n\t\t\t\t\tthis.refresh();\r\n\t\t\t\t});\r\n\t\t}\r\n\t}\r\n\tprivate dontWatchForChanges() {\r\n\t\tif (this.subscription) {\r\n\t\t\tthis.subscription.dispose();\r\n\t\t\tthis.subscription = null;\r\n\t\t}\r\n\t}\r\n\r\n\tunbind() {\r\n\t\tsuper.unbind();\r\n\t\tthis.dontWatchForChanges();\r\n\t}\r\n}","import {bindable, inject, BindingEngine, customElement, processContent, TargetInstruction} from 'aurelia-framework';\r\nimport {ViewCompiler, ViewSlot, ViewResources, Container} from 'aurelia-framework';\r\n\r\nimport {Grid} from './grid';\r\nimport {IGridDataSource} from './grid-source';\r\n\r\nexport class GridPager {\r\n\t// replaced template (if defined - otherwise we use our standard template)\r\n\ttemplate: any;\r\n\tgrid: Grid;\r\n\r\n\tenabled: boolean = true;\r\n\t\r\n\t/** number of pages to show in the pager */\r\n\t@bindable numPagesToShow: number = 5;\r\n\t@bindable showFirstLast: boolean = true;\r\n\t@bindable showJump: boolean = true;\r\n\t@bindable showPagingSummary: boolean = true;\r\n\t\r\n\t// CSV with page sizes\r\n\t@bindable pageSizes: number[] = [10, 25, 50];\r\n\r\n\t@bindable nextDisabled: boolean = false;\r\n\t@bindable prevDisabled: boolean = false;\r\n\r\n\t@bindable firstVisibleItem: number = 0;\r\n\t@bindable lastVisibleItem: number = 0;\r\n\t\r\n\t@bindable autoHide: boolean = false;\r\n\r\n\tpages = [];\r\n\t\r\n\tconstructor() {\r\n\t}\r\n\r\n\trefresh() {\r\n\t\tif (!this.grid.source)\r\n\t\t\treturn;\t// no source?\r\n\t\t\r\n\t\t// something changed in the data - recalculate\r\n\t\t// Cap the number of pages to render if the count is less than number to show at once\r\n\t\tvar numToRender = this.grid.source.pageCount < this.numPagesToShow ? this.grid.source.pageCount : this.numPagesToShow;\r\n\r\n\t\t// The current page should try to appear in the middle, so get the median \r\n\t\t// of the number of pages to show at once - this will be our adjustment factor\r\n\t\tvar indicatorPosition = Math.ceil(numToRender / 2);\r\n\r\n\t\t// Subtract the pos from the current page to get the first page no\r\n\t\tvar firstPageNumber = this.grid.source.page - indicatorPosition + 1;\r\n\r\n\t\t// If the first page is less than 1, make it 1\r\n\t\tif (firstPageNumber < 1)\r\n\t\t\tfirstPageNumber = 1;\r\n\r\n\t\t// Add the number of pages to render\r\n\t\t// remember to subtract 1 as this represents the first page number\r\n\t\tvar lastPageNumber = firstPageNumber + numToRender - 1;\r\n\r\n\t\t// If the last page is greater than the page count\r\n\t\t// add the difference to the first/last page\r\n\t\tif (lastPageNumber > this.grid.source.pageCount) {\r\n\t\t\tvar dif = this.grid.source.pageCount - lastPageNumber;\r\n\r\n\t\t\tfirstPageNumber += dif;\r\n\t\t\tlastPageNumber += dif;\r\n\t\t}\r\n\r\n\t\tvar pages = [];\r\n\r\n\t\tfor (var i = firstPageNumber; i <= lastPageNumber; i++) {\r\n\t\t\tpages.push(i);\r\n\t\t};\r\n\r\n\t\tthis.pages = pages;\r\n\r\n\t\tif(this.grid.source.count > 0)\r\n\t\t{\r\n\t\t\tthis.firstVisibleItem = (this.grid.source.page - 1) * Number(this.grid.source.pageSize) + 1;\r\n\t\t\tthis.lastVisibleItem = Math.min((this.grid.source.page) * Number(this.grid.source.pageSize), this.grid.source.count);\r\n\t\t} else{\r\n\t\t\tthis.firstVisibleItem = 0;\r\n\t\t\tthis.lastVisibleItem = 0;\r\n\t\t\tthis.pages = [];\r\n\t\t}\r\n\r\n\t\tthis.updateButtons();\r\n\t}\r\n\r\n\tupdateButtons() {\r\n\t\tthis.nextDisabled = this.grid.source.page >= this.grid.source.pageCount;\r\n\t\tthis.prevDisabled = this.grid.source.page <= 1;\r\n\t}\r\n\r\n\t// pageSizeChanged(newValue: number, oldValue: number) {\r\n\t// \tdebugger;\r\n\t// \tif (newValue == oldValue)\r\n\t// \t\treturn;\r\n\t// \tthis.grid.source.pageSize = newValue;\r\n\t// \tthis.grid.source.refresh();\r\n\t// }\r\n\r\n\tchangePage(page: number) {\r\n\t\tvar oldPage = this.grid.source.page;\r\n\r\n\t\tthis.grid.source.page = this.validate(page);\r\n\r\n\t\tif (oldPage !== this.grid.source.page) {\r\n\t\t\tthis.grid.source.refresh();\r\n\t\t}\r\n\t}\r\n\r\n\tnext() {\r\n\t\tthis.changePage(this.grid.source.page + 1);\r\n\t}\r\n\r\n\tnextJump() {\r\n\t\tthis.changePage(this.grid.source.page + this.numPagesToShow);\r\n\t}\r\n\r\n\tprev() {\r\n\t\tthis.changePage(this.grid.source.page - 1);\r\n\t}\r\n\r\n\tprevJump() {\r\n\t\tthis.changePage(this.grid.source.page - this.numPagesToShow);\r\n\t}\r\n\r\n\tfirst() {\r\n\t\tthis.changePage(1);\r\n\t}\r\n\r\n\tlast() {\r\n\t\tthis.changePage(this.grid.source.pageCount);\r\n\t}\r\n\r\n\tprivate validate(page: number): number {\r\n\t\tif (page < 1)\r\n\t\t\treturn 1;\r\n\t\tif (page > this.grid.source.pageCount)\r\n\t\t\treturn this.grid.source.pageCount;\r\n\r\n\t\treturn page;\r\n\t}\r\n}\r\n","import {GridColumn} from './grid-column';\r\nimport {GridRowAttributes} from './grid-row';\r\nimport {GridPager} from './grid-pager';\r\nimport {LogManager} from 'aurelia-framework';\r\n\r\nexport interface GridTemplate {\r\n\tcolumns: GridColumn[];\r\n\trowAttributes: GridRowAttributes;\r\n\tpager: GridPager;\r\n}\r\n\r\n/** Helper to do the parsing of the grid content */\r\nexport class GridParser {\r\n\tparse(element: any): GridTemplate {\r\n\t\tvar result = {\r\n\t\t\tcolumns: this.parseGridCols(element),\r\n\t\t\trowAttributes: this.parseGridRow(element),\r\n\t\t\tpager: this.parseGridPager(element)\r\n\t\t};\r\n\r\n\t\treturn result;\r\n\t}\r\n\tprivate parseGridCols(element: any): GridColumn[] {\r\n\t\tvar rowElement = element.querySelector(\"grid-row\");\r\n\t\tif(!rowElement){\r\n\t\t\tLogManager.getLogger(\"aurelia-grid\").warn(\"Grid has no defined\");\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tvar columnElements = Array.prototype.slice.call(rowElement.querySelectorAll(\"grid-col\"));\r\n\t\tvar cols = [];\r\n\r\n\t\tvar columnTemplate =\r\n\t\t\t'
${$column.heading}' +\r\n\t\t\t'' +\r\n\t\t\t'
';\r\n\r\n\t\t// ..\r\n\t\t// or header template \r\n\t\tcolumnElements.forEach(c => {\r\n\t\t\tvar col = new GridColumn();\r\n\r\n\t\t\tvar attrs = Array.prototype.slice.call(c.attributes);\r\n\t\t\tattrs.forEach(a => this.tryAssign(col, this.camelCaseName(a.name), a.value));\r\n\r\n\t\t\t// check for inner of template\r\n\t\t\tvar headingTemplate = c.querySelector(\"heading\");\r\n\t\t\tcol.headingTemplate = (headingTemplate && headingTemplate.innerHTML) ? headingTemplate.innerHTML : columnTemplate;\r\n\t\t\r\n\t\t\t// check for inner content of