Selection row disable/reenable text selection - javascript

I have this code which selects multiple row when shift key is pressed. But whenever selection starts, the table text always gets selected, hence I tried to add disableSelection( ); to the table and re-enable it once mouseup. However, it is not working, the text still get selected. Any help is greatly appreciated.
$(".tableGrid tr").live("click", function(event) {
if( event.shiftKey ) {
$(".tableGrid").disableSelection( );
}
var tableRow = $(this).closest("tr").prevAll("tr").length + 1;
if ($(this).hasClass("rowSelected")) {
event.shiftKey ? $(this).removeClass("rowSelected") : $(".tableGrid tr").removeClass("rowSelected");
}
else {
if( !event.shiftKey ) {
$(".tableGrid tr").removeClass("rowSelected");
}
$(this).addClass("rowSelected");
}
if( event.shiftKey ) {
var start = Math.min(tableRow, lastSelected);
var end = Math.max(tableRow, lastSelected);
for( var i=start; i<end; i++ ) { $(".tableGrid").find("tr").eq(i).addClass("rowSelected"); }
}
else {
lastSelected = $(this).closest("tr").prevAll("tr").length + 1;
}
}).mouseup(function( ) {
$(".tableGrid").enableSelection( );
});

To disable text selection of a specific DOM element, you could try this:
var element = document.getElementById('content');
element.onselectstart = function () { return false; } // ie
element.onmousedown = function () { return false; } // mozilla

Related

JS: How to enable submit button in form only if all inputs pass validation

