script.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. var widths = [12, 13, 13, 13, 13, 13, 13, 13];
  2. var opas = [0.8, 0.6, 0.5, 0.5, 0.4];
  3. var mwidths = [1, 1, 1, 1.5, 2, 3, 5, 6, 6, 4, 3, 2];
  4. var stCols = ['#78f378', '#0000c3', 'red'];
  5. var osmUrl = "//www.openstreetmap.org/";
  6. var grIdx, stIdx, selectedRes, prevSearch, delayTimer;
  7. var reqs = {};
  8. var openedGr = -1;
  9. var openedSt = -1;
  10. var sgMvOrNew = "Move into a <span class='grouplink' onmouseover='grHl(${tid})' onmouseout='grUnHl(${tid})'>new relation</span> <tt>public_transport=stop_area</tt>.";
  11. var sgMvOrEx = "Move into relation <a onmouseover='grHl(${tid})' onmouseout='grUnHl(${tid})' href=\"" + osmUrl + "relation/${toid}\" target=\"_blank\">${toid}</a>.";
  12. var sgMvRelNew = "Move from relation <a onmouseover='grHl(${oid})' onmouseout='grUnHl(${oid})' href=\"" + osmUrl + "relation/${ooid}\" target=\"_blank\">${ooid}</a> into a <span class='grouplink' onmouseover='grHl(${tid})' onmouseout='grUnHl(${tid})'>new relation</span> <tt>public_transport=stop_area</tt>.";
  13. var sgMvRelRel = "Move from relation <a onmouseover='grHl(${oid})' onmouseout='grUnHl(${oid})' href=\"" + osmUrl + "relation/${ooid}\" target=\"_blank\">${ooid}</a> into relation <a onmouseover='grHl(${tid})' onmouseout='grUnHl(${tid})' href=\"" + osmUrl + "relation/${toid}\" target=\"_blank\">${toid}</a>.";
  14. var sgMvOutRel = "Move out of relation <a onmouseover='grHl(${oid})' onmouseout='grUnHl(${oid})' href=\"" + osmUrl + "relation/${ooid}\" target=\"_blank\">${ooid}</a>";
  15. var sgFixAttr = "Fix attribute <tt>${attr}</tt>.";
  16. var sgAddName = "Consider adding a <tt><a target='_blank' href='https://wiki.openstreetmap.org/wiki/Key:name'>name</a></tt> attribute.";
  17. var sgAttrTr = "Attribute <tt>${attr}</tt> seems to be a track number. Use <tt>ref</tt> for this and set <tt>${attr}</tt> to the station name.";
  18. var suggsMsg = [sgMvOrNew, sgMvOrEx, sgMvRelNew, sgMvRelRel, sgMvOutRel, sgFixAttr, sgAddName, sgAttrTr];
  19. function $(a){return a[0] == "#" ? document.getElementById(a.substr(1)) : a[0] == "." ? document.getElementsByClassName(a.substr(1)) : document.getElementsByTagName(a)}
  20. function $$(t){return document.createElement(t) }
  21. function ll(g){return {"lat" : g[0], "lng" : g[1]}}
  22. function hasCl(e, c){return e.className.split(" ").indexOf(c) != -1}
  23. function addCl(e, c){if (!hasCl(e, c)) e.className += " " + c;e.className = e.className.trim()}
  24. function delCl(e, c){var a = e.className.split(" "); delete a[a.indexOf(c)]; e.className = a.join(" ").trim()}
  25. function stCol(s){return s.e ? stCols[2] : s.s ? stCols[1] : stCols[0]}
  26. function tmpl(s, r){for (var p in r) s = s.replace(new RegExp("\\${" + p + "}", "g"), r[p]); return s}
  27. function req(id, u, cb) {
  28. if (reqs[id]) reqs[id].abort();
  29. reqs[id] = new XMLHttpRequest();
  30. reqs[id].onreadystatechange = function() { if (this.readyState == 4 && this.status == 200 && this == reqs[id]) cb(JSON.parse(this.responseText))};
  31. reqs[id].open("GET", u, 1);
  32. reqs[id].send();
  33. }
  34. function marker(stat, z) {
  35. if (stat.g.length == 1) {
  36. if (z > 15) {
  37. return L.circle(
  38. stat.g[0], {
  39. color: '#000',
  40. fillColor: stCol(stat),
  41. radius: mwidths[23 - z],
  42. fillOpacity: 1,
  43. weight: z > 17 ? 1.5 : 1,
  44. id: stat.i
  45. }
  46. );
  47. } else {
  48. return L.polyline(
  49. [stat.g[0], stat.g[0]], {
  50. color: stCol(stat),
  51. fillColor: stCol(stat),
  52. weight: widths[15 - z],
  53. opacity: opas[15 - z],
  54. id: stat.i
  55. }
  56. );
  57. }
  58. } else {
  59. return L.polygon(
  60. stat.g, {
  61. color: z > 15 ? '#000': stCol(stat),
  62. fillColor: stCol(stat),
  63. smoothFactor: 0,
  64. fillOpacity: 0.75,
  65. weight: z > 17 ? 1.5 : 1,
  66. id: stat.i
  67. }
  68. );
  69. }
  70. }
  71. function poly(group, z) {
  72. var col = group.e ? 'red' : group.s ? '#0000c3' : '#85f385';
  73. var style = {
  74. color: col,
  75. fillColor: col,
  76. smoothFactor: 0.4,
  77. fillOpacity: 0.2,
  78. id: group.i
  79. };
  80. if (z < 16) {
  81. style.weight = 11;
  82. style.opacity = 0.5;
  83. style.fillOpacity = 0.5;
  84. }
  85. return L.polygon(group.g, style)
  86. }
  87. function sugArr(sug, z) {
  88. return L.polyline(sug.a, {
  89. id: sug.i,
  90. color: '#0000c3',
  91. smoothFactor: 0.1,
  92. weight: 4,
  93. opacity: 0.5
  94. });
  95. }
  96. function rndrSt(stat) {
  97. openedSt = stat.id;
  98. stHl(stat.id);
  99. var attrrows = {};
  100. var way = stat.osmid < 0;
  101. var osmid = Math.abs(stat.osmid);
  102. var ident = way ? "Way" : "Node";
  103. var con = $$('div');
  104. con.setAttribute("id", "nav")
  105. var suggD = $$('div');
  106. suggD.setAttribute("id", "sugg")
  107. con.innerHTML = ident + " <a target='_blank' href='" + osmUrl + ident.toLowerCase()+"/" + osmid + "'>" + osmid + "</a>";
  108. if (stat.attrs.name) con.innerHTML += " (<b>\"" + stat.attrs.name + "\"</b>)";
  109. con.innerHTML += "<a class='ebut' target='_blank' href='" + osmUrl + ident.toLowerCase() + "=" + osmid +"'>&#9998;</a>";
  110. var attrTbl = $$('table');
  111. attrTbl.setAttribute("id", "attr-tbl")
  112. con.appendChild(attrTbl);
  113. con.appendChild(suggD);
  114. var tbody = $$('tbody');
  115. attrTbl.appendChild(tbody);
  116. for (var key in stat.attrs) {
  117. var row = $$('tr');
  118. var col1 = $$('td');
  119. var col2 = $$('td');
  120. addCl(col2, "err-wrap");
  121. tbody.appendChild(row);
  122. row.appendChild(col1);
  123. row.appendChild(col2);
  124. col1.innerHTML = "<a href=\"https://wiki.openstreetmap.org/wiki/Key:" + key + "\" target=\"_blank\"><tt>" + key + "</tt></a>";
  125. for (var i = 0; i < stat.attrs[key].length; i++) col2.innerHTML += "<span class='attrval'>" + stat.attrs[key][i] + "</span>" + "<br>";
  126. attrrows[key] = row;
  127. }
  128. for (var i = 0; i < stat.attrerrs.length; i++) {
  129. var err = stat.attrerrs[i];
  130. var row = attrrows[err.attr[0]];
  131. addCl(row, "err-" + Math.round(err.conf * 10));
  132. var info = $$('div');
  133. if (err.other_grp) {
  134. // the mismatch was with a group name
  135. if (err.other_osmid > 1) info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in relation <a onmouseover='grHl( " + err.other_grp + ")' onmouseout='grUnHl( " + err.other_grp + ")' target=\"_blank\" href=\"" + osmUrl + "relation/" + Math.abs(err.other_osmid) + "\">" + Math.abs(err.other_osmid) + "</a>";
  136. else info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in relation <span onmouseover='grHl( " + err.other_grp + ")' onmouseout='grUnHl( " + err.other_grp + ")'>" + Math.abs(err.other_osmid) + "</span>";
  137. } else {
  138. // the mismatch was with another station
  139. if (err.other_osmid != stat.osmid) {
  140. var lident = err.other_osmid < 0 ? "way" : "node";
  141. info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in " + lident + " <a onmouseover='stHl( " + err.other + ")' onmouseout='stUnHl( " + err.other + ")' target=\"_blank\" href=\"" + osmUrl + lident+"/" + Math.abs(err.other_osmid) + "\">" + Math.abs(err.other_osmid) + "</a>";
  142. } else {
  143. info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> = '" + err.other_attr[1] + "'";
  144. }
  145. }
  146. addCl(info, 'attr-err-info');
  147. row.childNodes[1].appendChild(info);
  148. }
  149. var suggList = $$('ul');
  150. if (stat.su.length) {
  151. var a = $$('span');
  152. addCl(a, "sugtit");
  153. a.innerHTML = "Suggestions";
  154. suggD.appendChild(a);
  155. }
  156. suggD.appendChild(suggList);
  157. for (var i = 0; i < stat.su.length; i++) {
  158. var sg = stat.su[i];
  159. var sgDiv = $$('li');
  160. sgDiv.innerHTML = tmpl(suggsMsg[sg.type - 1], {"attr" : sg.attr, "tid" : sg.target_gid, "ooid" : sg.orig_osm_rel_id, "toid" : sg.target_osm_rel_id, "oid" : sg.orig_gid});
  161. suggList.appendChild(sgDiv);
  162. }
  163. L.popup({opacity: 0.8})
  164. .setLatLng(stat)
  165. .setContent(con)
  166. .openOn(map)
  167. .on('remove', function() {openedSt = -1; stUnHl(stat.id);});
  168. }
  169. function openSt(id) {req("s", "/stat?id=" + id, function(c) {rndrSt(c)});}
  170. function rndrGr(grp, ll) {
  171. openedGr = grp.id;
  172. var attrrows = {};
  173. grHl(grp.id);
  174. var con = $$('div');
  175. con.setAttribute("id", "nav");
  176. var newMembers = $$('div');
  177. newMembers.setAttribute("id", "group-stations-new")
  178. newMembers.innerHTML = "<span class='newmemberstit'>New Members</span>";
  179. var oldMembers = $$('div');
  180. oldMembers.setAttribute("id", "group-stations-old")
  181. oldMembers.innerHTML = "<span class='oldmemberstit'>Existing Members</span>";
  182. if (grp.osmid == 1) {
  183. con.innerHTML = "<span class='grouplink'>New relation</span> <tt>public_transport=stop_area</tt>";
  184. } else {
  185. con.innerHTML = "OSM relation <a target='_blank' href='https://www.openstreetmap.org/relation/" + grp.osmid + "'>" + grp.osmid + "</a>";
  186. if (grp.attrs.name) con.innerHTML += " (<b>\"" + grp.attrs.name + "\"</b>)";
  187. con.innerHTML += "<a class='ebut' target='_blank' href='https://www.openstreetmap.org/edit?relation=" + grp.osmid +"'>&#9998;</a>";
  188. }
  189. var attrTbl = $$('table');
  190. attrTbl.setAttribute("id", "attr-tbl")
  191. con.appendChild(attrTbl);
  192. var tbody = $$('tbody');
  193. attrTbl.appendChild(tbody);
  194. var suggD = $$('div');
  195. suggD.setAttribute("id", "sugg")
  196. for (var key in grp.attrs) {
  197. var row = $$('tr');
  198. var col1 = $$('td');
  199. var col2 = $$('td');
  200. addCl(col2, "err-wrap");
  201. tbody.appendChild(row);
  202. row.appendChild(col1);
  203. row.appendChild(col2);
  204. col1.innerHTML = "<a href=\"https://wiki.openstreetmap.org/wiki/Key:" + key + "\" target=\"_blank\"><tt>" + key + "</tt></a>";
  205. for (var i = 0; i < grp.attrs[key].length; i++) col2.innerHTML += "<span class='attrval'>" + grp.attrs[key][i] + "</span>" + "<br>";
  206. attrrows[key] = row;
  207. }
  208. for (var i = 0; i < grp.attrerrs.length; i++) {
  209. var err = grp.attrerrs[i];
  210. var row = attrrows[err.attr[0]];
  211. addCl(row, "err-" + Math.round(err.conf * 10));
  212. var info = $$('div');
  213. if (err.other_grp) {
  214. // the mismatch was with a group name
  215. if (err.other_osmid != grp.osmid) {
  216. if (err.other_osmid > 1) info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in relation <a onmouseover='grHl( " + err.other_grp + ")' onmouseout='grUnHl( " + err.other_grp + ")' target=\"_blank\" href=\"" + osmUrl + "relation/" + Math.abs(err.other_osmid) + "\">" + Math.abs(err.other_osmid) + "</a>";
  217. else info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in relation <span onmouseover='grHl( " + err.other_grp + ")' onmouseout='grUnHl( " + err.other_grp + ")'>" + Math.abs(err.other_osmid) + "</span>";
  218. } else info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> = '" + err.other_attr[1] + "'";
  219. } else {
  220. // the mismatch was with another station
  221. var ident = err.other_osmid < 0 ? "way" : "node";
  222. info.innerHTML = "Does not match <tt>" + err.other_attr[0] + "</tt> in " + ident + " <a onmouseover='stHl( " + err.other + ")' onmouseout='stUnHl( " + err.other + ")' target=\"_blank\" href=\"" + osmUrl + ident+"/" + Math.abs(err.other_osmid) + "\">" + Math.abs(err.other_osmid) + "</a>";
  223. }
  224. addCl(info, 'attr-err-info');
  225. row.childNodes[1].appendChild(info);
  226. }
  227. con.appendChild(newMembers);
  228. if (grp.osmid != 1) con.appendChild(oldMembers);
  229. for (var key in grp.stations) {
  230. var stat = grp.stations[key];
  231. var row = $$('div');
  232. var ident = stat.osmid < 0 ? "Way" : "Node";
  233. row.innerHTML = ident + " <a onmouseover='stHl( " + stat.id + ")' onmouseout='stUnHl( " + stat.id + ")' target='_blank' href='" + osmUrl + ident.toLowerCase() + "/" + Math.abs(stat.osmid) + "'>" + Math.abs(stat.osmid) + "</a>";
  234. if (stat.attrs.name) row.innerHTML += " (<b>\"" + stat.attrs.name + "\"</b>)";
  235. row.style.backgroundColor = stat.e ? '#f58d8d' : stat.s ? '#b6b6e4' : '#c0f7c0';
  236. if (grp.osmid == 1 || stat.orig_group != grp.id) newMembers.appendChild(row);
  237. else {
  238. oldMembers.appendChild(row);
  239. if (stat.group != grp.id) addCl(row, "del-stat");
  240. }
  241. }
  242. var suggList = $$('ul');
  243. if (grp.su.length) {
  244. var a = $$('span');
  245. addCl(a, "sugtit");
  246. a.innerHTML = "Suggestions";
  247. suggD.appendChild(a);
  248. }
  249. suggD.appendChild(suggList);
  250. for (var i = 0; i < grp.su.length; i++) {
  251. var sugg = grp.su[i];
  252. var suggDiv = $$('li');
  253. if (sugg.type == 6) suggDiv.innerHTML = "Fix attribute <tt>" + sugg.attr + "</tt>.";
  254. else if (sugg.type == 7) suggDiv.innerHTML = "Consider adding a <tt><a target='_blank' href='https://wiki.openstreetmap.org/wiki/Key:name'>name</a></tt> attribute.";
  255. else if (sugg.type == 8) suggDiv.innerHTML = "Attribute <tt>" + sugg.attr + "</tt> seems to be a track number. Use <tt>ref</tt> for this and set <tt>" + sugg.attr + "</tt> to the station name.";
  256. suggList.appendChild(suggDiv);
  257. }
  258. con.appendChild(suggD);
  259. L.popup({opacity: 0.8})
  260. .setLatLng(ll)
  261. .setContent(con)
  262. .openOn(map)
  263. .on('remove', function() {openedGr = -1; grUnHl(grp.id)});
  264. }
  265. function openGr(id, ll) {
  266. req("g", "/group?id=" + id, function(c) {rndrGr(c, ll)});
  267. }
  268. function grHl(id) {
  269. !grIdx[id] || grIdx[id].setStyle({'weight': 6, 'color': "#eecc00"});
  270. }
  271. function grUnHl(id) {
  272. !grIdx[id] || grIdx[id].setStyle({
  273. 'weight': 3,
  274. 'color': grIdx[id].options["fillColor"]
  275. });
  276. }
  277. function stHl(id) {
  278. if (!stIdx[id]) return;
  279. if (map.getZoom() > 15) {
  280. stIdx[id].setStyle({
  281. 'weight': 5,
  282. 'color': "#eecc00"
  283. });
  284. } else {
  285. stIdx[id].setStyle({
  286. 'color': "#eecc00"
  287. });
  288. }
  289. }
  290. function stUnHl(id) {
  291. if (!stIdx[id]) return;
  292. if (map.getZoom() > 15) {
  293. stIdx[id].setStyle({
  294. 'weight': map.getZoom() > 17 ? 1.5 : 1,
  295. 'color': "#000"
  296. });
  297. } else {
  298. stIdx[id].setStyle({
  299. 'color': stIdx[id].options["fillColor"]
  300. });
  301. }
  302. }
  303. var map = L.map('m', {renderer: L.canvas(), attributionControl: false}).setView([47.9965, 7.8469], 13);
  304. map.addControl(L.control.attribution({
  305. position: 'bottomright',
  306. prefix: '&copy; <a href="http://ad.cs.uni-freiburg.de">University of Freiburg, Chair of Algorithms and Data Structures</a>'
  307. }));
  308. map.on('popupopen', function(e) {
  309. var px = map.project(e.target._popup._latlng);
  310. px.y -= e.target._popup._container.clientHeight/2;
  311. map.panTo(map.unproject(px),{animate: true});
  312. s();
  313. });
  314. L.tileLayer('http://{s}.tile.stamen.com/toner-lite/{z}/{x}/{y}.png', {
  315. maxZoom: 20,
  316. attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
  317. opacity: 0.8
  318. }).addTo(map);
  319. var l = L.featureGroup().addTo(map);
  320. map.on("moveend", function() {render();});
  321. map.on("click", function() {s()});
  322. function render() {
  323. if (map.getZoom() < 11) {
  324. var b = map.getBounds();
  325. var sw = b.getSouthWest();
  326. var ne = b.getNorthEast();
  327. req("m", "/heatmap?z=" + map.getZoom() + "&bbox=" + [sw.lat, sw.lng, ne.lat, ne.lng].join(","),
  328. function(re) {
  329. l.clearLayers();
  330. var blur = 22 - map.getZoom();
  331. var rad = 25 - map.getZoom();
  332. l.addLayer(L.heatLayer(re.ok, {
  333. max: 500,
  334. gradient: {
  335. 0: '#cbf7cb',
  336. 0.5: '#78f378',
  337. 1: '#29c329'
  338. },
  339. minOpacity: 0.65,
  340. blur: blur,
  341. radius: rad
  342. }));
  343. l.addLayer(L.heatLayer(re.sugg, {
  344. max: 500,
  345. gradient: {
  346. 0: '#7f7fbd',
  347. 0.5: '#4444b3',
  348. 1: '#0606c1'
  349. },
  350. minOpacity: 0.65,
  351. blur: blur - 3,
  352. radius: Math.min(12, rad - 3)
  353. }));
  354. l.addLayer(L.heatLayer(re.err, {
  355. max: 500,
  356. gradient: {
  357. 0: '#f39191',
  358. 0.5: '#ff5656',
  359. 1: '#ff0000'
  360. },
  361. minOpacity: 0.75,
  362. blur: blur - 3,
  363. radius: Math.min(10, rad - 3),
  364. maxZoom: 15
  365. }));
  366. }
  367. )
  368. } else {
  369. req("m", "/map?z=" + map.getZoom() + "&bbox=" + [map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng].join(","),
  370. function(re) {
  371. l.clearLayers();
  372. grIdx = {};
  373. stIdx = {};
  374. var stats = [];
  375. for (var i = 0; i < re.stats.length; i++) {
  376. stIdx[re.stats[i].i] = stats[stats.push(marker(re.stats[i], map.getZoom())) - 1];
  377. }
  378. var groups = [];
  379. for (var i = 0; i < re.groups.length; i++) {
  380. grIdx[re.groups[i].i] = groups[groups.push(poly(re.groups[i], map.getZoom())) - 1];;
  381. }
  382. var suggs = [];
  383. for (var i = 0; i < re.su.length; i++) {
  384. suggs.push(sugArr(re.su[i], map.getZoom()));
  385. }
  386. if (map.getZoom() > 13) {
  387. l.addLayer(L.featureGroup(groups).on('click', function(a) {
  388. openGr(a.layer.options.id, a.layer.getBounds().getCenter());
  389. }));
  390. }
  391. l.addLayer(L.featureGroup(stats).on('click', function(a) {
  392. openSt(a.layer.options.id);
  393. }));
  394. if (map.getZoom() > 15) {
  395. l.addLayer(L.featureGroup(suggs).on('click', function(a) {
  396. openSt(a.layer.options.id);
  397. }));
  398. }
  399. grHl(openedGr);
  400. stHl(openedSt);
  401. }
  402. )
  403. };
  404. }
  405. function rowClick(row) {
  406. if (!isSearchOpen()) return;
  407. if (row.stat) openSt(row.stat.i, ll(row.stat.g[0]));
  408. else openGr(row.group.i, ll(row.group.g[0]));
  409. }
  410. function select(row) {
  411. if (!row) return;
  412. if (!isSearchOpen()) return;
  413. unselect(selectedRes);
  414. selectedRes = row;
  415. addCl(row, "selres");
  416. if (row.stat) stHl(row.stat.i);
  417. if (row.group) grHl(row.group.i);
  418. }
  419. function unselect(row) {
  420. selectedRes = undefined;
  421. if (!row) return;
  422. delCl(row, "selres");
  423. if (row.stat) stUnHl(row.stat.i);
  424. if (row.group) grUnHl(row.group.i);
  425. }
  426. function isSearchOpen() {
  427. return $("#sres").className == "res-open";
  428. }
  429. function s(q) {
  430. var delay = 0;
  431. if (q == prevSearch) return;
  432. clearTimeout(delayTimer);
  433. prevSearch = q;
  434. unselect(selectedRes);
  435. if (!q) {
  436. $('#si').value = "";
  437. $("#sres").className = "";
  438. return;
  439. }
  440. delayTimer = setTimeout(function() {
  441. req("sr", "/search?q=" + q, function(c) {
  442. var res = $("#sres");
  443. addCl(res, "res-open");
  444. res.innerHTML = "";
  445. for (var i = 0; i < c.length; i++) {
  446. var e = c[i];
  447. var row = $$('span');
  448. addCl(row, "sres");
  449. row.innerHTML = e.n;
  450. if (e.w) addCl(row, "res-way");
  451. if (e.s) {
  452. row.stat = e.s;
  453. addCl(row, "res-stat");
  454. if (e.s.s) addCl(row, "res-sugg");
  455. if (e.s.e) addCl(row, "res-err");
  456. } else {
  457. row.group = e.g;
  458. addCl(row, "res-group");
  459. if (e.g.s) addCl(row, "res-sugg");
  460. if (e.g.e) addCl(row, "res-err");
  461. }
  462. row.onmouseover = function(){select(this)};
  463. row.onclick = function(){rowClick(this)};
  464. if (e.v && e.v != e.name) {
  465. var via = $$('span');
  466. addCl(via, "via");
  467. via.innerHTML = e.v;
  468. row.appendChild(via);
  469. }
  470. res.appendChild(row);
  471. }
  472. }
  473. )}, delay);
  474. }
  475. function kp(e) {
  476. if (e.keyCode == 40) {
  477. var sels = $('.selres')
  478. if (sels.length) select(sels[0].nextSibling);
  479. else select($('.sres')[0]);
  480. e.preventDefault();
  481. } else if (e.keyCode == 38) {
  482. var sels = $('.selres')
  483. if (sels.length) {
  484. if (sels[0].previousSibling) select(sels[0].previousSibling);
  485. else unselect(sels[0]);
  486. e.preventDefault();
  487. }
  488. }
  489. if (e.keyCode == 13) {
  490. var sels = $('.selres');
  491. if (sels.length) rowClick(sels[0]);
  492. }
  493. }
  494. $('#del').onclick = function() {s();$("#si").focus()}
  495. render();