

/********************
 ie.js 
********************/

var Zen = {
    ie: jQuery.browser.msie,
   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
};



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

// Shortcut to the jQuery object
Zen.$ = AJS.$;

// {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
    $(".zen-column")
        .find(".blogpost .pagesubheading, .blog-post-listing .logoBlock, .blog-post-listing .blogHeading .page-metadata").remove();
    $(".blogSurtitle, .blogpost .endsection, .blog-post-listing .endsection").remove();
    
    // 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>"); 
    });
});

// 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(); };
	}
    
});

/**
 * 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.
 */


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

Zen.safari = jQuery.browser.webkit;
Zen.firefox = jQuery.browser.mozilla;
Zen.opera = jQuery.browser.opera;
Zen.ios = navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad)/);

// If there's a watermark, move it to the header
AJS.toInit( function ($) {
    $("#watermark").html($("#watermark-contents").html());

    // IE7 hack: text transform is ignored after the move, so reapply it
    if (Zen.ie7) $("#watermark").css({opacity: "0.10", filter: "alpha(opacity=10)", textTransform: zenWatermarkTextTransform});     
});

// 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");
});

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);
  }
};


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

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

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

var ZW = Zen.Wizard = {

    // Display basicMessage to the user, with a standard message unless proceedMessage is present, then use it.
    alert: function(basicMessage, proceedMessage) {
        var message = basicMessage + '\n' + '\n' + (proceedMessage ? proceedMessage : "Click 'OK' to continue editing.") + '\n';
        alert(message);
    },

    // Return the basic form's submit button
    basicForm: function () {
        return Zen.$("#zen-toolbar-holder form.zen-editor");
    },
    
    // Return the basic form's submit button
    basicFormSubmitButton: function () {
        return Zen.$(".zen-editor .return-button");
    },
    
    // Ignore the current editing session (prompting user if changes will be lost) and close the toolbar.
    // Does nothing to draft or page content on server
	cancelEdit: function () {

	    // Give the user a chance to save any edits
	    if (ZW.hasChanges() && !ZW.confirm("Looks like you've made changes. ", "Click 'OK' to discard them, or 'Cancel' to continue editing.")) return;

	    // Hide the toolbar, set it back to normal state, and reveal it again
	    ZW.resetToolbar();

        // Reset the view state
        ZW.clearEditing();
    },
	
    // Remove any current-editing flags
    clearEditing: function () {
        Zen.$(".zen-current-edit-content").removeClass("zen-current-edit-content view-wiki-markup");
    },
    
    // Display a confirm panel with basicMessage, plus a standard message unless proceedMessage is present, then use it.
    confirm: function(basicMessage, proceedMessage) {
        var message = basicMessage + '\n' + '\n' + (proceedMessage ? proceedMessage : "Click 'OK' to proceed, or 'Cancel' to keep editing.") + '\n';
        return confirm(message);
    },

    // Return a basic form with the cancel button and a submit button wrapping the html sent in formContents
    // The form's action will be set to url, and hidden fields will store the pageId and browser
    // location (the url the user is viewing)
    createBasicForm: function (formContents, url, submitButtonText, pageId) {
        return  "<form name='zen-editor' method='post' class='zen-editor basic-form' action='" + url + "'>" +
                    "<input type='hidden' name='pageId' value='" + pageId + "' />" +
                    "<input type='hidden' name='url' value='" + window.location + "' />" +
                    formContents +
                	"<div id='zen-editor-controls'>" +
                		"<div id='initial-controls'>" +
                			"<input type='button' class='button cancel' value='X' />" +
            				"<div class='control-wrapper'>" +
            					"<div class='button save return-button'>" + (submitButtonText ? submitButtonText : "Save") + "</div>" +
            				"</div>" +
                		"</div>" +
                		"<div class='clear-fix'></div>" +
                	"</div>" +
                "</form>";
    },

    // Return content area being edited
    editingContent: function () {
        return Zen.$(".zen-current-edit-content");
    },
    
    // Return the matching elements from the wizard
    find: function (selector) {
        return Zen.$("#zen-popup").find(selector);
    },
    
    // Hide the toolbar, display a wait message, and send the form to the given actionName to 
    // reload the page contents from the server
	finishEdit: function (actionName) {
	    
	    // Hide the toolbar, set it back to normal state, and reveal it again
        Zen.$("#zen-toolbar-holder").slideUp("medium", function () {
            
            // Let the user know something is happening
            ZW.showWaitSymbol();

            // Make sure the form knows which page to reload (the page being viewed, not the one being edited)
            var editForm = Zen.$("#zen-toolbar-form .form-contents .zen-editor");
            editForm.find("input[name='previewPageId']").val(ZW.editingContent().attr("pageId"));
            editForm.find("input[name='viewPageId']").val(latestVersionPageId);

            // Reload the page contents from the server
            editForm.attr("action", contextPath + "/plugins/zen/" + actionName + ".action").submit();

        });
    },
	
    // Return true if any of the input fields have changed
    hasChanges: function() {
        // Check each input field in the wizard for changes by the user
        var result = false;
        Zen.$("#zen-toolbar-form :input").each( function () {
            if (Zen.$(this).attr("originalValue") != Zen.$(this).val()) result = true;
        });
        return result;
    },

    // Stop the "waiting for server" status
	hideWaitSymbol: function (callback) {
	   ZW.editingContent().find(".loading").fadeOut("medium", callback);
    },
    
    // Return true if the wizard has focus
    hasFocus: function () {
        // The wizard is part of the toolbar, so use its state
        return Zen.Toolbar.hasFocus();
    },

    // Return true if any content area is being edited
    isEditing: function () {
        return ZW.editingContent().length;
    },

    // Handle odd keys on the wizard
    keyListener: function (event) {
        
        // Ignore events if I'm not active
        if (!ZW.hasFocus()) return;
        
        // Try to click the "cancel" object when the user presses ESC
        if (event.which === Event.KEY_ESC) {
            ZW.cancelFunction.call();

            // Needed to prevent endless loop in Safari 4 when dismissing the discard-changes panel with the ESC key
            event.preventDefault();
        }
        
        // Try to click the "submit" object when the user presses Return
        else if (event.which === Event.KEY_RETURN) {
            
            // Let the textarea handle returns
            if (event.target.nodeName.toUpperCase() == "TEXTAREA") {
                return;
            }
            
            var submitButton = ZW.basicFormSubmitButton();
            if (submitButton.length) {
                submitButton.click();

                // Needed to prevent endless loop in Safari 4 when dismissing the discard-changes panel with the ESC key
                event.preventDefault();
            }
        }
        
    },
    
    // Make the toolbar go back to the normal state (not editing)
	resetToolbar: function (zenEditorForm) {
            
        // Stop responding to keyboard events
        Zen.$(document).unbind("keydown", ZW.keyListener);

        // Hide the toolbar, reset it, and reveal it again
        Zen.$("#zen-toolbar-holder").slideUp("medium", function () {
            
            // Toss the editor
            Zen.$("#zen-toolbar-form .form-contents").empty();
            Zen.$("#zen-toolbar-form, .zen-editor").hide();

            // Show the regular toolbar
            Zen.$("#zen-toolbar").show();
            
            // Remove the gray blanket and restore its default opacity
            AJS.undim();
            Zen.$(".blanket").css("opacity", this.blanketOpacity);
        
            // IE7 hack to get toolbar in expando mode to return to full width
            if (Zen.ie7) Zen.$("#zen-toolbar-holder.expando").css({width: "100%", margin: 0, left: "auto"});
            
            // Reset the toolbar's z-index and remove the bottom shadow before dropping it back down
            Zen.Toolbar.disableToolbar();
            Zen.$("#zen-toolbar-holder").removeClass("toolbar-shadow").slideDown("medium");
            
        });

    },
    
    // Show the "waiting for server" status, adding one if needed
	showWaitSymbol: function () {
	    var item = ZW.editingContent();
	    if (!item) return;
	    item.toggleEditControls(false);
	    if (!item.find(".loading").length) item.prepend("<div class='loading'>Loading...</div>");
	    item.find(".loading").wait(500).fadeIn("slow");
    },
	
    // Put the form contained in zenEditorForm into the toolbar in edit mode, and call initializer after the 
    // wizard is filled with the form, but before it is visible
	startEditForm: function (zenEditorForm, initializerCallback, cancelCallback) {

        // Make sure the wait symbol shuts down
        ZW.hideWaitSymbol();
        
        // IE7 can't do too many things at once! So hide the toolbar now before animating
        if (Zen.ie7) Zen.$("#zen-toolbar").hide();
        
        // Hide the toolbar, set it up to edit my form, and reveal it again
        Zen.$("#zen-toolbar-holder").slideUp("medium", function () {
            
            // Get rid of the regular toolbar while editing
            Zen.$("#zen-toolbar").hide();
            
            // Drop the grey blanket over the UI, and adjust it's opacity to something more reasonable
            AJS.dim();
            this.blanketOpacity = Zen.$(".blanket").css("opacity");
            Zen.$(".blanket").css("opacity", "0.2");
            
            // Put my form into the toolbar form holder and make sure they both are visible
            Zen.$("#zen-toolbar-form .form-contents").html(zenEditorForm);
            Zen.$("#zen-toolbar-form, .zen-editor").show();

            // Remember the cancel function in case we need to close the wizard (for example, when the ESC key is pressed)
            ZW.cancelFunction = cancelCallback ? cancelCallback : ZW.cancelEdit;
            
            // Make the cancel button unwind the wizard
            Zen.$(".zen-editor #initial-controls .cancel").click(ZW.cancelFunction);

            // Use the callback method to set up the wizard
            if (initializerCallback) initializerCallback.call();
            
            // Make sure each input field remembers it's original value so it can be tested for change when the user closes the wizard
            Zen.$("#zen-toolbar-form :input").each( function () {
                Zen.$(this).attr("originalValue", Zen.$(this).val());
            })
            
            // Make sure we can respond to keyboard events
            Zen.$(document).keydown(ZW.keyListener);
            
            // Make sure the toolbar appears above the gray blanket, and make the wizard drop down with a bottom shadow
            // this.toolbarZindex = Zen.$("#zen-toolbar-holder").css("z-index");
            Zen.Toolbar.enableToolbar();
            Zen.$("#zen-toolbar-holder").addClass("toolbar-shadow").slideDown("medium");
            
            // IE7 hack to get toolbar to center over the canvas (otherwise it floats to right edge of window).
            if (Zen.ie7) Zen.$("#zen-toolbar-holder").css({width: "100%", margin: 0, left: 0});

        });

    },
    
    // Make sure there is a form to edit item, fetching it from the server if there isn't one yet
    // item                 - the display area for the item being edited, can be null
    // url                  - url to fetch the form
    // data                 - the data array to submit with the url, for example: {pageId: pageId}
    // initializerCallback  - the function to call after the form is in place (which allows the caller to finish wiring the form)
    //                      - note the cancel button (the 'X') will be automatically wired to the cancelCallback
    // cancelCallback       - the function to call when canceling the form; if null, default to ZW.cancelEdit()
	startEditFormViaAjax: function (item, url, data, initializerCallback, cancelCallback) {
        // Don't do anything if any content area is already being edited
        if (ZW.isEditing()) return;

        // Note that we're editing this content (or just viewing wiki markup if the user doesn't have edit permissions)
        if (item) item.addClass("zen-current-edit-content");
        // if (!canEdit) item.addClass("view-wiki-markup");

        // Otherwise, get the form from the server with the current wiki markup loaded.
        ZW.showWaitSymbol();
        
        // Get the form from the server, and start editing with the response
        jQuery.ajax({
            url: url, 
            data: data, 
            success: function (response) { ZW.startEditForm(response, initializerCallback, cancelCallback); },
            error: function (xhRequest, textStatus, errorThrown) {
                alert("Error from received from server: \n\n" + textStatus + (errorThrown ? "\n\n" + errorThrown : ""));
            }
        });
	},
   
    // 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 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;
    },
    
    // 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");
    }
    
};


