Skip to content

Instantly share code, notes, and snippets.

@paulfalgout
Last active June 24, 2017 18:22
Show Gist options
  • Save paulfalgout/95570a3a82141ff6a057164538371c78 to your computer and use it in GitHub Desktop.
Save paulfalgout/95570a3a82141ff6a057164538371c78 to your computer and use it in GitHub Desktop.
'use strict';
const _ = require('underscore');
const Bb = require('backbone');
const Mn = require('backbone.marionette');
const morphdom = require('morphdom');
const DomApi = {
// Returns a new HTML DOM node instance
createBuffer() {
return document.createDocumentFragment();
},
// Lookup the `selector` string
// Selector may also be a DOM element
// Returns an array-like object of nodes
getEl(selector) {
if (_.isObject(selector)) {
return [selector]
} else {
return document.querySelectorAll(selector);
}
},
// Finds the `selector` string with the el
// Returns an array-like object of nodes
findEl(el, selector) {
return el.querySelectorAll(selector);
},
// Detach `el` from the DOM without removing listeners
detachEl(el) {
if (el.parentNode) el.parentNode.removeChild(el);
},
// Remove `oldEl` from the DOM and put `newEl` in its place
replaceEl(newEl, oldEl) {
if (newEl === oldEl) {
return;
}
const parent = oldEl.parentNode;
if (!parent) {
return;
}
parent.replaceChild(newEl, oldEl);
},
// Replace the contents of `el` with the HTML string of `html`
setContents(el, html) {
if (html) el.innerHTML = html
},
// Takes the DOM node `el` and appends the DOM node `contents`
// to the end of the element's contents.
appendContents(el, contents) {
el.appendChild(contents)
},
// Remove the inner contents of `el` from the DOM while leaving
// `el` itself in the DOM.
detachContents(el) {
while (el.firstChild) {
el.removeChild(el.firstChild);
}
}
};
Mn.setDomApi(DomApi);
const rowTemplate = function(data) {
const tr = document.createElement('tr');
const td1 = document.createElement('td');
td1.className = 'col-md-1';
td1.innerText = data.id;
tr.appendChild(td1);
const td2 = document.createElement('td');
td2.className = 'col-md-4';
tr.appendChild(td2);
const a2 = document.createElement('a');
a2.className = 'js-link';
td2.appendChild(a2);
a2.innerText = data.label;
const td3 = document.createElement('td');
td3.className = 'col-md-1';
tr.appendChild(td3);
const a = document.createElement('a');
a.className = 'js-del';
a.dataset.id = data.id;
td3.appendChild(a);
const span = document.createElement('span');
span.className = 'glyphicon glyphicon-remove';
span.setAttribute('aria-hidden', 'true');
a.appendChild(span);
const td4 = document.createElement('td');
td4.className = 'col-md-6';
tr.appendChild(td4);
return tr;
}
var startTime;
var lastMeasure;
var startMeasure = function(name) {
//console.profile(name);
startTime = performance.now();
lastMeasure = name;
}
var stopMeasure = function() {
var last = lastMeasure;
if (lastMeasure) {
//console.profileEnd(lastMeasure);
window.setTimeout(function () {
lastMeasure = null;
var stop = performance.now();
var duration = 0;
console.log(last+" took "+(stop-startTime));
}, 0);
}
}
function _random(max) {
return Math.round(Math.random()*1000)%max;
}
const Store = Bb.Collection.extend({
initialize() {
this.id = 1;
this.on('reset update', this.clearSelected);
},
buildData(count = 1000) {
var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
var data = [];
for (var i = 0; i < count; i++)
data.push({id: this.id++, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] });
return data;
},
clearSelected() {
if(this.curSelected) {
this.curSelected.classList.remove('danger');
this.curSelected = null;
}
},
updateData(mod = 10) {
startMeasure("update");
for (let i=0;i<this.models.length;i+=10) {
const label = this.models[i].get('label');
this.models[i].set('label', label + ' !!!');
}
stopMeasure();
},
delete(id) {
startMeasure("delete");
this.trigger('removeRow', this.get(id));
this.remove(id, { silent: true });
stopMeasure();
},
run() {
startMeasure("run");
this.trigger('clear');
this.reset(this.buildData());
stopMeasure();
},
addData() {
startMeasure("add");
this.add(this.buildData(1000));
stopMeasure();
},
select(target) {
startMeasure("select");
if(this.curSelected) this.curSelected.classList.remove('danger');
this.curSelected = target.parentNode.parentNode;
this.curSelected.classList.add('danger');
stopMeasure();
},
runLots() {
startMeasure("runLots");
this.trigger('clear');
this.reset(this.buildData(10000));
stopMeasure();
},
clear() {
startMeasure("clear");
this.trigger('clear');
this.reset();
stopMeasure();
},
swapRows() {
startMeasure("swapRows");
if (this.length > 10) {
const a = this.models[4];
this.models[4] = this.models[9];
this.models[9] = a;
this.trigger('swapRows', this.models[4], this.models[9]);
}
stopMeasure();
}
});
const store = new Store();
const ChildView = Mn.View.extend({
monitorViewEvents: false,
setElement() {},
_setAttributes() {},
template: rowTemplate,
serializeData() {
return this.model.attributes;
},
attachElContent(el) {
if(this.isRendered()) morphdom(this.el, el, { onlyChildren: true });
else this.el = el;
},
destroy() {
this.stopListening();
}
});
const CollectionView = Mn.NextCollectionView.extend({
monitorViewEvents: false,
viewComparator: false,
el: '#tbody',
childView: ChildView,
initialize() {
this.listenTo(this.collection, {
'clear': this.onClear,
'swapRows': this.onSwapRows,
'removeRow': this.onRemoveRow,
'change:label': this.onChangeLabel
});
},
events: {
'click .js-link'(e) {
this.collection.select(e.currentTarget);
},
'click .js-del'(e) {
this.collection.delete(e.currentTarget.dataset.id);
}
},
childViewEventPrefix: false,
onClear() {
this.el.textContent = '';
},
onSwapRows(model1, model2) {
const el1 = this.children.findByModel(model1).el;
const el2 = this.children.findByModel(model2).el;
const parent1 = el1.parentNode;
const next1 = el1.nextSibling;
const parent2 = el2.parentNode;
const next2 = el2.nextSibling;
parent1.insertBefore(el2, next1);
parent2.insertBefore(el1, next2);
},
onRemoveRow(model) {
const view = this.children.findByModel(model);
this.el.removeChild(view.el);
this.removeChildView(view);
},
onChangeLabel(model) {
const view = this.children.findByModel(model);
view.render();
}
});
const collectionView = new CollectionView({
collection: store
});
collectionView.render();
const MainView = Mn.View.extend({
el : '.jumbotron',
triggers: {
'click #run': 'run',
'click #runlots': 'runLots',
'click #add': 'add',
'click #update': 'update',
'click #clear': 'clear',
'click #swaprows': 'swapRows'
},
onRun() {
store.run();
},
onRunLots() {
store.runLots();
},
onAdd() {
store.addData();
},
onUpdate() {
store.updateData();
},
onClear() {
store.clear();
},
onSwapRows() {
store.swapRows();
}
});
new MainView();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment