<commit_before>'use strict';

function FloatingCursor(world) {
    this.__init__(world);
}

FloatingCursor.prototype = {

    __init__: function(world) {
        this.world                 = world;
        this._cursors              = {};
        this.currently_attached_to = null;

        this._current_cursor       = null;
        this._previous_cursor      = null;

        this._currently_engaged    = false;
    },

    wheel_event: function(delta) {
        switch (delta) {
        case 1:
            this._horizontal_distance_to_player *= 1.1;
            break;
        case -1:
            this._horizontal_distance_to_player *= 0.9;
            break;
        }
    },

    engage: function() {
        this._currently_engaged = true;

        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        this._previous_vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;

        // Save the initial position at the engage.
        this._previous_y = cursor_position.y;

        var pp = CURRENT_PLAYER.get_position();

        this._horizontal_distance_to_player = this.currently_attached_to.get_horizontal_distance_to_center(pp.x, pp.z);

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_invisible();
    },

    disengage: function() {
        this._currently_engaged = false;

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_visible();

        if (this._is_current_cursor_type(CURSOR_TYPE_VERTICAL)) {
            var plane_current_position = this.currently_attached_to.get_position();
            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());
            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);
            var h = this.currently_attached_to.height;

            var current_vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - current_position[1] ) / h;

            current_vertical_percentage *= -1;
            current_vertical_percentage /= 2;
            this.currently_attached_to.update_height(current_vertical_percentage);

            /*
            var height_change = this._previous_vertical_percentage - current_vertical_percentage;

            l(height_change);

            this.currently_attached_to.update_height(height_change);
            */
        }

    },

    attach: function(object_to_attach_to) {
        this.currently_attached_to = object_to_attach_to;

        if (this.currently_attached_to.type === TYPE_BUTTON || this.currently_attached_to.type === TYPE_CHECK_BOX) {
            this._set_current_cursor(CURSOR_TYPE_HAND);
        } else if (this.currently_attached_to.scalable) {
            this._get_scalable_cursor_needed();
        } else {
            this._set_current_cursor(CURSOR_TYPE_POINTER);
        }
    },

    detach: function() {
        this._current_cursor.set_to_invisible();

        this.currently_attached_to = null;
        this._previous_cursor      = null;
        this._current_cursor       = null;
    },

    update_position: function(p) {
        var normal = this.currently_attached_to.get_normal();

        this.cursor_wall.set_position(p.x, p.y, p.z, false);
        this.cursor_wall.set_normal(normal.x, normal.y, normal.z, false);
        this.cursor_wall.refresh_position_and_look_at();
    },

    update: function() {
        if (this._currently_engaged) {

            var plane_current_position = this.currently_attached_to.get_position();

            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());

            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);

            if (this._is_current_cursor_type(CURSOR_TYPE_MOUSE)) {
                var pp = CURRENT_PLAYER.get_position();
                var pn = CURRENT_PLAYER.get_direction();

                var new_x_position = pp.x + pn.x * this._horizontal_distance_to_player;
                var new_z_position = pp.z + pn.z * this._horizontal_distance_to_player;

                this.currently_attached_to.set_position(new_x_position, (current_position[1] - this._previous_y) + plane_current_position.y, new_z_position);
                this._previous_y = current_position[1];

                this.currently_attached_to.set_normal(-pn.x, 0, -pn.z);
                this.currently_attached_to.refresh_position_and_look_at();
            }

        } else {
            if (is_defined(this.currently_attached_to)) {
                if (this.currently_attached_to.scalable) {
                    this._get_scalable_cursor_needed();
                }
            }
        }
    },

    _get_scalable_cursor_needed: function() {
        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        var scroll_vertical   = false;
        var scroll_horizontal = false;

        if (vertical_percentage < 0.03 || vertical_percentage > 0.97) {
            scroll_vertical = true;
        }

        if (horizontal_percentage > .47) {
            scroll_horizontal = true;
        }

        if (scroll_horizontal && scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_LARGER);
        } else if (scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_VERTICAL);
        } else if (scroll_horizontal) {
            this._set_current_cursor(CURSOR_TYPE_HORIZONTAL);
        } else {
            this._set_current_cursor(CURSOR_TYPE_MOUSE);
        }
    },

    _set_current_cursor: function(cursor) {
        if (this._current_cursor !== this._cursors[cursor]) {
            this._previous_cursor = this._current_cursor;
            if (is_defined(this._previous_cursor)) {
                this._previous_cursor.set_to_invisible();
            }
            this._current_cursor = this._cursors[cursor];
            this._current_cursor.set_to_visible();
        }
    },

    _is_current_cursor_type: function(cursor_type) {
        return this._current_cursor.get_text() === cursor_type;
    },

    /*        ___                      __        __
     | |\ | |  |  |  /\  |       |    /  \  /\  |  \
     | | \| |  |  | /~~\ |___    |___ \__/ /~~\ |__/ */
    create: function() {
        this.cursor_wall = new FloatingWall(16, 16, null, null, this.world, false);
        this.cursor_wall.set_to_invisible();
        this._create_cursor(CURSOR_TYPE_HORIZONTAL);
        this._create_cursor(CURSOR_TYPE_VERTICAL);
        this._create_cursor(CURSOR_TYPE_HAND);
        this._create_cursor(CURSOR_TYPE_POINTER);
        this._create_cursor(CURSOR_TYPE_LARGER);
        this._create_cursor(CURSOR_TYPE_MOUSE);
    },

    _create_cursor: function(cursor_type) {
        var c = this.cursor_wall.add_row_2D_text([0, 1], 0, cursor_type, TYPE_ICON);
        c.set_attachment_depth_offset(1);
        c.set_attachment_horizontal_offset(8, 0);
        c.set_attachment_vertical_offset(-8, 0);
        c.set_to_invisible();

        // TODO : Transparency issues still exist.
        // Needed for fixing transparency issues. This has the cursor be rendered last.
        c.mesh.renderDepth = -1;

        this._cursors[cursor_type] = c;
    }

};<commit_msg>general updating 21<commit_after>'use strict';

function FloatingCursor(world) {
    this.__init__(world);
}