I have a simple input that I'm using an keyup event listener on. If the input length is too short, the span element will remove the class on it that hides the element and display "Input too short".
If I have multiple inputs, how can I only enable the Submit button if all fields pass the validation.
Unfortunately, I'm thinking in a React-way and would accomplish this via state.
<style type="text/css">
.hide-first {
display: none;
}
.hide-last {
display: none;
}
</style>
<div>
<div>
<input id="first-name" />
<span id="validation-span" class="hide-first">Input too short</span>
</div>
<button>Submit</button>
</div>
<script type="text/javascript">
let firstName = document.getElementById( 'first-name' );
let span = document.getElementById( 'validation-span' );
firstName.addEventListener( 'keyup', () => {
console.log( event.target.value.length )
if ( event.target.value.length < 5 ) {
span.classList.remove( 'hide-first' )
} else {
span.classList.add( 'hide-first' )
}
} );
</script>
All your inputs could call the same validation function that checks everything except inputs that are empty. Only show the submit button if they all succeed and show the appropriate message on inputs that fail the validation.
Pseudo-code:
boolean succes = true
if username is invalid and not empty
username invalid message
success = false
if password is invalid and not empty
password invalid message
success = false
if success is true
show submit button
At first add style your button style="display:none". You can use jQuery as bellow
$( document ).ready( function () {
var _rules = {
"first-name": function ( $owner ) {
var val = $owner.val();
if ( !val ) return false;
if ( val.length < 5 ) return false;
return true;
}
};
//Validate here
function validate(total_mark) {
var mark = 0;//total mark
//Read all input value, than check rules
$( 'input' ).each( function () {
if ( 'function' !== typeof ( _rules[this.id] ) ) return;
var $owner = $( this );
var result = _rules[this.id]( $owner );
if ( !result ) {
mark -= 1;
$owner.next().removeClass( 'hide-first' );
return;
}
$owner.next().addClass( 'hide-first' );
mark += 1;
return;
} );
return mark;
};
var $btn = $( 'button' );
//Register keyup event for all input
var total_input = 1;
$( 'input' ).on( "keyup", function ( e ) {
e.preventDefault();
$btn.css( "display", "none" );
if ( validate() < total_input ) return;
$btn.css( "display", "" );
} );
} );
Something like this should work
<div>
<div>
<input id="first-name" onchange='validation()'/>
<span id ="validation-span" class="hide-first">Input too short</span>
</div>
<button id='submit-button'>
Submit
</button>
</div>
<script type="text/javascript">
function validateFirstName() {
let firstName = document.getElementById('first-name');
let span = document.getElementById('validation-span');
if (event.target.value.length < 5) {
span.classList.remove('hide-first')
return True
}
span.classList.add('hide-first')
return False
}
function validation() {
let submitButton = document.getElementById('submit-button');
submitButton.disabled = validateFirstName();
}
</script>
As you add additional fields, you should create the validation function for that field, and then running it inside validation() like:
function validation() {
let submitButton = document.getElementById('submit-button');
submitButton.disabled = validateFirstName() && validateSecondField() && validateThirdField() &&...;
}
Remember to add to the html input the onchange event listener.
Simple logic. Make a function that checks if all of the fields are validated, and call it from within the onkeyup event. A seemingly straight-forward way would be like this:
let firstName = document.getElementById('first-name'),
lastName = document.getElementById('last-name'),
company = document.getElementById('company-name');
let span = document.getElementById('validation-span'),
span1 = document.getElementById('validation-span1'),
span2 = document.getElementById('validation-span2'),
conditions = [],
length = 3;
firstName.addEventListener('keyup', () => {
console.log(event.target.value.length)
if (event.target.value.length < 5) {
span.classList.remove('hide-first')
conditions[0] = true;
} else {
span.classList.add('hide-first')
conditions[0] = false;
}
})
lastName.addEventListener('keyup', () => {
console.log(event.target.value.length)
if (event.target.value.length < 5) {
span1.classList.remove('hide-first')
conditions[1] = true;
} else {
span1.classList.add('hide-first')
conditions[1] = false;
}
})
company.addEventListener('keyup', () => {
console.log(event.target.value.length)
if (event.target.value.length < 5) {
span2.classList.remove('hide-first')
conditions[2] = true;
} else {
span2.classList.add('hide-first')
conditions[2] = false;
}
})
function checkAllTrueAndActivateSubmitBtn() {
var result = true;
for(var i = 0; i < length; i++) {
if(!conditions[i]) {
result = false;
}
}
if(result) {
submitBtn.classList.add("shown"); //or whatever
}
}
but of course, the more fields you have,the more messy this becomes. A more efficient way would be to use an array for the fields, and conditions:
let IDsAndConditions = {
'first-name':{
condition: (x) => x.length >= 5,
span: 'validation-span'
},
'last-name': {
condition: (x) => x.length >= 8,
span: 'validation-span-lastName'
},
'phoneNumber':{
condition: (x) => x.match(/^-{0,1}\d+$/),//or whatever
span:"phone-span"
}
};
var conditions = [];
var num = 0;
for(var k in IDsAndConditions) {
var cur = IDsAndConditions[k];
var el = document.getElementById(k);
var span = document.getElementById(cur["span"]);
if(el && span) {
el.addEventListener('keyup', () => {
console.log(event.target.value.length)
if (!cur["condition"](event.target.value)) {
span.classList.remove('hide-first')
conditions[num] = true;
} else {
span.classList.add('hide-first')
conditions[num] = false;
}
checkAllTrueAndActivateSubmitBtn();
});
} else {
conditions[num] = true; //this is to make the validation work even if the element doesn't exist
}
num++;
}
function checkAllTrueAndActivateSubmitBtn() {
var result = true;
for(var i = 0; i < IDsAndConditions.length; i++) {
if(!conditions[i]) {
result = false;
}
}
if(result) {
submitBtn.classList.add("active"); //or whatever
} else {
submitBtn.classList.remove("active"); //even if it was active at one point, if someone changes a field to an incorrect value, it deactivates again
}
}

Auto Nested Tree Auto Expand not working in IE11 but is working in Chrome

