Programmatically change class names - javascript

I'm trying to increase/decrease a number contained in a class name of an element.
Let's consider this code :
Increase
Decrease
<div id="my_div" class="large-12 columns">Div content</div>
I would like to achieve something like this :
$('a.decrease').click(function(e){
e.preventDefault();
$('#my_div').decreaseClass('class^=large-');
//decrease the number at the end of the class(es)
//starting with the name "large-"
//in this case large-12 would go to large-11
});
Any idea how to go about it?

Updated Answer
I refined the jQuery plugin to improve its functionality. There we have an .alterClass() method to increase/decrease the number of class (by step config):
;(function ($) {
$.fn.alterClass = function (cls, opt) {
opt = opt || {};
var conf = $.extend({}, {
'min': 1, // min number of the class
'max': 12, // max number of the class
'step': 1 // increment/decrement step
}, opt);
return this.each(function () {
var oldClass = $.grep(this.className.split(" "), function (v, i) {
return v.indexOf(cls) === 0;
}).join(),
oldNum = Number(oldClass.split('-')[1]),
newClass;
oldNum += conf.step;
if (conf.step > 0) { // increase mode
newClass = cls + (oldNum <= conf.max ? oldNum : conf.max);
} else { // decrease mode
newClass = cls + (oldNum >= conf.min ? oldNum : conf.min);
}
if (! $(this).hasClass(newClass)) {
$(this).removeClass(oldClass).addClass(newClass);
}
});
};
}(jQuery));
You could set the min and/or max numbers and the step as well:
$('.increase').click(function(e) {
e.preventDefault();
$('#my_div').alterClass('large-', {'step': 1});
});
$('.decrease').click(function(e) {
e.preventDefault();
$('#my_div').alterClass('large-', {'step': -1});
});
Here is the UPDATED DEMO.
Original Answer
Here's my attempt to create the .decreaseClass() method:
;(function($) {
$.fn.decreaseClass = function(cls) {
return this.each(function() {
var oldClass = $.grep(this.className.split(" "), function(v, i){
return v.indexOf(cls) === 0;
}).join(),
oldNum = oldClass.split('-')[1];
$(this).removeClass(oldClass).addClass(cls+--oldNum);
});
};
}(jQuery));
You could use the above plugin as follows:
$('.decrease').click(function(e) {
e.preventDefault();
$('#my_div').decreaseClass('large-');
});
WORKING DEMO.

Simply loop through your classes and remove the class they are at and add the class they are going to. For example:
for (var i = 12; i > 1; i--) {
$('#my_div .large-'+i).removeClass('large-'+i).addClass('large-'+(i-1));
}
Where #my_div is the div you are doing this in and large- is the prefix. I made the assumption that if you are at large-1 you'll just stay there.

you are looking for removeClass and addClass
removeClass support function, remove pattern class is very easy. so you can do in this way:
$('#my_div').removeClass(function(index, css) {
return (css.match(/\blarge-\S+/g) || []).join(' ');
})
in your case.
var matchClass;
$('#my_div').removeClass(function (index, css) {
matchClass = css.match(/\blarge-\S+/g);
return (matchClass || []).join(' ');
});
matchClass=matchClass.map(function (item) {
item = item.split("-");
--item[item.length - 1];
console.log(item);
return item.join("-");
});
$('#my_div').addClass(matchClass.join(" "));
I made a example jsfiddle
-------------Update----------
if you like plugin, you can go this way:
(function () {
$.fn.riseClass = function (prefix,direct) {
var matchClass;
return this.each(function () {
$(this).removeClass(function (index, css) {
var regex=RegExp('\\b'+prefix+'-\\S+', "g");
matchClass = css.match(regex);
return (matchClass || []).join(' ');
});
matchClass = matchClass.map(function (item) {
item = item.split("-");
if (direct == "down") {
item[item.length - 1]--;
} else {
item[item.length - 1]++;
}
return item.join("-");
});
$(this).addClass(matchClass.join(" "));
});
};
})();
check on jsfiddle: plugin version

Related

jQuery / js toLowercase

I can't turn searchBox to a .toLowerCase and my code is case sensitive because of this. I want the code to scan on both upperCase and lowerCase letters.
I wasn't able to find a solution to my problem.
<script>
$("#searchBtn").keyup(function () {
var searchBox = $("#searchBtn").val();
var returnRows = [];
$('tr').not('.headerRow').each(function () {
var addRow = true;
var $currentRow = $(this);
$currentRow.find('td').each(function () {
var $td = $(this);
var word = $td.text();
if (word.indexOf(searchBox) > -1) {
addRow = false;
return false;
// console.log("KOMT IN IF STATEMENT"); //sla deze rij op in een tijdelijke array
}
});
if (addRow) {
returnRows.push($currentRow)
}
});
if (true)
{
$('tr').show();
}
$.each(returnRows, function (i, v) {
$(v).hide();
});
});
</script>
I am not sure but you are making it a bit more complicated. Try something like this:
$("#searchBtn").keyup(function() {
var word = $("#searchBtn").val(),
timer;
if(timer){ clearTimeout(timer); }
timer = setTimeout(function(){
$('tr').not('.headerRow').filter(function(){
var txt = $(this).find('td').text();
return txt.indexOf(word) !== -1 && txt === word;
}).hide();
},900);
});
=== lets you compare strictly. So, in such case T !== t would result in true.

