

/********************
 zen.js 
********************/

var Zen = {
    // Shortcut to the jQuery object
    $:          AJS.$,

    // Browser detection
    ie:         jQuery.browser.msie,
    ie9:        jQuery.browser.msie && parseInt(jQuery.browser.version) == 9,
    ie8:        jQuery.browser.msie && parseInt(jQuery.browser.version) == 8,
    ie7:        jQuery.browser.msie && parseInt(jQuery.browser.version) == 7,
    ie6:        jQuery.browser.msie && parseInt(jQuery.browser.version) == 6,
    ie5:        jQuery.browser.msie && parseInt(jQuery.browser.version) <  6,
    safari:     jQuery.browser.webkit,
    firefox:    jQuery.browser.mozilla,
    opera:      jQuery.browser.opera,
    ios:        navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad)/),
 
    // Image information -- gets populated by zen-javascript-bridge.html
    images:     {},
    
    // Color map -- gets populated by zen-javascript-bridge.html
    colors:     {},
 
    // Return the URL path for attachmentName on pageId's page
    attachmentPath: function(pageId, attachmentName) {
        return attachmentName.trim() ? contextPath + "/download/attachments/" + pageId + "/" + attachmentName.trim() : null;
    },

    // Return the URL path for imageName (in the brand)
    brandImagePath: function(imageName) {
        return imageName.trim() ? Zen.images.location + imageName.trim() : null;
    },

    // Lookup color as a named Zen brand palette color (primary, secondary, etc.). If not a named color, just return the color itself
    translateColor: function (color) {
        if (!color) return color;   // Fixes IE bug
        color = Zen.$.trim(color);
        return Zen.colors[color] ? Zen.colors[color] : color;
    }
};

// Make sure any links to the current page are flagged as .current
AJS.toInit( function ($) {
    $("a[href='" + pageUrl + "']").addClass("current");
    $(".current").parent().filter("li").each(function () { 
        if (!$(this).parents().find("#dashboard").length) $(this).addClass("current"); 
    });
    $("li.current").find("a.current").removeClass("current");
});

// Support for the menu-link macro -- make sure tabs are marked as current based on the current space
AJS.toInit( function ($) {
    $("#zen-menu > ul > li > a[data-space-keys~='" + spaceKey + "']").each(function () {
        $(this).parent().filter("li").addClass("current");
    });
});

AJS.toInit(function ($) {
    
    // .wait(milliseconds) -- add a delay to the jQuery object's queue
	jQuery.fn.wait = function(milliseconds) {
        return this.each(function() {
            var item = $(this);
            item.queue(function() {
                setTimeout( function() { item.dequeue(); }, milliseconds );
            });
        });
	};
	
    // .defer(milliseconds, func) -- add a delayed function call to the jQuery object's queue
    // In the callback, this will be the DOM element on which the delay was set
	jQuery.fn.defer = function(milliseconds, callback) {
        return this.each(function() {
            var item = $(this);
            item.queue(function() {
                setTimeout( function() { callback.call(item); item.dequeue(); }, milliseconds );
            });
        });
	};
    

});

// Provide an error-safe method to execute a javascript function immediately, passing in a jQuery reference as $
Zen.safe = function(aFunction) {
  try {
      aFunction.call(this, Zen.$);
  }
  catch (ex) {
      alert("Safe code error: " + ex);
      console.log("Safe code error: " + ex);
      console.log("Here's the function that failed:");
      console.log(aFunction);
  }
};


/********************
 fix-confluence.js 
********************/

// {blog-posts} macro -- clean up when displayed in a column (and some elements when displaying in main section)
AJS.toInit( function ($) {
    // Get rid of the date separator and the metadata in Confluence < 3.5
    $(".zen-column")
        .find(".blogpost .pagesubheading, .blog-post-listing .logoBlock, .blog-post-listing .blogHeading .page-metadata").remove();
    $(".blogSurtitle, .blogpost .endsection, .blog-post-listing .endsection").remove();
    
    // Get rid of the date separator and the metadata in Confluence 3.5
    $(".zen-column .blog-post-list .sub-heading").remove();
    
    $(".blog-item-creator, .blog-item-date, .blog-item-space", ".zen-column .blog-post-list .blog-item").remove();
    
    // In the new blog layout, the "created by" text pollutes the DOM in a way that it's easier just to replace the whole title with the link
    $(".zen-column .blog-post-list .blog-title").each( function() { $(this).replaceWith($("a", this)); });
    
    // Replace the content with a couple hundred characters of text
    $(".zen-column").find(".blogpost .wiki-content, .blog-post-listing .wiki-content").each( function() {
        var chop = zenBlogPostSummaryLimit;
        var text = $(this).find("p").text();
        $(this).replaceWith("<p>" + text.substring(0, chop) + (text.length > chop ? "..." : "") + "</p>"); 
    });
});

// The RSS Macro displays badly in columns, so redo it here
AJS.toInit( function ($) {
   $(".zen-column .rssMacro a").each( function () {
       // Remove wacky &xxx; html characters
       var text = $(this).text().replace(/&amp;quot;/gi, '').replace(/&quot;/gi, '');
       
       // Long links in titles consistently mess up the word wrapping, so just remove links
       // The first group captures the hostname, so replace the second parameter with "$1 " to display the host name
       // (not done here because some host names can be super long)
       text = text.replace(/http:\/\/([^\/^\\]+)\S*/gi, " ");

       $(this).text(text);
   });
});

// Hide the unused menu items in the space admin area -- they have no effect on Zen, so don't confuse the user
AJS.toInit( function ($) {
    // Only bother when not viewing a page
    if (!pageId) {
        // Color Schemes
        $("#space-admin-menu li a[href*='lookandfeel.action']").parent().remove();

        // Layout
        $("#space-admin-menu li a[href*='listdecorators.action']").parent().remove();

        // Stylesheets
        $("#space-admin-menu li a[href*='viewstylesheet.action']").parent().remove();
    }
});

// This is a major hack to get pages like the "restore page" (restoretrashitem.action) to display reasonably.
AJS.toInit( function ($) {
    // At least add a white background
    if (spaceAdminAction) $("#header").next().wrap($("<div />").attr("id", "content"));
});

// This is another hack to get miscellaneous pages to display with a canvas
AJS.toInit( function ($) {
    // Hack to avoid affecting the create space form
    if (window.location.toString().indexOf("/spaces/createspace") != -1) return;

    if (!$("#content").length && $("div[align='center']").length) $("#header").next().wrap($("<div />").attr("id", "content"));
});

// Import Word's second panel draws its form outside the content
AJS.toInit( function ($) {
    // If the import word form is there, move it inside the zen-bin for better presentation
    if (importWord && $("#importwordform").length) {
        $("#canvas #zen-main .zen-bin").append($("#importwordform"));
    }
});

// Broken links (making it better for users without permissions)
AJS.toInit( function ($) {

    // The error class is used on broken links or create-page links when the user doesn't have permissions
    $(".error").each(function() {

        // Remove the square brackets around the broken link (we test for them first, just in case any render without
        // Confluence adding the square brackets).
        var text = $(this).text();
        // Regexp looks for a left bracket at the beginning, and a right bracket at the end of the link text
        if (text.search(/^\[.*\]$/) != -1) $(this).text(text.substring(1, text.length - 1)); 
        
        // Remove css class that add the pink background
        $(this).removeClass("error");
    });

});

// Ensure the fullscreen rich text editor displays above the toolbar
AJS.toInit( function ($) {
    $("#wysiwygTextarea_fullscreen").click( function () { $("#mce_fullscreen_container").css("z-index", 50000) });
});

// Block the autosave feature in the editor
AJS.toInit( function ($) {

	// Prevent the auto-save from interfering with Zen Drafts
	if (typeof(DraftAjax) == "undefined") {
		// DraftAjax disappeared in Confluence 3.3.x
        AJS.params.saveDrafts = false;
	}
	else {
		// In Confluence 3.2.x, the saveDraft function controls the auto-save on drafts
		DraftAjax.saveDraft = function () { $("#draft-status").empty(); };
	}
    
});

// Fix the wizards and dark blanket on the iPad
AJS.toInit(function ($) {

    if (!Zen.ios) return;

    // Fix the blanket by overriding the dim() method and making the blanket huge after it displays
    // The massive height offsets the ability for a user to scroll on long pages, which could get past the 
    // blanket if they work real hard.
    Zen.dim = AJS.dim;
    AJS.dim = function () {
        var result = Zen.dim();
        $(".aui-blanket").width(10000).height(200000);
        return result;
    }
    
});

/**
 * This a direct copy of linkpage.js from Confluence, but patched to remove dependency on the ajs-drop-down menu system.
 * Search for "Stepstone" to see specific changes
 */
AJS.toInit(function($) {
    var dialog = new AJS.Dialog(600, 210, "link-page-popup")
        .addHeader(AJS.params.linkToThisPageHeading)
        .addPanel(AJS.params.linkToThisPageHeading, "<form id='link-page-popup-form' class='aui'>" +
                               "<fieldset>" +
                               "</fieldset>" +
                               "</form>")
        .addButton(AJS.params.linkToThisPageClose, function(e) { hideDialog(e); }, "link-page-close-button");
    
    var keydownHandler = function(e) {
        if (e.which == Event.KEY_ESC) {
            hideDialog(dialog);
        }
    };

    var links = [
        {
            label: AJS.params.linkToThisPageLink,
            id: "link",
            value: $("link[rel=canonical]").attr("href")
        },
        {
            label: AJS.params.linkToThisPageTinyLink,
            id: "tiny-link",
            value: $("link[rel=shortlink]").attr("href")
        },
        {
            label: AJS.params.linkToThisPageWikiMarkup,
            id: "wiki-markup",
            value: $("meta[name=wikilink]").attr("content")
        }
    ];

    $.each(links, function() {
        $("#link-page-popup-form fieldset").append(AJS.format(
                "<div>" +
                    "<label for=''link-popup-field-{0}''>{1}:</label>" +
                    "<input id=''link-popup-field-{0}'' readonly=''readonly'' value='''' class=''text'' type=''text''>" +
                "</div>", this.id, this.label)).find("input:last").val(this.value);
    });

    var hideDialog = function(dialog) {
        dialog.hide();
        $(document).unbind("keydown", keydownHandler);
    };

    // Changed by Stepstone -- selector #link-to-page-link => #link-to-page-link-fix
    $("#link-to-page-link-fix").click(function(e) {
        // If the fieldset isn't available skip the dialoglogin
        if (!$("#link-to-page-fields")[0]) {
            alert("Due to customisations made to this space's layout, Confluence is unable to load the links dialog. " +
                  "For details on how to correct this, please visit the 'Upgrading Custom Layouts' page in our Confluence " +
                  "Documentation, or contact your administrators.");
            return;
        }
        // Removed by Stepstone
        // $(this).parents(".ajs-drop-down")[0].hide();
        dialog.show();
        
        // Added by Stepstone
        // Adjust the title to reflect what the user is linking to
        $("#link-page-popup .dialog-components h2:eq(1)").html("Link To This " + (isBlog ? "Post" : "Page"));
        
        $(document).keydown(keydownHandler);
        $("#link-page-popup-form #link-popup-field-tiny-link").select().focus();
        return AJS.stopEvent(e);
    });

    var linkText = $("#link-page-popup-form fieldset input.text");
    linkText.focus(function() {
        $(this).select();
    });

    // On Safari the mouse up event deselects the text
    linkText.mouseup(function(e){
        e.preventDefault();
    });

});
/**
 * End of the copy of linkpage.js from Confluence.
 */


/********************
 hover-activate.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
 */

(function ($) {

    // When the mouse hovers on the receiver, make itemToActivate appear or disappear. 
    // Make the animation happen at animationSpeed (defaults to "medium"), and wait appearanceDelay before 
    // beginning the animation (default is 500 milliseconds).
    // If slide is true, slide the item in/out of place, otherwise, fade it in/out.
	jQuery.fn.activateOnHover = function (itemToActivate, animationSpeed, appearanceDelay, slide) {
	    
        return this.each( function () {
	    
            var $item = Zen.$(this);

            // Convert the animation speed to numeric or use the default
            if (!animationSpeed) animationSpeed = 300;
            if (animationSpeed == "slow") animationSpeed = 1000;
            else if (animationSpeed == "medium") animationSpeed = 500;
            else if (animationSpeed == "fast") animationSpeed = 250;

            // Convert the delay speed to numeric or use the default
            if (!appearanceDelay) appearanceDelay = "medium";
            if (appearanceDelay == "slow") appearanceDelay = 1000;
            else if (appearanceDelay == "medium") appearanceDelay = 500;
            else if (appearanceDelay == "fast") appearanceDelay = 250;
	        
            var $animated = $(itemToActivate).addClass("animated");
            $animated
                .attr("data-animation-speed", animationSpeed)
                .attr("data-appearance-delay", appearanceDelay)
                .attr("data-slide-animation", slide);
        
            // Animate the appearance of the itemToActivate when the mouse hovers over this element
            $item.hover(
                function (event) { $animated.animateAppearance(event, true) },
                function (event) { $animated.animateAppearance(event, false) }
            );
        
            // Ensure that the control panel appears when the mouse is already over the editable item when the page loads (ZEN-154)
            $item.mouseover(function(event) { $animated.animateAppearance(event, true) });

        });

    };

	jQuery.fn.stopActivateOnHover = function (itemToActivate) {
	    
        return this.each( function () {
	    
            var $item = Zen.$(this);

            $(itemToActivate)
                .removeClass("animated")
                .removeAttr("data-animation-speed")
                .removeAttr("data-appearance-delay")
                .removeAttr("data-slide-animation");
        
            // Animate the appearance of the itemToActivate when the mouse hovers over this element, if the animationTestFunction returns true
            $item.unbind();
        
        });

    };

    // Toggle the edit control when mousing over a editable content area.
    jQuery.fn.animateAppearance = function(event, shouldShow) {
        return this.each(function () {
            
            // Suspend animations when dragging
            if (typeof(ZPD) != "undefined" && (ZPD.isScrolling() || ZPD.isDragging())) return;

            // Make sure we don't have double animations going (such as when hovering over the title in a zen-section)
            event.stopPropagation(shouldShow);
            
            var $this = $(this);
            
            stopAnimations($this);
            
            var animationSpeed = $this.attr("data-animation-speed");
            if (Zen.ie) animationSpeed = 0;
            var delay = $this.attr("data-appearance-delay");
            var slide = $this.attr("data-slide-animation");
           
            // Animate the (dis)appearance of the item
            if (shouldShow) {
                slide ? $this.wait(delay).slideDown(animationSpeed) : $this.wait(delay).fadeIn(animationSpeed);
            }
            else {
                slide ? $this.slideUp(animationSpeed) : $this.fadeOut(animationSpeed);
            }

        });
    };

    // Stop all other animations so edit buttons don't go nuts during spastic mousing
    function stopAnimations (actingOn) {
       $(".animated").stop(true, true);
    };

})(jQuery);


/********************
 wizard.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
 */

/**
 * The shortcut for Zen.Wizard is: ZW
 */

