Can this jQuery be done in vanilla JS? - javascript

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);
}
});

Related

How do I change the two "click" EventListeners to do the opposite function in JavaScript?

I just started learning JavaScript, and I am trying to get two different EventListeners to do the opposite function. Right now, I have it so that you can click on a mark and then a word, letter, or space and the mark appears/disappears there. I want to be able to click a word, letter, or space then click on a mark to add/remove it. Sentence Punctuation Marks I've tried switching the .querySelector and .querySelectorAll, but that doesn't work. Any help would be much appreciated.
var classlist = el.querySelectorAll(".letter, .space");
for (var i = 0; i < classlist.length; i++) {
classlist[i].addEventListener("click", function(event) {
var element = this.parentNode;
console.log(this);
if (
tooltype === "longVowel" ||
tooltype === "shortVowel" ||
this.classList.contains("space") === true
) {
element = this;
console.log(element);
}
var add = true;
var checklist = element.querySelectorAll("." + tooltype);
if (checklist.length > 0) {
add = false;
}
socket0s6.emit("action", {
slide: demo6,
action: "markingWords",
element: element.id,
class: tooltype,
add: add,
});
});
}
var classlist = el.querySelector(".toolbar").querySelectorAll("li");
for (var i = 0; i < classlist.length; i++) {
classlist[i].addEventListener("click", function(event) {
tooltype = this.className;
});
}
document.getElementById("slideContainer").appendChild(el);
/*}
//var oReq = new XMLHttpRequest();
//oReq.addEventListener("load", reqListener);
//oReq.open("GET", "slides/lesson0/slide6.html");
//oReq.send();*/
/*************** Server action ******************/
//socket0s6.on('action', function(details) {
var socket0s6 = {
emit: function(a, details) {
// //console.log(details[1]);
if (details.slide === demo6 && details.action === "markingWords") {
//document.getElementById(details.element).classList.toggle("active");
if (details.add) {
var el = document.createElement("span");
el.className = details.class;
document.getElementById(details.element).appendChild(el);
} else {
//where we will put code to find and remove existing marks
var markList = document
.getElementById(details.element)
.querySelectorAll("." + details.class);
console.log(markList);
for (var i = 0; i < markList.length; i++) {
markList[i].parentNode.removeChild(markList[i]);
}
}
}
},
};

Can't call function on HTML element