I have a nested tree which is an html table with buttons on each elements to get the child table via AJAX. This works when done manually in IE and in chrome but I have a link to "Expand All" which selects all down arrow images on the page and .click()'s them. This happens on a 600 millisecond loop until all images are clicked and tables are opened. Here is the code for the auto click loop.
function autoClick(searchElement, clickElement) {
setTimeout(function () {
if ($(searchElement).length > 0) {
$(searchElement).each(function () {
$(this).click();
});
$(clickElement).click();
}
}, 600);
return ($(searchElement).length);
}
It doesn't even to click the first levels of the tree because when I watch for the ajax calls on the network monitor, none are fired. Here is the expand and collapse functions which utilize the autoclick loop.
function expandClick() {
if (!collapseExecuting) {
expandExecuting = true;
numOfExpandElements = autoClick('img[src="../Images/details_open.png"]', '#expandLink');
if (numOfExpandElements == 0) {
expandExecuting = false;
}
}
}
function collapseClick() {
if (!expandExecuting) {
collapseExecuting = true;
numOfCollapseElements = autoClick('img[src="../Images/details_close.png"]', '#collapseLink');
if (numOfCollapseElements == 0) {
collapseExecuting = false;
}
}
}
Here's the Click event handler:
$('#requestsTable tbody td img[data-description="toggle"]').live('click', function () { //alt="expand/collapse"
// var nTr = this.parentNode.parentNode;
var parentid = this.parentNode.parentNode.parentNode.parentNode.id;
var item = this;
if (parentid == "requestsTable") {
getChild("request", requestTable, item, "RequestCustomers?RequestID=" + $(this).data("request"));
}
else if (parentid == "customerTable") {
getChild("customer", requestTable, item, ".." + $(this).data('url') + "?RequestID=" + $(this).data("customer"));
}
else if (parentid == "accountTable") {
getChild("account", requestTable, item, ".." + $(this).data('url') + "?AccountNum=" + $(this).data("account") + "&RequestID=" + $(this).data("request"));
}
});
If you need to see get child here it is too:
function getChild(details, rTable, item, getCall) {
var row = item.parentNode.parentNode;
var parentid = item.parentNode.parentNode.parentNode.parentNode.id;
var rowClass = 'accountDetails';
if (item.src.match('details_close')) {
/* This row is already open - close it */
item.src = "../Images/details_open.png";
$(item).attr('title', 'Expand');
rTable.fnClose(row);
}
else {
/* Open this row */
item.src = "../Images/details_close.png";
$(item).attr('title', 'Collapse');
//set the class of the row based on the model being returned.
if (details == 'request') {
rowClass = 'requestDetails';
} else if(details == 'customer') {
rowClass = 'customerDetails';
}
$.get(getCall, function (response) {
rTable.fnOpen(row, response, rowClass);
if (response.BatchComplete) {
$('#batchStatus').value('Batch Completed. Click here to send batch.');
}
});
}
}
I found what was happening. In my ExpandClick and CollapseClick functions I was selecting the elements via relative URLs in the SRC attribute. Apparently in IE (at least IE 11) these relative URLs are mapped and then displayed in the source as absolute URLs. In chrome it keeps the relative URLs as is in the source so my selector was able to target in Chrome but not IE.
Changed my selectors that I pass to the autoClick function and it worked:
function expandClick() {
if (!collapseExecuting) {
expandExecuting = true;
numOfExpandElements = autoClick('img[title="Expand"]', '#expandLink');
if (numOfExpandElements == 0) {
expandExecuting = false;
}
}
}
function collapseClick() {
if (!expandExecuting) {
collapseExecuting = true;
numOfCollapseElements = autoClick('img[title="Collapse"]', '#collapseLink');
if (numOfCollapseElements == 0) {
collapseExecuting = false;
}
}
}

How to make expand all/collapse all button in this certain script?

