/** * Boxy 0.1.4 - Facebook-style dialog, with frills * * (c) 2008 Jason Frame * Licensed under the MIT License (LICENSE) */ /* * jQuery plugin * * Options: *   message: confirmation message for form submit hook (default: "Please confirm:") *  * Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or * Boxy.load for AJAX operations) */jQuery.fn.boxy = function(options) {    options = options || {};    return this.each(function() {              var node = this.nodeName.toLowerCase(), self = this;        if (node == 'a') {            jQuery(this).click(function() {                var active = Boxy.linkedTo(this),                    href = this.getAttribute('href'),                    localOptions = jQuery.extend({actuator: this, title: this.title}, options);                                    if (active) {                    active.show();                } else if (href.indexOf('#') >= 0) {                    var content = jQuery(href.substr(href.indexOf('#'))),                        newContent = content.clone(true);                    content.remove();                    localOptions.unloadOnHide = false;                    new Boxy(newContent, localOptions);                } else { // fall back to AJAX; could do with a same-origin check                    if (!localOptions.cache) localOptions.unloadOnHide = true;                    Boxy.load(this.href, localOptions);                }                                return false;            });        } else if (node == 'form') {            jQuery(this).bind('submit.boxy', function() {                Boxy.confirm(options.message || 'Please confirm:', function() {                    jQuery(self).unbind('submit.boxy').submit();                });                return false;            });        }    });};//// Boxy Classfunction Boxy(element, options) {        this.boxy = jQuery(Boxy.WRAPPER);    jQuery.data(this.boxy[0], 'boxy', this);        this.visible = false;    this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});        if (this.options.modal) {        this.options = jQuery.extend(this.options, {center: true, draggable: false});    }        // options.actuator == DOM element that opened this boxy    // association will be automatically deleted when this boxy is remove()d    if (this.options.actuator) {        jQuery.data(this.options.actuator, 'active.boxy', this);    }        this.setContent(element || "<div></div>");    this._setupTitleBar();        this.boxy.css('display', 'none').appendTo(document.body);    this.toTop();    if (this.options.fixed) {        if (jQuery.browser.msie && jQuery.browser.version < 7) {            this.options.fixed = false; // IE6 doesn't support fixed positioning        } else {            this.boxy.addClass('fixed');        }    }        if (this.options.center && Boxy._u(this.options.x, this.options.y)) {        this.center();    } else {        this.moveTo(            Boxy._u(this.options.x) ? this.options.x : Boxy.DEFAULT_X,            Boxy._u(this.options.y) ? this.options.y : Boxy.DEFAULT_Y        );    }        if (this.options.show) this.show();};Boxy.EF = function() {};jQuery.extend(Boxy, {        WRAPPER:    "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'>" +                "<tr><td class='top-left'></td><td class='top'></td><td class='top-right'></td></tr>" +                "<tr><td class='left'></td><td class='boxy-inner'></td><td class='right'></td></tr>" +                "<tr><td class='bottom-left'></td><td class='bottom'></td><td class='bottom-right'></td></tr>" +                "</table>",        DEFAULTS: {        title:                  null,           // titlebar text. titlebar will not be visible if not set.        closeable:              true,           // display close link in titlebar?        draggable:              true,           // can this dialog be dragged?        clone:                  false,          // clone content prior to insertion into dialog?        actuator:               null,           // element which opened this dialog        center:                 true,           // center dialog in viewport?        show:                   true,           // show dialog immediately?        modal:                  false,          // make dialog modal?        fixed:                  true,           // use fixed positioning, if supported? absolute positioning used otherwise        closeText:              'x',      // text to use for default close link        unloadOnHide:           false,          // should this dialog be removed from the DOM after being hidden?        clickToFront:           false,          // bring dialog to foreground on any click (not just titlebar)?        behaviours:             Boxy.EF,        // function used to apply behaviours to all content embedded in dialog.        afterDrop:              Boxy.EF,        // callback fired after dialog is dropped. executes in context of Boxy instance.        afterShow:              Boxy.EF,        // callback fired after dialog becomes visible. executes in context of Boxy instance.        afterHide:              Boxy.EF,        // callback fired after dialog is hidden. executed in context of Boxy instance.        beforeUnload:           Boxy.EF         // callback fired after dialog is unloaded. executed in context of Boxy instance.    },        DEFAULT_X:          50,    DEFAULT_Y:          50,    zIndex:             1337,    dragConfigured:     false, // only set up one drag handler for all boxys    resizeConfigured:   false,    dragging:           null,        // load a URL and display in boxy    // url - url to load    // options keys (any not listed below are passed to boxy constructor)    //   type: HTTP method, default: GET    //   cache: cache retrieved content? default: false    //   filter: jQuery selector used to filter remote content    load: function(url, options) {                options = options || {};                var ajax = {            url: url, type: 'GET', dataType: 'html', cache: false, success: function(html) {                html = jQuery(html);                if (options.filter) html = jQuery(options.filter, html);                new Boxy(html, options);            }        };                jQuery.each(['type', 'cache'], function() {            if (this in options) {                ajax[this] = options[this];                delete options[this];            }        });                jQuery.ajax(ajax);            },        // allows you to get a handle to the containing boxy instance of any element    // e.g. <a href='#' onclick='alert(Boxy.get(this));'>inspect!</a>.    // this returns the actual instance of the boxy 'class', not just a DOM element.    // Boxy.get(this).hide() would be valid, for instance.    get: function(ele) {        var p = jQuery(ele).parents('.boxy-wrapper');        return p.length ? jQuery.data(p[0], 'boxy') : null;    },        // returns the boxy instance which has been linked to a given element via the    // 'actuator' constructor option.    linkedTo: function(ele) {        return jQuery.data(ele, 'active.boxy');    },        // displays an alert box with a given message, calling optional callback    // after dismissal.    alert: function(message, callback, options) {        return Boxy.ask(message, ['OK'], callback, options);    },        // displays an alert box with a given message, calling after callback iff    // user selects OK.    confirm: function(message, after, options) {        return Boxy.ask(message, ['OK', 'Cancel'], function(response) {            if (response == 'OK') after();        }, options);    },        // asks a question with multiple responses presented as buttons    // selected item is returned to a callback method.    // answers may be either an array or a hash. if it's an array, the    // the callback will received the selected value. if it's a hash,    // you'll get the corresponding key.    ask: function(question, answers, callback, options) {                options = jQuery.extend({modal: true, closeable: false},                                options || {},                                {show: true, unloadOnHide: true});                var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));                // ick        var map = {}, answerStrings = [];        if (answers instanceof Array) {            for (var i = 0; i < answers.length; i++) {                map[answers[i]] = answers[i];                answerStrings.push(answers[i]);            }        } else {            for (var k in answers) {                map[answers[k]] = k;                answerStrings.push(answers[k]);            }        }                var buttons = jQuery('<form class="answers"></form>');        buttons.html(jQuery.map(answerStrings, function(v) {            return "<input type='button' value='" + v + "' />";        }).join(' '));                jQuery('input[type=button]', buttons).click(function() {            var clicked = this;            Boxy.get(this).hide(function() {                if (callback) callback(map[clicked.value]);            });        });                body.append(buttons);                new Boxy(body, options);            },        // returns true if a modal boxy is visible, false otherwise    isModalVisible: function() {        return jQuery('.boxy-modal-blackout').length > 0;    },        _u: function() {        for (var i = 0; i < arguments.length; i++)            if (typeof arguments[i] != 'undefined') return false;        return true;    },        _handleResize: function(evt) {        var d = jQuery(document);        jQuery('.boxy-modal-blackout').css('display', 'none').css({            width: d.width(), height: d.height()        }).css('display', 'block');    },        _handleDrag: function(evt) {        var d;        if (d = Boxy.dragging) {            d[0].boxy.css({left: evt.pageX - d[1], top: evt.pageY - d[2]});        }    },        _nextZ: function() {        return Boxy.zIndex++;    },        _viewport: function() {        var d = document.documentElement, b = document.body, w = window;        return jQuery.extend(            jQuery.browser.msie ?                { left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :                { left: w.pageXOffset, top: w.pageYOffset },            !Boxy._u(w.innerWidth) ?                { width: w.innerWidth, height: w.innerHeight } :                (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ?                    { width: d.clientWidth, height: d.clientHeight } :                    { width: b.clientWidth, height: b.clientHeight }) );    }});Boxy.prototype = {        // Returns the size of this boxy instance without displaying it.    // Do not use this method if boxy is already visible, use getSize() instead.    estimateSize: function() {        this.boxy.css({visibility: 'hidden', display: 'block'});        var dims = this.getSize();        this.boxy.css('display', 'none').css('visibility', 'visible');        return dims;    },                    // Returns the dimensions of the entire boxy dialog as [width,height]    getSize: function() {        return [this.boxy.width(), this.boxy.height()];    },        // Returns the dimensions of the content region as [width,height]    getContentSize: function() {        var c = this.getContent();        return [c.width(), c.height()];    },        // Returns the position of this dialog as [x,y]    getPosition: function() {        var b = this.boxy[0];        return [b.offsetLeft, b.offsetTop];    },        // Returns the center point of this dialog as [x,y]    getCenter: function() {        var p = this.getPosition();        var s = this.getSize();        return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)];    },                    // Returns a jQuery object wrapping the inner boxy region.    // Not much reason to use this, you're probably more interested in getContent()    getInner: function() {        return jQuery('.boxy-inner', this.boxy);    },        // Returns a jQuery object wrapping the boxy content region.    // This is the user-editable content area (i.e. excludes titlebar)    getContent: function() {        return jQuery('.boxy-content', this.boxy);    },        // Replace dialog content    setContent: function(newContent) {        newContent = jQuery(newContent).css({display: 'block'}).addClass('boxy-content');        if (this.options.clone) newContent = newContent.clone(true);        this.getContent().remove();        this.getInner().append(newContent);        this._setupDefaultBehaviours(newContent);        this.options.behaviours.call(this, newContent);        return this;    },        // Move this dialog to some position, funnily enough    moveTo: function(x, y) {        this.moveToX(x).moveToY(y);        return this;    },        // Move this dialog (x-coord only)    moveToX: function(x) {        if (typeof x == 'number') this.boxy.css({left: x});        else this.centerX();        return this;    },        // Move this dialog (y-coord only)    moveToY: function(y) {        if (typeof y == 'number') this.boxy.css({top: y});        else this.centerY();        return this;    },        // Move this dialog so that it is centered at (x,y)    centerAt: function(x, y) {        var s = this[this.visible ? 'getSize' : 'estimateSize']();        if (typeof x == 'number') this.moveToX(x - s[0] / 2);        if (typeof y == 'number') this.moveToY(y - s[1] / 2);        return this;    },        centerAtX: function(x) {        return this.centerAt(x, null);    },        centerAtY: function(y) {        return this.centerAt(null, y);    },        // Center this dialog in the viewport    // axis is optional, can be 'x', 'y'.    center: function(axis) {        var v = Boxy._viewport();        var o = this.options.fixed ? [0, 0] : [v.left, v.top];        if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);        if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);        return this;    },        // Center this dialog in the viewport (x-coord only)    centerX: function() {        return this.center('x');    },        // Center this dialog in the viewport (y-coord only)    centerY: function() {        return this.center('y');    },        // Resize the content region to a specific size    resize: function(width, height, after) {        if (!this.visible) return;        var bounds = this._getBoundsForResize(width, height);        this.boxy.css({left: bounds[0], top: bounds[1]});        this.getContent().css({width: bounds[2], height: bounds[3]});        if (after) after(this);        return this;    },        // Tween the content region to a specific size    tween: function(width, height, after) {        if (!this.visible) return;        var bounds = this._getBoundsForResize(width, height);        var self = this;        this.boxy.stop().animate({left: bounds[0], top: bounds[1]});        this.getContent().stop().animate({width: bounds[2], height: bounds[3]}, function() {            if (after) after(self);        });        return this;    },        // Returns true if this dialog is visible, false otherwise    isVisible: function() {        return this.visible;        },        // Make this boxy instance visible    show: function() {        if (this.visible) return;        if (this.options.modal) {            var self = this;            if (!Boxy.resizeConfigured) {                Boxy.resizeConfigured = true;                jQuery(window).resize(function() { Boxy._handleResize(); });            }            this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>')                .css({zIndex: Boxy._nextZ(),                      opacity: 0.7,                      width: jQuery(document).width(),                      height: jQuery(document).height()})                .appendTo(document.body);            this.toTop();            if (this.options.closeable) {                jQuery(document.body).bind('keypress.boxy', function(evt) {                    var key = evt.which || evt.keyCode;                    if (key == 27) {                        self.hide();                        jQuery(document.body).unbind('keypress.boxy');                    }                });            }        }        this.boxy.stop().css({opacity: 1}).show();        this.visible = true;        this._fire('afterShow');        return this;    },        // Hide this boxy instance    hide: function(after) {        if (!this.visible) return;        var self = this;        if (this.options.modal) {            jQuery(document.body).unbind('keypress.boxy');            this.modalBlackout.animate({opacity: 0}, function() {                jQuery(this).remove();            });        }        this.boxy.stop().animate({opacity: 0}, 300, function() {            self.boxy.css({display: 'none'});            self.visible = false;            self._fire('afterHide');            if (after) after(self);            if (self.options.unloadOnHide) self.unload();        });        return this;    },        toggle: function() {        this[this.visible ? 'hide' : 'show']();        return this;    },        hideAndUnload: function(after) {        this.options.unloadOnHide = true;        this.hide(after);        return this;    },        unload: function() {        this._fire('beforeUnload');        this.boxy.remove();        if (this.options.actuator) {            jQuery.data(this.options.actuator, 'active.boxy', false);        }    },        // Move this dialog box above all other boxy instances    toTop: function() {        this.boxy.css({zIndex: Boxy._nextZ()});        return this;    },        // Returns the title of this dialog    getTitle: function() {        return jQuery('> .title-bar h2', this.getInner()).html();    },        // Sets the title of this dialog    setTitle: function(t) {        jQuery('> .title-bar h2', this.getInner()).html(t);        return this;    },        //    // Don't touch these privates        _getBoundsForResize: function(width, height) {        var csize = this.getContentSize();        var delta = [width - csize[0], height - csize[1]];        var p = this.getPosition();        return [Math.max(p[0] - delta[0] / 2, 0),                Math.max(p[1] - delta[1] / 2, 0), width, height];    },        _setupTitleBar: function() {        if (this.options.title) {            var self = this;            var tb = jQuery("<div class='title-bar'></div>").html("<h2>" + this.options.title + "</h2>");            if (this.options.closeable) {                tb.append(jQuery("<a href='#' class='close'></a>").html(this.options.closeText));            }            if (this.options.draggable) {                tb[0].onselectstart = function() { return false; }                tb[0].unselectable = 'on';                tb[0].style.MozUserSelect = 'none';                if (!Boxy.dragConfigured) {                    jQuery(document).mousemove(Boxy._handleDrag);                    Boxy.dragConfigured = true;                }                tb.mousedown(function(evt) {                    self.toTop();                    Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];                    jQuery(this).addClass('dragging');                }).mouseup(function() {                    jQuery(this).removeClass('dragging');                    Boxy.dragging = null;                    self._fire('afterDrop');                });            }            this.getInner().prepend(tb);            this._setupDefaultBehaviours(tb);        }    },        _setupDefaultBehaviours: function(root) {        var self = this;        if (this.options.clickToFront) {            root.click(function() { self.toTop(); });        }        jQuery('.close', root).click(function() {            self.hide();            return false;        }).mousedown(function(evt) { evt.stopPropagation(); });    },        _fire: function(event) {        this.options[event].call(this);    }    };$(function() {    /* set global variable for boxy window */    var contactBoxy = null;    /* what to do when click on contact us link */    $('.send_feedback').click(function(){        var boxy_content;        boxy_content += "<div style=\"width:310px; height:380px\"><form id=\"feedback\">";        boxy_content += "<p>Name:<br /><input type=\"text\" name=\"name\" id=\"name\" size=\"30\" /></p><p>Email:<br /><input type=\"text\" name=\"email\" size=\"30\" /></p><p>Message:<br /><textarea name=\"comment\" id=\"comment\" cols=\"35\" rows=\"8\"></textarea></p><p><input type=\"checkbox\" name=\"subscribe\"/> Subscribe to news and updates<br/></p><p style=\"padding-top:10px\"><input type=\"submit\" name=\"submit\" value=\"Send >>\" />";        boxy_content += "</form></div>";        contactBoxy = new Boxy(boxy_content, {            title: "Send feedback/suggestions",            draggable: false,            modal: true,            behaviours: function(c) {				                c.find('#feedback').submit(function() {					var _name_ = c.find("input[name='name']").val();					var _email_ = c.find("input[name='email']").val();					var _message_ = c.find("#comment").val();										var _feedback_ = c.find("input[name='subscribe']")[0].checked;//document.feedback.subscribe[0];					if(_name_ == "" || _email_ == "" || _message_ == ""){						alert("Please fill in all the fields before submitting");						return false;					}else{						Boxy.get(this).setContent("<div style=\"width: 310px; height: 380px\">Sending...</div>");						// submit form by ajax using post and send 3 values: subject, your_email, comment						$.post("/sendfeedback", { name: _name_, email: _email_, comment: _message_, subscribe: _feedback_},						function(data){							/*set boxy content to data from ajax call back*/							contactBoxy.setContent("<div style=\"width: 310px; height: 60px\">"+data+"</div>");						});						return false;					}                });            }         });		        return false;    });});