UNPKG

todomvc

Version:

> Helping you select an MV\* framework

451 lines (417 loc) 12.2 kB
/*! * CanJS - 2.0.3 * http://canjs.us/ * Copyright (c) 2013 Bitovi * Tue, 26 Nov 2013 18:21:22 GMT * Licensed MIT * Includes: CanJS default build * Download from: http://canjs.us/ */ define(["can/util/can", "yui", "can/util/event", "can/util/fragment", "can/util/array/each", "can/util/object/isplain", "can/util/deferred", "can/util/hashchange", "can/util/inserted"], function (can) { // lets overwrite YUI.add('can-modifications', function (Y, NAME) { var addHTML = Y.DOM.addHTML; Y.DOM.addHTML = function(node, content, where){ if(typeof content === "string" || typeof content == "number"){ content = can.buildFragment(content); } var elems; if( content.nodeType === 11 ) { elems = can.makeArray(content.childNodes); } else { elems = [content] } var ret = addHTML.call(this, node, content, where); can.inserted( elems ); return ret; } },'3.7.3', {"requires": ["node-base"]}) // --------- // _YUI node list._ // `can.Y` is set as part of the build process. // `YUI().use('*')` is called for when `YUI` is statically loaded (like when running tests). var Y = can.Y = can.Y || YUI().use('*'); // Map string helpers. can.trim = function (s) { return Y.Lang.trim(s); } // Map array helpers. can.makeArray = function (arr) { if (!arr) { return []; } return Y.Array(arr); }; can.isArray = Y.Lang.isArray; can.inArray = function (item, arr, fromIndex) { if (!arr) { return -1; } return Y.Array.indexOf(arr, item, fromIndex); }; can.map = function (arr, fn) { return Y.Array.map(can.makeArray(arr || []), fn); }; // Map object helpers. can.extend = function (first) { var deep = first === true ? 1 : 0, target = arguments[deep], i = deep + 1, arg; for (; arg = arguments[i]; i++) { Y.mix(target, arg, true, null, null, !!deep); } return target; } can.param = function (object) { return Y.QueryString.stringify(object, {arrayKey : true}) } can.isEmptyObject = function (object) { return Y.Object.isEmpty(object); } // Map function helpers. can.proxy = function (func, context) { return Y.bind.apply(Y, arguments); } can.isFunction = function (f) { return Y.Lang.isFunction(f); } // Element -- get the wrapped helper. var prepareNodeList = function (nodelist) { nodelist.each(function (node, i) { nodelist[i] = node.getDOMNode(); }); nodelist.length = nodelist.size(); return nodelist; } can.$ = function (selector) { if (selector === window) { return window; } else if (selector instanceof Y.NodeList) { return prepareNodeList(selector); } else if (typeof selector === "object" && !can.isArray(selector) && typeof selector.nodeType === "undefined" && !selector.getDOMNode) { return selector; } else { return prepareNodeList(Y.all(selector)); } } can.get = function (wrapped, index) { return wrapped._nodes[index]; } can.append = function( wrapped, html ) { wrapped.each(function( node ) { if ( typeof html === 'string' ) { html = can.buildFragment(html, node) } node.append(html) }); } can.addClass = function (wrapped, className) { return wrapped.addClass(className); } can.data = function (wrapped, key, value) { if (value === undefined) { return wrapped.item(0).getData(key) } else { return wrapped.item(0).setData(key, value) } } can.remove = function (wrapped) { return wrapped.remove() && wrapped.destroy(); } can.has = function(wrapped, node){ if( Y.DOM.contains(wrapped[0], node) ){ return wrapped; } else { return []; } } // Destroyed method. can._yNodeRemove = can._yNodeRemove || Y.Node.prototype.remove; Y.Node.prototype.remove = function () { // make sure this is only fired on normal nodes, if it // is fired on a text node, it will bubble because // the method used to stop bubbling (listening to an event) // does not work on text nodes var node = this.getDOMNode(); if( node.nodeType === 1 ){ can.trigger(this, "removed", [], false); var elems = node.getElementsByTagName('*'); for ( var i = 0, elem; (elem = elems[i]) !== undefined; i++ ) { can.trigger(elem, "removed", [], false); } } can._yNodeRemove.apply(this, arguments) } // Let `nodelist` know about the new destroy... Y.NodeList.addMethod("remove", Y.Node.prototype.remove); // Ajax var optionsMap = { type : "method", success : undefined, error : undefined } var updateDeferred = function (request, d) { // `YUI` only returns a request if it is asynchronous. if (request && request.io) { var xhr = request.io; for (var prop in xhr) { if (typeof d[prop] == 'function') { d[prop] = function () { xhr[prop].apply(xhr, arguments) } } else { d[prop] = prop[xhr] } } } } can.ajax = function (options) { var d = can.Deferred(), requestOptions = can.extend({}, options); for (var option in optionsMap) { if (requestOptions[option] !== undefined) { requestOptions[optionsMap[option]] = requestOptions[option]; delete requestOptions[option] } } requestOptions.sync = !options.async; var success = options.success, error = options.error; requestOptions.on = { success : function (transactionid, response) { var data = response.responseText; if (options.dataType === 'json') { data = eval("(" + data + ")") } updateDeferred(request, d); d.resolve(data); success && success(data, "success", request); }, failure : function (transactionid, response) { updateDeferred(request, d); d.reject(request, "error"); error && error(request, "error"); } }; var request = Y.io(requestOptions.url, requestOptions); updateDeferred(request, d); return d; } // Events - The `id` of the `function` to be bound, used as an expando on the `function` // so we can lookup it's `remove` object. var yuiEventId = 0, // Takes a node list, goes through each node // and adds events data that has a map of events to // `callbackId` to `remove` object. It looks like // `{click: {5: {remove: fn}}}`. addBinding = function (nodelist, selector, ev, cb) { if (nodelist instanceof Y.NodeList || !nodelist.on || nodelist.getDOMNode) { nodelist.each(function (node) { var node = can.$(node); var events = can.data(node, "events"), eventName = ev + ":" + selector; if (!events) { can.data(node, "events", events = {}); } if (!events[eventName]) { events[eventName] = {}; } if (cb.__bindingsIds === undefined) { cb.__bindingsIds = yuiEventId++; } events[eventName][cb.__bindingsIds] = selector ? node.item(0).delegate(ev, cb, selector) : node.item(0).on(ev, cb); }); } else { var obj = nodelist, events = obj.__canEvents = obj.__canEvents || {}; if (!events[ev]) { events[ev] = {}; } if (cb.__bindingsIds === undefined) { cb.__bindingsIds = yuiEventId++; } events[ev][cb.__bindingsIds] = obj.on(ev, cb); } }, // Removes a binding on a `nodelist` by finding // the remove object within the object's data. removeBinding = function (nodelist, selector, ev, cb) { if (nodelist instanceof Y.NodeList || !nodelist.on || nodelist.getDOMNode) { nodelist.each(function (node) { var node = can.$(node), events = can.data(node, "events"); if (events) { var eventName = ev + ":" + selector, handlers = events[eventName], handler = handlers[cb.__bindingsIds]; handler.detach(); delete handlers[cb.__bindingsIds]; if (can.isEmptyObject(handlers)) { delete events[ev]; } if (can.isEmptyObject(events)) { } } }); } else { var obj = nodelist, events = obj.__canEvents || {}, handlers = events[ev], handler = handlers[cb.__bindingsIds]; handler.detach(); delete handlers[cb.__bindingsIds]; if (can.isEmptyObject(handlers)) { delete events[ev]; } if (can.isEmptyObject(events)) { } } } can.bind = function (ev, cb) { // If we can bind to it... if (this.bind && this.bind !== can.bind) { this.bind(ev, cb) } else if (this.on || this.nodeType) { addBinding(can.$(this), undefined, ev, cb) } else if (this.addEvent) { this.addEvent(ev, cb) } else { // Make it bind-able... can.addEvent.call(this, ev, cb) } return this; } can.unbind = function (ev, cb) { // If we can bind to it... if (this.unbind && this.unbind !== can.unbind) { this.unbind(ev, cb) } else if (this.on || this.nodeType) { removeBinding(can.$(this), undefined, ev, cb); } else { // Make it bind-able... can.removeEvent.call(this, ev, cb) } return this; } // Alias on/off to bind/unbind respectively can.on = can.bind; can.off = can.unbind; can.trigger = function (item, event, args, bubble) { if (item instanceof Y.NodeList) { item = item.item(0); } if (item.getDOMNode) { item = item.getDOMNode(); } if (item.nodeName) { item = Y.Node(item); if (bubble === false) { // Force stop propagation by listening to `on` and then // immediately disconnecting item.once(event, function (ev) { ev.stopPropagation && ev.stopPropagation(); ev.cancelBubble = true; ev._stopper && ev._stopper(); }) } if(typeof event !== "string"){ args = event; event = args.type; delete args.type; } realTrigger(item.getDOMNode(), event, args || {}) } else { if (typeof event === 'string') { event = { type : event } } event.target = event.target || item; can.dispatch.call(item, event, args) } }; // Allow `dom` `destroyed` events. Y.mix(Y.Node.DOM_EVENTS, { removed: true, inserted: true, foo: true }); can.delegate = function (selector, ev, cb) { if (this.on || this.nodeType) { addBinding(can.$(this), selector, ev, cb) } else if (this.delegate) { this.delegate(selector, ev, cb) } return this; } can.undelegate = function (selector, ev, cb) { if (this.on || this.nodeType) { removeBinding(can.$(this), selector, ev, cb); } else if (this.undelegate) { this.undelegate(selector, ev, cb) } return this; } // `realTrigger` taken from `dojo`. var leaveRe = /mouse(enter|leave)/, _fix = function (_, p) { return "mouse" + (p == "enter" ? "over" : "out"); }, realTrigger = document.createEvent ? function (n, e, a) { // the same branch var ev = document.createEvent("HTMLEvents"); e = e.replace(leaveRe, _fix); ev.initEvent(e, true, true); a && can.extend(ev, a); n.dispatchEvent(ev); } : function (n, e, a) { // the janktastic branch var ev = "on" + e, stop = false, lc = e.toLowerCase(), node = n; try { // FIXME: is this worth it? for mixed-case native event support:? Opera ends up in the // createEvent path above, and also fails on _some_ native-named events. // if(lc !== e && d.indexOf(d.NodeList.events, lc) >= 0){ // // if the event is one of those listed in our NodeList list // // in lowercase form but is mixed case, throw to avoid // // fireEvent. /me sighs. http://gist.github.com/315318 // throw("janktastic"); // } n.fireEvent(ev, a); } catch (er) { // a lame duck to work with. we're probably a 'custom event' var evdata = can.extend({ type : e, target : n, faux : true, // HACK: [needs] added support for customStopper to _base/event.js // some tests will fail until del._stopPropagation has support. _stopper : function () { stop = this.cancelBubble; } }, a); realTriggerHandler(n, e, evdata); // handle bubbling of custom events, unless the event was stopped. while (!stop && n !== document && n.parentNode) { n = n.parentNode; realTriggerHandler(n, e, evdata); //can.isFunction(n[ev]) && n[ev](evdata); } } }, realTriggerHandler = function (n, e, evdata) { var node = Y.Node(n), handlers = can.Y.Event.getListeners(node._yuid, e); if (handlers) { for (var i = 0; i < handlers.length; i++) { handlers[i].fire(evdata) } } }; return can; });