Last active
March 28, 2018 18:37
-
-
Save 4d47/613ec0c95f06170aa5aac9b803a3f34d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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