var ZW = Zen.Wizard = {
    
    // Display a message to the user.
    // Call with any number of strings to be added to the message, (they will each be wrapped in paragraph tags), 
    // and the final parameter is an optional object with Zen.Dialog options.
    // Messages can contain HTML.
    // Defaults are {title: "Alert", height: 243, width: 432, noZenBin: true}
    alert: function(message1, message2, options) {
        // var message = basicMessage + '\n' + '\n' + (proceedMessage ? proceedMessage : "Click 'OK' to continue editing.") + '\n';
        // alert(message);
        // Convert the weird arguments object to a regular array
        var args = Array.prototype.slice.call(arguments);

        // Pull off the final options argument if present, merging it over the defaults
        options = ZW.defaults();
        if (typeof(args.last()) == "object") jQuery.extend(options, args.pop());

        // The remaining arguments are messages to display to the user
        var html = "<div class='alert-dialog'>";
        Zen.$.each(args, function() { 
            var msg = args.shift();
            if (msg) html += "<p>" + msg + "</p>";
        });
        html += "</div>";

        // Go right to left to find the options (if any)
        args = Array.prototype.slice.call(arguments);
        options = args.pop();
        if (!options || typeof(options) != "object") options = null;

        var dialog = new Zen.Dialog(html, options);
        dialog.addButton("OK", null, "dialog-close-button default-button");
        dialog.show();
        
        // Add a key press listener for the default button
        AJS.$(document).keydown(ZW.keypressListener);     
    },

    // Display a confirm panel with one or more messages.
    // Call with any number of strings to be added to the message, (they will each be wrapped in paragraph tags), 
    // the second-to-last parameter is an optional object with Zen.Dialog options,
    // and the final parameter is a required function that will be called if the user confirms.
    // Messages can contain HTML.
    // Defaults are {title: "Alert", height: 243, width: 432, noZenBin: true, okButton: "OK", cancelButton: "Cancel"}
    confirm: function(message1, message2, options, callbackFunction) {

        // Convert the weird arguments object to a regular array
        var args = Array.prototype.slice.call(arguments);

        // The initial arguments (up to the function) are messages to display to the user
        var html = "<div class='alert-dialog'>";
        Zen.$.each(args, function() {
            var msg = args.shift();
            if (msg && typeof(msg) == "string") html += "<p>" + msg + "</p>";
        });
        html += "</div>";
        
        // Go right to left to find the function and the options (if any)
        args = Array.prototype.slice.call(arguments);
        callbackFunction = args.pop();
        options = args.pop();
        if (!options || typeof(options) != "object") options = null;

        return ZW.dialog(html, options, callbackFunction);

    },

    // Display a panel with html, using OK/Cancel style buttons.
    // The second-to-last parameter is an optional object with Zen.Dialog options,
    // and the final parameter is a function that will be called if the user clicks the okButton.
    // In options, specify false for okButton or cancelButton to omit them
    // Defaults are {title: "Alert", height: 243, width: 432, noZenBin: true, okButton: "OK", cancelButton: "Cancel"}
    dialog: function(html, options, callbackFunction) {
        // var message = basicMessage + '\n' + '\n' + (proceedMessage ? proceedMessage : "Click 'OK' to proceed, or 'Cancel' to keep editing.") + '\n';
        // return confirm(message);
        
        // Convert the weird arguments object to a regular array
        var args = Array.prototype.slice.call(arguments);

        // Get the final function call that will be used if the user confirms
        callbackFunction = typeof(args.last()) == "function" ? args.pop() : false;

        // Pull off the final options argument if present, merging it over the defaults
        options = {title: "Confirm", height: 243, width: 432, noZenBin: true, okButton: "OK", cancelButton: "Cancel"};
        if (typeof(args.last()) == "object") jQuery.extend(options, args.pop());

        if (options.okButton && !callbackFunction) return ZW.alert("Missing function in ZW.dialog() method call. Required for OK button.");
        
        var dialog = new Zen.Dialog(html, options);
        
        // Add the OK and cancel buttons
        if (options.cancelButton) {
            dialog.addButton(options.cancelButton, null, "dialog-close-button default-button");
        }
        
        if (options.okButton) {
            dialog.addButton(options.okButton, null, "dialog-close-button confirm");
            dialog.$(".dialog-close-button.confirm").click(callbackFunction);
        }
        
        dialog.show();
        
        // Add a key press listener for the default button
        AJS.$(document).keydown(ZW.keypressListener);     

    },
    
    // Return a fresh object with the wizard default parameters
    defaults: function () {
        return {
            title: "Alert", 
            height: 243, 
            width: 432, 
            noZenBin: true
        };
    },

    keypressListener: function (event) {
        if (false && event.keyCode === Event.KEY_RETURN) {
            Zen.$(document).unbind("keydown", ZW.keypressListener);
            if (Zen.$("#zen-dialog:visible").length) {
                var defaultButton = Zen.$("#zen-dialog:visible .default-button");
                defaultButton.addClass("click-state");
                setTimeout(function () {defaultButton.click();}, 200);
            }
        }
    },

    // Display an unlicensed message, along with a blurb on where to get one
    unlicensed: function (message) {
        ZW.alert(message, "Visit <a href='http://www.stepstonetech.com/try'>http://www.stepstonetech.com/try</a> to get a free trial license key.", {title: "Get a Free Trial License", width: 640, height: 360});
        // Return false to cancel menu actions
        return false;
    },

    // Return the full URL for accessing actionName
    // actionName   - the name portion of the action, which will be embedded in the full URL
    //              - for example, if actionName = "banana", the URL returned will be $contextPath/plugins/zen/banana.action
    zenActionUrl: function (actionName) {
        return contextPath + "/plugins/zen/" + actionName + ".action";
    }
    
}



/********************
 toolbar.js 
********************/

Zen.Toolbar = {

    /**
     * Return the top-level DOM element for the toolbar (the holder) as a jQuery match set.
     * @param   selector    {string}                only the matching elements in the html will be displayed
    */
    $: function (selector) {
        var element = Zen.$("#zen-toolbar-holder");
        return selector ? element.find(selector) : element;
    },
    
    // Animate the toolbar's appearance/disappearance based on the user's selection
    adjustToolbarPinned: function (speed) {

        // If anonymous toolbar is disabled, ignore all other settings and just hide the toolbar
        if (Zen.anonymousUser && !Zen.showToolbarToAnonymousUsers) {
            Zen.$("#zen-toolbar-switch, #zen-toolbar-holder").hide();
            return;
        }

        // Start out with the toolbar pinned until the user unpins it
        if (!getCookie("zenToolbarPinned") && Zen.showToolbarByDefault) {
            // setCookie("zenToolbarPinned", "pinned");
            Zen.$("#zen-toolbar-switch").slideUp(speed, function () { Zen.$("#zen-toolbar-holder").slideDown(speed); });
            return;
        }
        
        if (Zen.Toolbar.shouldShow()) {
            Zen.$("#zen-toolbar-switch").slideUp(speed, function () { Zen.$("#zen-toolbar-holder").slideDown(speed); });
            
        }
        else {
            Zen.$("#zen-toolbar-holder").slideUp(speed, function () {  Zen.$("#zen-toolbar-switch").slideDown(speed); });
        }
    },

    // Disable the toolbar by pushing it below the gray blanket
    disableToolbar: function () {
        // The check for .blanket is needed to avoid blowing up IE8
        if (Zen.$(".blanket").length) Zen.Toolbar.$().css("z-index", Zen.$(".blanket").css("z-index") - 1);

        // IE7 hack to get toolbar beneath blanket
        if (Zen.ie7) Zen.Toolbar.$().css("z-index", 0);
    },

    // Enable the toolbar by pulling it on top of the gray blanket
    enableToolbar: function () {
        // The check for .blanket is needed to avoid blowing up IE8
        if (Zen.$(".blanket").length) Zen.Toolbar.$().css("z-index", Zen.$(".blanket").css("z-index") + 1);
    },
    
    // Return true if the toolbar is visible and enabled
    hasFocus: function () {
        return Zen.Toolbar.isEnabled() && Zen.Toolbar.$().is(":visible");
    },
    
    // Return true if the toolbar is enabled
    isEnabled: function () {
        return !Zen.$(".blanket").length || 
                Zen.Toolbar.$().css("z-index") > Zen.$(".blanket").css("z-index");
    },
    
    // Return true if the toolbar show be shown
    shouldShow: function () {
        return getCookie("zenToolbarPinned") == "pinned";
    }
    
};

AJS.toInit( function ($) {

    // Move the toolbar to the top of the browser window, but don't show for anonymous users if not allowed for them
    if (!Zen.anonymousUser || Zen.showToolbarToAnonymousUsers) {
        $("#zen-toolbar-target").replaceWith($("#zen-toolbar"));

        // Make the toolbar & search visible (they're display:none to avoid flashing on iPad)
        $("#zen-toolbar, #search").show();
    }    
});

AJS.toInit( function ($) {
    // Make sure the settings menu items return to the current page
    $(".settings-menu-item a").each( function() {
        var href = $(this).attr("href");
        href += href.indexOf("?") == -1 ? "?" : "&";
        href += "url="
        href += window.location;
        $(this).attr("href", href);
        // $(this).css("cursor", "progress");
        // jQuery.post(href, function(data) {window.location.reload()});
        // return false;
    });
    
    // Make sure the settings menu items hide the toolbar when fired
    $(".settings-menu-item a").click( function() {
        $("#zen-toolbar-holder").slideUp("medium");
    });
    
});

AJS.toInit(function ($) {

    // The selector for the pull-down menus (the drop-down part, not the static tab)
    var pulldowns = "#toolbar-menu > li, #zen-menu > ul > li";
    var slideoffs = ".toolbar-menu-toggle ul li";
    var delay = 400;
    
    // Remove any items the user lacks permission to see (or otherwise is failing)
    $("li .error").parent().remove();
    
    // Make sure that the menus have "first" and "last" indicator
    $("#toolbar-menu > li:first, #zen-menu > ul > li:first").addClass("first");
    $("#toolbar-menu > li:last, #zen-menu > ul > li:last").addClass("last");
    
    // Stop all other animations so menus don't go nuts during spastic mousing
    var stopAnimations = function (actingOn) {
        if ($(actingOn).find("> ul").length) $(pulldowns + "," + slideoffs).find("ul").stop(true, true);
    }

    // Toggle the sub-menu when mousing over a toolbar menu
    jQuery.fn.toggleToolbarMenu = function(mouseOver) {
        return this.each(function(){
            
            stopAnimations(this);
            
            // Animate the coming and going of the menu
            if (mouseOver) $(this).find("> ul").wait(delay).fadeIn("fast");
            else $(this).find("> ul").fadeOut("fast");

        });
    };
    
    // Make sure the menu items close when clicked
    $("a", pulldowns).click(function() { $(this).parents(".toolbar-menu-toggle").toggleToolbarMenu(false); });

    // Activate the toolbar and the navigation menus
    $(pulldowns).addClass("toolbar-menu-toggle").hover(
        function() { $(this).toggleToolbarMenu(true) },
        function() { $(this).toggleToolbarMenu(false) }
    );    

    // Toggle the slide-off menu when mousing over a drop-down menu item
    jQuery.fn.toggleSlideOffMenu = function(mouseOver) {
        return this.each(function(){
            
            stopAnimations(this);
            
            // Animate the coming and going of the menu
            if (mouseOver) $(this).find("> ul").wait(delay).fadeIn("fast");
            else $(this).find("> ul").fadeOut("fast");

        });
    };

    // Activate the first level of slide-off menus (first step to the right of the drop-down menu items)
    // alert($(slideoffs).length);
    $(slideoffs).addClass("toolbar-menu-toggle").hover(
        function() { $(this).toggleSlideOffMenu(true) },
        function() { $(this).toggleSlideOffMenu(false) }
    );
    
    // Add an identifying class to the first <li> in every menu <ul>
    $("#zen-menu ul ul").each( function() { $(this).find("li:first").addClass("first"); } );

});

AJS.toInit (function ($) {
    
    Zen.Toolbar.adjustToolbarPinned(0);

    $("#zen-toolbar-holder #pin a, #zen-toolbar-switch .switch").click(function() {
        setCookie("zenToolbarPinned", Zen.Toolbar.shouldShow() ? "unpinned" : "pinned");
        Zen.Toolbar.adjustToolbarPinned("fast");
        return false;
    });

});


/********************
 toolbar-actions.js 
********************/