i would like to ask for help in a simple task i really need to do at my work (I am a javascript newbie). I made a simple collapsible list with script provided by this guy http://code.stephenmorley.org/javascript/collapsible-lists/ but what i need right now are two simple buttons as stated in the title: expand all and collapse whole list. Do you guys know if something like that can be implemented in this certain script? Please help :)
var CollapsibleLists = new function () {
this.apply = function (_1) {
var _2 = document.getElementsByTagName("ul");
for (var _3 = 0; _3 < _2.length; _3++) {
if (_2[_3].className.match(/(^| )collapsibleList( |$)/)) {
this.applyTo(_2[_3], true);
if (!_1) {
var _4 = _2[_3].getElementsByTagName("ul");
for (var _5 = 0; _5 < _4.length; _5++) {
_4[_5].className += " collapsibleList";
}
}
}
}
};
this.applyTo = function (_6, _7) {
var _8 = _6.getElementsByTagName("li");
for (var _9 = 0; _9 < _8.length; _9++) {
if (!_7 || _6 == _8[_9].parentNode) {
if (_8[_9].addEventListener) {
_8[_9].addEventListener("mousedown", function (e) {
e.preventDefault();
}, false);
} else {
_8[_9].attachEvent("onselectstart", function () {
event.returnValue = false;
});
}
if (_8[_9].addEventListener) {
_8[_9].addEventListener("click", _a(_8[_9]), false);
} else {
_8[_9].attachEvent("onclick", _a(_8[_9]));
}
_b(_8[_9]);
}
}
};
function _a(_c) {
return function (e) {
if (!e) {
e = window.event;
}
var _d = (e.target ? e.target : e.srcElement);
while (_d.nodeName != "LI") {
_d = _d.parentNode;
}
if (_d == _c) {
_b(_c);
}
};
};
function _b(_e) {
var _f = _e.className.match(/(^| )collapsibleListClosed( |$)/);
var uls = _e.getElementsByTagName("ul");
for (var _10 = 0; _10 < uls.length; _10++) {
var li = uls[_10];
while (li.nodeName != "LI") {
li = li.parentNode;
}
if (li == _e) {
uls[_10].style.display = (_f ? "block" : "none");
}
}
_e.className = _e.className.replace(/(^| )collapsibleList(Open|Closed)( |$)/, "");
if (uls.length > 0) {
_e.className += " collapsibleList" + (_f ? "Open" : "Closed");
}
};
}();
It is important to understand why a post-order traversal is used. If you were to just iterate through from the first collapsible list li, it's 'children' may (will) change when expanded/collapsed, causing them to be undefined when you go to click() them.
In your .html
<head>
...
<script>
function listExpansion() {
var element = document.getElementById('listHeader');
if (element.innerText == 'Expand All') {
element.innerHTML = 'Collapse All';
CollapsibleLists.collapse(false);
} else {
element.innerHTML = 'Expand All';
CollapsibleLists.collapse(true);
}
}
</script>
...
</head>
<body>
<div class="header" id="listHeader" onClick="listExpansion()">Expand All</div>
<div class="content">
<ul class="collapsibleList" id="hubList"></ul>
</div>
</body>
In your collapsibleLists.js
var CollapsibleLists =
new function(){
...
// Post-order traversal of the collapsible list(s)
// if collapse is true, then all list items implode, else they explode.
this.collapse = function(collapse){
// find all elements with class collapsibleList(Open|Closed) and click them
var elements = document.getElementsByClassName('collapsibleList' + (collapse ? 'Open' : 'Closed'));
for (var i = elements.length; i--;) {
elements[i].click();
}
};
...
}();

On click change tab

I have been trying to figure out how to change a tab(target another tab) (i think its JQuery Tabs) using a random
from a previous tab.
What i currently have is:
<a class="txt-bblue hover-u" href="#" onclick="$(".wpb_tabs").tabs( "active", "tab-1393763893-1-88" )">becoming a carer</a>
but it doesn't seem to do anything. I have searched online and these forums for answers but the proposed solutions don't seem to work.
The Js function for the tabs is:
/* Tabs + Tours
---------------------------------------------------------- */
if ( typeof window['vc_tabsBehaviour'] !== 'function' ) {
function vc_tabsBehaviour() {
jQuery(function($){$(document.body).off('click.preview', 'a')});
jQuery('.wpb_tabs, .wpb_tour').each(function(index) {
var $tabs,
interval = jQuery(this).attr("data-interval"),
tabs_array = [];
//
$tabs = jQuery(this).find('.wpb_tour_tabs_wrapper').tabs({
show: function(event, ui) {wpb_prepare_tab_content(event, ui);},
activate: function(event, ui) {wpb_prepare_tab_content(event, ui);}
}).tabs('rotate', interval*1000);
jQuery(this).find('.wpb_tab').each(function(){ tabs_array.push(this.id); });
jQuery(this).find('.wpb_tab a[href^="#"]').click(function(e) {
e.preventDefault();
if ( jQuery.inArray( jQuery(this).attr('href'), tabs_array) ) {
$tabs.tabs("select", jQuery(this).attr('href'));
return false;
}
});
jQuery(this).find('.wpb_prev_slide a, .wpb_next_slide a').click(function(e) {
e.preventDefault();
var ver = jQuery.ui.version.split('.');
if(parseInt(ver[0])==1 && parseInt(ver[1]) < 9) {
var index = $tabs.tabs('option', 'selected');
if ( jQuery(this).parent().hasClass('wpb_next_slide') ) { index++; }
else { index--; }
if ( index < 0 ) { index = $tabs.tabs("length") - 1; }
else if ( index >= $tabs.tabs("length") ) { index = 0; }
$tabs.tabs("select", index);
} else {
var index = $tabs.tabs( "option", "active"),
length = $tabs.find('.wpb_tab').length;
if ( jQuery(this).parent().hasClass('wpb_next_slide') ) {
index = (index+1) >=length ? 0 : index+1;
} else {
index = index-1 < 0 ? length -1 : index-1;
}
$tabs.tabs( "option", "active", index );
}
});
});
}
}
it is the Js_composer plugin script for WP
The link to my page is: http://safercareltd.com/careers-training/jobs-vacancies/
any help for where i am going wrong would be great thanks
How about just triggering a click event on the tab you want to open:
onclick="$('#ui-id-2').trigger('click');return false;"
Try:
$(function(){
$('a.txt-bblue.hover-u').on('click',function(){
$('.wpb_tab').trigger('click');
return false;
});
});
or:
$(document).ready(function(){
$('a.txt-bblue.hover-u').on('click',function(){
$('.wpb_tab').trigger('click');
return false;
});
});

