Cell selection stops when mouse move fast on table - javascript

Demo
var flag=false;
$(document).live('mouseup', function () { flag = false; });
var colIndex; var lastRow;
$(document).on('mousedown', '.csstablelisttd', function (e) {
//This line gets the index of the first clicked row.
lastRow = $(this).closest("tr")[0].rowIndex;
var rowIndex = $(this).closest("tr").index();
colIndex = $(e.target).closest('td').index();
$(".csstdhighlight").removeClass("csstdhighlight");
if (colIndex == 0 || colIndex == 1) //)0 FOR FULL TIME CELL AND 1 FOR TIME SLOT CELL.
return;
if ($('#contentPlaceHolderMain_tableAppointment tr').eq(rowIndex).find('td').eq(colIndex).hasClass('csstdred') == false)
{
$('#contentPlaceHolderMain_tableAppointment tr').eq(rowIndex).find('td').eq(colIndex).addClass('csstdhighlight');
flag = true;
return false;
}
});
document.onmousemove = function () { return false; };
$(".csstablelisttd").live('mouseenter', function (e) {
// Compares with the last and next row index.
var currentRow = $(this).closest("tr")[0].rowIndex;
var currentColoumn = $(e.target).closest('td').index();
// cross row selection
if (lastRow == currentRow || lastRow == currentRow - 1 || lastRow == currentRow + 1)
{
lastRow = $(this).closest("tr")[0].rowIndex;
}
else
{
flag = false;
return;
}
// cross cell selection.
if (colIndex != currentColoumn)
{
flag = false;
return;
}
if (flag)
{
$('#contentPlaceHolderMain_tableAppointment tr').eq(currentRow).find('td').eq(currentColoumn).addClass('csstdhighlight');
e.preventDefault();
return false;
}
});
Cell selection stops when I move the cursor fast over the table.
What should I do to prevent the selection from stopping while moving the cursor fast on table cells.
I dont want to change the html of the page.
The problem mostly occurs in IE 7.
I have handled the event mousedown, mouseenter on tr class.