AJS.toInit(function ($) {
    
    // Check the theme contents form
    var validateThemeNameForm = function (dialog) {
        // Stop if the name is invalid (must be a valid page title)
        var name = $.trim(dialog.$("#page-extras-name").val());
        if (!ZPE.validTitle(name)) return false;
        
        return ZW.confirm("A new bundle of page extras called '" + name + "' will be created and used for " + (isBlog ? "blog posts" : "this page."));
    };
    
    // The function to invoke the "create new theme contents" form, which is a simple name input form
    var startPageExtrasBundleForm = function () {

        // Display the form
        var dialog = new Zen.Dialog($("#new-page-extras"), {title: "Create a New Page Extras Bundle", width: 600, height: 220});

        // Unbind the submit action before setting it as this can be called multiple times during a session
        dialog.$("#new-page-extras").unbind("submit").submit(function () { return validateThemeNameForm(dialog); });

        dialog.show();
        
        return false;
	};
	
    // Wire the menu item to invoke the "create new theme contents" form
    $("#create-page-extras a").click(startPageExtrasBundleForm); 
    
});

AJS.toInit( function ($) {

    // Move the toolbar to the top of the browser window
    $("#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");
    });
    
    // Reveal the toolbar after the page loads
    $("#zen-toolbar-holder").slideDown("fast");
    
    // // Hide the toolbar when the window loses focus
    // $(window).blur(function() {
    //    $("#zen-toolbar-holder").slideUp("medium");
    // });
    // 
    // // Put back the toolbar when the window loses focus
    // $(window).focus(function() {
    //    $("#zen-toolbar-holder").slideDown("medium");
    // });
   
});

