UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

306 lines (305 loc) 12.5 kB
/*! * CanJS - 2.3.34 * http://canjs.com/ * Copyright (c) 2018 Bitovi * Mon, 30 Apr 2018 20:56:51 GMT * Licensed MIT */ /*can@2.3.34#view/view*/ define(['can/util/library'], function (can) { var isFunction = can.isFunction, makeArray = can.makeArray, hookupId = 1; var makeRenderer = function (textRenderer) { var renderer = function () { return $view.frag(textRenderer.apply(this, arguments)); }; renderer.render = function () { return textRenderer.apply(textRenderer, arguments); }; return renderer; }; var checkText = function (text, url) { if (!text.length) { can.dev.log('can/view/view.js: There is no template or an empty template at ' + url); throw new Error('can.view: No template or empty template:' + url); } }; var getRenderer = function (obj, async) { if (isFunction(obj)) { var def = can.Deferred(); return def.resolve(obj); } var url = typeof obj === 'string' ? obj : obj.url, suffix = obj.engine && '.' + obj.engine || url.match(/\.[\w\d]+$/), type, el, id; if (url.match(/^#/)) { url = url.substr(1); } if (el = document.getElementById(url)) { suffix = '.' + el.type.match(/\/(x\-)?(.+)/)[2]; } if (!suffix && !$view.cached[url]) { url += suffix = $view.ext; } if (can.isArray(suffix)) { suffix = suffix[0]; } id = $view.toId(url); if (url.match(/^\/\//)) { url = url.substr(2); url = !window.steal ? url : steal.config().root.mapJoin('' + steal.id(url)); } if (window.require) { if (require.toUrl) { url = require.toUrl(url); } } type = $view.types[suffix]; if ($view.cached[id]) { return $view.cached[id]; } else if (el) { return $view.registerView(id, el.innerHTML, type); } else { var d = new can.Deferred(); can.ajax({ async: async, url: url, dataType: 'text', error: function (jqXHR) { checkText('', url); d.reject(jqXHR); }, success: function (text) { checkText(text, url); $view.registerView(id, text, type, d); } }); return d; } }; var getDeferreds = function (data) { var deferreds = []; if (can.isPromise(data)) { return [data]; } else { for (var prop in data) { if (can.isPromise(data[prop])) { deferreds.push(data[prop]); } } } return deferreds; }; var usefulPart = function (resolved) { return can.isArray(resolved) && resolved[1] === 'success' ? resolved[0] : resolved; }; var $view = can.view = can.template = function (view, data, helpers, callback) { if (isFunction(helpers)) { callback = helpers; helpers = undefined; } return $view.renderAs('fragment', view, data, helpers, callback); }; can.extend($view, { frag: function (result, parentNode) { return $view.hookup($view.fragment(result), parentNode); }, fragment: function (result) { return can.frag(result, document); }, toId: function (src) { return can.map(src.toString().split(/\/|\./g), function (part) { if (part) { return part; } }).join('_'); }, toStr: function (txt) { return txt == null ? '' : '' + txt; }, hookup: function (fragment, parentNode) { var hookupEls = [], id, func; can.each(fragment.childNodes ? can.makeArray(fragment.childNodes) : fragment, function (node) { if (node.nodeType === 1) { hookupEls.push(node); hookupEls.push.apply(hookupEls, can.makeArray(node.getElementsByTagName('*'))); } }); can.each(hookupEls, function (el) { if (el.getAttribute && (id = el.getAttribute('data-view-id')) && (func = $view.hookups[id])) { func(el, parentNode, id); delete $view.hookups[id]; el.removeAttribute('data-view-id'); } }); return fragment; }, hookups: {}, hook: function (cb) { $view.hookups[++hookupId] = cb; return ' data-view-id=\'' + hookupId + '\''; }, cached: {}, cachedRenderers: {}, cache: true, register: function (info) { this.types['.' + info.suffix] = info; if (typeof window !== 'undefined' && window.steal && steal.type) { steal.type(info.suffix + ' view js', function (options, success, error) { var type = $view.types['.' + options.type], id = $view.toId(options.id + ''); options.text = type.script(id, options.text); success(); }); } can[info.suffix] = $view[info.suffix] = function (id, text) { var renderer, renderFunc; if (!text) { renderFunc = function () { if (!renderer) { if (info.fragRenderer) { renderer = info.fragRenderer(null, id); } else { renderer = makeRenderer(info.renderer(null, id)); } } return renderer.apply(this, arguments); }; renderFunc.render = function () { var textRenderer = info.renderer(null, id); return textRenderer.apply(textRenderer, arguments); }; return renderFunc; } var registeredRenderer = function () { if (!renderer) { if (info.fragRenderer) { renderer = info.fragRenderer(id, text); } else { renderer = info.renderer(id, text); } } return renderer.apply(this, arguments); }; if (info.fragRenderer) { return $view.preload(id, registeredRenderer); } else { return $view.preloadStringRenderer(id, registeredRenderer); } }; }, types: {}, ext: '.ejs', registerScript: function (type, id, src) { return 'can.view.preloadStringRenderer(\'' + id + '\',' + $view.types['.' + type].script(id, src) + ');'; }, preload: function (id, renderer) { var def = $view.cached[id] = new can.Deferred().resolve(function (data, helpers) { return renderer.call(data, data, helpers); }); def.__view_id = id; $view.cachedRenderers[id] = renderer; return renderer; }, preloadStringRenderer: function (id, stringRenderer) { return this.preload(id, makeRenderer(stringRenderer)); }, render: function (view, data, helpers, callback, nodelist) { return can.view.renderAs('string', view, data, helpers, callback, nodelist); }, renderTo: function (format, renderer, data, helpers, nodelist) { return (format === 'string' && renderer.render ? renderer.render : renderer)(data, helpers, nodelist); }, renderAs: function (format, view, data, helpers, callback, nodelist) { if (callback !== undefined && typeof callback.expression === 'string') { nodelist = callback; callback = undefined; } if (isFunction(helpers)) { callback = helpers; helpers = undefined; } var deferreds = getDeferreds(data); var deferred, dataCopy, async, response; if (deferreds.length) { deferred = new can.Deferred(); dataCopy = can.extend({}, data); deferreds.push(getRenderer(view, true)); can.when.apply(can, deferreds).then(function (resolved) { var objs = makeArray(arguments), renderer = objs.pop(), result; if (can.isPromise(data)) { dataCopy = usefulPart(resolved); } else { for (var prop in data) { if (can.isPromise(data[prop])) { dataCopy[prop] = usefulPart(objs.shift()); } } } result = can.view.renderTo(format, renderer, dataCopy, helpers, nodelist); deferred.resolve(result, dataCopy); if (callback) { callback(result, dataCopy); } }, function () { deferred.reject.apply(deferred, arguments); }); return deferred; } else { async = isFunction(callback); deferred = can.__notObserve(getRenderer)(view, async); if (async) { response = deferred; deferred.then(function (renderer) { callback(data ? can.view.renderTo(format, renderer, data, helpers, nodelist) : renderer); }); } else { if (deferred.state() === 'resolved' && deferred.__view_id) { var currentRenderer = $view.cachedRenderers[deferred.__view_id]; return data ? can.view.renderTo(format, currentRenderer, data, helpers, nodelist) : currentRenderer; } else { deferred.then(function (renderer) { response = data ? can.view.renderTo(format, renderer, data, helpers, nodelist) : renderer; }); } } return response; } }, registerView: function (id, text, type, def) { var info = typeof type === 'object' ? type : $view.types[type || $view.ext], renderer; if (info.fragRenderer) { renderer = info.fragRenderer(id, text); } else { renderer = makeRenderer(info.renderer(id, text)); } def = def || new can.Deferred(); if ($view.cache) { $view.cached[id] = def; def.__view_id = id; $view.cachedRenderers[id] = renderer; } return def.resolve(renderer); }, simpleHelper: function (fn) { return function () { var realArgs = []; var fnArgs = arguments; can.each(fnArgs, function (val, i) { if (i <= fnArgs.length) { while (val && val.isComputed) { val = val(); } realArgs.push(val); } }); return fn.apply(this, realArgs); }; } }); if (typeof window !== 'undefined' && window.steal && steal.type) { steal.type('view js', function (options, success, error) { var type = $view.types['.' + options.type], id = $view.toId(options.id); var dependency = type.plugin || 'can/view/' + options.type, preload = type.fragRenderer ? 'preload' : 'preloadStringRenderer'; options.text = 'steal(\'can/view\',\'' + dependency + '\',function(can){return ' + 'can.view.' + preload + '(\'' + id + '\',' + options.text + ');\n})'; success(); }); } return can; });