Cancel XMLHttpRequest? - javascript

Good day there
I have a site where I have lots of 'tooltips'. These tooltips are created when hovered on a certain part of text. The tooltip is a div block which appears on top all the other content on site, and is removed when the cursor is moved away from the text. Now, this tooltip is spawned only when the text has <a rel> with 'tooltip' class. The tooltip fetches data from MySQL database with XMLHttpRequest and with the rel tag. This all works very well but I have a one little problem. Tooltip.php, which is the main script for fetching data from MySQL (8,809 lines), sometimes takes a while to respond. For example if I just quickly move my cursor through the site and the cursor accidently hovered for 0.05 secs a text with <a rel> text, it will generate a tooltip even if my cursor is not any longer on the text. I want some sort of check to check is the cursor still on the same <a rel> text, before creating the actual tooltip.
HTML:
A tooltip
Javascript:
function createTooltip(event)
{
var target = event.target || event.srcElement;
var str = target.rel || target.parentNode.rel;
if (str === "" || !str)
{
return;
}
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
else // for older IE clients
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var link = document.getElementsByClassName('tooltip');
var oldTooltip = document.getElementsByClassName('object-tooltip'); // removing possible old tooltips...
for (var k = 0; k < oldTooltip.length; k++)
{
if (oldTooltip[k])
{
oldTooltip[k].remove();
}
}
for (var i = 0; i < link.length; i++)
{
if (str == link[i].rel)
{
var tooltip = document.createElement("div");
tooltip.setAttribute('class', 'object-tooltip');
tooltip.style.border = "solid 1px black";
tooltip.style.color = "white"; //"#99CC00";
tooltip.style.position = "fixed";
tooltip.style.width = "300px";
tooltip.style.left = event.clientX + 'px';
tooltip.style.top = event.clientY + 'px';
tooltip.style.padding = "5px 10px 5px 10px";
tooltip.style.margin = "-25px 0 0 60px";
tooltip.style.backgroundColor = "#0E0E0F";
tooltip.style.opacity = "0.9";
tooltip.style.display = "inline-block";
tooltip.style.zIndex = "100000";
tooltip.style.textDecoration = "none";
tooltip.style.textAlign = "left";
tooltip.innerHTML = xmlhttp.responseText;
link[i].parentNode.insertBefore(tooltip, link[i].nextSibling);
}
}
}
};
xmlhttp.open("GET", "./armory/tooltip.php?s="+str, true);
xmlhttp.send();
}
function moveTooltip(event)
{
var tooltip = document.getElementsByClassName('object-tooltip');
for (var i = 0; i < tooltip.length; i++)
{
tooltip[i].style.left = event.clientX + 'px';
tooltip[i].style.top = event.clientY + 'px';
}
}
function removeTooltip()
{
var tooltip = document.getElementsByClassName('object-tooltip'); // you can have only one tooltip active at time
for (var i = 0; i < tooltip.length; i++)
{
tooltip[i].remove();
}
}
I will not share tooltip.php for the sake of your time. It only gets the rel attribute and searches MySQL database with the attribute and prints data back. Is it possible to check is the cursor still on the same text, before creating the tooltip?
The best regards

Welp, based on your current code, you need to add, for instance, a variable outside of the scope of your existing createTooltip function to bind the xhr request to, let's call it, xmlhttp to be aligned with your existing code
var xmlhttp; //not in a function
Now add an event listener for the mouseout function on the .tooltip class, then abort the xhr request.
document.querySelectorAll('.tooltip').addEventListener('mouseout', function(){
xmlhttp.abort();
});
Now when the element with .tooltip triggers the mouseleave needless xmlhttprequests will be aborted.

Related

highlighting and editing text in long string