AJS.toInit( function ($) {

    // Skip the toolbar adjustment on iPad
    if (Zen.ios) {
        return;
    }

    // If the toolbar is wider than the browser window, make it function like expando
    var toolbarWidth = $("#zen-toolbar").width();
    var bodyPadding = parseInt(zenBodyPadding);
    var holderWidth = $("#zen-toolbar-holder").width();
    if (toolbarWidth > holderWidth) {
        $("#zen-toolbar").width("auto");
        $("#zen-toolbar-holder #zen-toolbar #search").css({marginRight: zenBodyPadding});
    }
        
});

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"); } );

});


/********************
 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() {
        if (useZenEditor) {
            ZPE.startNewPage(null, this);
        }
        else {
            // 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
    $("#toolbar-menu #add").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 #shareContentLink-holder .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").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.disabled a").click(function () {return false;});
    $("a, li", "#view-drafts: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().removeClass("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.");
        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.");
        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();
});


/********************
 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
            $("#zen-toolbar-holder").slideUp("fast", function () {
                $("#wrapper").animate({width: zenCanvasWidth}, speed, function () {
                    $(".expando").removeClass("expando");
                    $("#canvas").css({width: canvasFixedWidth});
        
                    // IE7 hack to get toolbar to center over the canvas (same as page-view.js on initial load)
                    if (Zen.ie7) $("#zen-toolbar-holder").css({width: canvasFixedWidth, margin: "auto 0"});

                    $(".zen-column").fadeIn(speed);
                    $("#zen-toolbar-holder").slideDown("fast");                        
                });
            });
        }
        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);
            $("#zen-toolbar-holder").slideUp("fast", 
                function () {
                    $("#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");
        
                        // IE7 hack to get toolbar to display full width (it seeems to ignore the css here)
                        if (Zen.ie7) $("#zen-toolbar-holder").css({width: "100%", margin: "0"});
                        
                        $("#zen-toolbar-holder").slideDown("fast");
                    });
                }
            );
        }
        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) {

    /* 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("Error received from server:", textStatus + (errorThrown ? "\n\n" + errorThrown : ""));
        }
    });
};

/**
 * 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 () {
    // 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").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.
*/
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);
    }
    
    // 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 = {

    cancelEditor: function () {
        // For first time edits (new drafts that haven't been saved yet), re-wire the close button to 
        // toss the draft if the user closes the wizard without saving
        if (Zen.$(".zen-editor #initial-controls .cancel.first-time-edit").length) {
             // Give the user a chance to save any edits
    	    if (!ZW.hasChanges() || ZW.confirm("Looks like you've made changes. ", "Click 'OK' to discard them, or 'Cancel' to continue editing.")) {
    	        ZW.finishEdit("discarddraft");
    	    }
        }
        else {
            // For all other edits, just do the normal wizard close
            ZW.cancelEdit();
        }
        
    },
    
	// Return the contents of the page title field
	currentPageTitle: function () {
	    return Zen.$.trim(Zen.$("#content-title").val());
	},

    // Set up the wiki markup editor
    initializeMarkupEditor: function () {
        // Make the preview button retain the form and its edits in the browser (not server), 
        // and load the preview of the content
        ZPE.initializePageEditor(ZPE.savePreview);
    },
    
    // Set up the new page editor
    initializeNewPageEditor: function () {
        // Make the preview button save the new page title and a draft preview of the content
        ZPE.initializePageEditor(ZPE.saveNewPage);
    },
    
    // Set up the wiki markup editor
    initializePageEditor: function (previewCallback) {

        // Make the revert button unwind the form and discard any edits
        Zen.$(".zen-editor #initial-controls .revert").click( function () { 
            // Give the user a chance to save the draft
    	    if (ZW.confirm("You are about to permanently discard your draft.")) ZW.finishEdit("discarddraft");
        } );
        
        // Make the preview button retain the form and its edits in the browser (not server), 
        // and load the preview of the content
        Zen.$(".zen-editor #initial-controls .preview").click(previewCallback);
    	
    	// Make the help button open wiki markup help
    	Zen.$(".zen-editor #initial-controls .help").click(ZPE.showHelp);
        
        // Set up the link/attachment form
        Zen.$(".zen-editor #initial-controls .insert").click(ZPE.showLinkEditor);
        
    },
    
    // Set up the page title editor
    initializeTitleEditor: function () {
        Zen.$(".zen-editor #initial-controls .save").click(ZPE.saveTitle);
    },
    
    // Return the pageId associated with editableContent
    pageId: function (editableContent) {
        return Zen.$(editableContent).attr("pageId");
    },
    
    // Save the new page
    saveNewPage: function () {
            
        // Validate the title
	    if (!ZPE.validateTitle()) return;

        ZW.finishEdit("savenew" + context);        
    },

    // Save the edited contents as a page preview
    savePreview: function () {
        
        // If the user hasn't made any changes, confirm before creating a new draft
        // If creating a draft based on a historical version, don't warn the user if they
        // haven't made any changes to the historical version in the edit window
	    if (!isHistoricalVersion && !ZW.hasChanges() && !ZW.confirm("It doesn't look like you've made any changes.","Click 'OK' to create a new draft anyway, or 'Cancel' to continue editing.")) return;

	    ZW.finishEdit("previewcontent");
    },

    // Save the page title
    saveTitle: function () {
            
            // Validate the title
    	    if (!ZPE.validateTitle()) return;
	        
    	    // Give the user a chance to change their mind
    	    if (!ZW.confirm("This page title will be changed for others to see.", "Click 'OK' to change the title, or 'Cancel' to keep editing.")) return;

	        ZW.finishEdit("savepagetitle");        
    },

    // Display the wiki markup help screen
    showHelp: function () {
        window.open(contextPath + "/renderer/notationhelp.action", "zen_help");
    },
    
    // Display the link editor
    showLinkEditor: function (event) {
        if (!ZPE.linkEditor) ZPE.linkEditor = new Zen.LinkEditor();
        ZPE.linkEditor.show(Zen.$(this).attr("data-no-macros"));
        return AJS.stopEvent(event);
    },
    
    // Make sure there is a form to edit item's page, fetching it from the server if there isn't one yet
	startEditingMarkup: function (item) {

        // Invoke the wizard to either edit or view the wiki markup
        var actionName = canEdit ? "edit" + context : "viewwikimarkup";
        var editParams = {pageId: ZPE.pageId(item), viewPageId: pageId};
        if (isHistoricalVersion) editParams.copyPageId = pageId;
        ZW.startEditFormViaAjax(item, ZW.zenActionUrl(actionName), editParams, ZPE.initializeMarkupEditor, ZPE.cancelEditor);

        // Note that we're just viewing wiki markup if the user doesn't have edit permissions
        if (!canEdit) item.addClass("view-wiki-markup");

	},
  
    // Open the form to edit the page title
	startEditTitle: function (item) {
	    // Stop if the user can't edit
	    if (!canEdit) return;

        // Invoke the wizard to either edit or view the wiki markup
        ZW.startEditFormViaAjax(item, ZW.zenActionUrl("edit" + context + "title"), {pageId: pageId}, ZPE.initializeTitleEditor, ZPE.cancelEditor);

	},
	
    // Open the form to enter a new page title
    startNewPage: function (copyPageId, element) {
        // Stop if the user can't edit
        if (!canEdit) return;

        // See if the create page is being invoked from a Confluence-generated link
        var link = Zen.$(element).attr("href");
        var newPageTitle;
        if (link) {
            // Determine the new page title
            // Try looking for a title with more parameters after it
            var pattern = /.*title=(.*?)&/;
            var match = pattern.exec(link);
            // If not found, try the title as the last parameter
            if (!match) {
                pattern = /.*title=(.*?)$/;
                match = pattern.exec(link);
            }
            if (match) newPageTitle = match[1];

            // Determine if the page should be created in a different space
            // Try looking for a space key with more parameters after it
            pattern = /.*spaceKey=(.*?)&/;
            match = pattern.exec(link);
            // If not found, try the space key as the last parameter
            if (!match) {
                pattern = /.*spaceKey=(.*?)$/;
                match = pattern.exec(link);
            }
            var targetSpaceKey = match ? match[1] : null;
        }
        else {
            var targetSpaceKey = spaceKey;
        }

        // Invoke the wizard to either edit or view the wiki markup
        var editParams = {pageId: pageId, spaceKey: targetSpaceKey, targetSpaceKey: targetSpaceKey, newPage: true};
        if (newPageTitle) editParams.newPageTitle = newPageTitle;
        if (copyPageId) editParams.copyPageId = copyPageId;
        ZW.startEditFormViaAjax(null, ZW.zenActionUrl("startnew" + context), editParams, ZPE.initializeNewPageEditor);

        // Stop the link from loading
        return false;
    },
	
    // 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("A page title 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;                            
    },
    
    // Validate the page title, return true if valid
    validateTitle: function () {
            
        // Stop if the page title is invalid
	    if (!ZPE.validTitle(ZPE.currentPageTitle())) return false;
        
        // If the user hasn't made any changes, let them know before bailing out
	    if (!ZW.hasChanges()) {
	        ZW.alert("It doesn't look like you've made any changes.");
	        return false;
	    }
	        
	    return true;
    }

};