Add row to html table below the selected row when previous row has rowspan

I have the following code to add rows to a table using a context menu plugin so you can right click the cell you want to add the row below.
(function($){
function scanTable( $table ) {
var m = [];
$table.children( "tr" ).each( function( y, row ) {
$( row ).children( "td, th" ).each( function( x, cell ) {
var $cell = $( cell ),
cspan = $cell.attr( "colspan" ) | 0,
rspan = $cell.attr( "rowspan" ) | 0,
tx, ty;
cspan = cspan ? cspan : 1;
rspan = rspan ? rspan : 1;
for( ; m[y] && m[y][x]; ++x ); //skip already occupied cells in current row
for( tx = x; tx < x + cspan; ++tx ) { //mark matrix elements occupied by current cell with true
for( ty = y; ty < y + rspan; ++ty ) {
if( !m[ty] ) { //fill missing rows
m[ty] = [];
}
m[ty][tx] = true;
}
}
var pos = { top: y, left: x };
$cell.data( "cellPos", pos );
} );
} );
};
/* plugin */
$.fn.cellPos = function( rescan ) {
var $cell = this.first(),
pos = $cell.data( "cellPos" );
if( !pos || rescan ) {
var $table = $cell.closest( "table, thead, tbody, tfoot" );
scanTable( $table );
}
pos = $cell.data( "cellPos" );
return pos;
}
})(jQuery);
appendMe();
function appendMe() {
$('table.test td').find("em").remove()
$('table.test td').removeAttr("realCellEq").append(function(){
return "<em> " + $(this).cellPos().left + "</em>"
}).attr("realCellEq", function() {
return $(this).cellPos().left
});
}
$(function () {
$.contextMenu({
selector: 'table.test td',
items: {
"addRowBelow": {
name: "Add Row Below",
callback: function (key, options) {
$(this).parents("tr").after("<tr class='freshAdd'></tr>");
$(this).parents("tr").find("td").each( function() {
var thisRowSpan = ($(this).attr("rowspan")) ? $(this).attr("rowspan") : 1;
if(thisRowSpan > 1) {
$(this).attr("rowspan", (parseInt($(this).attr("rowspan"),10)+1));
} else {
$(this).clone().appendTo("tr.freshAdd");
}
});
$("tr.freshAdd").find("td").html("");
$("tr.freshAdd").removeClass("freshAdd");
appendMe();
}
}
}
});
});
The trouble is i can't work out what I need to do to take into consideration rowspans.
Here's a jsfiddle to explain what I mean.
http://jsfiddle.net/many_tentacles/sqjak/1/
The reason you are not able to add a fresh cell, using the the freshly added cells is , those freshly added cells contain a class called context-menu-active which prohibits the functions you have written to add the cells.
You need to do a small change inside callback like :
$(".context-menu-active").removeClass('context-menu-active');
This removes the class from any freshly added cell and hence it becomes usable again.
Look at the updated fiddle : http://jsfiddle.net/Q5PgG/
Your parents("tr") was not targeting previous parents so i have added prev() each() function , you can do it this way:
$(this).parent("tr").after("<tr class='freshAdd'></tr>");
$(this).parent("tr").prev().find("td").each( function() {
var thisRowSpan = ($(this).attr("rowspan")) ? $(this).attr("rowspan") : 1;
if(thisRowSpan > 1) {
$(this).attr("rowspan", (parseInt($(this).attr("rowspan"),10)+1));
}
})
$(this).parent("tr").find("td").each( function() {
var thisRowSpan = ($(this).attr("rowspan")) ? $(this).attr("rowspan") : 1;
if(thisRowSpan > 1) {
$(this).attr("rowspan", (parseInt($(this).attr("rowspan"),10)+1));
} else {
$(this).clone().appendTo("tr.freshAdd");
}
Working demo Fiddle

Categories