// Make the add bookmark button open a dialog
AJS.toInit(function ($) {

    // Make the add bookmark menu item show the form in a dialog
    var addBookmark = function() {
                
        // The element of the returned page that we want for the dialog
        var formSelector = "#PageContent";
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {selector: formSelector, title: "Add Bookmark", height: 700}, function (dialog) {
            // Dump the cancel button
            dialog.$(".submitButtons input[name='cancel']").remove();
            
            // Dump the labels -- they can't work on this page since they conflict with labels on the main page
            dialog.$("#labels_tab").remove();
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the add bookmark item to open a dialog instead of loading a new page
    $("#add-bookmark").click(addBookmark);
});

// Make the change posting date button open the dialog
AJS.toInit(function ($) {

    // Make the change posting date menu item show the form in a dialog
    var changePostDate = function() {

        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {title: "Change Posting Date", width: 600, height: 400}, function (dialog) {
            // Change to submit button's display text
            dialog.$("#confirm").attr("value", "Change Posting Date");

            // Dump the cancel button
            dialog.$("#cancel").remove();

            // Add the date picker to the form. It will set the hidden postingDateString text field that gets submitted by the form
            dialog.$("#datepicker").datepicker({dateFormat: "yy-mm-dd", defaultDate: postedDaysAgo, altField: "#postingDateString" });

        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the remove page menu item to open a dialog instead of loading a new page
    $("#change-post-date").click(changePostDate);
    
});

// Make the RSS configure feed open a dialog
AJS.toInit(function ($) {

    // Make the RSS feed menu item show the form in a dialog
    var configureRssFeed = function() {

        // The element of the returned page that we want for the wizard
        var formSelector = "#build-rss-form";
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, 
                                {selector: formSelector, title: "RSS Feed", height: 860, step: "Configure", panelClass: "rss-feed-configure"}, 
                                function (dialog) {
            
            // Dump the cancel button
            dialog.$("#cancel").remove();

            // Set the confirm button to bring up a wizard with the feed page
            var feedAction = contextPath + "/dashboard/" + dialog.$(formSelector).attr("action");
            dialog.$(formSelector).attr("action", feedAction);
            dialog.$("#confirm").click( function (event) {
                // Get all the form values before dismissing the first wizard
                var params = dialog.$(formSelector).serialize();
                
                // Get the form from the server, and start editing with the response
                jQuery.ajax({
                    url: feedAction, 
                    data: params, 
                    success: function (response) {
                        dialog.addPanel(response, {selector: "#rss-container .functionbox", step: "View", panelClass: "rss-feed-view"});
                    },
                    error: function (xhRequest, textStatus, errorThrown) {
                        alert("Error from received from server: \n\n" + textStatus + (errorThrown ? "\n\n" + errorThrown : ""));
                    }
                });
                
                // Stop the original (first) RSS form from firing (this might not be needed since that form was closed above)
                return false;
            });
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the RSS feed item to open a dialog instead of loading a new page
    // This also handles the rss-feed-link macro
    $("#configure-rss-feed, .rss-feed-link").click(configureRssFeed);

});

// Make the copy page button start the editor
AJS.toInit(function ($) {

    var copyPage = function() {
        // The a href is either the clicked item, or one of its children
        // http://skipper.local:8080/wiki/pages/copypage.action?idOfPageToCopy=1081410&pageId=1081410&key=zen&spaceKey=zen
        var link = $(this).attr("href") ? $(this).attr("href") : $("a", this).attr("href");
        window.location = link.replace("/pages/copy", "/zen/classic/create").replace("&pageId=", "&fromPageId=");

        return false;
    };

    $("#toolbar-menu #copy-page").click(copyPage);

});

// Make the create page button start the editor, and also any create-page links generated by Confluence
AJS.toInit(function ($) {

    // Make the create page button start the title editor
    var createPage = function() {
        // The a href is either the clicked item, or one of its children
        var link = $(this).attr("href") ? $(this).attr("href") : $("a", this).attr("href");
        window.location = link.replace("/pages/create", "/zen/classic/create");

        return false;
    };

    // Wire the create page menu item to ask for a new page title
    $(".add-page-link, .add-blog-link", "#toolbar-menu").click(createPage);
    
    // Grab all the create-page links and make them fire the create page wizard
    $(".createlink[href*='pages/createpage.action']").click(createPage);

});

// Wire the Share This Page toolbar heading (the dropdown title) to fire the share link
AJS.toInit(function ($) {

    // Click the Share This Page link (needed because the structure is different from the standard Zen toolbar menu item)
    var clickShareThisPageLink = function() {
        $("#shareContentLink").click();
        return false;
    };

    // Wire the create page menu item to ask for a new page title
    $("#toolbar-menu #share-content-item .heading").click(clickShareThisPageLink);

});

// Make the design editor appear
AJS.toInit(function ($) {
    
    var designEditor = function() {
        var editor = new Zen.DesignEditor();
        editor.show(this);
        return false;
    }

    // Wire the menu item to open the design editor
    $("#space-design-editor-link, #page-design-editor-link, #page-contents-editor-link").click(designEditor);

});

// Make the discard draft menu item show a dialog
AJS.toInit(function ($) {

    var discardDrafts = function() {
        
        var dialog = new Zen.Dialog($("#discard-draft-form").clone().show(), {title: "Permanently Discard Draft", height: 200});
        dialog.show();

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#discard-page-draft-link").click(discardDrafts);

});

// Make the incoming links button open the dialog
AJS.toInit(function ($) {

    // Make the menu item show the form in a dialog
    var incomingLinks = function() {
       
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {title: "Incoming Links"});

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the remove page menu item to open a dialog instead of loading a new page
    $("#incoming-links-link").click(incomingLinks);

});

// Make the people directory menu items both go to the people directory
AJS.toInit(function ($) {

    var peopleMenu = function() {
        // The a href is either the clicked item, or one of its children
        var link = $(this).attr("href") ? $(this).attr("href") : $("a", this).attr("href");
        window.location = link;
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#people-menu").click(peopleMenu);

});

// Make the remove page button open the confirm page in a dialog
AJS.toInit(function ($) {

    // Make the remove page menu item show the form in a dialog
    var removePage = function() {
        
        // The element of the returned page that we want for the dialog
        var formSelector = "form[name='removepageform']";
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {title: "Remove"}, function (dialog) {

            // Set the confirm button to fire the remove page
            dialog.$("#confirm").click( function (event) {
                window.location = dialog.$(formSelector).attr("action");
                return false;
            });
            
            // Dump the cancel button
            dialog.$("#cancel").remove();
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the remove page menu item to open a dialog instead of loading a new page
    $("#action-remove-content-link").click(removePage);

});

// Make the version history menu item show the form in a dialog
AJS.toInit(function ($) {
    
    /** NOTE: THE FOLLOWING IS AN EXACT COPY OF THE METHODS IN AJS.toInit() CONTENTS IN THE page-history.js FILE IN CONFLUENCE. */

    /**
     * Returns the table row the click/mouseover/mouseout event came from.
     */
    var getTargetRow = function(e) {
        return $(e.target).closest("tr");
    };

    /**
     * Allow the user to check/uncheck the checkbox by clicking anywhere in the row.
     */
	var versionRowClick = function(e) {

		// Don't do anything if a link was clicked.
		if ($(e.target).is('a'))
            return;

        var row = getTargetRow(e);
		var theCheckbox = row.find("input")[0];
        if (!theCheckbox)
            return;   // Ignore clicks in rows without checkboxes (e.g. the header)

        // If user clicked on checkbox itself default handler will toggle it otherwise we do it here.
        if (e.target != theCheckbox) {
            theCheckbox.checked = !theCheckbox.checked;
        }

        // Add a highlight to checked rows
	    if (theCheckbox.checked) {
            // Only allow two boxes to be checked
            if ($("input:checked", this).length <= 2) {
                row.addClass('page-history-item-selected');
            } else {
                theCheckbox.checked = false;
            }
        } else {
            row.removeClass('page-history-item-selected');
        }
	};

    // Use mouseovers instead of :hover for IE.
	var mouseOver = function(e) {
		getTargetRow(e).addClass('page-history-item-mouseover');
	};
	var mouseOut = function(e) {
		getTargetRow(e).removeClass('page-history-item-mouseover');
	};

    /** NOTE: END OF page-history.js COPY. */

    var showVersionHistory = function() {
            
        // The element of the returned page that we want for the dialog
        var formSelector = "form[name='diff']";
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {selector: formSelector, title: "Version History", height: 600}, function (dialog) {
            
            // Remove the column with the  links for restoring a version
            // (Zen let's users create drafts based on a version they're viewing)
            dialog.$("#page-history-container tr").each( function () {
                $(this).find("th:eq(4), td:eq(4)").remove();
            });
            
            // Fix the form's action for Firefox & IE (ZEN-135)
            dialog.$("form[name='diff']").attr("action", contextPath + "/pages/diffpagesbyversion.action");

            // Fix the links to add the full servlet path
            dialog.$("form[action^=diffpagesbyversion.action]").each(function () { $(this).attr("action", contextPath + "/pages/" + $(this).attr("action")); });
            dialog.$("[href^=viewpage.action], [href^=revertpagebacktoversion.action]").each(function () { $(this).attr("href", contextPath + "/pages/" + $(this).attr("href")); });
            
            // Invoke the functionality from the page-history.js file (copied above)
            $("#page-history-container").click(versionRowClick).mouseover(mouseOver).mouseout(mouseOut);
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#version-history-link").click(showVersionHistory);

});

// Make the view drafts menu item show the form in a dialog
AJS.toInit(function ($) {

    var viewDrafts = function() {
            
        // The element of the returned page that we want for the dialog
        var formSelector = ".tableview";
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).parents("#view-drafts-item").find("a").attr("href"), {}, {selector: formSelector, title: "View Drafts", height: 600}, function (dialog) {
            // Lose the table's zen-bin and make it full width
            dialog.$(formSelector).removeClass("zen-bin").css("width", "99%");
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#view-drafts-item.disabled a").click(function () {return false;});
    $("a, li", "#view-drafts-item:not(.disabled)").click(viewDrafts);

});

// Make the view favorites menu item show the form in a dialog
AJS.toInit(function ($) {

    var viewFavorites = function() {
            
        // The element of the returned page that we want for the dialog
        var formSelector = ".tableview";
        
        // Stop repeated openings from choking IE (ZEN-232)
        // Zen.Dialog.clearPrevious();
        
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {selector: formSelector, title: "View Favorites", height: 600}, function (dialog) {
            // Lose the table's zen-bin and make it full width
            dialog.$(formSelector).removeClass("zen-bin").css("width", "99%");
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#view-favorites-link").click(viewFavorites);

});

// Make the view history menu item show the form in a dialog
AJS.toInit(function ($) {

    var viewHistory = function() {
            
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {title: "Recently Viewed", height: 600}, function (dialog) {
            // Lose the table's zen-bin and make it full width
            dialog.$(".tableview").removeClass("zen-bin").css("width", "99%");
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#view-history-link").click(viewHistory);

});

// Make the view watches menu item show the form in a dialog
AJS.toInit(function ($) {

    var viewWatches = function() {
            
        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {selector: "table:eq(0)", title: "View Watches", height: 600}, function (dialog) {

            // Blast the last paragraph when no watches are set
            dialog.$("p:eq(0), p:eq(3)").remove();

            // Fix the broken email settings link
            dialog.$("a[href='viewmyemailsettings.action']").attr("href", contextPath + "/users/viewmyemailsettings.action");

            // Remove the column with the links for turning off the watches
            // Possible enhancement: convert them to Ajax calls and update the wizard display
            dialog.$(".tableview tr").each( function () {
                $(this).find("th:eq(1), td:eq(1)").remove();
            });
            
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#view-watches-link").click(viewWatches);

});

// Make the view wiki markup menu item show the markup in a dialog
AJS.toInit(function ($) {

    var viewWikiMarkup = function() {

        // Send an ajax call to get the dialog contents
        Zen.Dialog.dialogWithUrl($(this).attr("href"), {}, {title: "Wiki Markup on this Page", width: 1024, height: 600, step: "Page"}, function (dialog) {
            // The template renders everything into the first panel (all pages), so take the extra hidden ones and make additional panels
            dialog.$(".wiki-markup.hidden").each(function() {
                dialog.addPanel($(this).clone().show("hidden"), {step: $(this).attr("data-title")});
            });
            
            dialog.gotoPanel(0);
        });

        // Stop the default menu-item click action from firing
        return false;
    };

    // Wire the menu item to open a dialog instead of loading a new page
    $("#view-wiki-markup-link").click(viewWikiMarkup);

});



/********************
 fix-plugins.js 
********************/

// Make sure Gliffy can't start a diagram when in draft mode
AJS.toInit(function ($) {

    if (!hasDraft) return;
    
    // Replace the gliffy menu item with a message to publish before using
    $("#toolbar-menu .toolbar-menu-toggle a[href*='/plugins/gliffy/']").replaceWith("<a href='#' class='no-gliffy'>Gliffy on Drafts</a>");
    
    // Replace the gliffy edit/remove items with a message to publish before using
    // $(".zen-bin a[href*='/plugins/gliffy/remove']").remove();
    $(".zen-bin caption a[href*='/plugins/gliffy/show'], a[href*='/plugins/gliffy/remove']").parent().empty().append("<a href='#' class='no-gliffy'>Can't Edit Diagram</a>");
    
    // Wire the message to the above
    $(".no-gliffy").click( function () {
        ZW.alert("Editing diagrams is not available on draft pages.", "Publish your changes before editing diagrams.", {title: "Gliffy and Drafts"});
        return false; 
    });

});

// Make sure Balsamiq can't edit mockups when in draft mode
AJS.toInit(function ($) {

    if (!hasDraft) return;
    
    // Replace the balsamiq menu item with a message to publish before using
    $("#toolbar-menu .toolbar-menu-toggle a[href*='/plugins/servlet/mockups']").replaceWith("<a href='#' class='no-mockups'>Mockups on Drafts</a>");
    
    // Replace the balsamiq edit links with a message to publish before using
    $(".zen-bin a[href*='/plugins/servlet/mockups']").replaceWith("<a href='#' class='no-mockups'>can't edit this mockup</a>");
    
    // Wire the message to the above
    $(".no-mockups").click( function () {
        ZW.alert("Editing mockups is not available on draft pages.", "Publish your changes before editing mockups.", {title: "Balsamiq and Drafts"});
        return false; 
    });

});

// Hide the task-list plug for now -- it's really awful
AJS.toInit(function ($) {
    // $(".task-list").replaceWith("<p><em>Sorry, the {task-list} macro is not supported by Zen (yet).</em></p>"); 
});

// Remove the .zen pages from the recently updated macro results. This is an imperfect solution. See ZEN-185.
AJS.toInit(function ($) {
   $(".recently-updated li.update-item").filter(function() {return $("a", this).text().indexOf(".zen") == 0}).remove();
});

// Team Calendars patch
AJS.toInit(function ($) {
   $(".user-calendar").prepend($("#team-calendars-buttons").show());
});


/********************
 expando.js 
********************/

AJS.toInit( function ($) {
    
    // When the expando toolbar button is clicked, toggle the mode between normal and expando
    $("#expando").click( function() {
        var speed = "medium";

        if ($("#expando").hasClass("expando")) {
            // Turn off expando mode:
            // Animate narrowing the canvas to the configured width; remove .expando class 
            // from all elements; and fade in the columns
            $("#wrapper").animate({width: zenCanvasWidth}, speed, function () {
                $(".expando").removeClass("expando");
                $("#canvas").css({width: Zen.canvasFixedWidth});
                $(".zen-column").fadeIn(speed);
            });
        }
        else {
            // Turn on expando mode:
            // Fade out the columns; add the .expando class to the main content column; 
            // animate widening the canvas to full-browser width; add .expando class
            // to the toolbar, expando toolbar button, the canvas, and the columns; and finally 
            // remove the width: number (needed for the animation) from the canvas so it
            // can continue to size with the browser window
            $(".zen-column").fadeOut(speed);
            $("#canvas, #zen-main, .zen-column, #zen-footer").toggleClass("expando");
            $("#canvas").css({width: "auto"});
            var wide = $("body").width();
            $("#wrapper").animate({width: wide}, speed, function () {
                $("#zen-toolbar-holder, #expando").toggleClass("expando");
                
                // Make the canvas stretchy to follow window resizing
                $("#wrapper").css({width: "auto"});

            });
        }
        return false; 
    });

    // If not in expando state, and there's nothing to expand, don't display the expando button
    // $zenShowLeftColumn $zenShowRightColumn $zenCanvasWidth $zenMainColumnWidth
    if (isStretchy) $("#expando").remove();

});


/********************
 cookies.js 
********************/

// Set a browser cookie with name and value
function setCookie(name, value) {
	document.cookie = name + "=" + value + "" + "; path=/";
}

// Return the value of the browser cookie name, or null if none
function getCookie(name) {
	var cookies = document.cookie.split(';');
	var name = name + "=";
	for(var i = 0; i < cookies.length; i++) {
		var cookie = cookies[i];
		// Remove the spaces in the cookie
		while (cookie.charAt(0)==' ') {
			cookie = cookie.substring(1, cookie.length);
		}
		if (cookie.indexOf(name) == 0) {
			return cookie.substring(name.length, cookie.length);
		}
	}
	return null;
}

// Delete the browser cookie name
function removeCookie(name) {
	document.cookie = name + "=''; expires=Fri, 13 Jul 2001 00:00:00 UTC; path=/";
}



/********************
 crumbs.js 
********************/

// Prune breadcrumbs to lose the dashboard link and redundant space home/home page links
AJS.toInit( function ($) {

    // Strip off the wrapping <a href></a> if present, and trim white space.
    var linkText = function (html) {
    	return html.replace(/<a.+?>/, "").replace(/<\/a>/, "").replace(/^\s*/, "").replace(/\s*$/, "");
    }

    // Allow the individual templates to override the breadcrumbs
    // See dashboard.html and userdir.html for examples
    if ($("#override-breadcrumbs").length) {
        var override = $("#override-breadcrumbs").remove();
        $("#crumbs").html(override.html());
    }
    
    // Lose the dashboard link and replace it with the "landing page" link
    $("#breadcrumbs .first a").text(siteTitle).attr("href", homePageUrl);

    // // Lose the space link (redundant with home)
    // var crumbs = $("#breadcrumbs li");
    // if (crumbs.length > 0) {
    //  $(crumbs.get(0)).remove();
    // }

    // Eliminate the home page link if its text is duplicated by the space link
    var crumbs = $("#breadcrumbs li span");
    if (crumbs.length > 1) {
    	if (linkText(crumbs.get(0).innerHTML.toLowerCase()) == linkText(crumbs.get(1).innerHTML.toLowerCase())) {
    		var spaceHome = $("#breadcrumbs li").get(1);
    		$(spaceHome).remove();
    	}
    }

    // Make sure the first breadcrumb has the .first class
    var crumbs = $("#breadcrumbs li");
    if (crumbs.length > 0) {
    	$(crumbs.get(0)).addClass("first");
    }

});



/********************
 dialog.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
*/

/**
 * Zen.Dialog class
 *
 * Wraps an AJS.Dialog with methods for interacting with it.
 *
 * Usage: use the constructor:
 *      var dialog = new Zen.Dialog("<p>Hi</p>");
 *      dialog.show();
 *
 * or the convenience method Zen.Dialog.dialogWithUrl() (which shows automatically unless the initializer callback says not to)
 *
 * Also note: a dialog doesn't go away when it closes, which, depending on usage, can cause of strange behavior when opening
 * the same dialog a second time. To blast the previous dialog, use:
 *      Zen.Dialog.clearPrevious();
 *
 * Once you have a dialog, you can access DOM elements using the "$" method, like so: dialog.$("#cancel-button")
*/
 
/**
 * @constructor
 * @param   html        {string}    [required]  the html that will be inserted into the the dialog, wrapped into a single containing DIV with class="zen-bin"
 * @param   options     {array}     [optional]
 *          selector    {string}                only the matching elements in the html will be displayed
 *          width:      {number}                desired width of the dialog in pixels, subject to browser window size; default is 800
 *          height:     {number}                desired height of the dialog in pixels, subject to browser window size; default is 450
 *          title:      {string}                title for the dialog
 *          noZenBin:   {boolean}               don't add a zen-bin class to the top-level DIV element in the panel
 *          cssId:      {string}                the CSS id to add to the top-level panel DIV element; default is none
 *          panelClass: {string}                class to add to the panel; default is "panel1"
 *          step:       {string}                the title for the dialog panel (only needed if more than one panel is expected); default is "Step 1"
*/
Zen.Dialog = function (html, options) {

    // If there's a previous, uncleaned up dialog, finish it off
    // Get rid of stuff that interferes with the next open
    var old = Zen.$("#zen-dialog");
    old.prev(".shadow").remove();
    old.remove();
    
    /* Instance variables */
    // The underlying AJS.dialog that does the actual presentation
    this.ajsDialog;
    
    // Process the options
    options = options || {};

    // Set up the dialog with the desired size
    var width = Math.min(Zen.$(window).width() - 48, options.width || 800);
    var height = Math.min(Zen.$(window).height() - 48, options.height || 450);
    this.ajsDialog = new AJS.Dialog(width, height, "zen-dialog");
    
    // Add the title
    var title = (options.title || "");
    this.ajsDialog.addHeader(title, "wizard-header");
    
    // Add the close button
    // var title = (options.title || "") + ;
    Zen.$(".dialog-components", this.ajsDialog.popup.element).append("<a id='wizard-close-button' href='#'>x</a>");
    
    // Add the html as the first panel
    this.addPanel(html, options);
};

/**
 * Toss the previous dialog found with dialogSelector. If no dialogSelector is given, "#zen-dialog" is used.
*/
// Zen.Dialog.clearPrevious = function(dialogSelector) {
//     // Lose any previous dialog and its shadow
//     var old = Zen.$(dialogSelector == null ? "#zen-dialog" : dialogSelector);
//     old.prev(".shadow").remove();
//     old.remove();
// }

/**
 * Convenience method to create a new Zen.Dialog using the results of an AJAX call to url with data.
 * The parameters are the same as new Zen.Dialog(), with an additional one to do any post-loading cleanup.
 * But note that the dialog is NOT returned -- it's created by the AJAX callback and sent to the
 * initializer.
 * @param   url         {string}    [required]  the URL that will be called via AJAX
 * @param   data        {array}     [optional]  the data that will be sent along with the AJAX call
 * @param   initializer {function}  [optional]  a method that will called after the dialog is constructed
 *                                              but before it is shown; with the dialog as the sole parameter;
 *                                              if the initializer returns true, the dialog won't be shown automatically
*/
Zen.Dialog.dialogWithUrl = function (url, data, options, initializer) {

    // Invoke the url via AJAX and put the results into a dialog
    jQuery.ajax({
        url: url, 
        data: data, 
        success: function (response) { 
            var newDialog = new Zen.Dialog(response, options);
            var show = true;
            if (initializer) show = !initializer.call(this, newDialog);
            if (show) newDialog.show();
        },
        error: function (xhRequest, textStatus, errorThrown) {
            ZW.alert(textStatus, errorThrown, {title: "Error Received from Server", width: 640, height: 360});
        }
    });
};

/**
 * Return the top-level DOM element for the dialog as a jQuery match set.
 * Note: this returns all elements in ALL panels. If you need to just look at the currently displayed panel,
 * use this.currentPanel() instead.
 * @param   selector    {string}                only the matching elements in the dialog will be returned
*/
Zen.Dialog.prototype.$ = function (selector) {
    var element = this.ajsDialog.popup.element;
    return selector ? element.find(selector) : element;
};

/**
 * Add a new button to the underlying AJS.dialog
 * @param   label       {string}    [required]  the text displayed on the button
 * @param   onclick     {function}  [required]  the method that will be invoked when the button is clicked
 * @param   className   {string}    [optional]  an optional css class for the button
*/
Zen.Dialog.prototype.addButton = function (label, onclick, className) {
    this.ajsDialog.addButton(label, onclick, className);
};

/**
 * Add a new panel to the dialog
 * @param   html        {string}    [required]  the html that will be inserted into the the dialog, wrapped into a single containing DIV with class="zen-bin"
 * @param   options     {array}     [optional]
 *          selector    {string}                only the matching elements in the html will be displayed
 *          noZenBin:   {boolean}               don't add a zen-bin class to the top-level DIV element in the panel
 *          cssId:      {string}                the CSS id to add to the top-level panel DIV element; default is none
 *          panelClass: {string}                class to add to the panel; default is "panel1"
 *          step:       {string}                the title for the dialog panel (only needed if more than one panel is expected); default is "Step 1"
*/
Zen.Dialog.prototype.addPanel = function (html, options) {

    // Extract the desired bits from the html if a selector was provided
    if (options.selector) html = Zen.$(html).find(options.selector);

    // Wrap the html in a div with the desired CSS selectors
    var contents = Zen.$("<div />");
    if (!options.noZenBin)  contents.addClass("zen-bin");
    if (options.cssId)      contents.attr("id", options.cssId);
    contents.html(html);

    // This simple dialog has just one page/panel
    this.ajsDialog.addPanel(options.step ? options.step : "Step 1", options.panelClass ? options.panelClass : "panel1");
    
    // Add the content to the dialog's panel and display it
    this.ajsDialog.getCurrentPanel().html(contents);
    
};

/**
 * Hide the dialog.
*/
Zen.Dialog.prototype.close = function () {

    if (this.ajsDialog && this.ajsDialog.popup) {
        this.ajsDialog.popup.element.prev(".shadow").remove();
        this.ajsDialog.popup.element.remove();
    }

    // Close the underlying AJS dialog
    this.ajsDialog.hide();
    
    // Make sure the toolbar is re-enabled
    Zen.Toolbar.enableToolbar();
};

/**
 * Return the top-level DOM element for the panel currently being displayed.
 * @param   selector    {string}                only the matching elements in the current panel will be returned
*/
Zen.Dialog.prototype.currentPanel = function (selector) {
    var element = this.$(".panel-body:visible");
    return selector ? element.find(selector) : element;
};

/**
 * Go to the panel with className
*/
Zen.Dialog.prototype.gotoPanel = function (panel) {
    this.ajsDialog.gotoPanel(panel);
};

/**
 * Return true if the dialog is currently being displayed.
*/
Zen.Dialog.prototype.isShowing = function () {
    return this.currentPanel(":visible").length;
};

/**
 * Display the dialog.
*/
Zen.Dialog.prototype.show = function () {

    // Make sure the toolbar is properly disabled
    Zen.Toolbar.disableToolbar();
    
    // Show the underlying AJS dialog
    this.ajsDialog.show();
    
    // Make sure the close button is wired
    // alert(this.$().length);
    var dialog = this;
    this.$("#wizard-close-button, .dialog-close-button").click(function () { dialog.close(); return false; });
};

/**
 * The following are "private" methods and are subject to change. Do not invoke them from outside this class.
*/

/**
 * Handle key presses while the dialog is displaying.
 * TODO: This doesn't appear to be called anymore!
*/
Zen.Dialog.prototype._keyListener = function (event) {
    
    // If I'm not visible, ignore the event
    if (!this.isShowing()) return true;

    // Try to click the "cancel" object when the user presses ESC
    if (event.which === Event.KEY_ESC) {
        this.close();

        // Needed to prevent endless loop in Safari 4 when dismissing the discard-changes panel with the ESC key
        event.preventDefault();
        return AJS.stopEvent(event);
    }
    
    // If the user hit return, and there's a default button, click it
    else if (event.which === Event.KEY_RETURN && this.$(".default-button").length) {
        event.preventDefault();
        AJS.stopEvent(event);
        return this.$(".default-button").addClass("click-state").click();
    }
    
    // Otherwise, disable the "submit" object when the user presses Return
    else if (event.which === Event.KEY_RETURN) {
        event.preventDefault();
        return AJS.stopEvent(event);
    }
    
    // Don't interfere with events we don't care about
    return true;
    
};



/********************
 create-page-links.js 
********************/

// Adjust the createPage links to use the including page, rather than the included page, as parent

AJS.toInit(function ($) {

	$(".createlink").each(function () {
		var cpHREF = $(this).attr("href");
        cpHREF = cpHREF.replace(new RegExp("fromPageId=[0-9]+"), "key=" + spaceKey + "&fromPageId=" + pageId);
		$(this).attr("href", cpHREF);
	});

});


/********************
 page-editor.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
 */

/**
 * The shortcut for Zen.PageEditor is: ZPE
 */

var ZPE = Zen.PageEditor = {

	// Return the contents of the page title field
	currentPageTitle: function () {
	    return Zen.$.trim(Zen.$("#content-title").val());
	},

    // Return the pageId associated with editableContent
    pageId: function (editableContent) {
        return Zen.$(editableContent).attr("data-page-id");
    },
    
    // Return the page sections (zen-section elements) on the page, but omit any fixed ones (coming from a master page)
    // If column is specified, return only those sections in that column ("left", "right", or "main")
    pageSections: function (column) {
        return Zen.$((column ? "#" + column.trim() + " " : "") + ".zen-editable-content > .zen-section").not(".from-master");
    },
    
    // Return the page sections (zen-section elements) on the page, but omit any fixed ones (coming from a master page)
    pageSectionsFromMaster: function () {
        return Zen.$(".zen-editable-content > .zen-section.from-master");
    },
    
    // Publish the entire page
    publishPage: function () {

        if (!isLicensed) return ZW.unlicensed("Publishing is available with a Zen license.");
        
        // If labels are required, confirm that the page is labelled
        if (requireLabel && !Zen.$("#labelsList .confluence-label").length) {
            ZW.alert("You must add at least one label to this page before it can be published.", "Label Required");
            return;
        }

	    // Give the user a chance to change their mind, but use a special panel so it's visually different and requires an explicit click
	    ZW.dialog(Zen.$("#publish-draft-form").clone().show(), 
	             {title: "Publish Draft", height: 300, width: 750, noZenBin: true, okButton: "Publish"}, 
	             function () { Zen.$("#zen-dialog #publish-draft-form").submit(); });
	    
	    Zen.$("#zen-dialog #publish-draft-form").submit( function () {
            Zen.$("#zen-dialog button.confirm").addClass("click-state");
	    });

        return false;             
    },
            
    // Revert all changes on the page
    revertPage: function () {

	    // Give the user a chance to change their mind, but use a special panel so it's visually different and requires an explicit click
	    ZW.dialog(Zen.$("#discard-draft-form").clone().show(), 
	             {title: "Permanently Discard Draft", height: 300, width: 750, noZenBin: true, okButton: "Permanently Discard Changes"}, 
	             function () { Zen.$("#discard-draft-form").submit(); });

        //      var dialog = new Zen.Dialog(Zen.$("#discard-draft-form").clone().show(), {title: "Permanently Discard Draft", height: 300});
        // dialog.$("#discard-draft-form");
        //         dialog.show();
        return false;             
    },

    // Stop all other animations so edit buttons don't go nuts during spastic mousing
    stopAnimations: function () {
        Zen.$(".zen-editable-content .control-panel").stop(true, true);
    },

    // Return the actual edit control embedded near the page title (once it's in place)
    titleEditControl: function () {
        return Zen.$("#edit-title-control");
    },
    
    // Check pageTitle for blanks and invalid characters. Display warnings to the user for failed tests.
    // Return true if pageTitle is valid
    validTitle: function(pageTitle) {
    
        // Page titles cannot be blank
         if (!Zen.$.trim(pageTitle).length) {
             ZW.alert("Titles can't be blank.");
             return false;
        }
    
        // Page titles cannot contain:    @ / \ | ^ # ; : [ ] { } < >
        var pattern = /[@\/\\\|^#;:\[\]{}<>]/;
        if (pattern.exec(pageTitle)) {
            ZW.alert("Titles cannot contain: @ / \ | ^ # ; : [ ] { } < >");
            return false;
        }                            
    
        // Page titles cannot start with any of these three sequences:   $  ..  ~
        pattern = /^[$~]|^\.\./;
        if (pattern.exec(pageTitle)) {
            ZW.alert("Titles cannot start with: $  ..  ~");
            return false;
        }
        
        return true;                            
    }
    
};

(function ($) {
    
    // Add the edit/publish control panel to the editable item (used by menu & footer)
	jQuery.fn.addControlPanel = function () {
	    
        return this.each(function() {
	    
            // Stop if the control panel is already there
            var $item = Zen.$(this);
            if ($item.find(".control-panel").length) return;

            // Add the control panel to the top of object that contains the editable page contents
            $item.prepend("<div class='control-panel'></div>");
            var $panel = $item.find(".control-panel");
        
            // Add the edit control and set its click action (the editable object is the control panel's parent)
            var title = "View the page that provides content for this section";
            var pageUrl;
            if ($(this).attr("id") == "zen-menu") pageUrl = Zen.menuPageUrl;
            else if ($(this).attr("id") == "zen-header") pageUrl = Zen.headerPageUrl;
            else pageUrl = Zen.footerPageUrl;
            $panel.append("<a href='" + contextPath + pageUrl + "' class='edit-control' title='" + title + "'></a>");

            // Activate the control panel when the user hovers over the zen-section
            $item.activateOnHover($panel);

        });
        
    };

    // Add the edit control panel to the zen section
	jQuery.fn.addEditControl = function () {

        return this.each(function() {
	    
            // Stop if the control panel is already there
            var $item = Zen.$(this);
            if ($item.find(".control-panel").length) return;
        
            // Add the control panel to the top of object that contains the editable page contents
            $item.prepend("<div class='control-panel'></div>");
            var $panel = $item.find(".control-panel");
        
            // Add the edit control and set its click action
            if (!isHistoricalVersion) {
                $panel.append("<a href='#' class='edit-control' title='Edit this section'></a>");
                $panel.find(".edit-control").click( function () { 
                    window.location = contextPath + "/zen/classic/edit" + context + "section.action" + 
                        "?pageId=" + pageId + 
                        "&sectionId=" + $item.attr("data-section-id");
                    return false;
                } );
            }

            // Activate the control panel when the user hovers over the zen-section
            // Don't hide the button if the brand overrides it to be always visible
            if (Zen.alwaysShowEditButtons) $panel.show();
            else $item.activateOnHover($panel);

        });
    };

    // Add the edit control panel to the zen sections that are supplied by a Zen master page
	jQuery.fn.addNoEditMasterControl = function () {
	    
	    return this.each(function() {
        
            // Stop if the control panel is already there
            var $item = Zen.$(this);
            if ($item.find(".control-panel").length) return;
        
            // Add the control panel to the top of object that contains the editable page contents
            $item.prepend("<div class='control-panel blocked'></div>");
            var $panel = $item.find(".control-panel");
        
            // Add the edit control and set its click action (the editable object is the control panel's parent)
            $panel.append("<a href='#' class='blocked-edit-control' title='This section defined by a master page.'></a>");
            $panel.find(".blocked-edit-control").click( function () { 
                ZW.alert("This section is defined by a master page.", "<a href='" + contextPath + Zen.masterPageUrl + "'>Visit the Zen master page</a> to change it.", {title: "Content Defined by Master"});
                return false;
            });

            // Activate the control panel when the user hovers over the zen-section (longer delay to not annoy the user)
            $item.activateOnHover($panel, "medium", 1000);

        });
    };

    // Add the blocked indicator to the editable item
	jQuery.fn.addBlockedPanel = function () {
	    
        return this.each(function () {
	    
            // Stop if the control panel is already there
            var $item = Zen.$(this);
            if ($item.find(".control-panel").length) return;
        
            // Add the control panel to the top of object that contains the editable page contents
            $item.prepend("<div class='control-panel'></div>");
            var $panel = $item.find(".control-panel");
        
            // Add the edit control and set its click action (the editable object is the control panel's parent)
            $panel.append("<a href='#' class='blocked-edit-control' title='You are not allowed to edit this section.'></a>");
            $panel.find(".blocked-edit-control").click( function () { 
                ZW.alert("This section is shared by all pages in the space. Contact the space administrator to make changes.");
                return false;
            });
        
            // Activate the control panel when the user hovers over the zen-section
            $item.activateOnHover($panel);

        });
        
    };

    // Add the edit control to the page title
	jQuery.fn.addTitleEditControl = function () {
    
        // Add the edit controls to each of the editable Zen theme content areas, making sure there's a pageId to support it
        return this.each(function () {

            var $this = $(this);

            // Add the title editor control to title if it's displayed, otherwise, append it to the regular control panel
            var $titleArea = $("#zen-page-title:visible", $this);
            if (!$titleArea.length) $titleArea = $(".control-panel", $this);
            $titleArea.append("<a href='#' id='edit-title-control' title='Edit the title of this page'>&nbsp;&nbsp;&nbsp;</a>");
            
            // The parent of $item is the regular zen-bin that users are used to editing
            ZPE.titleEditControl().click( function () { 
                
                // Ignore if the user can't edit
        	    if (!canEdit) return false;
            
                // Send an ajax call to get the page title form
                var pageType = isBlog ? "Blog Post" : "Page";
                Zen.Dialog.dialogWithUrl(ZW.zenActionUrl("edit" + context + "title"), {pageId: pageId}, {title: "Edit " + pageType + " Title", height: 220}, function (dialog) {
                    // Make the user acknowledge an immediate (non-draft) change to the title
                    dialog.$("#title-editor").submit(function () {
            
                        var newTitle = dialog.$("#content-title").val().trim();
                        
                        // If no change was made, stop
                        if (dialog.$("#title-editor input[name='originalTitle']").val().trim() == newTitle) {
                            ZW.alert("It doesn't look like you've made any changes.");
                            return false;
                        }
            
                        // Validate the title
                        if (!ZPE.validTitle(newTitle)) return false;

                        // Invoke the url via AJAX and add errors to the dialog, or redirect if successful
                        var form = dialog.$("#title-editor");
                        jQuery.ajax({
                            url: form.attr("action"), 
                            data: form.serialize(), 
                            success: function (response) {
                                if (response.indexOf("errorMessage") == -1) {
                                    window.location = response.trim();
                                }
                                else {
                                    if (!$("#errors", form).length) form.prepend("<div id='errors'></div>");
                                    $("#errors", form).html(response);
                                }
                            },
                            error: function (xhRequest, textStatus, errorThrown) {
                                ZW.alert(textStatus, errorThrown, {title: "Error Received from Server", width: 640, height: 360});
                            }
                        });
                        
                        return false;
                        
                    });
                });
                return false; 
            } );

            // If we're displaying in the title, animate it. Otherwise, let the regular control panel animate it.
            // Don't hide the button if the brand overrides it to be always visible
            if (!Zen.alwaysShowEditButtons && $("#zen-page-title:visible", $this).length) {
                ZPE.titleEditControl().hide();
                $titleArea.activateOnHover(ZPE.titleEditControl());
            }
            

        });
    };
    
    // Publish the current draft (it's already on the server)
	jQuery.fn.publish = function () {
        return this.filter(".zen-preview-draft").each(function () {

            // If labels are required, confirm that the page is labelled
            if (requireLabel && !Zen.$("#labelsList .confluence-label").length) {
                ZW.alert("You must add at least one label to this page before it can be published.", "Label Required");
                return;
            }
    	    // Give the user a chance to change their mind
    	    if (!ZW.confirm("This draft will be published for others to see.", "Click 'OK' to publish, or 'Cancel' to keep editing.")) return;

            // Tell the server to publish the current draft
            window.location = contextPath + "/zen/classic/publish" + context + ".action?pageId=" + ZPE.pageId(this) + "&viewPageId=" + pageId;
             
        });
	};
   
})(jQuery);

AJS.toInit(function ($) {

    // No editing if:
    // 1) the user doesn't have edit permission, or
    // 2) Zen isn't licensed
    if (!canEdit) return;
    
    // Add the edit controls to each of the editable Zen content areas
    ZPE.pageSections().addEditControl();
    ZPE.pageSectionsFromMaster().addNoEditMasterControl();
    
    // Wire the page publish/revert buttons
    $("#publishing-control-panel .publish-control").click(ZPE.publishPage);
    $("#publishing-control-panel .revert-control").click(ZPE.revertPage);
    if (hasDraft) $("#publishing-control-panel").css("display", "block");
    else $("#canvas #canvas-control-panel").activateOnHover($("#publishing-control-panel"));

    // Add the edit controls to menu and footer, but just make a simple pencil that links to the actual page
    $(".zen-editable-content[data-page-id]").each(function () {
        // Do nothing if the user isn't allowed to edit the underlying page
        if ($(this).attr("id") == "zen-menu" && !Zen.canEditMenu) return;
        if ($(this).attr("id") == "zen-header" && !Zen.canEditHeader) return;
        if ($(this).attr("id") == "zen-footer" && !Zen.canEditFooter) return;
        
        $(this).addControlPanel();
    });
    
    // Add the control panel to support editing, which is activated when the mouse enters the editable content area
    $("#zen-main .zen-section:first").addTitleEditControl();
    
});


/********************
 page-tree.js 
********************/

function zenTreeId(treeId) {
  return "#zen-tree-" + treeId;
}

function nodeId(pageId) {
  return "#node-" + pageId;
}

function toggleZenTreeChild(contextPath, treeId, pageId) {
  if (jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .toggle.open").size() > 0) {
    closeZenTreeChild(treeId, pageId);
  }
  else {
    if (jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .child ul").size() > 0) {
      openZenTreeChild(treeId, pageId);
    }
    else {
      loadZenTreeChild(contextPath, treeId, pageId);
    }
  }
}

function loadZenTreeChild(contextPath, treeId, pageId) {
  jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .child").html("<i>Loading...</i>");
  jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .child").load(contextPath + "/plugins/zen/pagetree.action?pageId=" + pageId + "&treeId=" + treeId);
  jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .toggle").addClass("open");
}

function openZenTreeChild(treeId, pageId) {
  jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .child > ul").slideDown("fast", function () {
    jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .toggle").addClass("open");
  });
}

function closeZenTreeChild(treeId, pageId) {
  jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .child > ul").slideUp("fast", function () {
    jQuery(zenTreeId(treeId) + " " + nodeId(pageId) + " > .toggle").removeClass("open");
  });
}


/********************
 textarea.js 
********************/

AJS.toInit(function ($) {
    
    // Insert text at the cursor (or replace the current selection), and select the text when finished if
    // selectAfterInsert is true
    jQuery.fn.insertText = function (text, selectAfterInsert) {
        var textarea = $(this).get(0);
        var oldText = this.val();
        
        if (document.selection && document.selection.createRange) {
            // for ie
            try {
                // Focus the textarea so IE will get the correct selection range.
                textarea.focus();
            }
            catch (e) {
                // ignore
            }
            var ieRange = document.selection.createRange();
            var caretPos = ieRange.duplicate();
            caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
            // currentForm.selectedText.value = ieRange.text;
        }
        else {
            // for netscape, mozilla, gecko
            // For Safari, if no selection, move to end of text
            var sel = "";
            var sel1 = oldText;
            var sel2 = "";
            if (textarea.selectionEnd) {
                // Strange Safari bug that doesn't allow user to go to the end of the content and carriage return 
                // down to insert something on the first edit.
                // textarea.selectionEnd shows a number smaller than the textarea content length (appears constrained
                // by the textarea's value's length before editing; one less if no return at the end of the original value,
                // and equal to the original value's length if there is a return)
                // alert($(this).attr("originalValue").length + " : " + oldText.length + " : " + textarea.selectionEnd);
                sel = oldText.substr(textarea.selectionStart, textarea.selectionEnd - textarea.selectionStart);
                sel1 = textarea.value.substr(0, textarea.selectionStart);
                sel2 = textarea.value.substr(textarea.selectionEnd);
            }
            // currentForm.selectedText.value = textAreaObject.sel;

            this.val(sel1 + text + sel2);
            textarea.focus();
            textarea.selectionStart = sel1.length + (selectAfterInsert ? 0 : text.length);
            textarea.selectionEnd = sel1.length + text.length;
        }

    };
    
});


/********************
 page-view.js 
********************/

// {new-window} macro support:
// Make sure all "new window" links open in a new window, and by default, all external links open a new window
AJS.toInit( function ($) {
    $(".new_window a, .external-link").attr("target", "_blank");
});

// Override the default search form to add the spacekey
AJS.toInit( function ($) {
    $("#quick-search .hidden.parameters").append("<input type='hidden' name='where' value='" + spaceKey + "'>");
});

// Adjust the labels
AJS.toInit( function ($) {
    var title = $("#labels-section .section-header .section-title").remove();
    $("#labels-section .labels-editor").prepend("<div class='title'>" + title.text() + "</div>");
});

// Make sure empty editable-content areas can still present an edit icon 
AJS.toInit( function ($) {
    if (zen4) return;
    $(".zen-editable-content").each(function () {
       if (!$(":visible", this).length) {
           $(this).addClass("empty").append($("<div />").addClass("zen-bin placeholder"));
       }
    });
});

// Make sure any in-page anchors scroll with animation, and consider the toolbar
AJS.toInit( function ($) {
   $("a[href^='#']").filter(function() { return $(this).attr("href").length > 1}).click(Zen.adjustAnchorScrolling); 
});

// Replace the attachment links to keep unpublished attachments from appearing
Zen.adjustAttachmentsForPublishing = function ($) {
    $("#attachment-history .adjustments").each(function() {
       $("img[src='" + $(this).attr("data-current") + "']").attr("src", $(this).attr("data-adjustment"));
    });
};

// Adjust the canvas to account for padding
Zen.adjustCanvas = function ($) {

	Zen.canvasFixedWidth = 0;

    if (isStretchy) {
        $("body").css({padding: "0 " + zenBodyPadding});
    }
    else {
        var padding = $("#canvas").innerWidth() - $("#canvas").width();
        Zen.canvasFixedWidth = $("#canvas").width() - padding;

        // The blog list placeholder test is in place to fix ZEN-141
        if (!isBlogListPlaceholder) $("#canvas").css({width: Zen.canvasFixedWidth});

        // IE7 hack to get toolbar to center over the canvas (otherwise it floats to right edge of window)
        // if (Zen.ie7) $("#zen-toolbar-holder").css({width: Zen.canvasFixedWidth, margin: "auto 0"});
    }
};

// Scroll to the given anchor name, but adjust to provide space for the toolbar
// Note: doesn't always work on page reloads (for example, firefox)
Zen.scrollToAnchor = function (name) {
	var anchor = Zen.$("a[name='" + name + "']");
	if (!anchor.length) return;
	var offset = anchor.offset();
	var newTop = offset.top;
	if (Zen.firefox) newTop -= 60;
	else if (Zen.safari) newTop -= 40;
	else if (Zen.ie) newTop -= 40;
    // else if (Zen.ios) newTop -= Zen.$("body").scrollTop();
	Zen.$("body").animate({scrollTop: newTop}, 500);
};

// Adjust in-page anchor links to scroll nicely and leave space for the toolbar
Zen.adjustAnchorScrolling = function (event) {
    event.preventDefault();
    var anchor = Zen.$(this).attr("href");
    anchor = anchor.split("#")[1];
    Zen.scrollToAnchor(anchor);
}



/********************
 blog-post.js 
********************/

// Adjust the blog calendar
AJS.toInit( function ($) {
    // Dump everything but the calendar
    $("#blog-calendar > :not(.blogcalendar)").remove();

    // Move the blog post calendar to whichever column is available, preferring the right column.
    var $column = !$("#zen-right .zen-section").length && $("#zen-left .zen-section" ).length ? $("#zen-left") : $("#zen-right");
    $column.prepend($("#blog-calendar")).prepend($(".zen-title"));
    ZPD.recalculateColumns();
    
    // Make it visible
    $("#blog-calendar").show();
});

// For blog lists, move the read more into the final paragraph of the excerpt
AJS.toInit( function ($) {
    $(".blog-list-more-link").each(function () {
        $(this).prev().append($(this));
    })
});


/********************
 comments.js 
********************/

(function ($) {
    
    // Toggle the edit control when mousing over a editable content area
    jQuery.fn.toggleCommentControls = function (mouseOver) {
        return this.each(function () {

            // Stop all animations so controls don't go nuts during spastic mousing
            var allControls = Zen.$("#comments-section .comment .comment-actions ul");
            allControls.stop(true, true);
            
            // Animate the coming and going of the menu
            // The .hide is used instead of fadeOut because fadeOut wasn't working
            var options = Zen.$(".comment-actions ul", this);
            if (mouseOver) options.wait(500).fadeIn("fast");
            else options.hide();

        });
    };

})(jQuery);


// After the page loads
AJS.toInit(function ($) {

    // Activate the comment controls when the mouse enters the comment area
    Zen.$("#comments-section .comment").each(function () {
        Zen.$(this).hover(
            function () { Zen.$(this).toggleCommentControls(true) },
            function () { Zen.$(this).toggleCommentControls(false) }
        );
    });
    
    // If the comments section is showing but completely empty, display a simple message (ZEN-253)
    if (!$("#comments").text().trim()) $("#comments").append("<div class='title'>No Comments</div>");

});

// Adjust the comments window to be full width to avoid issues with the complex RTE being too wide.
AJS.toInit( function ($) {
    $("#comments #wysiwyg").append("<a href='' id='fix-rte-width'>Can't see the full editor? Click to toggle full width.</a>");
    $("#comments #wysiwyg #fix-rte-width").click(function () { 
        $("#expando").click();
        return false;
    } );
});


/********************
 table.js 
********************/

/*
AJS.toInit(function ($) {

	jQuery.fn.focusCell = function () {
        return this.filter(".confluenceTh, .confluenceTd").each(function () {
            
            // If there's no focus/input handler, add one to this cell and give it the "real" focus
            if (!$("#key-press-form").length) {
                // Create a form that can handle keypress events, and "hide" in the cell. Can't use display:none because browsers will ignore it
                $(this).append("<form id='key-press-form' onsubmit='return false' style='margin-top:-10000px;margin-left:-10000px'><input type='text' size='1'/></form>");
                $("#key-press-form input").keydown(function (event) { $(this).moveCell(event) });
            }

            // Make the keypress handler take focus. This is the browser's focus element, not the simulated one in the table
            $("#key-press-form input").focus();

            // Make the receiver the cell in focus
            $(".confluenceTh, .confluenceTd").removeClass("has-edit-focus");
            $(this).addClass("has-edit-focus");
            
            // Make sure the window scrolls to view the cell in focus
            var toolbarHeight = $("#zen-toolbar-holder").outerHeight();
            var cellOffset = $(this).offset();
            var cellTop = cellOffset.top;
            var cellBottom = cellTop + $(this).outerHeight();
            var cellLeft = cellOffset.left;
            var cellRight = cellLeft + $(this).outerWidth();
            var viewTop = $(window).scrollTop();
            var viewBottom = viewTop + $(window).height();
            var viewLeft = $(window).scrollLeft();
            var viewRight = viewLeft + $(window).width()
            // $(this).parent().parent().parent().find("td:first").text(viewTop + "," + viewLeft + ":" + viewBottom + "," + viewRight + " " + cellTop + "," + cellLeft + ":" + cellBottom + "," + cellRight + " " + toolbarHeight);
            if (cellTop < viewTop + toolbarHeight) {
                var newTop = cellTop - toolbarHeight;
                $(window).scrollTop(newTop);
            }
            if (cellBottom > viewBottom) {
                var newTop = cellBottom - $(window).height();
                $(window).scrollTop(newTop);
            }
            if (cellLeft < viewLeft) {
                var newLeft = cellLeft;
                $(window).scrollLeft(newLeft);
            }
            if (cellRight > viewRight) {
                var newLeft = cellRight - $(window).width();
                $(window).scrollLeft(newLeft);
            }
        });
	};
	
	jQuery.fn.moveCell = function (event) {
        return this.each(function () {

            // Find the table's selected cell
            var currentCell = $(".has-edit-focus");

            // Stop if we're not focused on the table
            if (!currentCell.length) return;

            // Determine the next cell based on the move direction from the event
            var nextCell;
            switch(event.which) {
                case Event.KEY_RETURN:
                    currentCell.removeClass("has-edit-focus");
                    break;
                case Event.KEY_ESC:
                    currentCell.removeClass("has-edit-focus");
                    break;
                case Event.KEY_LEFT:
                    nextCell = currentCell.prev();
                    break;
                case Event.KEY_UP:
                    var cell = currentCell.prevAll().length;
                    var row = currentCell.parent().prev();
                    nextCell = row.find(".confluenceTh, .confluenceTd").get(cell);
                    break;
                case Event.KEY_RIGHT:
                    nextCell = currentCell.next();
                    break;
                case Event.KEY_DOWN:
                    var cell = currentCell.prevAll().length;
                    var row = currentCell.parent().next();
                    nextCell = row.find(".confluenceTh, .confluenceTd").get(cell);
                    break;
            }
            
            // Focus on the "next" cell, if one was found
            $(nextCell).focusCell();

        });
	};
	
    // Make the table cells sensitive to clicks in order to similuate focus
    $(".confluenceTh, .confluenceTd").click(function () { $(this).focusCell() });
    
});
*/

AJS.toInit(function ($) {

	focusCell = function () {
            // Make the receiver the cell in focus
            $(".confluenceTh, .confluenceTd").removeClass("has-edit-focus");
            $(this).addClass("has-edit-focus").focus();

            // Make sure the containing element scrolls to view the cell in focus
            // var toolbarHeight = $("#zen-toolbar-holder").outerHeight();
            // var cellOffset = $(this).offset();
            // var cellTop = cellOffset.top;
            // var cellBottom = cellTop + $(this).outerHeight();
            // var cellLeft = cellOffset.left;
            // var cellRight = cellLeft + $(this).outerWidth();
            // var container = $(this).parents(".zen-editable-content");
            // // alert(container.html());
            // var viewTop = $(window).scrollTop();
            // var viewBottom = viewTop + $(window).height();
            // var viewLeft = $(container).scrollLeft();
            // var viewRight = viewLeft + $(container).width()
            // $("#table-test").html("toolbarHeight: " + toolbarHeight + " " + "cellWidth:" + $(this).outerWidth() + " cellHeight:" + $(this).outerHeight() + "<br />" + 
            //                     viewTop + "," + viewLeft + ":" + viewBottom + "," + viewRight + "<br />" + 
            //                     cellTop + "," + cellLeft + ":" + cellBottom + "," + cellRight);
            // var needsScroll = (cellTop < viewTop + toolbarHeight) ||
            //                  (cellBottom > viewBottom) || 
            //                  (cellLeft < viewLeft) || 
            //                  (cellRight > viewRight);
            // 
            // if (!needsScroll) event.preventDefault();
            event.preventDefault();
            return false;

	};
	
	moveCell = function (event) {

            // Find the table's selected cell
            var currentCell = $(".has-edit-focus");

            // Stop if we're not focused on the table
            if (!currentCell.length) return;

            // Determine the next cell based on the move direction from the event
            var nextCell;
            switch(event.which) {
                case Event.KEY_RETURN:
                    currentCell.removeClass("has-edit-focus");
                    break;
                case Event.KEY_ESC:
                    currentCell.removeClass("has-edit-focus");
                    break;
                case Event.KEY_LEFT:
                    nextCell = currentCell.prev();
                    break;
                case Event.KEY_UP:
                    var cell = currentCell.prevAll().length;
                    var row = currentCell.parent().prev();
                    nextCell = row.find(".confluenceTh, .confluenceTd").get(cell);
                    nextCell = $(nextCell || currentCell);
                    break;
                case Event.KEY_RIGHT:
                    nextCell = currentCell.next();
                    break;
                case Event.KEY_DOWN:
                    var cell = currentCell.prevAll().length;
                    var row = currentCell.parent().next();
                    nextCell = row.find(".confluenceTh, .confluenceTd").get(cell);
                    nextCell = $(nextCell || currentCell);
                    break;
            }
            
            // Stop if there's no next cell
            if (!nextCell) return;
            
            // If we'll step off the table, just stop
            if (!nextCell.length) nextCell = currentCell;
            
            // Focus on the "next" cell, if one was found
            focusCell.call(nextCell);

	};
	
	unfocus = function (event) {
	    // Do nothing if the user clicked on a table cell
	    if ($(event.target).parents(".confluenceTable").length) return;
	    
	    // Remove the focus from the table
	    var currentCell = $(".has-edit-focus");
	    if (currentCell.length) currentCell.removeClass("has-edit-focus");
	};
	
    // Make the table cells sensitive to clicks in order to similuate focus
    // $(document).mousedown(unfocus);
    // $(".confluenceTh, .confluenceTd").click(focusCell);
    // $(document).keydown(function (event) { moveCell(event); });
    // $("#canvas").prepend($("<div />").attr("id", "table-test"));
    
});



/********************
 zen-section.js 
********************/

var ZPD = Zen.PageDesigner = {
    
    moveSelector:           ".move-here",
    marker:                 Zen.$("<div class='move-here'>&nbsp;</div>"),
    movingBin:              false,
    movingImage:            false,
    movingImagePosition:    false,
    listeningBin:           false,
    movingBinDragOffsetX:   false,
    movingBinDragOffsetY:   false,
    originalColumn:         false,
    originallyBefore:       false,
    startingSpot:           false,
    
    // Create a handy way to grab elements in the designer
    $: function (selector) {
        return ZPD.designer.find(selector);
    },
    
    // If section is a tab (or if section is null, use the current section), return url with the tab parameter set
    adjustForTab: function (url, section) {
        if (ZPD.isTab(section)) url += "&tabId=" + ZPD.tabbedSectionFor(section).attr("data-tab");
        if (ZPD.tabbedSectionExists()) {
            var tabId = ZPD.tabbedSection().attr("data-tab");
            url += "&tabSectionId=" + tabId;
            url += "&lastTabSectionId=" + Zen.$(".zen-section[data-tab='" + tabId + "']:last").attr("data-section-id");
        }
        return url;
    },
    
    // Close the section menu (used by iPad)
    cancelSectionMenu: function (event) {
        ZPD.sectionMenu().fadeOut();
        Zen.$("body").unbind("touchstart");
    },
    
    // Return how many columns are showing (includes the center column)
    columnCount: function () {
        var columns = 1;
        if (Zen.$("#zen-left  .zen-section").length) columns += 1;
        if (Zen.$("#zen-right .zen-section").length) columns += 1;
        return columns;
    },
    
    currentColumn: function () {
        return ZPD.movingBin.parents("[data-column]");
    },
    
    // Return the section the user is currently working (using the section menu)
    currentSection: function () {
        return ZPD.findSection(ZPD.currentSectionId());
    },
    
    // Return the section the user is currently working (using the section menu)
    findSection: function (sectionId) {
        return Zen.$("#zen-section-" + sectionId);
    },
    
    // Return the id of section the user is currently working (using the section menu)
    currentSectionId: function () {
        return ZPD.sectionMenu().attr("data-section-id");
    },
    
    // Return true if the current section is in the main column
    currentSectionInCenterColumn: function () {
        return ZPD.currentSection().parents(".zen-editable-content").attr("id") == "wiki-body";
    },

    // Execute the chosen section menu item
    doSectionMenu: function () {
        
        // Make sure the menu item's url includes the correct section and whether it's a tab or not
        var url = ZPD.adjustForTab(Zen.$(this).attr("href") + ZPD.currentSectionId());
        var doIt = function() { window.location =  url };

        // If the link includes a confirmation message, use it to prompt the user before continuing
        var message1 = Zen.$(this).attr("data-confirm-message-1");
        if (message1) {
            var message2 = Zen.$(this).attr("data-confirm-message-2");
            var title = Zen.$(this).attr("data-confirm-title");
            var okButton = Zen.$(this).attr("data-ok-button");
            var cancelButton = Zen.$(this).attr("data-cancel-button");
            var options = title ? {title: title} : {};
            if (okButton) options.okButton = okButton;
            if (cancelButton) options.cancelButton = cancelButton;
            ZW.confirm(message1, message2, options, doIt);
        }
        else {
            doIt();
        }
        
        return false;
    },
    
    editSectionDesign: function () {

        // Recycle the dialog and show the design editor
        // Zen.Dialog.clearPrevious();

        // Copy the designer that's baked into the page
        ZPD.designer = Zen.$("#section-design-editor").clone().removeClass("hidden");
        ZPD.demo = ZPD.$(".section-demo");
        try {
            ZPD.initializeDemo();            
        }
        catch (err) {
            ZW.alert("Sorry, an error occurred", err);
            return false;
        }
        
        // Block the form from submitting by pressing return or any action explicitly click the Apply button
        ZPD.canSubmit = false;
        ZPD.$("#design-editor-form").submit(function() {return ZPD.canSubmit;});
        ZPD.$("#apply").click(function() {ZPD.canSubmit = true; ZPD.$("#submit").click();});
        
        // Create and show the dialog
        var dialog = new Zen.Dialog(ZPD.designer, {title: "Section Designer", width: Zen.$("#canvas").width() + 40, height: 640, noZenBin: true});
        dialog.show();

        // Stop the default menu-item click action from firing
        return false;
    },

    // Return true if event occurred inside element
    eventInsideElement: function (event, element) {
        var spot = ZPD.eventLocation(event);
        var position = Zen.$(element).offset();
        return  spot.X >= position.left && 
                spot.Y >= position.top && 
                spot.X <= (position.left + Zen.$(element).outerWidth()) &&
                spot.Y <= (position.top + Zen.$(element).outerHeight()); 
    },

    // Return the first element identified by selector in which event occurred
    eventInWhichElement: function (event, selector) {
        return Zen.$(selector).filter(function() { return ZPD.eventInsideElement(event, this); }).first();
    },
    
    // Return the location appropriate for browser or touch location calculations
    eventLocation: function (event) {
        var e = event.originalEvent.targetTouches ? event.originalEvent.targetTouches[0] : event;
        return {X: e.pageX, Y: e.pageY};
    },
    
    // Return the section the user is currently working (using the section menu)
    findSection: function (sectionId) {
        return Zen.$("#zen-section-" + sectionId);
    },
    
    initializeDemo: function () {
        
        // Make sure the form knows which section we're messing with
        ZPD.$("input[name='sectionId']").val(ZPD.currentSectionId());
        
        var $section = ZPD.currentSection();
        
        // Make the section-design-preview area match the column that the section came from
        var column = $section.parents(".zen-editable-content");
        ZPD.$("#section-design-preview").width(column.innerWidth()).css({padding: "20px"});

        // Set the initial values of the design option fields
        ZPD.$("#section-design-float").val($section.attr("data-float"));
        if ($section.attr("data-no-background")) ZPD.$("#section-design-no-background").attr("checked", "checked");
        if ($section.attr("data-no-border")) ZPD.$("#section-design-no-border").attr("checked", "checked");
        ZPD.$("#section-design-width").val($section.attr("data-width"));
        ZPD.$("#section-design-height").val($section.attr("data-height"));
        ZPD.$("#section-design-margin").val($section.attr("data-margin"));
        ZPD.$("#section-design-padding").val($section.attr("data-padding"));
        ZPD.$("#section-design-background-color").val($section.attr("data-background-color"));
        ZPD.$("#section-design-background-image").val($section.attr("data-background-image"));
        ZPD.$("#section-design-background-position").val($section.attr("data-background-position"));
        ZPD.$("#section-design-background-repeat").val($section.attr("data-background-repeat"));

    	// Wire the design option fields to be reflected in the demo
    	ZPD.$("input, select").change(ZPD.updateDemo);

        // Make the demo reflect the current settings
        ZPD.updateDemo();

    },
    
    insertAfterSection: function () {
        window.location = ZPD.adjustForTab(Zen.$(this).attr("href") + ZPD.currentSectionId());
        return false;
    },
    
    insertBeforeSection: function () {
        // Get the next section after the insertion point, if none, we're appending to the column
        return ZPD.movingBin.next(".zen-section");
    },

    isDragging: function () {
        // We're dragging if there's a bin (section) that's moving
        return ZPD.movingBin;
    },
    
    isScrolling: function () {
        return ZPD.isScrollingDown() || ZPD.isScrollingUp();
    },
    
    isScrollingDown: function () {
        return  ZPD.scrollDownAmount > 0;
    },
    
    isScrollingUp: function () {
        return  ZPD.scrollUpAmount > 0;
    },
    
    // Return true if section is a tabbed section. If section is null or missing, use the currently focused section
    isTab: function (section) {
        return ZPD.tabbedSectionFor(section).length;
    },
    
    justEditedSection: function () {
        var loc = window.location.toString();
        var flag = "zen-section=";
        var spot = loc.indexOf(flag);
        var sectionId = spot == -1 ? false : loc.substring(spot + flag.length);
        return ZPD.findSection(sectionId);
    },
    
    listenForDrag: function (event) {
        
        event.preventDefault();
        //event.stopImmediatePropagation();
        
        ZPD.listeningBin = Zen.$(this).parents(".zen-section");
        ZPD.movingImagePosition = ZPD.listeningBin.offset();
        var spot = ZPD.eventLocation(event);
        ZPD.movingBinDragOffsetY = spot.Y - ZPD.movingImagePosition.top;
        ZPD.movingBinDragOffsetX = spot.X - ZPD.movingImagePosition.left;
    },

    moveDragImage: function (x, y) {
        ZPD.movingImagePosition.left += x;
        ZPD.movingImagePosition.top  += y;
        var offsetX = ZPD.movingBinDragOffsetX;
        var offsetY = ZPD.movingBinDragOffsetY;
        var canvasTop = Zen.$("#canvas").position().top;
        var canvasLeft = Zen.$("#canvas").position().left;
        var canvasRight = canvasLeft + Zen.$("#canvas").width();
        var canvasBottom = canvasTop + Zen.$("#canvas").height();
        var imageWidth = ZPD.movingImage.outerWidth();
        var imageHeight = ZPD.movingImage.innerHeight();
        
        // Make sure the image doesn't move above the canvas
            // if ((ZPD.movingImagePosition.top - offsetY) < canvasTop) ZPD.movingImagePosition.top = canvasTop + offsetY;

        // Make sure the image doesn't move below the canvas
        // if ((ZPD.movingImagePosition.top - offsetY + imageHeight) > canvasBottom) ZPD.movingImagePosition.top = canvasBottom - imageHeight + offsetY;
        
        // Make sure the image doesn't move to the left of the canvas
        // if ((ZPD.movingImagePosition.left - offsetX) < canvasLeft) ZPD.movingImagePosition.left = canvasLeft + offsetX;
        
        // Make sure the image doesn't move to the right of the canvas
        // if ((ZPD.movingImagePosition.left - offsetX + imageWidth) > canvasRight) ZPD.movingImagePosition.left = canvasRight - imageWidth + offsetX;

        ZPD.movingImage.offset(ZPD.movingImagePosition);
        
        // ZPD.relocateBin(ZPD.movingImagePosition);
    },

    moveMarker: function (bin, before) {
        if (before) Zen.$(bin).before(marker);
        else Zen.$(bin).after(marker);
    },

    recalculateColumns: function () {
        var hasLeft  = Zen.$("#zen-left  .zen-bin").length;
        var hasRight = Zen.$("#zen-right .zen-bin").length;
        // Zen.$("#zen-page-title").text(hasLeft + " " + hasRight);
        var size = Zen.columnWidths.main;
        if      (hasLeft && hasRight) size = Zen.columnWidths.both;
        else if (hasLeft)  size = Zen.columnWidths.left;
        else if (hasRight) size = Zen.columnWidths.right;
        Zen.$("#zen-main" ).css({width: size.main});
        Zen.$("#zen-left" ).css({width: size.left }).toggleClass("hidden", !hasLeft );
        Zen.$("#zen-right").css({width: size.right}).toggleClass("hidden", !hasRight);
    },
    
    relocateBin: function (spot) {
        // Get the zen-sections that the mouse is over or "above", the first in the list is the one we want
        // var bins = eventInWhichElement(event, "#wiki-body, .zen-column").children(".zen-section");
        var targetColumn = ZPD.whichColumn(spot);
        var bins = targetColumn.children(".zen-section:not(.from-master)");

        // Zen.$("#zen-page-title").text(whichColumn(event).attr("id"));
        // var spot = ZPD.eventLocation(event);
        var bin = bins.filter(function() { return spot.Y <= (Zen.$(this).offset().top + Zen.$(this).outerHeight(false)); }).first();
        
        // If we have a bin, decide whether we are above or below its mid-point, which determines which side the drop will happen
        if (bin.length) {
            var above = spot.Y < (bin.offset().top + bin.outerHeight() / 2);
            
            // If the bin is the one we're moving, or the moving bin is adjacent to the spot we're moving to, 
            // it's not going anywhere, so don't bother
            if (bin.hasClass("moving") || (above && bin.prev(".moving").length) || (!above && bin.next(".moving").length)) return;

            // Place the moving bin before or after the target bin as calculated above
            if (above) Zen.$(bin).before(ZPD.movingBin);
            else Zen.$(bin).after(ZPD.movingBin);
        }
        else {
            // If we don't have a bin, and there's bottom extras from the master, move the bin above the extras
            var bottomExtras = targetColumn.children(".zen-section[data-position='bottom']");
            if (bottomExtras.length) {
                Zen.$(bottomExtras.first()).before(ZPD.movingBin);
            }
            else {
                // If we don't have a bin, just move the moving bin to the column
                targetColumn.append(ZPD.movingBin);
            }
        }
        
        ZPD.recalculateColumns();
        
    },
    
    removeMarker: function (event) {
        Zen.$(moveSelector).remove();
    },
    
    removeSection: function () {
        // Add some clues about the section we're removing
        var justTheText = ZPD.currentSection().clone();
        justTheText.find(".hidden, #zen-page-title, .meta-data").remove();
        justTheText = justTheText.text().trim();
        if (justTheText.length > 160) justTheText = justTheText.substring(0, 160) + "...";
        var msg = justTheText.length ? "\"" + justTheText + "\"" : "(empty section)";
        Zen.$(this).attr("data-confirm-message-2", msg);
        return ZPD.doSectionMenu.call(this);
    },
    
    scrollDown: function (mouseMove) {
        // Zen.$("body").stop();
        if (mouseMove) Zen.$("body").stop();
        if (!ZPD.isScrollingDown()) return;
        Zen.$("body").animate({scrollTop: Zen.$("body").scrollTop() - ZPD.scrollDownAmount}, 5, ZPD.scrollDown);
        // Move the moving bin by the scroll amount (only if not caused by a mouse move)
        if (!mouseMove) {
            ZPD.moveDragImage(0, - ZPD.scrollDownAmount);
        }
    },
    
    scrollUp: function (mouseMove) {
        // Zen.$("body").stop();
        if (mouseMove) Zen.$("body").stop();
        if (!ZPD.isScrollingUp()) return;
        Zen.$("body").animate({scrollTop: Zen.$("body").scrollTop() + ZPD.scrollUpAmount}, 5, ZPD.scrollUp);
        // Move the moving bin by the scroll amount (only if not caused by a mouse move)
        if (!mouseMove) {
            ZPD.moveDragImage(0, ZPD.scrollUpAmount);
        }
    },

    // Return the section menu
    sectionMenu: function () {
        return Zen.$("#section-menu");
    },
    
    // Display the coordinates of spot in the page title for debugging
    showLocation: function (spot) {
        Zen.$("#zen-page-title").text(spot.X + ", " + spot.Y + " / " + Zen.$(window).height());
    },
    
    // Show or hide the "remove section" menu item (and it's spacer) depending on whether show is true or false
    showRemoveSectionMenuItem: function (show) {
        Zen.$("#section-menu-remove").parent().prev("li.spacer").toggle(show);
        Zen.$("#section-menu-remove").parent().toggle(show);
    },
    
    showSectionMenu: function (event) {
        // event.preventDefault();
        // event.stopImmediatePropagation();
        // ZPD.stopDragging();

        var $section = Zen.$(this).parents(".zen-section");
        var $sectionMenu = ZPD.sectionMenu();
        $sectionMenu.attr("data-section-id", $section.attr("data-section-id"));
        
        // Put the menu in the canvas, but relative to the section's location
        var top = $section.offset().top + 6;
        var left = $section.offset().left + $section.outerWidth() - $sectionMenu.width() - 8;
        $sectionMenu.css({top: top, left: left}).fadeIn();
        
        // Adjust the toggle tab menu item text
        var anchorTab = ZPD.isTab() && $section.attr("data-section-id") == $section.attr("data-tab") && ZPD.tabbedSectionsWith($section).length > 1;
        Zen.$("#section-toggle-tab").text(ZPD.isTab() ? "Remove From Tabs" : "Become Tab");
        ZPD.showToggleTabSectionMenuItem(ZPD.currentSectionInCenterColumn() && !anchorTab);
        
        // If we're the last column in the center section, disable the remove menu
        // Also, disallow removal of anchor tabs
        var $column = $section.parents(".zen-editable-content");
        // Zen.$("#section-menu-remove").toggle($column.attr("id") != "wiki-body" || $column.find(".zen-section").length > 1);
        ZPD.showRemoveSectionMenuItem(!anchorTab && (!ZPD.currentSectionInCenterColumn() || $column.find(".zen-section").length > 1));

        // On iPad, make sure the section menu goes away when the user touches elsewhere
        Zen.$("body").bind("touchstart", ZPD.cancelSectionMenu);

        return false;
    },
    
    // Show or hide the "toggle tab" menu item (and it's spacer) depending on whether show is true or false
    showToggleTabSectionMenuItem: function (show) {
        Zen.$("#section-toggle-tab").parent().toggle(show);
    },
    
    startDragging: function (spot) {
        ZPD.movingBin = ZPD.listeningBin;
        ZPD.listeningBin = false;
        ZPD.originalColumn = ZPD.whichColumn(spot);
        ZPD.originallyBefore = ZPD.insertBeforeSection();
        ZPD.startingSpot = spot;
        ZPD.movingImage = ZPD.movingBin.clone()
            .addClass("moving-image")
            .width(ZPD.movingBin.width())
            .height(Math.min(ZPD.movingBin.height(), 200))
            .css({
                overflow:       "hidden", 
                marginTop:      ZPD.movingBin.css("margin-top"), 
                marginRight:    ZPD.movingBin.css("margin-right"), 
                marginBottom:   ZPD.movingBin.css("margin-bottom"), 
                marginLeft:     ZPD.movingBin.css("margin-left"), 
                paddingTop:     ZPD.movingBin.css("padding-top"), 
                paddingRight:   ZPD.movingBin.css("padding-right"), 
                paddingBottom:  ZPD.movingBin.css("padding-bottom"), 
                paddingLeft:    ZPD.movingBin.css("padding-left")
            });
        Zen.$("#canvas").append(ZPD.movingImage);
        ZPD.movingBin.addClass("moving");
        Zen.$("#zen-header-back").addClass("no-select-webkit");
        Zen.$(".from-master").addClass("dim-out");
    },
    
    stopDragging: function (event) {

        // If we're not dragging, don't bother
        if (!ZPD.isDragging()) {
            ZPD.listeningBin = false;
            return;
        }
        
        ZPD.scrollUpAmount = false;
        
        var newColumn = ZPD.currentColumn();
        var insertBefore = ZPD.insertBeforeSection();
        var oldColumnName = ZPD.originalColumn.attr("data-column") ? ZPD.originalColumn.attr("data-column") : "";
        var newColumnName = newColumn.attr("data-column") ? newColumn.attr("data-column") : "";
                            
        
        // If there was a move, save it, otherwise, just stop the drag
        if (oldColumnName != newColumnName || 
            insertBefore.attr("data-section-id") != ZPD.originallyBefore.attr("data-section-id")) {
            // alert(contextPath + "/zen/page/movepagesection.action?pageId=" + pageId +
            //     "&sectionId=" + ZPD.movingBin.attr("data-section-id") + 
            //     (newColumn.attr("data-column") ? "&column=" + newColumn.attr("data-column") : "") + 
            //     (insertBefore.length ? "&insertBefore=" + insertBefore.attr("data-section-id") : ""));
            window.location = contextPath + "/zen/page/movepagesection.action?pageId=" + pageId +
                "&sectionId=" + ZPD.movingBin.attr("data-section-id") + 
                (newColumn.attr("data-column") ? "&column=" + newColumn.attr("data-column") : "") + 
                (insertBefore.length ? "&insertBefore=" + insertBefore.attr("data-section-id") : "");
        }

        // Remove any webkit select patches
        Zen.$(".no-select-webkit").removeClass("no-select-webkit");
        
        // Make sure the moving visual feedback is gone
        Zen.$(".zen-section.moving").removeClass("moving");
        Zen.$(".dim-out").removeClass("dim-out");
        
        // If we had a mouse down, but no dragging yet, cancel the drag
        if (ZPD.listeningBin) {
            ZPD.listeningBin = false;
            return;
        }
        
        // If we are dragging, drop the bin and stop the drag
        if (ZPD.movingBin) {
            ZPD.movingImage.fadeOut(function() { ZPD.movingImage.remove(); });
            ZPD.movingBin = false;
        }
        
        event.preventDefault();
        event.stopImmediatePropagation();
    },
    
    // Return true if a tabbed section exists on the page
    tabbedSectionExists: function () {
        return ZPD.tabbedSection().length;
    },
    
    // Return the tabbed sections on the page
    tabbedSection: function () {
        return Zen.$(".zen-tabbed-section");
    },
    
    // Return the sections in a tab relationship with section (or the current section is section is null)
    tabbedSectionsWith: function (section) {
        return Zen.$(".zen-section[data-tab='" + Zen.$(section || ZPD.currentSection()).attr("data-tab") + "']");
    },
    
    // Return the section Id of the section that is the "root" tab for section (or the current section is section is null)
    tabbedSectionFor: function (section) {
        return Zen.$("#zen-tabbed-section-" + Zen.$(section || ZPD.currentSection()).attr("data-tab"));
    },
    
    tryDragging: function (event) {
        
        var spot = ZPD.eventLocation(event);
        
        // If the last time we checked, we had not started the drag, start it now
        if (ZPD.listeningBin) ZPD.startDragging(spot);
        
        // If we're not dragging, do nothing
        if (!ZPD.movingBin) return;
        
        // ZPD.showLocation(spot);

        // Scroll up if we need to
        var windowHeight = Zen.$(window).height() - 30;
        ZPD.scrollUpAmount = (spot.Y - Zen.$("body").scrollTop()) - windowHeight;
        if (ZPD.isScrollingUp()) ZPD.scrollUp(true);
        
        // Scroll down if we need to
        ZPD.scrollDownAmount = 30 - (spot.Y - Zen.$("body").scrollTop());
       if (ZPD.isScrollingDown()) ZPD.scrollDown(true);
        
        // Move the moving bin to the new drag location
        // ZPD.movingImagePosition.top  = spot.Y - ZPD.movingBinDragOffsetY - ZPD.movingImagePosition.top;
        // ZPD.movingImagePosition.left = spot.X - ZPD.movingBinDragOffsetX - ZPD.movingImagePosition.left;
        ZPD.moveDragImage(spot.X - ZPD.movingBinDragOffsetX - ZPD.movingImagePosition.left,
                        spot.Y - ZPD.movingBinDragOffsetY - ZPD.movingImagePosition.top);
        
        // Move the drop marker
        ZPD.relocateBin(spot);
        
        event.preventDefault();
        event.stopImmediatePropagation();
    },

    // twoFingerTouch: function (event) {
    //     
    //     // If we've got two fingers down, then we're looking for the menu and not dragging
    //     if (event.originalEvent && event.originalEvent.touches.length == 2) {
    //         event.preventDefault();
    //         ZPD.showSectionMenu.call(this, event);
    //     }
    //     
    // },
    
    // Make the demo zen-section reflect the settings in the designer form
    updateDemo: function () {

    	// The float left/right control (floaters need both the "float" class plus "zen-left" or "zen-right")
	    ZPD.demo.removeClass("float zen-right zen-left");
    	var float = ZPD.$("#section-design-float").val();
	    if (float) ZPD.demo.addClass("float zen-" + float);

        // The hide background and border toggles
        var noBackground = ZPD.$("#section-design-no-background:checked").length;
        if (noBackground) {
           ZPD.demo.addClass("no-background");
           ZPD.$(".background-details *").attr("disabled", "disabled").addClass("disabled");
        }
        else {
            ZPD.demo.removeClass("no-background");
            ZPD.$(".background-details *").removeAttr("disabled").removeClass("disabled");
        }
        if (ZPD.$("#section-design-no-border:checked").length) ZPD.demo.addClass("no-border");
        else ZPD.demo.removeClass("no-border");

        // General CSS values
        var width = ZPD.$("#section-design-width").val();
        ZPD.demo.css({
	        width:              width, 
	        height:             ZPD.$("#section-design-height").val(),
	        margin:             ZPD.$("#section-design-margin").val(),
	        padding:            ZPD.$("#section-design-padding").val()
	    });

	    // This is separated out to fix a bug in IE -- can't handle nulls as values
	    if (!noBackground) {
            var bgImage = ZPD.$("#section-design-background-image").val();
            bgImage = bgImage ? "url(" + Zen.attachmentPath(pageId, bgImage) + ")" : "";
	        ZPD.demo.css({
                backgroundColor: Zen.translateColor(ZPD.$("#section-design-background-color").val()),
                backgroundImage: bgImage,
    	        backgroundPosition: ZPD.$("#section-design-background-position").val(),
    	        backgroundRepeat: ZPD.$("#section-design-background-repeat").val()
	        })
	    }
	    
    },
    
    viewWikiMarkup: function (event) {

        // event.preventDefault();
        
        // See if there's markup to display
        var markup = ZPD.currentSection().find(".wiki-markup");
        if (!markup.length) return false;

        // Recycle the dialog and show the wiki markup
        // Zen.Dialog.clearPrevious();
        ZW.dialog(markup.clone().show(), {title: "Wiki Markup", width: 1024, height: 600, okButton: false, cancelButton: "Close"});
        // var dialog = new Zen.Dialog(markup.clone().removeClass("hidden"), {title: "Wiki Markup", width: 1024, height: 600, step: "Page"});
        // dialog.show();

        // Stop the default menu-item click action from firing
        return false;
    },

    whichColumn: function (spot) {

        var wikiBody = Zen.$("#wiki-body");
        var position = wikiBody.offset();

        // Figure out which column the user is aiming for
        var wantsLeftColumn  = spot.X < position.left;
        var wantsRightColumn = spot.X > (position.left + wikiBody.outerWidth());
        
        // Don't let the user move something into the columns if the page is using a master (but isn't a master itself)
        if ((wantsLeftColumn || wantsRightColumn) && !Zen.isOwnMaster && !Zen.isMaster) return wikiBody;
        
        // If we're left of the wiki-body, assume left column, after is right column.
        if (wantsLeftColumn) return Zen.$("#zen-left");
        else if (wantsRightColumn) return Zen.$("#zen-right");
        else return wikiBody;
    }
    
};

(function ($) {
    
    // Add the edit control panel to the zen section
	jQuery.fn.addSectionMenuControl = function () {

        return this.each(function() {
	    
            // Find the edit control panel
            var $panel = $(this).find(".control-panel");
        
            // Add the menu open control and set its click action
            $panel.append("<a href='#' class='section-menu-control'></a>");
            $panel.find(".section-menu-control").click(ZPD.showSectionMenu);

        });
    };

    // Make the receiving zen section visible in the scroll window.
    // This might also mean selecting the appropriate tab, if it's in a tabbed view
	jQuery.fn.scrollToBeVisible = function () {

        return this.each(function() {
            
            // If the section edited is in a tabbed view, make sure that tab is selected
            var tabbedSection = $(this).attr("data-tab");
            if (tabbedSection.length) {
                $(".zen-tabbed-section[data-tab='" + tabbedSection + "'] li a[data-section-id='" + $(this).attr("data-section-id") + "']").click();
            }

            // Get the window scroll location and height
            var bodyScroll = $("body").scrollTop();
            var windowHeight = $(window).height();

            var sectionTop = $(this).offset().top;
            var sectionHeight = Math.min($(this).height(), windowHeight - 60);
            
            // Make the full section visible (or at least as much as fits in the window), unless the section's top is 
            // visible without scrolling
            if ((sectionTop + 60) > windowHeight && (sectionTop + sectionHeight) > (bodyScroll + windowHeight)) {
                $("body").scrollTop(Math.max(0, sectionTop - 60));
            }

        });
    };

    // Make sure a tabbed view is available for this Zen section
	jQuery.fn.ensureTabbedSection = function () {

        return this.each(function() {

            // If the tabbed section is already set up, do nothing
            if (ZPD.isTab(this)) return;

            // Create the tabbed section and insert it just above the section
            var tabId = $(this).attr("data-tab");
            var tabbedSection = "<div id='zen-tabbed-section-" + tabId + "' class='zen-tabbed-section' data-tab='" + tabId + "'><ul class='tab-view-tabs'></ul></div>";
            var $tabbedSection = $(tabbedSection);
            $(this).before($tabbedSection);
            
            // Handle the clicks on the tabs
            $(".tab-view-tabs", $tabbedSection).delegate("li a", "click", function () {
                if (!$(this).parent("li").hasClass("current")) {
                    var $tabbedSection = $(this).parents(".zen-tabbed-section");
                    var sectionId = $(this).attr("data-section-id");
                    var tabId = $tabbedSection.attr("data-tab");
                    
                    // Adjust tab selection
                    $("li", $tabbedSection).removeClass("current");
                    $(this).parent("li").addClass("current");
                    
                    // Adjust visibility to match selection
                    $(".zen-section[data-tab='"        + tabId     + "']").css("display", "none");
                    $(".zen-section[data-section-id='" + sectionId + "']").css("display", "block");
                }
                return false;
            });
            
        });
    };

    // Organize into tab views.
	jQuery.fn.drawForTabbedView = function () {

        return this.each(function() {

            // Determine which section to join as a tab, and stop if none
            var $tab = ZPD.findSection($(this).attr("data-tab"));
            if (!$tab.length) return;
            
            // Make sure the tabbed section is set up
            $tab.ensureTabbedSection();
            
            // Add a titled tab for this section (use the first H1 or a tab number if none)
            var $tabbedSection = ZPD.tabbedSectionFor($tab);
            var $tabs = $tabbedSection.find(".tab-view-tabs");
            var title = $("h1:not(#zen-page-title):first", this).text().trim();
            if (!title.length) title = "Tab " + ($tabs.find("li").length + 1);
            $tabbedSection.find(".tab-view-tabs").append("<li><a href='' data-section-id='" + $(this).attr("data-section-id") + "'>" + title + "</a></li>");
            
            // Ensure the first tab has a class to help with styling
            $tabbedSection.find(".tab-view-tabs li:first").addClass("first current");

            // Move the section's content into a tab content
            

        });
    };

})(jQuery);

AJS.toInit( function ($) {

    // Add the handle for dragging
    ZPE.pageSections().find(".control-panel").append("<div class='drag-handle' onclick='void(0)'></div>");

    // No dragging if:
    // 1) we're not Zen v4, or
    // 2) we're looking at a historical page
    // 3) there's only one main-column section on a master-controlled page (it takes two to tango...), or
    if (!zen4 || $("#canvas.zen-view-historical").length || (!Zen.isMaster && !Zen.isOwnMaster && ZPE.pageSections("zen-main").length < 2)) {
        // Remove the drag handle mouse feedback before bailing
        $(".drag-handle", ZPE.pageSections("zen-main")).addClass("no-drag");
        
        // Also remove the "remove" item from the section menu -- makes no sense to remove the only section
        // (removes the menu separator as well)
        // REMOVED: makes no sense as there could be left/right column sections to be manipulated
        // $("#zen-main #section-menu-remove").parent().prev("li.spacer").remove();
        // $("#zen-main #section-menu-remove").parent().remove();
        
        return;
    }
    
    // Set up the events to monitor and handle dragging
    $(".drag-handle").mousedown(ZPD.listenForDrag);
    $(".drag-handle").bind('touchstart', ZPD.listenForDrag);
    $("#canvas").bind('touchmove', ZPD.tryDragging).bind('touchend', ZPD.stopDragging).bind('touchcancel', ZPD.stopDragging);
    $("#canvas").unbind('mousemove').mousemove(ZPD.tryDragging).mouseup(ZPD.stopDragging);
    
});

// Set up the section menu
AJS.toInit ( function ($) {

    // Move the menu to the body (it's rendered in the page)
    Zen.$("body").append(ZPD.sectionMenu());
    
    // Set up the section menu items
	$("#section-menu a").click(ZPD.doSectionMenu);
	$("#section-menu-after").unbind("click").click(ZPD.insertAfterSection);
	$("#section-menu-remove").unbind("click").click(ZPD.removeSection);
	$("#section-view-markup").unbind("click").click(ZPD.viewWikiMarkup);
	$("#section-menu-design").unbind("click").click(ZPD.editSectionDesign);
    $("#section-menu").bind('mouseleave', function (event) {$(this).hide();});
    
    // Add the section menu controls to each of the editable Zen content areas
    ZPE.pageSections().addSectionMenuControl();
    
});

// Make sure the section we just edited is visible
AJS.toInit( function ($) {
    ZPD.justEditedSection().scrollToBeVisible();
});



/********************
 design-editor.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
 */

/**
 * Zen.DesignEditor class
 *
 * Wraps an Zen.Dialog to provide the full link editor functionality.
 *
 * Usage: use the constructor:
 *      var layoutEditor = new Zen.DesignEditor();
 *      layoutEditor.show();
*/
 
/**
 * @constructor
*/
Zen.DesignEditor = function () {
    Zen.DesignEditor.designer = this;
};

Zen.DesignEditor.prototype.show = function(link) {

    var pageDesign = Zen.$(link).attr("id") == "page-design-editor-link";
    var pageContents = Zen.$(link).attr("id") == "page-contents-editor-link";
    var blog = Zen.$(link).attr("href").indexOf("designingBlog") != -1;
    var blogRoot = Zen.$(link).attr("href").indexOf("blogRoot=true") != -1;
    
    var title = blog ? "Blog Display Details" : "Page Display Details";
    var height = 400;
    var width = 400;
    
    // Lose any previous dialog and its shadow
    var old = Zen.$("#zen-dialog");
    old.prev(".shadow").remove();
    old.remove();
    
    // Send an ajax call to get the dialog contents
    Zen.Dialog.dialogWithUrl(Zen.$(link).attr("href"), {}, 
                {title: title, noZenBin: true, width: width, height: height}, 
                this.initializeDesignEditor);
    
};

Zen.DesignEditor.prototype.isSelected = function(selector) {
    return Zen.$(selector).hasClass("selected");
};

Zen.DesignEditor.prototype.submitDesign = function() {
    // Transfer selected state to the form fields
    Zen.$("[name='customMenu']",    this).val(Zen.$("#custom-menu-choice.selected"              ).length ? "true" : "false");
    Zen.$("[name='pageTitle']",     this).val(Zen.$("#page-title-section-layout.selected"       ).length ? "true" : "false");
    Zen.$("[name='metadata']",      this).val(Zen.$("#metadata-section-layout.selected"         ).length ? "true" : "false");
    Zen.$("[name='labels']",        this).val(Zen.$("#labels-section-layout.selected"           ).length ? "true" : "false");
    Zen.$("[name='comments']",      this).val(Zen.$("#comments-section-layout.selected"         ).length ? "true" : "false");
    Zen.$("[name='customContent']", this).val(Zen.$("#custom-section-contents-choice.selected"  ).length ? "true" : "false");
};

Zen.DesignEditor.prototype.initializeDesignEditor = function(dialog) {

    // Set up the layout toggles (for switching the component displays on/off)
    dialog.$(".layout-toggle").click(function() {
        // Stop if the link is immutable
        if (Zen.$(this).hasClass("immutable")) return;
    	Zen.$(this).toggleClass("selected");
    });
    
    // Set up the site vs. space menu selectors to work like radio buttons
    dialog.$(".menu-toggle").click(function() {
        Zen.$(".menu-toggle").removeClass("selected");
        Zen.$(this).addClass("selected");
    });
    
    // Set up the space vs. custom section contents selectors to work like radio buttons
    dialog.$(".contents-toggle").click(function() {
        Zen.$(".contents-toggle").removeClass("selected");
        Zen.$(this).addClass("selected");
    });

    // Adjust the form to submit with the selected values
    dialog.$("#design-editor-form").submit(Zen.DesignEditor.designer.submitDesign);

    // Give the user a chance to cancel when reverting page designs
    dialog.$("#design-editor-form input[name='revert']").click(function() {
        var blog = Zen.$("#design-editor-form").attr("action").indexOf("applyblogdesign") != -1;
        var what = blog ? "blog" : "page";
        return ZW.confirm("This " + what + " will no longer override the space design.", "Click 'OK' to revert to the space design, or 'Cancel' to keep the design for this " + what + ".");
    });

};


/********************
 tab-view.js 
********************/

/**
 * Zen Foundation
 *
 * Copyright Stepstone Technologies Inc.
 */

/**
 * The shortcut for Zen.TabView is: ZTV
 */

var ZTV = Zen.TabView = {

    // Set up the tab view -- add the tab menu
    init: function (element, showPageTitles, showPageNumbers) {
        var tabView = Zen.$(element);
        
        // Add the tabs to the menu
		tabView.find(".zen-tab-view-content").each(ZTV.addTab);
		
		// Select the first tab in the menu
		ZTV.menu(tabView).find(".tab-view-tab:first").addClass("selected");
		
		// Make the first page visible
		tabView.find(".zen-tab-view-content:first").removeClass("hidden");
		
		// Adjust the page title and number visibility
		if (!showPageTitles) tabView.find(".tab-view-page-title").remove();
		if (!showPageNumbers) tabView.find(".tab-view-tab .page-number, .tab-view-page-title .page-number").remove();
    },

	// Add a tab to the tab view. "this" should refer to an element of the form:
	// <div id="$safeId" class="zen-tab-view-content #if ($selected) selected #else hidden #end" data-title="$title">
	addTab: function () {
		var element = Zen.$(this);
		var tabView = element.parent();
		var tabViewId = tabView.attr("id");
		
		// Move the tab to the "menu"
		var tab = element.find(".tab-view-tab");
		ZTV.menu(tabView).append(tab);
		
		// Make the tab know it's tab-view
		tab.attr("data-tab-view-id", tabViewId);
		
		// Make the menu tab toggle the tab's visibility
		tab.click(ZTV.selectTab);
	},
	
	// Return the menu for tabView
	menu: function (tabView) {
		return tabView.find(".tab-view-tabs");
	},
	
	// Make the menu tab's page visible. "this" should refer to a clicked menu tab.
	selectTab: function () {
		var tab = Zen.$(this);
		var tabView = Zen.$("#" + tab.attr("data-tab-view-id"));
		
		// Adjust visibility of the menu tabs
		ZTV.menu(tabView).find(".tab-view-tab").removeClass("selected");
		tab.addClass("selected");
		
		// Make the tab's content visible
		tabView.find(".zen-tab-view-content").addClass("hidden");
		tabView.find("#" + tab.attr("data-id")).removeClass("hidden");
	}

}



/********************
 date-editor.js 
********************/

var ZDE = Zen.DateEditor = {
	
	// Return the number of days in month and year
	daysInMonth: function (month, year) {
		month = parseInt(month);
		year = parseInt(year);
		var m = [31,28,31,30,31,30,31,31,30,31,30,31];
		if (month != 2) return m[month - 1];
		if (year%4 != 0) return m[1];
		if (year%100 == 0 && year%400 != 0) return m[1];
		return m[1] + 1;
	}
};

(function ($) {
	
	var zeroPad = function (number, minimum, maximum) {
		if (minimum == undefined) minimum = 0;
		number = parseInt(number);
		if (isNaN(number) || number < minimum) number = minimum;
		if (maximum != undefined && number > maximum) number = maximum;
		if (number < 10) number = "0" + number;
		
		return number;
	}
	
    // Validate year input
    jQuery.fn.dateEditorValidateYear = function() {
        return this.each(function (){
			$(this).val(zeroPad($(this).val(), 2000, 2100));
			
			$(this).parents(".zen-date-editor").find(".day").dateEditorValidateDay();
        });
    };

    // Validate month input
    jQuery.fn.dateEditorValidateMonth = function() {
        return this.each(function (){
			$(this).val(zeroPad($(this).val(), 1, 12));
			
			$(this).parents(".zen-date-editor").find(".day").dateEditorValidateDay();
        });
    };

    // Validate day input
    jQuery.fn.dateEditorValidateDay = function() {
        return this.each(function (){

			var year  = zeroPad($(this).parents(".zen-date-editor").find(".year").val(), 2000, 2100);
			var month = zeroPad($(this).parents(".zen-date-editor").find(".month").val(), 1, 12);
			$(this).val(zeroPad($(this).val(), 1, ZDE.daysInMonth(month, year)));
			
			$(this).dateEditorPrepareForSubmit();

        });
    };

    // Validate hour input
    jQuery.fn.dateEditorValidateHour = function() {
        return this.each(function (){
			$(this).val(zeroPad($(this).val(), 1, 12));
			
			$(this).dateEditorPrepareForSubmit();
        });
    };

    // Validate minute input
    jQuery.fn.dateEditorValidateMinute = function() {
        return this.each(function (){
			$(this).val(zeroPad($(this).val(), 0, 59));						
			
			$(this).dateEditorPrepareForSubmit();
        });
    };

    // Validate am-pm input
    jQuery.fn.dateEditorValidateAmPm = function() {
        return this.each(function (){
	
			var ampm = $(this).val().toLowerCase();
            $(this).val(ampm.indexOf('p') == 0 ? "PM" : "AM");
			$(this).dateEditorPrepareForSubmit();
        });
    };

    // Validate am-pm input
    var dateEditorChooseAmPm = function (event) {	
		var keypress = event.which;
		if (keypress == 65) $(this).val("AM");
		if (keypress == 80) $(this).val("PM");
		this.select();
		$(this).dateEditorValidateAmPm();
		// Don't interfere with basic navigation and dialog commands
        if (keypress === Event.KEY_RETURN || keypress === Event.KEY_TAB || keypress === Event.KEY_ESC) return;
		event.stopPropagation();
		return false;
    };

	// Prepare the date editor for form submission
	jQuery.fn.dateEditorPrepareForSubmit = function () {
        return this.each(function () {
			// Locate the date editor (if this is not a date editor, this is a subcomponent of a date editor)
			var dateEditor = $(this);
			if (!dateEditor.hasClass("zen-date-editor")) dateEditor = $(this).parents(".zen-date-editor");
			
			// TODO:  Add validation for empty/partial input
			var dateResult = $(".year", dateEditor).val() + "." + $(".month", dateEditor).val() + "." + $(".day", dateEditor).val();
			dateResult = dateResult + "." + $(".ampm", dateEditor).val() + "." + $(".hour", dateEditor).val() + "." + $(".minute", dateEditor).val();
			$(".date-submit", dateEditor).val(dateResult);
			
			dateResult = $(".year", dateEditor).val() + "." + $(".month", dateEditor).val() + "." + $(".day", dateEditor).val();
			var hour = parseInt($(".hour", dateEditor).val());
			if (hour != 12 && $(".ampm", dateEditor).val() == "PM") hour = 12 + hour;
			else if (hour == 12 && $(".ampm", dateEditor).val() == "AM") hour = 0;
			dateResult = dateResult + "." + zeroPad(hour, 0, 23) + "." + $(".minute", dateEditor).val();
			$(".date-comparable", dateEditor).val(dateResult);
			
        });	
	};
	
	// Prepare the date editor to handle user input, etc.
	jQuery.fn.dateEditorInitialize = function (dateString) {
        return this.each(function (){
			// Split the date dataStr: MM.dd.yyyy.hh.mm.a
			var dateData = dateString.split(".");

			$("input.year",   this).val(dateData[0]);
			$("input.month",  this).val(dateData[1]);
			$("input.day",    this).val(dateData[2]);
			$("input.ampm",   this).val(dateData[3]);
			$("input.hour",   this).val(dateData[4]);
			$("input.minute", this).val(dateData[5]);

			$("input.year",   this).change(function() {$(this).dateEditorValidateYear()});
			$("input.month",  this).change(function() {$(this).dateEditorValidateMonth()});
			$("input.day",    this).change(function() {$(this).dateEditorValidateDay()});
			$("input.hour",   this).change(function() {$(this).dateEditorValidateHour()});
			$("input.minute", this).change(function() {$(this).dateEditorValidateMinute()});
			$("input.ampm",   this).change(function() {$(this).dateEditorValidateAmPm()});
            $("input.ampm",   this).focus(dateEditorChooseAmPm).keydown(dateEditorChooseAmPm);

			$(this).dateEditorPrepareForSubmit();
        });	
	};
    
})(jQuery);

AJS.toInit( function ($) {
});



/********************
 random-content.js 
********************/

var ZRC = ZenRandomContent = {
    
    randomizeContent: function (element) {
    	var data = Zen.$(".random-content-data", element);
    	jQuery.get(contextPath + "/plugins/zen/renderrandomcontent.action",
    		{pageId: data.attr("data-parent-page-id"), 
    		 currentPageId: data.attr("data-current-page-id"),
    		 labels: data.attr("data-labels")},
    		function (response) {
    			element.fadeOut("slow", function() { 
    				element.html(response); 
    				element.fadeIn("slow", function () {
    					window.setTimeout(function() { ZRC.randomizeContent(element); }, element.attr("data-delay"));
    				}); 
    			});
    		}
    	);
    }

};

AJS.toInit( function ($) {
	$(".random-content").each(function() {
		var element = $(this);
		window.setTimeout(function() { ZRC.randomizeContent(element); }, element.attr("data-initial-delay"));
	});
});



/********************
 unsupported.js 
********************/

// Stop Zen if IE6 or earlier
// If there's a watermark, move it to the header
AJS.toInit( function ($) {
    if (Zen.ie6 || Zen.ie5) {
        $("#zen-toolbar, .zen-column, #zen-top, #zen-bottom, #watermark, #labels, #comments, .zen-editable-content .control-panel, #zen-page-title #edit-title-control").remove();
        $("#canvas").css({width: "100%", paddingTop: "36px"});
        $("#crumbs").css({top: 0});
        alert("Sorry, you're using an unsupported version of Internet Explorer.\n\nTo use Zen Foundation, please upgrade to IE7 or later.");
    }
});



/********************
 toxipedia.js 
********************/

AJS.toInit( function ($) {
    // If there's a left column, move the old-style macro contents there
    if ($("#zen-left .zen-bin").length) {
        // Move the authors macro contents
        if ($("#authorContents").length) $("#zen-left").prepend($("<div class='zen-bin'><h1>Authors</h1></div>").append($("#authorContents")));

        // Move the right-column macro contents
        if ($(".old-right-column").length) $("#zen-left .zen-section:first").after($("<div class='zen-bin'></div>").html($(".old-right-column")));
    }
});

