API Docs for: 0.0.1
Show:

File: src/node-win/node-win.js

"use strict";

/**
 * Emulation of browser `window` and `dom`. Just enough to make ITSA work.
 *
 *
 * <i>Copyright (c) 2014 ITSA - https://github.com/itsa</i>
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 * @module node-win
 * @class window
 * @static
*/

require('js-ext/lib/array.js');

var xmlhttprequest = require('./lib/XMLHttpRequest.js').XMLHttpRequest,
    createHashMap = require('js-ext/extra/hashmap.js').createMap,
    xmlDOMParser = require('xmldom').DOMParser,
    Url = require('url'),
    used = createHashMap(),
    // vNodeParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g,
    count, doc, win, getHTML, reset, EventTypes;
    EventTypes = createHashMap({
        MouseEvents: function () {
            this.initMouseEvent = function (type, bubbles, cancelable, view, detail,
                    screenX, screenY, clientX, clientY,
                    ctrlKey, altKey, shiftKey, metaKey,
                    button, relatedTarget) {
                count('initMouseEvent');
                this.ev = {
                    type:type,
                    bubbles:bubbles,
                    cancelable:cancelable,
                    view:view,
                    detail:detail,
                    screenX:screenX,
                    screenY:screenY,
                    clientX:clientX,
                    clientY:clientY,
                    ctrlKey:ctrlKey,
                    altKey:altKey,
                    shiftKey:shiftKey,
                    metaKey:metaKey,
                    button:button,
                    relatedTarget:relatedTarget
                };
            };
        }
    });

count = function (method) {
    if (!used[method]) {
        used[method] = 1;
    } else {
        used[method] += 1;
    }
};

getHTML = function (node) {
    var prop, val,
        style, styles = [],
        html = '';

    if (!node.nodeName && node.nodeValue) {
        // For text nodes, I return the uppercase text
        // so that you can tell the parts generated at the server
        // from the normal lowercase of the actual app when run on the client
        return node.nodeValue.toUpperCase();
    }
    html += '<' + node.nodeName;
    for (prop in node) {
        val = node[prop];

        // Ignore functions, those will be revived on the client side.
        if (typeof val == 'function') continue;
        switch (prop) {
        case 'nodeName':
        case 'parentNode':
        case 'childNodes':
        case 'pathname':
        case 'search':
            continue;
        case 'checked':
            if (val == 'false') continue;
            break;
        case 'href':
            val = node.pathname;
            break;
        case 'className':
            prop = 'class';
            break;
        case 'style':
            if (val) {
                for (style in val) {
                    if (val[style]) {
                        styles.push(style + ': ' + val[style]);
                    }
                }
                if (!styles.length) {
                    continue;
                }
                val = styles.join(';');
            }
            break;
        }
        html += ' ' + prop + '="' + val.replace('"', '\\"') + '"';
    }

    if (node.childNodes.length) {
        html += '>' + node.childNodes.reduce(function (prev, node) {
            return prev + getHTML(node);
        }, '') + '</' + node.nodeName + '>';
    }
    else {
        // I don't know why Mithril assigns the content of textareas
        // to its value attribute instead of the innerHTML property.
        // Since it doesn't have children, the closing tag has to be forced.
        if (node.nodeName == 'TEXTAREA') {
            html += '></TEXTAREA>';
        } else {
            html += '/>';
        }
    }
    return html;
};


win = {
    cancelAnimationFrame: function() {

    },

    console: require('polyfill/lib/window.console.js'),

    CSSStyleDeclaration: {},

    document: doc,

    DOMParser: xmlDOMParser,

    HTMLCollection: Array,

    location: {},

    navigator: {
        userAgent: 'fake',
        stats: {
            clear: function () {
                used = {};
            },
            get: function () {
                return used;
            }
        },
        reset: reset,
        getHTML: function () {
            return getHTML(doc.body);
        },
        navigate: function (url) {
            var u = Url.parse(url, false, true);
            win.location.search = u.search || '';
            win.location.pathname = u.pathname || '';
            win.location.hash = u.hash || '';
        }
    },

    NodeList: Array,

    performance: function () {
        var timestamp = 50;
        this.$elapse = function(amount) {
            timestamp += amount;
        };
        this.now = function() {
            return timestamp;
        };
    },

    requestAnimationFrame: function(callback) {
        var instance = this;
        instance.requestAnimationFrame.$callback = callback;
        instance.requestAnimationFrame.$resolve = function() {
            instance.requestAnimationFrame.$callback && instance.requestAnimationFrame.$callback();
            instance.requestAnimationFrame.$callback = null;
            instance.performance.$elapse(20);
        };
    },

    XMLHttpRequest: xmlhttprequest

};

reset = function () {
    var body = doc.createElement('body');
    win.location.search = "?/";
    win.location.pathname = "/";
    win.location.hash = "";
    win.history = {};
    win.history.pushState = function(data, title, url) {
        win.location.pathname = win.location.search = win.location.hash = url;
    },
    win.history.replaceState = function(data, title, url) {
        win.location.pathname = win.location.search = win.location.hash = url;
    };
    doc.appendChild(body);
    doc.body = body;
};

reset();

module.exports = win;