I'm starting to write jQuery in Vanilla JS and my selectors work but when I call my append function on the HTML element I get an "is not a function" error.
var $ = function(){
this.select = function(input) {
if (input.split("")[0] == "#") {
input = input.slice(1, input.length)
return document.getElementById(input)
}
else if (input.split("")[0] == ".") {
input = input.slice(1, input.length)
return document.getElementsByClassName(input)
}
else {
return document.getElementsByTagName(input)
}
},
this.append = function(text) {
return this.innerhtml = this.innerhtml + text
}
};
my console attempts:
var myQuery = new $();
returns undefined
myQuery.select("#testspan")
returns my span tag here
myQuery.select("#testspan").append("hellohello")
returns error
VM2207:1 Uncaught TypeError: myQuery.select(...).append is not a function(…)
From your snippet the return of each of the select method return a DOM element (or collection). Really what you would like to do is called Chaining where the result of the method returns the original object. Therefore you can keep calling additional methods on the same object.
Now in your example you are going to need a collection of elements (nodes) somewhere the object can then access again. Here is a simple example.
var $ = function () {
this.nodes = [];
this.select = function (input) {
var self = this;
if (input.split("")[0] == "#") {
input = input.slice(1, input.length)
var node = document.getElementById(input);
if (node)
this.nodes.push(node);
}
else if (input.split("")[0] == ".") {
input = input.slice(1, input.length)
Array.prototype.slice.call(document.getElementsByClassName(input), 0).forEach(function (node) {
self.nodes.push(node);
});
}
else {
Array.prototype.slice.call(document.getElementsByTagName(input), 0).forEach(function (node) {
self.nodes.push(node);
});
}
return this;
},
this.append = function (text) {
this.nodes.forEach(function (i) {
i.innerHTML += text;
});
return this;
}
};
Sample Html:
<p id="test">This is test </p>
<p>This is number to</p>
Console (Chrome):
$ = new $()
$ {nodes: Array[0]}
$.select('p').append('hi')
Now a little issue here is you are (in the console) setting $ = new $() which effectivly overwrites the ability to call new $() again in the same script. I have provided a fiddle below that renames this to myQuery. Also changed that every time you call select will clear the node array.
Revised:
var myQuery = function () {
this.nodes = [];
this.select = function (input) {
this.nodes = [];
var self = this;
if (input.split("")[0] == "#") {
input = input.slice(1, input.length)
var node = document.getElementById(input);
if (node)
this.nodes.push(node);
}
else if (input.split("")[0] == ".") {
input = input.slice(1, input.length)
Array.prototype.slice.call(document.getElementsByClassName(input), 0).forEach(function (node) {
self.nodes.push(node);
});
}
else {
Array.prototype.slice.call(document.getElementsByTagName(input), 0).forEach(function (node) {
self.nodes.push(node);
});
}
return this;
},
this.append = function (text) {
this.nodes.forEach(function (i) {
i.innerHTML += text;
});
return this;
}
};
$ = new myQuery();
$.select('p').append(' test selection by tag name ');
$ = new myQuery();
$.select('.p1').append(' test selection by class ');
$ = new myQuery();
$.select('#p1').append(' test selection by id ');
$ = new myQuery();
$.select('#p2').append(' test selection by id ').append('and then chanined').select('.p2').append(' still chaining');
Fiddle: https://jsfiddle.net/kxwt9gmg/
You need to change up your approach a bit. You are wanting to store a result and call a method on it. You can ONLY call a method that that particular object has. That object you are returning, the raw html element, doesn't have that method. What you want to do is store the html element and then return an OBJECT that performs operations on what was stored. You can accomplish this using closure. For example:
function miniQuery(input){
function elementIterate(collection, action){
for (var i = elements.length -1; i >= 0; i-- ){
collection[i].style.display = action;
}
}
var isCollection = function(element){
if(element instanceof HTMLCollection){
return true
} else{
return false
}
}
function findElement(element){
if (element.startsWith("#")) {
// id element selector
return document.getElementById(element.substring(1));
} else if (element.startsWith(".")) {
// class element selector
return document.getElementsByClassName(element.substring(1));
} else {
// tag element selector
return document.getElementsByTagName(element);
};
}
if (input != undefined) {
var _this = this;
this.element = findElement(input);
var elements = findElement(input);
}
return {
append: function(content, position = 'beforeend'){
var elements = _this.element;
if (isCollection(elements)) {
for(var i = elements.length -1; i >= 0; i--){
elements[i].insertAdjacentHTML(position, content)
}
}else{
elements.insertAdjacentHTML(position, content);
}
}
}
}
function $(input){
return selector(input);
}
function selector(input){
var query = new miniQuery(input);
return query;
}

toggle class with pure javascript [duplicate]