FloatingCursor.prototype = {

    __init__: function(world) {
        this.world                 = world;
        this._cursors              = {};
        this.currently_attached_to = null;

        this._current_cursor       = null;
        this._previous_cursor      = null;

        this._currently_engaged    = false;
    },

    wheel_event: function(delta) {
        switch (delta) {
        case 1:
            this._horizontal_distance_to_player *= 1.1;
            break;
        case -1:
            this._horizontal_distance_to_player *= 0.9;
            break;
        }
    },

    engage: function() {
        this._currently_engaged = true;

        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        this._previous_vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;

        // Save the initial position at the engage.
        this._previous_y = cursor_position.y;

        var pp = CURRENT_PLAYER.get_position();

        this._horizontal_distance_to_player = this.currently_attached_to.get_horizontal_distance_to_center(pp.x, pp.z);

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_invisible();
    },

    disengage: function() {
        this._currently_engaged = false;

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_visible();

        if (this._is_current_cursor_type(CURSOR_TYPE_VERTICAL)) {
            var plane_current_position = this.currently_attached_to.get_position();
            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());
            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);
            var h = this.currently_attached_to.height;

            var current_vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - current_position[1] ) / h;

            current_vertical_percentage *= -1;
            current_vertical_percentage /= 2;
            this.currently_attached_to.update_height(1 + current_vertical_percentage);

            /*
            var height_change = this._previous_vertical_percentage - current_vertical_percentage;

            l(height_change);

            this.currently_attached_to.update_height(height_change);
            */
        }

    },

    attach: function(object_to_attach_to) {
        this.currently_attached_to = object_to_attach_to;

        if (this.currently_attached_to.type === TYPE_BUTTON || this.currently_attached_to.type === TYPE_CHECK_BOX) {
            this._set_current_cursor(CURSOR_TYPE_HAND);
        } else if (this.currently_attached_to.scalable) {
            this._get_scalable_cursor_needed();
        } else {
            this._set_current_cursor(CURSOR_TYPE_POINTER);
        }
    },

    detach: function() {
        this._current_cursor.set_to_invisible();

        this.currently_attached_to = null;
        this._previous_cursor      = null;
        this._current_cursor       = null;
    },

    update_position: function(p) {
        var normal = this.currently_attached_to.get_normal();

        this.cursor_wall.set_position(p.x, p.y, p.z, false);
        this.cursor_wall.set_normal(normal.x, normal.y, normal.z, false);
        this.cursor_wall.refresh_position_and_look_at();
    },

    update: function() {
        if (this._currently_engaged) {

            var plane_current_position = this.currently_attached_to.get_position();

            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());

            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);

            if (this._is_current_cursor_type(CURSOR_TYPE_MOUSE)) {
                var pp = CURRENT_PLAYER.get_position();
                var pn = CURRENT_PLAYER.get_direction();

                var new_x_position = pp.x + pn.x * this._horizontal_distance_to_player;
                var new_z_position = pp.z + pn.z * this._horizontal_distance_to_player;

                this.currently_attached_to.set_position(new_x_position, (current_position[1] - this._previous_y) + plane_current_position.y, new_z_position);
                this._previous_y = current_position[1];

                this.currently_attached_to.set_normal(-pn.x, 0, -pn.z);
                this.currently_attached_to.refresh_position_and_look_at();
            }

        } else {
            if (is_defined(this.currently_attached_to)) {
                if (this.currently_attached_to.scalable) {
                    this._get_scalable_cursor_needed();
                }
            }
        }
    },

    _get_scalable_cursor_needed: function() {
        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        var scroll_vertical   = false;
        var scroll_horizontal = false;

        if (vertical_percentage < 0.03 || vertical_percentage > 0.97) {
            scroll_vertical = true;
        }

        if (horizontal_percentage > .47) {
            scroll_horizontal = true;
        }

        if (scroll_horizontal && scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_LARGER);
        } else if (scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_VERTICAL);
        } else if (scroll_horizontal) {
            this._set_current_cursor(CURSOR_TYPE_HORIZONTAL);
        } else {
            this._set_current_cursor(CURSOR_TYPE_MOUSE);
        }
    },

    _set_current_cursor: function(cursor) {
        if (this._current_cursor !== this._cursors[cursor]) {
            this._previous_cursor = this._current_cursor;
            if (is_defined(this._previous_cursor)) {
                this._previous_cursor.set_to_invisible();
            }
            this._current_cursor = this._cursors[cursor];
            this._current_cursor.set_to_visible();
        }
    },

    _is_current_cursor_type: function(cursor_type) {
        return this._current_cursor.get_text() === cursor_type;
    },

    /*        ___                      __        __
     | |\ | |  |  |  /\  |       |    /  \  /\  |  \
     | | \| |  |  | /~~\ |___    |___ \__/ /~~\ |__/ */
    create: function() {
        this.cursor_wall = new FloatingWall(16, 16, null, null, this.world, false);
        this.cursor_wall.set_to_invisible();
        this._create_cursor(CURSOR_TYPE_HORIZONTAL);
        this._create_cursor(CURSOR_TYPE_VERTICAL);
        this._create_cursor(CURSOR_TYPE_HAND);
        this._create_cursor(CURSOR_TYPE_POINTER);
        this._create_cursor(CURSOR_TYPE_LARGER);
        this._create_cursor(CURSOR_TYPE_MOUSE);
    },

    _create_cursor: function(cursor_type) {
        var c = this.cursor_wall.add_row_2D_text([0, 1], 0, cursor_type, TYPE_ICON);
        c.set_attachment_depth_offset(1);
        c.set_attachment_horizontal_offset(8, 0);
        c.set_attachment_vertical_offset(-8, 0);
        c.set_to_invisible();

        // TODO : Transparency issues still exist.
        // Needed for fixing transparency issues. This has the cursor be rendered last.
        c.mesh.renderDepth = -1;

        this._cursors[cursor_type] = c;
    }

};<|endoftext|>


<commit_before>'use strict';

function FloatingCursor(world) {
    this.__init__(world);
}

FloatingCursor.prototype = {

    __init__: function(world) {
        this.world                 = world;
        this._cursors              = {};
        this.currently_attached_to = null;

        this._current_cursor       = null;
        this._previous_cursor      = null;

        this._currently_engaged    = false;
    },

    wheel_event: function(delta) {
        l('WHEEL EVENT!!');
        l(delta);
        /*
                if (delta === 1) {
            this.player_horizontal_distance_to_wall_center_liner *= 1.1;
        } else if (delta == -1) {
            this.player_horizontal_distance_to_wall_center_liner *= .9;
        }
        */
    },

    engage: function() {
        this._currently_engaged = true;

        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        this._engaged_vertical_percentage = vertical_percentage;

        // Save the initial position at the engage.
        this._previous_position = this.cursor_wall.get_position();

        this._horizontal_distance_to_player = this.currently_attached_to.get_horizontal_distance_to_center(this._previous_position.x, this._previous_position.z);

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_invisible();
    },

    disengage: function() {
        this._currently_engaged = false;

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_visible();
    },

    attach: function(object_to_attach_to) {
        this.currently_attached_to = object_to_attach_to;

        if (this.currently_attached_to.type === TYPE_BUTTON || this.currently_attached_to.type === TYPE_CHECK_BOX) {
            this._set_current_cursor(CURSOR_TYPE_HAND);
        } else if (this.currently_attached_to.scalable) {
            this._get_scalable_cursor_needed();
        } else {
            this._set_current_cursor(CURSOR_TYPE_POINTER);
        }
    },

    detach: function() {
        this._current_cursor.set_to_invisible();

        this.currently_attached_to = null;
        this._previous_cursor      = null;
        this._current_cursor       = null;
    },

    update_position: function(p) {
        var normal = this.currently_attached_to.get_normal();

        this.cursor_wall.set_position(p.x, p.y, p.z, false);
        this.cursor_wall.set_normal(normal.x, normal.y, normal.z, false);
        this.cursor_wall.refresh_position_and_look_at();
    },

    // TODO : update
    update: function() {
        if (this._currently_engaged) {

            //l('TODO : Currently engaged cursor function!');

            var plane_current_position = this.currently_attached_to.get_position();

            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());

            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);

            //l('OFFSET IS :');
            //l(current_position[0] - this._previous_position.x);
            l(current_position[1] - this._previous_position.y);
            //l(current_position[2] - this._previous_position.z);

            this.currently_attached_to.set_position(plane_current_position.x, (current_position[1] - this._previous_position.y) + plane_current_position.y, plane_current_position.z);

            this._previous_position = new THREE.Vector3(this._previous_position.x, current_position[1], this._previous_position.z);

            //this._previous_position = this.cursor_wall.get_position();

        } else {
            if (is_defined(this.currently_attached_to)) {
                if (this.currently_attached_to.scalable) {
                    this._get_scalable_cursor_needed();
                }
            }
        }
    },

    // TODO : Remove
    update_OLD: function() {
        if (this.cursor_needed_from_floating_walls || this.cursor_needed_from_interactive_objects) {
            this.current_cursor.visible = true;
            this.cursor_needed_from_floating_walls = false;
            this.cursor_needed_from_interactive_objects = false;
        } else {
            if (!this.engaged) {
                this.current_cursor.visible = false;
            }
        }

        if (this.engaged) {
            if (is_defined(this.current_floating_wall)) {
                this.current_floating_wall.perform_action(this.current_cursor.userData.name);
            }
        }

        // TODO : Update the late positions here.
    },

    _get_scalable_cursor_needed: function() {
        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        var scroll_vertical   = false;
        var scroll_horizontal = false;

        //l(vertical_percentage);
        //l(horizontal_percentage);

        if (vertical_percentage < 0.03 || vertical_percentage > 0.97) {
            scroll_vertical = true;
        }

        if (horizontal_percentage > .47) {
            scroll_horizontal = true;
        }

        if (scroll_horizontal && scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_LARGER);
        } else if (scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_VERTICAL);
        } else if (scroll_horizontal) {
            this._set_current_cursor(CURSOR_TYPE_HORIZONTAL);
        } else {
            this._set_current_cursor(CURSOR_TYPE_MOUSE);
        }
    },

    _set_current_cursor: function(cursor) {
        if (this._current_cursor !== this._cursors[cursor]) {
            this._previous_cursor = this._current_cursor;
            if (is_defined(this._previous_cursor)) {
                this._previous_cursor.set_to_invisible();
            }
            this._current_cursor = this._cursors[cursor];
            this._current_cursor.set_to_visible();
        }
    },

    /*        ___                      __        __
     | |\ | |  |  |  /\  |       |    /  \  /\  |  \
     | | \| |  |  | /~~\ |___    |___ \__/ /~~\ |__/ */
    create: function() {
        this.cursor_wall = new FloatingWall(16, 16, null, null, this.world, false);
        this.cursor_wall.set_to_invisible();
        this._create_cursor(CURSOR_TYPE_HORIZONTAL);
        this._create_cursor(CURSOR_TYPE_VERTICAL);
        this._create_cursor(CURSOR_TYPE_HAND);
        this._create_cursor(CURSOR_TYPE_POINTER);
        this._create_cursor(CURSOR_TYPE_LARGER);
        this._create_cursor(CURSOR_TYPE_MOUSE);
    },

    _create_cursor: function(cursor_type) {
        var c = this.cursor_wall.add_row_2D_text([0, 1], 0, cursor_type, TYPE_ICON);
        c.set_attachment_depth_offset(1);
        c.set_attachment_horizontal_offset(8, 0);
        c.set_attachment_vertical_offset(-8, 0);
        c.set_to_invisible();

        // TODO : Transparency issues still exist.
        // Needed for fixing transparency issues. This has the cursor be rendered last.
        c.mesh.renderDepth = -1;

        this._cursors[cursor_type] = c;
    }

};<commit_msg>general updating 09<commit_after>'use strict';