:contains case sensitive not working appropriately

I have added the code to overwrite the contains method however I am still not getting the right result. I have created a JFiddle to show the problem. http://jsfiddle.net/zjAyX/ I have also tried the code that works with the jQuery 1.8 which is the version of jQuery I'm using. Where do I place the code?
$(function() {
$.extend($.expr[":"], {
"containsIN": function(elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
$("#searchInput").keyup(function () {
//split the current value of searchInput
var data = this.value.split(" ");
//create a jquery object of the rows
var jo = $("tbody").find("tr");
if (this.value == "") {
jo.hide();
return;
}
//hide all the rows
jo.hide();
//Recusively filter the jquery object to get results.
jo.filter(function (i, v) {
var $t = $(this);
for (var d = 0; d < data.length; ++d) {
if ($t.is(":contains('" + data[d] + "')")) {
return true;
}
}
return false;
})
//show the rows that match.
.show();
}).focus(function () {
this.value = "";
$(this).css({
"color": "black"
});
$(this).unbind('focus');
}).css({
"color": "#C0C0C0"
});
});
Use :containsIN() instead of contains() in your condition.
jo.filter(function (i, v) {
var $t = $(this);
for (var d = 0; d < data.length; ++d) {
if ($t.is(":containsIN('" + data[d] + "')")) {
return true;
}
}
return false;
})
Demo: Fiddle

superslides jquery plugin customization

Hi All,
I need help customizing this jquery plugin so that the pagination looks like links with text in them instead of like the default.
So basically the output on the page should be: Link1 | Link2 | Link3,etc. I have tried creating an Array and returning that Array to the addPaginationItem() function, however, all attempts have been very unsuccessful.
Any help would be much appreciated as I have been struggling with it.
2 main functions Code that I need to manipulate looks as follows:
addPaginationItem = function(i) {
if (!(i >= 0)) {
i = _this.size() - 1;
}
return $pagination.append($("<a>", {
href: "#" + i,
"class": _this.current === $pagination.children().length ? "current" : void 0
}));
};
addPagination = function() {
var array, last_index;
if (!_this.options.pagination || _this.size() === 1) {
return;
}
if ($(el).find("." + _this.options.classes.pagination).length) {
last_index = $pagination.children().last().index();
array = $children;
} else {
last_index = 0;
array = new Array(_this.size() - last_index);
$pagination = $pagination.appendTo(_this.el);
}
return $.each(array, function(i) {
return addPaginationItem(i);
});
};
Thanks
I have solved my own problem. I think I just needed to walk away from the code for a bit.
Thanks all. I added the following code which solved my problem
addPaginationItem = function(i,linkText) {
if (!(i >= 0)) {
i = _this.size() - 1;
}
return $pagination.append($("<a>", {
href: "#" + i,
text:linkText,
"class": _this.current === $pagination.children().length ? "current" : void 0
}));
};
addPagination = function() {
var array, last_index;
var hrefText = ['test1','test2','test3','test4'];
if (!_this.options.pagination || _this.size() === 1) {
return;
}
if ($(el).find("." + _this.options.classes.pagination).length) {
last_index = $pagination.children().last().index();
array = $children;
} else {
last_index = 0;
array = new Array(_this.size() - last_index);
$pagination = $pagination.appendTo(_this.el);
}
$.each(hrefText,function(intIndex,objValue) {
linkText = objValue;
return addPaginationItem(intIndex,linkText)
});
};

Add space between numbers/digits and letters/characters

I have a code like this
(function($, window, document, undefined) {
$.fn.quicksearch = function (target, opt) {
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
delay: 100,
selector: null,
stripeRows: null,
loader: null,
noResults: '',
bind: 'keyup',
onBefore: function () {
return;
},
onAfter: function () {
return;
},
show: function () {
this.style.display = "";
},
hide: function () {
this.style.display = "none";
},
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
}, opt);
this.go = function () {
var i = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
if (val_empty || options.testQuery(query, cache[i], rowcache[i])) {
options.show.apply(rowcache[i]);
noresults = false;
} else {
options.hide.apply(rowcache[i]);
}
}
if (noresults) {
this.results(false);
} else {
this.results(true);
this.stripe();
}
this.loader(false);
options.onAfter();
return this;
};
this.stripe = function () {
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
{
var joined = options.stripeRows.join(' ');
var stripeRows_length = options.stripeRows.length;
jq_results.not(':hidden').each(function (i) {
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
});
}
return this;
};
this.strip_html = function (input) {
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
output = $.trim(output.toLowerCase());
return output;
};
this.results = function (bool) {
if (typeof options.noResults === "string" && options.noResults !== "") {
if (bool) {
$(options.noResults).hide();
} else {
$(options.noResults).show();
}
}
return this;
};
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
}
return this;
};
this.cache = function () {
jq_results = $(target);
if (typeof options.noResults === "string" && options.noResults !== "") {
jq_results = jq_results.not(options.noResults);
}
var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
cache = t.map(function () {
return e.strip_html(this.innerHTML);
});
rowcache = jq_results.map(function () {
return this;
});
return this.go();
};
this.trigger = function () {
this.loader(true);
options.onBefore();
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
e.go();
}, options.delay);
return this;
};
this.cache();
this.results(true);
this.stripe();
this.loader(false);
return this.each(function () {
$(this).bind(options.bind, function () {
val = $(this).val();
e.trigger();
});
});
};
}(jQuery, this, document));
I try to figure out where and how I can make a split/add space between numbers and letters. Cause some people type for example "ip1500" and the script cant match the input with an element that is like "ip 1500". My problem ist that Im a js beginner.
I was trying and trying but i cant get it work. I also tried this
I found this spot and I think it can be done here where the everything get splitted by an " " (space):
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
Would be very nice if somebody can help me.
If you want "123abc345def" to "123 abc 345 def". The replace function may help. The code is like this.
var str = "123abc345def";
str = str.replace(/(\d+)/g, function (_, num){
console.log(num);
return ' ' + num + ' ';
});
str = str.trim();
The code you linked didn't work mainly because it's using a different programming language to javascript. In theory, it should work, but javascript does not support regular expression lookbehinds (at this present time)..
Instead, I have re-wrote that fragment of code:
prepareQuery: function (val) {
function isNotLetter(a){
return (/[0-9-_ ]/.test(a));
}
var val=val.toLowerCase().split("");
var tempArray=val.join("").split("");
var currentIndex=1;
for (var i=0;i<val.length-1;i++){
if (isNotLetter(val[i]) !== isNotLetter(val[i+1])){
tempArray.splice(i+currentIndex, 0, " ");
currentIndex++;
}
}
return tempArray.join("");
}
Since you're new to javascript, I'm going to explain what it does.
It declares a function in prepareQuery to check whether or not a string contains a letter [this can be moved somewhere else]
It then splits val into an array and copies the content of val into tempArray
An index is declared (explained later)
A loop is made, which goes through every single character in val
The if statement detects whether or not the current character (val[i] as set by the loop) is the same as the character next to it (val[i+1]).
IF either one are different to the other (ie the current character is a letter while the next isn't) then a space is added to the tempArray at that "index"
The index is incremented and used as an offset in #6
The loop finishes, joins the "array" into a string and outputs the result.
DEMO:
http://jsbin.com/ebitus/1/edit
(JSFiddle was down....)
EDIT:
Sorry, but I completely misinterpreted your question... You failed to mention that you were using "quicksearch" and jQuery. In that case I'm assuming that you have a list of elements that have names and you want to search through them with the plugin...
A much easier way to match the user's query (if there is no space) is to strip the space from the search table along with the query itself - though original reverse method will work (just not as efficiently) [aka: expanding the user's query]
In this case, stripping the space from both the search table and user input would be a better method
prepareQuery: function (val) {
return val.toLowerCase().replace(/ /ig,'').split(" ");
},
testQuery: function (query, txt, _row) {
txt=txt.toLowerCase().replace(/ /ig,'');
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
DEMO:
http://jsfiddle.net/q9k9Y/3/
Edit 2:
It seems like your real intent is to create a fully functioning search feature on your website, not to just add spaces between letters and numbers. With this, I suggest using Quicksilver. I would love to work out an algorithm to extend quickSearcher but at the current time I cannot (timezones). Instead, I suggest using Quicksilver
http://jsbin.com/oruhet/12/

Can this jQuery be done in vanilla JS?

I've got this working on mobile devices, but because of the 32kb gzip-ed of jQuery I wonder if it's possible to create this code
$(document).ready(function() {
$('body').addClass('js');
var $menu = $('#menu'),
$menulink = $('.menu-link'),
$wrap = $('#wrap');
$menulink.click(function() {
$menulink.toggleClass('active');
$wrap.toggleClass('active');
return false;
});
});
can be written in no library dependany vanilla JavaScript.
Can it be done? Where would I start?
JQuery uses javascript/DOMscripting to create its framework. Everything JQuery does, can be done in basic scripting. For example $('body').addClass('js') can be written as:
document.querySelector('body').className += ' js';
And $menulink.toggleClass('active'); as something like
var current = $menulink.className.split(/\s+/)
,toggleClass = 'active'
,exist = ~current.indexOf(toggleClass)
;
current.splice(exist ? current.indexOf(toggleClass) : 0,
exist ? 1 : 0,
exist ? null : toggleClass);
$menulink.className = current.join(' ').replace(/^\s+|\s+$/,'');
That's why JQuery wrapped this kind of code.
This jsfiddle contains a working example using javascript without a framework. Besides that it demonstrates how to program your own element wrapper.
Where to start? You'll have to dive into javascript I suppose. Or check this SO-question
For modern browsers only.®
document.addEventListener('DOMContentLoaded', function() {
document.body.classList.add('js');
var wrap = document.getElementById('wrap');
var menuLinks = Array.prototype.slice.call(document.getElementsByClassName('menu-link'));
var toggleActive = function(element) {
element.classList.toggle('active');
};
menuLinks.forEach(function(menuLink) {
menuLink.addEventListener('click', function(e) {
menuLinks.forEach(toggleActive);
toggleActive(wrap);
}, false);
});
}, false);
var toggleClass = function (el, className) {
if(el) {
if(el.className.indexOf(className)) {
el.className = el.className.replace(className, '');
}
else {
el.className += ' ' + className;
}
}
};
document.addEventListener('DOMContentLoaded', function () {
document.body.className += ' js';
var $menu = document.querySelector('#menu'),
$menulink = document.querySelectorAll('.menu-link'),
$wrap = document.querySelector('#wrap');
$menulink.addEventListener('click', function (e) {
toggleClass($menulink, 'active');
toggleClass($wrap, 'active');
e.preventDefault();
});
});
There's always classList (workaround for incompatible browsers included).
Absolutely. Since jQuery is a subset of JavaScript (written entirely in JavaScript) any function you like can be duplicated. It's a matter of how much effort you want to put into it. Below is how I would duplicate the limited subset of jQuery in your post and it's reasonably cross-browser compatible (if a wee bit long...).
var Vanilla;
if (!Vanilla) {
Vanilla = {};
}
//execute this now to have access to it immediately.
(function () {
'use strict';
Vanilla.addHandler = function (elem, event, handler) {
if (elem.addEventListener) {
elem.addEventListener(event, handler, false);
} else if (elem.attachEvent) {
elem.attachEvent('on' + event, handler);
}
};
Vanilla.hasClass = function (elem, cssClass) {
var classExists = false;
//
if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
classExists = elem.className.indexOf(cssClass) > -1;
}
//
return classExists;
};
Vanilla.addClass = function (elem, cssClass) {
if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
//put spaces on either side of the new class to ensure boundaries are always available
elem.className += ' ' + cssClass + ' ';
}
};
Vanilla.removeClass = function (elem, cssClass) {
if (elem && typeof elem.className === 'string'&& (/\S+/g).test(cssClass)) {
//replace the string with regex
cssClass = new RegExp('\\b' + cssClass + '\\b', 'g');
elem.className = elem.className.replace(cssClass, '').replace(/^\s+/g, '').replace(/\s+$/g, ''); //trim className
}
};
Vanilla.toggleClass = function (elem, cssClass) {
if (Vanilla.hasClass(elem, cssClass)) {
Vanilla.removeClass(elem, cssClass);
} else {
Vanilla.addClass(elem, cssClass);
}
};
Vanilla.getElementsByClassName = function (cssClass) {
var nodeList = [],
classList = [],
allNodes = null,
i = 0,
j = 0;
if (document.getElementsByClassName1) {
//native method exists in browser.
nodeList = document.getElementsByClassName(cssClass);
} else {
//need a custom function
classList = cssClass.split(' ');
allNodes = document.getElementsByTagName('*');
for (i = 0; i < allNodes.length; i += 1) {
for (j = 0; j < classList.length; j += 1) {
if (Vanilla.hasClass(allNodes[i], classList[j])) {
nodeList.push(allNodes[i]);
}
}
}
}
return nodeList;
};
}());
//Now we have a proper window onload
Vanilla.addHandler(window, 'load', function () {
'use strict';
var body = document.body,
menu = document.getElementById('menu'),
menulink = [],
wrap = document.getElementById('wrap'),
i = 0,
menulinkClickHandler = function (e) {
var i = 0;
for (i = 0; i < menulink.length; i += 1) {
Vanilla.toggleClass(menulink[i], 'active');
}
Vanilla.toggleClass(wrap, 'active');
return false;
};
Vanilla.addClass(body, 'js');
menulink = Vanilla.getElementsByClassName('menu-link');
for (i = 0; i < menulink.length; i += 1) {
Vanilla.addHandler(menulink[i], 'click', menulinkClickHandler);
}
});

Categories

Resources