In a HTML/JavaScript/React/Redux web application, I have a long string (around 300kb) of natural language. It is a transcript of a recording being played back.
I need
to highlight the currently uttered word,
to recognize a word that's clicked on,
to extract selected ranges
and to replace parts of the string (when a correction to the transcript is submitted by the user).
Everything is easy when I wrap each word in its own <span>. However, this makes the number of elements unbearable for the browser and the page gets very slow.
I can think of two ways to approach this:
I could wrap each sentence in a <span> and only wrap each word of the currently played-back sentence.
I could leave the text without HTML tags, handle clicks via document.caretPositionFromPoint, but I don't know how to highlight a word.
I would welcome more ideas and thoughts on the balance between difficulty and speed.
"to recognize a word that's clicked on"
New answer
I figure that, the code in my previous answer actually had to split the huge string of text into an huge array on every on click event. After that, a linear search is performed on the array to locate the matching string.
However, this could be improved by precomputing the word array and use binary search instead of linear searching.
Now every highlighting will run in O(log n) instead of O(n)
See: http://jsfiddle.net/amoshydra/vq8y8h19/
// Build character to text map
var text = content.innerText;
var counter = 1;
textMap = text.split(' ').map((word) => {
result = {
word: word,
start: counter,
end: counter + word.length,
}
counter += word.length + 1;
return result;
});
content.addEventListener('click', function (e) {
var selection = window.getSelection();
var result = binarySearch(textMap, selection.focusOffset, compare_word);
var textNode = e.target.childNodes[0];
if (textNode) {
var range = document.createRange();
range.setStart(textNode, textMap[result].start);
range.setEnd(textNode, textMap[result].end);
var r = range.getClientRects()[0];
console.log(r.top, r.left, textMap[result].word);
// Update overlay
var scrollOffset = e.offsetY - e.clientY; // To accomondate scrolling
overlay.innerHTML = textMap[result].word;
overlay.style.top = r.top + scrollOffset + 'px';
overlay.style.left = r.left + 'px';
}
});
// Slightly modified binary search algorithm
function binarySearch(ar, el, compare_fn) {
var m = 0;
var n = ar.length - 1;
while (m <= n) {
var k = (n + m) >> 1;
var cmp = compare_fn(el, ar[k]);
if (cmp > 0) {
m = k + 1;
} else if(cmp < 0) {
n = k - 1;
} else {
return k;
}
}
return m - 1;
}
function compare_word(a, b) {
return a - b.start;
}
Original answer
I took a fork of code from this answer from aaron and implemented this:
Instead of setting a span tag on the paragraph, we could put an overlay on top of the word.
And resize and reposition the overlay when travelling to a word.
Snippet
JavaScript
// Update overlay
overlayDom.innerHTML = word;
overlayDom.style.top = r.top + 'px';
overlayDom.style.left = r.left + 'px';
CSS
Use an overlay with transparent color text, so that we can get the overlay to be of the same width with the word.
#overlay {
background-color: yellow;
opacity: 0.4;
display: block;
position: absolute;
color: transparent;
}
Full forked JavaScript code below
var overlayDom = document.getElementById('overlay');
function findClickedWord(parentElt, x, y) {
if (parentElt.nodeName !== '#text') {
console.log('didn\'t click on text node');
return null;
}
var range = document.createRange();
var words = parentElt.textContent.split(' ');
var start = 0;
var end = 0;
for (var i = 0; i < words.length; i++) {
var word = words[i];
end = start+word.length;
range.setStart(parentElt, start);
range.setEnd(parentElt, end);
// not getBoundingClientRect as word could wrap
var rects = range.getClientRects();
var clickedRect = isClickInRects(rects);
if (clickedRect) {
return [word, start, clickedRect];
}
start = end + 1;
}
function isClickInRects(rects) {
for (var i = 0; i < rects.length; ++i) {
var r = rects[i]
if (r.left<x && r.right>x && r.top<y && r.bottom>y) {
return r;
}
}
return false;
}
return null;
}
function onClick(e) {
var elt = document.getElementById('info');
// Get clicked status
var clicked = findClickedWord(e.target.childNodes[0], e.clientX, e.clientY);
// Update status bar
elt.innerHTML = 'Nothing Clicked';
if (clicked) {
var word = clicked[0];
var start = clicked[1];
var r = clicked[2];
elt.innerHTML = 'Clicked: ('+r.top+','+r.left+') word:'+word+' at offset '+start;
// Update overlay
overlayDom.innerHTML = word;
overlayDom.style.top = r.top + 'px';
overlayDom.style.left = r.left + 'px';
}
}
document.addEventListener('click', onClick);
See the forked demo: https://jsfiddle.net/amoshydra/pntzdpff/
This implementation uses the createRange API
I don't think the number of <span> elements is unbearable once they have been positioned. You might just need to minimize reflow by avoiding layout changes.
Small experiment: ~3kb of text highlighted via background-color
// Create ~3kb of text:
let text = document.getElementById("text");
for (let i = 0; i < 100000; ++i) {
let word = document.createElement("span");
word.id = "word_" + i;
word.textContent = "bla ";
text.appendChild(word);
}
document.body.appendChild(text);
// Highlight text:
let i = 0;
let word;
setInterval(function() {
if (word) word.style.backgroundColor = "transparent";
word = document.getElementById("word_" + i);
word.style.backgroundColor = "red";
i++;
}, 100)
<div id="text"></div>
Once the initial layout has finished, this renders smoothly for me in FF/Ubuntu/4+ years old laptop.
Now, if you where to change font-weight instead of background-color, the above would become unbearably slow due to the constant layout changes triggering a reflow.
Here is a simple editor that can easily handle very large string. I tried to use minimum DOM for performance.
It can
recognize a word that's clicked on
highlight the currently clicked word, or drag selection
extract selected ranges
replace parts of the string (when a correction to the transcript is submitted by the user).
See this jsFiddle
var editor = document.getElementById("editor");
var highlighter = document.createElement("span");
highlighter.className = "rename";
var replaceBox = document.createElement("input");
replaceBox.className = "replace";
replaceBox.onclick = function() {
event.stopPropagation();
};
editor.parentElement.appendChild(replaceBox);
editor.onclick = function() {
var sel = window.getSelection();
if (sel.anchorNode.parentElement === highlighter) {
clearSelection();
return;
}
var range = sel.getRangeAt(0);
if (range.collapsed) {
var idx = sel.anchorNode.nodeValue.lastIndexOf(" ", range.startOffset);
range.setStart(sel.anchorNode, idx + 1);
var idx = sel.anchorNode.nodeValue.indexOf(" ", range.endOffset);
if (idx == -1) {
idx = sel.anchorNode.nodeValue.length;
}
range.setEnd(sel.anchorNode, idx);
}
clearSelection();
range.surroundContents(highlighter);
range.detach();
showReplaceBox();
event.stopPropagation();
};
document.onclick = function(){
clearSelection();
};
function clearSelection() {
if (!!highlighter.parentNode) {
replaceBox.style.display = "none";
highlighter.parentNode.insertBefore(document.createTextNode(replaceBox.value), highlighter.nextSibling);
highlighter.parentNode.removeChild(highlighter);
}
editor.normalize(); // comment this line in case of any performance issue after an edit
}
function showReplaceBox() {
if (!!highlighter.parentNode) {
replaceBox.style.display = "block";
replaceBox.style.top = (highlighter.offsetTop + highlighter.offsetHeight) + "px";
replaceBox.style.left = highlighter.offsetLeft + "px";
replaceBox.value = highlighter.textContent;
replaceBox.focus();
replaceBox.selectionStart = 0;
replaceBox.selectionEnd = replaceBox.value.length;
}
}
.rename {
background: yellow;
}
.replace {
position: absolute;
display: none;
}
<div id="editor">
Your very large text goes here...
</div>
I would first find the clicked word via some annoying logic (Try looking here )
Then you can highlight the word simply by wrapping the exact word with a styled span as you suggested above :)
Well, I'm not really sure how you could recognise words. You may need a 3rd party software. To highlight a word, you can use CSS and span as you said.
CSS
span {
background-color: #B6B6B4;
}
To add the 'span' tags, you could use a find and replace thing. Like this one.
Find: all spaces
Replace: <span>

