├── README.md ├── LICENSE └── uMVC.js /README.md: -------------------------------------------------------------------------------- 1 | uMVC 2 | ==== 3 | 4 | A micro MVC framework for JavaScript applications. 5 | 6 | I tweeted: 7 | 8 | > You can write an MVC framework in one hundred lines of JavaScript & write about its effective use for one hundred thousand lines of English. 9 | 10 | I wondered exactly how small I could write a respectable MVC framework that included the observer, composite, and strategy patterns. 11 | 12 | Hopefully this code is educational for those new to the MVC paradigm. 13 | 14 | If you are looking for a more fully-featured MVC framework that follows the same principles of uMVC to use in real browser applications, I suggest you take a look at [Maria](https://github.com/petermichaux/maria). 15 | 16 | 17 | Author 18 | ------ 19 | 20 | Peter Michaux
21 | petermichaux@gmail.com
22 | http://peter.michaux.ca/
23 | [@petermichaux](https://twitter.com/petermichaux) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Peter Michaux 2 | All rights reserved. 3 | 4 | Redistribution and use of this software in source and binary forms, with or 5 | without modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /uMVC.js: -------------------------------------------------------------------------------- 1 | var uMVC = {}; 2 | uMVC.Model = function() { 3 | this._observers = []; 4 | }; 5 | uMVC.Model.prototype.observe = function(observer) { 6 | this._observers.push(observer); 7 | }; 8 | uMVC.Model.prototype.unobserve = function(observer) { 9 | for (var i = 0, ilen = this._observers.length; i < ilen; i++) { 10 | if (this._observers[i] === observer) { 11 | this._observers.splice(i, 1); 12 | return; 13 | } 14 | } 15 | }; 16 | uMVC.Model.prototype.notify = function(data) { 17 | var observers = this._observers.slice(0); 18 | for (var i = 0, ilen = observers.length; i < ilen; i++) { 19 | observers[i].update(data); 20 | } 21 | }; 22 | uMVC.View = function() { 23 | this._subViews = []; 24 | }; 25 | uMVC.View.prototype.update = function() {}; 26 | uMVC.View.prototype.getModel = function() { 27 | return this._model; 28 | }; 29 | uMVC.View.prototype.setModel = function(model) { 30 | this._setModelAndController(model, this._controller); 31 | }; 32 | uMVC.View.prototype.getDefaultController = function() { 33 | return new uMVC.Controller(); 34 | }; 35 | uMVC.View.prototype.getController = function() { 36 | if (!this._controller) this.setController(this.getDefaultController()); 37 | return this._controller; 38 | }; 39 | uMVC.View.prototype.setController = function(controller) { 40 | this._setModelAndController(this._model, controller); 41 | }; 42 | uMVC.View.prototype._setModelAndController = function(model, controller) { 43 | if (this._model !== model) { 44 | if (this._model) this._model.unobserve(this); 45 | if (model) model.observe(this); 46 | this._model = model; 47 | } 48 | if (controller) { 49 | controller.setView(this); 50 | controller.setModel(model); 51 | } 52 | this._controller = controller; 53 | }; 54 | uMVC.View.prototype.getSubViews = function() { 55 | return this._subViews.slice(0); 56 | }; 57 | uMVC.View.prototype.addSubView = function(subView) { 58 | var previousSuperView = subView.getSuperView(); 59 | if (previousSuperView) previousSuperView.removeSubView(subView); 60 | this._subViews.push(subView); 61 | subView.setSuperView(this); 62 | }; 63 | uMVC.View.prototype.removeSubView = function(subView) { 64 | for (var i = 0, ilen = this._subViews.length; i < ilen; i++) { 65 | if (this._subViews[i] === subView) { 66 | this._subViews[i].setSuperView(null); 67 | this._subViews.splice(i, 1); 68 | return; 69 | } 70 | } 71 | }; 72 | uMVC.View.prototype.setSuperView = function(superView) { 73 | this._superView = superView; 74 | }; 75 | uMVC.View.prototype.getSuperView = function() { 76 | return this._superView; 77 | }; 78 | uMVC.View.prototype.destroy = function() { 79 | if (this._model) { 80 | this._model.unobserve(this); 81 | } 82 | for (var i = 0, ilen = this._subViews.length; i < ilen; i++) { 83 | this._subViews[i].destroy(); 84 | } 85 | }; 86 | uMVC.Controller = function() {}; 87 | uMVC.Controller.prototype.getModel = function() { 88 | return this._model; 89 | }; 90 | uMVC.Controller.prototype.setModel = function(model) { 91 | this._model = model; 92 | }; 93 | uMVC.Controller.prototype.getView = function() { 94 | return this._view; 95 | }; 96 | uMVC.Controller.prototype.setView = function(view) { 97 | this._view = view; 98 | }; --------------------------------------------------------------------------------