I'm looking for a way to convert this jQuery code (which is used in responsive menu section) to pure JavaScript.
If it's hard to implement it's OK to use other JavaScript frameworks.
$('.btn-navbar').click(function()
{
$('.container-fluid:first').toggleClass('menu-hidden');
$('#menu').toggleClass('hidden-phone');
if (typeof masonryGallery != 'undefined')
masonryGallery();
});
2014 answer: classList.toggle() is the standard and supported by most browsers.
Older browsers can use use classlist.js for classList.toggle():
var menu = document.querySelector('.menu') // Using a class instead, see note below.
menu.classList.toggle('hidden-phone');
As an aside, you shouldn't be using IDs (they leak globals into the JS window object).
Here is solution implemented with ES6
const toggleClass = (el, className) => el.classList.toggle(className);
usage example
toggleClass(document.querySelector('div.active'), 'active'); // The div container will not have the 'active' class anymore
Take a look at this example: JS Fiddle
function toggleClass(element, className){
if (!element || !className){
return;
}
var classString = element.className, nameIndex = classString.indexOf(className);
if (nameIndex == -1) {
classString += ' ' + className;
}
else {
classString = classString.substr(0, nameIndex) + classString.substr(nameIndex+className.length);
}
element.className = classString;
}
don't need regex just use classlist
var id=document.getElementById('myButton');
function toggle(el,classname){
if(el.classList.contains(classname)){
el.classList.remove(classname)
}
else{
el.classList.add(classname)
}
}
id.addEventListener('click',(e)=>{
toggle(e.target,'red')
})
.red{
background:red
}
<button id="myButton">Switch</button>
Simple Usage above Example
var id=document.getElementById('myButton');
function toggle(el,classname){
el.classList.toggle(classname)
}
id.addEventListener('click',(e)=>{
toggle(e.target,'red')
})
.red{
background:red
}
<button id="myButton">Switch</button>
This one works in earlier versions of IE also.
function toogleClass(ele, class1) {
var classes = ele.className;
var regex = new RegExp('\\b' + class1 + '\\b');
var hasOne = classes.match(regex);
class1 = class1.replace(/\s+/g, '');
if (hasOne)
ele.className = classes.replace(regex, '');
else
ele.className = classes + class1;
}
.red {
background-color: red
}
div {
width: 100px;
height: 100px;
margin-bottom: 10px;
border: 1px solid black;
}
<div class="does red redAnother " onclick="toogleClass(this, 'red')"></div>
<div class="does collapse navbar-collapse " onclick="toogleClass(this, 'red')"></div>
This is perhaps more succinct:
function toggle(element, klass) {
var classes = element.className.match(/\S+/g) || [],
index = classes.indexOf(klass);
index >= 0 ? classes.splice(index, 1) : classes.push(klass);
element.className = classes.join(' ');
}
If anyone looking to toggle class on mousehover/mousleave using Javascript here is the code for it
function changeColor() {
this.classList.toggle('red');
this.classList.toggle('green');
}
document.querySelector('#btn').addEventListener('mouseenter', changeColor);
document.querySelector('#btn').addEventListener('mouseleave', changeColor );
Demo Fiddle link: https://jsfiddle.net/eg2k7mLj/1/
Source: Toggle Class (Javascript based, without jQuery)
Just for legacy reasons:
function toggleClassName(elementClassName, className) {
const originalClassNames = elementClassName.split(/\s+/);
const newClassNames = [];
let found = false;
for (let index = 0; index < originalClassNames.length; index++) {
if (originalClassNames[index] === '') {
continue;
}
if (originalClassNames[index] === className) {
found = true;
continue;
}
newClassNames.push(originalClassNames[index]);
}
if (!found) {
newClassNames.push(className);
}
return newClassNames.join(' ');
}
console.assert(toggleClassName('', 'foo') === 'foo');
console.assert(toggleClassName('foo', 'bar') === 'foo bar');
console.assert(toggleClassName('foo bar', 'bar') === 'foo');
console.assert(toggleClassName('bar foo', 'bar') === 'foo');
console.assert(toggleClassName('foo bar baz', 'bar') === 'foo baz');
console.assert(toggleClassName('foo-bar', 'foo') === 'foo-bar foo');
console.assert(toggleClassName('bar foo-bar', 'bar') === 'foo-bar');
console.assert(toggleClassName('bar bar bar foo-bar bar', 'bar') === 'foo-bar');
console.assert(toggleClassName(" \n\nbar-bar \nbar-baz foo", 'bar-baz') === 'bar-bar foo');
element.className = toggleClassName(element.className, 'foo');
Try this (hopefully it will work):
// mixin (functionality) for toggle class
function hasClass(ele, clsName) {
var el = ele.className;
el = el.split(' ');
if(el.indexOf(clsName) > -1){
var cIndex = el.indexOf(clsName);
el.splice(cIndex, 1);
ele.className = " ";
el.forEach(function(item, index){
ele.className += " " + item;
})
}
else {
el.push(clsName);
ele.className = " ";
el.forEach(function(item, index){
ele.className += " " + item;
})
}
}
// get all DOM element that we need for interactivity.
var btnNavbar = document.getElementsByClassName('btn-navbar')[0];
var containerFluid = document.querySelector('.container-fluid:first');
var menu = document.getElementById('menu');
// on button click job
btnNavbar.addEventListener('click', function(){
hasClass(containerFluid, 'menu-hidden');
hasClass(menu, 'hidden-phone');
})`enter code here`
Here is a code for IE >= 9 by using split(" ") on the className :
function toggleClass(element, className) {
var arrayClass = element.className.split(" ");
var index = arrayClass.indexOf(className);
if (index === -1) {
if (element.className !== "") {
element.className += ' '
}
element.className += className;
} else {
arrayClass.splice(index, 1);
element.className = "";
for (var i = 0; i < arrayClass.length; i++) {
element.className += arrayClass[i];
if (i < arrayClass.length - 1) {
element.className += " ";
}
}
}
}
If you want to toggle a class to an element using native solution, you could try this suggestion. I have tasted it in different cases, with or without other classes onto the element, and I think it works pretty much:
(function(objSelector, objClass){
document.querySelectorAll(objSelector).forEach(function(o){
o.addEventListener('click', function(e){
var $this = e.target,
klass = $this.className,
findClass = new RegExp('\\b\\s*' + objClass + '\\S*\\s?', 'g');
if( !findClass.test( $this.className ) )
if( klass )
$this.className = klass + ' ' + objClass;
else
$this.setAttribute('class', objClass);
else
{
klass = klass.replace( findClass, '' );
if(klass) $this.className = klass;
else $this.removeAttribute('class');
}
});
});
})('.yourElemetnSelector', 'yourClass');
I know that I am late but, I happen to see this and I have a suggestion..
For those looking for cross-browser support, I wouldn't recommend class toggling via JS.
It may be a little more work but it is more supported through all browsers.
document.getElementById("myButton").addEventListener('click', themeswitch);
function themeswitch() {
const Body = document.body
if (Body.style.backgroundColor === 'white') {
Body.style.backgroundColor = 'black';
} else {
Body.style.backgroundColor = 'white';
}
}
body {
background: white;
}
<button id="myButton">Switch</button>
function navbarToggler() {
const collapseBtn = document.querySelector('.collapseBtn').classList
collapseBtn.toggle('collapse')
}

