<commit_before>/**
 * Main ui constructor
 *
 * @contructor
 *
 */
MartIrcUi = function() {
    if (! (this instanceof arguments.callee)) {
        return new arguments.callee(arguments);
    }

    var self = this;

    self.ircConnection = null;

    self.init();
    self.bindEvents();
};

/**
 * MartIrcUi init
 *
 */
MartIrcUi.prototype.init = function() {
    var self = this;
};

MartIrcUi.prototype.bindEvents = function() {
    var self = this;

    $('#connectButton').click(function() {
				  self.connect();
			      });

    $('#prompt form').submit(function(event){
				 event.preventDefault();

				 self.parseOutgoingMessage();
			     });

    $('#chat .current-title img').live('click', function(event){
					   self.removeChat();
				       });

    $('#channels a.channel').live('click', function(event){
					  self.focusOnPublicChat($(this));
				      });

    $('#channels a.user, #users .list.active a').live('click', function(event){
							      self.focusOnPrivateChat($(this));
							  });

    $('#channels a.server').live('click', function(event){
					self.focusOnServer();
				     });

    $('#prompt form input').focus();
};

MartIrcUi.prototype.connect = function() {
    var self = this;

    if(self.ircConnection && self.ircConnection.connected()){
	self.ircConnection.disconnect();

	self.ircConnection = null;
    }

    self.ircConnection = new IrcConnection({
					       nodeServerHost : $('#nodeServerHost').val(),
					       nodeServerPort : parseInt($('#nodeServerPort').val()),
					       ircServerHost : $('#ircServerHost').val(),
					       ircServerPort : parseInt($('#ircServerPort').val()),
					       nickname : $('#nickname').val()
					   });

    $(self.ircConnection).bind('irc.server',function(event, data) {
				   $(self).trigger('irc.server', data);

				   self.displayServerMessage(data.raw);

				   self.parseIncomingMessage(data);
			       });

};

