I am looking to query any attachments of layers based on the results of an Identify Task. If there are attachments on the layer, I would like to add the links to the bottom of the infoTemplate.
I am having trouble working the multiple dojo Deferred objects. I know they are being resolved because the return values are logged in the console, but my infoWindow is never populated.
So what is the proper way to deal with several nested deferreds? Deferred Lists seem to be a step in the right direction, but I am unsure how I would format one in this situation.
Thanks,
Joe
Update:
I have updated my working code below.
map.on('click',executeIdentify);
function executeIdentify(evt) {
identifyParams.width = map.width;
identifyParams.height = map.height;
identifyParams.geometry = evt.mapPoint;
identifyParams.mapExtent = map.extent;
var deferred = identifyTask.execute(identifyParams);
deferred.addCallback(function(deferredResult){
var promiseList = []
var features = array.map(deferredResult,function(result) {
var feature = result.feature;
var content = "";
array.forEach(Object.keys(feature.attributes),function(attr) {
content += attr + ": " + feature.attributes[attr] + "<br>"
});
var url = identifyTask.url + "/" + result.layerId + "/" + result.feature.attributes.OBJECTID + "/attachments?f=json"
var req = esriRequest({url:url}).then(function(newDef) {
if (Object.keys(newDef).toString() == "attachmentInfos,_ssl") {
content += "<br><b>Attachments:</b><hr>"
array.forEach(newDef.attachmentInfos,function(attach) {
content += "<a href=" + identifyTask.url + "/" + result.layerId + "/" + result.feature.attributes.OBJECTID + "/attachments/" + attach.id + " target='_blank'>" + attach.name + "</a><br>"
})
}
content += "<br><br>";
console.log(result)
feature.infoTemplate = new InfoTemplate(result.layerName + " " + result.feature.attributes.OBJECTID,content)
// console.log(feature)
return feature
},function(newDef) {
feature.infoTemplate = new InfoTemplate(result.layerName + " " + result.feature.attributes.OBJECTID,content);
// console.log(feature)
return feature
});
promiseList.push(req);
});
var promiseAll = new all(promiseList)
promiseAll.then(function(r) {promiseFun(r)})
})
function promiseFun(r) {
map.infoWindow.setFeatures(r);
map.infoWindow.show(evt.mapPoint);
}
}
You should look at using dojo/promise/all to handle multiple deferred results. Here's an example that uses it to return the results from multiple services, with some extra code to identify which service the result is coming from.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Identify with Popup</title>
<link rel="stylesheet" href="http://js.arcgis.com/3.8/js/esri/css/esri.css">
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
</style>
<script>var dojoConfig = { parseOnLoad: true };</script>
<script src="http://js.arcgis.com/3.8/"></script>
<script>
var map;
var identifyTask, identifyParams, idPoint;
var identifyResults;
require([
"esri/map", "esri/dijit/Popup", "dojo/promise/all", "dojo/domReady!"
], function (
Map, Popup, All
) {
var popup = new Popup({
fillSymbol: new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 0, 0]), 2), new dojo.Color([255, 255, 0, 0.25]))
}, dojo.create("div"));
map = new Map("map", {
basemap: "satellite",
center: [-83.275, 42.573],
zoom: 18,
infoWindow: popup
});
dojo.connect(map, "onLoad", mapReady);
var landBaseLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer", { opacity: .55 });
map.addLayer(landBaseLayer);
var militaryLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Military/MapServer", { opacity: .55 });
map.addLayer(militaryLayer);
function mapReady(map) {
dojo.connect(map, "onClick", runIdentifies);
}
function runIdentifies(evt) {
identifyResults = [];
idPoint = evt.mapPoint;
var layers = dojo.map(map.layerIds, function (layerId) {
return map.getLayer(layerId);
});
layers = dojo.filter(layers, function (layer) {
if (layer.visibleLayers[0] !== -1) {
return layer.getImageUrl && layer.visible
}
}); //Only dynamic layers have the getImageUrl function. Filter so you only query visible dynamic layers
var tasks = dojo.map(layers, function (layer) {
return new esri.tasks.IdentifyTask(layer.url);
}); //map each visible dynamic layer to a new identify task, using the layer url
var defTasks = dojo.map(tasks, function (task) {
return new dojo.Deferred();
}); //map each identify task to a new dojo.Deferred
var params = createIdentifyParams(layers, evt);
var promises = [];
for (i = 0; i < tasks.length; i++) {
promises.push(tasks[i].execute(params[i])); //Execute each task
}
var allPromises = new All(promises);
allPromises.then(function (r) { showIdentifyResults(r, tasks); });
}
function showIdentifyResults(r, tasks) {
var results = [];
var taskUrls = [];
r = dojo.filter(r, function (result) {
return r[0];
});
for (i = 0; i < r.length; i++) {
results = results.concat(r[i]);
for (j = 0; j < r[i].length; j++) {
taskUrls = taskUrls.concat(tasks[i].url);
}
}
results = dojo.map(results, function (result, index) {
var feature = result.feature;
var layerName = result.layerName;
var serviceUrl = taskUrls[index];
feature.attributes.layerName = result.layerName;
var template = new esri.InfoTemplate("", "Service Url: " + serviceUrl + "<br/><br/>Layer name: " + result.layerName + "<br/><br/> Object Id: ${OBJECTID}");
feature.setInfoTemplate(template);
var resultGeometry = feature.geometry;
var resultType = resultGeometry.type;
return feature;
});
if (results.length === 0) {
map.infoWindow.clearFeatures();
} else {
map.infoWindow.setFeatures(results);
}
map.infoWindow.show(idPoint);
return results;
}
function createIdentifyParams(layers, evt) {
var identifyParamsList = [];
identifyParamsList.length = 0;
dojo.forEach(layers, function (layer) {
var idParams = new esri.tasks.IdentifyParameters();
idParams.width = map.width;
idParams.height = map.height;
idParams.geometry = evt.mapPoint;
idParams.mapExtent = map.extent;
idParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_VISIBLE;
var visLayers = layer.visibleLayers;
if (visLayers !== -1) {
var subLayers = [];
for (var i = 0; i < layer.layerInfos.length; i++) {
if (layer.layerInfos[i].subLayerIds == null)
subLayers.push(layer.layerInfos[i].id);
}
idParams.layerIds = subLayers;
} else {
idParams.layerIds = [];
}
idParams.tolerance = 3;
idParams.returnGeometry = true;
identifyParamsList.push(idParams);
});
return identifyParamsList;
}
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
Related
I have a Flask python application where the user can select a vehicle in the web page and depending on which vehicle is selected, the application should propose different WMS layers in the Leaflet layer control that the user can tick on / off depending of his needs. The logic of feeding new layers depending of vehicle selection is done via ajax, where the layers vs vehicle is fetched from a database.
This works fine the first time the vehicle is selected, however, when a different vehicle is selected and then the first vehicle again, the WMS layer does not show in the leaflet map, though the layer name can be selected in the layer control. To avoid having too many checkboxes the vessels has been added to the same marker group so the user only have the vessel group and a couple WMS layers to tick on/off.
I'm sure the solution is dead simple. However have been exhausing 'every' tip I could find on different forums.
JavaScript:
var vesselVar = null;
var mapVessel = null;
var layerControl = null;
var baseMaps = null;
var overlayMaps = null;
var layerNameArr = null;
var layerLinkArr = null;
var baseMapArr = null;
var myVessels = null;
var sLayerName = null;
var sUrl = null;
var wmsOptions = null;
var myWmsLayer = null;
function myOnSelectedVessel() {
let sSelectedVessel = $('#sSelectedVessel').find(":selected").text()
if (sSelectedVessel.length > 0) {
$.ajax({
url: '/vessel_map_set_vessel_id',
data: {
'sSelectedVesselName': sSelectedVessel,
},
type: 'POST',
dataType: 'json',
success: function (response) {
if (response.result) {
alert(response.msg);
}
myCreateOverlay(response.liVessels, response.liLastVesselPos, response.arrLeaflet.toString());
myCreateBaseLayers();
myCreateMap(response.lat, response.lon);
mapVessel.panTo(new L.LatLng(parseFloat(response.lat), parseFloat(response.lon)));
},
error: function (error) {
alert("error in function vessel_map.myOnSelectedVessel");
}
});
}
}
function myCreateVesselGroup(liVessels, liLastVesselPos) {
try {
myVessels = null;
vesselVar = null;
myVessels = L.layerGroup([]);
vesselVar = [];
let iLen = liLastVesselPos.length;
const arrVesselNames = liVessels.toString().split(',');
const arrVesselPos = liLastVesselPos.toString().split(',');
let iCntVesselPos = 0;
for (let iCn7 = 0; iCn7 < iLen; iCn7++) {
arrPos = liLastVesselPos[iCn7];
//alert(arrVesselNames[iCn7]);
myAddVesselMarker(arrVesselNames[iCn7], arrVesselPos[iCntVesselPos], arrVesselPos[iCntVesselPos + 1]);
myVessels.addLayer(vesselVar[iCn7]);
iCntVesselPos += 2;
}
}
catch (err) {
alert("Error in function myCreateBaseLayers: " + err.message);
}
}
function myCreateOverlay(liVessels, liLastVesselPos, sLeafletWmsString) {
try {
if (mapVessel !== null) {
if ((overlayMaps !== null) && (layerControl !== null)) {
mapVessel.eachLayer(function (layer) {
mapVessel.removeLayer(layer);
});
}
}
overlayMaps = null;
overlayMaps = {};
myCreateVesselGroup(liVessels, liLastVesselPos)
overlayMaps['Vessels'] = myVessels;
if (sLeafletWmsString.length > 1) {
const arrLeaflet2 = sLeafletWmsString.split(',')
let iLen = arrLeaflet2.length;
for (let iCnt4 = 0; iCnt4 < iLen; iCnt4 += 2) {
sLayerName = null;
sLayerName = arrLeaflet2[iCnt4].toString();
wmsOptions = null;
wmsOptions = {};
wmsOptions.layers = sLayerName;
wmsOptions.format = 'image/png';
wmsOptions.transparent = true;
wmsOptions.opacity = 0.5;
sUrl = null;
sUrl = arrLeaflet2[iCnt4 + 1];
myWmsLayer = null
myWmsLayer = new L.tileLayer.wms(sUrl, wmsOptions);
overlayMaps[sLayerName] = myWmsLayer;
}
}
}
catch (err) {
alert("Error in function myCreateOverlay: " + err.message);
}
}
function myCreateBaseLayers() {
try {
layerNameArr = null;
layerLinkArr = null;
baseMaps = null;
layerNameArr = [];
layerLinkArr = [];
baseMaps = []
layerNameArr.push('OpenStreetMap');
layerLinkArr.push(L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: 'OpenStreetMap', transparent: true }));
for (iCn2 = 0; iCn2 < layerLinkArr.length; iCn2++) {
baseMaps[layerNameArr[iCn2]] = layerLinkArr[iCn2];
}
}
catch (err) {
alert("Error in function myCreateBaseLayers: " + err.message);
}
}
function myAddVesselMarker(sTitle, dLat, dLon) {
try {
var markerOptions = {};
markerOptions.title = sTitle;
markerOptions.clickable = true;
markerOptions.draggable = false;
var sPopupText = "Lat: " + dLat.toString() + ", Lon: " + dLon.toString();
vesselVar.push(L.marker([dLat, dLon], markerOptions).bindPopup(sPopupText));
}
catch (err) {
alert("Error in function myAddVesselMarker: " + err.message);
}
}
function myCreateMap(dLatCenter, dLonCenter) {
try {
if (mapVessel !== null) {
mapVessel.invalidateSize();
mapVessel.off();
mapVessel.remove();
}
mapVessel = null;
layerControl = null;
mapVessel = new L.map('map', { center: [dLatCenter, dLonCenter], zoom: 13, layers: [layerLinkArr[0]] });
layerControl = new L.control.layers(baseMaps, overlayMaps).addTo(mapVessel);
}
catch (err) {
alert("Error in function myCreateMap: " + err.message);
}
}
For anybody else that struggles with the same issue. My problem was that the '&' character in the url string is a javascript entity character that is interpreted as javascript code (even though the url string was a varaiable and not in the JS code itself). For the first on load draw I used Flask's Jinja2, which automatically modified all the '&' characters in the url string, hence why the first time draw showed up ok. Once I replaced all the '&' characters in the ajax string, that I sent back to javascript when the user changed a vehicle, with '&', the overlay showed up also when I changed the vehicle.
Below is my code. if we use set timeout function we got all data but we not use we are not getting inspection data which is coming from my local db. i want use deferred and promises in my code. Thanks in advance.
function onclickToCall() {
this.$('.check-list > .check-list-box').each(function (i) {
var j = i + 1;
var answer_req = $(this).attr("data-isReq");
var checklist_guid = $(this).attr("data-guid");
var question_type = $(this).attr("data-type");
var yes_no = $("input:radio[name='radio_" + j + "']:checked").val();
var notes = $(this).find('#txtAreaNotes_' + j).val();
var attachment_url = $(this).find(".txtCameraImage").attr("data-path");
var appConfig = DriverConnectApp.State.get('config_settings');
var item = {};
item.checklist_guid = checklist_guid;
item.yes_no = yes_no;
item.attachment_url = attachment_url;
item.notes = notes;
if (question_type == 2) { // For Vehical visual inspection
var dataPromise = that.getInspectionData(checklist_guid);
dataPromise.done(function (response, vh_image) {
var inspectionItem = {};
inspectionItem.vh_url = vh_image;
inspectionItem.details = response;
item.vh_inspection = inspectionItem;
that.detailsArr.push(item);
});
} else {
item.vh_inspection = {};
that.detailsArr.push(item);
}
});
// after finish and push all data we need to call function here
test();
}
getInspectionData: function (checklist_guid) {
var that = this;
var deferred = $.Deferred();
that.dbchecklist.getVehicleInspectionlist(checklist_guid, function (data, res) {
var details = [];
if (data.length) {
var img = data[0].vh_image;
var arr = JSON.parse(data[0].vh_details);
for (var k = 0; k < arr.length; k++) {
var items = {};
items.number = arr[k].number;
items.notes = arr[k].notes;
items.attachment_url = arr[k].attachment_url;
details.push(items);
}
deferred.resolve(details, img);
} else {
deferred.resolve(details, img);
}
});
return deferred.promise();
}
When I run the javascript code below, it load specified amount of images from Flickr.
By var photos = photoGroup.getPhotos(10) code, I get 10 images from cache.
Then, I can see the object has exactly 10 items by checking console.log(photos);
But actual image appeared on the page is less than 10 items...
I have no idea why this work this way..
Thank you in advance.
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script>
var PhotoGroup = function(nativePhotos, callback) {
var _cache = new Array();
var numberOfPhotosLoaded = 0;
var containerWidth = $("#contents").css('max-width');
var containerHeight = $("#contents").css('max-height');
$(nativePhotos).each(function(key, photo) {
$("<img src='"+"http://farm" + photo["farm"] + ".staticflickr.com/" + photo["server"] + "/" + photo["id"] + "_" + photo["secret"] + "_b.jpg"+"'/>")
.attr("alt", photo['title'])
.attr("data-cycle-title", photo['ownername'])
.load(function() {
if(this.naturalWidth >= this.naturalHeight) {
$(this).attr("width", containerWidth);
} else {
$(this).attr("height", containerHeight);
}
_cache.push(this);
if(nativePhotos.length == ++numberOfPhotosLoaded)
callback();
})
});
var getRandom = function(max) {
return Math.floor((Math.random()*max)+1);
}
this.getPhotos = function(numberOfPhotos) {
var photoPool = new Array();
var maxRandomNumber = _cache.length-1;
while(photoPool.length != numberOfPhotos) {
var index = getRandom(maxRandomNumber);
if($.inArray(_cache[index], photoPool))
photoPool.push(_cache[index]);
}
return photoPool;
}
}
var Contents = function() {
var self = this;
var contentTypes = ["#slideShowWrapper", "#video"];
var switchTo = function(nameOfContent) {
$(contentTypes).each(function(contentType) {
$(contentType).hide();
});
switch(nameOfContent) {
case("EHTV") :
$("#video").show();
break;
case("slideShow") :
$("#slideShowWrapper").show();
break;
default :
break;
}
}
this.startEHTV = function() {
switchTo("EHTV");
document._video = document.getElementById("video");
document._video.addEventListener("loadstart", function() {
document._video.playbackRate = 0.3;
}, false);
document._video.addEventListener("ended", startSlideShow, false);
document._video.play();
}
this.startSlideShow = function() {
switchTo("slideShow");
var photos = photoGroup.getPhotos(10)
console.log(photos);
$('#slideShow').html(photos);
}
var api_key = '6242dcd053cd0ad8d791edd975217606';
var group_id = '2359176#N25';
var flickerAPI = 'http://api.flickr.com/services/rest/?jsoncallback=?';
var photoGroup;
$.getJSON(flickerAPI, {
api_key: api_key,
group_id: group_id,
format: "json",
method: "flickr.groups.pools.getPhotos",
}).done(function(data) {
photoGroup = new PhotoGroup(data['photos']['photo'], self.startSlideShow);
});
}
var contents = new Contents();
</script>
</head>
<body>
<div id="slideShow"></div>
</body>
</html>
I fix your method getRandom() according to this article, and completely re-write method getPhotos():
this.getPhotos = function(numberOfPhotos) {
var available = _cache.length;
if (numberOfPhotos >= available) {
// just clone existing array
return _cache.slice(0);
}
var result = [];
var indices = [];
while (result.length != numberOfPhotos) {
var r = getRandom(available);
if ($.inArray(r, indices) == -1) {
indices.push(r);
result.push(_cache[r]);
}
}
return result;
}
Check full solution here: http://jsfiddle.net/JtDzZ/
But this method still slow, because loop may be quite long to execute due to same random numbers occurred.
If you care about performance, you need to create other stable solution. For ex., randomize only first index of your images sequence.
I'm tryng to create a route planner to track my running routes. Using Bing Maps, I am able to create the route, but I'm struggling to remove to default 'beginning', 'end' and 'red circle' itinery icons.
Below is my code so far (based on this link). All I basically want is my own start icon at the beginning of the route and my end icon at the end. I don't need anything else in between apart from the route line.
Any help (along with code improvement tips) gratefully received!
jQuery(function() {
GetMap();
$("#btnStartRoute").click(function() {
map.AttachEvent('onclick', StartRouting);
});
});
var map = null;
var myRoute = [];
var noOfPushPins = 0;
function GetMap() {
map = new VEMap('mapContent');
map.SetCredentials("xxxxxxxxxxxxxxxxxx");
map.LoadMap();
}
function StartRouting(e) {
var xPoint = e.mapX, yPoint = e.mapY;
var pixel = new VEPixel(xPoint, yPoint);
var LL = map.PixelToLatLong(pixel);
cornerOne = LL; //cornerOne is a global level var
var latitude = map.PixelToLatLong(pixel).Latitude;
var longitiude = map.PixelToLatLong(pixel).Longitude;
myRoute[noOfPushPins] = new VELatLong(latitude, longitiude);
noOfPushPins++;
GetRoute();
}
function GetRoute() {
var myRouteOptions = new VERouteOptions();
myRouteOptions.RouteMode = VERouteMode.Walking;
myRouteOptions.RouteColor = new VEColor(0, 102, 51, .7);
myRouteOptions.RouteCallback = RouteCallback;
map.GetDirections(myRoute, myRouteOptions);
}
function RouteCallback(route) {
var myRouteShapes = [];
var myRoutePoints = [];
var points = route.RouteLegs[0].Itinerary.Items;
$.each(points, function(i) {
var routePointCoordinates = new VELatLong(route.RouteLegs[0].Itinerary.Items[i].LatLong.Latitude, route.RouteLegs[0].Itinerary.Items[i].LatLong.Longitude);
var routePointShape = new VEShape(VEShapeType.Pushpin, routePointCoordinates);
if (i != 0) {
routePointShape.SetCustomIcon("<img id='pushPin" + noOfPushPins + "' class='pushPin' src='/Content/Images/Maps/pushPinEnd.gif'><span class='pushPinText'>" + (noOfPushPins + 1) + "</span>");
} else {
routePointShape.SetCustomIcon("<img id='pushPin" + noOfPushPins + "' class='pushPin' src='/Content/Images/Maps/pushPinStart.gif'><span class='pushPinText'>" + (noOfPushPins + 1) + "</span>");
}
myRoutePoints.push(routePointShape);
map.Clear();
map.DeleteRoute();
map.AddShape(myRoutePoints);
});
}
There's an un-documented property called "Shape" on the Itinerary object. You can hide it...
More info here: http://social.msdn.microsoft.com/Forums/en/vemapcontroldev/thread/430449d0-fde4-4adb-9132-248fa6f9db65
This is my first attempt at a plugin but I think I'm missing the whole "How to" on this.
Ok here goes:
Trying to write an error popup box for form validation.
I like the look and functionality on this JavaScript code on this page, See demo here and source here.
It's basically what I want to do if the user enters invalid data.
Now I have tried to create a jQuery plugin with this code but it's not working, any help would be great :-)
(function($){
/* Might use the fadein fadeout functions */
var MSGTIMER = 20;
var MSGSPEED = 5;
var MSGOFFSET = 3;
var MSGHIDE = 3;
var errorBox = function(target, string, autohide, options)
{
var ebox = $(ebox);
var eboxcontent = $(eboxcontent);
var target = $(target);
var string = $(string);
var autohide = $(autohide);
var obj = this;
if (!document.getElementById('ebox')) {
ebox = document.createElement('div');
ebox.id = 'ebox';
eboxcontent = document.createElement('div');
eboxcontent.id = 'eboxcontent';
document.body.appendChild(ebox);
ebox.appendChild(eboxcontent);
ebox.style.filter = 'alpha(opacity=0)';
ebox.style.opacity = 0;
ebox.alpha = 0;
}
else {
ebox = document.getElementById('ebox');
eboxcontent = document.getElementById('eboxcontent');
}
eboxcontent.innerHTML = string;
ebox.style.display = 'block';
var msgheight = ebox.offsetHeight;
var targetdiv = document.getElementById(target);
targetdiv.focus();
var targetheight = targetdiv.offsetHeight;
var targetwidth = targetdiv.offsetWidth;
var topposition = topPosition(targetdiv) - ((msgheight - targetheight) / 2);
var leftposition = leftPosition(targetdiv) + targetwidth + MSGOFFSET;
ebox.style.top = topposition + 'px';
ebox.style.left = leftposition + 'px';
clearInterval(ebox.timer);
ebox.timer = setInterval("fadeMsg(1)", MSGTIMER);
if (!autohide) {
autohide = MSGHIDE;
}
window.setTimeout("hideMsg()", (autohide * 1000));
// hide the form alert //
this.hideMsg(msg) = function (){
var msg = document.getElementById('msg');
if (!msg.timer) {
msg.timer = setInterval("fadeMsg(0)", MSGTIMER);
}
};
// face the message box //
this.fadeMsg(flag) = function() {
if (flag == null) {
flag = 1;
}
var msg = document.getElementById('msg');
var value;
if (flag == 1) {
value = msg.alpha + MSGSPEED;
}
else {
value = msg.alpha - MSGSPEED;
}
msg.alpha = value;
msg.style.opacity = (value / 100);
msg.style.filter = 'alpha(opacity=' + value + ')';
if (value >= 99) {
clearInterval(msg.timer);
msg.timer = null;
}
else
if (value <= 1) {
msg.style.display = "none";
clearInterval(msg.timer);
}
};
// calculate the position of the element in relation to the left of the browser //
this.leftPosition(target) = function() {
var left = 0;
if (target.offsetParent) {
while (1) {
left += target.offsetLeft;
if (!target.offsetParent) {
break;
}
target = target.offsetParent;
}
}
else
if (target.x) {
left += target.x;
}
return left;
};
// calculate the position of the element in relation to the top of the browser window //
this.topPosition(target) = function() {
var top = 0;
if (target.offsetParent) {
while (1) {
top += target.offsetTop;
if (!target.offsetParent) {
break;
}
target = target.offsetParent;
}
}
else
if (target.y) {
top += target.y;
}
return top;
};
// preload the arrow //
if (document.images) {
arrow = new Image(7, 80);
arrow.src = "images/msg_arrow.gif";
}
};
$.fn.errorbox = function(options)
{
this.each(function()
{
var element = $(this);
// Return early if this element already has a plugin instance
if (element.data('errorbox')) return;
// pass options to plugin constructor
var errorbox = new errorBox(this, options);
// Store plugin object in this element's data
element.data('errorbox', errorbox);
});
};
})(jQuery);
How Im calling it
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>jQuery Plugin - Error ToolTip</title>
<script type="text/javascript" src="js/jquery.js">
</script>
<script type="text/javascript" src="js/jquery.errorbox.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
var name = document.getElementById('name');
if(name == "") {
$('#name','You must enter your name.',2).errorbox();
alert("Blank");
}
});
</script>
<link rel="stylesheet" type="text/css" href="css/errorbox.css" />
</head>
<body>
<div>
Name: <input type="text" id="name" width="30"></input>
</div>
</body>
Any help on my first plugin would be great, thanks in advance.
--Phill
The var errorBox = function(... needs to change to:
$.errorBox = function(...
then you can call it on the jquery object.
Secondly, for clarity you may want to use $('#eboxcontent') instead of document.getElementById('eboxcontent') . It wont be any faster, but it is "clearer" to other jquery developers.
Lastly, jQuery has many built in functions for fading things over a specified time period, and it appears that you have built your own. I know that jQuery's fading is cross-browser compatible. just use:
$('#someDivId').fadeOut(timeInMilliseconds);
var name = document.getElementById('name');
if(name == "") {
//...
}
should be
var name = document.getElementById('name');
if(name.value == "") {
//...
}
or
var name = $('#name').val();
if(name == "") {
//...
}