app.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. var app = angular.module('application', ['ngMaterial', 'adaptive.detection', 'ui.bootstrap.typeahead'])
  2. .config(['$locationProvider', function($locationProvider) {
  3. $locationProvider.html5Mode({
  4. enabled: true,
  5. requireBase: false
  6. });
  7. }]);
  8. app.directive('skrollr', function() {
  9. var directiveDefinitionObject = {
  10. link: function() {
  11. skrollr.init();
  12. }
  13. };
  14. return directiveDefinitionObject;
  15. });
  16. app.controller('mainController', function($scope, $detection, $http, $mdSidenav, $timeout, $sce, $mdToast, $location) {
  17. // Debugging mode
  18. $scope.debug = window.location.hostname === 'localhost' || typeof $location.search().debug !== 'undefined';
  19. if($scope.debug) {
  20. console.log('***** Debugging mode ****');
  21. }
  22. $scope.title = "Manche Numerique";
  23. $scope.$sce = $sce;
  24. var getGeoCodeInProgress = false,
  25. nbJoursFTTH = 365,
  26. siteName = 'Eligibilité Manche Numérique',
  27. siteUrl = 'http://eligibilite.manchenumerique.fr',
  28. siteEmail = 'ftth@manchenumerique.fr',
  29. siteAddresse = '235, rue Joseph Cugnot Zone Delta, 50000 SAINT LÔ',
  30. siteTel = '02.33.77.83.60',
  31. layer = {},
  32. currentMarker,
  33. cLayer;
  34. // Coordinates around Manche to limit the extent of the queries
  35. var mancheCoordinates = [[49.732307856286, -1.97117692088061],[48.4, -1.75],[48.4, -0.5],[49.732307856286, -1.2]];
  36. // This limit the search area
  37. var searchExtent = {
  38. "xmin" : _.max(_.map(mancheCoordinates, function(c) {return c[1];})),
  39. "ymin" : _.max(_.map(mancheCoordinates, function(c) {return c[0];})),
  40. "xmax" : _.min(_.map(mancheCoordinates, function(c) {return c[1];})),
  41. "ymax" : _.min(_.map(mancheCoordinates, function(c) {return c[0];})),
  42. "spatialReference" : {"wkid" : 84}
  43. };
  44. var suggestURL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest?f=pjson&searchExtent=' + JSON.stringify(searchExtent);
  45. var maps = {
  46. "carte" : 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
  47. "satellite" : 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
  48. };
  49. var catTypeVoie = [
  50. {
  51. "name": "Allée",
  52. "id" : "allee"
  53. },
  54. {
  55. "name": "Avenue",
  56. "id" : "avenue"
  57. },
  58. {
  59. "name": "Boulevard",
  60. "id" : "boulevard"
  61. },
  62. {
  63. "name": "Carrefour",
  64. "id" : "carrefour"
  65. },
  66. {
  67. "name": "Chemin",
  68. "id" : "chemin"
  69. },
  70. {
  71. "name": "Cité",
  72. "id" : "cite"
  73. },
  74. {
  75. "name": "Hammeau",
  76. "id" : "hammeau"
  77. },
  78. {
  79. "name": "Impasse",
  80. "id" : "impasse"
  81. },
  82. {
  83. "name": "Lieu-dit",
  84. "id" : "lieu_dit"
  85. },
  86. {
  87. "name": "Lotissement",
  88. "id" : "lotissement"
  89. },
  90. {
  91. "name": "Place",
  92. "id" : "place"
  93. },
  94. {
  95. "name": "Résidence",
  96. "id" : "residence"
  97. },
  98. {
  99. "name": "Route",
  100. "id" : "route"
  101. },
  102. {
  103. "name": "Rue",
  104. "id" : "rue"
  105. },
  106. {
  107. "name": "Villa",
  108. "id" : "villa"
  109. },
  110. {
  111. "name": "Village",
  112. "id" : "village"
  113. }
  114. ];
  115. var catVousEtes = [
  116. {
  117. "name": "Locataire de ce logement",
  118. "id" : "locataire"
  119. },
  120. {
  121. "name": "Occupant à titre gratuit de ce logement",
  122. "id" : "occupant_gratuit"
  123. },
  124. {
  125. "name": "Propriétaire de ce logement",
  126. "id" : "proprietaire"
  127. }
  128. ];
  129. var catCeLogementEst = [
  130. {
  131. "name": "Votre résidence principale",
  132. "id" : "residence_principale"
  133. },
  134. {
  135. "name": "Votre résidence secondaire",
  136. "id" : "residence_secondaire"
  137. }
  138. ];
  139. var catAccord = [
  140. {
  141. "name": "J’ai l’intention de souscrire à une offre Très Haut Débit après le pré-raccordement",
  142. "id" : "avec_souscription"
  143. },
  144. {
  145. "name": "Je n’ai pas l’intention de souscrire à une offre Très Haut Débit après le pré-raccordement",
  146. "id" : "sans_souscription"
  147. }
  148. ];
  149. $scope.formulaires = {
  150. "eligibilite": {
  151. "sections": [
  152. {
  153. "name": "Générale",
  154. "visible": false,
  155. "lines": [
  156. {
  157. "ctrls": [
  158. {
  159. "name" : "Prénom",
  160. "id" : "prenom",
  161. "type" : "text",
  162. "width" : "50%",
  163. "require": true,
  164. "isValid": function(value) {
  165. return !!value && value.length > 2;
  166. },
  167. "msg" : 'Prénom invalide'
  168. },
  169. {
  170. "name" : "Nom",
  171. "id" : "nom",
  172. "type" : "text",
  173. "width" : "50%",
  174. "require": true,
  175. "isValid": function(value) {
  176. return !!value && value.length > 2;
  177. },
  178. "msg" : 'Nom invalide'
  179. }
  180. ]
  181. },
  182. {
  183. "ctrls": [
  184. {
  185. "name" : "Email",
  186. "id" : "email",
  187. "type" : "text",
  188. "width" : null,
  189. "require": true,
  190. "isValid": function(value) {
  191. function validateEmail(email) {
  192. var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
  193. return re.test(email);
  194. }
  195. return validateEmail(value);
  196. },
  197. "msg" : 'Email invalide.'
  198. }
  199. ]
  200. },
  201. {
  202. "ctrls": [
  203. {
  204. "name" : "Téléphone fixe",
  205. "id" : "telephone_fixe",
  206. "type" : "text",
  207. "width" : "50%",
  208. "require": false
  209. },
  210. {
  211. "name" : "Téléphone portable",
  212. "id" : "telephone_portable",
  213. "type" : "text",
  214. "width" : "50%",
  215. "require": false
  216. }
  217. ]
  218. }
  219. ]
  220. },
  221. {
  222. "name": "Adresse",
  223. "visible": true,
  224. "lines": [
  225. {
  226. "ctrls": [
  227. {
  228. "name" : "Numero",
  229. "id" : "numero_voie",
  230. "type" : "text",
  231. "width" : "80px",
  232. "require": false
  233. },
  234. {
  235. "name" : "Type voie",
  236. "id" : "type_voie",
  237. "type" : "select",
  238. "width" : "106px",
  239. "require": false,
  240. "options": {
  241. "categories": catTypeVoie
  242. }
  243. },
  244. {
  245. "name" : "Nom voie",
  246. "id" : "nom_voie",
  247. "type" : "text",
  248. "width" : "378px",
  249. "require": true,
  250. "isValid": function(value) {
  251. return !!value;
  252. },
  253. "msg" : 'Nom de voie invalide.'
  254. }
  255. ]
  256. },
  257. {
  258. "ctrls": [
  259. {
  260. "name" : "Complément Adresse",
  261. "id" : "complement_addresse",
  262. "type" : "textarea",
  263. "width" : null,
  264. "require": false
  265. }
  266. ]
  267. },
  268. {
  269. "ctrls": [
  270. {
  271. "name" : "Bâtiment",
  272. "id" : "batiment",
  273. "type" : "text",
  274. "width" : "50%",
  275. "require": false
  276. },
  277. {
  278. "name" : "Cage escalier",
  279. "id" : "cage_escalier",
  280. "type" : "text",
  281. "width" : "50%",
  282. "require": false
  283. }
  284. ]
  285. },
  286. {
  287. "ctrls": [
  288. {
  289. "name" : "Etage / Niveau",
  290. "id" : "etage",
  291. "type" : "text",
  292. "width" : "50%",
  293. "require": false
  294. },
  295. {
  296. "name" : "Numero appartement / porte",
  297. "id" : "numero_appartement",
  298. "type" : "text",
  299. "width" : "50%",
  300. "require": false
  301. }
  302. ]
  303. },
  304. {
  305. "ctrls": [
  306. {
  307. "name" : "Code postal",
  308. "id" : "code_postal",
  309. "type" : "text",
  310. "width" : "50%",
  311. "require": true,
  312. "isValid": function(value) {
  313. if(!value || value.length !== 5 || isNaN(parseInt(value, 10))) {
  314. return false;
  315. }
  316. return true;
  317. },
  318. "msg" : 'Non valide'
  319. },
  320. {
  321. "name" : "Ville",
  322. "id" : "ville",
  323. "type" : "text",
  324. "width" : "50%",
  325. "require": true,
  326. "isValid": function(value) {
  327. return !!value && value.length > 2;
  328. },
  329. "msg" : 'Ville invalide.'
  330. }
  331. ]
  332. }
  333. ]
  334. },
  335. {
  336. "name": "Logement",
  337. "visible": true,
  338. "lines": [
  339. {
  340. "ctrls": [
  341. {
  342. "name" : "Vous êtes",
  343. "id" : "vous_etes",
  344. "type" : "radio",
  345. "width" : null,
  346. "require": true,
  347. "other" : true,
  348. "options": {
  349. "categories": catVousEtes,
  350. "alertes": {
  351. "locataire": "Si vous êtes locataire, vous devez impérativement avertir votre propriétaire que vous souhaitez bénéficier du pré-raccordement à la fibre optique."
  352. }
  353. },
  354. "isValid": function(value, other) {
  355. return !!value && value !== 'autre' || !!other;
  356. },
  357. "msg" : 'Choix incomplet.'
  358. }
  359. ]
  360. },
  361. {
  362. "ctrls": [
  363. {
  364. "name" : "Ce logement est",
  365. "id" : "ce_logement_est",
  366. "type" : "radio",
  367. "width" : null,
  368. "require": true,
  369. "other" : true,
  370. "options": {
  371. "categories": catCeLogementEst
  372. },
  373. "isValid": function(value, other) {
  374. return !!value && value !== 'autre' || !!other;
  375. },
  376. "msg" : 'Choix incomplet.'
  377. }
  378. ]
  379. }
  380. ]
  381. },
  382. {
  383. "name": "Conditions pour le raccordement final d’abonné dans un immeuble individuel",
  384. "visible": true,
  385. "lines": [
  386. {
  387. "text": "Manche Numérique propose aux personnes qui le souhaitent, de faire d’ores et déjà raccorder leur logement ou local à usage professionnel, au futur réseau de communications électroniques à Très Haut Débit FTTH. <b>Le montant de ce raccordement s’élevera à 50 € pour les personnes qui souscriront à une offre Très Haut Débit auprès d’un opérateur et de 400 € pour ceux qui demanderont uniquement la pose de la prise, sans souscription d’un abonnement.</b><br><span class = 'rmq'>Remarque : Ce raccordement s’appuiera sur vos infrastructures existantes, le coût lié à leur remise en état sera à votre charge en supplément des 50€ ou 400€.</span>",
  388. "ctrls": [
  389. {
  390. "name" : "Accord",
  391. "id" : "accord",
  392. "options": {
  393. "categories": catAccord,
  394. },
  395. "type" : "radio",
  396. "width" : null,
  397. "require": true,
  398. "other" : false,
  399. "isValid": function(value) {
  400. return !!value;
  401. },
  402. "msg" : 'Choix incorrect.',
  403. "note" : 'IMPORTANT : le règlement ne vous sera demandé qu’après travaux effectués'
  404. }
  405. ]
  406. }
  407. ]
  408. },
  409. {
  410. "name": "Informatique et libertés",
  411. "visible": false,
  412. "lines": [
  413. {
  414. "ctrls": [
  415. {
  416. "name" : "Informatique et libertés",
  417. "id" : "info_et_libertes",
  418. "libelle": 'La personne responsable du traitement de la présente demande de pré-raccordement est le représentant du Syndicat Mixte Manche Numérique, le Président, Monsieur Serge DESLANDES. Les informations portées sur ce formulaire sont obligatoires. Elles font l’objet d’un traitement informatisé destiné au raccordement final de l’usager à la fibre optique (FTTH) ainsi qu’à l’exploitation du réseau optique. Les destinataires des données sont : le Syndicat Mixte Manche Numérique, les entreprises en charge de réaliser les travaux de raccordement, ainsi que l’exploitant du réseau optique. Conformément à la loi "informatique et libertés" du 6 janvier 1978 modifiée, vous bénéficiez d’un droit d’accès, de rectification aux informations qui vous concernent, d’opposition au traitement de vos données personnelles. Si vous souhaitez exercer ce droit et obtenir communication des informations vous concernant, veuillez-vous adresser au Syndicat Mixte Manche Numérique ftth@manchenumerique.fr. Dans l’hypothèse où le présent formulaire est incomplet et/ou illisible, la présente demande de raccordement ne sera pas traitée.',
  419. "type" : "checkbox",
  420. "width" : null,
  421. "require": true,
  422. "isValid": function(value) {
  423. return !!value;
  424. },
  425. "msg" : 'Vous devez accepter.'
  426. }
  427. ]
  428. }
  429. ]
  430. }
  431. ]
  432. }
  433. };
  434. var addCurrentMarker = function(withReverse) {
  435. if(currentMarker) {
  436. map.removeLayer(currentMarker);
  437. }
  438. currentMarker = L.marker([$scope.geoCode.y, $scope.geoCode.x], {draggable: true, title: "Votre addresse"}).addTo(map);
  439. // currentMarker.on('add', function(event) {
  440. // map.setZoom(18);
  441. // });
  442. currentMarker.bindPopup("L'adresse que vous nous avez fournie est localisée sur la carte. Il se peut que la position réelle de votre logement soit un peu différente. Dans ce cas, merci de déplacer le pointeur sur la carte pour le positionner à l'emplacement de votre logement.").openPopup();
  443. if(withReverse) {
  444. $scope.magicKey = null;
  445. reverseLocation($scope.geoCode, null, function(address) {
  446. $scope.address = address;
  447. });
  448. }
  449. currentMarker.on('dragend', function(event) {
  450. var p = currentMarker.getLatLng();
  451. $scope.magicKey = null;
  452. $scope.geoCode = {
  453. x: p.lng,
  454. y: p.lat
  455. };
  456. reverseLocation($scope.geoCode, null, function(address) {
  457. $scope.address = address;
  458. getResults();
  459. });
  460. });
  461. };
  462. var checkDoublon = function(formValues, callback) {
  463. var query = 'SELECT * FROM `eligibilite`.`demandes` WHERE 1' +
  464. ' AND `email` = "' + mysql_real_escape_string(formValues.email) + '"' +
  465. ' AND `numero_voie` = "' + (formValues.numero_voie ? formValues.numero_voie : '') + '"' +
  466. ' AND `type_voie` = "' + mysql_real_escape_string(formValues.type_voie) + '"' +
  467. ' AND `nom_voie` = "' + mysql_real_escape_string(formValues.nom_voie) + '"' +
  468. ' AND `code_postal` = "' + formValues.code_postal + '"';
  469. $.ajax({
  470. method : "POST",
  471. url : "ajax/datastores.php",
  472. data : {query: query}
  473. })
  474. .done(function( result ) {
  475. var doublon = result && result !== 'null' ? result: null;
  476. callback(doublon);
  477. });
  478. };
  479. var computeDateFTTH = function() {
  480. if(!$scope.results.ftth) {return;}
  481. $scope.results.ftth.eligible = false;
  482. var momentDate;
  483. // Already deployed
  484. if($scope.results.ftth.PHASE_TRAV === 'Perimetre deploye FTTH MT') {
  485. $scope.results.ftth.eligible = true;
  486. }
  487. // Si date de début de travaux réelle est renseignée
  488. if ($scope.results.ftth.DATE_DEB_TRAV_REEL) {
  489. // Compute Date
  490. momentDate = moment($scope.results.ftth.DATE_DEB_TRAV_REEL, 'DD/MM/YY');
  491. momentDate.add(nbJoursFTTH, 'days');
  492. $scope.results.ftth.date = momentDate.format('MM/YYYY');
  493. }
  494. // Si date de début de travaux prévisionnelle est renseignée
  495. else if(($scope.results.ftth.PHASE_TRAV === 'Tranche 1 Travaux' || $scope.results.ftth.PHASE_TRAV === 'Tranche 1 Travaux completude') && $scope.results.ftth.DATE_DEB_TRAV_PREV) {
  496. // Compute Date
  497. momentDate = moment($scope.results.ftth.DATE_ABONNEMENT_PREV, 'DD/MM/YY');
  498. momentDate.add(nbJoursFTTH, 'days');
  499. var semester = '1er';
  500. if(parseInt(momentDate.format('M'), 10) > 5) {
  501. semester = '2nd';
  502. }
  503. $scope.results.ftth.date = semester + ' semestre ' + momentDate.format('YYYY');
  504. }
  505. };
  506. var computeFullAddress = function() {
  507. return $scope.result.eligibilite.complement_addresse;
  508. };
  509. var formatDate = function(value) {
  510. return moment(value, 'DD/MM/YY');
  511. };
  512. var getFullAddress = function(callback) {
  513. if($scope.magicKey) {
  514. var findURL = 'http://api-adresse.data.gouv.fr/search/?';
  515. var url = findURL + "q=" + $scope.address;
  516. $.get(
  517. url,
  518. function(data, status) {
  519. var next = function(record) {
  520. reverseLocation($scope.geoCode, null, function(string, address) {
  521. if(record) {
  522. address.StreetNumber = record.housenumber;
  523. address.Match_addr = $scope.address;
  524. }
  525. callback(null, address);
  526. });
  527. };
  528. if(data && data.features && data.features[0] && data.features[0].properties) {
  529. next(data.features[0].properties);
  530. }
  531. else {
  532. next();
  533. }
  534. });
  535. }
  536. else {
  537. reverseLocation($scope.geoCode, null, function(string, address) {
  538. callback(null, address);
  539. });
  540. }
  541. };
  542. var getRecordsFor = function(identifier, coordinates) {
  543. var records = [];
  544. _.each($scope.data[identifier], function(record) {
  545. _.some(record._polygons, function(polygon) {
  546. if(isInside(polygon, coordinates)) {
  547. records.push(record);
  548. return true;
  549. }
  550. });
  551. });
  552. return records;
  553. };
  554. var getResults = function() {
  555. $scope.results = {};
  556. $.ajax({
  557. method : "POST",
  558. url : "ajax/oracle.php",
  559. data : $scope.geoCode
  560. })
  561. .error(function(err) {
  562. console.error('Oracle issue', err);
  563. })
  564. .done(function( msg ) {
  565. onResults(msg);
  566. });
  567. var onResults = function(results) {
  568. try {
  569. $scope.results = JSON.parse(results);
  570. $scope.results.address = $scope.address;
  571. $scope.results.ftth = parseResults($scope.results.ftth);
  572. $scope.results.adsl = parseResults($scope.results.adsl);
  573. $scope.results.mimo = parseResults($scope.results.mimo);
  574. computeDateFTTH();
  575. console.log('results', $scope.results);
  576. }
  577. catch(e) {
  578. // Debugging purpose
  579. if(window.location.hostname === 'localhost') {
  580. onResults('{"x":-1.1060984089996,"y":49.119046582,"ftth":[{"ID_ZAPM_PARTIELLE":"203AP0","DATE_OUV_SERVICE_REEL":null,"DATE_OUV_SERVICE_PREV":null,"DATE_FIN_TRAV_PREV":"04\/05\/16","DATE_DEB_ETUDES_PREV":"01\/12\/14"}],"adsl":[{"ID_FT_ADSL":"656","LEGENDE":"TV sur ADSL","NATURE":"0 - 37"}],"mimo":null}');
  581. }
  582. else {
  583. console.error(e);
  584. alert('Probleme de connexion à la base de donnée Oracle.');
  585. $scope.hideResultPane();
  586. }
  587. }
  588. $scope.refreshInscriptionInfo();
  589. $scope.$apply();
  590. };
  591. $scope.$evalAsync();
  592. };
  593. var init = function() {
  594. var stlo = [49.1154686, -1.0828136000000086];
  595. var map = L.map('map', {zoomControl:false}).setView(stlo, 9);
  596. map.on('dblclick', function(e) {
  597. var p = e.latlng;
  598. $scope.geoCode = {
  599. x: p.lng,
  600. y: p.lat
  601. };
  602. addCurrentMarker(true);
  603. $scope.showResultPane();
  604. getResults();
  605. });
  606. cLayer = L.tileLayer(maps.satellite, {
  607. attribution: 'Carte fournie par <a href="http://openstreetmap.org">OpenStreetMap</a>',
  608. maxZoom: 18
  609. }).addTo(map);
  610. var styleOpts = {
  611. color : 'red',
  612. fillColor: 'red',
  613. weight : 8
  614. };
  615. $scope.data = {};
  616. $scope.colors = {
  617. "ftth": "#8cc474", // green
  618. "mimo": "#f9b256", // orange
  619. "adsl": "#76a7fa" // blue
  620. };
  621. $http({method: 'POST', url: 'data/dictionary.json'}).success(function(data) {
  622. $scope.dictionary = data;
  623. });
  624. // Debug: show manche limits on the map
  625. if($scope.debug) {
  626. L.polygon(mancheCoordinates, {color: 'blue', fillColor: 'blue',weight: 8}).addTo(map);
  627. }
  628. window.map = map;
  629. $scope.mapType = 'Satellite';
  630. $scope.view = {};
  631. $scope.isShown = {};
  632. if($location.search().q) {
  633. $scope.address = $location.search().q;
  634. $scope.suggestLocation($location.search().q);
  635. }
  636. };
  637. var isDate = function(value) {
  638. return (value.toString().length === 8 && value.toString().substr(2, 1) === "/" && value.toString().substr(5,1) === "/");
  639. };
  640. var isInside = function(polygon, point) {
  641. var y = point.x ? point.x : point[0],
  642. x = point.y ? point.y : point[1];
  643. var inside = false;
  644. for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
  645. var xi = polygon[i][0], yi = polygon[i][1];
  646. var xj = polygon[j][0], yj = polygon[j][1];
  647. var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  648. if (intersect) {
  649. inside = !inside;
  650. }
  651. }
  652. return inside;
  653. };
  654. var mysql_real_escape_string = function(str) {
  655. if(typeof str !== 'string') {return str;}
  656. return str.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
  657. switch (char) {
  658. case "\0":
  659. return "\\0";
  660. case "\x08":
  661. return "\\b";
  662. case "\x09":
  663. return "\\t";
  664. case "\x1a":
  665. return "\\z";
  666. case "\n":
  667. return "\\n";
  668. case "\r":
  669. return "\\r";
  670. case "\"":
  671. case "'":
  672. case "\\":
  673. case "%":
  674. return "\\" + char;
  675. }
  676. });
  677. };
  678. var parseData = function(identifier, data, style, properties) {
  679. var getPolygonsCoord = function(type, coord) {
  680. var result = [];
  681. if(type === 'Polygon') {
  682. result.push(_.map(coord[0], function(r) {return [r[1], r[0]];}));
  683. }
  684. if(type === 'MultiPolygon') {
  685. var p = [];
  686. _.each(coord, function(c) {
  687. result.push(_.map(c[0], function(r) {return [r[1], r[0]];}));
  688. });
  689. }
  690. return result;
  691. };
  692. var records = [];
  693. _.each(data.features, function(r) {
  694. var record = r.properties;
  695. var polygons = getPolygonsCoord(r.geometry.type, r.geometry.coordinates);
  696. record._coordinates = r.geometry.coordinates;
  697. record._type = r.geometry.type;
  698. record._polygons = polygons;
  699. record._style = style;
  700. record._properties = properties;
  701. records.push(record);
  702. });
  703. $scope.data[identifier] = records;
  704. };
  705. var parseResults = function(records) {
  706. if(!records || !records.length) {
  707. return null;
  708. }
  709. if(records.length === 1) {
  710. return records[0];
  711. }
  712. var result = records[0];
  713. return result;
  714. };
  715. var reverseLocation = function(geoCode, address, callback) {
  716. var reverseGeo = 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode?f=pjson&distance=300';
  717. var url = reverseGeo + '&location=' + (geoCode ? $scope.geoCode.x + ',' + $scope.geoCode.y : address) ;
  718. $.get(
  719. url,
  720. function(data, status) {
  721. data = JSON.parse(data);
  722. var adresse = data && data.address && data.address.Match_addr;
  723. if(data && data.address && data.address.Address) {
  724. var i = 0;
  725. var num = '';
  726. while(!isNaN(parseInt(data.address.Address[i], 10))) {
  727. num += data.address.Address[i];
  728. i++;
  729. }
  730. data.address.StreetNumber = num;
  731. data.address.Address = data.address.Address.substr(num.length).trim();
  732. var typeVoie = data.address.Address.substring(0, data.address.Address.indexOf(' ')).toLowerCase();
  733. type = _.find(catTypeVoie, function(c){
  734. if(c.id === typeVoie || c.name.toLowerCase() === typeVoie) {
  735. return true;
  736. }
  737. });
  738. if(type) {
  739. data.address.StreetType = type.id;
  740. data.address.Address = data.address.Address.substr(typeVoie.length).trim();
  741. }
  742. }
  743. callback(adresse, data.address);
  744. $scope.$evalAsync();
  745. });
  746. };
  747. $scope.changeMap = function(value) {
  748. map.removeLayer(cLayer);
  749. cLayer = L.tileLayer(maps[value], {
  750. attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
  751. maxZoom: 18
  752. }).addTo(map);
  753. };
  754. $scope.closeRight = function() {
  755. $mdSidenav('right').close().then(function(){});
  756. };
  757. $scope.computeLayer = function(identifier) {
  758. var Lpolygons = [];
  759. _.each($scope.data[identifier], function(record) {
  760. _.each(record._polygons, function(polygon) {
  761. Lpolygons.push(L.polygon(polygon, record._style).bindPopup($scope.getHtmlContent(identifier, record)));
  762. });
  763. });
  764. layer[identifier] = L.layerGroup(Lpolygons);
  765. };
  766. $scope.formatDateFTTH = function(date) {
  767. if(!date || date === "Invalid date") {return;}
  768. var result = '<div class="popup-line"><div class="box-eligibilite-title">Date prévisionnelle abonnement FTTH</div><div style="font-weight: bold;" class="popup-value">' + date + '</div></div>';
  769. return $sce.trustAsHtml(result);
  770. };
  771. $scope.formatResults = function(identifier, results) {
  772. return $sce.trustAsHtml($scope.getHtmlContent(identifier, results));
  773. };
  774. $scope.getGeoCode = function(address, magicKey, callback) {
  775. var findURL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find?f=pjson&searchExtent=' + JSON.stringify(searchExtent);
  776. getGeoCodeInProgress = true;
  777. var url = findURL + "&text=" + address + ((magicKey) ? ("&magicKey=" + magicKey) : ', Basse-Normandie, France');
  778. $.get(
  779. url,
  780. function(data, status) {
  781. data = JSON.parse(data);
  782. if (status === 'success' && data.locations[0]) {
  783. if(data.locations[0].extent.xmax < searchExtent.xmin &&
  784. data.locations[0].extent.xmax > searchExtent.xmax &&
  785. data.locations[0].extent.xmin > searchExtent.xmax &&
  786. data.locations[0].extent.xmin > searchExtent.xmax) {
  787. getGeoCodeInProgress = false;
  788. return callback(null, data);
  789. }
  790. getGeoCodeInProgress = false;
  791. callback('No result for ' + address);
  792. } else {
  793. getGeoCodeInProgress = false;
  794. callback(status !== 'success' ? status : 'No result for ' + address);
  795. }
  796. });
  797. };
  798. $scope.getHtmlContent = function(identifier, record) {
  799. // Tooltip content
  800. var tooltip = '';
  801. _.each(record, function(value, property) {
  802. if(property.charAt(0) === '_' ||
  803. (property === 'date' && identifier === 'ftth') ||
  804. value === null ||
  805. typeof value === 'undefined') {
  806. return;
  807. }
  808. var label = $scope.dictionary[property] || property;
  809. value = $scope.dictionary[value] || value;
  810. var date;
  811. if(property.substring(0, 5) === 'DATE_' && !$scope.dictionary[value] && isDate(value)) {
  812. date = formatDate(value);
  813. }
  814. if(!date || $scope.debug) { // Do not show dates to user otherwise
  815. tooltip += '<div class="popup-line"><div class="popup-label">' + label + '</div><div class="popup-value">' + (date ? date.locale("fr").format('MMMM YYYY') : value) + '</div><div class="popup-small-date">' + (date ? date.locale("fr").fromNow() : '') + '</div></div>';
  816. }
  817. });
  818. if(identifier === 'adsl') {
  819. tooltip = '<a style="float: right;" href="http://www.ariase.com/fr/eligibilite/test.html" target="_blank">Tester mon éligibilité ADSL avec Ariase.com</a>';
  820. }
  821. return tooltip;
  822. };
  823. $scope.hideLayer = function(identifier) {
  824. map.removeLayer(layer[identifier]);
  825. };
  826. $scope.hideResultPane = function() {
  827. if(!$('#result').height()) {return;}
  828. $('#result').animate({height: 0}, 1000);
  829. $('#map').animate({
  830. height: $('body').height(),
  831. }, 1000, function() {
  832. // Animation complete.
  833. map.invalidateSize();
  834. var centerPoint = $scope.geoCode ? new L.LatLng($scope.geoCode.y, $scope.geoCode.x) : stlo;
  835. map.setView(centerPoint, 14);
  836. });
  837. };
  838. $scope.initPopup = function() {
  839. $scope.postForm = null;
  840. getFullAddress(function(err, address) {
  841. if(err) {console.error(err);}
  842. $scope.result = {eligibilite: {}, autres: {}};
  843. $scope.result.eligibilite.geo_code = JSON.stringify($scope.geoCode);
  844. $scope.result.eligibilite.code_postal = address.Postal;
  845. $scope.result.eligibilite.complement_addresse = address.Match_addr;
  846. $scope.result.eligibilite.nom_voie = address.Address;
  847. $scope.result.eligibilite.numero_voie = address.StreetNumber;
  848. $scope.result.eligibilite.type_voie = address.StreetType;
  849. $scope.result.eligibilite.ville = address.City;
  850. });
  851. };
  852. $scope.isFormValid = function() {
  853. if(!$scope.result || !$scope.result.eligibilite) {return;}
  854. var isValid = true;
  855. _.each($scope.formulaires.eligibilite.sections, function(section) {
  856. _.each(section.lines, function(line) {
  857. _.each(line.ctrls, function(ctrl) {
  858. ctrl.invalid = false;
  859. if(ctrl.require && !ctrl.isValid($scope.result.eligibilite[ctrl.id], $scope.result.autres[ctrl.id])) {
  860. isValid = false;
  861. ctrl.invalid = true;
  862. }
  863. });
  864. });
  865. });
  866. return isValid;
  867. };
  868. $scope.refreshInscriptionInfo = function() {
  869. if(!$scope.results.ftth) {return false;}
  870. var dateDeb = moment($scope.results.ftth.DATE_OUV_BUL_PRERACCO, 'DD/MM/YY');
  871. var dateFin = moment($scope.results.ftth.DATE_FERM_BUL_PRERACCO, 'DD/MM/YY');
  872. var now = moment();
  873. var diffDaysDeb = now.diff(dateDeb) / 1000 / 3600 / 24;
  874. var diffDaysFin = now.diff(dateFin) / 1000 / 3600 / 24;
  875. var message = 'Déploiement prévu ultérieurement.';
  876. var isOpen = diffDaysDeb > 0 && (!$scope.results.ftth.DATE_FERM_BUL_PRERACCO || diffDaysFin < 0);
  877. var cas;
  878. if(isOpen) {
  879. message = $scope.results.ftth.DATE_FERM_BUL_PRERACCO ? 'L’inscription au pré-raccordement se termine le ' + dateFin.format('LLL') : '';
  880. cas = 3;
  881. }
  882. else if($scope.results.ftth.DATE_OUV_BUL_PRERACCO && diffDaysDeb < 0) {
  883. message = 'L’inscription au pré-raccordement sera possibe à partir du ' + dateDeb.format('LLL');
  884. cas = 2;
  885. }
  886. else if(dateFin && diffDaysFin > 0) {
  887. message = 'L’inscription au pré-raccordement est terminée. Pour souscrire à une offre internet Très Haut Débit, contactez les fournisseurs d’accès présents sur le réseau:';
  888. cas = 4;
  889. }
  890. else if($scope.results.ftth.DATE_DEB_TRAV_PREV){
  891. var date = moment($scope.results.ftth.DATE_DEB_TRAV_PREV, 'DD/MM/YY').add(12, 'M');
  892. message = ''; // TODO: should be a semester
  893. cas = 5;
  894. }
  895. else {
  896. cas = 1;
  897. }
  898. console.log('Cas ' + cas);
  899. $scope.inscription = {
  900. open : isOpen,
  901. message : message,
  902. cas : cas
  903. };
  904. };
  905. $scope.onSubmitAddress = function($item, $model, $label) {
  906. // Get magic key
  907. var item = _.find($scope.suggestions, {text: $item});
  908. if(!item) {
  909. item = $scope.suggestions[0];
  910. $scope.address = item.text;
  911. }
  912. $scope.magicKey = item.magicKey;
  913. $scope.getGeoCode($scope.address, $scope.magicKey, function(err, data) {
  914. $scope.geoCode = data && data.locations && data.locations[0] && data.locations[0].feature.geometry;
  915. if(err) {console.error('Geocode error', err);}
  916. var toast = toast || {
  917. template: '<md-toast><i class = " md-error"></i> Oups! Aucun résultat trouvé dans la Manche pour: ' + $scope.address + '</md-toast>',
  918. hideDelay: 3000,
  919. position: 'bottom right'
  920. };
  921. if(err || !$scope.geoCode) {
  922. $scope.hideResultPane();
  923. $mdToast.show(toast);
  924. }
  925. if($scope.geoCode) {
  926. addCurrentMarker();
  927. $scope.showResultPane();
  928. getResults();
  929. }
  930. });
  931. };
  932. $scope.postFormEl = function() {
  933. $scope.postForm = {inProgress: true};
  934. // Add ID_ZAPM_PARTIELLE
  935. $scope.result.eligibilite.id_zapm_partielle = $scope.results.ftth.ID_ZAPM_PARTIELLE;
  936. _.each($scope.result.autres, function(value, key) {
  937. $scope.result.eligibilite[key] = value;
  938. });
  939. $scope.$evalAsync();
  940. var keys = '';
  941. var values = '';
  942. _.each($scope.result.eligibilite, function(value, key) {
  943. keys += '`' + key + '`, ';
  944. if(value === 'undefined' || value === undefined) {
  945. value = '';
  946. }
  947. if(key === 'telephone_fixe' || key === 'telephone_portable') {
  948. value = value.replace(/ /g, '').replace(/\./g, '').replace(/-/g, '');
  949. }
  950. if(typeof value === 'boolean') {
  951. values += value + ', ';
  952. }
  953. else {
  954. values += "'" + mysql_real_escape_string(value) + "', ";
  955. }
  956. });
  957. var dateTime = (new Date ((new Date((new Date(new Date())).toISOString() )).getTime() - ((new Date()).getTimezoneOffset()*60000))).toISOString().slice(0, 19).replace('T', ' ');
  958. checkDoublon($scope.result.eligibilite, function(doublon) {
  959. if(doublon) {
  960. $scope.postForm = {error: 'Une demande de pré-raccordement a déjà été effectuée à cette adresse. Pour tout renseignement merci de contacter les services de Manche Numérique au 02.33.77.83.60'};
  961. return $scope.$apply();
  962. }
  963. var query = "INSERT INTO `eligibilite`.`demandes` (`date`," + keys.substring(0, keys.length -2) + ") VALUES ('" + dateTime + "', " + values.substring(0, values.length -2) + ");";
  964. $.ajax({
  965. method : "POST",
  966. url : "ajax/datastores.php",
  967. data : {query: query}
  968. })
  969. .done(function( msg ) {
  970. if(!isNaN(msg)) {
  971. $scope.postForm = {ok: true};
  972. var numDemande = moment().format('YYYYMMDD') + msg;
  973. var body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
  974. body += '<html><body style="font-size: 14px; font-family: calibri;">' +
  975. 'Bonjour ' + $scope.result.eligibilite.prenom + ' ' + $scope.result.eligibilite.nom + ', <br>' +
  976. 'Nous vous confirmons votre demande de pré-raccordement FTTH. <br><br>' +
  977. 'Cette demande porte le numéro: ' +
  978. '<span style="color: #31708f;font-size:17px; font-weight:bold;">' + numDemande + '</span><br><br>' +
  979. 'Voici le détail de votre demande:' +
  980. '<table WIDTH="100%" style="line-height: 40px;" bgColor="#d9edf7" bordercolor="#bce8f1">';
  981. // Numero demande
  982. body += '<tr>';
  983. body += '<th style="width:180px;text-align: left;white-space: nowrap;height: 40px;color: #666;">Numéro demande</th>';
  984. body += '<td>' + numDemande + '</td>';
  985. body += '</tr>';
  986. // Date demande
  987. body += '<tr>';
  988. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Date</th>';
  989. body += '<td>' + moment().lang('fr').format('LLLL') + '</td>';
  990. body += '</tr>';
  991. // Demandeur
  992. body += '<tr>';
  993. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Demandeur</th>';
  994. body += '<td>' + $scope.result.eligibilite.prenom + ' ' + $scope.result.eligibilite.nom + '</td>';
  995. body += '</tr>';
  996. // Email
  997. body += '<tr>';
  998. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Email</th>';
  999. body += '<td>' + $scope.result.eligibilite.email + '</td>';
  1000. body += '</tr>';
  1001. // Adresse
  1002. body += '<tr>';
  1003. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Adresse</th>';
  1004. body += '<td>' + computeFullAddress() + '</td>';
  1005. body += '</tr>';
  1006. // Vous etes
  1007. var cat = _.find(catVousEtes, {id: $scope.result.eligibilite.vous_etes});
  1008. var res = cat && cat.name ? cat.name : $scope.result.eligibilite.vous_etes;
  1009. body += '<tr>';
  1010. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Vous êtes</th>';
  1011. body += '<td>' + res + '</td>';
  1012. body += '</tr>';
  1013. // Ce logement est
  1014. var cat2 = _.find(catCeLogementEst, {id: $scope.result.eligibilite.ce_logement_est});
  1015. var res2 = cat2 && cat2.name ? cat2.name : $scope.result.eligibilite.ce_logement_est;
  1016. body += '<tr>';
  1017. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Ce logement est</th>';
  1018. body += '<td>' + res2 + '</td>';
  1019. body += '</tr>';
  1020. body += '</table><br><br>';
  1021. body += 'Conformément à la loi "informatique et libertés" du 6 janvier 1978 modifiée, vous bénéficiez d’un droit d’accès, de rectification aux informations qui vous concernent, d’opposition au traitement de vos données personnelles. Si vous souhaitez exercer ce droit et obtenir la communication des informations vous concernant, merci de nous contacter :' + '<br>' +
  1022. '<table bgcolor="#ddd" bordercolor="#666">' +
  1023. ' <tr>' +
  1024. ' <th style="width:180px;text-align: left;white-space: nowrap;height: 30px;color: #666;">Email</th><td>' + siteEmail + '</td>' +
  1025. ' </tr><tr>' +
  1026. ' <th style="text-align: left;white-space: nowrap;height: 30px;color: #666;">Adresse</th><td>' + siteAddresse + '</td>' +
  1027. ' </tr><tr>' +
  1028. ' <th style="text-align: left;white-space: nowrap;height: 30px;color: #666;">Tel</th><td>' + siteTel + '</td>' +
  1029. ' </tr>' +
  1030. '</table><br><br>';
  1031. body += 'A bientôt sur: <a href="' + siteUrl + '">' + siteName + '</a></body></html>';
  1032. var mail = {
  1033. to : $scope.result.eligibilite.email,
  1034. sujet : 'Votre demande de pré-raccordement FTTH n° ' + numDemande,
  1035. message: body
  1036. };
  1037. $.ajax({
  1038. method : "POST",
  1039. url : "ajax/datastores.php",
  1040. data : {
  1041. siteEmail: siteEmail,
  1042. mail : mail}
  1043. })
  1044. .done(function( msg ) {
  1045. console.log('Email sent', msg);
  1046. });
  1047. $scope.result.eligibilite = {};
  1048. $scope.autres = {};
  1049. $scope.address = null;
  1050. $scope.magicKey = null;
  1051. }
  1052. else {
  1053. $scope.postForm = {error: msg};
  1054. }
  1055. $scope.hideResultPane();
  1056. $scope.$apply();
  1057. });
  1058. });
  1059. };
  1060. $scope.showLayer = function(identifier) {
  1061. map.addLayer(layer[identifier]);
  1062. };
  1063. $scope.showResultPane = function() {
  1064. var bodyHeight = $('body').height();
  1065. var height = Math.max(300, bodyHeight / 3);
  1066. var heightMap = bodyHeight - height;
  1067. $('#result').animate({height: height + 'px'}, 1000);
  1068. $('#map').animate({
  1069. height: heightMap + 'px',
  1070. }, 1000, function() {
  1071. // Animation complete.
  1072. map.invalidateSize();
  1073. map.setView(new L.LatLng($scope.geoCode.y, $scope.geoCode.x), 18);
  1074. });
  1075. };
  1076. var i = 0, j = 0;
  1077. $scope.suggestLocation = function(val) {
  1078. try {
  1079. var coordinates = JSON.parse(val);
  1080. if(coordinates && coordinates.x) {
  1081. $scope.geoCode = coordinates;
  1082. addCurrentMarker();
  1083. }
  1084. return;
  1085. }
  1086. catch(e) {
  1087. $scope.suggestionsReady = false;
  1088. i++;
  1089. return $http.get(suggestURL, {
  1090. params: {
  1091. text: val
  1092. }
  1093. }).then(function(response) {
  1094. if(val === $scope.address) { // Very important to debounce queries
  1095. $scope.suggestionsReady = response.data.suggestions.length !== 0;
  1096. $scope.suggestions = _.cloneDeep(response.data.suggestions);
  1097. }
  1098. return response.data.suggestions.map(function(item){
  1099. return item.text;
  1100. });
  1101. });
  1102. }
  1103. };
  1104. $scope.toggleResultPane = function() {
  1105. if($('#result').height()) {
  1106. return $scope.hideResultPane();
  1107. }
  1108. if($scope.results && $scope.results.ftth) {
  1109. return $scope.showResultPane();
  1110. }
  1111. };
  1112. $scope.toggleRight = function() {
  1113. $mdSidenav('right').toggle()
  1114. .then(function(){});
  1115. };
  1116. $scope.$watch('view', function(view) {
  1117. if(_.isEmpty(view)) {return;}
  1118. $('#layer-loading').removeClass('force-hidden').find('.md-inner').show();
  1119. setTimeout(function() {
  1120. _.each(view, function(value, key) {
  1121. if($scope.isShown[key] !== value) {
  1122. if(value) {
  1123. if(typeof $scope.isShown[key] !== 'undefined') {
  1124. $scope.showLayer(key);
  1125. $('#layer-loading').find('.md-inner').hide();
  1126. }
  1127. else {
  1128. $timeout(function() {
  1129. $scope.computeLayer(key);
  1130. $scope.showLayer(key);
  1131. $('#layer-loading').find('.md-inner').hide();
  1132. }, 500);
  1133. }
  1134. }
  1135. else {
  1136. $scope.hideLayer(key);
  1137. setTimeout(function() {
  1138. $('#layer-loading').find('.md-inner').hide();
  1139. }, 1000);
  1140. }
  1141. $scope.isShown[key] = value;
  1142. }
  1143. });
  1144. });
  1145. }, true);
  1146. $(window).resize(function() {
  1147. if(!$('#result').height()) {return;}
  1148. $scope.showResultPane();
  1149. });
  1150. init();
  1151. });