/* * @Author: 陶秋峰 * @Date: 2015-12-24 23:14:12 * @Last Modified by: 陶秋峰 * @Last Modified time: 2015-12-24 23:35:45 * @CopyRight 蛮蛮工作室 */ import {IPV} from './base'; import Component = require('./component'); import global from './global'; import has from './has'; import {Hash} from './interfaces'; import * as lang from './lang'; import {emit} from './on'; import Promise from './promise'; // import {Component} from './component'; let window: Window = global; function get_body(){ let doc = window && window.document; return doc && (doc.body || doc.getElementsByTagName("body")[0]); } interface N{ type?: string; node: HTMLElement; parent: N; } function scan(root: HTMLElement): Promise{ let list: N[] = []; let mids: string[] = []; let mid_hash: Hash = {}; let mmtype = "data-mm-type"; let node = root.firstElementChild; let parent: N; while(true){ if(!node){ if(!parent || !parent.node){ break; } node = parent.node.nextElementSibling; parent = parent.parent; continue; } // if(node.nodeType != 1){ // node = node.nextElementSibling; // continue; // } let type = node.getAttribute(mmtype); let nextElementSibling = node.nextElementSibling; if(!type){ node = node.nextElementSibling; continue; } let current: N; if(!mid_hash[type]){ mid_hash[type] = true; mids.push('proj/' + type + '/d'); mids.push('proj/' + type + '/c'); mids.push('proj/' + type + '/s'); mids.push('text!proj/' + type + '/r.nrl'); mids.push('text!proj/' + type + '/t.tpl'); } current = { type: type, parent: parent, node: node }; list.push(current); parent = current; node = nextElementSibling; } return new Promise(function(resolve, reject){ if(list.length){ requirejs(mids, function(){ resolve(list); }); }else{ resolve([]); } }); } function construct(ctor: typeof Component, tpl: string, node: HTMLElement, state: any, rule: string, def: IPV): Component{ let params: { [attr: string]: any; } = {}; let attributes: NamedNodeMap | {name: string, value: string}[]; // let attributes: NamedNodeMap; if(has("dom-attributes-explicit")){ // Standard path to get list of user specified attributes attributes = node.attributes; }else{ let clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false), attrs = clone.outerHTML.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*\s*/, "").replace(/\s*>.*$/, ""); attributes = attrs.split(/\s+/).map(function(name){ let lcName = name.toLowerCase(); return { name: name, value: (node.nodeName == "LI" && name == "value") || lcName == "enctype" ? node.getAttribute(lcName) : node.getAttributeNode(lcName).value }; }); } let i = 0; let item; let extra: string; while(item = attributes[i++]){ let name: string = item.name; let value: string = item.value; switch(name){ case "data-mm-type": break; case "data-mm-props": extra = value; break; case "data-mm-attach-point": params['attach_point'] = value; break; case "data-mm-attach-event": params['attach_event'] = value; break; // case "class": // params["class"] = node.className; // break; // case "style": // params["style"] = node.style && node.style.cssText; // break; default: params[name] = value; } } if(extra){ try{ extra = eval("{" + extra + "}"); lang.mixin(params, extra); }catch(e){ // give the user a pointer to their invalid parameters. FIXME: can we kill this in production? throw new Error(e.toString() + " in data-mm-props='" + extra + "'"); } } let ins = new ctor(); ins.create(params, tpl, node, state, rule, def); return ins; } function instantiate(nodes: N[]): Promise{ let thelist = nodes.map(function(obj){ let d = require('proj/' + obj.type + '/d'); let ctor = require('proj/' + obj.type + '/c'); let state = require('proj/' + obj.type + '/s'); let tpl = require('text!proj/' + obj.type + '/t.tpl'); let nrl = require('text!proj/' + obj.type + '/r.nrl'); return construct(ctor, tpl, obj.node, state, nrl, d); }); return Promise.all(thelist); } export function parse(root?: HTMLElement): Promise { root || (root = get_body()); if(!root){ console.error('cannot get body of current window document'); return; } return scan(root) .then(instantiate) .then(function(widgets){ emit(window, {type: 'resize'}); return widgets; }) .catch(function(e){ console.error('pase error:', e); return []; }); } declare module mmstudio { export function parse(root?: HTMLElement): Promise; }