removeChild Syntax - I Need A Pair of Experienced Eyes

I am using the removeChild method for the first time. I have use javascript to modify my navbar so that it changes to fixed position and and scroll with the user. This causes the content of the body div to jump up slightly when this happens. As a result, I have managed to insert a red box (it will later be white) to take up the extra space when the navbar's position changes.
I need that red box to be removed when the user scrolls back to the top but I can't seem to get the remove child function to fire. If somebody could take a look and point me in the right direction that would be swell!
code (relevant code section is in bold):
var fillerState = false;
// fixed positioning on scroll property for taskbar:
window.addEventListener('scroll', function (evt) {
var distance_from_top = document.body.scrollTop;
if (distance_from_top <= 80) {
document.getElementById("navBar").style.position = "static";
document.getElementById("navBarList").style.borderBottom = "solid black 4px";
document.getElementById("navBar").style.borderTop = "initial";
var myCollection = document.getElementsByClassName("navBarLink");
var collectionLength = myCollection.length;
for(var i = 0; i < collectionLength; i++){
myCollection[i].style.borderTopLeftRadius = "1em";
myCollection[i].style.borderTopRightRadius = "1em";
myCollection[i].style.borderBottomLeftRadius = "initial";
myCollection[i].style.borderBottomRightRadius = "initial";
}
// stops loads of boxes from forming:
**if(fillerState == true){
var parentRemove = document.getElementById("bodyDiv");
var fillerBoxRemove = document.getElementById("fillerBox");
parentRemove.removeChild(fillerBoxRemove);
fillerState = false;
alert(fillerState);**
}
}
else if(distance_from_top > 80) {
document.getElementById("navBar").style.position = "fixed";
document.getElementById("navBar").style.top = "0px";
document.getElementById("navBar").style.borderTop = "solid black 4px";
document.getElementById("navBarList").style.borderBottom = "initial";
var myCollection = document.getElementsByClassName("navBarLink");
var collectionLength = myCollection.length;
if(fillerState == false){
// sets filler element so that the page doesn't bounce:
var filler = document.createElement("div");
filler.style.width = "200px";
filler.style.height = "80px";
filler.style.backgroundColor = "red";
filler.style.id = "fillerBox";
//defines where the new element will be placed:
var parent = document.getElementById("bodyDiv");
var brother = document.getElementById("leftColumn");
parent.insertBefore(filler,brother);
fillerState = true;
}
for(var i = 0; i < collectionLength; i++){
myCollection[i].style.borderTopLeftRadius = "initial";
myCollection[i].style.borderTopRightRadius = "initial";
myCollection[i].style.borderBottomLeftRadius = "1em";
myCollection[i].style.borderBottomRightRadius = "1em";
}
}
});
as squint pointed out, when you're making the element, you're setting it's style.id, which is not right.
Change:
filler.style.id = "fillerBox";
To:
filler.id = "fillerBox";
And your code will work.
Alternatively, you can do as others have suggested and create the box in the html itself, set it to a class that has no display, then change it's class. Not only easier, but also stops you from creating and destroying. less resource intensive that way.