(function ($) {
    
    // Add the edit/publish control panel to the editable item
	jQuery.fn.addControlPanel = 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 = canEdit ? "Edit this section" : "View wiki markup for this section";
        if (isHistoricalVersion) title = "Start a draft using this historical version";
        panel.append("<a href='#' class='edit-control' title='" + title + "'></a>");
        panel.find(".edit-control").click( function () { 
            // Confirm editing the site menu
            if (item.hasClass("site-menu") && !item.hasClass("zen-preview-draft") && 
                !ZW.confirm("Changes to this menu will be seen across the entire site.", "Click 'OK' to continue, or 'Cancel' to go back.")) return false;

            // Confirm creating a draft based on the historical version
            if (isHistoricalVersion && !ZW.confirm("You are about to create a draft based on this historical version.", "Click 'OK' to create a new draft, or 'Cancel' to continue viewing.")) return false;

            // if (useZenEditor) ZPE.startEditingMarkup(item);
            var url = contextPath + "/zen/classic/edit" + context + ".action?viewPageId=" + pageId + "&pageId=" + ZPE.pageId(item);
            if (isHistoricalVersion) url += "&copyPageId=" + pageId;
            window.location = url;

            return false;
        } );

        // Add the publish control, if needed, and set its click action (the editable object is the control panel's parent)
        if (item.hasClass("zen-preview-draft")) {
            panel.append("<a href='#' class='publish-control' title='Publish this draft section'></a>");
            panel.find(".publish-control").click( function () { panel.parent().publish(); return false } );
        }
        
        // Activate the edit and publish controls when the mouse enters the editable Zen theme area
        item.hover(
            function () { 
                if (disableEdits || ZW.isEditing()) item.toggleEditControls(false)
                else item.toggleEditControls(true)
            },
            function () { item.toggleEditControls(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() {
            if (!disableEdits && !ZW.isEditing()) {
                item.toggleEditControls(true);
            }
        });
    };

    // Add the blocked indicator to the editable item
	jQuery.fn.addBlockedPanel = 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 edit and publish controls when the mouse enters the editable Zen theme area
        item.hover(
            function () { 
                if (disableEdits || ZW.isEditing()) item.toggleEditControls(false)
                else item.toggleEditControls(true)
            },
            function () { item.toggleEditControls(false) }
        );    
    };

    // 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 () {
            // Add the edit title control and wire it to open the title editor
            var item = Zen.$("#zen-page-title", this);
            
            // If there's no visible page title, add the title editor control to the regular control panel
            if (!item.length || item.css("display") == "none") item = Zen.$("#zen-main .control-panel");
            
            item.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 () { 
                
                if (useZenEditor) {
                    ZPE.startEditTitle(item.parent());
                }
                else {
                    // Ignore if the user can't edit
            	    if (!canEdit) return false;

                    // ZW.startEditFormViaAjax(item, ZW.zenActionUrl("edit" + context + "title"), {pageId: pageId}, ZPE.initializeTitleEditor, ZPE.cancelEditor);
                    // 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;
                            }

                            // Can't have a blank title
                            if (!newTitle.length) {
                                ZW.alert("Titles can't be blank.");
                                return false;
                            }
                            
                            // Page titles cannot contain:    @ / \ | ^ # ; : [ ] { } < >
                            var pattern = /[@\/\\\|^#;:\[\]{}<>]/;
                            if (pattern.exec(newTitle)) {
                                ZW.alert("Titles cannot contain: @ / \ | ^ # ; : [ ] { } < >");
                                return false;
                            }                            

                            // Page titles cannot start with any of these three sequences:   $  ..  ~
                            pattern = /^[$~]|^\.\./;
                            if (pattern.exec(newTitle)) {
                                ZW.alert("Titles cannot start with: $  ..  ~");
                                return false;
                            }                            

                            // Give the user a chance to confirm the immediate title change
                            return ZW.confirm("This " + pageType + " title will be changed for others to see.", "Click 'OK' to change the title, or 'Cancel' to keep editing.");
                        });
                    });
                }
                return false; 
            } );

            // Activate the edit title control when the mouse enters the page title area
            // If edit title control is in the control panel, then just activate it full time within the control panel
            if (Zen.$("#zen-main .control-panel #edit-title-control").length) {
                item.toggleTitleEditControl(true);
            }
            else {
                item.hover(
                    function () { item.toggleTitleEditControl(true) },
                    function () { item.toggleTitleEditControl(false) }
                );    
            }
        });
    };
    
    // 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.");
                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;
             
        });
	};
   
    // Stop all other animations so edit buttons don't go nuts during spastic mousing
    jQuery.fn.stopTitleEditAnimations = function () {
        ZPE.titleEditControl().stop(true, true);
    };

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

            ZW.stopAnimations();
            
            // Animate the coming and going of the menu
            if (mouseOver) Zen.$(this).find(".control-panel").wait(500).fadeIn("medium");
            else Zen.$(this).find(".control-panel").fadeOut("fast");

        });
    };

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

            // Animate the coming and going of the menu
            if (mouseOver) ZPE.titleEditControl().wait(500).fadeIn("medium");
            else ZPE.titleEditControl().fadeOut("fast");
       });
    };

})(jQuery);

