Skip to content

Instantly share code, notes, and snippets.

@4d47
Last active March 28, 2018 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 4d47/613ec0c95f06170aa5aac9b803a3f34d to your computer and use it in GitHub Desktop.
Save 4d47/613ec0c95f06170aa5aac9b803a3f34d to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.clipboard-button {
display: none;
}
.clipboard--supported .clipboard-button {
display: initial;
}
.slide {
display: none;
}
.slide.slide--current {
display: block;
}
</style>
<link rel="stylesheet" href="https://edwardtufte.github.io/tufte-css/tufte.css">
</head>
<body onload="miniStimulus()">
<article>
<h1>miniStimulus</h1>
<p class="subtitle">
An even more modest JavaScript framework for the HTML you have.
</p>
<section>
<p>
I really liked the way <a href="https://stimulusjs.org/">Stimulus</a>
structured JavaScript by putting emphasis on
<em>Separation of Concerns</em>
and <em>A Readable Document</em>.
This structure removes the need to query elements
and attach events, which I found is the two messier parts.
</p>
<p>
If you don't have the need for <code>MutationObserver</code>
and nested controllers you can get something that is very
easy to implement even in ES5 !
See this page source for reference.
</p>
<p>
Attributes differences from Stimulus.js
</p>
<p>
<pre>data-controller="controller"</pre>
<ul>
<li>not an ES6 class but an instanciable object in <code>window</code></li>
</ul>
</p>
<p>
<pre>data-action="event method"</pre>
<ul>
<li>event is required, no shorthand notation</li>
<li>no controller, always call method of the nested controller; use space as separator to be more HTML ish</li>
</ul>
</p>
<p>
<pre>data-target="name"</pre>
<ul>
<li>no controller, always bind to the nested controller</li>
</ul>
</p>
</section>
<section>
<h2>Examples</h2>
<h3>Hello</h3>
<div data-controller="hello">
<input data-target="name" type="text">
<button data-action="click greet">Greet</button>
<span data-target="output"></span>
</div>
<hr>
<div data-controller="hello">
<input data-target="name" type="text">
<button data-action="click greet">Greet</button>
<span data-target="output"></span>
</div>
<hr>
<h3>Clipboard</h3>
<div data-controller="clipboard">
PIN: <input data-target="source" type="text" value="1234" readonly>
<button data-action="click copy" class="clipboard-button">
Copy to Clipboard
</button>
</div>
<hr>
<h3>Slideshow</h3>
<div data-controller="slideshow" data-slideshow-index="1">
<button data-action="click previous">←</button>
<button data-action="click next">→</button>
<div data-target="slide" class="slide">1</div>
<div data-target="slide" class="slide">2</div>
<div data-target="slide" class="slide">3</div>
<div data-target="slide" class="slide">4</div>
</div>
</section>
</article>
<script>
function miniStimulus() {
document.querySelectorAll('[data-controller]').forEach(function(el) {
var
id = el.getAttribute('data-controller'),
controller;
// instanciate controller
if (!window[id]) throw '"' + name + '" controller not found';
controller = new window[id];
controller.element = el;
// assign targets
el.querySelectorAll('[data-target]').forEach(function(el) {
var
name = el.getAttribute('data-target') + 'Target',
plural = name + 's';
if (!controller[name]) controller[name] = el;
if (!controller[plural]) controller[plural] = [];
controller[plural].push(el);
});
// attach events
el.querySelectorAll('[data-action]').forEach(function(el) {
var
evt = el.getAttribute('data-action').split(' ');
if (!controller[ evt[1] ])
throw id + '.' + evt[1] + ' undefined';
el.addEventListener(evt[0], controller[ evt[1] ].bind(controller));
});
// initialization calls
if (controller.initialize) controller.initialize();
if (controller.connect) controller.connect();
});
}
function hello() {
}
hello.prototype.greet = function(e) {
console.log('Hello', this.nameTarget.value);
}
function clipboard() {
}
clipboard.prototype.copy = function(e) {
e.preventDefault();
this.sourceTarget.select();
document.execCommand('copy');
}
clipboard.prototype.connect = function() {
if (document.queryCommandSupported('copy')) {
this.element.classList.add('clipboard--supported')
}
}
function slideshow() {
}
slideshow.prototype.initialize = function() {
var index = parseInt(this.element.getAttribute('data-slideshow-index'));
this.showSlide(index);
}
slideshow.prototype.next = function() {
this.showSlide(this.index + 1);
}
slideshow.prototype.previous = function() {
this.showSlide(this.index - 1);
}
slideshow.prototype.showSlide = function(index) {
this.index = index;
this.slideTargets.forEach(function(el, i) {
el.classList.toggle('slide--current', index == i);
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment