Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Pattern for JavaScript prototypical inheritance with private and protected state
var Modal = (function() {
function createType(subTypeBox) {
var subTypeBox = subTypeBox || { };
var internal = { }; // "protected" state bag
var stack = [ ]; // "private" field
// Name the constructor function strictly for debug purposes, in a way that doesn't spill throughout this scope.
var Type = (function() { return function Modal(id) { this.id = id; }; })();
Type.prototype = {
id: undefined,
getEl: function() { return internal[this.id].el; },
getPromise: function() { return internal[this.id].deferred.promise(); },
isOpen: function() { return !!internal[this.id]; },
isTop: function() {
var top = stack[stack.length - 1];
return top === this.id;
},
close: function(data) {
if (!this.isTop()) { return false; }
$(this.getEl()).parent().remove();
var state = internal[this.id];
delete internal[this.id];
stack.pop();
state.deferred.resolveWith(this, [data]);
return true;
},
constructor: Type
};
Type.create = function() {
var deferred = $.Deferred(),
id = Date.now(), // hacky
modal = new (subTypeBox.Type || Type)(id);
var $el = $('<div class="modal"><div class="modal-content">').
appendTo('body').
click(function(e) {
if (e.target === $(modal.getEl()).parent()[0]) { modal.close({ canceled: true }); }
}).
find('.modal-content');
internal[id] = { el: $el[0], deferred: deferred, api: modal };
stack.push(id);
return modal;
};
Type.find = function(el) {
var id, state, $el = $(el);
for (id in internal) {
if (!internal.hasOwnProperty(id)) { continue; }
state = internal[id];
if ($el.closest(state.el)) { return state.api; }
}
};
return {
Type: Type,
friend: internal
};
};
var SealedType = createType();
SealedType.createType = createType;
return SealedType;
})();
var SuperModal = (function() {
var box = { };
var typeData = Modal.createType(box);
var UnsealedModal = typeData.Type;
var friend = typeData.friend;
var Type = (function() { return function SuperModal() { UnsealedModal.prototype.constructor.apply(this, arguments); }; })();
box.Type = Type;
Type.prototype = Object.create(UnsealedModal.prototype);
Type.prototype.isClosed = function() { return !friend[this.id]; };
Type.prototype.constructor = Type;
Type.create = UnsealedModal.create;
Type.find = UnsealedModal.find;
return Type;
})();
Owner

mcgwiz commented Nov 3, 2015

This could be improved to reuse the same objects for Type.prototype and internal across calls to createType().

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