MartIrcUi.prototype.displayServerMessage = function(rawMsg) {
    var self = this;

    //console.log('Notice: ' + message);

    var msg = $('').addClass('msg');
    msg.append($('').addClass('server-msg').text('Server : '));
    msg.append($('').addClass('txt').text(rawMsg));

    $("#chat .server").append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.scanMessage = function(rawMsg) {
    var self = this;

    var regex = /\b(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)[-A-Z0-9+&@#\/%=~_|$?!:,.]*[A-Z0-9+&@#\/%=~_|$]/i;

    return rawMsg.replace(regex," $& ");
};

MartIrcUi.prototype.parseIncomingMessage = function(data) {
    var self = this;

    switch(data.command){
	case 'privmsg':
	self.receiveMessage(data.params[0], data.person.nick, data.params[1]);
	break;
    }
};

MartIrcUi.prototype.parseOutgoingMessage = function() {
    var self = this;

    var extractCommand = new RegExp("^:(\\w)(?: ([\\S]+))*", "");

    var rawMsg = $('#prompt form input').val();

    $('#prompt form input').val('');

    var matches = rawMsg.match(extractCommand);

    if(!matches) {
	self.sendMessage(rawMsg);

	return;
    }

    switch(matches[1]){
    case 'c':
	self.connect();
	break;
    case 'j':
	self.ircConnection.join(matches[2]);

	if(matches[2][0] === '#'){
	    var id = self.createPublicChat(matches[2]);

	    self.focusOnPublicChat($('#channels a#'+id));
	} else {
	    var id = self.createPrivateChat(matches[2]);

	    self.displayUsersTab(false);
	    self.focusOnPrivateChat($('#channels a#'+id));
	}

	break;
    }
};

MartIrcUi.prototype.receiveMessage = function(chat, nickname, rawMsg) {
    var self = this;

    var msg = $('').addClass('msg');
    msg.append($('').addClass("nick").text(nickname +' : '));
    msg.append($('').addClass('txt').append(self.scanMessage(rawMsg)));

    var id = $('#channels a:contains("'+chat+'")').attr('id');

    if(!id){
	id = self.createPrivateChat(chat);

	self.displayUsersTab(false);
	self.focusOnPrivateChat($('#channels a#'+id));
    }

    $('#chat .'+id).append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.sendMessage = function(rawMsg) {
    var self = this;

    var msg = $('').addClass('msg');

    if($('#chat .active').hasClass('server')) {
	msg.append($('').addClass("command").text('Command : '));
	msg.append($('').addClass('txt').text(rawMsg));
	self.ircConnection.sendMessage(rawMsg);
    } else {
	msg.append($('').addClass("current-user nick").text($('#nickname').val()+' : '));
	msg.append($('').addClass('txt').append(self.scanMessage(rawMsg)));
	self.ircConnection.privmsg($('#channels .active').text(), rawMsg);
    }

    $('#chat .active').append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.createPublicChat = function(name) {
    var self = this;

    var id = 'channel-'+new Date().getTime();

    $('#channels').append($('').attr('id', id).addClass('channel').text(name));
    $('#chat').append($('
').addClass(id));
    $("#users").append($('
').addClass('list '+id));

    return id;
};

MartIrcUi.prototype.createPrivateChat = function(name) {
    var self = this;

    var id = 'user-'+new Date().getTime();

    $('#channels').append($('').attr('id', id).addClass('user').text(name));
    $('#chat').append($('
').addClass(id));

    return id;
};

MartIrcUi.prototype.focusOnPrompt = function() {
    var self = this;

    $("#chat .active").attr({ scrollTop: $("#chat .active").attr("scrollHeight") });

    $('#prompt form input').focus();
};

MartIrcUi.prototype.focusOnServer = function() {
    var self = this;

    self.changeActiveChat('server', 'Server');

    self.displayUsersTab(false);
    self.displayCloseIcon(false);

    var chatToEnable = $('#chat .server').addClass('active');
    chatToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.focusOnPrivateChat = function(channel) {
    var self = this;
    var id;

    if(channel.attr('id')){
	id = channel.attr('id');
    } else {
	id = channel.attr('class');
    }

    self.changeActiveChat(id, 'Private : '+channel.text());

    self.displayUsersTab(false);
    self.displayCloseIcon(true);

    if(!$('#channels a#'+id).get(0)){
	var user = $('').attr('id', id).attr('class', 'user').text(channel.text());
	$('#channels').append(user);

	var userChat = $('
').attr('class', id);
	$('#chat').append(userChat);
    }

    var chatTitle = 'Private : '+channel.text();

    var chatToEnable = $('#chat .'+id).addClass('active');
    chatToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.focusOnPublicChat = function(channel) {
    var self = this;
    var id = channel.attr('id');

    self.changeActiveChat(id, 'Public : '+channel.text());

    self.displayUsersTab(true);
    self.displayCloseIcon(true);

    var chatTitle = 'Public : '+channel.text();

    var chatAndUsersToEnable = $('#chat .'+id+', #users .list.'+id).addClass('active');
    chatAndUsersToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.changeActiveChat = function(id, chatTitle) {
    var self = this;

    var channelToDisable = $('#channels .active');
    var chatAndUsersToDisable = $('#chat .active, #users .list.active');

    chatAndUsersToDisable.hide();
    channelToDisable.removeClass('active');
    chatAndUsersToDisable.removeClass('active');

    $("#chat .current-title span").text(chatTitle);

    $('#'+id).addClass('active');
};

MartIrcUi.prototype.removeChat = function() {
    var self = this;

    var id = $('#channels .active').attr('id');

    $('#channels  #'+id+', #chat .'+id).remove();

    if($('#channels .active').hasClass('channel')){
	$('#users .'+id).remove();
    }

    var lastChannel = $('#channels a').last();

    if(lastChannel.hasClass('channel')) {
	self.focusOnPublicChat(lastChannel);
    } else if(lastChannel.hasClass('user')) {
	self.focusOnPrivateChat(lastChannel);
    } else {
	self.focusOnServer();
    }
};

MartIrcUi.prototype.displayUsersTab = function(display) {
    var self = this;

    if(display){
	$('#chat, #prompt').removeClass('span-19');
	$('#chat, #prompt').addClass('span-16');
	$('#prompt').removeClass('append-1');
	$('#prompt').addClass('append-4');
	$('#prompt .text').addClass('span-14');
	$('#prompt .text').removeClass('span-17');
	$('#users').removeClass('last');
	$('#chat').addClass('last');
	$('#users').show();
    } else {
	$('#chat, #prompt').removeClass('span-16');
	$('#chat, #prompt').addClass('span-19');
	$('#prompt').removeClass('append-4');
	$('#prompt').addClass('append-1');
	$('#prompt .text').removeClass('span-14');
	$('#prompt .text').addClass('span-17');
	$('#users').addClass('last');
	$('#chat').removeClass('last');
	$('#users').hide();
    }
};

MartIrcUi.prototype.displayCloseIcon = function(display) {
    var self = this;

    if(display){
	$('#chat .current-title img').css('visibility', 'visible');
    } else {
	$('#chat .current-title img').css('visibility', 'hidden');
    }
};
<commit_msg>Fix: closing remote connection action to channel was missing<commit_after>/**
 * Main ui constructor
 *
 * @contructor
 *
 */
MartIrcUi = function() {
    if (! (this instanceof arguments.callee)) {
        return new arguments.callee(arguments);
    }

    var self = this;

    self.ircConnection = null;

    self.init();
    self.bindEvents();
};

/**
 * MartIrcUi init
 *
 */
MartIrcUi.prototype.init = function() {
    var self = this;
};

MartIrcUi.prototype.bindEvents = function() {
    var self = this;

    $('#connectButton').click(function() {
				  self.connect();
			      });

    $('#prompt form').submit(function(event){
				 event.preventDefault();

				 self.parseOutgoingMessage();
			     });

    $('#chat .current-title img').live('click', function(event){
					   self.removeChat();
				       });

    $('#channels a.channel').live('click', function(event){
					  self.focusOnPublicChat($(this));
				      });

    $('#channels a.user, #users .list.active a').live('click', function(event){
							      self.focusOnPrivateChat($(this));
							  });

    $('#channels a.server').live('click', function(event){
					self.focusOnServer();
				     });

    $('#prompt form input').focus();
};

MartIrcUi.prototype.connect = function() {
    var self = this;

    if(self.ircConnection && self.ircConnection.connected()){
	self.ircConnection.disconnect();

	self.ircConnection = null;
    }

    self.ircConnection = new IrcConnection({
					       nodeServerHost : $('#nodeServerHost').val(),
					       nodeServerPort : parseInt($('#nodeServerPort').val()),
					       ircServerHost : $('#ircServerHost').val(),
					       ircServerPort : parseInt($('#ircServerPort').val()),
					       nickname : $('#nickname').val()
					   });

    $(self.ircConnection).bind('irc.server',function(event, data) {
				   $(self).trigger('irc.server', data);

				   self.displayServerMessage(data.raw);

				   self.parseIncomingMessage(data);
			       });

};

MartIrcUi.prototype.displayServerMessage = function(rawMsg) {
    var self = this;

    //console.log('Notice: ' + message);

    var msg = $('').addClass('msg');
    msg.append($('').addClass('server-msg').text('Server : '));
    msg.append($('').addClass('txt').text(rawMsg));

    $("#chat .server").append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.scanMessage = function(rawMsg) {
    var self = this;

    var regex = /\b(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)[-A-Z0-9+&@#\/%=~_|$?!:,.]*[A-Z0-9+&@#\/%=~_|$]/i;

    return rawMsg.replace(regex," $& ");
};

MartIrcUi.prototype.parseIncomingMessage = function(data) {
    var self = this;

    switch(data.command){
	case 'privmsg':
	self.receiveMessage(data.params[0], data.person.nick, data.params[1]);
	break;
    }
};

MartIrcUi.prototype.parseOutgoingMessage = function() {
    var self = this;

    var extractCommand = new RegExp("^:(\\w)(?: ([\\S]+))*", "");

    var rawMsg = $('#prompt form input').val();

    $('#prompt form input').val('');

    var matches = rawMsg.match(extractCommand);

    if(!matches) {
	self.sendMessage(rawMsg);

	return;
    }

    switch(matches[1]){
    case 'c':
	self.connect();
	break;
    case 'j':
	self.ircConnection.join(matches[2]);

	if(matches[2][0] === '#'){
	    var id = self.createPublicChat(matches[2]);

	    self.focusOnPublicChat($('#channels a#'+id));
	} else {
	    var id = self.createPrivateChat(matches[2]);

	    self.displayUsersTab(false);
	    self.focusOnPrivateChat($('#channels a#'+id));
	}

	break;
    }
};

MartIrcUi.prototype.receiveMessage = function(chat, nickname, rawMsg) {
    var self = this;

    var msg = $('').addClass('msg');
    msg.append($('').addClass("nick").text(nickname +' : '));
    msg.append($('').addClass('txt').append(self.scanMessage(rawMsg)));

    var id = $('#channels a:contains("'+chat+'")').attr('id');

    if(!id){
	id = self.createPrivateChat(chat);

	self.displayUsersTab(false);
	self.focusOnPrivateChat($('#channels a#'+id));
    }

    $('#chat .'+id).append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.sendMessage = function(rawMsg) {
    var self = this;

    var msg = $('').addClass('msg');

    if($('#chat .active').hasClass('server')) {
	msg.append($('').addClass("command").text('Command : '));
	msg.append($('').addClass('txt').text(rawMsg));
	self.ircConnection.sendMessage(rawMsg);
    } else {
	msg.append($('').addClass("current-user nick").text($('#nickname').val()+' : '));
	msg.append($('').addClass('txt').append(self.scanMessage(rawMsg)));
	self.ircConnection.privmsg($('#channels .active').text(), rawMsg);
    }

    $('#chat .active').append(msg);

    self.focusOnPrompt();
};

MartIrcUi.prototype.createPublicChat = function(name) {
    var self = this;

    var id = 'channel-'+new Date().getTime();

    $('#channels').append($('').attr('id', id).addClass('channel').text(name));
    $('#chat').append($('
').addClass(id));
    $("#users").append($('
').addClass('list '+id));

    return id;
};

MartIrcUi.prototype.createPrivateChat = function(name) {
    var self = this;

    var id = 'user-'+new Date().getTime();

    $('#channels').append($('').attr('id', id).addClass('user').text(name));
    $('#chat').append($('
').addClass(id));

    return id;
};

MartIrcUi.prototype.focusOnPrompt = function() {
    var self = this;

    $("#chat .active").attr({ scrollTop: $("#chat .active").attr("scrollHeight") });

    $('#prompt form input').focus();
};

MartIrcUi.prototype.focusOnServer = function() {
    var self = this;

    self.changeActiveChat('server', 'Server');

    self.displayUsersTab(false);
    self.displayCloseIcon(false);

    var chatToEnable = $('#chat .server').addClass('active');
    chatToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.focusOnPrivateChat = function(channel) {
    var self = this;
    var id;

    if(channel.attr('id')){
	id = channel.attr('id');
    } else {
	id = channel.attr('class');
    }

    self.changeActiveChat(id, 'Private : '+channel.text());

    self.displayUsersTab(false);
    self.displayCloseIcon(true);

    if(!$('#channels a#'+id).get(0)){
	var user = $('').attr('id', id).attr('class', 'user').text(channel.text());
	$('#channels').append(user);

	var userChat = $('
').attr('class', id);
	$('#chat').append(userChat);
    }

    var chatTitle = 'Private : '+channel.text();

    var chatToEnable = $('#chat .'+id).addClass('active');
    chatToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.focusOnPublicChat = function(channel) {
    var self = this;
    var id = channel.attr('id');

    self.changeActiveChat(id, 'Public : '+channel.text());

    self.displayUsersTab(true);
    self.displayCloseIcon(true);

    var chatTitle = 'Public : '+channel.text();

    var chatAndUsersToEnable = $('#chat .'+id+', #users .list.'+id).addClass('active');
    chatAndUsersToEnable.show();

    self.focusOnPrompt();
};

MartIrcUi.prototype.changeActiveChat = function(id, chatTitle) {
    var self = this;

    var channelToDisable = $('#channels .active');
    var chatAndUsersToDisable = $('#chat .active, #users .list.active');

    chatAndUsersToDisable.hide();
    channelToDisable.removeClass('active');
    chatAndUsersToDisable.removeClass('active');

    $("#chat .current-title span").text(chatTitle);

    $('#'+id).addClass('active');
};

MartIrcUi.prototype.removeChat = function() {
    var self = this;

    var id = $('#channels .active').attr('id');
    var name = $('#channels .active').text();

    if(name[0] === '#'){
	self.ircConnection.part(name);
    }

    $('#channels  #'+id+', #chat .'+id).remove();

    if($('#channels .active').hasClass('channel')){
	$('#users .'+id).remove();
    }

    var lastChannel = $('#channels a').last();

    if(lastChannel.hasClass('channel')) {
	self.focusOnPublicChat(lastChannel);
    } else if(lastChannel.hasClass('user')) {
	self.focusOnPrivateChat(lastChannel);
    } else {
	self.focusOnServer();
    }
};

MartIrcUi.prototype.displayUsersTab = function(display) {
    var self = this;

    if(display){
	$('#chat, #prompt').removeClass('span-19');
	$('#chat, #prompt').addClass('span-16');
	$('#prompt').removeClass('append-1');
	$('#prompt').addClass('append-4');
	$('#prompt .text').addClass('span-14');
	$('#prompt .text').removeClass('span-17');
	$('#users').removeClass('last');
	$('#chat').addClass('last');
	$('#users').show();
    } else {
	$('#chat, #prompt').removeClass('span-16');
	$('#chat, #prompt').addClass('span-19');
	$('#prompt').removeClass('append-4');
	$('#prompt').addClass('append-1');
	$('#prompt .text').removeClass('span-14');
	$('#prompt .text').addClass('span-17');
	$('#users').addClass('last');
	$('#chat').removeClass('last');
	$('#users').hide();
    }
};

MartIrcUi.prototype.displayCloseIcon = function(display) {
    var self = this;

    if(display){
	$('#chat .current-title img').css('visibility', 'visible');
    } else {
	$('#chat .current-title img').css('visibility', 'hidden');
    }
};
<|endoftext|>


<commit_before>/*
    Light weight jQuery like dom lib

    Global Object: lightDom
 */
 (function(window,document){
    // CustomEvent polyfill
    (function () {
        function CustomEvent ( event, params ) {
            params = params || { bubbles: false, cancelable: false, detail: undefined };
            var evt = document.createEvent( 'CustomEvent' );
            evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
            return evt;
        };
        CustomEvent.prototype = window.Event.prototype;
        window.CustomEvent = CustomEvent;
    })();

    // Only needed for the console css
    var is_chrome = typeof window.chrome == "undefined";
    // Display color if available
    function customLog(text, css){
        if( is_chrome )
            console.log('%c'+text, css || '');
        else
            console.log(text);
    }

    // Global object
    var lightDom = window["LD"] = window["lightDom"] = function(selector) {
        return new domManipulator(selector);
    };

    // Let extend the LightDom object
    lightDom.extend = function(extendingObjs){
        for( var i in  extendingObjs ){
            domManipulator.prototype[i] = extendingObjs[i];
        }
    };

    // Ajax request
    lightDom.ajax = function(params){
        var request = params.crossDomain ? createCORSRequest() : new XMLHttpRequest() ;

        request.open(params.type, params.url, params.async || true);

        var needJSONParsing = false;
        try {   // ResponseType is fairly new, so does not work everywhere
            request.responseType = params.dataType || "";
        }
        catch(e){
            customLog("Could not set responseType", 'color:red');
            needJSONParsing = (params.dataType || "") == "json";
        }

        request.onreadystatechange=function() {
            if( request ) {
                if (request.readyState == 4 && request.status == 200) {
                    params.success(  needJSONParsing || (params.dataType == "json" && typeof request.response != 'object') ? JSON.parse(request.response) : request.response);
                }
                else if (request.status >= 400 && request.readyState == 4) {
                    params.error(request, request.status, request.statusText);
                }
            }
        };

        request.timeout = params.timeout || null;
        request.onprogress = params.progress || null;
        request.onerror = request.ontimeout =  params.error || null;

        request.send();

        function createCORSRequest(){
            var xhr = new XMLHttpRequest();
            if ("withCredentials" in xhr){
            } else if (typeof XDomainRequest != "undefined"){
                xhr = new XDomainRequest();
            } else {
                xhr = null;
            }
            return xhr;
        }
    };

    // Figure out if we're on a touch device or not -> TODO: improve to fix problem with devices having both click & touch
    lightDom.isTouchDevice =  ('ontouchstart' in document.documentElement )

    // Selector / constuctor
    function domManipulator(selector){
        this.init(selector);
    }

    // pass a parameter than can be wether a String, a domManipulator or DOM node
    function getDOMFromParameter(selector){
        if( selector instanceof domManipulator)
            return selector.dom;

        // String == selector || HTML string
        if( typeof selector == "string") {
            var tmp = document.createElement("div");
            tmp.className = "mziDiv";
            tmp.innerHTML = selector;
            var findMe = tmp.querySelectorAll('.mziDiv > *');
            if( findMe.length == 0 )                                // If no child created by innerHTML -> We assume we're selecting in the document
                return document.querySelectorAll(selector);
            else                                                    // Else the string has created nodes, so we return this new object
                return findMe;
        }
        else
            if( selector.length )   // DOM nodes array passed in param TODO: find a better way to check: typeof Array does not work, and Object.prototype.toString.call(o) === '[object Array]' neither
                return selector;
             else
                 return [selector];  // Single dom node passed in param
    }

    // Init
    domManipulator.prototype.init =  function (selector){  // Todo, does not create a node -> only select
        if( selector )
            this.dom = getDOMFromParameter(selector);
        else
            this.dom = getDOMFromParameter('body');
    };

    // Browse each dom
    domManipulator.prototype.each =  function (cb){
        for (var i = 0; i < this.dom.length; i++) {
            cb.apply(this.dom[i]);
        }
    };

    // Find nodes child nodes from the selector
    domManipulator.prototype.find = function(selector){
        var nodes = [];
        this.each(function findSelected(){
            var children = this.querySelectorAll(selector);
            for( var i = 0 ; i < children.length ; i++)
                nodes.push(children[i])
        });
        return lightDom(nodes);
    };

    // Return parent of the first node of the element
    domManipulator.prototype.parent = function(){
        return lightDom(this.dom[0].parentNode);
    };

    // Add classes passed as parameter
    domManipulator.prototype.addClass =  function (newClassName){
        this.each(function addClassToNode(){
            this.className = (this.className+" "+newClassName).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // Avoid spaces at beginning and end
        });
    };

    // Remove ONE class
    domManipulator.prototype.removeClass =  function (removeClassName){
        this.each(function removeClassOnNode(){
            var classes = " "+this.className+" ";
            if( classes.indexOf(removeClassName+" ") != -1  ) // Secure in order to avoid replacing class that would have similar names
                this.className =  classes.replace(removeClassName+" ", "" ).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
            if( classes.indexOf(" "+removeClassName) != -1  )
                 this.className =  classes.replace(" "+removeClassName, "" ).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        });
    };

    // Check if first dom has a class
    domManipulator.prototype.hasClass = function(selector){
        return (" " + this.dom[0].className + " ").replace(/[\t\r\n\f]/g, " ").indexOf(" " + selector + " ") >= 0;
    };

    // Return or set an attribute
    domManipulator.prototype.attr = function(name, value){
         if( value )
             this.each(function(){
                 this.setAttribute(name, value);
             });
         else
             return this.dom[0].getAttribute(name);
    };

    // Remove an attribute
    domManipulator.prototype.removeAttr = function(name){
        this.each(function removeAttributeFromNode(){
            this.removeAttribute(name);
        });
    };

    // add css properties || return the computed value of a css property
    domManipulator.prototype.css = function(css, val){
        if( typeof css == "string" && val )        // Single prop
            this.each(function setStye(){
                this.style[css] = val.toString();
            });
        else if( typeof css == "object" )    // prop dictionnary passed
            this.each(function setStyle(){
                for(var i in css )
                    this.style[i] = css[i].toString();
            });
        else if( typeof css == "string" && typeof val == "undefined") { // asking for a value, return the value of the first element
            return getComputedStyle(this.dom[0]).getPropertyValue(css)
        }
    };

    // bind event(s) on each node
    domManipulator.prototype.bind = function(eventsString, cb){
        var splited = eventsString.split(" ");
        this.each(function bindEvent(){
            for(var i = 0 ; i < splited.length ; i++ )
                this.addEventListener(splited[i], cb);
        });
    };

    // unbind event(s) on each node
    domManipulator.prototype.unbind = function(eventsString, cb){
        var splited = eventsString.split(" ");
        this.each(function unbindEvent(){
            for(var i = 0 ; i < splited.length ; i++ )
                this.removeEventListener(splited[i], cb);
        });
    };

    // append to THE FIRST DOM of this object
    // Accept multiple args
    domManipulator.prototype.append = function(stuffToAppend){
        for(var j=0; j < arguments.length ; j++) {
            var doms = getDOMFromParameter(arguments[j]);
            for (var i = 0; i < doms.length; i++)
                this.dom[0].appendChild(doms[i]);
        }
    };

    // prepend to THE FIRST DOM of this object
    // Accept multiple args
    domManipulator.prototype.prepend = function(stuffToPrepend){
        for(var j=0; j < arguments.length ; j++) {
            var doms = getDOMFromParameter(arguments[j]);
            for (var i = 0; i < doms.length; i++)
                this.dom[0].insertBefore(doms[i], null);
        }
    };

    // Replace html content + parse args to see if html
    domManipulator.prototype.html =  function(stuffToPut){
        this.dom[0].innerHTML = "";
        var doms = getDOMFromParameter(stuffToPut);
        for(var i=0; i < doms.length ; i++ )
            this.dom[0].appendChild(doms[i]);
    };

    // replace html content by a string
    domManipulator.prototype.text = function(textToPut){
        this.each(function fillTextIntoNode(){
            this.innerHTML = textToPut;
        });
    };

    // Return one NODE width or set all of the nodes WIDTH
    domManipulator.prototype.width = function(val){
        if( val )
            this.each(function setWith(){
                this.style.width = parseFloat(val).toString().length < val.toString().length ? val : val+"px";
            });
        else {
            var width = this.dom[0].clientWidth;

            function getWidthFromPecentage(el, val){
                var parentWidth = lightDom(el.parentNode).width();
                    return parentWidth != 0 ? parseFloat(el.style.width) / 100 * parentWidth : 0;
            }

            if( this.dom[0].clientWidth == 0)
                if(document.defaultView) {
                    if( this.dom[0].style.width.indexOf("%") != -1 )
                        width = getWidthFromPecentage(this.dom[0], document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("width"))
                    else
                        width = parseInt(document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("width"));
                }

                else if(this.dom[0].currentStyle) {
                    if( this.dom[0].currentStyle["width"].indexOf("%") != -1 )
                        width = getWidthFromPecentage(this.dom[0], this.dom[0].currentStyle["width"] );
                    else
                        width = parseInt(this.dom[0].currentStyle["width"]);
                }

           // console.log("Here with  =  "+width+" "+typeof width)
            return width;
        }
    };

    // return outerWidth: width + padding + border
    domManipulator.prototype.outerWidth = function(){
        return this.dom[0].offsetWidth;
    };

    // Return ONE node HEIGHT or set all of the NODES height
    domManipulator.prototype.height = function(val){
        if( val )
            this.each(function setHeight(){
                this.style.height =  parseFloat(val).toString().length < val.toString().length ? val : val+"px";
            });
        else
        {
            var height = this.dom[0].clientHeight;

            function getHeightFromPecentage(el, val){
                var parentHeight = lightDom(el.parentNode).height();
                if( parentHeight != 0 ){
                    return parseFloat(el.style.height) / 100 * parentHeight;
                }
                return 0;
            }

            if( this.dom[0].clientHeight == 0)
                if(document.defaultView) {
                    if( this.dom[0].style.height.indexOf("%") != -1 )
                        height = getHeightFromPecentage(this.dom[0], document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("height"));
                    else
                        height = parseInt(document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("height"));
                }

                else if(this.dom[0].currentStyle) {
                    if( this.dom[0].currentStyle["height"].indexOf("%") != -1 )
                        height = getHeightFromPecentage(this.dom[0], this.dom[0].currentStyle["height"] );
                    else
                        height = parseInt(this.dom[0].currentStyle["height"]);
                }

            return height;
        }
    };

    domManipulator.prototype.outerHeight = function(){
        return this.dom[0].offsetHeight;
    };

    // Return top / left position of an element: TODO: this ignore positioning using the css transform
    domManipulator.prototype.position = function(){
        var top = 0, left = 0,
            el = this.dom[0];

        while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
            left += el.offsetLeft - el.scrollLeft;
            top += el.offsetTop - el.scrollTop;
            el = el.offsetParent;
        }

        return{
            left:left,
            top: top
        }
    };
})(window,document);<commit_msg>Updated customLog fct<commit_after>/*
    Light weight jQuery like dom lib

    Global Object: lightDom
 */
 (function(window,document){
    // CustomEvent polyfill
    (function () {
        function CustomEvent ( event, params ) {
            params = params || { bubbles: false, cancelable: false, detail: undefined };
            var evt = document.createEvent( 'CustomEvent' );
            evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
            return evt;
        };
        CustomEvent.prototype = window.Event.prototype;
        window.CustomEvent = CustomEvent;
    })();

    // Only needed for the console css
    var is_chrome = typeof window.chrome == "undefined";
    // Display color if available
    function customLog(data, css){
        if( is_chrome )
            console.log('%c'+data, css || '');
        else
            console.log(data);
    }

    // Global object
    var lightDom = window["LD"] = window["lightDom"] = function(selector) {
        return new domManipulator(selector);
    };

    // Let extend the LightDom object
    lightDom.extend = function(extendingObjs){
        for( var i in  extendingObjs ){
            domManipulator.prototype[i] = extendingObjs[i];
        }
    };

    // Ajax request
    lightDom.ajax = function(params){
        var request = params.crossDomain ? createCORSRequest() : new XMLHttpRequest() ;

        request.open(params.type, params.url, params.async || true);

        var needJSONParsing = false;
        try {   // ResponseType is fairly new, so does not work everywhere
            request.responseType = params.dataType || "";
        }
        catch(e){
            customLog("Could not set responseType", 'color:red');
            needJSONParsing = (params.dataType || "") == "json";
        }

        request.onreadystatechange=function() {
            if( request ) {
                if (request.readyState == 4 && request.status == 200) {
                    params.success(  needJSONParsing || (params.dataType == "json" && typeof request.response != 'object') ? JSON.parse(request.response) : request.response);
                }
                else if (request.status >= 400 && request.readyState == 4) {
                    params.error(request, request.status, request.statusText);
                }
            }
        };

        request.timeout = params.timeout || null;
        request.onprogress = params.progress || null;
        request.onerror = request.ontimeout =  params.error || null;

        request.send();

        function createCORSRequest(){
            var xhr = new XMLHttpRequest();
            if ("withCredentials" in xhr){
            } else if (typeof XDomainRequest != "undefined"){
                xhr = new XDomainRequest();
            } else {
                xhr = null;
            }
            return xhr;
        }
    };

    // Figure out if we're on a touch device or not -> TODO: improve to fix problem with devices having both click & touch
    lightDom.isTouchDevice =  ('ontouchstart' in document.documentElement )

    // Selector / constuctor
    function domManipulator(selector){
        this.init(selector);
    }

    // pass a parameter than can be wether a String, a domManipulator or DOM node
    function getDOMFromParameter(selector){
        if( selector instanceof domManipulator)
            return selector.dom;

        // String == selector || HTML string
        if( typeof selector == "string") {
            var tmp = document.createElement("div");
            tmp.className = "mziDiv";
            tmp.innerHTML = selector;
            var findMe = tmp.querySelectorAll('.mziDiv > *');
            if( findMe.length == 0 )                                // If no child created by innerHTML -> We assume we're selecting in the document
                return document.querySelectorAll(selector);
            else                                                    // Else the string has created nodes, so we return this new object
                return findMe;
        }
        else
            if( selector.length )   // DOM nodes array passed in param TODO: find a better way to check: typeof Array does not work, and Object.prototype.toString.call(o) === '[object Array]' neither
                return selector;
             else
                 return [selector];  // Single dom node passed in param
    }

    // Init
    domManipulator.prototype.init =  function (selector){  // Todo, does not create a node -> only select
        if( selector )
            this.dom = getDOMFromParameter(selector);
        else
            this.dom = getDOMFromParameter('body');
    };

    // Browse each dom
    domManipulator.prototype.each =  function (cb){
        for (var i = 0; i < this.dom.length; i++) {
            cb.apply(this.dom[i]);
        }
    };

    // Find nodes child nodes from the selector
    domManipulator.prototype.find = function(selector){
        var nodes = [];
        this.each(function findSelected(){
            var children = this.querySelectorAll(selector);
            for( var i = 0 ; i < children.length ; i++)
                nodes.push(children[i])
        });
        return lightDom(nodes);
    };

    // Return parent of the first node of the element
    domManipulator.prototype.parent = function(){
        return lightDom(this.dom[0].parentNode);
    };

    // Add classes passed as parameter
    domManipulator.prototype.addClass =  function (newClassName){
        this.each(function addClassToNode(){
            this.className = (this.className+" "+newClassName).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // Avoid spaces at beginning and end
        });
    };

    // Remove ONE class
    domManipulator.prototype.removeClass =  function (removeClassName){
        this.each(function removeClassOnNode(){
            var classes = " "+this.className+" ";
            if( classes.indexOf(removeClassName+" ") != -1  ) // Secure in order to avoid replacing class that would have similar names
                this.className =  classes.replace(removeClassName+" ", "" ).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
            if( classes.indexOf(" "+removeClassName) != -1  )
                 this.className =  classes.replace(" "+removeClassName, "" ).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        });
    };

    // Check if first dom has a class
    domManipulator.prototype.hasClass = function(selector){
        return (" " + this.dom[0].className + " ").replace(/[\t\r\n\f]/g, " ").indexOf(" " + selector + " ") >= 0;
    };

    // Return or set an attribute
    domManipulator.prototype.attr = function(name, value){
         if( value )
             this.each(function(){
                 this.setAttribute(name, value);
             });
         else
             return this.dom[0].getAttribute(name);
    };

    // Remove an attribute
    domManipulator.prototype.removeAttr = function(name){
        this.each(function removeAttributeFromNode(){
            this.removeAttribute(name);
        });
    };

    // add css properties || return the computed value of a css property
    domManipulator.prototype.css = function(css, val){
        if( typeof css == "string" && val )        // Single prop
            this.each(function setStye(){
                this.style[css] = val.toString();
            });
        else if( typeof css == "object" )    // prop dictionnary passed
            this.each(function setStyle(){
                for(var i in css )
                    this.style[i] = css[i].toString();
            });
        else if( typeof css == "string" && typeof val == "undefined") { // asking for a value, return the value of the first element
            return getComputedStyle(this.dom[0]).getPropertyValue(css)
        }
    };

    // bind event(s) on each node
    domManipulator.prototype.bind = function(eventsString, cb){
        var splited = eventsString.split(" ");
        this.each(function bindEvent(){
            for(var i = 0 ; i < splited.length ; i++ )
                this.addEventListener(splited[i], cb);
        });
    };

    // unbind event(s) on each node
    domManipulator.prototype.unbind = function(eventsString, cb){
        var splited = eventsString.split(" ");
        this.each(function unbindEvent(){
            for(var i = 0 ; i < splited.length ; i++ )
                this.removeEventListener(splited[i], cb);
        });
    };

    // append to THE FIRST DOM of this object
    // Accept multiple args
    domManipulator.prototype.append = function(stuffToAppend){
        for(var j=0; j < arguments.length ; j++) {
            var doms = getDOMFromParameter(arguments[j]);
            for (var i = 0; i < doms.length; i++)
                this.dom[0].appendChild(doms[i]);
        }
    };

    // prepend to THE FIRST DOM of this object
    // Accept multiple args
    domManipulator.prototype.prepend = function(stuffToPrepend){
        for(var j=0; j < arguments.length ; j++) {
            var doms = getDOMFromParameter(arguments[j]);
            for (var i = 0; i < doms.length; i++)
                this.dom[0].insertBefore(doms[i], null);
        }
    };

    // Replace html content + parse args to see if html
    domManipulator.prototype.html =  function(stuffToPut){
        this.dom[0].innerHTML = "";
        var doms = getDOMFromParameter(stuffToPut);
        for(var i=0; i < doms.length ; i++ )
            this.dom[0].appendChild(doms[i]);
    };

    // replace html content by a string
    domManipulator.prototype.text = function(textToPut){
        this.each(function fillTextIntoNode(){
            this.innerHTML = textToPut;
        });
    };

    // Return one NODE width or set all of the nodes WIDTH
    domManipulator.prototype.width = function(val){
        if( val )
            this.each(function setWith(){
                this.style.width = parseFloat(val).toString().length < val.toString().length ? val : val+"px";
            });
        else {
            var width = this.dom[0].clientWidth;

            function getWidthFromPecentage(el, val){
                var parentWidth = lightDom(el.parentNode).width();
                    return parentWidth != 0 ? parseFloat(el.style.width) / 100 * parentWidth : 0;
            }

            if( this.dom[0].clientWidth == 0)
                if(document.defaultView) {
                    if( this.dom[0].style.width.indexOf("%") != -1 )
                        width = getWidthFromPecentage(this.dom[0], document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("width"))
                    else
                        width = parseInt(document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("width"));
                }

                else if(this.dom[0].currentStyle) {
                    if( this.dom[0].currentStyle["width"].indexOf("%") != -1 )
                        width = getWidthFromPecentage(this.dom[0], this.dom[0].currentStyle["width"] );
                    else
                        width = parseInt(this.dom[0].currentStyle["width"]);
                }

           // console.log("Here with  =  "+width+" "+typeof width)
            return width;
        }
    };

    // return outerWidth: width + padding + border
    domManipulator.prototype.outerWidth = function(){
        return this.dom[0].offsetWidth;
    };

    // Return ONE node HEIGHT or set all of the NODES height
    domManipulator.prototype.height = function(val){
        if( val )
            this.each(function setHeight(){
                this.style.height =  parseFloat(val).toString().length < val.toString().length ? val : val+"px";
            });
        else
        {
            var height = this.dom[0].clientHeight;

            function getHeightFromPecentage(el, val){
                var parentHeight = lightDom(el.parentNode).height();
                if( parentHeight != 0 ){
                    return parseFloat(el.style.height) / 100 * parentHeight;
                }
                return 0;
            }

            if( this.dom[0].clientHeight == 0)
                if(document.defaultView) {
                    if( this.dom[0].style.height.indexOf("%") != -1 )
                        height = getHeightFromPecentage(this.dom[0], document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("height"));
                    else
                        height = parseInt(document.defaultView.getComputedStyle(this.dom[0], "").getPropertyValue("height"));
                }

                else if(this.dom[0].currentStyle) {
                    if( this.dom[0].currentStyle["height"].indexOf("%") != -1 )
                        height = getHeightFromPecentage(this.dom[0], this.dom[0].currentStyle["height"] );
                    else
                        height = parseInt(this.dom[0].currentStyle["height"]);
                }

            return height;
        }
    };

    domManipulator.prototype.outerHeight = function(){
        return this.dom[0].offsetHeight;
    };

    // Return top / left position of an element: TODO: this ignore positioning using the css transform
    domManipulator.prototype.position = function(){
        var top = 0, left = 0,
            el = this.dom[0];

        while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
            left += el.offsetLeft - el.scrollLeft;
            top += el.offsetTop - el.scrollTop;
            el = el.offsetParent;
        }

        return{
            left:left,
            top: top
        }
    };
})(window,document);<|endoftext|>


<commit_before>/**
 * @author Mat Groves http://matgroves.com/
 */

/**
 * A tiling sprite is a fast way of rendering a tiling image
 *
 * @class TilingSprite
 * @extends Sprite
 * @constructor
 * @param texture {Texture} the texture of the tiling sprite
 * @param width {Number}  the width of the tiling sprite
 * @param height {Number} the height of the tiling sprite
 */
PIXI.TilingSprite = function(texture, width, height)
{
    PIXI.Sprite.call( this, texture);

    /**
     * The with of the tiling sprite
     *
     * @property width
     * @type Number
     */
    this._width = width || 100;

    /**
     * The height of the tiling sprite
     *
     * @property height
     * @type Number
     */
    this._height = height || 100;

    /**
     * The scaling of the image that is being tiled
     *
     * @property tileScale
     * @type Point
     */
    this.tileScale = new PIXI.Point(1,1);

    /**
     * A point that represents the scale of the texture object
     *
     * @property tileScaleOffset
     * @type Point
     */
    this.tileScaleOffset = new PIXI.Point(1,1);

    /**
     * The offset position of the image that is being tiled
     *
     * @property tilePosition
     * @type Point
     */
    this.tilePosition = new PIXI.Point(0,0);

    /**
     * Whether this sprite is renderable or not
     *
     * @property renderable
     * @type Boolean
     * @default true
     */
    this.renderable = true;

    /**
     * The tint applied to the sprite. This is a hex value
     *
     * @property tint
     * @type Number
     * @default 0xFFFFFF
     */
    this.tint = 0xFFFFFF;

    /**
     * The blend mode to be applied to the sprite
     *
     * @property blendMode
     * @type Number
     * @default PIXI.blendModes.NORMAL;
     */
    this.blendMode = PIXI.blendModes.NORMAL;

};

// constructor
PIXI.TilingSprite.prototype = Object.create(PIXI.Sprite.prototype);
PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite;

/**
 * The width of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property width
 * @type Number
 */
Object.defineProperty(PIXI.TilingSprite.prototype, 'width', {
    get: function() {
        return this._width;
    },
    set: function(value) {

        this._width = value;
    }
});

/**
 * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set
 *
 * @property height
 * @type Number
 */
Object.defineProperty(PIXI.TilingSprite.prototype, 'height', {
    get: function() {
        return  this._height;
    },
    set: function(value) {
        this._height = value;
    }
});

PIXI.TilingSprite.prototype.setTexture = function(texture)
{
    if (this.texture === texture) return;

    this.texture = texture;

    this.refreshTexture = true;

    this.cachedTint = 0xFFFFFF;
};

/**
* Renders the object using the WebGL renderer
*
* @method _renderWebGL
* @param renderSession {RenderSession}
* @private
*/
PIXI.TilingSprite.prototype._renderWebGL = function(renderSession)
{
    if (this.visible === false || this.alpha === 0) return;
    var i,j;

    if (this._mask)
    {
        renderSession.spriteBatch.stop();
        renderSession.maskManager.pushMask(this.mask, renderSession);
        renderSession.spriteBatch.start();
    }

    if (this._filters)
    {
        renderSession.spriteBatch.flush();
        renderSession.filterManager.pushFilter(this._filterBlock);
    }

    if (!this.tilingTexture || this.refreshTexture)
    {
        this.generateTilingTexture(true);

        if (this.tilingTexture && this.tilingTexture.needsUpdate)
        {
            //TODO - tweaking
            renderSession.renderer.updateTexture(this.tilingTexture.baseTexture);
            this.tilingTexture.needsUpdate = false;
           // this.tilingTexture._uvs = null;
        }
    }
    else
    {
        renderSession.spriteBatch.renderTilingSprite(this);
    }
    // simple render children!
    for (i=0,j=this.children.length; i<j; i++)
    {
        this.children[i]._renderWebGL(renderSession);
    }

    renderSession.spriteBatch.stop();

    if (this._filters) renderSession.filterManager.popFilter();
    if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);

    renderSession.spriteBatch.start();
};

/**
* Renders the object using the Canvas renderer
*
* @method _renderCanvas
* @param renderSession {RenderSession}
* @private
*/
PIXI.TilingSprite.prototype._renderCanvas = function(renderSession)
{
    if (this.visible === false || this.alpha === 0)return;

    var context = renderSession.context;

    if (this._mask)
    {
        renderSession.maskManager.pushMask(this._mask, context);
    }

    context.globalAlpha = this.worldAlpha;

    var transform = this.worldTransform;

    var i,j;

    var resolution = renderSession.resolution;

    context.setTransform(transform.a * resolution,
                         transform.b * resolution,
                         transform.c * resolution,
                         transform.d * resolution,
                         transform.tx * resolution,
                         transform.ty * resolution);

    if (!this.__tilePattern ||  this.refreshTexture)
    {
        this.generateTilingTexture(false);

        if (this.tilingTexture)
        {
            this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');
        }
        else
        {
            return;
        }
    }

    // check blend mode
    if (this.blendMode !== renderSession.currentBlendMode)
    {
        renderSession.currentBlendMode = this.blendMode;
        context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
    }

    var tilePosition = this.tilePosition;
    var tileScale = this.tileScale;

    tilePosition.x %= this.tilingTexture.baseTexture.width;
    tilePosition.y %= this.tilingTexture.baseTexture.height;

    // offset - make sure to account for the anchor point..
    context.scale(tileScale.x,tileScale.y);
    context.translate(tilePosition.x + (this.anchor.x * -this._width), tilePosition.y + (this.anchor.y * -this._height));

    context.fillStyle = this.__tilePattern;

    context.fillRect(-tilePosition.x,
                    -tilePosition.y,
                    this._width / tileScale.x,
                    this._height / tileScale.y);

    context.scale(1 / tileScale.x, 1 / tileScale.y);
    context.translate(-tilePosition.x + (this.anchor.x * this._width), -tilePosition.y + (this.anchor.y * this._height));

    if (this._mask)
    {
        renderSession.maskManager.popMask(renderSession.context);
    }

    for (i=0,j=this.children.length; i<j; i++)
    {
        this.children[i]._renderCanvas(renderSession);
    }
};

/**
* Returns the framing rectangle of the sprite as a PIXI.Rectangle object
*
* @method getBounds
* @return {Rectangle} the framing rectangle
*/
PIXI.TilingSprite.prototype.getBounds = function()
{
    var width = this._width;
    var height = this._height;

    var w0 = width * (1-this.anchor.x);
    var w1 = width * -this.anchor.x;

    var h0 = height * (1-this.anchor.y);
    var h1 = height * -this.anchor.y;

    var worldTransform = this.worldTransform;

    var a = worldTransform.a;
    var b = worldTransform.b;
    var c = worldTransform.c;
    var d = worldTransform.d;
    var tx = worldTransform.tx;
    var ty = worldTransform.ty;

    var x1 = a * w1 + c * h1 + tx;
    var y1 = d * h1 + b * w1 + ty;

    var x2 = a * w0 + c * h1 + tx;
    var y2 = d * h1 + b * w0 + ty;

    var x3 = a * w0 + c * h0 + tx;
    var y3 = d * h0 + b * w0 + ty;

    var x4 =  a * w1 + c * h0 + tx;
    var y4 =  d * h0 + b * w1 + ty;

    var maxX = -Infinity;
    var maxY = -Infinity;

    var minX = Infinity;
    var minY = Infinity;

    minX = x1 < minX ? x1 : minX;
    minX = x2 < minX ? x2 : minX;
    minX = x3 < minX ? x3 : minX;
    minX = x4 < minX ? x4 : minX;

    minY = y1 < minY ? y1 : minY;
    minY = y2 < minY ? y2 : minY;
    minY = y3 < minY ? y3 : minY;
    minY = y4 < minY ? y4 : minY;

    maxX = x1 > maxX ? x1 : maxX;
    maxX = x2 > maxX ? x2 : maxX;
    maxX = x3 > maxX ? x3 : maxX;
    maxX = x4 > maxX ? x4 : maxX;

    maxY = y1 > maxY ? y1 : maxY;
    maxY = y2 > maxY ? y2 : maxY;
    maxY = y3 > maxY ? y3 : maxY;
    maxY = y4 > maxY ? y4 : maxY;

    var bounds = this._bounds;

    bounds.x = minX;
    bounds.width = maxX - minX;

    bounds.y = minY;
    bounds.height = maxY - minY;

    // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
    this._currentBounds = bounds;

    return bounds;
};

/**
 * When the texture is updated, this event will fire to update the scale and frame
 *
 * @method onTextureUpdate
 * @param event
 * @private
 */
PIXI.TilingSprite.prototype.onTextureUpdate = function()
{
   // overriding the sprite version of this!
};

/**
*
* @method generateTilingTexture
*
* @param forcePowerOfTwo {Boolean} Whether we want to force the texture to be a power of two
*/
PIXI.TilingSprite.prototype.generateTilingTexture = function(forcePowerOfTwo)
{
    if (!this.texture.baseTexture.hasLoaded) return;

    var texture = this.originalTexture || this.texture;
    var frame = texture.frame;
    var targetWidth, targetHeight;

    //  Check that the frame is the same size as the base texture.
    var isFrame = frame.width !== texture.baseTexture.width || frame.height !== texture.baseTexture.height;

    var newTextureRequired = false;

    if (!forcePowerOfTwo)
    {
        if (isFrame)
        {
            targetWidth = frame.width;
            targetHeight = frame.height;

            newTextureRequired = true;
        }
    }
    else
    {
        targetWidth = PIXI.getNextPowerOfTwo(frame.width);
        targetHeight = PIXI.getNextPowerOfTwo(frame.height);

        //  If the BaseTexture dimensions don't match the texture frame then we need a new texture anyway because it's part of a texture atlas
        if (frame.width !== targetWidth || frame.height !== targetHeight || texture.baseTexture.width !== targetWidth || texture.baseTexture.height || targetHeight) newTextureRequired = true;
    }

    if (newTextureRequired)
    {
        var canvasBuffer;

        if (this.tilingTexture && this.tilingTexture.isTiling)
        {
            canvasBuffer = this.tilingTexture.canvasBuffer;
            canvasBuffer.resize(targetWidth, targetHeight);
            this.tilingTexture.baseTexture.width = targetWidth;
            this.tilingTexture.baseTexture.height = targetHeight;
            this.tilingTexture.needsUpdate = true;
        }
        else
        {
            canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight);

            this.tilingTexture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
            this.tilingTexture.canvasBuffer = canvasBuffer;
            this.tilingTexture.isTiling = true;
        }

        canvasBuffer.context.drawImage(texture.baseTexture.source,
                               texture.crop.x,
                               texture.crop.y,
                               texture.crop.width,
                               texture.crop.height,
                               0,
                               0,
                               targetWidth,
                               targetHeight);

        this.tileScaleOffset.x = frame.width / targetWidth;
        this.tileScaleOffset.y = frame.height / targetHeight;
    }
    else
    {
        //  TODO - switching?
        if (this.tilingTexture && this.tilingTexture.isTiling)
        {
            // destroy the tiling texture!
            // TODO could store this somewhere?
            this.tilingTexture.destroy(true);
        }

        this.tileScaleOffset.x = 1;
        this.tileScaleOffset.y = 1;
        this.tilingTexture = texture;
    }

    this.refreshTexture = false;

    this.originalTexture = this.texture;
    this.texture = this.tilingTexture;

    this.tilingTexture.baseTexture._powerOf2 = true;
};
<commit_msg>Fixed transform order in TilingSprite.<commit_after>/**
 * @author Mat Groves http://matgroves.com/
 */

/**
 * A tiling sprite is a fast way of rendering a tiling image
 *
 * @class TilingSprite
 * @extends Sprite
 * @constructor
 * @param texture {Texture} the texture of the tiling sprite
 * @param width {Number}  the width of the tiling sprite
 * @param height {Number} the height of the tiling sprite
 */
PIXI.TilingSprite = function(texture, width, height)
{
    PIXI.Sprite.call( this, texture);

    /**
     * The with of the tiling sprite
     *
     * @property width
     * @type Number
     */
    this._width = width || 100;

    /**
     * The height of the tiling sprite
     *
     * @property height
     * @type Number
     */
    this._height = height || 100;

    /**
     * The scaling of the image that is being tiled
     *
     * @property tileScale
     * @type Point
     */
    this.tileScale = new PIXI.Point(1,1);

    /**
     * A point that represents the scale of the texture object
     *
     * @property tileScaleOffset
     * @type Point
     */
    this.tileScaleOffset = new PIXI.Point(1,1);

    /**
     * The offset position of the image that is being tiled
     *
     * @property tilePosition
     * @type Point
     */
    this.tilePosition = new PIXI.Point(0,0);

    /**
     * Whether this sprite is renderable or not
     *
     * @property renderable
     * @type Boolean
     * @default true
     */
    this.renderable = true;

    /**
     * The tint applied to the sprite. This is a hex value
     *
     * @property tint
     * @type Number
     * @default 0xFFFFFF
     */
    this.tint = 0xFFFFFF;

    /**
     * The blend mode to be applied to the sprite
     *
     * @property blendMode
     * @type Number
     * @default PIXI.blendModes.NORMAL;
     */
    this.blendMode = PIXI.blendModes.NORMAL;

};

// constructor
PIXI.TilingSprite.prototype = Object.create(PIXI.Sprite.prototype);
PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite;

/**
 * The width of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property width
 * @type Number
 */
Object.defineProperty(PIXI.TilingSprite.prototype, 'width', {
    get: function() {
        return this._width;
    },
    set: function(value) {

        this._width = value;
    }
});

/**
 * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set
 *
 * @property height
 * @type Number
 */
Object.defineProperty(PIXI.TilingSprite.prototype, 'height', {
    get: function() {
        return  this._height;
    },
    set: function(value) {
        this._height = value;
    }
});

PIXI.TilingSprite.prototype.setTexture = function(texture)
{
    if (this.texture === texture) return;

    this.texture = texture;

    this.refreshTexture = true;

    this.cachedTint = 0xFFFFFF;
};

/**
* Renders the object using the WebGL renderer
*
* @method _renderWebGL
* @param renderSession {RenderSession}
* @private
*/
PIXI.TilingSprite.prototype._renderWebGL = function(renderSession)
{
    if (this.visible === false || this.alpha === 0) return;
    var i,j;

    if (this._mask)
    {
        renderSession.spriteBatch.stop();
        renderSession.maskManager.pushMask(this.mask, renderSession);
        renderSession.spriteBatch.start();
    }

    if (this._filters)
    {
        renderSession.spriteBatch.flush();
        renderSession.filterManager.pushFilter(this._filterBlock);
    }

    if (!this.tilingTexture || this.refreshTexture)
    {
        this.generateTilingTexture(true);

        if (this.tilingTexture && this.tilingTexture.needsUpdate)
        {
            //TODO - tweaking
            renderSession.renderer.updateTexture(this.tilingTexture.baseTexture);
            this.tilingTexture.needsUpdate = false;
           // this.tilingTexture._uvs = null;
        }
    }
    else
    {
        renderSession.spriteBatch.renderTilingSprite(this);
    }
    // simple render children!
    for (i=0,j=this.children.length; i<j; i++)
    {
        this.children[i]._renderWebGL(renderSession);
    }

    renderSession.spriteBatch.stop();

    if (this._filters) renderSession.filterManager.popFilter();
    if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);

    renderSession.spriteBatch.start();
};

/**
* Renders the object using the Canvas renderer
*
* @method _renderCanvas
* @param renderSession {RenderSession}
* @private
*/
PIXI.TilingSprite.prototype._renderCanvas = function(renderSession)
{
    if (this.visible === false || this.alpha === 0)return;

    var context = renderSession.context;

    if (this._mask)
    {
        renderSession.maskManager.pushMask(this._mask, context);
    }

    context.globalAlpha = this.worldAlpha;

    var transform = this.worldTransform;

    var i,j;

    var resolution = renderSession.resolution;

    context.setTransform(transform.a * resolution,
                         transform.b * resolution,
                         transform.c * resolution,
                         transform.d * resolution,
                         transform.tx * resolution,
                         transform.ty * resolution);

    if (!this.__tilePattern ||  this.refreshTexture)
    {
        this.generateTilingTexture(false);

        if (this.tilingTexture)
        {
            this.__tilePattern = context.createPattern(this.tilingTexture.baseTexture.source, 'repeat');
        }
        else
        {
            return;
        }
    }

    // check blend mode
    if (this.blendMode !== renderSession.currentBlendMode)
    {
        renderSession.currentBlendMode = this.blendMode;
        context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
    }

    var tilePosition = this.tilePosition;
    var tileScale = this.tileScale;

    tilePosition.x %= this.tilingTexture.baseTexture.width;
    tilePosition.y %= this.tilingTexture.baseTexture.height;

    // offset - make sure to account for the anchor point..
    context.scale(tileScale.x,tileScale.y);
    context.translate(tilePosition.x + (this.anchor.x * -this._width), tilePosition.y + (this.anchor.y * -this._height));

    context.fillStyle = this.__tilePattern;

    context.fillRect(-tilePosition.x,
                    -tilePosition.y,
                    this._width / tileScale.x,
                    this._height / tileScale.y);

    context.translate(-tilePosition.x + (this.anchor.x * this._width), -tilePosition.y + (this.anchor.y * this._height));
    context.scale(1 / tileScale.x, 1 / tileScale.y);

    if (this._mask)
    {
        renderSession.maskManager.popMask(renderSession.context);
    }

    for (i=0,j=this.children.length; i<j; i++)
    {
        this.children[i]._renderCanvas(renderSession);
    }
};

/**
* Returns the framing rectangle of the sprite as a PIXI.Rectangle object
*
* @method getBounds
* @return {Rectangle} the framing rectangle
*/
PIXI.TilingSprite.prototype.getBounds = function()
{
    var width = this._width;
    var height = this._height;

    var w0 = width * (1-this.anchor.x);
    var w1 = width * -this.anchor.x;

    var h0 = height * (1-this.anchor.y);
    var h1 = height * -this.anchor.y;

    var worldTransform = this.worldTransform;

    var a = worldTransform.a;
    var b = worldTransform.b;
    var c = worldTransform.c;
    var d = worldTransform.d;
    var tx = worldTransform.tx;
    var ty = worldTransform.ty;

    var x1 = a * w1 + c * h1 + tx;
    var y1 = d * h1 + b * w1 + ty;

    var x2 = a * w0 + c * h1 + tx;
    var y2 = d * h1 + b * w0 + ty;

    var x3 = a * w0 + c * h0 + tx;
    var y3 = d * h0 + b * w0 + ty;

    var x4 =  a * w1 + c * h0 + tx;
    var y4 =  d * h0 + b * w1 + ty;

    var maxX = -Infinity;
    var maxY = -Infinity;

    var minX = Infinity;
    var minY = Infinity;

    minX = x1 < minX ? x1 : minX;
    minX = x2 < minX ? x2 : minX;
    minX = x3 < minX ? x3 : minX;
    minX = x4 < minX ? x4 : minX;

    minY = y1 < minY ? y1 : minY;
    minY = y2 < minY ? y2 : minY;
    minY = y3 < minY ? y3 : minY;
    minY = y4 < minY ? y4 : minY;

    maxX = x1 > maxX ? x1 : maxX;
    maxX = x2 > maxX ? x2 : maxX;
    maxX = x3 > maxX ? x3 : maxX;
    maxX = x4 > maxX ? x4 : maxX;

    maxY = y1 > maxY ? y1 : maxY;
    maxY = y2 > maxY ? y2 : maxY;
    maxY = y3 > maxY ? y3 : maxY;
    maxY = y4 > maxY ? y4 : maxY;

    var bounds = this._bounds;

    bounds.x = minX;
    bounds.width = maxX - minX;

    bounds.y = minY;
    bounds.height = maxY - minY;

    // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
    this._currentBounds = bounds;

    return bounds;
};

/**
 * When the texture is updated, this event will fire to update the scale and frame
 *
 * @method onTextureUpdate
 * @param event
 * @private
 */
PIXI.TilingSprite.prototype.onTextureUpdate = function()
{
   // overriding the sprite version of this!
};

/**
*
* @method generateTilingTexture
*
* @param forcePowerOfTwo {Boolean} Whether we want to force the texture to be a power of two
*/
PIXI.TilingSprite.prototype.generateTilingTexture = function(forcePowerOfTwo)
{
    if (!this.texture.baseTexture.hasLoaded) return;

    var texture = this.originalTexture || this.texture;
    var frame = texture.frame;
    var targetWidth, targetHeight;

    //  Check that the frame is the same size as the base texture.
    var isFrame = frame.width !== texture.baseTexture.width || frame.height !== texture.baseTexture.height;

    var newTextureRequired = false;

    if (!forcePowerOfTwo)
    {
        if (isFrame)
        {
            targetWidth = frame.width;
            targetHeight = frame.height;

            newTextureRequired = true;
        }
    }
    else
    {
        targetWidth = PIXI.getNextPowerOfTwo(frame.width);
        targetHeight = PIXI.getNextPowerOfTwo(frame.height);

        //  If the BaseTexture dimensions don't match the texture frame then we need a new texture anyway because it's part of a texture atlas
        if (frame.width !== targetWidth || frame.height !== targetHeight || texture.baseTexture.width !== targetWidth || texture.baseTexture.height || targetHeight) newTextureRequired = true;
    }

    if (newTextureRequired)
    {
        var canvasBuffer;

        if (this.tilingTexture && this.tilingTexture.isTiling)
        {
            canvasBuffer = this.tilingTexture.canvasBuffer;
            canvasBuffer.resize(targetWidth, targetHeight);
            this.tilingTexture.baseTexture.width = targetWidth;
            this.tilingTexture.baseTexture.height = targetHeight;
            this.tilingTexture.needsUpdate = true;
        }
        else
        {
            canvasBuffer = new PIXI.CanvasBuffer(targetWidth, targetHeight);

            this.tilingTexture = PIXI.Texture.fromCanvas(canvasBuffer.canvas);
            this.tilingTexture.canvasBuffer = canvasBuffer;
            this.tilingTexture.isTiling = true;
        }

        canvasBuffer.context.drawImage(texture.baseTexture.source,
                               texture.crop.x,
                               texture.crop.y,
                               texture.crop.width,
                               texture.crop.height,
                               0,
                               0,
                               targetWidth,
                               targetHeight);

        this.tileScaleOffset.x = frame.width / targetWidth;
        this.tileScaleOffset.y = frame.height / targetHeight;
    }
    else
    {
        //  TODO - switching?
        if (this.tilingTexture && this.tilingTexture.isTiling)
        {
            // destroy the tiling texture!
            // TODO could store this somewhere?
            this.tilingTexture.destroy(true);
        }

        this.tileScaleOffset.x = 1;
        this.tileScaleOffset.y = 1;
        this.tilingTexture = texture;
    }

    this.refreshTexture = false;

    this.originalTexture = this.texture;
    this.texture = this.tilingTexture;

    this.tilingTexture.baseTexture._powerOf2 = true;
};
<|endoftext|>