I think the selection logic is incorrectly getting stuck in a flag = false state.
When the mouse moves quickly the lastRow == currentRow || lastRow == currentRow - 1 || lastRow == currentRow + 1 will evaluate to false since the currentRow is not next to the lastRow, therefore flag is set to false (in the else). Then for all subsequent mouseenter events flag will always be false and the highlight class will never get added.
The problem occurs on Chrome also and I assume is far more pronounced on IE7 because the JavaScript engine is so much slower in IE7. I think that the JavaScript is quite complex and also the .live() jQuery function should be avoided since it was removed in jQuery 1.9. .on() (as you already use in another event binding) is the preferred method now.
I have included an alternate approach to highlighting the last table cell of each row if the left mouse button is held down, which is a lot simpler. If I have understood the code correctly, the only functionality missing is checking if a current row is either side of a previous row, as I couldn't see a good reason for this extra checking.
There is still the possibility that if a user is moving the mouse quickly over the rows, I would expect the that some rows miss the mouseenter event as the mouse is too quick. You may be able to use a mousemove event handler on the <table> itself to help address this.
The demo uses jQuery 1.9.1, and I also removed the table height to better demonstrate the code.
JavaScript
// disable text selection
document.onselectstart = function() {
return false;
}
var $table = $('#contentPlaceHolderMain_tableAppointment');
$table.on('mouseenter', 'td:last-child', function(e) {
if (e.which === 1) {
$(this).addClass('csstdhighlight');
}
}).on('click', function() {
$table.find('.csstdhighlight').removeClass('csstdhighlight');
});
I'd be happy to explain my example code in more detail if necessary :-)
Note: An answer (https://stackoverflow.com/a/6195715/637889) on jQuery: Detecting pressed mouse button during mousemove event was very helpful when I was looking at this.
Edit: Updated demo based on revised requirements:
JavaScript
// disable text selection
document.onselectstart = function() {
return false;
}
var $table = $('#contentPlaceHolderMain_tableAppointment');
var startIndex = -1;
var direction = 0;
$table.on('mouseenter', 'td:last-child', function(e) {
var $this = $(this);
var rowIndex = $this.parent().index();
if (direction === 0 && startIndex != -1) {
direction = rowIndex > startIndex ? 1 : -1;
}
if (e.which === 1 && (
(direction === -1 && rowIndex < startIndex) ||
(direction === 1 && rowIndex > startIndex))
) {
$(this).addClass('csstdhighlight');
}
}).on('mousedown', 'td:last-child', function() {
var $this = $(this);
startIndex = $this.parent().index();
$this.addClass('csstdhighlight');
}).on('mouseup', 'td:last-child', function() {
direction = 0;
startIndex = -1;
}).on('click', 'td:last-child', function() {
$table.find('.csstdhighlight').removeClass('csstdhighlight');
});

Related

Javascript scroll and validation form

i would like to inform guest that he skip important form section.
That's why i want to change background color div to some else when he scroll and did not checked anyone input or write text to input
I wrote some like this
$(function(){
$(document).scroll(function(){
if($(this).scrollTop() >= $('#questrow1').offset().top - -100) && document.getElementsByClassName("wiztype").checked = false; {
$("#questrow1").addClass('redback');
}
});
});
Without that
&& document.getElementsByClassName("wiztype").checked = false;
Colorize is fine but checking inputs must works.
= will not compare value and rather assign it. Here's updated expression -
$(function() {
$(document).scroll(function() {
if (($(this).scrollTop() >= ($('#questrow1').offset().top - -100)) && !document.getElementsByClassName("wiztype").checked) {
$("#questrow1").addClass('redback');
}
});
});
= false is not a comparison but an assignment. You'll want == (or simply a negation of the checked property since you want false).
However, getElementsByClassName returns a collection of elements, so you'll need to loop over all of them.
Also - -100 is just + 100
$(function(){
$(document).scroll(function(){
var checkboxes = document.getElementsByClassName("wiztype");
var hasChecked = false;
for(var i = 0; i < checkboxes.length; ++i) {
if(checkboxes.item(i).checked) {
hasChecked = true;
break;
}
}
if($(this).scrollTop() >= $('#questrow1').offset().top + 100 && !hasChecked) {
$("#questrow1").addClass('redback');
}
});
});

How to undo and redo onclick in svg element?

I have svg text fill which is dynamic. once the user click undo button it must undo the svg and textarea and once the user click redo button it should redo the svg text fill and textarea. i have completed with the textarea undo and redo functionality but not with svg element how to achieve this through jquery
$("#enter-text").on("keypress",function(){
$("#svg_id").html($(this).val());
})
//this value is kept small for testing purposes, you'd probably want to use sth. between 50 and 200
const stackSize = 10;
//left and right define the first and last "index" you can actually navigate to, a frame with maximum stackSize-1 items between them.
//These values are continually growing as you push new states to the stack, so that the index has to be clamped to the actual index in stack by %stackSize.
var stack = Array(stackSize), left=0, right=0, index = 0, timeout;
//push the first state to the stack, usually an empty string, but not necessarily
stack[0] = $("#enter-text").val();
updateButtons();
$("#enter-text").on("keydown keyup change", detachedUpdateText);
$("#undo").on("click", undo);
$("#redo").on("click", redo);
//detach update
function detachedUpdateText(){
clearTimeout(timeout);
timeout = setTimeout(updateText, 500);
}
function updateButtons(){
//disable buttons if the index reaches the respective border of the frame
//write the amount of steps availabe in each direction into the data- count attribute, to be processed by css
$("#undo")
.prop("disabled", index === left)
.attr("data-count", index-left);
$("#redo")
.prop("disabled", index === right)
.attr("data-count", right-index);
//show status
$("#stat").html(JSON.stringify({
left,
right,
index,
"index in stack": index % stackSize,
stack
}, null, 4))
}
function updateText(){
var val = $("#enter-text").val().trimRight();
//skip if nothing really changed
if(val === stack[index % stackSize]) return;
//add value
stack[++index % stackSize] = val;
//clean the undo-part of the stack
while(right > index)
stack[right-- % stackSize] = null;
//update boundaries
right = index;
left = Math.max(left, right+1-stackSize);
updateButtons();
}
function undo(){
if(index > left){
$("#enter-text").val(stack[--index % stackSize]);
updateButtons();
}
}
function redo(){
if(index < right){
$("#enter-text").val(stack[++index % stackSize]);
updateButtons();
}
}
https://jsfiddle.net/yvp3jedr/6/
$("#enter-text").on("keypress", function () {
$("#svg_id").text($(this).val());
})
//this value is kept small for testing purposes, you'd probably want to use sth. between 50 and 200
const stackSize = 10;
//left and right define the first and last "index" you can actually navigate to, a frame with maximum stackSize-1 items between them.
//These values are continually growing as you push new states to the stack, so that the index has to be clamped to the actual index in stack by %stackSize.
var stack = Array(stackSize), left = 0, right = 0, index = 0, timeout;
//push the first state to the stack, usually an empty string, but not necessarily
stack[0] = $("#enter-text").val();
updateButtons();
$("#enter-text").on("keydown keyup change", detachedUpdateText);
$("#undo").on("click", undo);
$("#redo").on("click", redo);
//detach update
function detachedUpdateText() {
clearTimeout(timeout);
timeout = setTimeout(updateText, 500);
}
function updateButtons() {
//disable buttons if the index reaches the respective border of the frame
//write the amount of steps availabe in each direction into the data-count attribute, to be processed by css
$("#undo")
.prop("disabled", index === left)
.attr("data-count", index - left);
$("#redo")
.prop("disabled", index === right)
.attr("data-count", right - index);
//show status
$("#stat").html(JSON.stringify({
left,
right,
index,
"index in stack": index % stackSize,
stack
}, null, 4))
}
function updateText() {
var val = $("#enter-text").val().trimRight();
//skip if nothing really changed
if (val === stack[index % stackSize]) return;
//add value
stack[++index % stackSize] = val;
//clean the undo-part of the stack
while (right > index)
stack[right-- % stackSize] = null;
//update boundaries
right = index;
left = Math.max(left, right + 1 - stackSize);
updateButtons();
}
function undo() {
if (index > left) {
var text = stack[--index % stackSize];
$("#enter-text").val(text);
$("#svg_id").text(text);
updateButtons();
}
}
function redo() {
if (index < right) {
var text = stack[++index % stackSize];
$("#enter-text").val(text);
$("#svg_id").text(text);
updateButtons();
}
}

Nonconcurrent async recursion

My end goal is to mitigate as much lag (window freezing/stuttering) as possible, giving the client a responsive window from page load.
My program is a Chrome extension, and part of it needs to search through a reddit submission, including all comments for certain words and then do some stuff with them. After this answer, I converted my code to use setInterval for the recursive search. Unforutnately, this runs concurrently, so even though each branch in the comment tree is delayed from its parent, the overall search overlaps each other, negating any benefit in the delay.
I have a solution, but I don't know how to implement it.
The solution would be to have a callback when a branch runs out that goes to the nearest parent fork. This in effect would traverse the comment tree linearly and would allow the setInterval (or probably setTimeout would be more appropriate) to have a noticeable affect.
The code that would need to be changed is:
function highlightComments(){
var elems = $(".content .usertext-body > .md");
var index = 0;
var total = elems.length;
console.log("comments started");
var intId = setInterval(function(){
highlightField(elems.get(index));
index++;
if(index == total){
clearInterval(intId);
addOnClick();
console.log("comments finished");
}
}, 25);
}
and highlightField is:
function highlightField(node) {
var found = $(node).attr("data-ggdc-found") === "1";
var contents = $.makeArray($(node).contents());
var index = 0;
var total = contents.length;
if (total == 0){
return;
}
var intId = setInterval(function() {
if (contents[index].nodeType === 3) { // Text
if (!found){
//Mods
var content = contents[index].nodeValue.replace(new RegExp(data.mods.regex, "gi"), data.mods.replacement);
//Creators
content = content.replace(new RegExp(data.creators.regex, "gi"), data.creators.replacement);
//Blacklist
for (var key in data.blacklist.regex){
if(data.blacklist.regex.hasOwnProperty(key)){
content = content.replace(new RegExp(data.blacklist.regex[key], "gi"), data.blacklist.replacement[key]);
}
}
if (content !== contents[index].nodeValue) {
$(contents[index]).replaceWith(content);
}
}
} else if (contents[index].nodeType === 1) { // Element
highlightField(contents[index]);
}
index++;
if(index == total){
clearInterval(intId);
}
}, 25);
}

Javascript - How do I improve performance when animating integers?

On the site I'm working on, we collect data from a datasource and present these in their own design element, in the form of an SVG. The SVG files are renamed to .php in order to insert the dynamic data from the datasource.
Then, I'm using inview javascript to initialize a function that animates the data from the source, from 0 to their actual value. However, I notice this gets kinda heavy on the browser, when there are a lot of elements that are running the animate function.
Is there perhaps a smarter way of doing this? I haven't really dug that much into it, because it's not that bad. I just happened to notice the lag when scrolling through the area being repainted.
Here's my js code:
$('.inview article').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
if (isInView) {
// element is now visible in the viewport
if (visiblePartY == 'top' || visiblePartY == 'both' || visiblePartY == 'bottom') {
var $this = $(this);
var element = $($this);
$this.addClass('active');
reinitializeText(element);
$this.unbind('inview');
// top part of element is visible
} else if (visiblePartY == 'bottom') {
} else {
}
} else {
}
});
function reinitializeText(element) {
var svg = element.find('svg');
var children = svg.children('.infographics_svg-text');
// If there is no class in svg file, search other elements for the class
if (children.length == 0) {
var children = element.find('.infographics_svg-text');
}
children.each(function (){
var step = this.textContent/100;
var round = false;
if (this.textContent.indexOf('.') !=-1) {
round = true;
}
animateText(this, 0, step, round);
});
}
function animateText(element, current, step, round) {
if (current > 100) return;
var num = current++ *step;
if (round) {
num = Math.round((num)*100)/100
} else {
num = Math.round(num);
}
element.textContent = num;
setTimeout(function() {
animateText(element, current, step, round);
}, 10);
}
Edit: Because of the difference in data values received from the source (low numbers to huge numbers), The speed of the animation is increased so it doesn't go on forever