AJS.toInit(function ($) {
    
    // Stop if user can't edit
    if (!canEdit || !isLicensed) return;
    
    // Add the edit controls to each of the editable Zen theme content areas, making sure there's a pageId to support it
    $(".zen-editable-content").filter("[pageId]").each(function () {
        // Do nothing if the user isn't allowed to edit the menu
        if ($(this).attr("id") == "zen-menu" && !canEditMenu) return;
        if ($(this).attr("id") == "zen-footer" && !canEditFooter) return;
        
        // Add the control panel to support editing, which is activated when the mouse enters the editable content area
        // For unauthorized page sections, display a different control panel
        if ($(this).hasClass(".zen-page-section") && !canEditSections) $(this).addBlockedPanel();
        else $(this).addControlPanel();
    });
    
    // Add the control panel to support editing, which is activated when the mouse enters the editable content area
    $("#zen-main").addTitleEditControl();
    // if (!titleEditLocation.length) titleEditLocation = 
    //     $(".zen-editable-content[pageId] #zen-page-title").each(function () {
    //         $(this).addTitleEditControl();
    //     });
    // }
    // else {
    //     
    // }
    

});


/********************
 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 ($) {
    $(".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 ($) {
	canvasFixedWidth = 0;

    if (isStretchy) {
        $("body").css({padding: "0 " + zenBodyPadding});
        $("#zen-toolbar-holder").css({marginLeft: "-" + zenBodyPadding});
        $("#zen-toolbar").css({marginRight: zenBodyPadding});
    }
    else {
        var padding = $("#canvas").innerWidth() - $("#canvas").width();
        // canvasFixedWidth is a "global"
        canvasFixedWidth = $("#canvas").width() - padding;
        // The blog list placeholder test is in place to fix ZEN-141
        if (!isBlogListPlaceholder) $("#canvas").css({width: 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: 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, .zen-title)").remove();

    // Move the blog post calendar to the top of the right or left column, top or bottom extras,
    // or the main page area if none of those exist.
    if      ($("#zen-right").length)  $("#zen-right").prepend($("#blog-calendar"))
    else if ($("#zen-left").length)   $("#zen-left").prepend($("#blog-calendar"))
    else                              $("#blog-calendar").remove();
    // Remaining options removed for ZEN-99
    // else if ($("#zen-top").length)    $("#zen-top").prepend($("#blog-calendar"))
    // else if ($("#zen-bottom").length) $("#zen-bottom").prepend($("#blog-calendar"))
    // else                              $("#zen-page-title").after($("#blog-calendar"));
    
    // 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>");

});


/********************
 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"));
    
});



/********************
 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 = "Space Designer";
    var height = 624;
    var width = 600;
    if (pageDesign) {
        title = blog ? "Blog Designer" : "Page Designer";
        height = 524;
    }
    if (pageContents) {
        title = blog ? "Blog Contents" : "Page Contents";
        height = 264;
    }
    
    // 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='top']",           this).val(Zen.$("#top-section-layout.selected"              ).length ? "true" : "false");
    Zen.$("[name='right']",         this).val(Zen.$("#right-column-layout.selected"             ).length ? "true" : "false");
    Zen.$("[name='bottom']",        this).val(Zen.$("#bottom-section-layout.selected"           ).length ? "true" : "false");
    Zen.$("[name='left']",          this).val(Zen.$("#left-column-layout.selected"              ).length ? "true" : "false");
    Zen.$("[name='metaData']",      this).val(Zen.$("#meta-data-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");
	}

}



/********************
 calendar.js 
********************/

