Super minimal selector and event library

Overview

min.js

A super tiny JavaScript library to execute simple DOM querying and hooking event listeners. Aims to return the raw DOM node for you to manipulate directly, using HTML5 (et al) tech like element.classList or element.innerHTML, etc.

Flattr this

Build Status

Query elements

var links = $('p:first-child a');

If there is more than one link, the return value is NodeList, if there's only a single match, you have an Element object. So you need to have an idea of what to expect if you want to modify the DOM.

Events

Bind events

$('p:first-child a').on('click', function (event) {
  event.preventDefault();
  // do something else
});

Note: the on and trigger methods are on both Node objects and NodeList objects, which also means this affects the document node, so document.on(type, callback) will also work.

Custom events

$('a').on('foo', function () {
  // foo was fired
});

$('a:first-child').trigger('foo');

Arbitrary events / pubsub

$.on('foo', function () {
  // foo was fired, but doesn't require a selector
});

Turning off events?

Current min.js has no support for turning off events (beyond .removeEventListener -- but even then you don't have the reference function to work with). Currently there's no plans to implement this (as I find I don't disable events very often at all) -- but I'm not closed to the idea. There's an issue open, but it adds quite a bit more logic to a very small file. If there's enough 👍 on the issue, I'll add it in. Equally, if you think min.js should stay simple, please 👎 -- this is useful too.

Looping

$('p').forEach(function (el, index) {
  console.log(el.innerHTML);
});

Note: jQuery-like libraries tend to make the context this the element. Since we're borrowing forEach from the array object, this does not refer to the element.

Chaining events

$('a').on('foo', bar).on('click', doclick).trigger('foobar');

Also when a single element is matched, you have access to it:

$('a').href = '/some-place.html';

Silent failing

Like jQuery, this tiny library silently fails when it doesn't match any elements. As you might expect.

More info

Comments
  • Don't use NodeList.__proto__

    Don't use NodeList.__proto__

    This is based on our Twitter discussion.

    The problematical code:

    nodeList = NodeList.__proto__ || NodeList.prototype
    

    and then

    nodeList[forEach] = each;
    

    NodeList.__proto__ shouldn't be used. In Chrome, it refers to Object.prototype (!!) and in Firefox it refers to some "magical" host object. So, in Chrome you're adding a forEach property to Object.prototype, i.e. you're extending Object.prototype. You're doing this unintentionally, but even if you were doing this on purpose, it would be an awful approach.

    From what I see, your intent is to be able to iterate over NodeList instances. The standard approach would be to extend NodeList prototype:

    NodeList.prototype.forEach = Array.prototype.forEach;
    

    But you're already doing the iteration differently by invoking Array.prototype.forEach via call() like so:

    each.call(this, function (el) {
      el.on(event, fn);
    });
    

    This is a good approach. It gets the job done just fine. Therefore, you don't need to add a forEach method to NodeList.prototype and the two lines of code (from the beginning of my message) should be removed. (Edit: Only the second line should be removed. The first line is need to add stuff to Node.prototype. See my pull request.)

    opened by simevidas 6
  • Added in some features!

    Added in some features!

    Hey,

    I saw those "Gotchas" you listed, which motivated me to see if I could fix them. I also thought it'd be nice to add in Grunt to manage the build process. So, long story short:

    • npm install -> fetches grunt, grunt-contrib-concat, and grunt-contrib-uglify
    • created /dist and /src folders and moved the script to /src/$.js
    • grunt build -> uglifies src/$.js to dist/$.js, dist/$.min.js, and $.js.map for source mapping
    • created a component.json if you want to bower register min.js git://github.com/remy/min.js.git
    • added chaining to triggers

    I also added an internal empty element (not inserted on the document). When no results are returned from $('a query'), this empty div is returned, which will allow .on and .trigger to be used, as any other element. Also, this fake element is used if a user wants to say, simply $.trigger and $.on, without using $ as a function.

    I think that's about it, lemme know what you think.

    opened by stephenplusplus 4
  • Refactored `element.trigger()` into a feature complete Strategy

    Refactored `element.trigger()` into a feature complete Strategy

    • Refactored element.trigger() into a strategy which uses CustomEvent if available
    • Normalized the Event shape between CustomEvent & document.createEvent("HTMLEvents");
    • Fixing a reference error of forEach()
    • Aligned variables because ... I do that
    opened by avoidwork 4
  • Fix component install.

    Fix component install.

    I was having trouble getting this module to work with component and making these changes to component.json seems to alleviate the issue.

    Specifically, it seems to have confused component to be missing the 'scripts' element and to use './' in the file paths.

    I've also made a stylistic change that I'd be happy to discuss: changing the component name to 'min' (as opposed to 'min.js'). That results in code that looks like this:

    require( 'min' );
    

    vs.

    require( 'min.js' );
    

    The former feels more like normal node.js require syntax.

    Thoughts?

    opened by andyburke 3
  • Why not use this.forEach within nodeList.on and nodeList.trigger?

    Why not use this.forEach within nodeList.on and nodeList.trigger?

    Not really an issue, but wasn't sure where I could pass this along? If you are only var'ing the "each" to use within the NodeList protototype addons, why not just declare it, and then actually use it?

    var list = NodeList.prototype
    
    list.forEach = Array.prototype.forEach
    
    list.on = function(e, fn) {
      this.forEach(function(el) { el.on(e, fn) })
      return this
    }
    
    list.trigger = function(e) {
      this.forEach(function(el) { el.trigger(e) })
      return this
    }
    
    opened by joncasey 1
  • About Bower

    About Bower

    Hey, I'm new to using Bower, but thought I'd share what I learned about how the versions work. The version you state in component.json will refer back to a tag from the git repository. With each tag, you effectively freeze the code where it is at that point, which then enables Bower users to ask for specific version, ex: bower install min.js#0.0.2

    When you've made a change big enough for a tag, run: git tag -a 0.0.3 -m 'v0.0.3' then push the branch with the --tags flag: git push origin master --tags

    Woo!

    opened by stephenplusplus 1
  • Headless tests, and the internal element is back!

    Headless tests, and the internal element is back!

    I'm back!

    Mostly, I thought it'd be cool to expand on the tests, and steer towards headless testing. grunt watch will watch for changes to /src and /test files, re-build the code, and re-run the tests. I wrote a few more tests, and split them out into a few different files as well.

    And, I added that internal element back in, but to be used in a slightly different way. I think having that hidden element is handy, for when you want to trigger and listen for an app-wide event. It could be something like "photoAdded" or "todoRemoved", allowing any part of your code who's interested to listen for that event, and execute whatever code is necessary as a result.

    To use it, it's $.on and $.trigger.

    So, let me know how you feel about that. I'm happy to yank it back out if that's not the direction you wanted to go with this.

    opened by stephenplusplus 1
  • Update $.js

    Update $.js

    nodeList should refer to NodeList.prototype instead of its .__proto__.

    The line nodeList[forEach] = each; is not needed as you're iterating NodeList instances by invoking Array.prototype.each directly and passing the NodeList instance via .call().

    opened by simevidas 0
  • When script loaded: Failed to execute 'createElement'

    When script loaded: Failed to execute 'createElement'

    Getting the following on Chrome 41 (and FF)

    Uncaught TypeError: Failed to execute 'createElement' on 'Document': 1 argument required, but only 0 present.

    image

    I'm probably doing something wrong, the script is loaded like:

    <script src="/static/bower_components/min.js/dist/$.js"></script>

    opened by wjdp 2
  • Allow .forEach() on a node

    Allow .forEach() on a node

    Hi Remy, just a suggestion: Allowing .forEach() on a node makes it easier to manipulate the result, regardless of whether one or many elements are returned. Thoughts?

    opened by MadeByMike 0
  • Different release versions

    Different release versions

    Hi,

    Since June 24 2013 there are no new tags on GitHub (the latest is version 0.1.0), your component.json is stuck at version 0.1.0, but package.json is on version 0.2.3. Can you update all files what contains a version number? I recommend https://github.com/mikaelbr/mversion to keep it up to date. Maybe you can create an 1.0 version, because it's stable since your last commit on July 22, 2013. Thank you in advance.

    opened by PMK 0
  • delegate

    delegate

    Looking at your source it doesn't seem like delegation is done correctly: you can't just compare the event.target, you have to find the closest ancestor matching the selector.

    This is how jQuery & Zepto do it, and that's the correct behaviour. Example:

    $('body').delegate('li > a', 'click', fn);
    

    If you've clicked a span within the a element then it won't match even though a child of the a element was indeed clicked.

    Because of this requirement, firing delegated events is actually quite a bit slower, and is rarely a necessity. I've opted against them in espresso.js and have not had any issues at all.

    opened by akrymski 1
  • Avoid conflicts with $

    Avoid conflicts with $

    Renamed the $ variable to minjs to remove conflicts with potential libraries. Using the module pattern you can still refer to minjs with a dollar.

    (function ($) { ... })(minjs);

    opened by dtsn 9
Owner
Remy Sharp
JavaScript (node + client side) developer with over 20 years experience. Contact me for any work or questions about JS I might be able to help you with.
Remy Sharp
io-ts Typed Event Bus for the runtime of your Node.js application. A core for any event-driven architecture based app.

Typed Event Bus Based on io-ts types, this bus provides a handy interface to publish and consume events in the current runtime of the Node.js process.

Konstantin Knyazev 3 May 23, 2022
A super simple minimal tRPC for next-js

Typed Routes A way to have fully typed routes in next, without all the complexity of tRPC. This is more for super minimal use cases, where you don't n

Rahul Tarak 4 Dec 28, 2022
Gatsby-starter-minimal-blog - Typography driven, feature-rich blogging theme with minimal aesthetics.

Gatsby-starter-minimal-blog - Typography driven, feature-rich blogging theme with minimal aesthetics. Includes tags/categories support and extensive features for code blocks such as live preview, line numbers, and line highlighting.

Priya Chakraborty 0 Jan 29, 2022
🌗 1 line of code to apply auto dark / light theme and support custom theme for your website. Super fast and lightweight theme library.

themes.js A super lightweight and fast Theme library with auto system color scheme detection in JavaScript. Features Auto detect Dark / Light mode by

SerKo 4 Nov 29, 2022
A super tiny Javascript library to make DOM elements draggable and movable. ~500 bytes and no dependencies.

dragmove.js A super tiny Javascript library to make DOM elements draggable and movable. Has touch screen support. Zero dependencies and 500 bytes Gzip

Kailash Nadh 814 Dec 29, 2022
Super tiny size multi-touch gestures library for the web.    You can touch this →

Preview You can touch this → http://alloyteam.github.io/AlloyFinger/ Install You can install it via npm: npm install alloyfinger Usage var af = new Al

腾讯 AlloyTeam 3.3k Dec 12, 2022
A ~2kb hotkeys library for solid that adds only 2 event listeners.

Solid Hotkeys - Cmd+S+H Solid Hotkeys is the easiest way to add hotkeys to your application. Built for and with Solid. Motivation You gotta have hotke

Alek Angelov 12 Aug 1, 2022
Mag🔥Lit - A super fast and easy-to-use free and open source private encrypted Magnet/HTTP(s) Link Shortener

Mag ?? Lit Mag ?? Lit - A super fast and easy-to-use free and open source private encrypted Magnet/HTTP(s) Link Shortener https://maglit.ml Features ✅

null 280 Jan 8, 2023
An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve and modify the bot state, respectively.

CQRS Wechaty An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve

Wechaty 3 Mar 23, 2022
A super simple and lightweight API to get crypto token live information.

TokenStats ?? ?? A super simple and lightweight API to get crypto token live information. APP URL https://tokenstats.herokuapp.com/ Quick Start To get

Abdulfatai Suleiman 21 Jun 28, 2022
Super Mario Bros using JavaScript and Kaboom.js

mario-kaboom.js Super Mario Bros using JavaScript and kaboom.js ?? This is a game of Super Mario Bros made using javascript and javascript gaming libr

Damini Pandey 3 May 6, 2022
✏️ Super lightweight JSX syntax highlighter, around 1KB after minified and gzipped

Sugar High Introduction Super lightweight JSX syntax highlighter, around 1KB after minified and gzipped Usage npm install --save sugar-high import { h

Jiachi Liu 67 Dec 8, 2022
A chip8 and super chip8 emulator.

(s)chip8 Emulator CHIP-8 是一种解释型编程语言,由 Joseph Weisbecker 开发。它最初用于 COSMAC VIP 和 Telmac 1800 8 位微型计算机在 70 年代中期。CHIP-8 程序在一个 CHIP-8 虚拟机上运行。它的问世是为了让电子游戏更容易

daief 2 Jun 13, 2022
:iphone: A super lightweight HTML, Sass, CSS, and JavaScript framework for building responsive websites

Responsive Boilerplate A powerful, accessible, developer friendly, framework for building responsive websites Responsive Boilerplate is the developers

ResponsiveBP 845 Dec 22, 2022
Our super simple URL shortener. Powered by Deno and Supabase.

Feelantera URL Shortener This is our super simple URL shortener. Powered by Supabase and Deno, and Oak for the http framework. You can deploy this pro

Feelantera 16 Oct 14, 2022
🚀 The super app for creators and their audience.

OneSocial It's the ultimate super app for creators and their audience. With OneSocial, you can share your thoughts on blog, manage an active newslette

Subham Sahu 16 Oct 21, 2022
tb-grid is a super simple and lightweight 12 column responsive grid system utilizing css grid.

tb-grid Lightweight (<1kb gzipped) 12 column grid system, built with css grid. ?? Demos & Playground Have a look at those examples: Main Demo: https:/

Taskbase 26 Dec 28, 2022
Super Mario 64 ported to JavaScript and WebAssembly via Emscripten.

SM64-JS Super Mario 64 ported to JavaScript and WebAssembly via Emscripten. REPL Takedown I was forced to take down the REPL for this project due to c

Sevenworks 12 Dec 23, 2022
Timers for Lost Ark bosses, islands, events, wandering merchants and more! Never miss an event again.

Timers for Lost Ark bosses, islands, events, wandering merchants and more! Never miss an event again. LostArkTimer.app Website Website Features Event

Joshua Kuan 28 Oct 17, 2022