Touch Events not registering for HTML5 Canvas Authoring using Flash CC

I have been having some issues when it comes to authoring HTML 5 Canvas in Flash CC, mostly as a result of the lack of information on writing JavaScript inside Flash.
I have been converting an existing drag and drop .fla into HTML 5 with the hope of making it iOS and Android compatible. It is already functioning with mouse, but I have hit a brick wall on trying to add touch support.
The only way I have been able to even register the touch events is by listening to the entire window, which isn't very useful when I have multiple pieces that I want to move around.
This is what I have so far, all this code is located on the first frame of the main Scene Timeline, and the scene is composed of 5 pieces and 5 targets for those pieces, as well as a pop up task completed box and a reset button.
this.stop();
MainStage = this;//Declare
//*********************
//Actual Drag and Dropping
// Initialize:
var numPieces = 5;//<---------------Place number of pieces HERE---------------
var homePosX = [];
var homePosY = [];
var correctAns = 0;
var isClickableAry = [];
var whoAmI = [];//Declared "Globally" so that I can identify which piece is being grabbed later
for (var i = 0; i < numPieces; i++)
{
var pieceName = "p" + (i + 1);
var piece = this[pieceName];
//This sets the starting position for each piece
homePosX[i+1] = piece.x;//(i+1) is so that Piece names line up with Target names and MC names
homePosY[i+1] = piece.y;
whoAmI[i] = piece;
isClickableAry[i] = 1;//Makes it so each pieces is set as clickable
if( piece ){
piece.name = pieceName;
piece.on("mousedown" || "touchstart", function(evt)
{
evt.preventDefault();
//Debug
console.log(checkPiece(this));
//Rather than adding and removing event listeners, just check to see if piece is clickable
if(isClickableAry[checkPiece(this)] == 1){
this.parent.addChild(this);// Bump to top
this.offset = {x:this.x - evt.stageX, y:this.y - evt.stageY};
//Debug
console.log(piece + "PICKED UP, X " + piece.x + ", Y " + piece.y + " is Clickable? ");
//Set Home Coordinates (Where it was picked up)
homeX = this.x;
homeY = this.y;
}
});
piece.on("touchmove",function(evt)
{
console.log("touch moved! " + touchobj);
evt.preventDefault();
});
piece.on("pressmove", function(evt)
{
if(isClickableAry[checkPiece(this)] == 1){
this.x = evt.stageX + this.offset.x;
this.y = evt.stageY + this.offset.y;
//Mouse Cursor change
document.body.style.cursor='move';
}
});
piece.on("pressup" || "touchend" || "touchcancel", function(evt)
{
var target = this.parent["t"+this.name.substr(1)];
//Reset Cursor
document.body.style.cursor='auto';
if( target && hitTestInRange( target, 60) && isClickableAry[checkPiece(this)] == 1 ){
this.x = target.x;
this.y = target.y;
//If it is correct add one
correctAns++;
//Make that button Unclickable
isClickableAry[checkPiece(this)] = 0;
if(correctAns >= numPieces){
//If they have answered correctly equal to the the number of pieces
MainStage.complete_mc.parent.addChild(MainStage.complete_mc);//Bump to top
MainStage.complete_mc.gotoAndStop(1);
//reset answer counter and make drag pieces and buttons unclickable
correctAns = 0;
//Debug
console.log(correctAns + "CORRECT!";)
}
}else{
//Return to home Coordinates (Where it was on intialization)
if(isClickableAry[checkPiece(this)] == 1){
this.x = homePosX[checkPiece(this)+1];
this.y = homePosY[checkPiece(this)+1];
}
}
});
piece.on("mouseover", function(evt)
{
if(isClickableAry[checkPiece(this)] == 1){
//Makes cursor a pointer finger
document.body.style.cursor='pointer';
}
});
piece.on('mouseout',function(evt)
{
//sets cursor back to normal
document.body.style.cursor='auto';
});
}
}
function hitTestInRange( target, range )
{
if( target.x > stage.mouseX - range &&
target.x < stage.mouseX + range &&
target.y > stage.mouseY - range &&
target.y < stage.mouseY + range )
{
return true;
}
return false;
}
//Check which piece it is
function checkPiece(checkName)
{
for (var i = 0; i < numPieces; i++)
{
if (checkName == whoAmI[i]){
return i;
}
}
}
//Reset Functionality
this.complete_mc.reset_btn.addEventListener("click", resetPos.bind(this));
function resetPos(){
for (var i = 0; i < numPieces; i++)
{
var pieceName = "p" + (i + 1);
var piece = this[pieceName];
correctAns = 0;
//Makes Pieces Grabable again
isClickableAry[i] = 1;
//This returns each piece to their Original Starting Positions
piece.x = homePosX[i+1];
piece.y = homePosY[i+1];
}
}
//Controlling the Pop Up Window, window pops up when user answers everything correctly
this.complete_mc.exitComplete_btn.addEventListener("click", closePopUp.bind(this));
this.complete_mc.exitComplete_btn_alt. addEventListener("click", closePopUp.bind(this));
function closePopUp(){
MainStage.complete_mc.gotoAndStop(0);
}
In my own troubleshooting with other problems that have come up generally the issue has to do with scope of either functions or variables, since when flash exports the files it generates its own .js file and turns all of your movie clips into code and separates the code that you have written by whichever frame you wrote it on.
Any help at all would be appreciated.
EDIT: After a bit more research I think the problem might have something to do with touch events only being able to target separate elements? So it isn't able to grab objects inside the canvas element just the canvas element itself?
Turns out that adding touch support is incredibly easy. All I was missing was one line of code
createjs.Touch.enable(stage);
this makes all the touch events respond as mouse events. and fixed all my issues.

