1 /* Copyright (c) 2009 Arnaud Renevier, Inc, published under the modified BSD
4 // drag feature with tolerance
5 OpenLayers.Control.SypDragFeature = OpenLayers.Class (OpenLayers.Control.DragFeature, {
11 downFeature: function(pixel) {
12 OpenLayers.Control.DragFeature.prototype.downFeature.apply(this, arguments);
13 this.dragStart = (new Date()).getTime();
14 this.startPixel = pixel;
17 doneDragging: function(pixel) {
18 OpenLayers.Control.DragFeature.prototype.doneDragging.apply(this, arguments);
20 var passesTimeTolerance =
21 (new Date()).getTime() > this.dragStart + this.timeTolerance;
23 var xDiff = this.startPixel.x - pixel.x;
24 var yDiff = this.startPixel.y - pixel.y;
26 var passesPixelTolerance =
27 Math.sqrt(Math.pow(xDiff,2) + Math.pow(yDiff,2)) > this.pixelTolerance;
29 if(passesTimeTolerance && passesPixelTolerance){
30 this.onComplete(this.feature, pixel);
32 var feature = this.feature;
33 var res = this.map.getResolution();
34 this.feature.geometry.move(res * (this.startPixel.x - this.lastPixel.x),
35 res * (this.lastPixel.y - this.startPixel.y));
36 this.layer.drawFeature(this.feature);
38 this.layer.drawFeature(this.feature, "select");
41 moveFeature: function(pixel) {
42 OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this, arguments);
43 this.layer.drawFeature(this.feature, "temporary");
46 overFeature: function (feature) {
47 // can only drag and drop currently selected feature
48 if (feature != Admin.currentFeature) {
51 OpenLayers.Control.DragFeature.prototype.overFeature.apply(this, arguments);
54 CLASS_NAME: "OpenLayers.Control.SypDragFeature"
59 MARKER_ICON: "media/marker-normal.png",
60 MARKER_SELECT_ICON: "media/marker-selected.png",
61 MARKER_TEMPORARY_ICON: "media/marker-temp.png",
68 selFeatureControl: null,
69 moveFeatureControl: null,
70 addFeatureControl: null,
73 currentFeatureLocation: null,
76 this.map = new OpenLayers.Map ("map", {
78 new OpenLayers.Control.Navigation (),
79 new OpenLayers.Control.PanZoom ()
81 projection: new OpenLayers.Projection("EPSG:900913"),
82 displayProjection: new OpenLayers.Projection("EPSG:4326")
85 this.baseLayer = this.createBaseLayer ();
86 this.dataLayer = this.createDataLayer ();
87 this.map.addLayers([this.baseLayer, this.dataLayer]);
90 this.selFeatureControl = this.createSelectFeatureControl();
91 this.map.addControl(this.selFeatureControl);
92 this.moveFeatureControl = this.createMoveFeatureControl();
93 this.map.addControl(this.moveFeatureControl);
94 this.addFeatureControl = this.createNewfeatureControl();
95 this.map.addControl(this.addFeatureControl);
98 var centerBounds = new OpenLayers.Bounds();
100 var mapProj = this.map.getProjectionObject();
101 var sypOrigProj = new OpenLayers.Projection("EPSG:4326");
103 var bottomLeft = new OpenLayers.LonLat(sypOrig[0],sypOrig[1]);
104 bottomLeft = bottomLeft.transform(sypOrigProj, mapProj);
105 var topRight = new OpenLayers.LonLat(sypOrig[2],sypOrig[3])
106 topRight = topRight.transform(sypOrigProj, mapProj);
108 centerBounds.extend(bottomLeft);
109 centerBounds.extend(topRight);
111 // at that moment, ie does not know size of the map, we need to update
113 this.map.updateSize();
114 this.map.zoomToExtent(centerBounds);
120 this.addFeatureControl.deactivate();
121 this.moveFeatureControl.deactivate();
122 this.selFeatureControl.activate();
123 this.checkForFeatures();
124 $("#newfeature_button").show().val(SypStrings.AddItem);
125 $("#newfeature_button").unbind("click").click(function () {
126 Admin.addNewFeature();
130 createBaseLayer: function () {
131 return new OpenLayers.Layer.OSM("OSM");
134 createDataLayer: function () {
135 var styleMap = new OpenLayers.StyleMap (
137 externalGraphic: this.Settings.MARKER_ICON,
138 graphicHeight: this.Settings.MARKER_HEIGHT || 32
141 externalGraphic: this.Settings.MARKER_TEMPORARY_ICON,
142 graphicHeight: this.Settings.MARKER_HEIGHT || 32
145 externalGraphic: this.Settings.MARKER_SELECT_ICON,
146 graphicHeight: this.Settings.MARKER_HEIGHT || 32
149 var layer = new OpenLayers.Layer.GML("KML", "items.php",
152 format: OpenLayers.Format.KML,
153 projection: this.map.displayProjection,
154 eventListeners: { scope: this,
155 loadend: this.checkForFeatures
162 createMoveFeatureControl: function () {
163 var control = new OpenLayers.Control.SypDragFeature(
169 createSelectFeatureControl: function () {
170 var control = new OpenLayers.Control.SelectFeature(
172 onSelect: OpenLayers.Function.bind(this.onFeatureSelect, this)
177 createNewfeatureControl: function () {
178 var control = new OpenLayers.Control ();
179 var handler = new OpenLayers.Handler.Click(control, {
180 'click': OpenLayers.Function.bind(FeatureMgr.add, FeatureMgr)
182 control.handler = handler;
186 onFeatureSelect: function (feature) {
187 this.showEditor(feature);
189 this.selFeatureControl.deactivate();
190 this.moveFeatureControl.activate();
193 closeEditor: function() {
194 if (this.currentFeature && this.currentFeature.layer) {
195 this.selFeatureControl.unselect(this.currentFeature);
197 this.currentFeature = null;
198 this.currentFeatureLocation = null;
199 $("#img").removeAttr('src');
200 $("#img").parent().html($("#img").parent().html());
201 $("#img").parent().show();
202 $("#title, #description").val("");
204 // do it once before hidding and once after hidding to work in all cases
205 $("#title, #description").val("");
206 $("#image_file").parent().html($("#image_file").parent().html());
207 $(document).unbind("keydown");
208 this.checkForFeatures();
212 showEditor: function (feature) {
213 $("#newfeature_button").hide();
219 $(document).unbind("keydown").keydown(function(e) {
220 if (e.keyCode == 27) {
221 Admin.cancelCurrentFeature()
225 this.currentFeature = feature;
226 this.currentFeatureLocation = new OpenLayers.Pixel(feature.geometry.x, feature.geometry.y);
228 $("#instructions").text(SypStrings.DragDropHowto);
229 $("#title").val(feature.attributes.name);
230 var fullDesc = $(feature.attributes.description).parent();
231 $("#description").val(fullDesc.find('p').text());
232 var src = fullDesc.find('img').attr('src');
234 $("#img").parent().show();
235 $("#img").attr('src', src);
236 $("#image_file").parent().hide();
237 $("#image_delete").show();
239 $("#img").parent().hide();
240 $("#image_file").parent().show();
241 $("#image_delete").hide();
243 $("#title").select().focus();
246 checkForFeatures: function () {
247 if (this.dataLayer.features.length != 0) {
248 $("#instructions").text(SypStrings.SelectHowto);
252 addNewFeature: function () {
253 alert (SypStrings.DisabledForDemo);
256 $(document).unbind("keydown");
259 $(document).unbind("keydown").keydown(function(e) {
260 if (e.keyCode == 27) {
266 $("#newfeature_button").val("annuler");
267 $("#newfeature_button").unbind("click").click(cancel);
269 $("#instructions").text(SypStrings.AddHowto);
270 this.selFeatureControl.deactivate();
271 this.addFeatureControl.activate();
275 cancelCurrentFeature: function() {
276 if (AjaxMgr.running) {
279 var feature = this.currentFeature;
281 FeatureMgr.move (feature, this.currentFeatureLocation);
283 this.dataLayer.removeFeatures([feature]);
288 reloadLayer: function (layer) {
289 layer.destroyFeatures();
290 layer.loaded = false;
295 escapeHTML: function (str) {
300 replace(/&/gm, '&').
301 replace(/'/gm, ''').
302 replace(/"/gm, '"').
303 replace(/>/gm, '>').
304 replace(/</gm, '<');
307 startsWith: function (str, prefix) {
308 return (str.slice(0, prefix.length) == prefix);
311 indexOf: function (array, item) {
312 if (array.indexOf !== undefined) {
313 return array.indexOf(item);
315 return OpenLayers.Util.indexOf(array, item);
328 var pos = map.getLonLatFromViewPortPx(evt.xy);
329 feature = this.update (null, pos, "", "", "");
330 Admin.addFeatureControl.deactivate();
331 Admin.selFeatureControl.select(feature);
334 move: function (feature, aLocation) {
335 if (!feature || !aLocation) {
338 var curLoc = feature.geometry;
339 feature.geometry.move(aLocation.x - curLoc.x, aLocation.y - curLoc.y);
340 feature.layer.drawFeature(feature);
343 update: function(feature, lonlat, imgurl, title, description) {
344 var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
346 feature = new OpenLayers.Feature.Vector(point);
347 Admin.dataLayer.addFeatures([feature]);
349 this.move (feature, point);
351 feature.attributes.name = title;
352 feature.attributes.description = "<p>" + Admin.Utils.escapeHTML(description) + "</p>"
353 + "<img src=\"" + imgurl + "\">"
357 del: function (feature) {
358 alert (SypStrings.DisabledForDemo);
360 var form = $("#feature_delete");
361 form.find('input[name="fid"]').val(feature.fid);
364 oncomplete: OpenLayers.Function.bind(this.ajaxReply, this),
365 onsend: function() { $("#editor_throbber").css("visibility", "visible"); }
369 save: function (feature) {
370 var x = feature.geometry.x;
371 var y = feature.geometry.y;
373 var mapProj = feature.layer.map.getProjectionObject();
374 var lonlat = new OpenLayers.LonLat(x, y).
376 new OpenLayers.Projection("EPSG:4326"));
377 var form = $("#feature_update");
378 form.find('input[name="lon"]').val(lonlat.lon);
379 form.find('input[name="lat"]').val(lonlat.lat);
380 form.find('input[name="fid"]').val(feature.fid);
381 form.find('input[name="keep_img"]').val(
382 $("#img").attr("src") ? "yes": "no"
386 form.find('input[name="request"]').val("update");
388 form.find('input[name="request"]').val("add");
392 oncomplete: OpenLayers.Function.bind(this.ajaxReply, this),
393 onsend: function() { $("#editor_throbber").css("visibility", "visible"); }
397 ajaxReply: function (data) {
398 $("#editor_throbber").css("visibility", "hidden");
400 this.commError(SypStrings.ServerError);
404 var xml = new OpenLayers.Format.XML().read(data);
406 switch (xml.documentElement.nodeName.toLowerCase()) {
408 switch (xml.documentElement.getAttribute("reason")) {
410 $("#login_area").show();
411 $("#cookie_warning").show();
413 Admin.cancelCurrentFeature();
417 this.commError(SypStrings.ServerError);
421 this.commError(SypStrings.UnreferencedError);
422 Admin.reloadLayer(Admin.dataLayer);
426 this.commError(SypStrings.NochangeError);
430 this.commError(SypStrings.RequestError);
434 this.commError(SypStrings.ToobigError);
435 $("#image_file").parent().html($("#image_file").parent().html());
436 $("#image_file").focus();
439 this.commError(SypStrings.NotimageError);
440 $("#image_file").parent().html($("#image_file").parent().html());
441 $("#image_file").focus();
444 this.commError(SypStrings.UnknownError);
450 switch (xml.documentElement.getAttribute("request")) {
452 this.commSuccess(SypStrings.DelSucces);
453 var someFeature = false;
455 $.each($(xml).find("FEATURE,feature"), function () {
457 var id = parseFloat($(this).find("ID:first,id:first").text());
458 if ((id === null) || isNaN (id)) {
461 var features = Admin.dataLayer.features;
462 for (var idx = 0; idx < features.length; idx++) {
463 if (features[idx].fid == id) {
464 Admin.dataLayer.removeFeatures([features[idx]]);
468 if (someFeature == false) {
469 this.commError(SypStrings.UnconsistentError);
476 var someFeature = false;
478 $.each($(xml).find("FEATURE,feature"), function () {
480 var id = parseFloat($(this).find("ID:first,id:first").text());
481 if ((id === null) || isNaN (id)) {
485 var lon = parseFloat($(this).find("LON:first,lon:first").text());
486 if ((typeof (lon) != "number") || isNaN (lon) ||
487 (lon < -180) || (lon > 180)) {
491 var lat = parseFloat($(this).find("LAT:first,lat:first").text());
492 if ((typeof (lat) != "number") || isNaN (lat) ||
493 (lat < -90) || (lat > 90)) {
497 var mapProj = Admin.map.getProjectionObject();
498 var lonlat = new OpenLayers.LonLat (lon, lat).
499 transform( new OpenLayers.Projection("EPSG:4326"), mapProj);
501 var imgurl = $(this).find("IMGURL:first,imgurl:first").text();
502 var title = $(this).find("HEADING:first,heading:first").text();
503 var description = $(this).find("DESCRIPTION:first,description:first").text();
505 feature = self.update (Admin.currentFeature, lonlat, imgurl, title, description);
509 if (someFeature == false) {
510 this.commError(SypStrings.UnconsistentError);
512 this.commSuccess(SypStrings.UpdateSucces);
518 this.commError(SypStrings.UnconsistentError);
523 this.commError(SypStrings.UnconsistentError);
528 commSuccess: function (message) {
529 $("#server_comm").text(message);
530 $("#server_comm").removeClass().addClass("success");
533 commError: function (message) {
534 $("#server_comm").text(message);
535 $("#server_comm").removeClass().addClass("error");
539 /* maintains a queue of ajax queries, so I'm sure they all execute in the same
540 * order they were defined */
546 add: function(query) {
547 this._queue.push(query);
548 if (this._queue.length > 1) {
551 this._runQuery(query);
555 _runQuery: function(query) {
557 $('#api_frame').one("load", function() {
558 self.running = false;
560 if (typeof (query.oncomplete) == "function") {
563 if (this.contentDocument) {
564 body = this.contentDocument.body;
565 } else if (this.contentWindow) {
566 body = this.contentWindow.document.body;
568 body = document.frames[this.id].document.body;
572 query.oncomplete(body.innerHTML);
574 query.oncomplete(null);
578 query.form.attr("action", "api.php");
579 query.form.attr("target", "api_frame");
580 query.form.attr("method", "post");
582 query.form.get(0).submit();
583 if (typeof (query.onsend) == "function") {
588 _reqEnd: function() {
590 if (this._queue.length > 0) {
591 this._reqEnd(this._queue[0]);
599 $("#login_form").submit(this.submit);
600 $("#password").focus().select();
607 submit: function () {
609 pwdMgr.commError("");
611 form: $("#login_form"),
613 $("#pwd_throbber").css("visibility", "visible");
614 $("#login_error").hide();
616 // we need a timeout; otherwise those fields will not be submitted
617 window.setTimeout(function() {
618 // removes focus from #password before disabling it. Otherwise, opera
619 // prevents re-focusing it after re-enabling it.
620 $("#password").blur();
621 $("#login_submit, #password").attr("disabled", "disabled");
624 oncomplete: OpenLayers.Function.bind(pwdMgr.ajaxReply, pwdMgr)
631 ajaxReply: function (data) {
633 $("#pwd_throbber").css("visibility", "hidden");
634 // here, we need a timeout because onsend timeout sometimes has not been triggered yet
635 window.setTimeout(function() {
636 $("#login_submit, #password").removeAttr("disabled");
640 this.commError(SypStrings.ServerError);
641 $("#login_error").show();
642 window.setTimeout(function() {
643 $("#password").focus().select();
647 var xml = new OpenLayers.Format.XML().read(data);
649 switch (xml.documentElement.nodeName.toLowerCase()) {
651 switch (xml.documentElement.getAttribute("reason")) {
653 this.commError(SypStrings.ServerError);
656 this.commError(SypStrings.UnauthorizedError);
659 this.commError(SypStrings.RequestError);
662 this.commError(SypStrings.UnknownError);
665 $("#login_error").show();
666 window.setTimeout(function() {
667 $("#password").focus().select();
672 $("#login_area").hide();
675 this.commError(SypStrings.UnconsistentError);
680 commError: function (message) {
681 $("#login_error").text(message);
683 $("#login_error").show();
685 $("#login_error").hide();
690 $(window).load(function () {
691 // if using .ready, ie triggers an error when trying to access
692 // document.namespaces
694 $("#newfeature_button").click(function () {
695 Admin.addNewFeature();
697 $("#editor_close").click(function () {
698 Admin.cancelCurrentFeature()
700 $("#feature_update").submit(function() {
702 FeatureMgr.save(Admin.currentFeature);
706 $("#feature_delete").submit(function() {
708 FeatureMgr.del(Admin.currentFeature);
712 $("#image_delete").click(function() {
713 alert (SypStrings.DisabledForDemo);
715 $("#img").removeAttr('src');
716 // needs to rebuild element otherwise some browsers still
718 $("#img").parent().html($("#img").parent().html());
719 $("#img").parent().hide();
720 $("#image_delete").hide();
721 $("#image_file").parent().show();