Skip to content

Instantly share code, notes, and snippets.

@nickytonline
Last active August 29, 2015 14:15
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 nickytonline/e34290b72661db9873f1 to your computer and use it in GitHub Desktop.
Save nickytonline/e34290b72661db9873f1 to your computer and use it in GitHub Desktop.
Event management in the DOM via bubbling for Handlebars templating POC
<html>
<head>
<title>Client-Side Event Binding with HandleBards POC</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<![endif]-->
<style type="text/css">
#logger {
height: 250px;
overflow-y: auto;
background-color: #000;
color: #fff;
margin: 10px;
padding: 10px;
}
.date--log {
color: #336600;
}
.message--important {
color: #ff3300;
}
</style>
</head>
<body>
<div class="col-md-5">
<h2>Logger</h2>
<div id="logger"></div>
</div>
<div class="col-md-5">
<div id="main-content"></div>
</div>
<script id="testTemplate" type="template">
<ul>
{{#each names}}
<li>
<input value="{{this}}" data-orckaction="{'mouseover': 'mouseOverAction', 'mouseout': 'mouseOutAction', 'click': 'inputClickAction', 'dblclick': 'doubleClickAction', 'change': 'inputChangedAction', 'keypress': 'keyPressAction', 'keyup': 'keyUpAction', 'keydown': 'keyDownAction' }" />
</li>
{{/each}}
</ul>
<ul>
{{#each urls}}
<li>
<a href="{{this}}" data-orckaction="{'mouseover': 'mouseOverAction', 'mouseout': 'mouseOutAction', 'click': 'linkClickAction', 'dblclick': 'doubleClickAction' }">Test Event Bubbling on link {{@index}}</a>
</li>
{{/each}}
</ul>
</script>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="//cdn.jsdelivr.net/lodash/3.0.0/lodash.compat.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.0/handlebars.min.js"></script>
<script>
$(document).ready(function() {
var linkTimeoutId = 0,
template,
model,
log,
mainElementContext = $('#main-content'),
bodyContext = $(document.body),
nonBubblingEvents = {
focus: 'focus',
blur: 'blur',
submit: 'submit',
reset: 'reset',
change: 'change'
},
bubblingEvents = [ 'mouseover', 'mouseout', 'click', 'dblclick', 'keypress', 'keyup', 'keydown' ],
actions = {
'mouseOverAction': function(e) {
e.stopPropagation();
log('Moused over');
},
'mouseOutAction': function(e) {
e.stopPropagation();
log('Moused out');
},
'linkClickAction': function(e) {
e.stopPropagation();
e.preventDefault();
log('<span class="message--important">Hyperlink clicked! Did you know my URL is ' + this.attr('href') + '</span>');
},
'inputChangedAction': function(e) {
log('<span class="message--important">Changed! Did you know my new value is ' + this.val() + '</span>');
},
'inputClickAction': function(e) {
e.stopPropagation();
e.preventDefault();
log('<span class="message--important">Clicked! Did you know my value is ' + this.val() + '</span>');
},
'doubleClickAction': function(e) {
clearTimeout(linkTimeoutId);
e.stopPropagation();
e.preventDefault();
log('Double-clicked! Did you know my URL is ' + this.attr('href'));
},
'keyPressAction': function(e) {
log('Keypress fired! Keycode is ' + (e.keyCode ? e.keyCode : e.which));
},
'keyUpAction': function(e) {
log('Keyup fired! Keycode is ' + (e.keyCode ? e.keyCode : e.which));
},
'keyDownAction': function(e) {
log('Keydown fired! Keycode is ' + (e.keyCode ? e.keyCode : e.which));
}
};
log = (function(loggerContext) {
return function (message) {
loggerContext.prepend('<span class="date--log">' + (new Date()).toLocaleString() + '</span> ' + message + '<br />');
};
})($("#logger"));
function manageAction(e) {
var context = $(e.target),
eventType = e.type,
elementActions,
rawActions,
action,
elementActionEventType,nonBubblingAction;
rawActions = context.data('orckaction');
if (_.isEmpty(rawActions)) {
return;
}
// Csn probably set this as an expando property instead of parsing the JSON all the time.
elementActions = $.parseJSON(rawActions.replace(/'/g, '"'));
action = elementActions[eventType];
if (action in actions) {
if (context.data('orckBound') !== true) {
context.data('orckBound', true);
for (elementActionEventType in elementActions) {
if (elementActionEventType in nonBubblingEvents) {
nonBubblingAction = elementActions[elementActionEventType];
context.on(
elementActionEventType,
(function(context, actionCallback) {
return actionCallback.bind(context);
})(context, actions[nonBubblingAction])
);
log('This ' + action + ' is a non-bubbling event. Binding to the element directly');
}
}
}
if (!(eventType in nonBubblingEvents)) {
actions[action].apply(context, [e]);
}
} else {
log("No action " + action + " is registered.");
}
}
$.map(bubblingEvents , function(item, index) {
bodyContext.on(item, manageAction);
});
template = Handlebars.compile($("#testTemplate").html());
model = {
names: [
'nick',
'john',
'suzie',
'walter',
'jesse'
],
urls: [
'http://www.google.com',
'http://www.twitter.com',
'http://www.microsoft.com',
'http://www.bing.com',
'http://youtube.com',
'http://facebook.com',
'http://linkedin.com',
'http://cnn.com',
'http://msnbc.com'
]
};
mainElementContext.html(template(model));
});
</script>
</body>
</html>
@nickytonline
Copy link
Author

And here's the code running http://jsfiddle.net/nickyt/jk3fespv . It works in IE8+/Chrome/FF and although not tested, I would assume Safari and Opera.

@nickytonline
Copy link
Author

Here is a version that uses hammer.js for tactile events, specifically single tap and double tap.
http://plnkr.co/edit/jZeCUc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment