PageRenderTime 541ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/todo-example/fidel/vendor/fidel.js

http://github.com/addyosmani/todomvc
JavaScript | 268 lines | 212 code | 29 blank | 27 comment | 47 complexity | 9f47c43c0eae6a0aa477e0148e8a7508 MD5 | raw file
Possible License(s): MIT, Apache-2.0, 0BSD, CC-BY-4.0, BSD-3-Clause
  1. /*!
  2. * Fidel - A javascript controller
  3. * v1.2.2
  4. * https://github.com/jgallen23/fidel
  5. * copyright JGA 2011
  6. * MIT License
  7. */
  8. !function (name, definition) {
  9. if (typeof module != 'undefined' && module.exports) module.exports = definition();
  10. else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
  11. else this[name] = definition();
  12. }('Fidel', function() {
  13. var context = this;
  14. var Fidel = {};
  15. Fidel.guid = function(){
  16. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  17. var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
  18. return v.toString(16);
  19. }).toUpperCase();
  20. };
  21. Fidel.extend = function() {
  22. throw new Error("Fidel.extend is deprecated, please use Fidel.ViewController.extend");
  23. };
  24. var o = context.Fidel;
  25. Fidel.noConflict = function() {
  26. context.Fidel = o;
  27. return this;
  28. };
  29. var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  30. // The base Class implementation (does nothing)
  31. Fidel.Class = function(){};
  32. // Create a new Class that inherits from this class
  33. Fidel.Class.extend = function(prop) {
  34. var _super = this.prototype;
  35. // Instantiate a base class (but only create the instance,
  36. // don't run the init constructor)
  37. initializing = true;
  38. var prototype = new this();
  39. initializing = false;
  40. // Copy the properties over onto the new prototype
  41. for (var name in prop) {
  42. // Check if we're overwriting an existing function
  43. prototype[name] = typeof prop[name] == "function" &&
  44. typeof _super[name] == "function" && fnTest.test(prop[name]) ?
  45. (function(name, fn){
  46. return function() {
  47. var tmp = this._super;
  48. // Add a new ._super() method that is the same method
  49. // but on the super-class
  50. this._super = _super[name];
  51. // The method only need to be bound temporarily, so we
  52. // remove it when we're done executing
  53. var ret = fn.apply(this, arguments);
  54. this._super = tmp;
  55. return ret;
  56. };
  57. })(name, prop[name]) :
  58. prop[name];
  59. }
  60. // The dummy class constructor
  61. function Class(opt) {
  62. // All construction is actually done in the init method
  63. if (!initializing) {
  64. if (this.defaults) {
  65. for (var key in this.defaults) {
  66. if (typeof opt !== 'object' || !opt[key]) this[key] = this.defaults[key];
  67. }
  68. }
  69. if (typeof opt === 'object') {
  70. for (var okey in opt) {
  71. this[okey] = opt[okey];
  72. }
  73. }
  74. if (!this.guid) this.guid = Fidel.guid();
  75. if (this._initialize) this._initialize.apply(this, arguments);
  76. if (this.init) this.init.apply(this, arguments);
  77. }
  78. }
  79. // Populate our constructed prototype object
  80. Class.prototype = prototype;
  81. Class.prototype.proxy = function(func) {
  82. var thisObject = this;
  83. return(function(){
  84. if (!func) return;
  85. return func.apply(thisObject, arguments);
  86. });
  87. };
  88. // Enforce the constructor to be what we expect
  89. Class.constructor = Class;
  90. // And make this class extendable
  91. Class.extend = arguments.callee;
  92. return Class;
  93. };
  94. var cache = {}; //check for "c_" cache for unit testing
  95. //publish("/some/topic", ["a","b","c"]);
  96. Fidel.publish = function(topic, args){
  97. var subs = cache[topic], len = subs ? subs.length : 0;
  98. //can change loop or reverse array if the order matters
  99. while(len--){
  100. subs[len].apply(this, args || []);
  101. }
  102. };
  103. //subscribe("/some/topic", function(a, b, c){ /* handle data */ });
  104. Fidel.subscribe = function(topic, callback){
  105. if(!cache[topic]){
  106. cache[topic] = [];
  107. }
  108. cache[topic].push(callback);
  109. return [topic, callback]; // Array
  110. };
  111. //var handle = subscribe("/some/topic", function(){});
  112. //unsubscribe(handle);
  113. Fidel.unsubscribe = function(handle){
  114. var subs = cache[handle[0]],
  115. callback = handle[1],
  116. len = subs ? subs.length : 0;
  117. while(len--){
  118. if(subs[len] === callback){
  119. subs.splice(len, 1);
  120. }
  121. }
  122. };
  123. Fidel.Class.prototype.on = Fidel.Class.prototype.bind = function(name, callback) {
  124. return Fidel.subscribe(this.guid+"."+name, this.proxy(callback));
  125. };
  126. Fidel.Class.prototype.emit = Fidel.Class.prototype.trigger = function(name, data) {
  127. Fidel.publish(this.guid+"."+name, data);
  128. Fidel.publish(name, data);
  129. };
  130. Fidel.Class.prototype.removeListener = Fidel.Class.prototype.unbind = function(handle) {
  131. Fidel.unsubscribe(handle);
  132. };
  133. !function() {
  134. var templateCache = {};
  135. Fidel.template = function tmpl(template, data) {
  136. var fn = !/\W/.test(template) ?
  137. templateCache[template] = templateCache[template] ||
  138. tmpl(template) :
  139. new Function("obj",
  140. "var p=[],print=function(){p.push.apply(p,arguments);};" +
  141. "with(obj){p.push('" +
  142. template
  143. .replace(/[\r\t\n]/g, "")
  144. .split("{!").join("\t")
  145. .replace(/((^|!})[^\t]*)'/g, "$1\r")
  146. .replace(/\t=(.*?)!}/g, "',$1,'")
  147. .split("\t").join("');")
  148. .split("!}").join("p.push('")
  149. .split("\r").join("\\'")
  150. + "');}return p.join('');");
  151. return data ? fn( data ) : fn;
  152. };
  153. }();
  154. var eventSplitter = /^(\w+)\s*(.*)$/;
  155. var ViewController = Fidel.Class.extend({
  156. _initialize: function(options) {
  157. if (!this.el) throw "el is required";
  158. this._subscribeHandles = {};
  159. if (this.events) this.delegateEvents();
  160. if (this.elements) this.refreshElements();
  161. if (this.templates) this.loadTemplates();
  162. if (!this.actionEvent) this.actionEvent = "click";
  163. if (this.subscribe) this.bindSubscriptions();
  164. this.delegateActions();
  165. this.getDataElements();
  166. },
  167. template: Fidel.template,
  168. delegateEvents: function() {
  169. for (var key in this.events) {
  170. var methodName = this.events[key];
  171. var match = key.match(eventSplitter);
  172. var eventName = match[1], selector = match[2];
  173. var method = this.proxy(this[methodName]);
  174. if (selector === '') {
  175. this.el.bind(eventName, method);
  176. } else {
  177. this.el.delegate(selector, eventName, method);
  178. }
  179. }
  180. },
  181. delegateActions: function() {
  182. var self = this;
  183. this.el.delegate('[data-action]', this.actionEvent, function(e) {
  184. var el = $(this);
  185. var methodName = el.attr('data-action');
  186. if (self[methodName]) self[methodName].call(self, el, e);
  187. });
  188. },
  189. refreshElements: function() {
  190. for (var key in this.elements) {
  191. this[key] = this.find(this.elements[key]);
  192. }
  193. },
  194. getDataElements: function() {
  195. var self = this;
  196. var elements = this.find("[data-element]");
  197. for (var i = 0, c = elements.length; i < c; i++) {
  198. var name = elements[i].getAttribute('data-element');
  199. if (!self[name]) {
  200. var elem = this.find('[data-element="'+name+'"]');
  201. self[name] = elem;
  202. }
  203. }
  204. },
  205. bindSubscriptions: function() {
  206. for (var key in this.subscribe) {
  207. this._subscribeHandles[key] = Fidel.subscribe(key, this.proxy(this[this.subscribe[key]]));
  208. }
  209. },
  210. loadTemplates: function() {
  211. for (var name in this.templates) {
  212. this.templates[name] = $(this.templates[name]).html();
  213. }
  214. },
  215. find: function(selector) {
  216. return $(selector, this.el[0]);
  217. },
  218. render: function(templateName, data, selector) {
  219. if (arguments.length == 1) {
  220. data = templateName;
  221. templateName = this.primaryTemplate;
  222. }
  223. template = this.templates[templateName];
  224. if (!template) return;
  225. var tmp = this.template(template, data);
  226. selector = (selector)?$(selector):this.el;
  227. selector.html(tmp);
  228. },
  229. destroy: function() {
  230. for (var key in this._subscribeHandles) {
  231. Fidel.unsubscribe(this._subscribeHandles[key]);
  232. }
  233. this.el.undelegate('[data-action]', this.actionEvent);
  234. this.el = null;
  235. }
  236. });
  237. Fidel.ViewController = ViewController;
  238. return Fidel;
  239. });