Regex to change a html element class with javascript not working

I have the following javascript function to open and close sub list elements on an onclick event:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className == "nav nav-second-level collapse in") {
subMen.className = "nav nav-second-level collapse";
} else {
subMen.className += " in";
}
}
}
The "collapse" is a css class which makes display=none hiding the sub list and "in" is a class which makes display=block showing the sub list, creating a menu with submenus.
I found in this question Change an element's class with JavaScript in the first(accepted) answer use of a regex in order to do this. I tried it like this:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
} else {
subMen.className += " in";
}
}
}
The code without the regex works perfectly but with the regex it doesn't. I checked the regex in regex101.com and it seems to work there. As I understand it's more appropriate to use the regex than a long string of all the class names and also I also have a nav-third-level class that I have to close and open so the regex seems to be the convenient and proper way to do it.
What's wrong?
Thank you.
No need of regex here. You can use classList
Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className.
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
subMen.classList.toggle('in');
}
}
toggle() will toggle the class of the element. If the element already has the class, it'll remove it, if not then toggle will add the class to the element.
Check the Browser Compatibility.
You can use following SHIM from MDN for IE9,
/*
* classList.js: Cross-browser full element.classList implementation.
* 2014-07-23
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! #source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if ("document" in self) {
// Full polyfill for browsers with no classList support
if (!("classList" in document.createElement("_"))) {
(function (view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList",
protoProp = "prototype",
elemCtrProto = view.Element[protoProp],
objCtr = Object,
strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
},
arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0,
len = this.length;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
,
DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
},
checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR", "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR", "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
},
ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || ""),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
i = 0,
len = classes.length;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute("class", this.toString());
};
},
classListProto = ClassList[protoProp] = [],
classListGetter = function () {
return new ClassList(this);
};
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false;
do {
token = tokens[i] + "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false,
index;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
token += "";
var
result = this.contains(token),
method = result ?
force !== true && "remove" :
force !== false && "add";
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
} else {
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function () {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function (method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function (token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function (token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
testElement = null;
}());
}
}
If you're using jQuery, you can use toggleClass():
function ShowHideDtls(itId) {
$('#' + itId).toggleClass('in');
}
Edit
If you still want to use regex:
if (/\bin\b/.test(subMen.className))
subMen.className.replace(/\bin\b/, '');
} else {
subMen.className += " in";
}
You can also use split() and indexOf as follow to check if a class is present on element.
var classes = className.split(/\s+/),
classIndex = classes.indexOf('in');
if (classIndex > -1) {
classes.splice(classIndex, 1);
subMen.className = classes.join(' ');
} else {
subMen.className += " in";
}
replace function returns the resultant value, it do not assign value indirectly.
So do following:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className = subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
}
else {
subMen.className += " in";
}
}
}

Javascript select element in library

I am working on a javascript library that will work like this: tex("element").print("hi"). Here is the code:
(function (window) {
var regex = {
Id : /^[#]\w+$/,
Class : /^[.]\w+$/,
Tag : /^\w+$/,
validSelector : /^([#]\w+|[.]\w+|\w+)$/
},
tex = function(selector){
//only some of the functions need to select an element
//EX:
// style: tex(selector).style(style);
//one that would not need a selector is the random number function:
// tex().random(from,to);
if (selector){
if (typeof selector === 'string'){
var valid = regex.validSelector.test(selector);
if( valid ){
if(regex.Id.test(selector)){
this = document.getElementById(selector);
}
if(regex.Class.test(selector)){
this = document.getElementByClass(selector);
}
if(regex.Tag.test(selector)){
this = document.getElementByTagName(selector);
}
}
}else if(typeof selector === 'object'){
this = selector;
}
//this = document.querySelector(selector);
// I could make a selector engine byt I only need basic css selectors.
}
};
tex.prototype = {
dit : function(){
this.innerHTML = 'Hi?!?!?!'
}
};
window.tex = tex;
})(window);
When I try to run the code I get an error that says, "Left side of argument is not a reference" referring to this = document.getElementById(selector);
Does anyone know what is wrong with my code?
Because you can not set this.
To do something that you are after, you just return this.
without using a prototype
var foo = function( selector ) {
this.print = function () {
console.group("in print");
console.log(this.elements[0].innerHTML);
console.groupEnd("in print");
return this;
}
this.printAll = function () {
console.group("in printAll");
for (var i=0; i<this.elements.length; i++) {
console.log(this.elements[i].innerHTML);
}
console.groupEnd("in printAll");
return this;
}
this.elements = document.querySelectorAll( selector );
return this;
}
console.group("id");
foo("#foofoo").print();
console.groupEnd("id");
console.group("class");
foo(".bar").printAll().print();
console.groupEnd("class");
JSFiddle
Basic example with prototype
(function () {
var basic = function (selector) {
this.elements = document.querySelectorAll(selector);
return this;
}
basic.prototype.print = function () {
console.group("in print");
console.log(this.elements[0].innerHTML);
console.groupEnd("in print");
return this;
}
basic.prototype.printAll = function () {
console.group("in printAll");
for (var i = 0; i < this.elements.length; i++) {
console.log(this.elements[i].innerHTML);
}
console.groupEnd("in printAll");
return this;
}
var foo = function (selector) {
return new basic(selector);
}
window.foo = foo;
})();
console.group("id");
foo("#foofoo").print();
console.groupEnd("id");
console.group("class");
foo(".bar").printAll().print();
console.groupEnd("class");
JSFiddle

Categories

Resources