Custom Lazy Load - IE9 Memory Leak

I'm currently developing a basic image gallery that dynamically loads new images in the following order (on document.ready):
Uses an ajax call to get JSON which contains all the information needed to dynamically render images.
Iterates over the JSON object to create proper divs/img elements which are then appended to the page.
$.ajax({
url: '/wp-content/themes/base/library/ajax/posts-json.php',
type: 'get',
//dataType: 'json',
success: function(data) {
// turn string response to JSON array
window.responseArray = JSON.parse(data);
window.lastPhotoIndex = 0;
// make sure there is a response
if (responseArray.length > 0) {
// get container
var container = document.getElementById("photos-container");
var ulElement = document.createElement('ul');
ulElement.className = "rig columns-3";
ulElement.setAttribute("id", "photo-list");
// iterate over each response
window.photoCount = 0;
for (var i = 0; i < responseArray.length; i += 1) {
// Only load first 10 images
if (responseArray[i]["post-type"] == "photo" && photoCount < 20) {
// Set the last photo index to this photo
lastPhotoIndex = i;
// create the li
var liElement = document.createElement("li");
liElement.className = liElement.className + responseArray[i]["day"];
//create class name string from WP tags
if (responseArray[i].tags.length > 0) {
for (var ii = 0; ii < responseArray[i].tags.length; ii += 1) {
nospaceTagName = responseArray[i].tags[ii].split(' ').join('');
liElement.className += " " + nospaceTagName;
}
}
//create image element and append to div
var imgTag = document.createElement("img");
imgTag.src = responseArray[i]["thumb-url"];
liElement.appendChild(imgTag);
//Add modal class info to outer div
liElement.className += " md-trigger";
//Add data-modal attribute to outer div
liElement.setAttribute("data-modal", "photo-modal");
ulElement.appendChild(liElement);
//next slide
photoCount++;
}
}
//append ul to container
container.appendChild(ulElement);
}
},
error: function(xhr, desc, err) {
console.log(xhr);
console.log("Details: " + desc + "\nError:" + err);
}
});// end ajax call
After the ajax call, I add a window scroll event that will be called while there are still more photos in the JSON object.
// Window scroll event
$(window).scroll(function () {
var trigger = $(document).height() - 300;
if (trigger <= $(window).scrollTop() + $(window).height()) {
//Call function to load next 10
loadNextPhotos();
}
});
The function called by the scroll even simply starts off at the previously left off index (lastPhotoIndex variable set at the beginning of ajax call - 'window.lastPhotoIndex'). The function looks like this:
function loadNextPhotos() {
if (photoCount < getPhotoCount()) {
var photosOutput = 0;
var startingIndex = lastPhotoIndex + 1;
var photoList = $('#photo-list');
for (var i = startingIndex; i < responseArray.length; i += 1) {
if (responseArray[i]["post-type"] == "photo" && photosOutput < 10) {
lastPhotoIndex = i;
photosOutput++;
// create the li needed
var element = document.createElement("li");
element.className = responseArray[i]["day"];
//create class name string from tags
if (responseArray[i].tags.length > 0) {
for (var ii = 0; ii < responseArray[i].tags.length; ii += 1) {
nospaceTagName = responseArray[i].tags[ii].split(' ').join('');
element.className = element.className + " " + nospaceTagName;
}
}
//create image element and append to li
var imgTag = document.createElement("img");
imgTag.src = responseArray[i]["thumb-url"];
element.appendChild(imgTag);
//Add modal class info to li
element.className = element.className + " md-trigger";
//Add data-modal attribute to outer div
element.setAttribute("data-modal", "photo-modal");
photoList.append(element);
// Keep track of photo numbers so modal works for appropriate slide number
photoCount++;
}
}
}
}
Bear in mind, this code is stripped down a lot from the full application. It works fine in Chrome, Safari, Firefox, IE10+.
When loaded in IE9, I'm experiencing crazy memory leaks as I hit the scroll event and append more items to the UL.
My guess is that I'm not following best practices when creating new items to be appended and they're staying in memory longer than they should. The only issue is I'm not sure how to solve it/debug it because the page crashes so quickly in IE9.
Any help would be awesome. Thanks!
EDIT:
I've tried implementing Darmesh's solution with no real luck. As I said in his comment it only delays the rate at which memory is leaked. I've also added jquery.visible.js on top of a scroll event so it looks like this:
$(window).scroll(function () {
if($('#lazy-load-trigger').visible() && window.isLoadingPhotos != true) {
console.log("VISIBLE!");
loadNextPhotos();
}
});
But it also only delays the memory leak. I still believe there are issues with Garbage Collection in IE9, but am not sure how to troubleshoot.
I think this is due to the browser calling loadNextPhotos function multiple times at the same time every time you scroll. This might work, give it a try,
function loadNextPhotos() {
// Add flag to indicate new photos adding started
window.isLoadingPhotos = true;
....
....
....
....
// Indicate new photos adding completed
window.isLoadingPhotos = false;
}
And,
$(window).scroll(function () {
var trigger = $(document).height() - 300;
if (trigger <= $(window).scrollTop() + $(window).height()) {
if(!window.isLoadingPhotos) {
//Call function to load next 10
loadNextPhotos();
}
}
});