// TEMPORARY VARIABLES
const ENGAGE_ACTION_MOVE = 1;
const ENGAGE_ACTION_SCALE_HEIGHT = 2;
const ENGAGE_ACTION_SCALE_WIDTH = 3;
const ENGAGE_ACTION_SCALE_BOTH = 4;

function FloatingCursor(world) {
    this.__init__(world);
}

FloatingCursor.prototype = {

    __init__: function(world) {
        this.world                 = world;
        this._cursors              = {};
        this.currently_attached_to = null;

        this._current_cursor       = null;
        this._previous_cursor      = null;

        this._currently_engaged    = false;
    },

    wheel_event: function(delta) {
        switch (delta) {
        case 1:
            this._horizontal_distance_to_player *= 1.1;
            break;
        case -1:
            this._horizontal_distance_to_player *= 0.9;
            break;
        }
    },

    engage: function() {
        this._engage_action = null;
        if (this._current_cursor === this._cursors[CURSOR_TYPE_HAND]) {
            this._engage_action = ENGAGE_ACTION_MOVE;
        } else if (this._current_cursor === this._cursors[CURSOR_TYPE_VERTICAL]) {
            this._engage_action = ENGAGE_ACTION_SCALE_HEIGHT;
        } else if (this._current_cursor === this._cursors[CURSOR_TYPE_HORIZONTAL]) {
            this._engage_action = ENGAGE_ACTION_SCALE_WIDTH;
        } else if (this._current_cursor === this._cursors[CURSOR_TYPE_LARGER]) {
            this._engage_action = ENGAGE_ACTION_SCALE_BOTH;
        }

        this._currently_engaged = true;

        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        this._engaged_vertical_percentage = vertical_percentage;

        // Save the initial position at the engage.
        this._previous_position = this.cursor_wall.get_position();
        this._previous_y = cursor_position.y;

        this._horizontal_distance_to_player = this.currently_attached_to.get_horizontal_distance_to_center(this._previous_position.x, this._previous_position.z);

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_invisible();
    },

    disengage: function() {
        this._currently_engaged = false;

        // TODO : TEMPORARY MEASURE.
        this._current_cursor.set_to_visible();
    },

    attach: function(object_to_attach_to) {
        this.currently_attached_to = object_to_attach_to;

        if (this.currently_attached_to.type === TYPE_BUTTON || this.currently_attached_to.type === TYPE_CHECK_BOX) {
            this._set_current_cursor(CURSOR_TYPE_HAND);
        } else if (this.currently_attached_to.scalable) {
            this._get_scalable_cursor_needed();
        } else {
            this._set_current_cursor(CURSOR_TYPE_POINTER);
        }
    },

    detach: function() {
        this._current_cursor.set_to_invisible();

        this.currently_attached_to = null;
        this._previous_cursor      = null;
        this._current_cursor       = null;
    },

    update_position: function(p) {
        var normal = this.currently_attached_to.get_normal();

        this.cursor_wall.set_position(p.x, p.y, p.z, false);
        this.cursor_wall.set_normal(normal.x, normal.y, normal.z, false);
        this.cursor_wall.refresh_position_and_look_at();
    },

    // TODO : update
    update: function() {
        if (this._currently_engaged) {

            //l('TODO : Currently engaged cursor function!');

            var plane_current_position = this.currently_attached_to.get_position();

            var player_parametric_equation = get_parametric_line_equation(CURRENT_PLAYER.get_position(), CURRENT_PLAYER.get_direction());
            var plane_parametric_equation = get_parametric_plane_equation(plane_current_position, this.currently_attached_to.get_normal());

            var current_position = get_line_intersection_on_infinite_plane(player_parametric_equation, plane_parametric_equation);

            //l('OFFSET IS :');

            //l(current_position[0] - this._previous_position.x);
            l(current_position[1] - this._previous_position.y);
            //l(current_position[2] - this._previous_position.z);

            if (this._engage_action === ENGAGE_ACTION_MOVE) {

                var pp = CURRENT_PLAYER.get_position();
                var pn = CURRENT_PLAYER.get_direction();

                var new_x_position = pp.x + pn.x * this._horizontal_distance_to_player;
                var new_z_position = pp.z + pn.z * this._horizontal_distance_to_player;

                this.currently_attached_to.set_position(new_x_position, (current_position[1] - this._previous_y) + plane_current_position.y, new_z_position);
                this._previous_y = current_position[1];
                //this._previous_position = new THREE.Vector3(this._previous_position.x, current_position[1], this._previous_position.z);
            }

            //this._previous_position = this.cursor_wall.get_position();

        } else {
            if (is_defined(this.currently_attached_to)) {
                if (this.currently_attached_to.scalable) {
                    this._get_scalable_cursor_needed();
                }
            }
        }
    },

    _get_scalable_cursor_needed: function() {
        var h = this.currently_attached_to.height;
        var w = this.currently_attached_to.width;

        var cursor_position = this.cursor_wall.get_position();

        var vertical_percentage = ((this.currently_attached_to.object3D.position.y + h / 2) - cursor_position.y ) / h;
        var horizontal_percentage = this.currently_attached_to.get_horizontal_distance_to_center(cursor_position.x, cursor_position.z) / w;

        var scroll_vertical   = false;
        var scroll_horizontal = false;

        if (vertical_percentage < 0.03 || vertical_percentage > 0.97) {
            scroll_vertical = true;
        }

        if (horizontal_percentage > .47) {
            scroll_horizontal = true;
        }

        if (scroll_horizontal && scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_LARGER);
        } else if (scroll_vertical) {
            this._set_current_cursor(CURSOR_TYPE_VERTICAL);
        } else if (scroll_horizontal) {
            this._set_current_cursor(CURSOR_TYPE_HORIZONTAL);
        } else {
            this._set_current_cursor(CURSOR_TYPE_MOUSE);
        }
    },

    _set_current_cursor: function(cursor) {
        if (this._current_cursor !== this._cursors[cursor]) {
            this._previous_cursor = this._current_cursor;
            if (is_defined(this._previous_cursor)) {
                this._previous_cursor.set_to_invisible();
            }
            this._current_cursor = this._cursors[cursor];
            this._current_cursor.set_to_visible();
        }
    },

    /*        ___                      __        __
     | |\ | |  |  |  /\  |       |    /  \  /\  |  \
     | | \| |  |  | /~~\ |___    |___ \__/ /~~\ |__/ */
    create: function() {
        this.cursor_wall = new FloatingWall(16, 16, null, null, this.world, false);
        this.cursor_wall.set_to_invisible();
        this._create_cursor(CURSOR_TYPE_HORIZONTAL);
        this._create_cursor(CURSOR_TYPE_VERTICAL);
        this._create_cursor(CURSOR_TYPE_HAND);
        this._create_cursor(CURSOR_TYPE_POINTER);
        this._create_cursor(CURSOR_TYPE_LARGER);
        this._create_cursor(CURSOR_TYPE_MOUSE);
    },

    _create_cursor: function(cursor_type) {
        var c = this.cursor_wall.add_row_2D_text([0, 1], 0, cursor_type, TYPE_ICON);
        c.set_attachment_depth_offset(1);
        c.set_attachment_horizontal_offset(8, 0);
        c.set_attachment_vertical_offset(-8, 0);
        c.set_to_invisible();

        // TODO : Transparency issues still exist.
        // Needed for fixing transparency issues. This has the cursor be rendered last.
        c.mesh.renderDepth = -1;

        this._cursors[cursor_type] = c;
    }

};<|endoftext|>


