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: "openlayers/img/marker-blue.png",
60 MARKER_ICON_HEIGHT: 25,
61 MARKER_SELECT_ICON: "openlayers/img/marker-green.png",
62 MARKER_SELECT_ICON_HEIGHT: 25,
63 MARKER_TEMPORARY_ICON: "openlayers/img/marker-gold.png",
64 MARKER_TEMPORARY_ICON_HEIGHT: 25
70 selFeatureControl: null,
71 moveFeatureControl: null,
72 addFeatureControl: null,
75 currentFeatureLocation: null,
78 this.map = new OpenLayers.Map ("map", {
80 new OpenLayers.Control.Navigation (),
81 new OpenLayers.Control.PanZoom ()
83 projection: new OpenLayers.Projection("EPSG:900913"),
84 displayProjection: new OpenLayers.Projection("EPSG:4326")
87 this.baseLayer = this.createBaseLayer ();
88 this.dataLayer = this.createDataLayer ();
89 this.map.addLayers([this.baseLayer, this.dataLayer]);
92 this.selFeatureControl = this.createSelectFeatureControl();
93 this.map.addControl(this.selFeatureControl);
94 this.moveFeatureControl = this.createMoveFeatureControl();
95 this.map.addControl(this.moveFeatureControl);
96 this.addFeatureControl = this.createNewfeatureControl();
97 this.map.addControl(this.addFeatureControl);
100 var centerBounds = new OpenLayers.Bounds();
102 var mapProj = this.map.getProjectionObject();
103 var sypOrigProj = new OpenLayers.Projection("EPSG:4326");
105 var bottomLeft = new OpenLayers.LonLat(sypOrig[0],sypOrig[1]);
106 bottomLeft = bottomLeft.transform(sypOrigProj, mapProj);
107 var topRight = new OpenLayers.LonLat(sypOrig[2],sypOrig[3])
108 topRight = topRight.transform(sypOrigProj, mapProj);
110 centerBounds.extend(bottomLeft);
111 centerBounds.extend(topRight);
113 // at that moment, ie does not know size of the map, we need to update
115 this.map.updateSize();
116 this.map.zoomToExtent(centerBounds);
122 this.addFeatureControl.deactivate();
123 this.moveFeatureControl.deactivate();
124 this.selFeatureControl.activate();
125 this.checkForFeatures();
126 $("#newfeature_button").show().val(SypStrings.AddItem);
127 $("#newfeature_button").unbind("click").click(function () {
128 Admin.addNewFeature();
132 createBaseLayer: function () {
133 return new OpenLayers.Layer.OSM("OSM");
136 createDataLayer: function () {
137 var styleMap = new OpenLayers.StyleMap (
139 externalGraphic: this.Settings.MARKER_ICON,
140 graphicHeight: this.Settings.MARKER_ICON_HEIGHT
144 externalGraphic: this.Settings.MARKER_TEMPORARY_ICON,
145 graphicHeight: this.Settings.MARKER_TEMPORARY_ICON_HEIGHT
149 externalGraphic: this.Settings.MARKER_SELECT_ICON,
150 graphicHeight: this.Settings.MARKER_SELECT_ICON_HEIGHT
154 var layer = new OpenLayers.Layer.GML("KML", "items.php",
157 format: OpenLayers.Format.KML,
158 projection: this.map.displayProjection,
159 eventListeners: { scope: this,
160 loadend: this.checkForFeatures
167 createMoveFeatureControl: function () {
168 var control = new OpenLayers.Control.SypDragFeature(
174 createSelectFeatureControl: function () {
175 var control = new OpenLayers.Control.SelectFeature(
177 onSelect: OpenLayers.Function.bind(this.onFeatureSelect, this)
182 createNewfeatureControl: function () {
183 var control = new OpenLayers.Control ();
184 var handler = new OpenLayers.Handler.Click(control, {
185 'click': OpenLayers.Function.bind(FeatureMgr.add, FeatureMgr)
187 control.handler = handler;
191 onFeatureSelect: function (feature) {
192 this.showEditor(feature);
194 this.selFeatureControl.deactivate();
195 this.moveFeatureControl.activate();
198 closeEditor: function() {
199 if (this.currentFeature && this.currentFeature.layer) {
200 this.selFeatureControl.unselect(this.currentFeature);
202 this.currentFeature = null;
203 this.currentFeatureLocation = null;
204 $("#img").removeAttr('src');
205 $("#img").parent().html($("#img").parent().html());
206 $("#img").parent().show();
207 $("#title, #description").val("");
209 // do it once before hidding and once after hidding to work in all cases
210 $("#title, #description").val("");
211 $("#image_file").parent().html($("#image_file").parent().html());
212 $(document).unbind("keydown");
213 this.checkForFeatures();
217 showEditor: function (feature) {
218 $("#newfeature_button").hide();
224 $(document).unbind("keydown").keydown(function(e) {
225 if (e.keyCode == 27) {
226 Admin.cancelCurrentFeature()
230 this.currentFeature = feature;
231 this.currentFeatureLocation = new OpenLayers.Pixel(feature.geometry.x, feature.geometry.y);
233 $("#instructions").text(SypStrings.DragDropHowto);
234 $("#title").val(feature.attributes.name);
235 var fullDesc = $(feature.attributes.description).parent();
236 $("#description").val(fullDesc.find('p').text());
237 var src = fullDesc.find('img').attr('src');
239 $("#img").parent().show();
240 $("#img").attr('src', src);
241 $("#image_file").parent().hide();
242 $("#image_delete").show();
244 $("#img").parent().hide();
245 $("#image_file").parent().show();
246 $("#image_delete").hide();
248 $("#title").select().focus();
251 checkForFeatures: function () {
252 if (this.dataLayer.features.length != 0) {
253 $("#instructions").text(SypStrings.SelectHowto);
257 addNewFeature: function () {
259 $(document).unbind("keydown");
262 $(document).unbind("keydown").keydown(function(e) {
263 if (e.keyCode == 27) {
269 $("#newfeature_button").val("annuler");
270 $("#newfeature_button").unbind("click").click(cancel);
272 $("#instructions").text(SypStrings.AddHowto);
273 this.selFeatureControl.deactivate();
274 this.addFeatureControl.activate();
278 cancelCurrentFeature: function() {
279 if (AjaxMgr.running) {
282 var feature = this.currentFeature;
284 FeatureMgr.move (feature, this.currentFeatureLocation);
286 this.dataLayer.removeFeatures([feature]);
291 reloadLayer: function (layer) {
292 layer.destroyFeatures();
293 layer.loaded = false;
298 escapeHTML: function (str) {
303 replace(/&/gm, '&').
304 replace(/'/gm, ''').
305 replace(/"/gm, '"').
306 replace(/>/gm, '>').
307 replace(/</gm, '<');
310 startsWith: function (str, prefix) {
311 return (str.slice(0, prefix.length) == prefix);
314 indexOf: function (array, item) {
315 if (array.indexOf !== undefined) {
316 return array.indexOf(item);
318 return OpenLayers.Util.indexOf(array, item);
331 var pos = map.getLonLatFromViewPortPx(evt.xy);
332 feature = this.update (null, pos, "", "", "");
333 Admin.addFeatureControl.deactivate();
334 Admin.selFeatureControl.select(feature);
337 move: function (feature, aLocation) {
338 if (!feature || !aLocation) {
341 var curLoc = feature.geometry;
342 feature.geometry.move(aLocation.x - curLoc.x, aLocation.y - curLoc.y);
343 feature.layer.drawFeature(feature);
346 update: function(feature, lonlat, imgurl, title, description) {
347 var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
349 feature = new OpenLayers.Feature.Vector(point);
350 Admin.dataLayer.addFeatures([feature]);
352 this.move (feature, point);
354 feature.attributes.name = title;
355 feature.attributes.description = "<p>" + Admin.Utils.escapeHTML(description) + "</p>"
356 + "<img src=\"" + imgurl + "\">"
360 del: function (feature) {
361 var form = $("#feature_delete");
362 form.find('input[name="fid"]').val(feature.fid);
365 oncomplete: OpenLayers.Function.bind(this.ajaxReply, this)
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)
396 ajaxReply: function (data) {
398 this.commError(SypStrings.ServerError);
402 var xml = new OpenLayers.Format.XML().read(data);
404 switch (xml.documentElement.nodeName.toLowerCase()) {
406 switch (xml.documentElement.getAttribute("reason")) {
408 $("#login_area").show();
409 $("#cookie_warning").show();
411 Admin.cancelCurrentFeature();
415 this.commError(SypStrings.ServerError);
419 this.commError(SypStrings.UnreferencedError);
420 Admin.reloadLayer(Admin.dataLayer);
424 this.commError(SypStrings.NochangeError);
428 this.commError(SypStrings.RequestError);
432 this.commError(SypStrings.ToobigError);
433 $("#image_file").parent().html($("#image_file").parent().html());
434 $("#image_file").focus();
437 this.commError(SypStrings.NotimageError);
438 $("#image_file").parent().html($("#image_file").parent().html());
439 $("#image_file").focus();
442 this.commError(SypStrings.UnknownError);
448 switch (xml.documentElement.getAttribute("request")) {
450 this.commSuccess(SypStrings.DelSucces);
451 var someFeature = false;
453 $.each($(xml).find("FEATURE,feature"), function () {
455 var id = parseFloat($(this).find("ID:first,id:first").text());
456 if ((id === null) || isNaN (id)) {
459 var features = Admin.dataLayer.features;
460 for (var idx = 0; idx < features.length; idx++) {
461 if (features[idx].fid == id) {
462 Admin.dataLayer.removeFeatures([features[idx]]);
466 if (someFeature == false) {
467 this.commError(SypStrings.UnconsistentError);
474 var someFeature = false;
476 $.each($(xml).find("FEATURE,feature"), function () {
478 var id = parseFloat($(this).find("ID:first,id:first").text());
479 if ((id === null) || isNaN (id)) {
483 var lon = parseFloat($(this).find("LON:first,lon:first").text());
484 if ((typeof (lon) != "number") || isNaN (lon) ||
485 (lon < -180) || (lon > 180)) {
489 var lat = parseFloat($(this).find("LAT:first,lat:first").text());
490 if ((typeof (lat) != "number") || isNaN (lat) ||
491 (lat < -90) || (lat > 90)) {
495 var mapProj = Admin.map.getProjectionObject();
496 var lonlat = new OpenLayers.LonLat (lon, lat).
497 transform( new OpenLayers.Projection("EPSG:4326"), mapProj);
499 var imgurl = $(this).find("IMGURL:first,imgurl:first").text();
500 var title = $(this).find("HEADING:first,heading:first").text();
501 var description = $(this).find("DESCRIPTION:first,description:first").text();
503 feature = self.update (Admin.currentFeature, lonlat, imgurl, title, description);
507 if (someFeature == false) {
508 this.commError(SypStrings.UnconsistentError);
510 this.commSuccess(SypStrings.UpdateSucces);
516 this.commError(SypStrings.UnconsistentError);
521 this.commError(SypStrings.UnconsistentError);
526 commSuccess: function (message) {
527 $("#server_comm").text(message);
528 $("#server_comm").removeClass().addClass("success");
531 commError: function (message) {
532 $("#server_comm").text(message);
533 $("#server_comm").removeClass().addClass("error");
537 /* maintains a queue of ajax queries, so I'm sure they all execute in the same
538 * order they were defined */
544 add: function(query) {
545 this._queue.push(query);
546 if (this._queue.length > 1) {
549 this._runQuery(query);
553 _runQuery: function(query) {
555 $('#api_frame').one("load", function() {
556 self.running = false;
558 if (typeof (query.oncomplete) == "function") {
561 if (this.contentDocument) {
562 body = this.contentDocument.body;
563 } else if (this.contentWindow) {
564 body = this.contentWindow.document.body;
566 body = document.frames[this.id].document.body;
570 query.oncomplete(body.innerHTML);
572 query.oncomplete(null);
576 query.form.attr("action", "api.php");
577 query.form.attr("target", "api_frame");
578 query.form.attr("method", "post");
580 query.form.get(0).submit();
581 if (typeof (query.onsend) == "function") {
586 _reqEnd: function() {
588 if (this._queue.length > 0) {
589 this._reqEnd(this._queue[0]);
597 $("#login_form").submit(this.submit);
598 $("#password").focus().select();
605 submit: function () {
607 pwdMgr.commError("");
609 form: $("#login_form"),
611 $("#pwd_throbber").css("visibility", "visible");
612 $("#login_error").hide();
614 // we need a timeout; otherwise those fields will not be submitted
615 window.setTimeout(function() {
616 // removes focus from #password before disabling it. Otherwise, opera
617 // prevents re-focusing it after re-enabling it.
618 $("#password").blur();
619 $("#login_submit, #password").attr("disabled", "disabled");
622 oncomplete: OpenLayers.Function.bind(pwdMgr.ajaxReply, pwdMgr)
629 ajaxReply: function (data) {
631 $("#pwd_throbber").css("visibility", "hidden");
632 // here, we need a timeout because onsend timeout sometimes has not been triggered yet
633 window.setTimeout(function() {
634 $("#login_submit, #password").removeAttr("disabled");
638 this.commError(SypStrings.ServerError);
639 $("#login_error").show();
640 window.setTimeout(function() {
641 $("#password").focus().select();
645 var xml = new OpenLayers.Format.XML().read(data);
647 switch (xml.documentElement.nodeName.toLowerCase()) {
649 switch (xml.documentElement.getAttribute("reason")) {
651 this.commError(SypStrings.ServerError);
654 this.commError(SypStrings.UnauthorizedError);
657 this.commError(SypStrings.RequestError);
660 this.commError(SypStrings.UnknownError);
663 $("#login_error").show();
664 window.setTimeout(function() {
665 $("#password").focus().select();
670 $("#login_area").hide();
673 this.commError(SypStrings.UnconsistentError);
678 commError: function (message) {
679 $("#login_error").text(message);
681 $("#login_error").show();
683 $("#login_error").hide();
688 $(window).load(function () {
689 // if using .ready, ie triggers an error when trying to access
690 // document.namespaces
692 $("#newfeature_button").click(function () {
693 Admin.addNewFeature();
695 $("#editor_close").click(function () {
696 Admin.cancelCurrentFeature()
698 $("#feature_update").submit(function() {
700 FeatureMgr.save(Admin.currentFeature);
704 $("#feature_delete").submit(function() {
706 FeatureMgr.del(Admin.currentFeature);
710 $("#image_delete").click(function() {
711 $("#img").removeAttr('src');
712 // needs to rebuild element otherwise some browsers still
714 $("#img").parent().html($("#img").parent().html());
715 $("#img").parent().hide();
716 $("#image_delete").hide();
717 $("#image_file").parent().show();