Javascript drag and drop code works on div but doesn't work on img

I'm fairly new to JavaScript, so any help would be awesome!
I created this small block of code that let's me grab a div and drag it around. I assign the "dragme" id to the div and all is fine and dandy. The problem is that if I replace that div from my html and put an img element instead (obviously assigning the "dragme" id to the img), things don't work as expected.
When I click to drag the img, it actually moves for about 3 or 4 pixels then it freezes until I lift the mouse button (mouseup).
Is there some property or characteristic that would prevent the img element from acting the same way as the div does?
var isClicked = false;
var startClientX = 0;
var startClientY = 0;
var startLeft = 0;
var startTop = 0;
window.addEventListener("load", addListeners, true);
function addListeners()
{
document.getElementById("dragme").addEventListener("mousedown", mouseIsDown, false);
document.getElementById("dragme").addEventListener("mouseup", mouseIsUp, false);
window.addEventListener("mousemove", moveImage, false);
function mouseIsDown(e)
{
if (isClicked == false)
{
isClicked = true;
startClientX = e.clientX;
startClientY = e.clientY;
startLeft = document.getElementById("dragme").offsetLeft;
startTop = document.getElementById("dragme").offsetTop;
}
}
function mouseIsUp()
{
if (isClicked == true)
{
isClicked = false;
}
}
function moveImage(e)
{
if (isClicked == true)
{
imageLeftDif = e.clientX - startClientX;
imageTopDif = e.clientY - startClientY;
var newLeftPos = (startLeft + imageLeftDif) + "px";
var newTopPos = (startTop + imageTopDif) + "px";
document.getElementById("dragme").style.left = newLeftPos;
document.getElementById("dragme").style.top = newTopPos;
}
}
}
This fixed the problem (answer provided as a comment by syazdani):
I'd venture to say that the built in browser drag and drop for images
is kicking in. Try e.preventDefault and return false in the mousedown
handler. – syazdani Dec 2 '12 at 17:26

Categories

Resources