Looking at the website, I cannot figure out what it does, find actual code examples, the documentation seems nonexistent, and overall the lack of content on the site (much less zero content per page) really isn't blowing my skirt up.
What little code I can find -- like that codepen -- seems to use outdated/sloppy methodology like writing markup to the document innerHTML style, use gibberish heading depths indicating a lack of the fundamentals of using HTML properly... and I think whatever it is doing is utterly banjaxed given how painfully slow loading even the pen is, much less the massive 5 second-plus delay for the event handler!
That you have to "new" the object instance also seems a bit wasteful/pointless.
Document it better, put more emphasis on working with the DOM instead of slopping out markup in strings, maybe provide some polyfills so it can actually be deployed on production websites... and maybe we'll talk.
You could probably also benefit from the fact that Object.prototype can be used to extend an existing object letting you {} your subfunctions instead of doing Zam.prototype.whatever every joe-blasted time. Same goes for your multiple VAR for nothing, checks for null on things that would never be anything but loose true or null, and so forth.
Even just something as simple as your (confusingly named) index function could be gutted down to:
Zam.prototype.countMatchingPrevSiblingTagNames = function(e) {
var
i = 0,
match = e.tagName.toLowerCase();
while (e = e.previousElementSibling)
if (e.tagName.toLowerCase() === match)
i++;
return i;
}
That way you aren't wasting time creating an extra element value, a calculation/function call that does NOT change in value isn't wasting time being run inside the loop, and you REALLY don't need to waste time on that null check since DOM nodes either exist or they don't.
THOUGH I would write that as:
Zam.prototype.countMatchingPrevSiblingTagNames = function(e) {
var
i = 0,
match = e.tagName.toLowerCase();
while (e = e.previousSibling)
if (e.nodeType == 1 && e.tagName.toLowerCase() === match)
i++;
return i;
}
Since previousElementSibling is too new to rely upon in deployment on websites -- though if all I cared about was building crapplets in something like electron, nw.js or so forth, THEN I'd skip the compatibility check.
NOT that I can figure out any reason why you'd want to count the number of matching tags that are previous siblings in a practical usage scenario.
Other functions could benefit from the "it's either null or loose true" optimization, take your (uselessly vaguely named) "c" function.
Zam.prototype.c = function(event, target, func) {
if(typeof(func) === 'string') func = this.functions[func];
if (func.name !== 'anonymous') this.functions[func.name] = func;
if (typeof(target) == 'object') e.addEventListener(event, func, false);
else {
target = document.querySelectorAll(target);
for (var i = 0, e; e = target[i]; i++) e.addEventListener(event, func, false);
}
}
NOT that I'm sure why you're wasting time storing the functions being assigned in an array.
Oh, and I'd probably skip the on/off functions, and instead of trying to pass an space delimited string to it, why not accept either a string or an array. String for single event, array for multiples. That would simplify the detection of what's being passed down to typeof, and speed things up since you wouldn't be wasting time (and possibly memory) on a String.splice. Likewise that recursive call is no winner.
I'd also kill the fadein/fadeout nonsense that should be handled almost entirely by the stylesheet and triggered by nothing more than a class swap/toggle. This plays to the notion that 99% of the time you access style="" from the JavaScript, you're probably doing something WRONG! Like creating/accessing styles that make no sense for non-screen media users.
But really a number of things it does -- like your entire Zam.html function -- are things I would NEVER do in modern JavaScript in the first place, and was never a fan of either. Use the bloody DOM so you can skip the entire parser stage in the browser saving time, RAM, and possibly battery life.
Hence why where you have this in your codepen example:
zam.html('.stats', `
<span>
IP: `+data.ip+`
City: `+data.city+`
Zip: `+data.zip_code+`
</span>`
);
My own elementals.js library would have this:
_.make('span', {
content : '/\
IP: ' + data.ip + '\
City: ' + data.city + '\
Zip: ' + data.zip_code + \
\u00A0\
',
parent : document.getElementsByTagName(':span')[0]
});
(in practice I'd have to do a node flush, though depending on what the parent is I'd consider a 1:1 node replace skipping the SPAN entirely)
Note I'm using escaped line endings for multiline as backtick strings are too new for web deployment, and I have to use the utf-8 character code for a non-breaking space since my library uses document.createTextNode which escapes ALL code.
Which is an advantage to the approach of going to the DOM and building proper textnodes as it means code injections are impossible. The way you're doing it someone types in "<script>document.write('tarfu');</script>" as their city, and that scripting will actually RUN!
Hence why I think innerHTML really needs to go the way of the dodo for all but the rarest of corner-cases. It is an outdated, outmoded relic of the past that's saddled with gross inefficiencies.