<commit_before>/* simple postMessage - v0.3.0
 * by Leonardo Dutra (https://github.com/LeoDutra/simple-postmessage)
 * Dual licensed under the MIT and GPL licenses.
 *
 * based on
 *
 * ender postMessage - v0.1.3 - 5/1/2012
 * by Thomas Sturm http://www.sturm.to
 * Dual licensed under the MIT and GPL licenses.
 *
 * based on
 *
 * jQuery postMessage - v0.5 - 9/11/2009
 * http://benalman.com/projects/jquery-postmessage-plugin/
 * Copyright (c) 2009 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Release History
//   visit https://github.com/LeoDutra/simple-postmessage/releases
//
// Fork history
//   ender postMessage
//   0.1.3 - (5/1/2012) compatible with browserify
//   0.1.2 - (5/26/2011) Initial Fork and Release
//
//   jQuery postMessage
//   0.5 - (9/11/2009) Improved cache-busting
//   0.4 - (8/25/2009) Initial release

(function(window) {
    "use strict";

    var queueInterval = 0,
        receiveInterval = 0,
        hashQueue = [],
        last_hash,
        original_hash,
        receiveCallback,
        cache_bust = 0,
        INTERNAL_HASH_DELAY = 100,
        INTERNAL_QUEUE_DELAY = INTERNAL_HASH_DELAY + 20, // FIXME: using "+ms" against collisions / bad CPU times
        FALSE = !1, // BETTER MINIFICATION
        POST_MESSAGE = "postMessage",
        ADD_EVENT_LISTENER = "addEventListener",
        HAS_POSTMESSAGE = window[POST_MESSAGE],
        JSON = window.JSON;

        // ie 10- version detection. Useful to fix IE9 and IE8 problem when passing objects as message
        //   http://stackoverflow.com/a/15983064/1260526
        var IE_FIX = parseInt(navigator.userAgent.toLowerCase().split("msie")[1], 10) < 10;

    function serialize(any) {
        return JSON ? JSON.stringify(any) : any;
    }

    function deserialize(any) {
        return JSON ? JSON.parse(any) : any;
    }

    function locationOrigin(location) {
        return location.origin || location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
    }

    function locationWithoutHash(location) {
        return location.href.replace(location.hash, '');
    }

    function sendHash(target, hash) {
        target.location = hash;
    }

    function queueToSend(target, hash) {
        if (queueInterval) {
            hashQueue.push({target: target, hash: hash}); // queue our baby
        }
        else {
            sendHash(target, hash); // first is always sent and starts queue verification

            if (!queueInterval) queueInterval = setInterval(function() {
                if (hashQueue.length) {
                    var current = hashQueue.shift();
                    try {
                        // FIXME: try/catch reason: maybe target window was closed! Better be safe
                        sendHash(current.target, current.hash);
                    }
                    catch(current) {}
                }
                else if (queueInterval) { // SHALL require this additional cycle before clear
                    clearInterval(queueInterval);
                    hashQueue = [];
                    queueInterval = 0;
                }
            }, INTERNAL_QUEUE_DELAY);
        }
    }

    function copyProperties(obj, destination) {
        // the damn Message Event is immutable... so we copy it for set deserialization to data
        destination = destination || {};
        for (var prop in obj) {
            if (typeof prop !== "function") { // hasOwnProperty = no property :(
                destination[prop] = obj[prop];
            }
        }
        return destination;
    }

    function verifyOrigin(source_origin, messageEvent_origin) {
        return !source_origin || source_origin === '*' || // listens to all
            /*STRING*/  messageEvent_origin === source_origin ||
            /*FUNCTION*/typeof source_origin === "function" && source_origin(messageEvent_origin) ||
            /*ARRAY*/   Object.prototype.toString.call(source_origin) === '[object Array]'
                            && ~source_origin.indexOf(messageEvent_origin);
    }

    // Method: window.postMessage
    //
    // This method will call native window.postMessage if available, setting the
    // targetOrigin parameter to the base of the target_url parameter for maximum
    // security in browsers that support it. If window.postMessage is not available,
    // the target window's location.hash will be used to pass the message, and an internal queue
    // will handle message multiplicity.
    //
    // Please Note: This version does not support the jQuery object serialization
    // for postMessage
    //
    // Usage:
    //
    // > window.postMessage( message, target_url [, target ] );
    //
    // Arguments:
    //
    //  message - (String) A message to be passed to the other frame.
    //  target_url - (String) The URL of the other frame this window is
    //    attempting to communicate with. This must be the exact URL (including
    //    any query string) of the other window for this script to work in
    //    browsers that don't support window.postMessage.
    //  target - (Object) A reference to the other frame this window is
    //    attempting to communicate with. If omitted, defaults to `opener`, then `parent`
    //    and then `window`
    //
    // Returns:
    //    (Nothing)
    //
    // Throws:
    //    Error - when no target_url (nor "*") is defined
    //
    window.simplePostMessage = function(message, target_url, target) {

        if (!target_url) throw 'simplePostMessage:: at least a "*" (any target) is expected for "target_url" argument.';

        // opener is not null when this came from window.open(), parent is not null when this is inside of an iframe
        target = target || opener || parent || window;

        // The browser supports window.postMessage, so call it with a targetOrigin
        // set appropriately, based on the target_url parameter.
        if (HAS_POSTMESSAGE) { // USE NATIVE POST MESSAGE -------------

            if (IE_FIX) {
                // IE9- can't pass objects as message. Serialize using JSON.stringify (need Crockford's json2.js for IE8Compat, IE7 & IE6)
                message = serialize(message);
            }
            // only "schema://host:port" is needed
            // defaults to "*" (any), which is bad for security but is an option of the spec
            target[POST_MESSAGE](message, target_url === '*' ? target_url : target_url.replace(/([^:]+:\/\/[^\/]+).*/, "$1"));
        }
        else { // USE HASH ALTERNATIVE POST MESSAGE -------------
            // The browser does not support window.postMessage, so set the location
            // of the target to target_url#message. A bit ugly, but it works! A cache
            // bust parameter is added to ensure that repeat messages trigger the
            // callback.

            // target_url === '*', get the location of the target without hash (prevent bugs)
            target_url = target_url === '*' ? locationWithoutHash(target.location) : target_url.replace(/#.*$/, "");

            message = { // Fake MessageEvent
                type: 'message',
                timeStamp: +new Date,
                data: message,
                origin: locationOrigin(location)
            };

            // encodeURIComponent avoids problem with invalid URL chars
            queueToSend(target, target_url + "#--HASH--" + (+new Date) + (++cache_bust) + "&" + encodeURIComponent(serialize(message)))
        }
    };

    // Method: window.receiveMessage
    //
    // Register a single callback for either a window.postMessage call, if
    // supported, or if unsupported, for any change in the current window
    // location.hash. If window.postMessage is supported and source_origin is
    // specified, the source window will be checked against this for maximum
    // security. If window.postMessage is unsupported, a polling loop will be
    // started to watch for changes to the location.hash.
    //
    // Note that for simplicity's sake, only a single callback can be registered
    // at one time. Passing no params will unbind this event (or stop the polling
    // loop), and calling this method a second time with another callback will
    // unbind the event (or stop the polling loop) first, before binding the new
    // callback.
    //
    // Also note that if window.postMessage is available, the optional
    // source_origin param will be used to test the event.origin property. From
    // the MDC window.postMessage docs: This string is the concatenation of the
    // protocol and "://", the host name if one exists, and ":" followed by a port
    // number if a port is present and differs from the default port for the given
    // protocol. Examples of typical origins are https://example.org (implying
    // port 443), http://example.net (implying port 80), and http://example.com:8080.
    //
    // Usage:
    //
    // > window.receiveMessage( callback [, source_origin ] [, hashModeDelay ] );
    //
    // Arguments:
    //
    //  callback - (Function) This callback will execute whenever a <window.postMessage>
    //    message is received, provided the source_origin matches. If callback is
    //    omitted, any existing receiveMessage event bind or polling loop will be
    //    canceled.
    //  source_origin - if source_origin is not defined, or is "*", the callback IS ALWAYS called
    //  source_origin - (String) If window.postMessage is available and this value
    //    is not equal to the event.origin property, the callback WILL NOT be
    //    called.
    //  source_origin - (Function) If window.postMessage is available and this
    //    function returns false when passed the event.origin property, the
    //    callback WILL NOT be called.
    //  source_origin - (Array) If window.postMessage is available and this
    //    array does not contain the event.origin property value, the
    //    callback WILL NOT be called.
    //  hashModeDelay - (Number) An optional zero-or-greater delay in milliseconds at
    //    which the polling loop will execute (for browser that don't support
    //    window.postMessage). If omitted, defaults to 100.
    //
    // Returns:
    //   (Nothing)
    //
    window.simpleReceiveMessage = function(callback, source_origin/*="*"*/) {

        if (HAS_POSTMESSAGE) {  // USE NATIVE RECEIVER -------------
            // Since the browser supports window.postMessage, the callback will be
            // bound to the actual event associated with window.postMessage.

            if (callback) {
                // Unbind an existing callback if it exists (yes, recursive call without args)
                if (receiveCallback) window.simpleReceiveMessage();

                // Bind the callback. A reference to the callback is stored for ease of unbinding.
                receiveCallback = function(messageEvent) {
                    if (verifyOrigin(source_origin, messageEvent.origin)) {

                        if (IE_FIX) {
                            messageEvent = copyProperties(messageEvent); // the damn Message Event is immutable... so we copy it, deserialize data and set in the copied object

                            // IE9- can't pass objects as message. Deserialize  using JSON.parse (need Crockford's json2.js for IE8Compat, IE7 & IE6)
                            messageEvent.data = deserialize(messageEvent.data);
                        }

                        callback(messageEvent);
                    }
                };
            }

            if (window[ADD_EVENT_LISTENER]) { // good browser / horrible browser ?
                window[callback ? ADD_EVENT_LISTENER : "removeEventListener"]("message", receiveCallback, FALSE);
            } else {
                window[callback ? "attachEvent" : "detachEvent"]("onmessage", receiveCallback);
            }

        }
        else { // USE ARTIFICIAL RECEIVER FOR HASH ALTERNATIVE -------------
            // Since the browser sucks, a polling loop will be started, and the
            // callback will be called whenever the location.hash changes.

            if (receiveInterval) {
                receiveInterval = clearInterval(receiveInterval);
            }
            if (callback) {
                original_hash = document.location.hash;
                receiveInterval = setInterval(function() {
                    var hash = document.location.hash;
                    var re = /^#?--HASH--\d+&/;
                    if (hash !== last_hash && hash !== original_hash && re.test(hash)) {
                        last_hash = hash;
                        document.location.hash = original_hash ? original_hash : '';

                        // replace(/\+/gim, ' ') fixes a Mozilla bug
                        //   http://stackoverflow.com/questions/75980/best-practice-escape-or-encodeuri-encodeuricomponent/12796866#comment30658935_12796866
                        var messageEvent = deserialize(decodeURIComponent(hash.replace(re, "").replace(/\+/gim, " ")));
                        if (verifyOrigin(source_origin, messageEvent.origin)) {
                            callback(messageEvent);
                        }
                    }
                }, INTERNAL_HASH_DELAY);
            }
        }
    };
})(window);
<commit_msg>hash cache_bust can't reach Infinity anymore<commit_after>/* simple postMessage - v0.3.0
 * by Leonardo Dutra (https://github.com/LeoDutra/simple-postmessage)
 * Dual licensed under the MIT and GPL licenses.
 *
 * based on
 *
 * ender postMessage - v0.1.3 - 5/1/2012
 * by Thomas Sturm http://www.sturm.to
 * Dual licensed under the MIT and GPL licenses.
 *
 * based on
 *
 * jQuery postMessage - v0.5 - 9/11/2009
 * http://benalman.com/projects/jquery-postmessage-plugin/
 * Copyright (c) 2009 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Release History
//   visit https://github.com/LeoDutra/simple-postmessage/releases
//
// Fork history
//   ender postMessage
//   0.1.3 - (5/1/2012) compatible with browserify
//   0.1.2 - (5/26/2011) Initial Fork and Release
//
//   jQuery postMessage
//   0.5 - (9/11/2009) Improved cache-busting
//   0.4 - (8/25/2009) Initial release

(function(window) {
    "use strict";

    var queueInterval = 0,
        receiveInterval = 0,
        hashQueue = [],
        last_hash,
        original_hash,
        receiveCallback,
        cache_bust = 0,
        INTERNAL_HASH_DELAY = 100,
        INTERNAL_QUEUE_DELAY = INTERNAL_HASH_DELAY + 20, // FIXME: using "+ms" against collisions / bad CPU times
        FALSE = !1, // BETTER MINIFICATION
        POST_MESSAGE = "postMessage",
        ADD_EVENT_LISTENER = "addEventListener",
        HAS_POSTMESSAGE = window[POST_MESSAGE],
        JSON = window.JSON;

        // ie 10- version detection. Useful to fix IE9 and IE8 problem when passing objects as message
        //   http://stackoverflow.com/a/15983064/1260526
        var IE_FIX = parseInt(navigator.userAgent.toLowerCase().split("msie")[1], 10) < 10;

    function serialize(any) {
        return JSON ? JSON.stringify(any) : any;
    }

    function deserialize(any) {
        return JSON ? JSON.parse(any) : any;
    }

    function locationOrigin(location) {
        return location.origin || location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
    }

    function locationWithoutHash(location) {
        return location.href.replace(location.hash, '');
    }

    function sendHash(target, hash) {
        target.location = hash;
    }

    function queueToSend(target, hash) {
        if (queueInterval) {
            hashQueue.push({target: target, hash: hash}); // queue our baby
        }
        else {
            sendHash(target, hash); // first is always sent and starts queue verification

            if (!queueInterval) queueInterval = setInterval(function() {
                if (hashQueue.length) {
                    var current = hashQueue.shift();
                    try {
                        // FIXME: try/catch reason: maybe target window was closed! Better be safe
                        sendHash(current.target, current.hash);
                    }
                    catch(current) {}
                }
                else if (queueInterval) { // SHALL require this additional cycle before clear
                    clearInterval(queueInterval);
                    hashQueue = [];
                    queueInterval = 0;
                }
            }, INTERNAL_QUEUE_DELAY);
        }
    }

    function copyProperties(obj, destination) {
        // the damn Message Event is immutable... so we copy it for set deserialization to data
        destination = destination || {};
        for (var prop in obj) {
            if (typeof prop !== "function") { // hasOwnProperty = no property :(
                destination[prop] = obj[prop];
            }
        }
        return destination;
    }

    function verifyOrigin(source_origin, messageEvent_origin) {
        return !source_origin || source_origin === '*' || // listens to all
            /*STRING*/  messageEvent_origin === source_origin ||
            /*FUNCTION*/typeof source_origin === "function" && source_origin(messageEvent_origin) ||
            /*ARRAY*/   Object.prototype.toString.call(source_origin) === '[object Array]'
                            && ~source_origin.indexOf(messageEvent_origin);
    }

    // Method: window.postMessage
    //
    // This method will call native window.postMessage if available, setting the
    // targetOrigin parameter to the base of the target_url parameter for maximum
    // security in browsers that support it. If window.postMessage is not available,
    // the target window's location.hash will be used to pass the message, and an internal queue
    // will handle message multiplicity.
    //
    // Please Note: This version does not support the jQuery object serialization
    // for postMessage
    //
    // Usage:
    //
    // > window.postMessage( message, target_url [, target ] );
    //
    // Arguments:
    //
    //  message - (String) A message to be passed to the other frame.
    //  target_url - (String) The URL of the other frame this window is
    //    attempting to communicate with. This must be the exact URL (including
    //    any query string) of the other window for this script to work in
    //    browsers that don't support window.postMessage.
    //  target - (Object) A reference to the other frame this window is
    //    attempting to communicate with. If omitted, defaults to `opener`, then `parent`
    //    and then `window`
    //
    // Returns:
    //    (Nothing)
    //
    // Throws:
    //    Error - when no target_url (nor "*") is defined
    //
    window.simplePostMessage = function(message, target_url, target) {

        if (!target_url) throw 'simplePostMessage:: at least a "*" (any target) is expected for "target_url" argument.';

        // opener is not null when this came from window.open(), parent is not null when this is inside of an iframe
        target = target || opener || parent || window;

        // The browser supports window.postMessage, so call it with a targetOrigin
        // set appropriately, based on the target_url parameter.
        if (HAS_POSTMESSAGE) { // USE NATIVE POST MESSAGE -------------

            if (IE_FIX) {
                // IE9- can't pass objects as message. Serialize using JSON.stringify (need Crockford's json2.js for IE8Compat, IE7 & IE6)
                message = serialize(message);
            }
            // only "schema://host:port" is needed
            // defaults to "*" (any), which is bad for security but is an option of the spec
            target[POST_MESSAGE](message, target_url === '*' ? target_url : target_url.replace(/([^:]+:\/\/[^\/]+).*/, "$1"));
        }
        else { // USE HASH ALTERNATIVE POST MESSAGE -------------
            // The browser does not support window.postMessage, so set the location
            // of the target to target_url#message. A bit ugly, but it works! A cache
            // bust parameter is added to ensure that repeat messages trigger the
            // callback.

            // target_url === '*', get the location of the target without hash (prevent bugs)
            target_url = target_url === '*' ? locationWithoutHash(target.location) : target_url.replace(/#.*$/, "");

            message = { // Fake MessageEvent
                type: 'message',
                timeStamp: +new Date,
                data: message,
                origin: locationOrigin(location)
            };

            if (++cache_bust > 9999999) cache_bust = 0; // Don't try to touch the Infinity. God's logic would rape you.

            // encodeURIComponent avoids problem with invalid URL chars
            queueToSend(target, target_url + "#--HASH--" + (+new Date) + (++cache_bust) + "&" + encodeURIComponent(serialize(message)))
        }
    };

    // Method: window.receiveMessage
    //
    // Register a single callback for either a window.postMessage call, if
    // supported, or if unsupported, for any change in the current window
    // location.hash. If window.postMessage is supported and source_origin is
    // specified, the source window will be checked against this for maximum
    // security. If window.postMessage is unsupported, a polling loop will be
    // started to watch for changes to the location.hash.
    //
    // Note that for simplicity's sake, only a single callback can be registered
    // at one time. Passing no params will unbind this event (or stop the polling
    // loop), and calling this method a second time with another callback will
    // unbind the event (or stop the polling loop) first, before binding the new
    // callback.
    //
    // Also note that if window.postMessage is available, the optional
    // source_origin param will be used to test the event.origin property. From
    // the MDC window.postMessage docs: This string is the concatenation of the
    // protocol and "://", the host name if one exists, and ":" followed by a port
    // number if a port is present and differs from the default port for the given
    // protocol. Examples of typical origins are https://example.org (implying
    // port 443), http://example.net (implying port 80), and http://example.com:8080.
    //
    // Usage:
    //
    // > window.receiveMessage( callback [, source_origin ] [, hashModeDelay ] );
    //
    // Arguments:
    //
    //  callback - (Function) This callback will execute whenever a <window.postMessage>
    //    message is received, provided the source_origin matches. If callback is
    //    omitted, any existing receiveMessage event bind or polling loop will be
    //    canceled.
    //  source_origin - if source_origin is not defined, or is "*", the callback IS ALWAYS called
    //  source_origin - (String) If window.postMessage is available and this value
    //    is not equal to the event.origin property, the callback WILL NOT be
    //    called.
    //  source_origin - (Function) If window.postMessage is available and this
    //    function returns false when passed the event.origin property, the
    //    callback WILL NOT be called.
    //  source_origin - (Array) If window.postMessage is available and this
    //    array does not contain the event.origin property value, the
    //    callback WILL NOT be called.
    //  hashModeDelay - (Number) An optional zero-or-greater delay in milliseconds at
    //    which the polling loop will execute (for browser that don't support
    //    window.postMessage). If omitted, defaults to 100.
    //
    // Returns:
    //   (Nothing)
    //
    window.simpleReceiveMessage = function(callback, source_origin/*="*"*/) {

        if (HAS_POSTMESSAGE) {  // USE NATIVE RECEIVER -------------
            // Since the browser supports window.postMessage, the callback will be
            // bound to the actual event associated with window.postMessage.

            if (callback) {
                // Unbind an existing callback if it exists (yes, recursive call without args)
                if (receiveCallback) window.simpleReceiveMessage();

                // Bind the callback. A reference to the callback is stored for ease of unbinding.
                receiveCallback = function(messageEvent) {
                    if (verifyOrigin(source_origin, messageEvent.origin)) {

                        if (IE_FIX) {
                            messageEvent = copyProperties(messageEvent); // the damn Message Event is immutable... so we copy it, deserialize data and set in the copied object

                            // IE9- can't pass objects as message. Deserialize  using JSON.parse (need Crockford's json2.js for IE8Compat, IE7 & IE6)
                            messageEvent.data = deserialize(messageEvent.data);
                        }

                        callback(messageEvent);
                    }
                };
            }

            if (window[ADD_EVENT_LISTENER]) { // good browser / horrible browser ?
                window[callback ? ADD_EVENT_LISTENER : "removeEventListener"]("message", receiveCallback, FALSE);
            } else {
                window[callback ? "attachEvent" : "detachEvent"]("onmessage", receiveCallback);
            }

        }
        else { // USE ARTIFICIAL RECEIVER FOR HASH ALTERNATIVE -------------
            // Since the browser sucks, a polling loop will be started, and the
            // callback will be called whenever the location.hash changes.

            if (receiveInterval) {
                receiveInterval = clearInterval(receiveInterval);
            }
            if (callback) {
                original_hash = document.location.hash;
                receiveInterval = setInterval(function() {
                    var hash = document.location.hash;
                    var re = /^#?--HASH--\d+&/;
                    if (hash !== last_hash && hash !== original_hash && re.test(hash)) {
                        last_hash = hash;
                        document.location.hash = original_hash ? original_hash : '';

                        // replace(/\+/gim, ' ') fixes a Mozilla bug
                        //   http://stackoverflow.com/questions/75980/best-practice-escape-or-encodeuri-encodeuricomponent/12796866#comment30658935_12796866
                        var messageEvent = deserialize(decodeURIComponent(hash.replace(re, "").replace(/\+/gim, " ")));
                        if (verifyOrigin(source_origin, messageEvent.origin)) {
                            callback(messageEvent);
                        }
                    }
                }, INTERNAL_HASH_DELAY);
            }
        }
    };
})(window);
<|endoftext|>


<commit_before>(function(DOM, location) {
    "use strict";

    DOM.ready(function() {
        var // internal data structures
            historyData = {},
            currentLocation = location.href.split("#")[0],
            animationEvents = ["animationend", "transitionend", "webkitAnimationEnd", "webkitTransitionEnd"],
            handleLinkClick = function(link, cancel) {
                if (!cancel && !link.get("target") && !link.get("href").indexOf("http")) return !link.fire("ajaxify:fetch");
            },
            // use late binding to determine when element could be removed from DOM
            containers = DOM.findAll("[data-ajaxify]").on(animationEvents, "_handleAjaxify"),
            switchContent = (function() {
                var prevContainers = {},
                    // remove element from dom and cleanup
                    _handleAjaxify = function() { delete this.remove()._handleAjaxify };

                return function(response) {
                    if (typeof response !== "object") return;

                    var cacheEntry = {html: {}, title: DOM.get("title"), url: currentLocation};

                    containers.each(function(el, index) {
                        var key = el.data("ajaxify"),
                            content = response.html[key];

                        // make sure that previous element is hidden
                        if (key in prevContainers) _handleAjaxify.call(prevContainers[key]);

                        if (content != null) {
                            if (typeof content === "string") {
                                content = el.clone(false).set(content).on(animationEvents, "_handleAjaxify");
                            }

                            el.before(content.hide());
                            // show/hide content async to display animation
                            setTimeout(function() { el.hide() }, 0);
                            setTimeout(function() { content.show() }, 0);
                            // postpone removing element from DOM if an animation exists
                            if (!el.matches(":hidden") && (
                                parseFloat(el.style("transition-duration")) ||
                                parseFloat(el.style("animation-duration")))) {
                                el._handleAjaxify = _handleAjaxify;
                            } else {
                                el.remove();
                            }

                            cacheEntry.html[key] = el;
                            // update content in the internal collection
                            containers[index] = content;
                        }
                    });
                    // update old containers to their latest state
                    historyData[currentLocation] = cacheEntry;
                    // update current location variable
                    currentLocation = response.url;
                    // update page title
                    DOM.set("title", response.title);
                };
            }());

        DOM.on("ajaxify:fetch", (function() {
            // lock element to prevent double clicks
            var lockedEl,
                sharedXHR = new XMLHttpRequest(),
                createXHR = function(target, url, callback) {
                    var resultXHR = sharedXHR;

                    if (callback === switchContent) {
                        // abort previous request if it's still in progress but
                        // skip cases when refresh was triggered programatically
                        sharedXHR.abort();

                        if (lockedEl) lockedEl.fire("ajaxify:abort", sharedXHR);

                        lockedEl = target;
                    } else {
                        resultXHR = new XMLHttpRequest();
                    }

                    resultXHR.ontimeout = function() { target.fire("ajaxify:timeout", this) };
                    resultXHR.onerror = function() { target.fire("ajaxify:error", this) };
                    resultXHR.onreadystatechange = function() {
                        if (this.readyState === 4) {
                            var status = this.status,
                                response = this.responseText;

                            // cleanup outer variables
                            if (callback === switchContent) lockedEl = null;

                            target.fire("ajaxify:loadend", this);

                            try {
                                response = JSON.parse(response);
                                // populate default values
                                response.url = response.url || url;
                                response.title = response.title || DOM.get("title");
                                response.html = response.html || {};
                            } catch (err) {
                                // response is a text content
                            } finally {
                                callback(response);

                                if (status >= 200 && status < 300 || status === 304) {
                                    target.fire("ajaxify:load", response);
                                } else {
                                    target.fire("ajaxify:error", this);
                                }
                            }
                        }
                    };

                    return resultXHR;
                };

            return function(data, target, cancel) {
                if (arguments.length === 2) {
                    cancel = target;
                    target = data;
                    data = null;
                }

                if (cancel || lockedEl === target && target !== DOM) return;

                var url = typeof data === "string" ? data : null,
                    callback = typeof data === "function" ? data : switchContent,
                    queryString = null, xhr;

                if (!url) {
                    if (target === DOM || !target.matches("a,form")) {
                        throw "Illegal ajaxify:fetch event with {" + String(data) + "}";
                    }

                    if (target.matches("a")) {
                        url = target.get("href");
                    } else {
                        url = target.get("action");
                        queryString = target.toQueryString();

                        if (target.get("method") === "get") {
                            url += (~url.indexOf("?") ? "&" : "?") + queryString;
                            queryString = null;
                        }
                    }
                }

                xhr = createXHR(target, url, callback);
                xhr.open(queryString ? "POST" : "GET", queryString ? url : (url + (~url.indexOf("?") ? "&" : "?") + new Date().getTime()), true);
                xhr.timeout = 15000;
                xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

                if (queryString) xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

                if (target.fire("ajaxify:loadstart", xhr)) xhr.send(queryString);
            };
        }()));

        DOM.on("touchstart a", function(link, cancel) {
            // fastclick support by checking touch-action: none property
            if (link.style("touch-action") === "none") return handleLinkClick(link, cancel);
        });

        DOM.on("click a", handleLinkClick);

        DOM.on("submit", function(form, cancel) {
            if (!cancel && !form.get("target")) return !form.fire("ajaxify:fetch");
        });

        DOM.on("ajaxify:history", function(url) {
            if (url in historyData) {
                switchContent(historyData[url]);
            } else {
                DOM.fire("ajaxify:fetch", url);
            }
        });
    });

    var makePair = function(name, value) {
        return encodeURIComponent(name) + "=" + encodeURIComponent(value);
    };

    DOM.extend("form", {
        constructor: function() {
            var submits = this.findAll("[type=submit]");

            this.on("ajaxify:fetch", function() {
                submits.set("disabled", true);
            });

            this.on(["ajaxify:load", "ajaxify:error", "ajaxify:abort", "ajaxify:timeout"], function() {
                submits.set("disabled", false);
            });
        },
        toQueryString: function() {
            return this.findAll("[name]").reduce(function(memo, el) {
                var name = el.get("name");

                if (name) { // don't include form fields without names
                    switch(el.get("type")) {
                    case "select-one":
                    case "select-multiple":
                        el.children().each(function(option) {
                            if (option.get("selected")) {
                                memo.push(makePair(name, option.get()));
                            }
                        });
                        break;

                    case undefined:
                    case "fieldset": // fieldset
                    case "file": // file input
                    case "submit": // submit button
                    case "reset": // reset button
                    case "button": // custom button
                        break;

                    case "radio": // radio button
                    case "checkbox": // checkbox
                        if (!el.get("checked")) break;
                        /* falls through */
                    default:
                        memo.push(makePair(name, el.get()));
                    }
                }

                return memo;
            }, []).join("&").replace(/%20/g, "+");
        }
    });
}(window.DOM, location));
<commit_msg>use 1.6 goodies to improve code<commit_after>(function(DOM, location) {
    "use strict";

    DOM.ready(function() {
        var // internal data structures
            historyData = {},
            currentLocation = location.href.split("#")[0],
            animationEvents = ["animationend", "transitionend", "webkitAnimationEnd", "webkitTransitionEnd"],
            handleLinkClick = function(link, cancel) {
                if (!cancel && !link.get("target") && !link.get("href").indexOf("http")) return !link.fire("ajaxify:fetch");
            },
            // use late binding to determine when element could be removed from DOM
            containers = DOM.findAll("[data-ajaxify]").on(animationEvents, "_handleAjaxify"),
            switchContent = (function() {
                var prevContainers = {},
                    // remove element from dom and cleanup
                    _handleAjaxify = function() { delete this.remove()._handleAjaxify };

                return function(response) {
                    if (typeof response !== "object") return;

                    var cacheEntry = {html: {}, title: DOM.get("title"), url: currentLocation};

                    containers.each(function(el, index) {
                        var key = el.data("ajaxify"),
                            content = response.html[key];

                        // make sure that previous element is hidden
                        if (key in prevContainers) _handleAjaxify.call(prevContainers[key]);

                        if (content != null) {
                            if (typeof content === "string") {
                                content = el.clone(false).set(content).on(animationEvents, "_handleAjaxify");
                            }
                            // show/hide content async to display CSS3 animation
                            el.before(content.hide().show(1)).hide(1);
                            // postpone removing element from DOM if an animation exists
                            if (!el.matches(":hidden") && (
                                parseFloat(el.style("transition-duration")) ||
                                parseFloat(el.style("animation-duration")))) {
                                el._handleAjaxify = _handleAjaxify;
                            } else {
                                el.remove();
                            }

                            cacheEntry.html[key] = el;
                            // update content in the internal collection
                            containers[index] = content;
                        }
                    });
                    // update old containers to their latest state
                    historyData[currentLocation] = cacheEntry;
                    // update current location variable
                    currentLocation = response.url;
                    // update page title
                    DOM.set("title", response.title);
                };
            }());

        DOM.on("ajaxify:fetch", (function() {
            // lock element to prevent double clicks
            var lockedEl,
                sharedXHR = new XMLHttpRequest(),
                createXHR = function(target, url, callback) {
                    var resultXHR = sharedXHR;

                    if (callback === switchContent) {
                        // abort previous request if it's still in progress but
                        // skip cases when refresh was triggered programatically
                        sharedXHR.abort();

                        if (lockedEl) lockedEl.fire("ajaxify:abort", sharedXHR);

                        lockedEl = target;
                    } else {
                        resultXHR = new XMLHttpRequest();
                    }

                    resultXHR.ontimeout = function() { target.fire("ajaxify:timeout", this) };
                    resultXHR.onerror = function() { target.fire("ajaxify:error", this) };
                    resultXHR.onreadystatechange = function() {
                        if (this.readyState === 4) {
                            var status = this.status,
                                response = this.responseText;

                            // cleanup outer variables
                            if (callback === switchContent) lockedEl = null;

                            target.fire("ajaxify:loadend", this);

                            try {
                                response = JSON.parse(response);
                                // populate default values
                                response.url = response.url || url;
                                response.title = response.title || DOM.get("title");
                                response.html = response.html || {};
                            } catch (err) {
                                // response is a text content
                            } finally {
                                callback(response);

                                if (status >= 200 && status < 300 || status === 304) {
                                    target.fire("ajaxify:load", response);
                                } else {
                                    target.fire("ajaxify:error", this);
                                }
                            }
                        }
                    };

                    return resultXHR;
                };

            return function(url, callback, target, cancel) {
                if (arguments.length === 3) {
                    // url, target, cancel
                    cancel = target;
                    target = callback;
                    callback = switchContent;
                } else if (arguments.length === 2) {
                    // target, cancel
                    target = url;
                    cancel = callback;
                    callback = switchContent;
                    url = null;
                }

                if (cancel || lockedEl === target && target !== DOM) return;

                var queryString = null, xhr;

                if (typeof url !== "string") {
                    if (target === DOM || !target.matches("a,form")) {
                        throw "Illegal ajaxify:fetch event with {" + String(url) + "}";
                    }

                    if (target.matches("a")) {
                        url = target.get("href");
                    } else {
                        url = target.get("action");
                        queryString = target.toQueryString();

                        if (target.get("method") === "get") {
                            url += (~url.indexOf("?") ? "&" : "?") + queryString;
                            queryString = null;
                        }
                    }
                }

                xhr = createXHR(target, url, callback);
                xhr.open(queryString ? "POST" : "GET", queryString ? url : (url + (~url.indexOf("?") ? "&" : "?") + new Date().getTime()), true);
                xhr.timeout = 15000;
                xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

                if (queryString) xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

                if (target.fire("ajaxify:loadstart", xhr)) xhr.send(queryString);
            };
        }()));

        DOM.on("touchstart a", function(link, cancel) {
            // fastclick support by checking touch-action: none property
            if (link.style("touch-action") === "none") return handleLinkClick(link, cancel);
        });

        DOM.on("click a", handleLinkClick);

        DOM.on("submit", function(form, cancel) {
            if (!cancel && !form.get("target")) return !form.fire("ajaxify:fetch");
        });

        DOM.on("ajaxify:history", function(url) {
            if (url in historyData) {
                switchContent(historyData[url]);
            } else {
                DOM.fire("ajaxify:fetch", url);
            }
        });
    });

    var makePair = function(name, value) {
        return encodeURIComponent(name) + "=" + encodeURIComponent(value);
    };

    DOM.extend("form", {
        constructor: function() {
            var submits = this.findAll("[type=submit]");

            this.on("ajaxify:fetch", function() {
                submits.set("disabled", true);
            });

            this.on(["ajaxify:load", "ajaxify:error", "ajaxify:abort", "ajaxify:timeout"], function() {
                submits.set("disabled", false);
            });
        },
        toQueryString: function() {
            return this.findAll("[name]").reduce(function(memo, el) {
                var name = el.get("name");

                if (name) { // don't include form fields without names
                    switch(el.get("type")) {
                    case "select-one":
                    case "select-multiple":
                        el.children().each(function(option) {
                            if (option.get("selected")) {
                                memo.push(makePair(name, option.get()));
                            }
                        });
                        break;

                    case undefined:
                    case "fieldset": // fieldset
                    case "file": // file input
                    case "submit": // submit button
                    case "reset": // reset button
                    case "button": // custom button
                        break;

                    case "radio": // radio button
                    case "checkbox": // checkbox
                        if (!el.get("checked")) break;
                        /* falls through */
                    default:
                        memo.push(makePair(name, el.get()));
                    }
                }

                return memo;
            }, []).join("&").replace(/%20/g, "+");
        }
    });
}(window.DOM, location));
<|endoftext|>