AJS.toInit( function ($) {
   
	// Validate the user's input for an event
	var validateEvent = function () {
		var title =  $("#title", this).val();
		if (!ZPE.validTitle(title)) {
			// ZPE will alert if title is invalid
			return false;
		}
		var fromDate = $("#start-date-submit", this).val();
		var toDate =   $("#end-date-submit",   this).val();
		if (toDate < fromDate) {
			alert("Your event ends before it starts. Check dates and times.");
			return false;
		}
		if (!$("#calendar-filter option:selected", this).val().length) {
			alert("Please select a calendar.");
			return false;
		}
	};

    // Make the edit menu item show the form in a dialog
    var editEvent = function() {
	
		// Lose any previous dialog and its shadow
	    Zen.Dialog.clearPrevious();
		
		// Find the currently selected event (TODO: factor out)
		var event = $(".zen-calendar .focus .calendar-event-title");
		
		// Copy the edit panel into a dialog and set it to the current event
        var dialog = new Zen.Dialog($(".event-edit").clone().attr("id", "event-edit").show(), {title: "Edit Event", height: 400});
		dialog.$("input[name='pageId']").val(pageId);
		dialog.$("input[name='eventToken']").val(event.attr("data-id"));
		dialog.$("#title").val(event.text());
		dialog.$("#where").val(event.attr("data-where"));
		dialog.$("#start-date-editor").dateEditorInitialize(event.attr("data-from"));
		dialog.$("#end-date-editor"  ).dateEditorInitialize(event.attr("data-to"));
		dialog.$("#details"  ).val(event.attr("data-details"));
		// Set the relevant calendar option to selected
		dialog.$("#calendar-filter option[value='" + event.attr("data-calendar") + "']").attr("selected", "selected");
				
		// Validate the form
		dialog.$("#event-edit").submit(validateEvent);

        dialog.show();

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

    // Make the remove page menu item show the form in a dialog
    var removeEvent = 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;
    };
    
    var loseFocus = function (event) {
        // Stop if the user clicked on the popup
        if ($(event != undefined && event.target).parents(".event-popup").length) return;
        
        $(".event-popup").remove();
        $(".zen-calendar .focus").removeClass("focus");

		// Stop listening for key events
		$(document).unbind("keydown", popupProcessKey);
    };

	var setPopupElement = function (popup, element, selector) {
		if ($(element).attr("data-" + selector).length) {
			$("." + selector, popup).append($(element).attr("data-" + selector));
		}
		else {
			$("." + selector, popup).hide();
		}
	};
	
	var setPopupElementDate = function (popup, element, selector) {
		if ($(element).attr("data-" + selector).length) {
			var dateData = $(element).attr("data-" + selector).split(".");
			var dateString = dateData[1] + "/" + dateData[2] + "/" + dateData[0] + " " + dateData[4] + ":" + dateData[5] + " " + dateData[3];
			$("." + selector, popup).append(dateString);
		}
		else {
			$("." + selector, popup).hide();
		}
	};
	
	// All views - open details panel
    var focusEvent = function (event) {
        // Remove the old focus and any popup, before setting the focus on the clicked event
        $(".focus", $(this).offsetParent()).removeClass("focus");
        $(".event-popup").remove();
        $(this).parent().addClass("focus");
        
        // Make a copy of the event popup
        var popup = $("#popup-template").clone().addClass("event-popup").show();
        
        // Copy the event's title, date, and other information to the popup
        $(".title", popup).text($(this).text());
		setPopupElement(popup, this, "where");
		setPopupElement(popup, this, "details");
		setPopupElementDate(popup, this, "from");
		setPopupElementDate(popup, this, "to");

        // Calculate a display spot for the popup that leans toward the center of the screen
        var pos = $(this).offset();
        $(this).offsetParent().append(popup);
        pos.top = pos.top - 8;
        var newLeft = pos.left - 232;
        if (newLeft < $(this).offsetParent().offset().left) newLeft = pos.left + $(this).parents("ul").width();
        pos.left = newLeft;
        popup.offset(pos);
        
        // Set the popup controls to have relevant actions (view, move, edit, etc.)
        $(".view", popup).attr("href", contextPath + $(this).attr("data-link"));
        $(".edit", popup).click(editEvent);
        // $(".scraps", popup).attr("href", contextPath + "/zen/classic/editblogpost.action?viewPageId=" + pageId + "&pageId=" + $(this).attr("data-id") + "&publish=true");
        $(".delete", popup).attr("href", contextPath + "/plugins/zen/removepage.action?pageId=" + $(this).attr("data-id") + "&key=" + spaceKey + "&spaceKey=" + spaceKey).click(removeEvent);
        $(".hide", popup).click(function() {popup.hide(); return false;});
        
        // Allow the popup to respond to key presses
        $(document).keydown(popupProcessKey);
        
        // Prevent other events from firing due to the focus event
        event.stopPropagation();
    };

	// Launch new event dialog 
	var newEvent = function () {
		
		// Lose any previous dialog and its shadow
	    Zen.Dialog.clearPrevious();
				
		// Copy the edit/create panel into a dialog and set it to the current date
        var dialog = new Zen.Dialog($(".event-edit").clone().attr("id", "event-edit").show(), {title: "Edit Event", height: 400});
		dialog.$("input[name='pageId']").val(pageId);
		
		// Make the form call the create action (by default it calls the edit action)
		var newAction = dialog.$("#event-edit").attr("data-create-action");
		dialog.$("#event-edit").attr("action", newAction);
		
		// Initialize to the currently selected date	
		dialog.$("#start-date-editor").dateEditorInitialize($(this).attr("data-from"));
		dialog.$("#end-date-editor"  ).dateEditorInitialize($(this).attr("data-to"));
				
		// Validate the form
		dialog.$("#event-edit").submit(validateEvent);

        dialog.show();

        // Stop the default menu-item click action from firing ************
        return false;
	}
    
	// Position weekly event
    var positionEvent = function () {
        // Find the target timeslot
        var timeslot = $("#" + $(this).attr("data-timeslot"));
        
        // Figure out how many timeslots the event will fill
        var slots = $(this).attr("data-hours") * 4;
        
        // For each affected timeslot, increment the count of events occupying it
        var affected = $.merge(timeslot.parent().nextAll(":lt(" + slots + ")").find(".timeslot"), timeslot);
        affected.each(function() { $(this).attr("data-count", parseInt("0" + $(this).attr("data-count")) + 1)});

        // Adjust the height to be multiples of the quarter-hour timeslots, then subtract the event's padding
        var height = timeslot.outerHeight() * slots;
        height -= $(this).outerHeight() - $(this).height();
        timeslot.append($(this).css({height: height}).show());
    };
    
    // Handle key events on the calendar
    var popupProcessKey = function (event) {
	
		// Don't try to handle keyboard events when the event editor is showing
		if ($("#event-edit:visible").length) return;

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

            // Needed to prevent endless loop in Safari 4 when dismissing the discard-changes panel with the ESC key
            event.preventDefault();
            return AJS.stopEvent(event);
        }

        // 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;
    };

	// Toggle visibility of events in response to selection
	var toggleCalendar = function () {
		// If hidden, make visible
		$(this).toggleClass("hide-calendar");
		$(".zen-calendar .calendar-event-title[data-calendar='" + $(this).attr("data-calendar") + "']").parent().toggleClass("hidden");
	}

	// Highlight the calendar selector in response to event hovers
	var highlightSelector = function () {
		unhighlightCalendar();
		$(this).addClass("highlight");
		$("#calendar-selector li[data-calendar='" + $(this).attr("data-calendar") + "']").addClass("highlight");
	}
	
	// Highlight the calendar events in response to mouse hovers
	var highlightCalendar = function () {
		unhighlightCalendar();
		$(this).addClass("highlight");
		$(".zen-calendar .calendar-event-title[data-calendar='" + $(this).attr("data-calendar") + "']").addClass("highlight");
	}

	// Unhighlight the calendar events in response to mouse hovers
	var unhighlightCalendar = function () {
		$(".zen-calendar .calendar-event-title").removeClass("highlight");
		$("#calendar-selector .highlight").removeClass("highlight");
	}
    
    // Return the number of calendars displayed in the scrollable view
    var count = function () {
        return $(".zen-calendar").length;
    };
    
    // Return the first calendar (or placeholder) in the scrollable view
    var first = function () {
        return $(".zen-calendar:first");
    }
    
    // Return the last calendar (or placeholder) in the scrollable view
    var last = function () {
        return $(".zen-calendar:last");
    }
    
    // Return the position of calendar
    var position = function (calendar) {
        return parseInt($(calendar).css("margin-left"));
    }
    
    // Return the currently viewed calendar
    var current = function () {
        return $(".zen-calendar.current");
    }
    
    // Make calendar the currently viewed calendar
    var show = function (calendar) {
        loseFocus();
        $(".zen-calendar.current").removeClass("current");
        $(calendar).addClass("current");
        $("#calendar-selector").hide();
        canvas().height(calendar.height());
        canvas().animate({marginLeft: -position(calendar)}, "medium", function () {
            $("#calendar-selector").show();
        });
    };

    // Return the calendar before the current calendar in the scroller, if any
    var previous = function () {
        return current().prev();
    };
    
    // Return the calendar after the current calendar in the scroller, if any
    var next = function () {
        return current().next();
    };

    // Load the calendar for the current waiting placeholder element
    var load = function () {
        // Call the server to provide the calendar via AJAX
        var destination = placeholder();
        jQuery.ajax({
            url: contextPath + "/plugins/zen/loadcalendar.action", 
            data: {view: "month", dateString: destination.attr("data-this-month") + "/01", spaceKey: spaceKey}, 
            success: function (response) {
                // Preserve the location of the placeholder in the scroller
                var newCal = $(response).addClass("current").css({marginLeft: position(destination)});
                destination.replaceWith(newCal);
                initializeCalendar(newCal);
            },
            error: function (xhRequest, textStatus, errorThrown) {
                ZW.alert("Couldn't load calendar from server:", textStatus + (errorThrown ? "\n\n" + errorThrown : ""));
            }
        });
        
    };
    
    // Return the existing placeholder, if any
    var placeholder = function () {
        return $("#calendar-loading");
    };
    
    // Return a new placeholder for a loading calendar for the month in the current calendar's dataAttr,
    // ready to display at newPos in the scroller
    var newPlaceholder = function (dataAttr, newPos) {
        return $("<div id='calendar-loading' class='zen-calendar scroll-horizontal'></div>")
            .attr("data-this-month", current().attr(dataAttr))
            .css({width: scrollAmount(), height: current().outerHeight(), marginLeft: newPos});
    };

    // Add room for another calendar to end of the scroller, and ask the server to render it
    var loadNext = function () {
        // Stop if we're already waiting for another month to load
        if (placeholder().length) return;
        
        canvas().append(newPlaceholder("data-next-month", position(last()) + scrollAmount()));
        load();
    };
    
    // Add room for another calendar to beginning of the scroller, and ask the server to render it
    var loadPrevious = function () {
        // Stop if we're already waiting for another month to load
        if (placeholder().length) return;
        
        canvas().prepend(newPlaceholder("data-previous-month", position(first()) - scrollAmount()));
        load();
    };
    
    // Move to the next calendar in the scroller, loading it if necessary
    var viewNext = function () {
        if (!next().length) loadNext();
        else show(next());
    };
    
    // Move to the previous calendar in the scroller, loading it if necessary
    var viewPrevious = function () {
        if (!previous().length) loadPrevious();
        else show(previous());
    };
    
    var canvas = function () {
        return $("#zen-calendar-canvas");
    };
    
    var scrollAmount = function () {
        return $("#zen-calendar-viewer").outerWidth();
    };
    
    // For each new calendar inserted into the scroller, make sure it is wired and sized properly
    var initializeCalendar = function (calendar) {
        $(".calendar-event-title", calendar).click(focusEvent);
    	$(".calendar-event-title", calendar).hover(highlightSelector, unhighlightCalendar);
    	$(".new-event", calendar).dblclick(newEvent);
        $(calendar).click(loseFocus);

        $(calendar).css({width: baselineCalendar.width() + "px", left: 0});

        // Move the weekly calendar events into place
        $(".week .time .event", calendar).each(positionEvent);
        
        show(calendar);
    };
    
	// Bind the calendar filters
	$("#calendar-selector li").hover(highlightCalendar, unhighlightCalendar);
	$("#calendar-selector li").click(toggleCalendar);

    // Make sure the scroll area is sized to match the current calendar
    var baselineCalendar = $(".zen-calendar");
    if (baselineCalendar.length) {
        
        $("#zen-calendar-viewer").innerWidth(baselineCalendar.outerWidth());
        canvas().width(scrollAmount()).height(baselineCalendar.height());

        // Wire the calendar previous/next buttons
        $("#zen-previous-calendar").click(viewPrevious);
        $("#zen-next-calendar").click(viewNext);

        // Initialize the first calendar
        initializeCalendar(baselineCalendar);

    }

});


/********************
 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);
        });	
	};
	
	// 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 ($) {
});



/********************
 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.");
    }
});