javascript 'over-clicking' bug

I have a bug in Javascript where I am animating the margin left property of a parent container to show its child divs in a sort of next/previous fashion. Problem is if clicking 'next' at a high frequency the if statement seems to be ignored (i.e. only works if click, wait for animation, then click again) :
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
//roll margin back to 0
}
An example can be seen on jsFiddle - http://jsfiddle.net/ZQg5V/
Any help would be appreciated.
Try the below code which will basically check if the container is being animated just return from the function.
Working demo
$next.click(function (e) {
e.preventDefault();
if($contain.is(":animated")){
return;
}
var marLeft = $contain.css('margin-left'),
$this = $(this);
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
$contain.animate({
marginLeft: 0
}, function () {
$back.fadeOut('fast');
});
} else {
$back.fadeIn(function () {
$contain.animate({
marginLeft: "-=" + regWidth + "px"
});
});
}
if (marLeft > -combinedWidth) {
$contain.animate({
marginLeft: 0
});
}
});
Sometimes is better if you create a function to take care of the animation, instead of writting animation code on every event handler (next, back). Also, users won't have to wait for the animation to finish in order to go the nth page/box.
Maybe this will help you:
if (jQuery) {
var $next = $(".next"),
$back = $(".back"),
$box = $(".box"),
regWidth = $box.width(),
$contain = $(".wrap")
len = $box.length;
var combinedWidth = regWidth*len;
$contain.width(combinedWidth);
var currentBox = 0; // Keeps track of current box
var goTo = function(n) {
$contain.animate({
marginLeft: -n*regWidth
}, {
queue: false, // We don't want animations to queue
duration: 600
});
if (n == 0) $back.fadeOut('fast');
else $back.fadeIn('fast');
currentBox = n;
};
$next.click(function(e) {
e.preventDefault();
var go = currentBox + 1;
if (go >= len) go = 0; // Index based, instead of margin based...
goTo(go);
});
$back.click(function(e) {
e.preventDefault();
var go = currentBox - 1;
if (go <= 0) go = 0; //In case back is pressed while fading...
goTo(go);
});
}
Here's an updated version of your jsFiddle: http://jsfiddle.net/victmo/ZQg5V/5/
Cheers!
Use a variable to track if the animation is taking place. Pseudocode:
var animating = false;
function myAnimation() {
if (animating) return;
animating = true;
$(this).animate({what:'ever'}, function() {
animating = false;
});
}
Crude, but it should give you the idea.
Edit: Your current code works fine for me as well, even if I jam out on the button. On firefox.

Categories

Resources