/*
 * This file is generated.  Do not edit it directly.
 * Run 'ant annotate' to regenerate it.  See tools.javascript.JSConstantApf
 */

var LookupInputElement = {
'LOOKUP_IFRAME' : "lookupIFrame",
'pLOOKUP_WIDGET' : "_lkwgt",
'DIALOG_ID' : "LookupOverlayDialog"
};

var ForecastRoleUser = {
'pUSER' : "user",
'FORECAST_SHARE_RADIO' : "forecastSharingRadios",
'pCAN_SHARE' : "allowMgrFctSharing"
};

var OppSalesTeamRowEdit = {
'SPLIT_PERCENTAGE_LABEL' : "splitPercentage_row",
'IS_SPLIT_LABEL' : "isSplit_row",
'SPLIT_AMOUNT_LABEL' : "splitAmount_row",
'ROW_TYPE_LABEL' : "rowType_row",
'SUMMARY_ROW_ID' : "stt_summaryRow",
'USER_LOOKUP_ID_LABEL' : "userLookup_row",
'SPLIT_NOTE_LABEL' : "splitNote_row",
'ROW_ID_LABEL' : "salesTeam_row"
};

var IFrameElement = {
'EmptyRelatedListDoc' : "emptyHtmlDoc.html",
'BLANK_SRC' : "javascript: \'\'"
};

var DetailElement = {
'DEFAULT_DETAIL_ELEMENT_ID' : "ep",
'DEFAULT_ERROR_DIV_ID' : "errorDiv_ep",
'TOP_BUTTON_ROW' : "topButtonRow",
'BOTTOM_BUTTON_ROW' : "bottomButtonRow"
};

var TaskOwnerLookup = {
'pLOOKUP_UROG_SUFFIX' : "_lkurogid",
'DONE_BUTTON_ID' : "doneButton"
};

var DatePickerIds = {
'DOM_ID' : "datePicker",
'MONTH_PICKER' : "calMonthPicker",
'TABLE_ID' : "datePickerCalendar",
'YEAR_PICKER' : "calYearPicker"
};

var SectionElement = {
'LEFT_TABLE_CLASS' : "detailList"
};

var BusinessHoursPageConstants = {
'p24X7_CHECKBOX' : "has24x7"
};

var EmailAuthorConstants = {
'EMAIL_ADDR_DELIM' : "; "
};

var AjaxGetFieldTreeChildren = {
'FORMULA_TYPE' : "formulaType",
'NODE_LIST' : "nodeList",
'NODE_KEY' : "nodeKey"
};

var UserDeactivate = {
'pREMOVE_FROM_CLOSED_OPP_TEAMS' : 2,
'pREMOVE_FROM_ACCOUNT_TEAMS' : 1,
'pREMOVE_FROM_OPEN_OPP_TEAMS' : 3,
'pSPLITS_REMOVAL_NOTE' : 4
};

var InlineEditConstants = {
'FIELD_REQUIRED' : "required",
'MASS_EDITABLE' : "massEditable",
'VALIDATION_ERRORS' : "validationErrors",
'NULLABLE' : "nullable",
'FIELD_STATE' : "state",
'LAYOUT_INFO' : "layoutInfo",
'IS_PERSON' : "isPerson",
'FIELD_ID' : "fieldId",
'MAX_SAVE' : 200,
'COLUMN_NAME' : "columnName",
'COLUMN_ID' : "columnId",
'NON_SPECIFIC_ERRORS' : "nonSpecificErrors",
'OVERRIDE_TYPE' : "overrideType",
'ROLODEXABLE' : "useRolodex",
'SUCCESS' : "success",
'IS_TASK' : "isTask",
'INNER_ID' : "_ileinner",
'ENTITY_ID' : "entityId",
'FIELD_VALUE' : "initialValue",
'EDITABLE' : "editable",
'LAST_MOD' : "sysMod",
'CELL_ID' : "_ilecell",
'SAVED' : "saved",
'FIELD_TYPE' : "fieldType",
'SAVE_BUTTON' : "inlineEditSave",
'FIELD_DATA' : "fields",
'IDS' : "recordIds",
'ENTITY_TYPE' : "entityType",
'CANCEL_BUTTON' : "inlineEditCancel",
'NAME_LABEL' : "nameLabel",
'SORTABLE' : "isSortable",
'COLUMN_LABEL' : "label",
'DYNAMIC_DATA' : "dynamicData"
};

var CreateNewList = {
'DHTML_ID' : "newEntityList"
};

var SetupTreeNodeConstants = {
'COOKIE_KEY' : "setupopen"
};

var CriteriaInputConstants = {
'pOP' : "critop",
'pCOL' : "critfld",
'FILTER_SECTION_ID' : "filterSection",
'pFIELD_VAL' : "critfld_val",
'pVAL' : "pVAL",
'pLOOKUP' : "pLOOKUP",
'SHOW_SUMMARY_FILTER' : "filterControl"
};

var EmailCCBccLookupConstants = {
'CC_NAME_ID' : "cc_name",
'CC_ID' : "cc",
'ADDITIONAL_TO_ID' : "additional_to",
'BCC_ADDR_ID' : "bcc_addr",
'BCC_ID' : "bcc",
'ADDITIONAL_TO_NAME_ID' : "additional_to_name",
'ADDITIONAL_TO_ADDR_ID' : "additional_to_addr",
'BCC_NAME_ID' : "bcc_name",
'REF_ID' : "ref",
'CC_ADDR_ID' : "cc_addr"
};

var SearchSettingsConstants = {
'SIDEBAR_SEARCH_ENTITY_PICKER_ID' : "enableSidebarSearchEntityPicker",
'DEFAULT_SEARCH_ENTITY_CHECKBOX_ID' : "defaultSearchEntityCheckbox",
'DEFAULT_SEARCH_ENTITY_PICKLIST_ID' : "defaultSearchEntityPicklist"
};

var MultiSelectList = {
'pIDS' : "selectedIds",
'pFILTER_TYPE' : "filterType",
'availableTableId' : "availableTable",
'availableFrameId' : "available",
'pUNSAVED_IDS' : "unsavedIds",
'pTOTAL_ROW_COUNT_FILTER' : "msl_totalRowCountFilter",
'selectedFrameId' : "selected",
'availableCheckboxPrefix' : "chk_",
'nameCellPrefix' : "name_",
'availableRowPrefix' : "row_",
'allOrNoneCheckbox' : "allOrNone",
'pTOTAL_ROW_COUNT' : "msl_totalRowCount",
'selectedCheckboxPrefix' : "uch_",
'listEmptyLabelId' : "listEmptyLabel",
'selectionsTableId' : "selections",
'selectedRowPrefix' : "sel_",
'selectLabelId' : "selectLabel",
'deselectLabelId' : "deselectLabel"
};

var BlowoutServlet = {
'SUCCESS' : "success",
'BLOWOUT' : "blowout",
'SUFFIX' : "suf",
'SERVLETURL' : "/_ui/system/scheduler/cron/ScheduleBlowoutServlet"
};

var CSRFConstants = {
'CSRF_TOKEN' : "_CONFIRMATIONTOKEN"
};

var AjaxLoadPLAServlet = {
'TYPE' : "type",
'PAGE_SIZE' : "pageSize"
};

var FilterEditPageConstants = {
'pSEARCH_ANCHOR' : "searchAnchor"
};

var EmailTemplatePreviewConstants = {
'REQUIRED_BLOCK_CLASS' : "requiredBlock",
'ID_REQUIRED_BLOCK_ID' : "_id_required_block",
'LOOKUP_REQUIRED_BLOCK_ID' : "_lookup_required_block"
};

var InlineHelp = {
'CLASS_NAME' : "helpButton",
'ORB' : "helpOrb",
'DISPLAY_DIV_CLASS' : "helpText",
'CLASS_NAME_HOVER' : "helpButtonOn",
'ID_SUFFIX' : "_help"
};

var SchedulePage = {
'pNotifyMe' : "nm",
'pIsOffPeak' : "isoffpeak",
'pBlowout' : "bout",
'pNotifyOthers' : "no",
'pJobType' : "jt",
'pDuelOuter' : "duelOuter",
'pEmailUrog' : "eurog"
};

var ListView = {
'CHECKBOX_ID' : "ids",
'DEFAULT_ROWS_PER_PAGE' : 50,
'ID_COLUMN' : "LIST_RECORD_ID",
'SELECT_ALL_BOX_ID' : "allBox",
'ACTION_COLUMN' : "ACTION_COLUMN"
};

var OpportunitySalesTeamEdit = {
'SPLIT_AMOUNT_TOTAL_ID' : "splitAmtPer",
'SPLIT_TOTAL_ID' : "splitTotal",
'SALES_TEAM_MEMBER_TABLE_ID' : "stt",
'SPLIT_TOTAL_PER_ID' : "splitTotPer"
};

var TagConstants = {
'TAG_EDIT_LIST' : "tag_edit_list",
'BROWSER_SEARCH_HEADER_CLASS' : "pbTagBrowserSearch",
'TAG_DROP_DOWN_CONTENTS_ID' : "tag_drop_down_contents",
'BROWSER_LIST_ID' : "browseTags",
'BROWSER_TAG_TABLE_ID' : "browseTagsTable",
'EDIT_AREA_ID' : "tag_edit_area",
'TAG_DISPLAY_CONTAINER' : "tag_display_container",
'TAG_RESULTS_ID' : "tagResults",
'TAG_VALUE_FOR_UPDATE' : "tValForUpdate",
'ROLODEX_SEARCH_VALUE' : "-10",
'HIDING_PUBLIC_SECTION_ID' : "layoutPublicEditSection",
'CHANGE_TAGS_NAMES' : "changeTagsNames",
'TAG_SEARCH_FIELD' : "tagsSearch",
'TAG_MERGE_CHECK' : "/ui/tag/TagMergeCheckServlet",
'ERROR_DIV_ID' : "tagHomeErrorDiv",
'TAG_RESULTS_BODY_ID' : "tagListBody",
'TAG_EDIT_ERROR_ID' : "tag_edit_error",
'TAG_DROP_DOWN_ID' : "tag_drop_down",
'LOOKUP_TAGS_PAGE' : "/ui/tag/LookupTagsPage",
'TAG_ID_LIST' : "tIdList",
'TAG_HEADER' : "tag_header",
'TAG_SEARCH_RESULTS_URL' : "/search/TagSearchResults",
'SAVED_TAG_SEARCH' : "savedTagSearch",
'EDIT_SECTION_ID' : "editSectionId",
'NOTIFY_MSG_ID' : "successNotifyId",
'PUBLIC_TAG_IDS_ELEM' : "pTagIds",
'TAG_SAVE_ID' : "tag_save",
'HIDING_SECTION_ID' : "layoutEditSection",
'TAG_SUMMARY_ID' : "tagSummary",
'PUBLIC_TAG_NAMES_ELEM' : "pTagNames",
'TAG_DISPLAY_LIST' : "tag_display_list",
'TAG_ROLODEX_ID' : "tagRolodexId",
'TAG_SET_HAS_RECORDS' : "tagSetHasRecords",
'CHANGE_TAGS_IDS' : "changeTagsIds",
'HIDDEN_TAG_LIST' : "hidden_tag_list",
'TAG_IDS_ELEM' : "tagIds",
'SAVE_TAGS_PAGE' : "/ui/tag/SaveTagsPage",
'HIDDEN_TAG_ID_LIST' : "hidden_tag_id_list",
'TAG_UPDATE_STRING' : "tagUpdate",
'TAG_EDIT_ID' : "tag_edit",
'TAG_NAMES_ELEM' : "tagNames",
'EDIT_TAGS_PAGE' : "/ui/tag/TagsEditPage",
'pTAG_SCOPE_MODE' : "scopeMode",
'TAG_EDIT_TEXT_ID' : "tag_edit_text",
'IS_DELETE' : "isDelete",
'TAG_CANCEL_ID' : "tag_cancel"
};

var BounceEmailConstants = {
'HIDDEN_BOUNCE_DATE' : "hidden_bounce_date",
'HIDDEN_EMAIL_ADDRESS' : "hidden_email_address",
'HIDDEN_BOUNCE_REASON' : "hidden_bounce_reason"
};

var RequestInfo = {
'pSID' : "sid"
};

var LookupsUi = {
'LOOKUPS' : "lookups",
'FIELD' : "field",
'PATH' : "path"
};

var CrtLookupConstants = {
'LOOKUP_HEADER' : "lookupInnerHeader",
'CONTROL_ELEM_1' : "controlLinks1",
'LOOKUP_DEPTH_LIMIT' : 4,
'LOOKUP_ELEM' : "lookupBox",
'PATH_ELEM' : "pathBox"
};

var StageManager = {
'pWIZARD_RET_URL' : "wizardRetUrl"
};

var ActivityReminderPage = {
'pCLASS_NAME' : "ui.core.activity.ActivityReminderPage"
};

var MouseOverElement = {
'DEFAULT_CLASS_INNER' : "mouseOverInfo",
'DEFAULT_CLASS' : "mouseOverInfoOuter"
};

var ActivityReminderConstants = {
'pTEST' : "test",
'DISMISS_ID' : "dismiss",
'SUMMARY_ID' : "summary",
'SNOOZE_TIME_ID' : "snooze_time",
'DUE_MINUTES_ID' : "minutes",
'ALL_DAY_ATTR' : "all_day",
'DUE_TIME_ATTR' : "due_time",
'DISMISS_ALL_ID' : "dismiss_all",
'SNOOZE_ID' : "snooze",
'pAT' : "at",
'REMINDERS_OK' : "reminders_ready",
'pSNOOZED_AT' : "snoozed_at",
'REMINDER_ID' : "reminder",
'REMINDERS_NONE' : "reminders_none_active"
};

var ForecastSettings = {
'pFORECAST_SHARING' : "forecastSharing",
'pALLOW_FM_SHARING' : "allowFMSharing"
};

var ColorInputConstants = {
'COLOR_BOX_CSS' : "colorBox",
'ERROR_COLOR_BOX_CSS' : "errorColorBox"
};

var AdvancedCurrencyEnable = {
'pENABLE' : "enable",
'enableButton' : "enableButton"
};

var AjaxLoadPLAForRecordTypeServlet = {
'RECORD_TYPE_ID' : "rtId"
};

var AjaxLoadPLAForPageServlet = {
'PAGE_NUM' : "pageNum"
};

var CustomMotifDefinitionPageConst = {
'MOTIF_ICON_PARAM' : "file_id",
'COLOR_ELEMENT' : "ce"
};

var DeveloperSettings = {
'LICENSE_MGR_CHOICE_STR' : "licenseMgr"
};

var ReportsFch = {
'FLOATING_HEADER' : "floatingHeader",
'HEADER_ROW' : "headerRow",
'FCH_AREA' : "fchArea"
};

var findSimilarQueryPage = {
'FIND_PROVIDER' : "findSimilarProvider",
'SEARCH_QUERY_STRING' : "srch"
};

var UiData = {
'pCANCEL_URL' : "cancelURL",
'pRET_URL' : "retURL",
'pSAVE_URL' : "saveURL"
};

var SetupSearchElement = {
'ATT_SEARCH_TEXT' : "searchText",
'SETUP_SEARCH_PARAM' : "setupSearch"
};

var DurationInputElement = {
'pMINUTES_NAME' : "mi",
'pHOURS_NAME' : "hh"
};

var CompactLayoutUiConst = {
'showItemsLeft' : "showItemsLeft",
'showItemsRight' : "showItemsRight",
'switchColumnToLeft' : "switchColumnLeft",
'hideItemsLeft' : "hideItemsLeft",
'hideItemsRight' : "hideItemsRight",
'switchColumnToRight' : "switchColumnRight",
'saveButtonId' : "saveButton"
};

var MotifInputElementConst = {
'FIELD_NAME_MOTIF' : "motifName",
'MOTIF_ELEMENT_SUFFIX' : "motifElement",
'FIELD_NAME_ICON' : "motifIcon",
'FIELD_NAME_DESCRIPTION' : "motifClass"
};

var DesktopSidebarComponents = {
'GOOGLETALK_CONTAINER_ID' : "googleTalk",
'SOFTPHONE_CONTAINER_ID' : "softphoneContainer",
'MRU_LIST_CONTAINER_ID' : "mruList"
};

var EventObject = {
'ONE_DAY_IN_MINUTES' : 1440
};

var MultiLookupInputElement = {
'MULTI_LOOKUP_SELECT_SUFFIX' : "_mlktp"
};

var SoftphoneLayoutEditorConstants = {
'RESULT_FIELDS_KEY' : "resultFields",
'CALL_TYPE_PREFIX' : "callType_",
'XSLT_RELATED_OBJS_CSS' : "relatedObjects",
'HIDDEN_IFRAME_ID' : "previewIframe",
'FLIPPY_PREFIX' : "flippy_",
'CALL_TYPE_PREVIEW_PREFIX' : "callTypePreview_",
'FIRST_FLIPPY_CSS' : "firstFlippy",
'FLIPPY_CONTROL_PREFIX' : "control_",
'XSLT_INFO_FIELDS_CSS' : "infoFields",
'LISTING_PREFIX' : "listing_"
};

var ChangePasswordConstants = {
'pANSWER_ERROR_ELEM' : "answerContainsPassword",
'pNEW_PASSWORD_CONFIRMATION_ICON_ELEM' : "passVerify",
'pNEW_PASSWORD_CONFIRMATION_ELEM' : "p6",
'pQUESTION_ELEM' : "p2",
'pOLD_PASSWORD_ELEM' : "p4",
'pNEW_PASSWORD_ELEM' : "p5",
'pANSWER_ELEM' : "p3",
'pANSWER_ICON_ELEM' : "answerVerify",
'pNEW_PASSWORD_STRENGTH_ELEM' : "passStrength",
'pNEW_PASSWORD_ICON_ELEM' : "strengthImage"
};

var ForecastSummaryPage = {
'pLOOKUP_INPUT_ENTERED' : "lookupEntered"
};

var vaSelectElementConst = {
'UP_CLASS' : "up",
'DOWN_CLASS' : "down"
};

var MCXHRParams = {
'pLoadObjId' : "LOI",
'pIsSuccess' : "isSuccess",
'pTestResultRecordCount' : "recordCount",
'pSaveObjParentId' : "SPI",
'pTestResultDataSize' : "dataSize",
'pScope' : "scope",
'pLoadObjType' : "LOT",
'pTotalsElement' : "totalsElement",
'pTestResultConfigError' : "configError",
'pCollisionParam' : "LMT",
'pData' : "data",
'pSaveObjId' : "SOI",
'pQSTestResults' : "qsTestResults",
'pTestResultQSID' : "id",
'pAction' : "ACT",
'pSaveObjType' : "SOT",
'pFilterItemCount' : "itemCount"
};

var TagMode = {
'PUBLIC' : "public",
'PERSONAL' : "personal"
};

var AjaxValidateFormula = {
'RANGE_KEY' : "range",
'VALID_KEY' : "valid"
};

var UserInterfaceUI = {
'pNEW_LIST_VIEW_NAME' : "newListView",
'pCLICK_AND_CREATE_ON_CALENDAR_NAME' : "clickAndCreateOnCalendar",
'pINLINE_SCHEDULING_NAME_MESSAGE' : "inlineSchedulingMessage",
'pDRAG_AND_DROP_ON_CALENDAR_NAME' : "dragAndDropOnCalendar",
'pINLINE_SCHEDULING_NAME' : "inlineScheduling"
};

var CrtLayoutElement = {
'cFIELD_IN_SECTION' : "#CCCCCC",
'pVALUE' : "val",
'SECTION_NAME' : "name",
'SECTION_CAN_EDIT_LABEL' : "canEditLabel",
'MAX_DISPLAY_FIELD_LENGTH' : 15,
'cFIELD_USED_FONT' : "#B0B0B0",
'CSS_CLASS_LAYOUT_ITEM_SEPARATOR' : "sepCell",
'LAYOUT_NAME' : "name",
'pSAVE_AND_CLOSE' : "saveAndClose",
'ACTIONREF_NAME' : "name",
'COLUMN_NAME' : "columnName",
'LAST_SEC_SEP_DIV' : "LAST_SEC_SEP_DIV",
'SECTION_SORT_ORDER_HORIZONTAL' : "h",
'cSEPARATOR_ON' : "#000000",
'SECTION_NUM_COLUMNS' : "numColumns",
'SECTION_SORT_ORDER' : "sortOrder",
'cFIELD_UNUSED' : "#CCCCAA",
'cFIELD_SELECTED' : "#6699CC",
'SECTION_DIV_SUFFIX' : "availSectionDiv",
'ITEM_CUSTOMLABEL' : "customLabel",
'ACTIONREF' : "actionRef",
'ITEM_LAYOUT_IDS' : "lIds",
'CSS_CLASS_LAYOUT_ITEM' : "itemCell",
'ITEM_BEHAVIOR' : "behavior",
'SECTION_HEADER_ID_PREFIX' : "sec_",
'ITEM_NAME' : "name",
'ITEM_POS_X' : "xPos",
'XML_FORM_NAME' : "submitForm",
'SCROLL_BUFFER_ID' : "scrollBuffer",
'cFIELD_EMPTY' : "#FFFFFF",
'LAYOUT_FIELDS_LIMIT' : 1000,
'SECTION_MASTER_LABEL' : "masterLabel",
'SECTION_TABLE_ID_PREFIX' : "table",
'ITEM_HEIGHT' : "height",
'SECTION_ID' : "sectionId",
'ITEM_WIDTH' : "width",
'COLUMN_ID' : "columnId",
'DEFAULT_NUM_COLS' : "defaultNumCols",
'HOVER_DIV' : "MOUSE_HOVER_DIV",
'SECTION_EDIT_HEADING' : "editHeading",
'cAVAILABLE_HIGHLIGHT' : "#000000",
'MAIN_TABLE_DIV_ID' : "mainTableDiv",
'ITEM' : "item",
'ITEM_ID' : "itemId",
'SECTION_SEP_DIV_PREFIX' : "LayoutSectionSeparator_",
'ACTIONREF_ORDER' : "order",
'NUM_LAYOUT_COLS' : 4,
'FIELD_TYPE_SELECT_NAME' : "availableDropDown",
'SEPARATOR_PREFIX' : "rp_",
'SECTION' : "section",
'CSS_CLASS_LAYOUT_CELL' : "layoutCell",
'cFIELD_USED' : "#EEEEEE",
'SECTION_AVAIL_WRAPPER_ID' : "availableSectionWrapper",
'ITEM_DEFAULT_CHECKED' : "defaultChecked",
'AVAIL_CELL' : "availCell",
'ITEM_SHOWLABEL' : "showLabel",
'ITEM_SHOWSCROLLBARS' : "showScrollbars",
'LEFT_SECTION_ID' : "layoutdndLeft",
'COLUMN' : "column",
'ITEM_TYPE' : "itemType",
'SECTION_DETAIL_HEADING' : "detailHeading",
'ROOT_CONTAINER' : "root"
};

var MailmergeTemplateSelectElementConst = {
'TEMPLATE_DESCRIPTION' : "mmtse_description",
'TEMPLATE_VIEW_BUTTON' : "mmtse_preview",
'TEMPLATE_ID' : "mmtse_id",
'TEMPLATE_TITLE' : "mmtse_title"
};

var GoogleDocCreator = {
'FORM_NAME' : "googleDocForm",
'UPLOAD' : 1,
'DOC_NAME' : "docName",
'DOC_UPLOAD_NAME' : "docUploadName",
'DOC_UPLOAD' : "docUpload",
'DOC_TYPE' : "docType",
'DIALOG_ID' : "DocNameInputId",
'CREATE' : 0,
'METHOD' : "method",
'PARENT_ID' : "parentId"
};

var FilterSelectionElement = {
'pCOLUMN' : "col",
'ON_LOAD_CRITERIA' : "onLoadCriteria",
'pOPERATOR' : "oper",
'pFILTER_VALUE' : "fval"
};

var TaskUi = {
'ASSIGNEE_SEPARATOR' : ",",
'pLOOKUP_BUTTON_MULTI_OWNER_SUFFIX' : "m",
'pSHOW_PREFERENCE' : "show_pref",
'MAX_TMU_ASSIGNEES' : 100,
'pNOTIFY_PREFERENCE_GROUP_ELEMENT' : "prefEl",
'pMAX_ASSIGNEE_TEXT_LENGTH' : 200,
'pLOOKUP_SUMMARY_SUFFIX' : "_sum",
'pLOOKUP_DISPLAY_SUFFIX' : "_dsp"
};

var DynamicContent = {
'pTYME' : "tyme",
'pERROR_TITLE' : "errorTitle",
'pCOOKIE_PARAM' : "cookieParam",
'pERROR_DESC' : "errorDesc"
};

var TimePickerInputElementConstants = {
'EMPTY_TIME_STANDIN' : "HH:MM"
};

var RoleTreeCookieConstants = {
'COOKIE_KEY' : "roleopen"
};

var HTPortal = {
'pORG_ID' : "orgId",
'pID' : "id",
'pTRACK' : "track",
'pTARGET' : "target",
'pCLASS_NAME' : "cname",
'pSECTION' : "section",
'pCLASS_DAY' : "R_DAY",
'pSELECT_LOCATION' : "sel_loc",
'pBODY' : "body",
'pLOCATION' : "loc",
'pFEATURE' : "feature"
};

var EditPageConstants = {
'pCANCEL' : "cancel",
'pEDIT_PAGE' : "editPage",
'pSAVE_CLOSE' : "save_close",
'pSAVE_ATTACH' : "save_attach",
'pSAVE_NEW_URL' : "save_new_url",
'pSAVE_NEW' : "save_new",
'pSAVE' : "save",
'pQUICK_SAVE' : "quick_save"
};

var EventUi = {
'START_TIME_PARAM_NAME' : "startTimeId",
'REMINDER_DATE_TIME_ID' : "reminder_dt",
'PRIVATE_CHECKBOX_PARAM_NAME' : "privateCheckboxId",
'REMINDER_SET_ID' : "reminder_select_check",
'ALL_DAY_PARAM_NAME' : "allDayId",
'WHAT_LINK_PARAM_NAME' : "whatLinkId",
'WHAT_NAME_PARAM_NAME' : "whatNameId",
'REMINDER_DATE_TIME_PARAM_NAME' : "reminderDateTimeTimeId",
'pONLINE_HOVER' : "olmhov",
'ALL_SUBGROUP_DIVS' : "dwmy",
'WHO_ID_PARAM_NAME' : "whoId",
'START_DATE_PARAM_NAME' : "startDateId",
'WHO_TYPE_PARAM_NAME' : "whoTypeId",
'RECURRING_EVENT_PARAM_NAME' : "isRecurringId",
'RECURRENCE_PATTERN_DIV' : "recpat",
'LEAD_PREFIX_PARAM_NAME' : "leadPrefix",
'pADD_INVITEE_ID' : "addInvId",
'REMINDER_SELECT_ID' : "reminder_lt",
'pONLINE_MEETING' : "onlinemtg",
'VISIBLE_IN_SS_PARAM_NAME' : "isVisibleInSelfServiceId",
'WHAT_ID_PARAM_NAME' : "whatIdId",
'WHAT_TYPE_PARAM_NAME' : "whatTypeId",
'END_DATE_PARAM_NAME' : "endDateId",
'pISPERSONACCOUNT' : "pip",
'END_TIME_PARAM_NAME' : "endTimeId"
};

var EmailAddrEditConstants = {
'pSAVE_CANCEL' : "saveCancel",
'pPASS_IN_EMAIL_ADDRESS' : "pass_in_email_address"
};

var EventPage = {
'DISABLED_RECURRENCE_MSG_DIV' : "DisabledRecurrenceMsgDiv",
'CALENDAR_IFRAME_ID' : "calendarIFrame"
};

var MenuButtonElement = {
'BUTTON' : "Button",
'GO_BUTTON' : "Go",
'MENU' : "Menu",
'SELECT' : "Select"
};

var CrtConstants = {
'PICKLIST_VALUE_TABLE_FIELD_SEPARATOR' : '.',
'OBJECT_PREFIX' : "o",
'MAX_OBJECTS' : 4,
'PICKLIST_VALUE_ID_SEPARATOR' : '|'
};

var Activity = {
'WHO_BUTTON_ID' : "whobtn",
'pNEW_ATTACHMENTS' : "newatt",
'pATT_WARNING' : "attWarning"
};

var ColorPickerConstants = {
'HEX_VIEW_ID' : "colorPickerHexView",
'DOM_ID' : "colorPicker",
'COLOR_VIEW_ID' : "colorPickerColorView"
};

var CrtObjectElement = {
'TERMINAL_OBJECT_WARNING' : "endWarning",
'REMOVE_OBJECT_LINK' : "remove",
'INNER_JOIN_SELECT' : "inner_select",
'GHOST1' : "ghost1",
'MAX_OBJECTS_WARNING' : "warning",
'LEVEL' : "level",
'ELBOW_INNER' : "elbow_inner",
'ELBOW_OUTER' : "elbow_outer",
'EST_OBJECT_LABEL' : "estObjLabel",
'JOIN_RADIO' : "radio",
'INNER_JOIN_OPTION' : "inner_join_option",
'GHOST_ELBOW' : "ghost_elbow",
'GHOST0' : "ghost0",
'OUTER_JOIN_SELECT' : "outer_select"
};

var MCFilterPaneParams = {
'pORDER_BY_DIV' : "orderBySection",
'pNO_LIMIT' : "noLimit",
'pMAX_RECORD_RADIO' : "maxRecordRadio",
'pSCOPE' : "ofscope",
'pSET_LIMIT' : "setLimit",
'NONE_SCOPE_VALUE' : "-1"
};

var BodyLayout = {
'FOOTER_DIV_ID' : "bodyFooter",
'PAGE_HEADER_ID' : "AppBodyHeader",
'BODY_CELL_ID' : "bodyCell",
'BODY_TABLE_ID' : "bodyTable"
};

var HoverTooltipElement = {
'DEFAULT_CLASS_TEXT' : "mouseOverText"
};

var JSPDispatcher = {
'STANDARD_PACKAGE' : "ui",
'NONSTANDARD_PACKAGE_PREFIX' : "_ui/",
'PACKAGE_MARKER' : "p/"
};

var InlineScontrolElement = {
'DEFAULT_WIDTH' : -100,
'DEFAULT_HEIGHT' : 200
};

var ActivityReminderRefreshPage = {
'pCLASS_NAME' : "ui.core.activity.ActivityReminderRefreshPage"
};

var AjaxServlet = {
'CSRF_PROTECT' : "while(1);\n",
'ERROR_MSG_KEY' : "errMsg"
};

var RuleFilterPageConstants = {
'NO_REASSIGN_SUFFIX' : "_noReassign"
};

var FieldTreeConstants = {
'SELECT_ID' : "FieldTreeSelect"
};

var Udd = {
'EMPTY_KEY' : "000000000000000"
};

var ProfileEditConstants = {
'CRUD_DELETE' : "crudDelete",
'CRUD_UPDATE' : "crudUpdate",
'CRUD_CREATE' : "crudCreate",
'CRUD_READ' : "crudRead"
};

var CaptchaVerifierServlet = {
'RESPONSE_PARAM' : "resp",
'SERVLET_NAME' : "common.html.captcha.CaptchaVerifierServlet",
'VALID_KEY' : "valid",
'CLIENT_ERROR_PARAM' : "error",
'CHALLENGE_PARAM' : "chal"
};

var AbstractAutoCompleteServlet = {
'AUTOCOMPLETE_USED_SUFFIX' : "_acused",
'pINPUT' : "inputString"
};

var EditEventMultiUserCalendarElementConstants = {
'EDIT_PAGE_CALENDAR' : "editEventCalendar"
};

var SearchRelatedList = {
'FILTER_FIELDS_PARAM' : "sFltrFields",
'ALL_STATES_PREFIX' : "allStates_",
'SearchUserLayoutServletName' : "UserSearchListLayout",
'COMBO_BUTTON_ID' : "comboButton",
'SearchFilterInfoServletName' : "SearchFilterInfo",
'COLUMN_SELECTOR_PREFIX' : "selector_",
'LIST_LAYOUT_TYPE_PARAMETER' : "layoutType",
'ERROR_DIV_ID_PREFIX' : "srchErrorDiv_",
'SEARCH_ACTION_IDENTIFIER_PARAM' : "aId",
'COLUMN_PARAMETER' : "columns",
'pSEARCH' : "search",
'pSEARCH_STR' : "str",
'ENTITY_PARAMETER' : "entity",
'SEARCH_IDENTIFIER_PARAM' : "searchId",
'PER_ENTITY_VALUE' : "perEntityValue",
'FILTER_FIELDS_SAVE_PREFIX' : "save_filter_",
'pENTITY_ALL' : "0",
'ShouldNotLookUp' : "noLookUp",
'FILTER_FIELD_FORM_PREFIX' : "field_name_form_",
'FILTER_FIELDS_PREFIX' : "field_name_"
};

var AjaxGetUsersInGroups = {
'pOWNER_ID_LIST' : "ownerIdList",
'pCLASS_NAME' : "common.ownership.group.AjaxGetUsersInGroups",
'pNUM_USERS' : "numUsers",
'pINVALID_GROUPS_MESSAGE' : "invalidGroups",
'pOWNER_NAME_LIST' : "ownerNameList"
};

var SidebarConstants = {
'HANDLE_ID' : "handle",
'SIDEBAR_PINNED_COOKIE' : "sidebarPinned",
'pSEARCH_SIDEBAR_STR' : "sbstr",
'PIN2_INDICATOR_ID' : "pinIndicator2",
'PIN_INDICATOR_ID' : "pinIndicator",
'SIDEBAR_DIV_ID' : "sidebarDiv"
};

var ColumnTypeConstants = {
'PERSONNAME_LASTNAME_OFFSET' : 2,
'PERSONNAME_FIRSTNAME_OFFSET' : 1,
'DEFAULT_STATE_LENGTH' : 20,
'ADDRESS_STREET_OFFSET' : 0,
'DEFAULT_CITY_LENGTH' : 40,
'PERSONNAME_SALUTATION_OFFSET' : 0,
'DEFAULT_ZIP_LENGTH' : 20,
'DEFAULT_SALUTATION_LENGTH' : 40,
'ADDRESS_POSTAL_CODE_OFFSET' : 3,
'DEFAULT_LASTNAME_LENGTH' : 80,
'DEFAULT_FIRSTNAME_LENGTH' : 40,
'DEFAULT_COUNTRY_LENGTH' : 40,
'ADDRESS_COUNTRY_OFFSET' : 4,
'ADDRESS_CITY_OFFSET' : 1,
'ADDRESS_STATE_OFFSET' : 2,
'DEFAULT_TEXTNAME_LENGTH' : 255,
'DEFAULT_STREET_LENGTH' : 255
};

var Desktop = {
'AgentConsoleY' : "AgentConsoleY",
'AgentConsoleS' : "AgentConsoleS",
'pGOTO_ID' : "goToId",
'RESIZE_WIDTH' : "resizeWidth",
'pGOTO_URL' : "goToUrl",
'AgentConsoleX' : "AgentConsoleX",
'BROWSER_MAX_URL' : "2048",
'AgentConsoleFE' : "AgentConsoleFE",
'SIDEBAR_NORMAL_WIDTH_STYLE_PX' : "200",
'IS_DESKTOP' : "isdtp"
};

var EditElement = {
'FIELD_NAME_LAST' : "name_last",
'pOLD_NAME_SUFFIX' : "_lkold",
'SELECTED_ID_SUFFIX' : "_selected",
'FIELD_NAME_ZIP' : "zip",
'pBASE_NAME' : "lknm",
'pTYPE_SUFFIX' : "_lktp",
'FIELD_NAME_SALUTATION' : "name_salutation",
'FIELD_NAME_CITY' : "city",
'FIELD_NAME_COUNTRY' : "country",
'pID_SUFFIX' : "_lkid",
'STREET_NUM_COLS' : 27,
'FIELD_NAME_FIRST' : "name_first",
'FIELD_NAME_STREET' : "street",
'FIELD_NAME_STATE' : "state",
'CHECKBOX_SUFFIX' : "_chkbox",
'STREET_NUM_ROWS' : 2,
'ERROR_CLASS' : "error",
'UNSELECTED_ID_SUFFIX' : "_unselected"
};

var EmailRelayConstants = {
'EMAIL_RELAY_TLS_SETTING_ID' : "email_relay_tls_setting",
'RESTRICT_TO_DOMAINS_ID' : "restrict_to_domains",
'ACTIVATE_RESTRICT_TO_DOMAINS_ID' : "activate_restrict_to_domains",
'EMAIL_HOST_PORT_ID' : "email_host_port",
'EMAIL_HOST_ID' : "email_host",
'ACTIVATE_EMAIL_RELAY_ID' : "activate_email_relay",
'RESTRICT_TO_DOMAINS_HIDDEN_ID' : "restrict_to_domains_hidden"
};

var BrowserSettingsWarningElement = {
'NEVER_SHOW_AGAIN_ID' : "browserSettingsWarningGoAway",
'cBrowserSettings' : "numReqs",
'BROWSER_SETTINGS_WARNING_ID' : "browserSettingsWarning",
'MORE_INFO_ID' : "browserSettingsWarningMoreInfo"
};

var ReportConstants = {
'pSubTotalBy0' : "subtotalBy0"
};

var CreateNewElement = {
'DOM_ID' : "createNew"
};

var ForecastSharingPrefPopup = {
'CAN_SHARE_RADIO' : "enableRadio",
'pIS_FCT_SHARE_ENABLED' : "isFctShareEnabled",
'DISABLE_CHECKBOX' : "disableCheckbox"
};

var SummaryFieldConstants = {
'OPERATION_CONTAINER_ID' : "operationCtr"
};

var NewLayoutEditor = {
'BLANK_ID' : "__BLANK",
'STD_BTN_PREFIX' : "BTN__"
};

var ScheduleElement = {
'pPrefTimeDiv' : "prefTime",
'pPrefTimeLabelDiv' : "prefTimeLabel",
'pDailyEveryNDays' : "dn",
'pMonthlyOnDayN' : "mdom",
'pPrefTime' : "pst",
'pEndDate' : "end",
'pStartDate' : "start",
'pPrefTimeLoadingDiv' : "prefTimeLoad",
'pFreq' : "freq",
'pMonthlyOnNthDay' : "mond",
'pDailyRec' : "dr",
'pOtherPrefTimeLabelDiv' : "otherPrefTimeLabel",
'pDayOfWeek' : "ww",
'pOuterBox' : "outerBox",
'pMonthlyRec' : "mr",
'pMonthlyOnNDayOfWeek' : "mdn"
};

var GoogleTalkConstants = {
'MIN_EXPANDED_HEIGHT' : 22,
'EXPANDED_HEIGHT' : 400,
'HEIGHT_COOKIE' : "gTalkHeight",
'COLLAPSED_HEIGHT' : 0,
'COLLAPSED_COOKIE' : "gTalkCollapsed"
};

var PortalStyleConfigEditorConstants = {
'PARAM_PREFIX' : "p_"
};

var SalesTeamRowTypeEnum = {
'EXISTING_DELETED' : "Existing_Deleted",
'NEW_DELETED' : "New_Deleted",
'EXISTING_INACTIVE' : "Existing_Inactive",
'EXISTING' : "Existing",
'NEW' : "New"
};

var AjaxLoadFieldsForEntity = {
'pFIELD_LIST' : "fieldList",
'pENTITY_NAME' : "entity",
'pPARENT_ENTITY_NAME' : "parentEntity"
};

var TaskMassAction = {
'ROW_LIMIT' : 200
};

var ManageableInfo = {
'MORE_INFO_CLASS' : "manageableMoreInfo",
'DHTML_ID' : "manageableInfo"
};

var LayoutItemTypeEnum = {'CUSTOM_RELATED_LIST':{'dbValue':'L','apiValue':'L'}
,'CUSTOM_LINK':{'dbValue':'K','apiValue':'K'}
,'STANDARD_FIELD':{'dbValue':'F','apiValue':'F'}
,'EMPTY_SPACE':{'dbValue':'E','apiValue':'E'}
,'CUSTOM_FIELD':{'dbValue':'C','apiValue':'C'}
,'TAGGING':{'dbValue':'T','apiValue':'T'}
,'DETAIL_BUTTON_BAR':{'dbValue':'B','apiValue':'B'}
,'CUSTOM_S_CONTROL':{'dbValue':'S','apiValue':'S'}
,'STANDARD_RELATED_LIST':{'dbValue':'R','apiValue':'R'}
,'PAGE':{'dbValue':'P','apiValue':'P'}
}
;
var InlineEditState = {'READONLY':{'display':true,'cssClass':'inlineEditLock'}
,'POSTONLY':{'display':false,'cssClass':''}
,'NONE':{'display':false,'cssClass':''}
,'EDIT':{'display':true,'cssClass':'inlineEditWrite'}
}
;
var QueryOperator = {'NOT_EQUAL':{'value':'n'}
,'EQUALS':{'value':'e'}
,'GREATER_THAN':{'value':'g'}
,'NOT_LIKE':{'value':'j'}
,'EXACT_EQUALS':{'value':'a'}
,'RANGE_EXCLUSIVE':{'value':'E'}
,'EXCLUDES':{'value':'x'}
,'STARTS_WITH':{'value':'s'}
,'NOT_CONTAIN':{'value':'k'}
,'RANGE_INCLUSIVE':{'value':'I'}
,'LESS_THAN':{'value':'l'}
,'RANGE_INCL_RIGHT':{'value':'R'}
,'RANGE_INCL_LEFT':{'value':'L'}
,'LESS_OR_EQUAL':{'value':'m'}
,'CONTAINS':{'value':'c'}
,'NOT_START_WITH':{'value':'t'}
,'INCLUDES':{'value':'u'}
,'LIKE':{'value':'i'}
,'NOT_EXACT_EQUALS':{'value':'o'}
,'GREATER_OR_EQUAL':{'value':'h'}
}
;
var ColumnType = {'ANYTYPE':{'inlineEditFieldObject':null,'queryOperators':null,'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'K','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'AUTONUMBER':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'V','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'PERCENT':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return NumberField;},'datatypeLetter':'P','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':true,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'BLOB':{'inlineEditFieldObject':null,'queryOperators':null,'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'X','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'FAX':{'inlineEditFieldObject':'PhoneField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return PhoneField;},'datatypeLetter':'G','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength','formatPhone'],'isDate':false}
,'DOUBLE':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return NumberField;},'datatypeLetter':'N','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':true,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'STATICENUM':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return StaticEnumField;},'datatypeLetter':'L','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':true,'inlineEditable':true,'inlineEditExtraData':['picklistData'],'isDate':false}
,'CURRENCYCODE':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return StaticEnumField;},'datatypeLetter':'L','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['picklistData'],'isDate':false}
,'TEXTENUM':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'L','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'ADDRESSCOUNTRY':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'S','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'EMAIL':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'E','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'PHONE':{'inlineEditFieldObject':'PhoneField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return PhoneField;},'datatypeLetter':'H','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength','formatPhone'],'isDate':false}
,'ENTITYID':{'inlineEditFieldObject':'ForeignKeyField','queryOperators':['e','n','s'],'isCompond':false,'inlineEditFieldConstructor':function(){return ForeignKeyField;},'datatypeLetter':'Y','filterQueryOperators':['e','n','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['domain','useNewLookups'],'isDate':false}
,'YEARQUARTER':{'inlineEditFieldObject':null,'queryOperators':null,'isCompond':true,'inlineEditFieldConstructor':null,'datatypeLetter':'O','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'TIMEONLY':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'f','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'ENCRYPTEDTEXT':{'inlineEditFieldObject':'EncryptedTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return EncryptedTextField;},'datatypeLetter':'6','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength','masked'],'isDate':false}
,'RECORDTYPE':{'inlineEditFieldObject':null,'queryOperators':['e','n'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'7','filterQueryOperators':['e','n'],'isNumber':false,'needsLookup':true,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'HTMLSTRINGPLUSCLOB':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return MultiLineTextField;},'datatypeLetter':'z','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength','numCols','numRows','isHtml'],'isDate':false}
,'SWITCHABLE_PERSONNAME':{'inlineEditFieldObject':null,'queryOperators':null,'isCompond':true,'inlineEditFieldConstructor':function(){return null;},'datatypeLetter':'m','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'PERSONNAME':{'inlineEditFieldObject':'PersonNameField','queryOperators':null,'isCompond':true,'inlineEditFieldConstructor':function(){return PersonNameField;},'datatypeLetter':'M','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['hasSalutation','reverse','picklistId','labels'],'isDate':false}
,'DUEDATE':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return DateField;},'datatypeLetter':'F','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['hasTime'],'isDate':true}
,'URL':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'U','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'CONTENT':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'9','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'MULTILINETEXT':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return MultiLineTextField;},'datatypeLetter':'X','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'ADDRESSSTATE':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'S','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'MULTIENUM':{'inlineEditFieldObject':'MultiEnumField','queryOperators':['e','n','u','x'],'isCompond':false,'inlineEditFieldConstructor':function(){return MultiEnumField;},'datatypeLetter':'Q','filterQueryOperators':['e','n'],'isNumber':false,'needsLookup':true,'inlineEditable':true,'inlineEditExtraData':['picklistId','controller','controllerLabel','height'],'isDate':false}
,'SFDCENCRYPTEDTEXT':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'T','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'STRINGPLUSCLOB':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return MultiLineTextField;},'datatypeLetter':'J','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'BIRTHDAY':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return DateField;},'datatypeLetter':'D','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['hasTime'],'isDate':true}
,'INTEGER':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return NumberField;},'datatypeLetter':'N','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':true,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'BOOLEAN':{'inlineEditFieldObject':'BooleanField','queryOperators':['e','n'],'isCompond':false,'inlineEditFieldConstructor':function(){return BooleanField;},'datatypeLetter':'B','filterQueryOperators':['e','n'],'isNumber':false,'needsLookup':true,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'CURRENCY':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return NumberField;},'datatypeLetter':'C','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':true,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':null,'isDate':false}
,'DATETIME':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return DateField;},'datatypeLetter':'F','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['hasTime'],'isDate':true}
,'DIVISION':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return StaticEnumField;},'datatypeLetter':'I','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':true,'inlineEditable':true,'inlineEditExtraData':['picklistData'],'isDate':false}
,'INETADDRESS':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'W','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'TEXT':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return TextField;},'datatypeLetter':'S','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength'],'isDate':false}
,'DYNAMICENUM':{'inlineEditFieldObject':'DynamicEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return DynamicEnumField;},'datatypeLetter':'L','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':true,'inlineEditable':true,'inlineEditExtraData':['picklistId','controller','controllerLabel'],'isDate':false}
,'BITVECTOR':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'8','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'HTMLMULTILINETEXT':{'inlineEditFieldObject':'HtmlMultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':function(){return HtmlMultiLineTextField;},'datatypeLetter':'5','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['maxLength','isHtml'],'isDate':false}
,'ENUMORID':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'L','filterQueryOperators':['e','n','c','k','s'],'isNumber':false,'needsLookup':true,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'DATEONLY':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'isCompond':false,'inlineEditFieldConstructor':function(){return DateField;},'datatypeLetter':'D','filterQueryOperators':['e','n','l','g','m','h'],'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['hasTime'],'isDate':true}
,'FFX_BLOB':{'inlineEditFieldObject':null,'queryOperators':null,'isCompond':false,'inlineEditFieldConstructor':null,'datatypeLetter':'X','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':false,'inlineEditExtraData':null,'isDate':false}
,'ADDRESS':{'inlineEditFieldObject':'AddressField','queryOperators':null,'isCompond':true,'inlineEditFieldConstructor':function(){return AddressField;},'datatypeLetter':'A','filterQueryOperators':null,'isNumber':false,'needsLookup':false,'inlineEditable':true,'inlineEditExtraData':['showState','labels'],'isDate':false}
}
;
/*
* @author mpolcari
* @since 142.wm
*/

function GenericSfdcPage() {
  this.init()

  this.inlineHelpMap = {};
  this.helpFader = null;
  this.helpParentElement = null;

  var self = this;

  this.handleHelpHover = function(e){
      var target = getEventTarget(getEvent(e));
      if (!target || UserContext.isAccessibleMode) return;
      if (target.className == InlineHelp.CLASS_NAME){
          target.className = InlineHelp.CLASS_NAME_HOVER;
      } else if (target.nodeName == 'LABEL' && target.parentNode && target.parentNode.className == InlineHelp.CLASS_NAME){
          target.parentNode.className = InlineHelp.CLASS_NAME_HOVER;
      }else if (target.className == InlineHelp.ORB){
          helpSpan = target.parentNode;
          while (!(helpSpan.className == InlineHelp.CLASS_NAME || helpSpan.className == InlineHelp.CLASS_NAME_HOVER)){
              helpSpan = helpSpan.parentNode
          }
          var helpId = helpSpan.id;
          helpSpan.className = InlineHelp.CLASS_NAME_HOVER;
          if (helpId && helpId.length > InlineHelp.ID_SUFFIX.length){
              var helpKey = helpId.substring(0, helpId.length - InlineHelp.ID_SUFFIX.length);
              self.showHelp(helpKey, helpSpan);
          }
      }
  }

  this.handleHelpUnhover = function(e){
      var target = getEventTarget(getEvent(e));
      if (!target || UserContext.isAccessibleMode) return;
      if ((target.className == InlineHelp.CLASS_NAME_HOVER) && mouseExited(e, target)){
          target.className = InlineHelp.CLASS_NAME;
      } else if ((target.nodeName == 'LABEL' && target.parentNode.className == InlineHelp.CLASS_NAME_HOVER) && mouseExited(e, target.parentNode)) {
          target.parentNode.className = InlineHelp.CLASS_NAME;
      } else if (target.className == InlineHelp.DISPLAY_DIV_CLASS && mouseExited(e, target)){
          var toElement = getEventToElement(getEvent(e));
          if (toElement && toElement.className != InlineHelp.ORB && self.helpFader){
              self.helpFader.fadeOut();
          }
      } else if (target.className == InlineHelp.ORB && mouseExited(e, target)){
          var toElement = getEventToElement(getEvent(e));
          var parent = target.parentNode;
          //hack for accessiblity mode, where the img has a link around it.
          if (UserContext.isAccessibleMode){
              parent = parent.parentNode;
          }
          if (toElement.className == InlineHelp.DISPLAY_DIV_CLASS){
              return;
          }
          if (toElement != parent){
              parent.className = InlineHelp.CLASS_NAME;
          }
          if (self.helpFader){
              self.helpFader.fadeOut();
          }
      }
  }

  this.appendToOnloadQueue(function() {
      addEvent(document, 'mouseover', self.handleHelpHover, false);
        addEvent(document, 'mouseout', self.handleHelpUnhover, false);
        if (XBrowser.userAgent.isIE){
            addEvent(document.body, 'click', self.handleLabelClickIEOnly);
        }
  });
}

GenericSfdcPage.prototype.init = function() {
  this.onLoadQueue = [];
  this.onBeforeUnloadQueue = [];
  this.hasRun = false;
  this.relatedLists = [];
  this.relatedListsById = {};
  this.dialogs = {};
  this.messages = {};
  this.appendToOnloadQueue(function() { XBrowser.turnOnBackgroundImageCache(); }, "Turn on CSS background image cache (IE6 only)");
}

GenericSfdcPage.prototype.handleLabelClickIEOnly = function(e){
    var event = getEvent(e);
    var target = getEventTarget(event);
    if (!target) return;
    if (target.tagName == "LABEL" && target.htmlFor){
        var input = getElementByIdCS(target.htmlFor);
        if (input){
        	if (input.type && input.type.toLowerCase() == 'checkbox'){
        		input.click()
        	} 
        	if (input.focus){
        		input.focus();
        		e.returnValue = false;
        	}
        }
    }
};

GenericSfdcPage.prototype.prependToOnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  if (this.hasRun) {
    this.execFunctionNoThrow(fn); //if the queue has already run, just execute this function
  } else {
    this.onLoadQueue.unshift(fn);
  }
}

GenericSfdcPage.prototype.appendToOnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  if (this.hasRun) {
    this.execFunctionNoThrow(fn); //if the queue has already run, just execute this function
  } else {
    this.onLoadQueue.push(fn);
  }
}

GenericSfdcPage.prototype.executeOnloadQueue = function() {
  for(var i = 0; (this.onLoadQueue && (i < this.onLoadQueue.length)); i++) {
    this.execFunctionNoThrow(this.onLoadQueue[i]);
  }
  this.hasRun = true;
  this.onLoadQueue = [];
}

GenericSfdcPage.prototype.prependToOnBeforeUnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  this.onBeforeUnloadQueue.unshift(fn);
}

GenericSfdcPage.prototype.appendToOnBeforeUnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  this.onBeforeUnloadQueue.push(fn);
}

GenericSfdcPage.prototype.executeOnBeforeUnloadQueue = function() {
  for(var i = 0; (this.onBeforeUnloadQueue && (i < this.onBeforeUnloadQueue.length)); i++) {
    this.execFunctionNoThrow(this.onBeforeUnloadQueue[i]);
  }
}

GenericSfdcPage.prototype.execFunctionNoThrow = function(fn) {
    try {
      fn();
    } catch (ex) {
      if (fn.desc) ex.sfdcDesc = fn.desc;
      Gack.handleException(ex);
    }
}


GenericSfdcPage.prototype.registerRelatedList = function(listId, visibleRowCount, title, hasMore, refURL, refQS, onlySkipLink) {
  var firstList = (this.relatedLists.length == 0);

  if(!this.relatedListsById[listId]){
      this.relatedListsById[listId] = new RelatedList(listId, visibleRowCount, title, hasMore, refURL, refQS, onlySkipLink);
      this.relatedLists.push(this.relatedListsById[listId]);
  }

  if (this.relatedListPanel) {
    this.relatedListPanel.registerList(this.relatedListsById[listId]);
  }
  ///If this is the first RL on the page, queue up the panel initialization script
   var self = this;
   if (firstList) {
     this.prependToOnloadQueue(
       function () {
         if ((self.relatedListPanel) && (self.relatedListPanel.addListsToPanel)) {
           self.relatedListPanel.addListsToPanel();
         }
      }, "rlHovers: Initializing panel");
    }
}

GenericSfdcPage.prototype.registerDialog = function(dialog) {
    this.appendToOnloadQueue(function() { dialog.createDialog(); }, "Create a dialog");
    this.dialogs[dialog.id] = dialog;
}

GenericSfdcPage.prototype.getDialogById = function(dialogId) {
    return this.dialogs[dialogId];
}

GenericSfdcPage.prototype.getRelatedListById = function(listId) {
  return this.relatedListsById[listId];
}

/**
  Retrieves the current address as an URLencoded retUrl
*/
GenericSfdcPage.prototype.getHrefAsRetURL = function() {
  var href = window.location.href;

  var retUrlArr = href.split("/");
  retUrlArr.splice(0,3);
  return encodeURIComponent("/" + retUrlArr.join("/"));
}

GenericSfdcPage.prototype.includeJavascriptTag = function(scriptUri) {
    return this.embedJSTag(scriptUri, document);
}

GenericSfdcPage.prototype.embedJSTag = function(scriptUri, doc) {
    var html_doc = doc.getElementsByTagName('head').item(0);
    var js = doc.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', scriptUri);
    html_doc.appendChild(js);
    return false;
}

GenericSfdcPage.prototype.embedExternalStyleSheet = function(sheetUrl, doc) {
    var styleNode = doc.createElement("link");
    styleNode.setAttribute("href", sheetUrl);
    styleNode.setAttribute("type", "text/css");
    styleNode.setAttribute("rel", "stylesheet");

    var targetHead = doc.body.parentNode.firstChild;
    targetHead.appendChild(styleNode);
}

GenericSfdcPage.prototype.hideEmbeddingIframe = function(iframeWin) {
    if (iframeWin.name && document.getElementById(iframeWin.name)) {
      document.getElementById(iframeWin.name).style.display = 'none';
      document.getElementById(iframeWin.name).parentNode.style.border ='none';
    }
}

GenericSfdcPage.prototype.setHelp = function(key, text){
    this.inlineHelpMap[key] = text;
}

GenericSfdcPage.prototype.getHelp = function(key){
    return this.inlineHelpMap[key];
}

/**
 * Set parent for the help element
 */
GenericSfdcPage.prototype.setHelpParent = function(parentElement){
    this.helpParentElement = parentElement;
}

GenericSfdcPage.prototype.showHelp = function(id, element){
    var help = this.getHelp(id);
    if (help){
        if (!this.displayDiv){
            this.displayDiv = document.createElement("DIV");
            this.displayDiv.className = InlineHelp.DISPLAY_DIV_CLASS;
        }

        // set the local variable of parentElement to be class level this.helpParentElement
        var parentElement = this.helpParentElement;

        // if this.helpParentElement is not set, get the default value
         if (!parentElement) {
            var parentElement = document.getElementById(BodyLayout.BODY_CELL_ID);
            if (!parentElement){
                parentElement = document.body;
            }
         }

        parentElement.appendChild(this.displayDiv);
        this.displayDiv.style.top = (getObjY(element) + element.offsetHeight + 8 - getObjY(parentElement)) + 'px';
        if (!this.helpFader){
            this.helpFader = new MouseOverFadeHandler(null, this.displayDiv, false);
        }
        this.displayDiv.innerHTML = help;
        this.helpFader.setPosition();

        // calculate the left based on the parement element's left value
        var left = (getObjX(element) - getObjX(parentElement) + element.offsetWidth - this.displayDiv.offsetWidth);
        //Make sure it's not behind the sidebar.
        var sidebar = document.getElementById(SidebarConstants.SIDEBAR_DIV_ID);
        if (sidebar){
            var sidebarRight = getObjX(sidebar) + sidebar.offsetWidth;
            if (left < sidebarRight){
                left = sidebarRight;
            }
        }
        if (left >= 0){
            this.displayDiv.style.left = left + 'px';
        }
        this.helpFader.fadeIn();
    }
}

/**
 * simple messaging for now. should have type, strength, etc and allow sorting, dismissing...
 */
GenericSfdcPage.prototype.registerMessage = function(id) {
    var message = document.getElementById(id);
    if (message && !this.messages[id]) {
        this.messages[id] = message;
    }
}

GenericSfdcPage.prototype.hideMessage = function(id) {
    var message = this.messages[id];
    if (message) {
        message.style.display = "none";
    }
}

GenericSfdcPage.prototype.showMessage = function(id) {
    var message = this.messages[id];
    if (message) {
        message.style.display = "block";
    }
}

// used for search similar utility button. constructs target url
GenericSfdcPage.prototype.findSimilarNavigate = function(tagName1, titleId, descriptionId, custFieldId){
    var tagTypeElements = document.getElementsByTagName(tagName1);
    var custInputs = document.getElementById(custFieldId);
    var descriptionElement = document.getElementById(descriptionId);
    var titleElement = document.getElementById(titleId);
    var qs = new QueryString("");
    var searchCommand ="common.search.similar.IdeaFindSimilarProvider";
    var url = UserContext.getUrl("/_ui/common/search/similar/FindSimilarQueryPage/d");
    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, titleElement.innerHTML," "); // manually add default fields, diff depth than custom fields
    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, descriptionElement.innerHTML," ");

    function appendSearchStringComponents (tagTypeElements, customFieldContainerId){
        for(var i =0; i < tagTypeElements.length; i++){
            var node = tagTypeElements[i];
            var shouldConitnue = false;
            for(var j = 0; j < 6; j++){
                    node = node.parentNode;
                    if(!node){
                        shouldConitnue = true;
                        break;
                    }
                }
            if(shouldConitnue || !node.id){
                    continue;
            }
            var id = node.id;
            if(id == customFieldContainerId){
                    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, tagTypeElements[i].innerHTML, " ");
            }
        }
    }
    if(custInputs!=undefined){
        appendSearchStringComponents(tagTypeElements, custInputs.id);
       }
    qs.add(findSimilarQueryPage.FIND_PROVIDER, searchCommand);
    return url + qs.toString();
}



/**
 * Introducing a brand new flavor of UserContext, this time in javascript! Variables passed down from
 * java MUST be declared here or they will not be set.
 * 
 * @author jmooney
 * @since 148
 */
var UserContext = {
	
    initialized : false,
    locale : "",
    language: "",
    startOfWeek : 0,
    dateFormat : "",
    dateTimeFormat : "",
    ampm: null,
    today : "",
    isAccessibleMode : false,
    userPreferences : null,
    siteUrlPrefix : "",

    initialize : function(values) {
    	if (!values){
    		UserContext.initializeFromServlet();
    		return;
    	}
    	UserContext.processValues(values);
    },
    
    initializeFromServlet : function(){
		var url = UserContext.getUrl("/_ui/system/context/UserContextServlet");
		XBrowser.getHttpResponse(url, function(request) {
		    var values = Util.evalAjaxServletOutput(request.responseText);
    	    UserContext.processValues(values);
		} );
    },
    
    processValues : function (values) {
        for (var key in values) {
            // force strict variable declaration
            if (typeof UserContext[key] != "undefined") {
                if (key == "userPreferences" || key == "orgPreferences") {
                    UserContext[key] = new PreferenceBits(values[key]);
                } else {
                    UserContext[key] = values[key];
                }
            }
        }
        UserContext.initialized = true;
    },

    getUrl : function (url) {
        // fix URL for sites with prefixes
        if (typeof url == "undefined" || typeof UserContext.siteUrlPrefix == "undefined" || !UserContext.siteUrlPrefix) 
            return url;

        if (url.indexOf('/') != 0)
            return url;

        if(url.indexOf(UserContext.siteUrlPrefix) == 0)
            return url;

        return UserContext.siteUrlPrefix + url;
    }
    
};

/**
  A select element with the up & down arrows next to it.

  @author polcari
  @since 144

*/
function VerticallyArrangableSelectElement(_id) {
  this.id = _id;
  var vaSelectElement = this;
  sfdcPage.appendToOnloadQueue(function() {vaSelectElement.init()});
}

VerticallyArrangableSelectElement.prototype.init = function() {
  var containingNode = document.getElementById(this.id).parentNode.parentNode;
   //find the up & down buttons & attach to them
  var imgs = containingNode.getElementsByTagName("img");

  var _id = this.id;
  for (var i=0; (imgs && (i < imgs.length)); i++) {
    if (hasStyleClass(imgs[i], vaSelectElementConst.UP_CLASS)) {
      addEvent(imgs[i], 'click', function() {moveUp(document.getElementById(_id))}, false);
    } else if (hasStyleClass(imgs[i], vaSelectElementConst.DOWN_CLASS)) {
      addEvent(imgs[i], 'click', function() {moveDown(document.getElementById(_id))}, false);
    }
  }
}

/**
 * Functions for handling Email Relay Activation processing.
 * @author ccopek
 * @since 146
 */

function EmailRelay() {}

/**
 * The Activate Restrict Relay To Domains checkbox has to enable/disable the
 * restrict relay to domains input field based on being checked/un-checked.
 * When Activate is checked, the input field must be enabled.  When Activate
 * is un-checked, the input field must be disabled and blanked out.
 */
EmailRelay.prototype.checkActivateRestrictToDomains = function() {
    var restrictRelayToDomainsCheckbox = document.getElementById(EmailRelayConstants.ACTIVATE_RESTRICT_TO_DOMAINS_ID);
    var restrictRelayToDomains = document.getElementById(EmailRelayConstants.RESTRICT_TO_DOMAINS_ID);
    var restrictRelayToDomainsHidden = document.getElementById(EmailRelayConstants.RESTRICT_TO_DOMAINS_HIDDEN_ID);

    if (restrictRelayToDomainsCheckbox.checked) {
        // Activate Restrict Relay To Domains is checked.  Need to enable the Restrict Relay
        // To Domains input field.
        restrictRelayToDomains.disabled = false;
    } else {
        // Activate Restrict Relay To Domains is un-checked.  Need to disable the Restrict Relay
        // To Domains input field and blank out it's value.
        restrictRelayToDomains.value = '';

        // Blank out the hidden field as well.
        restrictRelayToDomainsHidden.value = '';

        restrictRelayToDomains.disabled = true;
    }
}

/**
 * In the case were the Restrict Relay To Domains field is disabled in either of these scenarios:
 *		- Come into the panel disabled and then is enabled via the activate checkbox being checked
 *	    OR
 *		- Is disabled via the activate checkbox being unchecked.
 * In these scenarios, the value contained in the Restrict Relay to Domains is not being sent
 * when the form is submitted.  A hidden variable is being used to transmit the value to
 * the server.  This function will set the value of the hidden variable to the value of the
 * restrict relay to domains input field when it has changed.
 */
EmailRelay.prototype.changeRestrictToDomains = function() {
    var restrictRelayToDomains = document.getElementById(EmailRelayConstants.RESTRICT_TO_DOMAINS_ID);
    var restrictRelayToDomainsHidden = document.getElementById(EmailRelayConstants.RESTRICT_TO_DOMAINS_HIDDEN_ID);

    restrictRelayToDomainsHidden.value = restrictRelayToDomains.value;
}

/**
 * When the Email Relay TLS Setting is changed to Off or from Off, we need to default
 * the Port as follows:
 * 		Change TLS TO Off - Default Port to 25
 *		Change TLS FROM Off - Default Port to 587
 */
EmailRelay.prototype.handleTlsChange = function() {
    var TLS_OFF_VALUE = 0;
    var DEFAULT_EMAIL_HOST_PORT_INDEX = 0;
    var DEFAULT_TLS_PORT_INDEX = 1;

    var emailRelayTlsSetting = document.getElementById(EmailRelayConstants.EMAIL_RELAY_TLS_SETTING_ID);
    var relayPort = document.getElementById(EmailRelayConstants.EMAIL_HOST_PORT_ID);
    var emailRelayTlsSettingVal = emailRelayTlsSetting.options[emailRelayTlsSetting.selectedIndex].value;
    var relayPortSelectedIndex = relayPort.selectedIndex;

    if (emailRelayTlsSettingVal == TLS_OFF_VALUE && relayPortSelectedIndex == DEFAULT_TLS_PORT_INDEX) {
        // TLS has been changed to Off.  Default Port to non TLS default value.
        // We will only Default the value if it's set to the non-TLS default.  We
        // don't want to change the value if the user has set their port to a custom
        // port.
        relayPort.options[DEFAULT_EMAIL_HOST_PORT_INDEX].selected = true;
    }
    else if (emailRelayTlsSettingVal != TLS_OFF_VALUE && relayPortSelectedIndex == DEFAULT_EMAIL_HOST_PORT_INDEX) {
        // TLS has been turned on.  Default Port to TLS default value.
        relayPort.options[DEFAULT_TLS_PORT_INDEX].selected = true;
    }
}

function ApiUtils() {}

ApiUtils.getApiURL = function(isPartner, version) {
    var url = window.location.href;
    var idx = url.indexOf('/', 10); // well after (http|https)://
    var base = url.substring(0, idx) + UserContext.getUrl("/services/Soap/") + (isPartner ? "u" : "c") + "/" + version;
    return base;
}

ApiUtils.getSessionId = function(){
    var sessionId = getCookie(RequestInfo.pSID);
    return sessionId;
}

// fluff up a 15 char id to return an 18 char id
ApiUtils.to18CharId = function (id) {
 if (id == null || (id.length == 18)) return id;
 id = id.replace(/\"/g, ''); // scrub quotes from this id
 if (id.length != 15) {
  return null;
 }
 var suffix = "";
 for (var i = 0; i < 3; i++) {
  var flags = 0;
  for (var j = 0; j < 5; j++) {
   var c = id.charAt(i * 5 + j);
   if (c >= 'A' && c <= 'Z') {
    flags += 1 << j;
   }
  }
  if (flags <= 25) {
   suffix += "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(flags);
  } else {
   suffix += "012345".charAt(flags-26);
  }
 }
 return id + suffix;
}

ApiUtils.to15CharId = function(id){
    if (!id) return null;
    return id.substring(0, 15);
}

// the id field returned by the API is often returned twice,resulting
// in an array when calling record.get(). this returns a single ID always.
ApiUtils.getId = function(record){
    if (!record) return null;
    var id = record.get("Id");
    // looking for array by checking for "splice()" function
    if (id.splice && id.length && id.length > 0) {
        id = id[0];
    }
    if (id){
        id = ApiUtils.to15CharId(id);
    }
    return id;
}

ApiUtils.soqlEncode = function(str){
    var newStr = str;
    newStr = newStr.replace("\\", "\\\\");
    newStr = newStr.replace("'", "\\'");
    return newStr;
}

/*
* @author mpolcari
* @since 142.ml
*/
function DetailPage() {
    this.relatedListPanel = null;
    this.editMode = false;
    this.inlineEditData = null;
    this.detailButtons = [];
    this.editButtons = [];
    this.errorDiv = null;
    this.saving = false;
}

DetailPage.prototype = new GenericSfdcPage();

DetailPage.prototype.registerRelatedListPanel = function (panelId, skipAppendOnLoad) {
  this.relatedListPanel = new RelatedListPanel(panelId);
  var self = this;
  if(!skipAppendOnLoad) {
      this.appendToOnloadQueue(
        function () { //Copy css styleSheets, script includes, & body.className
          var iFrameWindow = self.relatedListPanel.getIFrameNode().contentWindow;
          var iFrameDoc = iFrameWindow.document;
          DomUtil.copyScriptsCssBodyClass(document, iFrameDoc);
          iFrameDoc.body.className += " rlHoverFrame";
          iFrameWindow.sfdcPage = self;
        }, "rlHovers: Importing Scripts and CSS");
  }
}

DetailPage.prototype.getEntityId = function() {
  var href = window.location.href;
  var paths = href.split('?')[0].split('/');
  return paths[paths.length-1];
}

DetailPage.prototype.evalScripts = function (rlElement) {
  var scriptElements = rlElement.getElementsByTagName('script');
  for (var ind = 0; ind<scriptElements.length;ind++){
      var jsExpression = scriptElements[ind].innerHTML;
      eval(jsExpression);
  }
}

DetailPage.prototype.hasNoRelatedList = function(doc, listId) {
    var retVal = getElementByIdCSWithDoc(doc, listId);
    if(!retVal){
        return true;
    }else{
        return false;
    }
}

DetailPage.prototype.desktopAjaxDisplayErrorInline = function() {
    return false;
}

DetailPage.prototype.hook_postRelatedListActionUpdate = function(listUrl) {
    return;
}

DetailPage.prototype.initInlineEdit = function(iled) {
    this.inlineEditData = iled;
    if (iled.isEditable) {
        var self = this;
        this.appendToOnloadQueue(function() { self.inlineEditData.init(); }, "Initialize inline edit");
        this.appendToOnloadQueue(function() { self.initializeButtons(); }, "Setup detail buttons");
    }
}

DetailPage.prototype.getFieldById = function(domId) {
    if (this.inlineEditData) {
        if (domId.search(InlineEditConstants.CELL_ID + "$") != -1) {
            return this.inlineEditData.getField(domId.substring(0, domId.length - InlineEditConstants.CELL_ID.length));
        } else {
            return this.inlineEditData.getField(domId);
        }
    }
}

DetailPage.prototype.initializeButtons = function() {
    var self = this;
    function getButtonsInCell(cellId) {
        var cell = document.getElementById(cellId);
        var buttons = cell.getElementsByTagName("input");
        for (var i = 0; i < buttons.length; i++) {
            var button = buttons[i];
            if (button.type == "button") {
                if (button.name == InlineEditConstants.SAVE_BUTTON || button.name == InlineEditConstants.CANCEL_BUTTON) {
                    self.editButtons.push(button);
                } else {
                    self.detailButtons.push(button);
                }
            }
        }
        var muttons = cell.getElementsByTagName("div");
        for (var i = 0; i < muttons.length; i++) {
            var mutton = muttons[i];
            if (mutton.className == "menuButton") {
                self.detailButtons.push(mutton);
            }
        }
    };
    getButtonsInCell(DetailElement.TOP_BUTTON_ROW);
    getButtonsInCell(DetailElement.BOTTOM_BUTTON_ROW);
}

DetailPage.prototype.focusOnSave = function() {
    this.editButtons[0].focus();
}

DetailPage.prototype.activateInlineEditMode = function() {
    if (!this.errorDiv) {
        this.errorDiv = document.getElementById(DetailElement.DEFAULT_ERROR_DIV_ID);
    }
    this.editMode = true;
    for (var i = 0; i < this.detailButtons.length; i++) {
        this.detailButtons[i].style.display = "none";
    }
    for (var i = 0; i < this.editButtons.length; i++) {
        this.editButtons[i].style.display = "inline";
    }
}

DetailPage.prototype.deactivateInlineEditMode = function() {
    this.editMode = false;
    for (var i = 0; i < this.detailButtons.length; i++) {
        this.detailButtons[i].style.display = "inline";
    }
    for (var i = 0; i < this.editButtons.length; i++) {
        this.editButtons[i].style.display = "none";
    }
    this.clearError();
}

DetailPage.prototype.setError = function(error) {
    if (this.saving) {
        this.saving = false;
        for (var i = 0; i < this.editButtons.length; i++) {
            this.editButtons[i].className = "btn"
            if (this.editButtons[i].name == InlineEditConstants.SAVE_BUTTON) {
                this.editButtons[i].value = LC.getLabel("Buttons", "save");
            } else if (this.editButtons[i].name == InlineEditConstants.CANCEL_BUTTON) {
                this.editButtons[i].value = LC.getLabel("Buttons", "cancel");
            }
        }
    }
    if (error) {
        this.errorDiv.innerHTML = error;
    }
    this.errorDiv.style.display = "block";
}

DetailPage.prototype.clearError = function(error) {
    this.errorDiv.style.display = "none";
}

DetailPage.prototype.refreshDetail = function() {
    //this.deactivateInlineEditMode();
    // TODO: ajax refresh here
    navigateToUrl(window.location);
}

DetailPage.prototype.save = function() {
    if (!this.saving && this.editMode) {
        this.saving = true;
        for (var i = 0; i < this.editButtons.length; i++) {
            this.editButtons[i].className = "btnDisabled";
            this.editButtons[i].value = LC.getLabel("Buttons", "saving");
        }
        this.inlineEditData.save();
    }
}

DetailPage.prototype.revert = function() {
    if (!this.saving && this.editMode) {
        this.inlineEditData.revert();
        this.deactivateInlineEditMode();
    }
}

DetailPage.prototype.dblClickField = function(evt, element) {
    var target = getEventTarget(getEvent(evt));
    if (target.nodeName.toLowerCase() != "a") {
        var field = this.getFieldById(element.id);
        if (field && field.state == InlineEditState.EDIT) {
            if (!this.editMode) {
                this.activateInlineEditMode();
            }
            if (!this.inlineEditData.isCurrentField(field)) {
                this.inlineEditData.openField(field);
            }
            eventCancelBubble(evt);
        }
    }
}

DetailPage.prototype.clickField = function(evt, element) {
    var field = this.getFieldById(element.id);
    if (field && this.inlineEditData.isCurrentField(field)) {
        eventCancelBubble(evt);
    }
}

DetailPage.prototype.mouseOverField = function(evt, element) {
    var field = this.getFieldById(element.id);
    if (field) {
        delStyleClass(element, field.getCSSClass());
        addStyleClass(element, field.getCSSHoverClass());
    }
}

DetailPage.prototype.mouseOutField = function(evt, element) {
    var field = this.getFieldById(element.id);
    if (field) {
        delStyleClass(element, field.getCSSHoverClass());
        addStyleClass(element, field.getCSSClass());
    }
}

DetailPage.prototype.dismissILEBanner = function() {
    UserContext.userPreferences.setBoolean("HideInlineEditSplash", true);
    this.hideMessage("ileBanner");
}



var backgroundIFrameTitle;
function EmailTemplateEditorUi(title, isCustomP, formNameP) {
    registerEmptyCellText(LC.getLabel("EmailTemplate", "emptyCellText"));
    this.editAreaIds = null;
    backgroundIFrameTitle = title; //used by EmailEditorJS
    this.isCustom = isCustomP;
    this.formName = formNameP;
}

EmailTemplateEditorUi.prototype.gatherEditableIds = function () {
    var tempIds = new Object(20);
    var elements = document.getElementsByTagName('td');
    var index = 0;
    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        if (element.id != null && element.id.length > 0) {
            tempIds[index] = element.id;
            index++;
        }
    }
    editAreaIds = new Object(index);
    for (var i = 0; i < index; i++) {
        editAreaIds[i] = tempIds[i]
    }
}

EmailTemplateEditorUi.prototype.getTopTable = function() {
      var topTable = document.getElementById('topTable');
      var allTables = document.getElementsByTagName("table");
      if ((!topTable) && allTables) {
        topTable = allTables[0];
      }
      return topTable;
    }

EmailTemplateEditorUi.prototype.getDefaultPopupWidth = function (){
  var topTable = getTopTable();
  if (topTable) {
    return Math.min(Math.max(topTable.offsetWidth + 60, 500), 1024);
  } else {
    return 500;
  }
}
EmailTemplateEditorUi.prototype.getDefaultPopupHeight = function (){
  var topTable = getTopTable();
  if (topTable) {
    return Math.min(Math.max(topTable.offsetHeight + 200, 500), 768);
  } else {
    return 500;
  }
}
// Init function called by the onload event handler in the <BODY> tag.
EmailTemplateEditorUi.prototype.init = function () {
    if (top != this) {
    	if(this.isCustom) {
	        if (document.body) {
	 	       parent.setFrameWidth(document.body.scrollWidth);
    		   parent.setFrameHeight(document.body.scrollHeight);
	        }
    	}
    	else {
	        this.gatherEditableIds();
	        setEditableIds(editAreaIds);
	        registerLockingConfirmText(LC.getLabel("EmailTemplate", "SetLockedConfirmText"));
	        setLockedImageSrc(UserContext.getUrl("/email/wysiwyg/images/locked.gif"));
	        setUnlockedImageSrc(UserContext.getUrl("/email/wysiwyg/images/unlocked.gif"));
	        // Tells the editor where to load the values from, and where to save them to.
	        registerEditForm(parent.document.forms[this.formName]);
	        initializeEditor();
	        //signal the parent that the edit ctr is finished initializing
	        top.editFinishedLoading=true;
        }
    } else {
        window.resizeTo(this.getDefaultPopupWidth(), this.getDefaultPopupHeight());
    }
}
var SELECT_MENU_SELECT = 1;
var SELECT_MENU_SIDEWAYS = 2;

/**
 * A class that acts more or less exactly like a select box.
 *
 * @param sourceID The DOM id of a UL that will form the elements of the select
 * @param targetID A div target in which to build the SelectMenu
 * @param displayWord A string to display as the initial entry of the menu.
 * @param hasDefaultAction Splits the button in two parts if true: the button area, which when clicked
 *		  loads the first link in the list, and the arrow area, which displays or hides the menu.
 * @author emoses
 * @deprecated don't use this, use MenuButton instead
 */
function SelectMenu(sourceId, targetId, displayWord, selectMenuOuterClass, selectMenuClass, style, groupClass, needScrollbars, hasDefaultAction, isRightAligned){
    this.sourceList = document.getElementById(sourceId)
    this.select = null;
    this.menuDiv = null;
    this.displayWord = displayWord;
    this.targetDiv = document.getElementById(targetId)
    this.divClass = selectMenuOuterClass;
    this.menuClass = selectMenuClass;
    this.menuOpen = false;
    this.hasSetPosition = false;
    this.scrollbars = needScrollbars;
    this.hasDefaultAction = hasDefaultAction;
    this.isCreateNew = false;
    this.isRightAligned = isRightAligned;

    if (style){
        this.style = style;
    } else {
        this.style = SELECT_MENU_SELECT;
    }

    var self = this;

    this.documentHideMenu = function(e){
        var elem = getEventTarget(e);
        if(elem.className == groupClass) { return;}
        if (self.menuOpen){
            self.hideMenu();
        }
    }

    this.handleDocumentKeyDown = function(e){
        var evt = getEvent(e);

        if (self.menuOpen && evt.keyCode == KEY_ESC){
            //ESC key, when not pinned and all the way out
            self.hideMenu();
        }
    };

    this.handleDivClick = function(e) {
        var elem = getEventTarget(e);
        if(elem.className == groupClass) { return;}

        if (self.hasDefaultAction) {
            var nOffsetX=(e.layerX)?(e.layerX):e.offsetX;
            if(nOffsetX<(elem.offsetWidth-17)) {
                window.location = self.sourceList.childNodes[0].href;
                eventCancelBubble(e);
                return;
            }
        }
        if (self.menuOpen){
            self.hideMenu();

        } else {
            self.showMenu();
            self.setPosition();
        }
        eventCancelBubble(e);
    }

    if (!this.sourceList) return;
    if (!this.targetDiv) return;
    this.init();
}

SelectMenu.prototype.showMenu = function(){
    if (!this.isCreateNew) {
        this.targetDiv.style.position = "relative";
    }
    this.menuDiv.setStyle("display", "block");
    this.menuOpen = true;
};

SelectMenu.prototype.hideMenu = function(){
    if (!this.isCreateNew) {
        this.targetDiv.style.position = "static";
    }    
        this.menuDiv.setStyle("display", "none");
        this.menuOpen = false;
};

SelectMenu.prototype._setPositionSelect = function(){
    if (!this.hasSetPosition) {
        this.hasSetPosition = true;

        if (!this.isCreateNew) {
            this.menuDiv.setStyle("top", this.select.offsetHeight + "px");
            if(!this.isRightAligned){
                this.menuDiv.setStyle("left", "0px");
            }else{
                this.menuDiv.setStyle("right","3px");
            }
        }

        // Begin IE fix
        // Can't do this in CSS because the whitespace at the end of
        // the link elements don't function as a link.
        // So, grab the maximum text length of the link elements, make that
        // the width of the container div, and then set all link elements
        // to width 100%.

        var maxWidth = this.sourceList.childNodes[0].scrollWidth;
        var maxOptionWidth = maxWidth;
        for (var i = 1; i < this.sourceList.childNodes.length; i++) {
            if (this.sourceList.childNodes[i].scrollWidth > maxWidth)
                maxWidth = this.sourceList.childNodes[i].scrollWidth;
        }
        // this should not be set for menu with scrollbars
        for (var i = 0; i < this.sourceList.childNodes.length; i++) {
            this.sourceList.childNodes[i].style.width = "100%";
            if(this.sourceList.childNodes[i].offsetWidth > maxOptionWidth){
                maxOptionWidth = this.sourceList.childNodes[i].offsetWidth;
            }
        }
        this.menuDiv.setStyle("width", maxWidth + "px");
        // End IE Fix.

        // if the menu should have scrollbars then proceed with height calculations below
        if(this.scrollbars){
            // show a maximum of 20 items
            var maxHeight = this.sourceList.childNodes[0].offsetHeight*20;
            var actualHeight = this.sourceList.offsetHeight;
            if (actualHeight < maxHeight){
                maxHeight = actualHeight;
            }
            this.menuDiv.setStyle("height", maxHeight + "px");
            this.menuDiv.setStyle("overflowY", "auto");


        }
        if (this.menuDiv.div.offsetWidth < this.select.childNodes[0].offsetWidth){
            this.menuDiv.setStyle("width", this.select.childNodes[0].offsetWidth + "px");
            // firefox fix to ensure that horizontal scrollbar doesn't show up on click
            if(this.scrollbars){
                this.menuDiv.setStyle("width", (maxOptionWidth + 34) + "px");
                this.menuDiv.setStyle("backgroundColor", "#CCC");
                this.menuDiv.div.childNodes[0].style.width = this.menuDiv.div.offsetWidth - 34 + "px";
            }
        }
    }
};

SelectMenu.prototype._setPositionSideways = function() {
    this.menuDiv.setStyle("top", this.select.offsetHeight / 2 + "px");
    this.menuDiv.setStyle("left", this.select.offsetWidth + "px");
}

SelectMenu.prototype.init = function(){

    this.select = document.createElement("div");
    this.select.className = this.divClass;

    this.targetDiv.insertBefore(this.select, this.targetDiv.firstChild);

    var upperDiv = document.createElement("div");
    if (this.hasDefaultAction) {
        upperDiv.className = "selectMenuButton hasDefault";
    } else {
        upperDiv.className = "selectMenuButton";
    }
    this.select.appendChild(upperDiv);
    upperDiv.appendChild(document.createTextNode(this.displayWord));

    this.menuDiv = document.createElement("div");
    this.menuDiv.className = this.menuClass;
    this.select.appendChild(this.menuDiv);

    this.menuDiv.appendChild(this.sourceList);
    switch(this.style){
    case SELECT_MENU_SIDEWAYS:
        this.setPosition = this._setPositionSideways;
//      document.body.appendChild(this.menuDiv);
        break;
    case SELECT_MENU_SELECT:
    default:
        this.setPosition = this._setPositionSelect;
    }

    this.menuDiv = new iframeShim(this.menuDiv);
    this.menuDiv.setStyle("display", "none");
    this.menuDiv.setStyle("position", "absolute");

    addEvent(document, 'click', this.documentHideMenu, false);
    addEvent(document, 'keydown', this.handleDocumentKeyDown, true);
    addEvent(this.targetDiv, 'click', this.handleDivClick, false);
};

    /** @author zzhou
     *  @since 150
     * Used to determine whether we take a user directly to another forecast on inputting a value in the forecast user lookup
     * input box and pressing enter */

function FctSummaryPage() {}

FctSummaryPage.onForecastLookupBoxInput = function(element,oEvent) {
	if ((oEvent.keyCode && oEvent.keyCode==13) || (oEvent.which && oEvent.which==13)) {
		document.getElementById(ForecastSummaryPage.pLOOKUP_INPUT_ENTERED).value = 1;
		element.form.submit();
	}
}

function SearchQueryTool(targetEntityInputId) {
	this.queryTypeWithEntityStorage = new Object();
	this.targetEntityInputId = targetEntityInputId;
	this.entityInput = null;
	this.savedValue = null;
}

SearchQueryTool.prototype.addQueryTypeWithEntity = function (queryType){
	this.queryTypeWithEntityStorage[queryType] = queryType;
}

SearchQueryTool.prototype.processTargetEntity = function (queryType){
	if(!this.entityInput && !this.targetEntityInputId){ return; }
	
	// initialize lazily
	if (!this.entityInput){ 
		this.entityInput = document.getElementById(this.targetEntityInputId);
		this.targetEntityInputId = null;
	}
	
	if (queryType in this.queryTypeWithEntityStorage){
		this.entityInput.disabled = true;
		this.savedValue = this.entityInput.value;
		this.entityInput.value = '';
	} else {
		this.entityInput.disabled = false;
		if(this.savedValue){
			this.entityInput.value = this.savedValue;
		}
	}
}
/**
 * This class handles auto complete functionality on the tag header element.
 * It grabs _all_ the tags for the current user from LookupTagsPage and caches this list.
 * Given the current count limit on private tags (500) this is not a problem, but in the
 * future we might want to be more selective about what we grab.
 *
 * @author mpaksoy
 * @since 150
 * based on AutoComplete.js by rchoi
 */

/**
 * @param elem text area element used for auto complete
 * NOTE: this element needs a DOM id
 * @param callback keypress event handler callback. Auto complete needs priviledged access to
 * the keypress event to grab the tab/enter keys, it will pass the event on as necessary.
 */
function TagAutoComplete(elem, tagMode, callback) {
    this.element = elem;
    this.id = this.element.id;
    this.tagMode = tagMode;

    this.recordHeight = 18;

    this.selection = false;
    this.keyPressCallback = callback;

    // EVENT HANDLERS
    var self = this;
    addEvent(this.element, 'keyup', function(e) { self.onKeyUp(e); });
    addEvent(this.element, 'keydown', function(e) { self.captureKeyPress(e); });
    addEvent(this.element, 'keypress', function(e) { self.captureKeyPress(e, true); });
    addEvent(this.element, 'blur', function(e) { self.onBlur(e); });
    addEvent(window, 'resize', function(e) { self.resizeLocationUpdater(e); });

    window[this.id + TagAutoComplete.MOUSE_OVER_HANDLER] = function(i) { self.updateSelection(i); };
}

// STATIC CONSTANTS
TagAutoComplete.MOUSE_OVER_HANDLER = '_autoCompleteMouseOverHandler';
TagAutoComplete.BOX_ID = '_autoCompleteBoxId';
TagAutoComplete.FRAME_ID = '_autoCompleteFrameId';
TagAutoComplete.ROW_ID = '_autoCompleteRowId';
TagAutoComplete.BOX_CSS_CLASS = 'autoCompleteBox';
TagAutoComplete.ROW_CSS_CLASS = 'autoCompleteRow';
TagAutoComplete.SELECTED_ROW_CSS_CLASS = 'autoCompleteSelectedRow';
TagAutoComplete.MORE_ROW_CSS_CLASS = 'autoCompleteMoreRow';
TagAutoComplete.MIN_LENGTH_THRESHOLD = 1;
TagAutoComplete.MAX_SUGGESTIONS = 15;
TagAutoComplete.EMPTY = /^\s*$/;

// INSTANCE METHODS

/**
 * Set the function to call when text is entered to see if text area needs to
 * be resized.
 */
TagAutoComplete.prototype.setResizer = function(callback) {
    this.resizeCallback = callback;
}

/**
 * Call the resize handler and move auto complete box if necessary.
 */
TagAutoComplete.prototype.resizeTextArea = function() {
    if (this.resizeCallback && this.resizeCallback()) { // if resized
        this.updateBoxLocation();
    }
}

/**
 * Display the auto-complete box containing the given set of suggestions.
 * @param records array of suggestions
 */
TagAutoComplete.prototype.displayResults = function(records) {
    if (!records || !(records instanceof Array)) return;
    if (records.length == 0) {
        if (this.box) {
            this.doClear();
        }
        return;
    }

    var html = [];
    html.push("<table width='100%' cellpadding='0' cellspacing='0' border='0'>");
    for (var i = 0; i < records.length; i++){
        if (i >= TagAutoComplete.MAX_SUGGESTIONS) {
            html.push("<tr><td>");
            html.push("<div ");
            html.push("class='" + TagAutoComplete.MORE_ROW_CSS_CLASS+"'");
            html.push(">");
            html.push(LC.getLabel('TagHeader','auto_complete_more'));
            html.push("</div>");
            html.push("</td></tr>");
            break;
        }

        var record = records[i];
        html.push("<tr><td>");
        html.push("<div ");
        html.push("onmouseover='");
        html.push("window."+this.id+TagAutoComplete.MOUSE_OVER_HANDLER+"("+i+");'");
        html.push("class='"+TagAutoComplete.ROW_CSS_CLASS+"' ");
        html.push("id='"+this.getRowId(i)+"'>");
        html.push("<span>");
        html.push(record);
        html.push("</span>");
        html.push("</div>");
        html.push("</td></tr>");
    }
    html.push("</table>");

    var recordsShown = (records.length > TagAutoComplete.MAX_SUGGESTIONS) ?
                        TagAutoComplete.MAX_SUGGESTIONS + 1: records.length;
    if (!this.box){ // need to create auto complete box
        // IE6 returns the wrong element position if we call getObjX() right after calling makeBox() so we save coordinates from before.
        var y = getObjY(this.element) + this.element.offsetHeight;
        var x = getObjX(this.element);
        this.makeBox();
        this.moveBox(y, x);
    }
    this.box.div.innerHTML = html.join('');
    this.showBox(true);
    this.updateSelection(0); // pick the first one by default
}

TagAutoComplete.prototype.resizeLocationUpdater = function() {
    if (this.box) // box already created
        this.updateBoxLocation();
}

TagAutoComplete.prototype.updateBoxLocation = function() {
    this.moveBox(getObjY(this.element) + this.element.offsetHeight, getObjX(this.element));
}

/**
 * Connects to the servlet to grab the list tags for the current user.
 * This list is only grabbed once, and cached.
 */
TagAutoComplete.prototype.doLookup = function() {
    if (this.IS_PROCESSING) return;
    if (this.cache || this.doneCaching) return;

    var qs = new QueryString("");
    qs.add(TagConstants.pTAG_SCOPE_MODE, this.tagMode);
    var servlet = UserContext.getUrl(TagConstants.LOOKUP_TAGS_PAGE) + qs.toString();
    this.IS_PROCESSING = true;
    var self = this;

    var requestHandler = function(request) {
        var resp = request.responseText;
        if (resp) {
            self.cache = resp.split(', ');
            self.filterDisplayResults();
        }
        self.doneCaching = true;
        self.IS_PROCESSING = false;
    }

    XBrowser.getHttpResponse(servlet, requestHandler);
}

/**
 * Hide the suggestion box and deselection suggestion.
 */
TagAutoComplete.prototype.doClear = function(){
    this.selection = false;
    this.results = false;
    this.lastSearched = false;
    this.showBox(false);
}

/**
 * Update the selected suggestion. Updates highlighing on suggestion rows accordingly.
 */
TagAutoComplete.prototype.updateSelection = function(index) {
    if (this.getRow(this.selection)) { // if something previously selected, unselect
        this.getRow(this.selection).className = TagAutoComplete.ROW_CSS_CLASS;
    }
    var row = this.getRow(index);
    if (!row) return;
    this.selection = index;
    row.className = TagAutoComplete.SELECTED_ROW_CSS_CLASS;
}

/**
 * Return the last word in the comma seperated list of tags from the text area.
 * Trims the whitespace around this element.
 */
TagAutoComplete.prototype.getCurrentWord = function() {
    if (!this.element || !this.element.value) return;
    var tags = this.element.value.split(",");
    return tags[tags.length-1].replace(/^\s+|\s+$/g,""); // trim spaces before/after word
}

/**
 * Search the cache for tags starting with the current word (see getCurrentWord)
 * If the new search string matches beginning of the last search string, it will
 * do an incremental search on the results of the last search
 * If not, it will do a brute force search.
 *
 * With 500 tags, this is not a very big issue, but might become an issue in the future.
 * Might want to use a data structure like a trie to  easily narrow down results and
 * backtrack as necessary.
 */
TagAutoComplete.prototype.filterDisplayResults = function() {
    if (!this.cache) {
        this.results = false;
        return; // need stuff in the cache
    }
    var val = this.getCurrentWord();
    if (this.results && this.lastSearched && TagAutoComplete.isMatch(this.lastSearched, val)) {
        var newresults = [];
        for (var i = 0; i < this.results.length; i++) {
            var string = this.results[i];
            if (TagAutoComplete.isMatch(val, string)) {
                newresults.push(this.results[i]);
            }
        }
        this.results = newresults;
    } else {
        this.results = [];
        for (var i = 0; i < this.cache.length; i++) {
            var string = this.cache[i];
            if (TagAutoComplete.isMatch(val, string)) {
                this.results.push(string);
            }
        }
        this.results.sort(function(a,b) { // case insensitive compare
                var aNorm = a.toLowerCase();
                var bNorm = b.toLowerCase();
                if (aNorm == bNorm) return 0;
                return (aNorm > bNorm) ? 1 : -1;
            });
    }

    this.lastSearched = val;
    this.displayResults(this.results);
}

/**
 * Get the id of the suggestion row with index
 */
TagAutoComplete.prototype.getRowId = function(index) {
    return this.id + TagAutoComplete.ROW_ID + index;
}

/**
 * Get the DOM node for the suggestion row
 */
TagAutoComplete.prototype.getRow = function(index) {
    return document.getElementById(this.getRowId(index));
}

// EVENTS (called from within the context of this class)

/**
 * Called by the (yes, you guessed it) key up listener.
 * Calls the enter/tab/esc keys accordingly, or updates the suggestions for the
 * new string.
 */
TagAutoComplete.prototype.onKeyUp = function(event){
    if (!event || !event.keyCode) return;

    this.captureKeyPress(event);

    var inIME = this.inKeyIME;
    this.inKeyIME = false;

    var val = this.element.value;
    if (this.IS_PROCESSING) {
        return;
    } else if (!inIME && TagAutoComplete.isComplete(event)) {
        this.complete();
        return;
    } else if (TagAutoComplete.isNavigation(event)) {
        this.handleNav(event);
        return;
    } else if (TagAutoComplete.isEscape(event) || !this.checkCursorAtEnd()) {
        this.doClear();
        return;
    } else if (TagAutoComplete.isIgnore(event)) {
        return;
    } else if (inIME && event.keyCode != KEY_ENTER) {
        return;
    }

    if (!this.cache) {
        this.doLookup();
    }

    this.resizeTextArea();

    if (val != null && val.length >= TagAutoComplete.MIN_LENGTH_THRESHOLD){
        this.filterDisplayResults();
    } else if (val == null || val.length < TagAutoComplete.prototype.MIN_LENGTH_THRESHOLD || TagAutoComplete.EMPTY.exec(val)){
        this.doClear();
    }
}

/**
 * Auto-complete with the current suggestion: replace the partially entered
 * suggestion with the text of the chosen suggestion and close suggestion box.
 */
TagAutoComplete.prototype.complete = function() {
    if (this.selection === null || this.selection === false) return;
    if (this.selection < 0 || this.selection >= this.results.length) return;

    var suggestion = this.results[this.selection];
    this.completeText(suggestion);
    this.doClear();
    this.element.focus();

    if (XBrowser.userAgent.isSafari) {
        this.element.selectionStart = this.element.value.length;
        this.element.selectionEnd = this.element.value.length;
    }
}

/**
 * Handles the string substitution for completing the partially typed
 * tag with the chosen suggestion.
 */
TagAutoComplete.prototype.completeText = function(text) {
    var values = this.element.value.split(',');
    if (values.length <= 1) {
        values = [text];
    } else {
        values[values.length-1] = ' '+text;
    }
    this.element.value = values.join(',')+', ';
    this.resizeTextArea();
}

/**
 * Called when focus moves away from our text area. Closes the suggestion box.
 * There's a delay associated with this to allow clicks to be processed on the
 * suggestion box, otherwised it's closed before the event can be caught.
 */
TagAutoComplete.prototype.onBlur = function() {
    var self = this;
    var handler = function() { self.doClear(); }
    setTimeout(handler, 200);
}

/**
 * Handle the up and down navigation keys. Wraps around the suggestion box (going up at the top
 * will go back to the bottom).
 */
TagAutoComplete.prototype.handleNav = function(event) {
    if (!event || !event.keyCode) return;
    if (!this.results || (this.results.length == 0)) return;

    var lastIndex = (this.results.length > TagAutoComplete.MAX_SUGGESTIONS) ?
                        TagAutoComplete.MAX_SUGGESTIONS - 1: this.results.length - 1;

    var keyCode = event.keyCode;
    var newSelect = this.selection;
    if (keyCode == KEY_ARROW_U) {
        if (newSelect === false) { // nothing selected yet
            newSelect = lastIndex;
        } else {
            newSelect--;
        }
    } else if (keyCode == KEY_ARROW_D) {
        if (newSelect === false) {
            newSelect = 0;
        } else {
            newSelect++;
        }
    }

    if (newSelect > lastIndex) {
        newSelect = 0;
    } else if (newSelect < 0) {
        newSelect = lastIndex;
    }

    this.updateSelection(newSelect);
}

// BOXES
TagAutoComplete.prototype.makeBox = function() {
    // div for the contents
    this.box = document.createElement("div");
    this.box.id = this.id+TagAutoComplete.BOX_ID;
    this.box.className = TagAutoComplete.BOX_CSS_CLASS;
    document.body.appendChild(this.box);
    // add event handler
    var self = this;
    addEvent(this.box, 'click', function() { self.complete(); });
    this.box = new iframeShim(this.box);
    return this.box;
}

TagAutoComplete.prototype.moveBox = function(top, left){
    if (this.box){
        this.box.setStyle('top', top + "px");
        this.box.setStyle('left', left + "px");
    }
}

TagAutoComplete.prototype.showBox = function(isVisible){
    var disp = isVisible ? "block" : "none";

    if (this.box){
        this.box.setStyle('display', disp);
    }
}

/**
 * Prevent the navigation and tab/enter keys from being handled
 * @param event event object for the key/up/down/press
 * @param boolean set to true, if you want to execute keyPressCallback as necessary
 */
TagAutoComplete.prototype.captureKeyPress = function(event, isKeyPress) {
    if (!event || (!event.charCode && !event.keyCode)) {
        return;
    }
    var code = event.charCode ? event.charCode : event.keyCode;
    // If we get a KEY_PROCESS in a keydown, then the user is using
    // IME to input characters like Japanese Hiragana, and therefore
    // we'll need to ignore the ending enter as it's part of character entry
    // http://bugforce.soma.salesforce.com/bug/bugDetail.jsp?id=100000000000qY0
    if (!isKeyPress && code == KEY_PROCESS) {
        this.inKeyIME = true;
    }
    if (this.selection === false) {
        if (isKeyPress && this.keyPressCallback) this.keyPressCallback(event);
        return;
    }

    if (code == KEY_ENTER || code == KEY_TAB || code == KEY_ARROW_U || code == KEY_ARROW_D || code == KEY_ESC) {
        TagAutoComplete.stopBubble(event);
    }
}

/**
 * Return true if there is no text after cursor in input element (excluding spaces).
 * If 1 or more characters are selected, returns false.
 * Note: Behavior is undefined if the element does not have focus, so make sure it does.
 */
TagAutoComplete.prototype.checkCursorAtEnd = function() {
    if (!this.element) return false;
    var afterCaret;
    if (XBrowser.userAgent.isIE) {
        var selRange = document.selection.createRange().duplicate();
        if (selRange.text && (selRange.text.length > 0)) return false; // text selected
        var textRange = selRange.duplicate();
        textRange.moveToElementText(this.element);
        try { // setEndPoint is known throw exceptions on bad days
            selRange.setEndPoint("EndToEnd", textRange);
            afterCaret = selRange.text;
        } catch (e) {
            return true;
        }
    } else { // life's so much better with Firefox
        if (this.element.selectionStart != this.element.selectionEnd) return false; // text selected
        afterCaret = this.element.value.substring(this.element.selectionStart);
    }
    return TagAutoComplete.EMPTY.exec(afterCaret);
}

// STATIC METHODS
TagAutoComplete.isNavigation = function(event){
    var code = event.keyCode;
    return (code == KEY_ARROW_U || code == KEY_ARROW_D);
}

// 9 is TAB; 16 is SHIFT-TAB
TagAutoComplete.isIgnore = function(event){
    var code = event.keyCode;
    return (code == 16 || (code >= 33 && code <= 46) || (code >= 112 && code <= 123));
}

TagAutoComplete.isEscape = function(event){
    var code = event.keyCode;
    return code == KEY_ESC;
}

/**
 * Tab/enter keys execute auto complete.
 * Checks if the current keystroke is tab or enter.
 */
TagAutoComplete.isComplete = function(event){
    var code = event.keyCode;
    return (code == KEY_ENTER || code == KEY_TAB);
}

/**
 * Return the normalized version of the given tag.
 */
TagAutoComplete.normalize = function(tag) {
    return tag.replace(/\s|-|_/g,"").toLowerCase()
}

/**
 * Return true if substring matches the beginning of string. Case insensitive.
 * Ex. if substring='abc' and string='AbCdef' then this will return true.
 */
TagAutoComplete.isMatch = function(substring, string) {
    if (!substring || !string) return false;
    substring = TagAutoComplete.normalize(substring);
    string = TagAutoComplete.normalize(string);
    if (substring.length > string.length) return false;
    return (string.indexOf(substring) === 0);
}

/**
 * Stops bubbling on the event and prevents default browser behavior at the same time.
 */
TagAutoComplete.stopBubble = function(event) {
    if (XBrowser.userAgent.isIE) {
        event.returnValue = false;
        event.cancelBubble = false;
    } else {
        event.preventDefault();
        event.stopPropagation();
    }
}

/*
 * History Storage for ajax based states
 */
/** 
   Material Copyrighted  2005, Brad Neuberg, bkn3@columbia.edu  
   Modified by salesforce.com 2007
   --------------------------------STARTS HERE-----------------------------------------

   Copyright (c) 2005, Brad Neuberg, bkn3@columbia.edu
   http://codinginparadise.org
   
   Permission is hereby granted, free of charge, to any person obtaining 
   a copy of this software and associated documentation files (the "Software"), 
   to deal in the Software without restriction, including without limitation 
   the rights to use, copy, modify, merge, publish, distribute, sublicense, 
   and/or sell copies of the Software, and to permit persons to whom the 
   Software is furnished to do so, subject to the following conditions:
   
   The above copyright notice and this permission notice shall be 
   included in all copies or substantial portions of the Software.
*/ 
DhtmlHistory.POLLING_FREQUENCY = 300;
DhtmlHistory.WAIT_FREQUENCY = 500;
 function DhtmlHistory(storageMap, listenerFunction, parentObject) {
   this.locationOfBlankPage = UserContext.getUrl("/back_blank.html?");
	/** Our current hash location, without the "#" symbol. */
   this.currentLocation = null;
   this.listener = listenerFunction;
   /** A hidden IFrame we use in Internet Explorer to detect history
       changes. */
   this.iframe = null;
   /** Indicates to the browser whether to ignore location changes. */
   this.ignoreLocationChange = false;
   /** The amount of time in milliseconds an add request has to wait in line before being
       run on a window.setTimeout. */
   this.currentWaitTime = 0;
   this.historyStorage = storageMap;
   // initialization
   this.parentObject = parentObject;
   this.create();
}

DhtmlHistory.prototype.add = function(newLocation, historyData) {	
	// most browsers require that we wait a certain amount of time before changing the
	// location, such as 200 milliseconds; thus we internally handle this
	// detail by using a 'currentWaitTime' variable and have requests wait in line
	var self = this;
	var addImpl = function() {
	   // indicate that the current wait time is now less
	   if (self.currentWaitTime > 0) {
	      self.currentWaitTime = self.currentWaitTime - DhtmlHistory.WAIT_FREQUENCY;
	   }
	   // remove any leading hash symbols on newLocation
	   newLocation = self.removeHash(newLocation);
	   var idCheck = document.getElementById(newLocation);
	   if (idCheck) {
	      Gack.sendGack("History locations can not have the same value as any id's that might be in the document");
	      return; 
	   }
	   self.historyStorage[newLocation] = historyData;
	   // indicate to the browser to ignore this upcomming 
	   // location change
	   self.ignoreLocationChange = true;
	   // save this as our current location
	   self.currentLocation = newLocation;
	   // change the browser location
	   window.location.hash = newLocation;
	   // change the hidden iframe's location if on IE
	   if (XBrowser.userAgent.isIE){
	   		// write out a hidden iframe for IE and
	   		if(!self.iframe) {
		      	var b = document.getElementsByTagName('body')[0];
		      	if(!b){ return; }
		        var divElem = document.createElement('div');
		       	b.appendChild(divElem);
		       	divElem.style.display = 'none';
		        divElem.innerHTML = "<iframe class='dhtmlHistoryFrame' name='DhtmlHistoryFrame' id='DhtmlHistoryFrame' "
		                               + "src='"+ self.locationOfBlankPage + newLocation + "'></iframe>";
		         self.iframe = document.getElementById("DhtmlHistoryFrame");
	   	  } else {	
	      	self.iframe.src = self.locationOfBlankPage + newLocation;
	   	  }
	   }
	};
	// now execute this add request after waiting a certain amount of time, so as to
	// queue up requests
	 window.setTimeout(addImpl, this.currentWaitTime);
	 // indicate that the next request will have to wait for awhile
	 this.currentWaitTime = this.currentWaitTime + DhtmlHistory.WAIT_FREQUENCY;
}

/** Gets the current hash value that is in the browser's
       location bar, removing leading # symbols if they are present. */
DhtmlHistory.prototype.getCurrentLocation = function() {
	return this.removeHash(window.location.hash);
}
   
DhtmlHistory.prototype.create = function() {

      var initialHash = this.getCurrentLocation();
      this.currentLocation = initialHash;
      this.ignoreLocationChange = true;
      if(!XBrowser.userAgent.isIE){
      	var self = this;
      	var locationHandler = function() {
       	 	self.checkLocation();
      	};
      	setInterval(locationHandler, DhtmlHistory.POLLING_FREQUENCY);
      }
}
   
DhtmlHistory.prototype.fireHistoryEvent = function(oldHash, newHash) {
    this.listener.call(this.parentObject, oldHash, newHash);
}

DhtmlHistory.prototype.shouldProceedWithHistoryEvent = function () {
	if (this.ignoreLocationChange) {
       this.ignoreLocationChange = false;
       return false;
    } else {
    	return true;
    }
}

DhtmlHistory.prototype.checkLocation = function() {
   	if (XBrowser.userAgent.isIE || !this.shouldProceedWithHistoryEvent()){ return; }
    var hash = this.getCurrentLocation();
    if (hash == this.currentLocation) { return; }
    // save this new location
    var oldHash = this.currentLocation;
    this.currentLocation = hash;
    this.fireHistoryEvent(oldHash, hash);
}  
   
DhtmlHistory.prototype.removeHash = function(hashValue) {
    if (!hashValue){return null;}
    else if (hashValue == "" ||  (hashValue.length == 1 && hashValue.charAt(0) == "#")) { return ""; } 
    else if (hashValue.length > 1 && hashValue.charAt(0) == "#") { return hashValue.substring(1);} 
    else { return hashValue; }     
}          
   
DhtmlHistory.prototype.iframeLoaded = function(newLocation) {
    if (!XBrowser.userAgent.isIE || !this.shouldProceedWithHistoryEvent()){ return; }
    // get the new location
    var hash = new String(newLocation.search);
    if (!hash || (hash.length == 1 && hash.charAt(0) == "?")) {
       hash = "";
    } else if (hash.length >= 2 && hash.charAt(0) == "?") {
       hash = hash.substring(1);
    }
    
   	var oldHash = this.removeHash(window.location.hash);
    window.location.hash = hash;
    this.fireHistoryEvent(oldHash, hash);
}
/**
 * Material Copyrighted  2005, Brad Neuberg, bkn3@columbia.edu 
 * Modified by salesforce.com 2007
 * 
 * --------------------------------ENDS HERE-----------------------------------------
 */

/*
    This controls the greying out of certain checkboxes on the user edit page according to
    the license type that's picked by the user.

    @param picklistID. 	String.  The ID of the picklist that controls the user's license types.
    @param dataMap.		Map.     The control data.  It should be a map from picklist values to
                                 an array of the dom ids of checkboxes that should be disabled if that
                                 picklist values is checked.  For instance, if the 'mktUser'
                                 and 'offline' should be disabled when the option in picklistID with the
                                 value '0' is selected, the checkbox 'other' should be disabled when
                                 '1' is selected, and nothing should be greyed when '2' is selected,
                                 then the map should look like this:

                                {
                                  '0' : ['mktUser', 'offline'],
                                  '1' : ['other'],
                                  '2' : []
                                }
    @author emoses
    @since 144
*/
function UserEdit(picklistId, dataMap){
    var self = this;

    self.picklist = document.getElementById(picklistId);
    self.controlMap = dataMap;

    if (!(self.picklist && self.controlMap)) return;
    self.allCheckboxes = null;

    function initAllChecks(){
        self.allCheckboxes = {};
        for (var val in self.controlMap){
            for (var i = 0; i < self.controlMap[val].length; i++){
                var controlId = self.controlMap[val][i];
                var control = (document.getElementById(controlId));
                if (control){
                    self.allCheckboxes[controlId] = true;
                }
            }
        }
    }

    this.handleSelectChange = function(e){
        var curr = self.picklist.options[self.picklist.selectedIndex];
        if (curr.value && curr.value.length > 0){
            self.setChecksTo(curr.value);
        } else {
            self.resetChecks();
        }
    }

    initAllChecks();
    addEvent(self.picklist, "change", this.handleSelectChange, false);
    self.handleSelectChange(null);
}

UserEdit.prototype.resetChecks = function(){
    for (var id in this.allCheckboxes){
        document.getElementById(id).disabled = false;
    }
}

UserEdit.prototype.setChecksTo = function(setTo){
    this.resetChecks();
    if (!(setTo in this.controlMap)) return;
    var idsToDisable = this.controlMap[setTo];
    for (var i = 0; i < idsToDisable.length; i++){
        var control = document.getElementById(idsToDisable[i]);
        if (control) {
            control.disabled = true;
            if (control.checked){
                control.checked = false;
            }
        }
    }
}
function SchedulePageUtil() {}

SchedulePageUtil.clickExpand = function() {
	Animation.rollIn(document.getElementById(SchedulePage.pDuelOuter), function() {});
}

SchedulePageUtil.clickCollapse = function() {
	Animation.rollOut(document.getElementById(SchedulePage.pDuelOuter), function() {});
}

SchedulePageUtil.disableTime = function(suffix) {
	document.getElementById(ScheduleElement.pPrefTime + suffix).value = '';
	document.getElementById(ScheduleElement.pPrefTime + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pPrefTime + suffix).disabled = true;

	document.getElementById(ScheduleElement.pOtherPrefTimeLabelDiv + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'block';
}

SchedulePageUtil.enableTime = function(suffix) {
	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pOtherPrefTimeLabelDiv + suffix).style.display = 'none';

	//start loading
	document.getElementById(ScheduleElement.pPrefTimeLoadingDiv + suffix).style.display = 'block';

	var saveData = SchedulePageUtil.buildPost(suffix);
	XBrowser.postHttpResponse(UserContext.getUrl(BlowoutServlet.SERVLETURL),
                                  function(response) { SchedulePageUtil.handleResponse(suffix, response.responseText); },
                                  XBrowser.buildPost(saveData),
                                  // check the errorMsg??
                                  null
                                  );
	return false;
}

SchedulePageUtil.buildPost = function(suffix) {
	var saveData = {};
	saveData[BlowoutServlet.SUFFIX] = suffix;

	saveData[SchedulePage.pBlowout] = document.getElementById(SchedulePage.pBlowout).value;
	saveData[SchedulePage.pIsOffPeak] = document.getElementById(SchedulePage.pIsOffPeak).value;
	saveData[ScheduleElement.pFreq + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pFreq + suffix);
	saveData[ScheduleElement.pStartDate + suffix] = document.getElementById(ScheduleElement.pStartDate + suffix).value;
	saveData[ScheduleElement.pEndDate + suffix] = document.getElementById(ScheduleElement.pEndDate + suffix).value;
	saveData[ScheduleElement.pDailyRec + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pDailyRec + suffix);
	//saveData[ScheduleElement.pDailyEveryNDays + suffix] = document.forms['editPage'].elements[ScheduleElement.pDailyEveryNDays + suffix].value;

	for (var i = 0; i < 7; i++) {
		saveData[ScheduleElement.pDayOfWeek + i + suffix] = document.getElementById(ScheduleElement.pDayOfWeek + i + suffix).checked ? '1' : '0';
	}

	saveData[ScheduleElement.pMonthlyRec + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pMonthlyRec + suffix);
	saveData[ScheduleElement.pMonthlyOnDayN + suffix] = document.getElementById(ScheduleElement.pMonthlyOnDayN + suffix).value;
	saveData[ScheduleElement.pMonthlyOnNthDay + suffix] = document.getElementById(ScheduleElement.pMonthlyOnNthDay + suffix).value;
	saveData[ScheduleElement.pMonthlyOnNDayOfWeek + suffix] = document.getElementById(ScheduleElement.pMonthlyOnNDayOfWeek + suffix).value;
    saveData[SchedulePage.pJobType] = document.getElementById(SchedulePage.pJobType).value;
    return saveData;
}

SchedulePageUtil.getCheckedValue = function(paramName) {
	var params = document.getElementsByName(paramName);

	if (params.length == null) {
		if (params.checked) return params.value;
	} else {
		for (var i = 0; i < params.length; i++) {
			if (params[i].checked) return params[i].value;
		}
	}
	return '';
}

SchedulePageUtil.handleResponse = function(suffix, responseText) {
    var response = null;
    try {
    	response = Util.evalAjaxServletOutput(responseText);
    } catch (err) {
		if (window.location.replace){
			window.location.replace(window.location);
		} else {
			window.location.href = window.location.href;
		}
    	return;
    }

    //stop loading
	document.getElementById(ScheduleElement.pPrefTimeLoadingDiv + suffix).style.display = 'none';

    if (response[BlowoutServlet.SUCCESS]) {
    	SchedulePageUtil.setTimePicklist(suffix, response[BlowoutServlet.BLOWOUT]);
    	document.getElementById(ScheduleElement.pPrefTime + suffix).disabled = false;
    	document.getElementById(ScheduleElement.pPrefTime + suffix).style.display = 'block';
    } else {
    	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'block';
    }
    SchedulePageUtil.handleErrors(response);
}

SchedulePageUtil.setTimePicklist = function(suffix, values) {
	var options = document.getElementById(ScheduleElement.pPrefTime + suffix).options;

	//remove everything
	options.length = 0;

	if (values.length == 0) {
		options[0] = new Option(LC.getLabel('SelectElement', 'Required'), '');
	} else {
		for (var i = 0; i < values.length; i++) {
			options[i] = new Option(values[i], values[i]);
		}
	}
}

SchedulePageUtil.handleErrors = function(response) {
    var specific = response[AjaxServlet.ERROR_MSG_KEY];

    if (specific instanceof Array) {
    	if (specific.length > 3) {
    		document.getElementById(DetailElement.DEFAULT_ERROR_DIV_ID).style.display = 'block';
    	} else {
    		document.getElementById(DetailElement.DEFAULT_ERROR_DIV_ID).style.display = 'none';
    	}
	    for (var i = 0; i < specific.length; i++) {
	        var idAndVal = SchedulePageUtil.getIdAndVal(specific[i]);
	        SchedulePageUtil.setError(idAndVal[0], idAndVal[1]);
	    }
    } else {
    	//this is bad
    	//there are by default 3 elements in the array
    }
}

SchedulePageUtil.getIdAndVal = function(idVal) {
	return idVal.split(',');
}

SchedulePageUtil.setError = function(id, message) {
	//I have to get the div that this element is contained in.
	//Then search through that div and look for an errorMsg class
	//This is incrediby hacky and prone to error.
	var elem = null;
	if (document.getElementById(id).nodeName == "DIV") {
		elem = document.getElementById(id).parentNode
	} else {
		elem = document.getElementById(id).parentNode.parentNode;
	}
	var isErrorPresent = false;
	var errorLoc;
	for (var i = 0; i < elem.childNodes.length; i++) {
		if (elem.childNodes[i].className != null && elem.childNodes[i].className == "errorMsg") {
			isErrorPresent = true;
			errorLoc = i;
		}
	}

	//if the error is not there and we should be putting an error on the page, then create a new error div
    if (!isErrorPresent) {
    	if(message != '') {
	        var errorDiv = document.createElement("div");
		    errorDiv.className = "errorMsg";
		    errorDiv.innerHTML = message;
		    elem.appendChild(errorDiv);
    	}
    } else {
    	//if the error already exists on the page then simply show it
    	if(message != null) {
	        elem.childNodes[errorLoc].innerHTML = message;
	        elem.childNodes[errorLoc].style.display = "block";
    	} else {
    		elem.childNodes[errorLoc].style.display = "none";
    	}
    }
}



/**
* @author: mpolcari
* @since: 144
*/
function DeveloperNameInputElement() {}

DeveloperNameInputElement.setName = function(labelElement, developerNameElement, defaultName) {
  var ov = labelElement.value;
  var v =""
  var hasFirstChar = false;
  var lastCharIsUnderscore = false;
  if (developerNameElement.value.length == 0 && ov.length > 0) {
    for (i = 0; i < ov.length; i++) {
      var ch = ov.charAt(i);
      if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
          //                copy char if alphanumeric
        if (!hasFirstChar && (ch >= '0' && ch <= '9')) {
          //                  first char must be letter
          v += 'X';
        }
        v += ch;
        hasFirstChar = true;
        lastCharIsUnderscore = false;
      } else if (hasFirstChar && !lastCharIsUnderscore) {
          //                convert non-alphanumeric char to underscore, except that first char must not be underscore, and no consecutive underscores
        v += '_';
        lastCharIsUnderscore = true;
      }
    }
    if (!hasFirstChar) {
          //              if there is no alphanumeric chars, use the default
      developerNameElement.value = defaultName ;
    } else if (lastCharIsUnderscore) {
          //              make sure the last char is not an underscore
      developerNameElement.value = v.substring(0, v.length-1);
    } else {
      developerNameElement.value = v;
    }
  }
  return true;
}


SfdcElement = function() {};

SfdcElement.prototype.getElements = function(ids) {
    var elements = [];
    for (var n = 0; n < ids.length; n++) {
         elements.push(document.getElementById(ids[n]))
    }
    return elements;
}

SfdcElement.prototype.setVisibleElementsById = function(ids, show) {
    SfdcElement.prototype.setVisibleElements(SfdcElement.prototype.getElements(ids), show);
}

SfdcElement.prototype.setVisibleElements = function(elements, show) {
    for (var n = 0; n < elements.length; n++) {
        elements[n].style.visibility = (show) ? 'visible' : 'hidden'
    }
}

SfdcElement.prototype.setDisplayElementsById = function(ids, display) {
    SfdcElement.prototype.setDisplayElements(SfdcElement.prototype.getElements(ids), display);
}

SfdcElement.prototype.setDisplayElements = function(elements, display) {
    for (var n = 0; n < elements.length; n++) {
        elements[n].style.display = (display) ? 'block' : 'none'
    }
}

SfdcElement.prototype.setDisabledById = function(ids, disabled){
    SfdcElement.prototype.setDisabled(SfdcElement.prototype.getElements(ids), disabled);
}

SfdcElement.prototype.setDisabled = function(elements, disabled){
    for (var n = 0; n < elements.length; n++) {
        elements[n].disabled = disabled;
    }
}


/**
 * JS for Page Layout Asssignment Page
 */

/**
 * @param pagePLAUrl paginated Page Layout assignment URL
 * @param rtPLAUrl jump to a specific record type
 */
function LayoutMapping(pagePLAUrl, rtPLAUrl, pageLayoutType, pageLayoutDetailUrl, viewProfileId, isEdit, pageNum,
	recordTypeFieldsUrl, sysAdminQS) {
	this.pagePLAUrl = pagePLAUrl;
	this.rtPLAUrl = rtPLAUrl;
	this.pageLayoutType = pageLayoutType;
	this.pageNum = pageNum;
	this.isEdit = isEdit;
	this.pageSize = Cookies.prototype.GetCookie(LayoutMapping.PAGE_SIZE_COOKIE_NAME);
	if (!this.pageSize) {
		this.pageSize = LayoutMapping.DEFAULT_PAGE_SIZE;
	}
	this.profiles = null;
	this.recordTypes = null;
	this.pageLayouts = null;
	this.pageLayoutsMap = new Object();
	this.mapping = new Object();
	this.beginIndex = 0; // inclusive on recordtypes
	this.endIndex = 0; // exclusive on recordtypes
	this.pageLayoutQS = new QueryString(pageLayoutDetailUrl.substring(pageLayoutDetailUrl.indexOf('?') + 1));
	this.pageLayoutDetailUrl = pageLayoutDetailUrl.substring(0, pageLayoutDetailUrl.indexOf('?'));
	this.recordTypeFieldsQS = new QueryString(recordTypeFieldsUrl.substring(recordTypeFieldsUrl.indexOf('?') + 1));
	this.recordTypeFieldsUrl = recordTypeFieldsUrl.substring(0, recordTypeFieldsUrl.indexOf('?'));
	this.viewProfileId = viewProfileId; // profile and all its pla cells to highlight in view mode
	this.sysAdminQS = new QueryString(sysAdminQS.substring(sysAdminQS.indexOf('?') + 1));

	// mouse move cell selection
	this.cellMouseDown = false;
	this.origCell = null;
	this.curTarget = null;
	// click/ctrl+click/shift+click cell selection
	this.curCell = null;
	// select rows, click/ctrl+click/shift+click
	this.curRow = null;
	this.selectedRows = new Map();
	// select cols, click/ctrl+click/shift+click
	this.curCol = null;
	this.selectedCols = new Map();
	// selected cells and changed cells
	this.selected = new Map();
	this.profileRecordTypeSelected = new Map();
	this.recordTypeProfileSelected = new Map();
	this.changed = new Map();
}

LayoutMapping.CELLS_LIMIT = 2000;

LayoutMapping.DEFAULT_PAGE_SIZE = 4;

LayoutMapping.PAGE_SIZE_COOKIE_NAME = 'plaPageSize';

LayoutMapping.CELL_EVENT_HANDLER_HTML = " onmousedown=\"if(layoutMapping){layoutMapping.resetPageLayoutSelector(); layoutMapping.cellHandleMouseDown(event,this);}\" "
	+ "onmousemove=\"if(layoutMapping){layoutMapping.cellHandleMouseMove(event,this);}\" "
	+ "onmouseup=\"if(layoutMapping){layoutMapping.cellHandleMouseUp(event, this);}\" ";

LayoutMapping.PROFILE_HEADER_EVENT_HANDLER_HTML = " onclick=\"if(layoutMapping){layoutMapping.resetPageLayoutSelector(); layoutMapping.handleClickProfileHeader(event, this);}\" ";

LayoutMapping.RT_HEADER_EVENT_HANDLER_HTML = " onclick=\"if(layoutMapping){layoutMapping.resetPageLayoutSelector(); layoutMapping.handleClickRTHeader(event, this);}\" ";

LayoutMapping.EMPTY_KEY = "000000000000000";

LayoutMapping.PROFILE_HEADER_BASE_CLASS_NAME = " profileHeader ";

LayoutMapping.RT_HEADER_BASE_CLASS_NAME = " rtHeader ";

LayoutMapping.MASTER_RT_HEADER_BASE_CLASS_NAME = " pHeader rtHeader ";

LayoutMapping.prototype.getPageLayoutAssignment = function (profileId, recordTypeId) {
	if (!this.mapping) {
		return null;
	}
	var key = profileId + "_" + recordTypeId;
	var mappingVal = this.mapping[key];
	var changedMappingVal = this.changed.map[key];
	if (changedMappingVal) {
		mappingVal = changedMappingVal;
	}
	if (!mappingVal || !this.pageLayoutsMap) {
		return null;
	}
	return this.pageLayoutsMap[mappingVal.plId];
}

LayoutMapping.prototype.fetchMappingPage = function (showLoadingOverlay) {
	var qs = new QueryString("");
	qs.add('type', this.pageLayoutType);
	qs.add('pageNum', this.pageNum);
	qs.add('pageSize', this.pageSize);
	qs.add('pid', this.viewProfileId);

	if (showLoadingOverlay) {
		var plaContainerEl = document.getElementById('plaContainer');
		this.drawLoadingOverlay(plaContainerEl);
	}

	var lm = this;
	XBrowser.getHttpResponse(this.getUrl(this.pagePLAUrl, qs), function(req) {lm.processMappingData(req);});
}

LayoutMapping.prototype.getChunk = function (direction) {
	this.resetSelectionStartPoints();
	if (direction < 0) { // previous
		if (this.pageNum == 0)
			return;
		this.pageNum = this.pageNum - 1;
	} else { // next
		this.pageNum =  this.pageNum + 1;
	}
	this.fetchMappingPage(true);
}

LayoutMapping.prototype.processMappingData = function (request) {
	// json
	var response = Util.evalAjaxServletOutput(request.responseText);

	// page number
	this.pageNum = response.pageNum;

	// profile
	this.profiles = response.profiles;

	// record type
	this.recordTypes = response.recordTypes;
	this.beginIndex = this.pageNum * this.pageSize;
	this.endIndex = this.beginIndex + this.pageSize;
	if (this.endIndex > this.recordTypes.length) {
		this.endIndex = this.recordTypes.length;
	}

	// page layout
	this.pageLayouts = response.pageLayouts;
	for (var i = 0; i < this.pageLayouts.length; i++) {
		this.pageLayoutsMap[this.pageLayouts[i].id] = this.pageLayouts[i];
	}

	// mapping
	for (var i = 0; i < response.mapping.length; i++) {
		var key = response.mapping[i].pId + '_' + response.mapping[i].rtId;
		this.mapping[key] = response.mapping[i];
	}

	// hide loading indicator if needed
	var loadingDivEl = document.getElementById('loadingDiv');
	if (loadingDivEl) {
		if (loadingDivEl.style.display != 'none') {
			loadingDivEl.style.display = 'none';
		}
	}

	// rendering
	if (this.isEdit) {
		var pageLayoutSelectorSpan = document.getElementById('pageLayoutSelectorSpan');
		pageLayoutSelectorSpan.innerHTML = this.getPageLayoutSelectorHTML();
	}
	this.selectInitProfileRow();
	this.drawTable();
	this.setHeadersWidth();
	var lm = this;
	window.onresize = function(event) { lm.setHeadersWidth(); };
}

LayoutMapping.prototype.switchToEditMode = function () {
	var qs = new QueryString("");
	qs.add("type", this.pageLayoutType);
	qs.add("e", 1);
	qs.add("pageNum", this.pageNum);
	if (this.viewProfileId) {
		qs.add("pid", this.viewProfileId);
	}

	var url = location.href.substring(0, location.href.indexOf('?'));
	location.href = url + qs.toString();
}

//---------------------------------//
// Rendering                       //
//---------------------------------//
LayoutMapping.prototype.drawTable = function () {
	var w = [];

	w.push("<div id=\"plaHeaderDiv\" class=\"plaHeader\">");
	w.push("<table id=\"plaHeaderTable\" cellpadding=\"0\" cellspacing=\"0\">");
	this.drawTableHeader(w);
	w.push("</table></div>");
	w.push("<div id=\"plaBodyDiv\" class=\"plaBody\">");
	w.push("<table id=\"plaBodyTable\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">");
	w.push("<tbody>");
	for (var i = 0; i < this.profiles.length; i++) {
		w.push("<tr>");
		w.push(this.getProfileHTML(this.profiles[i]));
		for (var j = this.beginIndex; j < this.endIndex; j++) {
			var pageLayout = this.getPageLayoutAssignment(this.profiles[i].id, this.recordTypes[j].id);
			var highLight = (this.profiles[i].id == this.viewProfileId);
			if (!highLight) {
				highLight = (LayoutMappingHelper.getCellId(this.profiles[i].id, this.recordTypes[j].id) in this.selected.map);
			}
			this.drawPageLayoutCell(w, this.profiles[i].id, this.recordTypes[j].id, pageLayout, highLight);
		}
		w.push("</tr>");
	}
	w.push("</tbody>");
	w.push("</table>");
	w.push("</div>");
	var containerElem = document.getElementById("plaContainer");
	containerElem.innerHTML = w.join('');
}

LayoutMapping.prototype.drawLoadingOverlay = function (el) {
	if (!el) {
		return;
	}

	var loadingOpacityEl = this.createLoadingDivEl(el);
	loadingOpacityEl.className = "loadingOverlayDiv loadingOverlayDivOpacity";

	var loadingClearEl = this.createLoadingDivEl(el);
	loadingClearEl.className = "loadingOverlayDiv";

	var description = LC.getLabel("Global", "loading");

	var loadingHolder = document.createElement('span');
	loadingClearEl.appendChild(loadingHolder);
	loadingHolder.className = 'loadingHolder';

	var loadingImage = document.createElement('img');
	loadingHolder.appendChild(loadingImage);
	loadingImage.src = UserContext.getUrl('/img/loading.gif');
	loadingImage.className  = 'loadingImage';

	var loadingDescription = document.createElement('span');
	loadingHolder.appendChild(loadingDescription);
	loadingDescription.innerHTML =  description;
	loadingDescription.className  = 'loadingDescription';
}

LayoutMapping.prototype.createLoadingDivEl = function (el) {
	var loadingDivEl = document.createElement('div');
	el.appendChild(loadingDivEl);
	var height = el.offsetHeight;
	if (XBrowser.userAgent.isIE) {
		height = el.offsetHeight - 15;
	}
	loadingDivEl.style.width = el.offsetWidth + "px";
	loadingDivEl.style.height = height + "px";

	return loadingDivEl;
}

LayoutMapping.prototype.drawPageLayoutCell = function (w, profileId, recordTypeId, pageLayout, highLight) {
	var isChanged = this.changed.map[profileId + "_" + recordTypeId];
	w.push("<td id=\"" + LayoutMappingHelper.getCellId(profileId, recordTypeId) + "\" class=\""
		+ (isChanged ? " changedCell ": "") + (highLight ? " selectedCell " : "") + "\" "
		+ (this.isEdit ? LayoutMapping.CELL_EVENT_HANDLER_HTML : "") + ">");
	if (pageLayout == undefined) {
		w.push(LC.getLabel("LayoutMap", "NotAssigned"));
	} else {
		if (!this.isEdit) {
			this.pageLayoutQS.add("type", this.pageLayoutType);
			this.pageLayoutQS.add("lid", pageLayout.id);
			w.push("<a href=\"" +  (this.pageLayoutDetailUrl + this.pageLayoutQS.toString()) + "\">"
				+ pageLayout.name + "</a>");
		} else {
			w.push(pageLayout.name);
		}
	}
	w.push("</td>");
}

LayoutMapping.prototype.drawTableHeader = function (w) {
	if (this.recordTypes.length > 1) { // has record types other than just master
		w.push("<thead><tr><th id=\"emptyHeader\" class=\"prtHeader\"><div/></th>");
		this.drawRecordTypeHeader(w);
		w.push("</tr>");
		w.push("<tr><th class=\"prtHeader\"><div>" + LC.getLabel("LayoutMap", "Profiles") + "</div></th>");
		for (var i = this.beginIndex; i < this.endIndex; i++) {
			w.push(this.getRecordTypeHTML(this.recordTypes[i]));
		}
		w.push("</tr></thead>");
	} else {
		w.push("<thead><tr><th class=\"\prtHeader\"><div>" + LC.getLabel("LayoutMap", "Profiles")
			+ "</div></th>");
		this.drawRecordTypeHeader(w);
		w.push("</tr></thead>");
	}
}

LayoutMapping.prototype.getRecordTypeHTML = function (recordType) {
	var className = this.getRecordTypeHeaderClassName(recordType.id);
	var rtHTML = [];
	rtHTML.push('<th' + (this.isEdit ? LayoutMapping.RT_HEADER_EVENT_HANDLER_HTML : "")
		+ " id=\"" + recordType.id + "\" class=\"rtHeader " + className + "\"><div title=\"" + recordType.name + "\">");
	if (!this.isEdit && recordType.id != LayoutMapping.EMPTY_KEY) {
		this.recordTypeFieldsQS.add('id', recordType.id);
		this.recordTypeFieldsQS.add('type', this.pageLayoutType);
		rtHTML.push('<a href=\"' + this.recordTypeFieldsUrl + this.recordTypeFieldsQS.toString() + '\">'
			+ recordType.name + '</a>');
	} else {
		rtHTML.push(recordType.name);
	}
	rtHTML.push('</div></th>');
	return rtHTML.join('');
}

LayoutMapping.prototype.getProfileHTML = function (profile) {
	var className = this.getProfileHeaderClassName(profile.id, this.viewProfileId);
	var profileHTML = [];
	profileHTML.push("<td class=\"profileHeader " + className + "\""
			+ (this.isEdit ? LayoutMapping.PROFILE_HEADER_EVENT_HANDLER_HTML : "")
			+ " id=\"" + profile.id + "\">");
	if (!this.isEdit) {
		profileHTML.push("<a href=\"" + this.getUrl('/' + profile.id, this.sysAdminQS) + "\">" + profile.name + "</a>");
	} else {
		profileHTML.push(profile.name);
	}
	profileHTML.push("</td>");
	return profileHTML.join('');
}

LayoutMapping.prototype.drawRecordTypeHeader = function(w) {
	if (this.recordTypes.length > 1) {
		w.push("<th id=\"recordTypesHeader\" colspan=\"" + (this.endIndex - this.beginIndex)
			+ "\"><table width=\"100%\" id=\"recordTypeHeader\"><thead><tr><th class=\"prtHeader alignLeft\">"
			+ LC.getLabel("LayoutMap", "RecordTypes")
			+ "</th><th class=\"navigationHeaderNormal\">");
		this.drawPrevNext(w);
		w.push("</th></tr></thead></table></th>");
	} else {
		var className = this.getRecordTypeHeaderClassName(this.recordTypes[0].id);
		w.push("<th class=\"pHeader rtHeader " + className + "\""
			+ (this.isEdit ? LayoutMapping.RT_HEADER_EVENT_HANDLER_HTML : "")
			+ " id=\"" + this.recordTypes[0].id + "\"><div>" + LC.getLabel("FLSLayout", "Layout") + "</div></th>");
	}
}

LayoutMapping.prototype.drawPrevNext = function(w) {
	if (this.pageNum > 0) {
		w.push("<a href=\"javascript: layoutMapping.getChunk(-1);\" id=\"plaPrevLink\">&lt;Prev</a>");
	} else {
		w.push("");
	}
	w.push(" (" + (this.beginIndex + 1) + "-" + this.endIndex + " of " + this.recordTypes.length + ") ");
	if (this.endIndex >= this.recordTypes.length) {
		w.push("");
	} else {
		w.push("<a href=\"javascript: layoutMapping.getChunk(1);\" id=\"plaNextLink\">Next&gt;</a>");
	}
}

LayoutMapping.prototype.getPageLayoutSelectorHTML = function () {
	var pageLayoutSelectorHTML = "<select id=\"pageLayoutSelector\" name=\"pageLayoutSelector\" onchange=\"layoutMapping.onChangePLA(this);\">";
	pageLayoutSelectorHTML += "<option selected=\"selected\" value=\"000000000000000\">"
		+ LC.getLabel("LayoutMap", "SelectOne") + "</option>";
	for (var i = 0; i < this.pageLayouts.length; i++) {
		pageLayoutSelectorHTML += "<option value=\"" + this.pageLayouts[i].id + "\">" + this.pageLayouts[i].name
			+ "</option>";
	}
	pageLayoutSelectorHTML += "</select>";
	return pageLayoutSelectorHTML;
}

//------------------------------------------//
// Fixed column header, Scrollable body     //
//------------------------------------------//
LayoutMapping.prototype.setHeadersWidth = function () {
	var plaBodyTableEl = document.getElementById('plaBodyTable');
	if (!plaBodyTableEl) {
		return;
	}
	var plaBodyDivEl = document.getElementById('plaBodyDiv');
	if (plaBodyDivEl) {
		if (plaBodyTableEl.clientHeight < 450) {
			plaBodyDivEl.style.height = plaBodyTableEl.clientHeight + "px";
		} else {
			plaBodyDivEl.style.height = "450px";
		}
	}

	var plaBodyTableBodyEl = plaBodyTableEl.getElementsByTagName('tbody')[0];
	var plaBodyTableFirstRowEl = plaBodyTableBodyEl.firstChild;
	var firstRowCells = plaBodyTableFirstRowEl.childNodes;
	var profileHeaderCell = firstRowCells[0];

	var plaHeaderTableEl = document.getElementById('plaHeaderTable');
	plaHeaderTableEl.style.display = "none";

	var plaHeaderTableHeaderEl = plaHeaderTableEl.getElementsByTagName('thead')[0];
	if (this.recordTypes.length > 1) {
		var emptyHeaderEl = document.getElementById('emptyHeader');
		emptyHeaderEl.firstChild.style.width = profileHeaderCell.clientWidth + "px";
		var recordTypeHeaderRowEl = plaHeaderTableHeaderEl.childNodes[1];
		var recordTypeCells = recordTypeHeaderRowEl.childNodes;
		for (var i = 0; i < firstRowCells.length; i++) {
			recordTypeCells[i].firstChild.style.width = firstRowCells[i].clientWidth + "px";
		}
	} else {
		var pageLayoutHeaderRowEl = plaHeaderTableHeaderEl.childNodes[0];
		var pageLayoutHeaderCells = pageLayoutHeaderRowEl.childNodes;
		for (var i = 0; i < firstRowCells.length; i++) {
			pageLayoutHeaderCells[i].firstChild.style.width = firstRowCells[i].clientWidth + "px";
		}
	}

	plaHeaderTableEl.style.display="";
}

//---------------------------------//
// Selection                       //
//---------------------------------//
// cell onmousedown
LayoutMapping.prototype.cellHandleMouseDown = function (ev, el) {
	this.clearTextSelection();
	this.curRow = null;
	this.curCol = null;

	this.cellMouseDown = true;
	this.curTarget = el;
	if (ev.shiftKey && this.curCell) { // shift+click following a click
		this.clearSelection();
		this.selectRange(el, this.curCell);
	} else {
		if (ev.ctrlKey) { // toggle selection, ctrl+click
			this.curCell = null;
			this.origCell = el; // start point for holding mouse down and move
			this.toggleCell(el.id);
		} else { // click or shift+click not following a click
			this.clearSelection();
			this.curCell = el; // for shift+click later
			this.origCell = el; // for cellHandleMouseMove
			this.selectCell(el.id);
		}
	}
	this.updateNumSelected();
}

// cell onmousemove
LayoutMapping.prototype.cellHandleMouseMove = function(ev,el) {
	if(this.cellMouseDown && el != this.curTarget) {
		this.curTarget = el;
		this.clearTextSelection();
		if( !ev.ctrlKey )
			this.clearSelection();
		this.selectRange(el, this.origCell);
		this.updateNumSelected();
	}
}

// cell onmouseup
LayoutMapping.prototype.cellHandleMouseUp = function () {
	this.cellMouseDown = false;
	this.origCell = null;
	this.curTarget = null;
	this.clearTextSelection();
	this.setStylesOfAllHeaders();
}

LayoutMapping.prototype.handleClickProfileHeader = function (ev, el) {
	this.clearTextSelection();
	this.curCell = null;
	this.curCol = null;

	if (ev.shiftKey && this.curRow) {
		this.clearSelection();
		this.selectRows(el.id, this.curRow.id);
	} else {
		if (ev.ctrlKey) {
			this.curRow = null;
			this.toggleRow(el.id);
		} else {
			this.clearSelection();
			this.curRow = el;
			this.selectRow(el.id);
		}
	}
	this.setStylesOfAllHeaders();
	this.updateNumSelected();
}

LayoutMapping.prototype.handleClickRTHeader = function (ev, el) {
	this.clearTextSelection();
	this.curCell = null;
	this.curRow = null;

	if (ev.shiftKey && this.curCol) {
		this.clearSelection();
		this.selectColumns(el.id, this.curCol.id);
	} else {
		if (ev.ctrlKey) {
			this.curCol = null;
			this.toggleColumn(el.id);
		} else {
			this.clearSelection();
			this.curCol = el;
			this.selectColumn(el.id);
		}
	}
	this.setStylesOfAllHeaders();
	this.updateNumSelected();
}

LayoutMapping.prototype.selectRange = function (elFrom, elTo) {
	if (!elFrom || !elTo) {
		return;
	}

	var fromRecordTypeId = LayoutMappingHelper.getCellRecordTypeId(elFrom);
	var fromProfileId = LayoutMappingHelper.getCellProfileId(elFrom);
	var toRecordTypeId = LayoutMappingHelper.getCellRecordTypeId(elTo);
	var toProfileId = LayoutMappingHelper.getCellProfileId(elTo);

	var rtIndex1 = LayoutMappingHelper.getIndex(this.recordTypes, fromRecordTypeId);
	var rtIndex2 = LayoutMappingHelper.getIndex(this.recordTypes, toRecordTypeId);
	var pIndex1 = LayoutMappingHelper.getIndex(this.profiles, fromProfileId);
	var pIndex2 = LayoutMappingHelper.getIndex(this.profiles, toProfileId);

	var beginRTIndex = Math.min(rtIndex1, rtIndex2);
	var endRTIndex = Math.max(rtIndex1, rtIndex2) + 1;
	var beginPIndex = Math.min(pIndex1, pIndex2);
	var endPIndex = Math.max(pIndex1, pIndex2) + 1;

	for (var i = beginRTIndex; i < endRTIndex; i++) {
		for (var j = beginPIndex; j < endPIndex; j++) {
			this.selectCell(LayoutMappingHelper.getCellId(this.profiles[j].id, this.recordTypes[i].id));
		}
	}
}

LayoutMapping.prototype.selectColumn = function (recordTypeId) {
	this.selectedCols.put(recordTypeId, recordTypeId);
	for (var i = 0; i < this.profiles.length; i++) {
		this.selectCell(LayoutMappingHelper.getCellId(this.profiles[i].id, recordTypeId));
	}
}

LayoutMapping.prototype.selectColumns = function (fromRecordTypeId, toRecordTypeId) {
	var rtIndex1 = LayoutMappingHelper.getIndex(this.recordTypes, fromRecordTypeId);
	var rtIndex2 = LayoutMappingHelper.getIndex(this.recordTypes, toRecordTypeId);
	var beginRTIndex = Math.min(rtIndex1, rtIndex2);
	var endRTIndex = Math.max(rtIndex1, rtIndex2) + 1;
	for (var i = beginRTIndex; i < endRTIndex; i++) {
		this.selectColumn(this.recordTypes[i].id);
	}
}

LayoutMapping.prototype.selectInitProfileRow = function () {
	if (!this.viewProfileId) {
		return;
	}

	this.selectedRows.put(this.viewProfileId, this.viewProfileId);
	for (var i = 0; i < this.recordTypes.length; i++) {
		this.populateDataForSelectedCell(this.viewProfileId, this.recordTypes[i].id);
	}

	if (this.isEdit) {
		this.updateNumSelected();
	}
}

LayoutMapping.prototype.selectRow = function (profileId) {
	this.selectedRows.put(profileId, profileId);
	for (var i = 0; i < this.recordTypes.length; i++) {
		this.selectCell(LayoutMappingHelper.getCellId(profileId, this.recordTypes[i].id));
	}
}

LayoutMapping.prototype.selectRows = function (fromProfileId, toProfileId) {
	var pIndex1 = LayoutMappingHelper.getIndex(this.profiles, fromProfileId);
	var pIndex2 = LayoutMappingHelper.getIndex(this.profiles, toProfileId);
	var beginPIndex = Math.min(pIndex1, pIndex2);
	var endPIndex = Math.max(pIndex1, pIndex2) + 1;
	for (var i = beginPIndex; i < endPIndex; i++) {
		this.selectRow(this.profiles[i].id);
	}
}

LayoutMapping.prototype.selectCell = function (id) {
	LayoutMappingHelper.selectCellById(id);
	var recordTypeId = id.substring(id.indexOf("_") + 1);
	var profileId = id.substring(0, id.indexOf("_"));

	this.populateDataForSelectedCell(profileId, recordTypeId);
}

LayoutMapping.prototype.populateDataForSelectedCell = function (profileId, recordTypeId) {
	var id = profileId + "_" + recordTypeId;
	var val = this.mapping[id];
	if (!val) {
		val = new Object();
		val.rtId = recordTypeId;
		val.pId = profileId;
	}
	this.selected.put(id, val);

	var recordTypeSelected = this.profileRecordTypeSelected.map[profileId];
	if (!recordTypeSelected) {
		recordTypeSelected = new Map();
		this.profileRecordTypeSelected.put(profileId, recordTypeSelected);
	}
	recordTypeSelected.put(recordTypeId, val);

	var profileSelected = this.recordTypeProfileSelected.map[recordTypeId];
	if (!profileSelected) {
		profileSelected = new Map();
		this.recordTypeProfileSelected.put(recordTypeId, profileSelected);
	}
	profileSelected.put(profileId, val);
}

LayoutMapping.prototype.deselectColumn = function(recordTypeId) {
	for (var i = 0; i < this.profiles.length; i++) {
		this.deselectCell(LayoutMappingHelper.getCellId(this.profiles[i].id, recordTypeId));
	}
	this.selectedCols.remove(recordTypeId);
}

LayoutMapping.prototype.deselectRow = function (profileId) {
	for (var i = 0; i < this.recordTypes.length; i++) {
		this.deselectCell(LayoutMappingHelper.getCellId(profileId, this.recordTypes[i].id));
	}
	this.selectedRows.remove(profileId);
}

LayoutMapping.prototype.deselectCell = function (id) {
	LayoutMappingHelper.deselectCellById(id);
	this.selected.remove(id);

	var profileId = id.substring(0, id.indexOf("_"));
	var recordTypeId = id.substring(id.indexOf("_") + 1);
	this.selectedRows.remove(profileId);
	this.selectedCols.remove(recordTypeId);

	var recordTypeSelected = this.profileRecordTypeSelected.map[profileId];
	if (recordTypeSelected) {
		recordTypeSelected.remove(recordTypeId);
		if (recordTypeSelected.size == 0) {
			this.profileRecordTypeSelected.remove(profileId);
		}
	}

	var profileSelected = this.recordTypeProfileSelected.map[recordTypeId];
	if (profileSelected) {
		profileSelected.remove(profileId);
		if (profileSelected.size == 0) {
			this.recordTypeProfileSelected.remove(recordTypeId);
		}
	}
}

LayoutMapping.prototype.toggleRow = function (id) {
	if (id in this.selectedRows.map) {
		this.deselectRow(id);
	} else {
		this.selectRow(id);
	}
}

LayoutMapping.prototype.toggleColumn = function (id) {
	if (id in this.selectedCols.map) {
		this.deselectColumn(id);
	} else {
		this.selectColumn(id);
	}
}

LayoutMapping.prototype.toggleCell = function (id) {
	if (id in this.selected.map) {
		this.deselectCell(id);
	} else {
		this.selectCell(id);
	}
}

LayoutMapping.prototype.resetSelectionStartPoints = function () {
	this.curRow = null;
	this.curCol = null;
	this.cellMouseDown = false;
	this.origCell = null;
	this.curTarget = null;
	this.curCell = null;
}

LayoutMapping.prototype.clearSelection = function () {
	for (var key in this.selected.map) {
		this.deselectCell(key);
	}
	this.selectedRows = new Map();
	this.selectedCols = new Map();
	this.selected = new Map();
	this.profileRecordTypeSelected = new Map();
	this.recordTypeProfileSelected = new Map();
}

LayoutMapping.prototype.clearTextSelection = function (){
    if (document.selection && document.selection.empty) {
        document.selection.empty();
    } else {
		if (window.getSelection().removeAllRanges)
	    	window.getSelection().removeAllRanges();
	}
}

LayoutMapping.prototype.updateNumSelected = function () {
	var numSelectedEl = document.getElementById("selectedCellsSpan");
	if (numSelectedEl) {
		numSelectedEl.innerHTML = this.selected.size + " " + LC.getLabel("LayoutMap", "Selected");
	}
}

LayoutMapping.prototype.updateNumChosen = function () {
	var numChangedEl = document.getElementById("changedCellsSpan");
	if (numChangedEl) {
		numChangedEl.innerHTML = this.changed.size + " " + LC.getLabel("LayoutMap", "Changed");
	}
}

//-----------------------//
// Change                //
//-----------------------//
LayoutMapping.prototype.onChangePLA = function (plaSelectorEl) {
	var newPageLayoutId = plaSelectorEl.options[plaSelectorEl.selectedIndex].value;
	if (newPageLayoutId == LayoutMapping.EMPTY_KEY || this.selected.size == 0) {
		return;
	}

	if (this.isChangedOverLimit()) {
		alert(LC.getLabel("LayoutMap", "PLAChangesAboveLimit", LayoutMapping.CELLS_LIMIT));
		return;
	}

	for (var profileRTId in this.selected.map) {
		var origPLA = this.mapping[profileRTId];
		var newPLA = new Object();
		if (!origPLA) {
			newPLA.pId = profileRTId.substring(0, profileRTId.indexOf("_"));
			newPLA.rtId = profileRTId.substring(profileRTId.indexOf("_") + 1);
			newPLA.plId = newPageLayoutId;
		} else {
			var newPLA = new Object();
			newPLA.id = origPLA.id;
			newPLA.pId = origPLA.pId;
			newPLA.rtId = origPLA.rtId;
			newPLA.plId = newPageLayoutId;
		}
		this.changed.put(profileRTId, newPLA);
		LayoutMappingHelper.changeCellById(profileRTId);
		var cellEl = getElementByIdCS(profileRTId);
		if (cellEl) {
			cellEl.innerHTML = this.pageLayoutsMap[newPageLayoutId].name;
		}
	}

	this.updateNumChosen();
	this.setHeadersWidth();
}

LayoutMapping.prototype.resetPageLayoutSelector = function () {
	var pageLayoutSelectorEl = document.getElementById('pageLayoutSelector');
	if (pageLayoutSelectorEl) {
		pageLayoutSelectorEl.selectedIndex = 0;
	}
}

LayoutMapping.prototype.isChangedOverLimit = function () {
	if (this.selected.size == 0 || (this.selected.size + this.changed.size) <= LayoutMapping.CELLS_LIMIT) {
		return false;
	}

	var totalToBeChanged = this.changed.size;
	for (var profileRTId in this.selected.map) {
		if (!(profileRTId in this.changed.map)) {
			totalToBeChanged++;
		}
	}
	if (totalToBeChanged > LayoutMapping.CELLS_LIMIT) {
		return true;
	}
	return false;
}

//-----------------------//
// Header Style          //
//-----------------------//
LayoutMapping.prototype.setStylesOfAllHeaders = function () {
	for (var i = 0; i < this.profiles.length; i++) {
		var recordTypeSelected = this.profileRecordTypeSelected.map[this.profiles[i].id];
		var profileHeaderEl = getElementByIdCS(this.profiles[i].id);
		this.setHeaderStyle(LayoutMapping.PROFILE_HEADER_BASE_CLASS_NAME, profileHeaderEl, recordTypeSelected,
			 this.selectedRows);
	}

	var rtHeaderBaseClassName = (this.recordTypes.length > 1) ? LayoutMapping.RT_HEADER_BASE_CLASS_NAME :
		LayoutMapping.MASTER_RT_HEADER_BASE_CLASS_NAME;

	for (var j = this.beginIndex; j < this.endIndex; j++) {
		var profileSelected = this.recordTypeProfileSelected.map[this.recordTypes[j].id];
		var recordTypeHeaderEl = getElementByIdCS(this.recordTypes[j].id);
		this.setHeaderStyle(rtHeaderBaseClassName, recordTypeHeaderEl, profileSelected, this.selectedCols);
	}
}

LayoutMapping.prototype.setHeaderStyle = function (baseClassName, el, selectedMap, selectedHeaders) {
	if (!el) {
		return;
	}
	if (!selectedMap || selectedMap.size == 0) {
		if (el.className.indexOf('selectedHeader') > 0 || el.className.indexOf('highlightedHeader') > 0) {
			el.className = baseClassName;
		}
		// el.className = baseClassName;
	} else {
		if (el.id in selectedHeaders.map) {
			if (el.className.indexOf('selectedHeader') < 0) {
				el.className =	baseClassName + ' selectedHeader';
				// el.style.backgroundColor = '#8E9DBE';
				// el.style.color = '#FFFFFF';
			}
		} else {
			if (el.className.indexOf('highlightedHeader') < 0) {
				el.className =	baseClassName + ' highlightedHeader';
				// el.style.backgroundColor = '#D0D0FF';
			}
		}
	}
}

LayoutMapping.prototype.getProfileHeaderClassName = function (headerProfileId, profileId) {
	var isSelectedRow = (this.viewProfileId == headerProfileId);
	if (this.isEdit && !isSelectedRow) {
		isSelectedRow = (headerProfileId in this.selectedRows.map);
	}
	if (isSelectedRow) {
		return " selectedHeader ";
	}
	var recordTypeSelected = this.profileRecordTypeSelected.map[headerProfileId];
	if (recordTypeSelected && recordTypeSelected.size > 0) {
		return " highlightedHeader ";
	}
	return " ";
}

LayoutMapping.prototype.getRecordTypeHeaderClassName = function (recordTypeId) {
	if (this.isEdit && (recordTypeId in this.selectedCols.map)) {
		return " selectedHeader ";
	}
	var profileSelected = this.recordTypeProfileSelected.map[recordTypeId];
	if (profileSelected && profileSelected.size > 0) {
		return " highlightedHeader ";
	}
	return " ";
}

//---------------------------------//
// Save                            //
//---------------------------------//
LayoutMapping.prototype.save = function() {
	var changedPLAsEl = document.getElementById('changedPLAs');
	if (!changedPLAsEl) {
		return;
	}
	changedPLAsEl.value = this.toXML();
}

LayoutMapping.prototype.toXML = function () {
	var xml = [];
	xml.push('<changedPLAs>');
	for (var profileRTId in this.changed.map) {
		var val = this.changed.map[profileRTId];
		xml.push('<item ');
		xml.push('id="' + (val.id ? val.id : LayoutMapping.EMPTY_KEY) + '" ');
		xml.push('pId="' + val.pId + '" ');
		xml.push('rtId="' + val.rtId + '" ');
		xml.push('plId="' + val.plId + '" ');
		xml.push('/>');
	}
	xml.push('</changedPLAs>');
	return xml.join('');
}

LayoutMapping.prototype.cancel = function () {
	var qs = new QueryString("");
	qs.add("type", this.pageLayoutType);
	qs.add("pageNum", this.pageNum);
	if (this.viewProfileId) {
		qs.add("pid", this.viewProfileId);
	}
	var url = location.href.substring(0, location.href.indexOf('?'));
	location.href = url + qs.toString();
}

LayoutMapping.prototype.getUrl = function (url, qs) {
	if (!url || !qs) {
		return "";
	}

    url = UserContext.getUrl(url);
    
	// query string is empty
	var qsStr = qs.toString();
	if (qsStr.length == 0) {
		return url;
	}

	// question mark in url
	if (url.indexOf('?') >= 0) {
		if (url.indexOf('?') == (url.length - 1)) {
			// no params after question mark
			return url + qs.toString().substring(1);
		} else {
			// params after question mark
			return url + '&' + qs.toString().substring(1);
		}
	}

	// no question mark in url
	return url + qs.toString();
}



/**
 * multiforce!
 */
function AppPicker(appExchangeUrl, appStoreUrl, developerUrl, pick, urlMap, btn) {
    this.appExchangeUrl = appExchangeUrl;
    this.appStoreUrl = appStoreUrl;
    this.developerUrl = developerUrl;
    this.picker = pick;
    this.originalIndex = pick.selectedIndex;
    this.urlMap = urlMap;

    var self = this;
    if (btn) {
        addEvent(btn, 'click', function() { self.handleChange(); }, false);
        addEvent(pick, 'change', function() { self.changeAlt(); }, false);
    } else {
        addEvent(pick, 'change', function() { self.handleChange(); }, false);
    }
    this.changeAlt();
}

AppPicker.prototype.changeAlt = function() {
    this.picker.title = this.picker[this.picker.selectedIndex].text;
}

AppPicker.prototype.handleChange = function() {
    if (this.picker.options[this.picker.selectedIndex].value == "AppExchange") {
        var newWindow = window.open(this.appExchangeUrl, "AppExchangePopup");
        this.picker.selectedIndex = this.originalIndex;
        newWindow.focus();
    } else if(this.picker.options[this.picker.selectedIndex].value == "AppStore") {
        var newWindow = window.open(this.appStoreUrl, "AppStorePopup");
        this.picker.selectedIndex = this.originalIndex;
        newWindow.focus();
    } else if(this.picker.options[this.picker.selectedIndex].value == "DeveloperForce") {
        var newWindow = window.open(this.developerUrl, "DeveloperForcePopup");
        this.picker.selectedIndex = this.originalIndex;
        newWindow.focus();
    } else if(this.picker.options[this.picker.selectedIndex].value == "EMPTY") {
        this.picker.selectedIndex = this.originalIndex;
    } else {
    	var url = this.urlMap[this.picker.options[this.picker.selectedIndex].value];
        // strip off base url e.g. site url prefix for next comparison
        var tmpUrl = url.replace(UserContext.getUrl('/'), '/');
    	if(tmpUrl.length >= 4 && tmpUrl.substring(0, 4) == '/sfc') {
    		this.handleSFCTabSwitch(url);
    		return;
    	}
		else if (url.indexOf("?") >= 0 ){  // If there are parameters in the URL
			url = this.parseUrlParamsIntoHiddens(url);
    	}
    	this.picker.form.action = this.urlMap[this.picker.options[this.picker.selectedIndex].value];
        this.picker.form.submit();
    }
}

AppPicker.prototype.parseUrlParamsIntoHiddens = function( url ){
	var urlWithoutParams = url.split('?')[0]
    var paramString = url.split('?')[1];
	var params = paramString.split('&');
	for (var i=0;i<params.length;i++){
		var newHidden = document.createElement("INPUT");
		newHidden.type = "hidden";
		newHidden.name = params[i].split('=')[0];
		newHidden.id = params[i].split('=')[0];
		newHidden.value = params[i].split('=')[1];
		this.picker.form.appendChild(newHidden);
	}
	return urlWithoutParams;
}

AppPicker.prototype.handleSFCTabSwitch = function(url) {
	var tsidParam = this.picker.name + '=' + this.picker.options[this.picker.selectedIndex].value;
	if(url.indexOf('?') > -1) {
		url += '&';
	}
	else {
		url += '?';
	}
	url += tsidParam;
	document.location.href = url;
}

/*
 * @author pburstein
 * @since 150
 * Lookup input element
 *
 */

function LookupElement() {
    var self=this;
    this.lookupPick = function (formName, parentIdElementName, parentEditElementName, relatedFieldName, id, display, relatedFieldValue, extraNameElementName) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPick(formName, parentIdElementName, parentEditElementName, relatedFieldName, id, display, relatedFieldValue, extraNameElementName);
    }
    
    this.lookupPick2 = function(formName, parentIdElementName, parentEditElementName, id, display, extraNameElementName, extraName, extraIdElementName, extraId, allowOverwrite) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPick2(formName, parentIdElementName, parentEditElementName, id, display, extraNameElementName, extraName, extraIdElementName, extraId, allowOverwrite)
    }
    this.lookupPhonePick = function(parentId, newValue) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPhonePick(parentId, newValue)
    }
}

LookupElement.prototype.openLookup = function(baseURL, width, modified, searchParam) {
    if (modified == '1') baseURL = baseURL + searchParam;
    this.initOverlay(baseURL).show();
}

LookupElement.prototype.closeLookup = function() {
    this.getOverlay().hide();
    this.redirectIframe(IFrameElement.BLANK_SRC);
}

LookupElement.prototype.getOverlay = function() {
    return sfdcPage.getDialogById(LookupInputElement.DIALOG_ID);
}

LookupElement.prototype.redirectIframe = function(url) {
    this.getOverlay().getContentElement().firstChild.src = url;
}

LookupElement.prototype.initOverlay = function (baseURL) {
    var ret = this.getOverlay();
    if (ret) {
        this.redirectIframe(baseURL);
    } else {
        var iframeHtml=[]
        iframeHtml.push('<iframe ');
        iframeHtml.push('src="');
        iframeHtml.push(baseURL);
        iframeHtml.push('" class="pageMaskIFrame" scrolling="no" ');
        iframeHtml.push('id="');
        iframeHtml.push(LookupInputElement.LOOKUP_IFRAME);
        iframeHtml.push('" name="');
        iframeHtml.push(LookupInputElement.LOOKUP_IFRAME);
        iframeHtml.push('"></iframe>');
        iframeHtml = iframeHtml.join('');
    
        ret = new FunctionalDialog(LookupInputElement.DIALOG_ID, true, LC.getLabel('Lookup', 'Title'));
        ret.setWidth(900);
        ret.setMaxHeight(700);
        ret.hideSummaryElement();
        ret.clearButtons();
        sfdcPage.registerDialog(ret);
        ret.setContentInnerHTML(iframeHtml);
    }
    return ret;
}


/**
  CustomMotifDefinition is instantiated on (you guessed it) CustomMotifDefinitionPage.java

  @author polcari
  @since 144


  @parentMotifId  This id for the parent's motifElement.  It is passed as a QS var to CustomMotifDefinitionPage

*/

function CustomMotifDefinition(parentMotifId) {

  this.parentMotifInputObject = window.opener.document.getElementById(parentMotifId).motifInputElement;
  this.motifObject = document.getElementById(CustomMotifDefinitionPageConst.COLOR_ELEMENT).motifInputElement;
  this.iconObject = document.getElementById(CustomMotifDefinitionPageConst.MOTIF_ICON_PARAM).imageSelectElement;
}


//this has dependancies on a number of global JS vars
//see CustomMotifDefinitionPage.getVariablesForJS()
CustomMotifDefinition.prototype.returnSelections = function() {
  if (this.motifObject.isNull()) {
    alert(noMotifErrorMsg);  //It would be nice to load these from LC
    return false;
  } else if (this.iconObject.isNull()) {
    alert(noIconErrorMsg);
    return false;
  } else {
   //copy Motif key
    this.parentMotifInputObject.motifElement.className = this.motifObject.motifElement.className.replace("motifColorElement","customDefinedMotif");
    this.parentMotifInputObject.setMotifKey(this.motifObject.motifKeyInput.value);
   //copy text
    this.parentMotifInputObject.setDescription(userDefinedDescription);
   //copy image
    this.parentMotifInputObject.setIconSrc(this.iconObject.image.src);
    this.parentMotifInputObject.setIconValue(this.iconObject.inputElement.value);

    window.blur();
    window.close();
    return true;
  }
}


//helper function
CustomMotifDefinition.prototype.copyInputVal = function(fromID, toID) {
  window.opener.document.getElementById(toID).value = document.getElementById(fromID).value;
}
//helper function
CustomMotifDefinition.prototype.copyInput = function(fromInput, toInput) {
  toInput.value = fromInput.value;
}



/*
 * @author ldelascurain
 * @since 150
 *
 */

function FieldTreeNode( key, isLeaf, children, labelName, showLabel, attributes) {
    this.key = key;
    this.isLeaf = isLeaf;
    this.labelName = labelName;
    this.showLabel = showLabel;
    this.attributes = attributes;
    if (children)
	    this.setChildren(children);
}

FieldTreeNode.prototype.setChildren = function(children){
	this.isLeaf = false;
	this.children = children;
	for (var i=0;i<children.length;i++){
    	children[i].parent = this;
    }
}

FieldTreeNode.prototype.getLabelToInsert = function(ignoreShowLabel){
	
    if (!(this.parent && (this.parent.showLabel || ignoreShowLabel)))
        return this.key;
    return this.parent.getLabelToInsert(ignoreShowLabel) + "." + this.key;
}

FieldTreeNode.prototype.getExtraAttributes = function(){

	var attributeArr = ["<table class='fieldPickerAttributeTable'>"];
	for (var key in this.attributes){
		attributeArr.push("<tr><td class='fieldPickerAttributeCategory'>");
		attributeArr.push(key);
		attributeArr.push("&nbsp;")
		attributeArr.push(this.attributes[key]);
		attributeArr.push("</td></tr>");
	}
    attributeArr.push("</table>");

    return attributeArr.join("");
}
function SimpleDecimalFormat(decimalSeparator, groupingSeparator, posPrefix, negPrefix, posSuffix, negSuffix) {
	this.decimalSeparator = decimalSeparator;
	this.groupingSeparator = groupingSeparator;
	this.posPrefix = posPrefix;
	this.negPrefix = negPrefix;
	this.posSuffix = posSuffix;
	this.negSuffix = negSuffix;
}

SimpleDecimalFormat.prototype.formatNumber = function(n) {
	n = parseFloat(n);
	var whole = String(parseInt(n, 10));
	var sub = Math.round((n - parseInt(n, 10))*100);
    sub = (sub < 0) ? sub * -1 : sub;
	if (sub == 100) {
		whole++;
		sub = '00';
	} else {
		sub = sub == 0 ? '00' : sub < 10 ? '0' + sub : String(sub);
	}
	var r = /(\d+)(\d{3})/;
	while (r.test(whole)) {
	    whole = whole.replace(r, '$1' + this.groupingSeparator + '$2');
	}
	return whole + this.decimalSeparator + sub;
}

SimpleDecimalFormat.prototype.formatCurrency = function(n) {
	val = parseFloat(n);
	n = this.formatNumber(n);
	if (val >= 0) {
		return this.posPrefix + n + this.posSuffix;
	} else {
		if(n.charAt(0) == '-'){
		    n = n.substr(1);
		}
		return this.negPrefix + n + this.negSuffix;
	}
}

SimpleDecimalFormat.prototype._parseFloat = function(n) {
	n = String(n);
	if (n.indexOf(this.decimalSeparator) < 0)
		return parseInt(n, 10);
	var ps = n.split(this.decimalSeparator);
	var sub = ps[1] ? parseInt(ps[1], 10) : 0;
	if (isNaN(ps[0]) || isNaN(sub)) {
		return NaN;
	} 
	sub = ps[1] ? sub / (Math.pow(10, ps[1].length)) : 0;
	if (ps[0].length > 0) {
	   return parseInt(ps[0]) + sub;
    } else {
        return sub;
    }
}

SimpleDecimalFormat.prototype._isNaN = function(n) {
	for (var i=0; i<n.length; i++) {
		var c = n.charAt(i);
		if (isNaN(parseInt(c)) && c != this.decimalSeparator) {
			return true;
		}
	}
	return false;
}

/**
 * @author zzhou
 * since 148
 * CrtLayout javascript code; also see AvailableSection.js, AvailableField.js, Lookups.js
 */

     CrtLayoutElement.layoutSections = {};
     CrtLayoutElement.layoutSecPos = [];
     MoveableItem.selectedBucket = [];
     LayoutSection.currentSelectedObj = null;
     MoveableItem.currentSelectedObj = null;
     CrtLayoutElement.mouseDown = false;
     CrtLayoutElement.dragMove = false;
     CrtLayoutElement.CSS_CLASS_SELECTED_SECTION = 'sectionSelected';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION = 'layoutSecHeaderLeft';
     CrtLayoutElement.CSS_CLASS_SELECTED_ITEM = 'itemSelected';
     CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR_HIGHLIGHT = 'sepCellHighlight';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR_HIGHLIGHT = 'sepSectionHighlight';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR = 'sepSection';
     LayoutItemSeparator.highlightSep = null;
     LayoutSection.NEW_SECTION_ID_PREFIX = "newSectionId";
     LayoutSection.NEW_SECTION_SEP_ID_PREFIX = "newSectionSepId";
     LayoutSection.sectionIdInterator = 0;
     CrtLayoutElement.FIELD_SEP = '$';
     CrtLayoutElement.COL_SEP = '|';
     CrtLayoutElement.DIV_SEP = '_';
     CrtLayoutElement.sectionNameIdMap = {};
     CrtLayoutElement.initialStateColIdMap = null;
     CrtLayoutElement.lookupItemPosMap = {};
     CrtLayoutElement.currentDisplayedSec = null;
     CrtLayoutElement.NUM_ROWS_PER_AVAILABLE_SECTION = 8;
     CrtLayoutElement.disableButtons = false;
     CrtLayoutElement.HOVER_TIME_OUT = 1000;
     CrtLayoutElement.availableSectionPosInited = false;
     CrtLayoutElement.availableSectionInitPosY = 0;
     CrtLayoutElement.sectionsToReformat = {};

     LayoutItem.prototype.createNewCellId = function() {
        return this.sectionId + 'r'+this.rowPos+'c'+(this.colPos+1);
     }

     LayoutItemSeparator.prototype.createNewCellId = function() {
        return 'rp_'+this.sectionId + 'r'+this.rowPos+'c'+(this.colPos+1);
     }

     CrtLayoutElement.init = function() {
         document.onmousemove = function(evt) {CrtLayoutElement.handleMouseMove(evt)};
         document.onmouseup = function(evt) {CrtLayoutElement.handleMouseUp(evt)};
         window.onscroll = function(evt) {CrtLayoutElement.scrollAvailableSection(evt)};
         sfdcPage.appendToOnloadQueue(CrtLayoutElement.onLoad,"onLoad Scripts for the CrtLayout Page");
     }

     CrtLayoutElement.onLoad = function() {
        setTimeout('CrtLayoutElement.initLoad()',10);
     }

     CrtLayoutElement.handleMouseOver = function() {

     }

    CrtLayoutElement.openPropertiesEdit = function(evt) {
        if (!MoveableItem.currentSelectedObj) {
            alert(LC.getLabel("CrtLayout","mustSelectField"));
            return;
        }
        if (MoveableItem.currentSelectedObj.isSection) {
            CrtLayoutElement.openSectionPopup(evt,MoveableItem.currentSelectedObj.fieldObj.sectionId);
            return;
        }

        evt = getEvent(evt);
        setLastMousePosition(evt);


        var url = MoveableItem.currentSelectedObj.inLayout ? CrtLayoutElement.CRT_FIELD_EDIT_URL : "";
        var h = (MoveableItem.selectedBucket.length > 2) ? 400 : 200;
        openPopup(url, 'sectionEdit', 450, h, 'width=450,height='+h+',scrollbars=yes,toolbar=no,status=no,directories=no,menubar=no,resizable=yes', true);
        return false;

    }

     CrtLayoutElement.swapAvailableType = function(sel,fromPageNum,toPageNum) {
        if (CrtLayoutElement.currentDisplayedSec) {
            CrtLayoutElement.currentDisplayedSec.swapFromPage(fromPageNum);
        }
        var secId = sel.options[sel.selectedIndex].value;
        CrtLayoutElement.availableSections[secId].swapToPage(toPageNum);
     }

    CrtLayoutElement.getPrimObjMetaMap = function() {
        return CrtLookups.primaryObjects;
    }

    CrtLayoutElement.getLookupIdFromPrimObjId = function(primaryObjId) {
        return primaryObjId+'_'+LookupsUi.LOOKUPS;
    }

    CrtLayoutElement.setLookupItemPostion = function(fieldValue, fieldObj) {
        if (CrtLayoutElement.lookupItemPosMap == null) {
            CrtLayoutElement.lookupItemPosMap = {};
        }
        CrtLayoutElement.lookupItemPosMap[fieldValue] = fieldObj;
    }

    CrtLayoutElement.clearTextSelection = function(){
        if (isIE) {
            document.selection.empty();
        } else {
          if (window.getSelection().removeAllRanges) {
              window.getSelection().removeAllRanges();
          }
        }
    }

    CrtLayoutElement.deleteSection = function(sectionId) {
        var section = CrtLayoutElement.layoutSections[sectionId];
        if (!section.isEmpty && !window.confirm(LC.getLabel("LayoutDND", "confirmDeleteSectionPrompt") + '\n\n' + LC.getLabel("Global", "are_you_sure"))) {
            return;
        }

        section.remove();

        CrtLayoutElement.layoutSections[sectionId].numFields = 0;
        CrtLayoutElement.checkDisableSave();
        //delete
        delete CrtLayoutElement.layoutSections[sectionId];
        //this name no longer exists for lookup fields
        delete CrtLayoutElement.sectionNameIdMap[section.labelName];

    }

    CrtLayoutElement.createNewSection = function(sectionName, evt) {
        if (sectionName) {
            var sec = initSectionTable(null,null, null, 'H', sectionName);
            sec.reformatSection();
            sec.attachItemEvents();
            return sec;
        }
    }

    CrtLayoutElement.openSectionPopup = function(evt,sectionId) {
        var url = CrtLayoutElement.CRT_SECTION_EDIT_URL;
        if (sectionId) {
          url += '?sectionId=' + sectionId;
        }
        evt = getEvent(evt);
        setLastMousePosition(evt);
        openPopup(url, 'sectionEdit', 450, 245, 'width=450,height=245,scrollbars=yes,toolbar=no,status=no,directories=no,menubar=no,resizable=yes', true);
    }

    CrtLayoutElement.handleMouseUp = function(evt) {
        if (CrtLayoutElement.dragMove) {
            document.getElementById('dragDummy').style.visibility = 'hidden';
             //Shouldn't be handling mouseup here but on the element itself but that seems broken (broken on FIREFOX) - for now...so handle it here
            CrtLayoutElement.handleSelectedItems();
            MoveableItem.clearSelectedItems();
            CrtLayoutElement.clearHighlights();
            CrtLayoutElement.dragMove = false;
        }
        CrtLayoutElement.mouseDown = false;
     }

     CrtLayoutElement.clearHighlights = function() {
        if (CrtLayoutElement.highlightAvailSection) {
            CrtLayoutElement.highlightAvailSection.handleMouseUp(null);

        }
        if (CrtLayoutElement.highlightSec) {
            CrtLayoutElement.highlightSec.setHighlighted(false);
        }
        if (LayoutItemSeparator.highlightSep) {
            LayoutItemSeparator.highlightSep.setHighlighted(false);
        }
     }

     CrtLayoutElement.handleMouseMove = function(evt) {
        var evt = getEvent(evt);
        if (MoveableItem.currentSelectedObj && CrtLayoutElement.mouseDown) {
            CrtLayoutElement.dragMove = true;
            CrtLayoutElement.clearTextSelection();
            var scrollX = getScrollX();
            var scrollY = getScrollY();
            var dragDummy = document.getElementById('dragDummy');
            var dragDummyValue = document.getElementById('dragDummyValue');
            dragDummy.style.visibility = 'visible';
            if (MoveableItem.currentSelectedObj.isSection) {
                dragDummyValue.innerHTML =  MoveableItem.selectedBucket.length > 1 ? LC.getLabel("CrtLayout","dragMultiSelect") : MoveableItem.currentSelectedObj.fieldName;
            } else {
                dragDummyValue.innerHTML = MoveableItem.selectedBucket.length > 1 ? LC.getLabel("CrtLayout","dragMultiSelect") : MoveableItem.currentSelectedObj.fieldName;
            }

            var parentX = 0;
            var parentY = 0;
            if (dragDummy.offsetParent) {
               var dummyParent = dragDummy.offsetParent;
               parentX = getObjX(dummyParent);
               parentY = getObjY(dummyParent);
            }
            dragDummy.style.left = (getMouseX(evt) - parentX) + "px";
            dragDummy.style.top = (getMouseY(evt) - parentY) + "px";
            var currentX = getObjX(dragDummy) - scrollX;
            var theWidth = 500;
            if (document.documentElement && document.documentElement.clientWidth)
                theWidth = document.documentElement.clientWidth;
            else if (document.body) {
                theWidth = document.body.clientWidth;
                if (currentX > theWidth) {
                    if (isIE) document.body.scrollLeft = document.body.scrollLeft + 10;
                    //else window.scroll(10, 0);
                } else if (currentX < 0) {
                    if (isIE) document.body.scrollLeft = document.body.scrollLeft - 10;
                    //else window.scroll(-10, 0);
                }
            }
            else {

            }
            var currentY = getObjY(dragDummy) - scrollY;
            var theHeight = 500;
            if (document.documentElement && document.documentElement.clientHeight)
                theHeight = document.documentElement.clientHeight;
            else if (document.body) {}
                theHeight = document.body.clientHeight;
                if (currentY > theHeight - 50) {
                    //if (isIE) document.documentElement.scrollTop = document.body.scrollTop + 50;
                    window.scrollBy(0, 50);
                } else if (currentY < 50) {
                    // if (isIE) document.documentElement.scrollTop = document.body.scrollTop - 50;
                    window.scrollBy(0, -50);
                }
            }
            else {
            }
     }

     function initSectionTable(sectionId,sectionHeaderId, sectionTableId, sortOrder, masterLabel) {
         var section = new LayoutSection(sectionId,sectionHeaderId, sectionTableId, sortOrder,masterLabel);
         CrtLayoutElement.layoutSections[section.sectionId] = section;
         //position map to keep track of the positions of the layout sections
         CrtLayoutElement.layoutSecPos.push(section.sectionId);

        //some section name handling
        //for now handle section names so that we place the lookups in the appropriate buckets
        CrtLayoutElement.sectionNameIdMap[masterLabel] = section;
        return section;
     }

     //init the innerHTML on constructing a new table;
     LayoutSection.prototype.initSectionInnerHtml = function() {
        var secDiv = document.createElement("DIV");
        var innerHTML = '';
        secDiv.id = this.sectionId;
        secDiv.className = "layoutSection";
        innerHTML += '<div class="layoutSecHeader"><table  border="0" cellpadding="0" cellspacing="0"><tr><td class="layoutSecHeaderLeft" ';
        innerHTML += 'id="' + this.sectionHeaderId  +'">' + this.labelName + '</td><td class="layoutSecHeaderLink">';
        innerHTML += '<span class="sectionHeadLink" onclick="CrtLayoutElement.openSectionPopup(event,\'' + this.sectionId + '\');">'+LC.getLabel("CrtLayout","sectionEdit")+'</span>';
        innerHTML += '&nbsp;|&nbsp;<span class="sectionHeadLink" onclick="CrtLayoutElement.deleteSection(\'' + this.sectionId + '\');">'+LC.getLabel("CrtLayout","sectionDelete")+'</span></td></table></div>';
        innerHTML += '<div><table id="' + this.sectionTableId + '"class="layoutSectionTable">';
        innerHTML += '</table></div>';
        secDiv.innerHTML = innerHTML;
        return secDiv;
     }

     //init the innerHTML for a new table separator
     LayoutSection.prototype.initSectionSepInnerHtml = function() {
        var sepDiv = document.createElement("DIV");
        sepDiv.id = this.getSectionSepId();
        sepDiv.className = "sepSection";
        return sepDiv;
     }

     LayoutSection.prototype.createSectionId = function() {
        return LayoutSection.NEW_SECTION_ID_PREFIX + '_' + LayoutSection.sectionIdInterator++;
     }

     LayoutSection.prototype.getSectionTableId = function() {
        return this.sectionId + "_layoutItemSection";
     }

     LayoutSection.prototype.getSectionHeaderId = function() {
         return "sec_" + this.sectionId;
     }

     LayoutSection.prototype.getLastSectionSepId = function() {
        return CrtLayoutElement.SECTION_SEP_DIV_PREFIX +CrtLayoutElement.LAST_SEC_SEP_DIV;
     }


     function LayoutSection(sectionId,sectionHeaderId, sectionTableId, sortOrder, masterLabel) {
         this.labelName = masterLabel;
         if (sectionId == null) {
             this.sectionId = this.createSectionId();
             this.sectionHeaderId = this.getSectionHeaderId();
             this.sectionTableId = this.getSectionTableId();
             var parentNode = document.getElementById("mainTableDiv");
             var lastSecSep = document.getElementById(this.getLastSectionSepId());
             var sepDiv = this.initSectionSepInnerHtml();
             parentNode.insertBefore(sepDiv,lastSecSep);
             parentNode.insertBefore(this.initSectionInnerHtml(),lastSecSep);
             new LayoutSectionSeparator(sepDiv.id, this.sectionId);
             this.sectionValue = "";
             this.attachEvents();
         } else {
             this.sectionId = sectionId;
             this.sectionHeaderId = sectionHeaderId;
             this.sectionTableId = sectionTableId;
             this.sectionValue = sectionId;
         }

         this.sortOrder = sortOrder;
         this.isSelected = false;
         this.numCols = CrtLayoutElement.NUM_LAYOUT_COLS;
         this.numRows = 0;
         this.layoutItems = [];
         //only here to keep the separator objects alive
         this.layoutSeparators = [];
         this.fieldsMap = {};
         this.isEmpty = true;
     }

    //move cell -- or more precisely move contents of fromField to the contents of toField
    LayoutSection.prototype.moveCell = function(toField,fromField) {
            toField.sectionId = this.sectionId;
            toField.customName = fromField.customName;
            toField.displayName = fromField.displayName;
            toField.fieldName = fromField.fieldName;
            toField.fieldId = fromField.fieldId;
            toField.isEmpty = fromField.isEmpty;
            toField.type = fromField.type;
            toField.isLookup = fromField.isLookup;
            toField.defaultChecked = fromField.defaultChecked;
            fromField.isEmpty = true;
    }

    LayoutSection.prototype.insertCell = function(toField,moveableItem) {
        toField.fieldName = moveableItem.fieldName;
        toField.displayName = moveableItem.displayName;
        toField.customName = moveableItem.customName;
        toField.type = moveableItem.type;
        toField.fieldId = moveableItem.itemId;
        toField.isLookup = moveableItem.isLookup;
        toField.defaultChecked = moveableItem.defaultChecked;
        toField.isEmpty = false;
    }

    LayoutItem.prototype.setCellToEmpty = function() {
        this.itemElem.innerHTML = '';
    }


     //insert a table row in the html for this layout section
     //update internal object references
     LayoutSection.prototype.insertSectionRow = function() {
        var tableElem = document.getElementById(this.sectionTableId);
        var row = tableElem.insertRow(-1);
        var numRows = this.numRows;
        for (var i=0; i<this.numCols; i++) {
            setSeparatorAttributes(this.sectionId,null,numRows,i,row);
            setEmptyFieldAttributes(this.sectionId,null,numRows,i,row);
        }
     }

    //delete an extra empty row in a section
    LayoutSection.prototype.deleteSectionRow = function() {
        var tableElem = document.getElementById(this.sectionTableId);
        tableElem.deleteRow(-1);
        this.layoutItems.splice(this.numRows-1,1);
        this.layoutSeparators.splice(this.numRows-1,1);
        this.numRows--;
    }

    //reformat section after putting in cells from selected bucket
    //alignment is from left to right; cells automatically align as far left on their row as possible
    //@ param isLoad specifies whether we are calling this on loading the page or not -- if we are loading, we don't do most of the formatting for speed
    LayoutSection.prototype.reformatSection = function(isLoad) {
        var columnSize = this.numCols;
        var pos =0;
        var lastEmpty= -1; //assume non cells Empty at start
        var row, col;
        for (var lastEmpty = -1, pos = 0; Math.floor(pos / columnSize) < this.numRows; pos++) {
            row = Math.floor(pos / columnSize);
            col = (pos % columnSize);
            //if we see a nonEmptyCell, copy it over
            if (!this.layoutItems[row][col].isEmpty) {
                 if (lastEmpty == -1) {
                     continue;
                 }
                 this.moveCell(this.layoutItems[Math.floor(lastEmpty/columnSize)][lastEmpty%columnSize],
                             this.layoutItems[row][col]);

                 //move lastEmptyPosition
                 lastEmpty++;
            }
            else {
                if (lastEmpty == -1) {
                    lastEmpty = pos;
                }
            }
        }

        var lastNonEmpty = lastEmpty-1;
        this.isEmpty = true;

        if (lastEmpty >= 0 && (pos-columnSize) > lastNonEmpty) {
            var emptyRows = Math.floor((pos-1-lastNonEmpty)/columnSize);
            //if we have more than one empty row, delete the extras
            while (emptyRows > 1) {
               this.deleteSectionRow();
               emptyRows--;
            }
        }
        else {
            //else we have no empty rows, so add one here
            this.insertSectionRow();
        }
        this.numFields = 0;

        //set cell style
        for (var j = 0; j < this.numRows; j++) {
            for (var k = 0; k < this.numCols; k++) {
                var field = this.layoutItems[j][k];
                this.fieldsMap[field.itemId] = field;
                var sep = this.layoutSeparators[j][k];
                if (!isLoad) {
                    sep.setHighlighted(false);
                }
                if (!isLoad || field.isEmpty) {
                    field.formatField();
                }
                if (!field.isEmpty) {
                    this.isEmpty = false;
                    this.numFields++;
                    //set lookup positioning
                    if (field.isLookup) {
                        CrtLayoutElement.setLookupItemPostion(field.fieldId,field);
                    }
                }

            }
        }

        //attach the the event handlers that would handle the events on the LayoutItems
        if (isLoad) {
            this.attachItemEvents();
        }
    }

    //theorically it will make more sense to attach event handlers to the individual field element themselves
    //however setting all the event handlers on each of the fields would take too long on a page with many fields
    //thus we attach events to the parent element and then delegate to the appropriate event handler during events
    LayoutSection.prototype.attachItemEvents = function() {
         var self = this;
         var tableElem = document.getElementById(self.sectionTableId);
         addEvent(tableElem, 'click', function(evt) {self.handleItemMouseClick(evt);}, false);
         addEvent(tableElem, 'mousedown', function(evt) {self.handleItemMouseDown(evt);}, false);
         addEvent(tableElem, 'mouseover', function(evt) {self.handleItemMouseOver(evt);}, false);
         addEvent(tableElem, 'dblclick', function(evt) {self.handleItemMouseDblClick(evt);}, false);
         addEvent(tableElem, 'mouseout', function(evt) {self.handleItemMouseOut(evt);}, false);
    }

    LayoutSection.prototype.handleItemMouseClick = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseClick(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseDown = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseDown(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseOver = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseOver(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseDblClick = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseDblClick(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseOut = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseOut(evt);
        }
    }

    CrtLayoutElement.disableLayoutButtons = function(disableButton) {
        if (disableButton) {
            //if there are empty sections, disable both save and preview layout buttons
            for (var i=0; i<2; i++) {
                if (document.getElementsByName("saveAndCloseButton")[i]) {
                    document.getElementsByName("saveAndCloseButton")[i].className = 'btnDisabled';
                    document.getElementsByName("saveAndCloseButton")[i].disabled = true;
                    document.getElementsByName("previewButton")[i].className = 'btnDisabled';
                    document.getElementsByName("previewButton")[i].disabled = true;
                    CrtLayoutElement.disableButtons = true;
                }
            }
        }
        else {
        //else, enable buttons
           for (var i=0; i<2; i++) {
              if (document.getElementsByName("saveAndCloseButton")[i]) {
                  document.getElementsByName("saveAndCloseButton")[i].className = 'btn';
                  document.getElementsByName("saveAndCloseButton")[i].disabled = false;
                  document.getElementsByName("previewButton")[i].className = 'btn';
                  document.getElementsByName("previewButton")[i].disabled = false;
                  CrtLayoutElement.disableButtons = false;
              }
          }
        }
    }

    LayoutItem.prototype.handleMoved = function() {
        this.isEmpty = true;
        //reformat any sections as needed
        CrtLayoutElement.sectionsToReformat[this.sectionId] = CrtLayoutElement.getLayoutSection(this.sectionId);
    }

    /*move the cells around the layout
     *param rowPos, colPos specifies position to move these cells to
     */
     LayoutSection.prototype.moveCells = function(rowPos, colPos) {
         //first set the old positions to empty for all the cells being moved
         for (var i=0; i < MoveableItem.selectedBucket.length; i++) {
              MoveableItem.selectedBucket[i].fieldObj.handleMoved();
         }

        var shiftSize = MoveableItem.selectedBucket.length;
        var columnSize = this.numCols;
        //leftmost cell that needs to be moved
        var start = rowPos * columnSize + colPos;

        //rightmost element
        var lastElement = this.numRows * columnSize - 1;
        var lastNonEmptyPos = lastElement;
        if (!this.isEmpty) {
            while (lastNonEmptyPos >= 0 && this.layoutItems[Math.floor(lastNonEmptyPos/columnSize)][lastNonEmptyPos%columnSize].isEmpty) {
                lastNonEmptyPos--;
            }
        } else {
            lastNonEmptyPos = -1;
        }

        //farthest element that can be shifted but still be kept on screen
        var end = lastElement - shiftSize;

        //if we are moving to the very end, then we should just move it right after the lastNonEmptyPos if possible
        start = Math.min(start,lastNonEmptyPos+1);

       //if there are elements that we can't keep on the screen, we might have to increase the row size
       if (lastNonEmptyPos > end) {
            var moreRows = Math.ceil((lastNonEmptyPos + shiftSize - lastElement)/columnSize);
            while (moreRows > 0) {
                this.insertSectionRow();
                moreRows--;
            }
       }

       //shift all elements to the right one by one, starting from the rightmost until we reach the leftmost cell to be moved
       while (lastNonEmptyPos >= start) {
               this.moveCell(this.layoutItems[Math.floor((lastNonEmptyPos+shiftSize)/columnSize)][(lastNonEmptyPos+shiftSize)%columnSize],
                          this.layoutItems[Math.floor(lastNonEmptyPos/columnSize)][lastNonEmptyPos%columnSize]);
              lastNonEmptyPos--;
       }

       //now move all selected cells into vacated spot
       //starting from leftmost moving right
       for (var i =0 ; i < MoveableItem.selectedBucket.length; i++) {
              var selItem = MoveableItem.selectedBucket[i];
              this.insertCell(this.layoutItems[Math.floor((start+i)/columnSize)][(start+i)%columnSize],
                        selItem);
       }
        CrtLayoutElement.sectionsToReformat[this.sectionId] = this;
        CrtLayoutElement.reformatSections();
    }

    CrtLayoutElement.reformatSections = function() {
        for (var sId in CrtLayoutElement.sectionsToReformat) {
            CrtLayoutElement.sectionsToReformat[sId].reformatSection();
        }
        CrtLayoutElement.sectionsToReformat = {};

        CrtLayoutElement.checkDisableSave();

    }

    CrtLayoutElement.checkDisableSave = function() {

        var totalFields = 0;
        for (var sId in CrtLayoutElement.layoutSections) {
            totalFields += CrtLayoutElement.layoutSections[sId].numFields;
        }

        //check for fields limits
        var counter = document.getElementById('fieldsCounterInner');
        var counter2 = document.getElementById('fieldsCounterInner2');
        counter.innerHTML = totalFields;
        counter2.innerHTML = totalFields;
        if (totalFields > CrtLayoutElement.LAYOUT_FIELDS_LIMIT) {
            counter.style.color = '#CC0000';
            counter2.style.color = '#CC0000';
            if (document.getElementById('fieldsLimitError').style.display == 'none') {
                alert(LC.getLabel("CrtLayout","fieldsLimitErrorMsg",CrtLayoutElement.LAYOUT_FIELDS_LIMIT));

                //there's something weird with the order these statements are being run -- hide the dragDummy again because this alert clears the execution of the prior hiding of this dragDummy
                document.getElementById('dragDummy').style.visibility = 'hidden';
            }
            document.getElementById('fieldsLimitError').style.display = 'block';
            document.getElementById('fieldsLimitError2').style.display = 'block';
            CrtLayoutElement.disableLayoutButtons(true);
        } else {
            counter.style.color = 'green';
            counter2.style.color = 'green';
            document.getElementById('fieldsLimitError').style.display = 'none';
            document.getElementById('fieldsLimitError2').style.display = 'none';

            //if all fields are empty then we also disable the layout buttons
            if (totalFields > 0) {
                CrtLayoutElement.disableLayoutButtons(false);
            } else {
                CrtLayoutElement.disableLayoutButtons(true);
            }
        }
    }

    CrtLayoutElement.handleSelectedItems = function() {
        if (CrtLayoutElement.highlightSec) {
            CrtLayoutElement.moveSections();
        }
        else if (CrtLayoutElement.highlightAvailSection) {
            CrtLayoutElement.highlightAvailSection.moveCells();
        }
        else if (LayoutItemSeparator.highlightSep) {
            var itemSep = LayoutItemSeparator.highlightSep;
            CrtLayoutElement.getLayoutSection(itemSep.sectionId).moveCells(itemSep.rowPos, itemSep.colPos);
        } else {
        }
   }

   //move layout sections around in drag and drop
   CrtLayoutElement.moveSections = function() {
        //find the highlighted sec separator and insert all selected sections after this separator
        //find the of the section position we are inserting before
        var moveSecPos;
        var highlightSec = CrtLayoutElement.highlightSec;

        var moveToSep = document.getElementById(highlightSec.divId);
        var parentNode = document.getElementById(highlightSec.divId).parentNode;
        for (var i=0; i < MoveableItem.selectedBucket.length; i++) {
            if (MoveableItem.selectedBucket[i].isSection) {
                var sectionObj = MoveableItem.selectedBucket[i].fieldObj;
                var secDiv = document.getElementById(sectionObj.sectionId);
                var sepDivId = sectionObj.getSectionSepId();
                var sepDiv = document.getElementById(sepDivId);
                //insert both the section Div and the sep div that separates it from the next section
                parentNode.insertBefore(sepDiv,moveToSep);
                parentNode.insertBefore(secDiv,moveToSep);

                //remove the section
                for (var k=0; k<CrtLayoutElement.layoutSecPos.length;k++) {
                    if (sectionObj.sectionId == CrtLayoutElement.layoutSecPos[k]) {
                        CrtLayoutElement.layoutSecPos.splice(k,1);
                        break;
                    }
                }
            }
        }

        if (highlightSec.sectionId != CrtLayoutElement.LAST_SEC_SEP_DIV) {
            for (moveSecPos=0; moveSecPos<CrtLayoutElement.layoutSecPos.length; moveSecPos++) {
                if (highlightSec.sectionId == CrtLayoutElement.layoutSecPos[moveSecPos]) {
                    break;
                }
            }
        } else {
            //if we are inserting before the last section separator, we are inserting at the end
            moveSecPos = -1;
        }

        //insert the section into its new position
        for (var l=0; l<MoveableItem.selectedBucket.length; l++) {
            if (MoveableItem.selectedBucket[l].isSection) {
                //insert at the end
                if (moveSecPos < 0) {
                   CrtLayoutElement.layoutSecPos.push(MoveableItem.selectedBucket[l].fieldObj.sectionId);
                } else {
                   CrtLayoutElement.layoutSecPos.splice(moveSecPos,0,MoveableItem.selectedBucket[l].fieldObj.sectionId);
                }
            }
        }

   }


    LayoutSection.prototype.getSectionSepId = function() {
        return CrtLayoutElement.SECTION_SEP_DIV_PREFIX + this.sectionId;
    }


     LayoutSection.prototype.insertSepItemRow = function(itemObj){
        this.layoutSeparators[itemObj.rowPos] = [];
        if (itemObj.rowPos == this.numRows) {
            this.numRows++;
        }
     }

     LayoutSection.prototype.insertSeparatorCell = function(itemObj) {
         if (!this.layoutSeparators[itemObj.rowPos]) {
             this.insertSepItemRow(itemObj);
         }
         this.layoutSeparators[itemObj.rowPos][itemObj.colPos] = itemObj;
     }

     LayoutSection.prototype.insertItemRow = function(itemObj){
        this.layoutItems[itemObj.rowPos] = [];
        if (itemObj.rowPos == this.numRows) {
            this.numRows++;
        }
     }

     LayoutSection.prototype.insertField = function(itemObj) {
         if (!this.layoutItems[itemObj.rowPos]) {
             this.insertItemRow(itemObj);
         }
         this.layoutItems[itemObj.rowPos][itemObj.colPos] = itemObj;
     }

     LayoutSection.prototype.attachEvents = function() {
         var self = this;
         var tableElem = document.getElementById(self.sectionHeaderId);
         addEvent(tableElem, 'click', function(evt) {self.handleMouseClick(evt);}, false);
         addEvent(tableElem, 'mousedown', function(evt) {self.handleMouseDown(evt);}, false);
         addEvent(tableElem, 'mouseover', function(evt) {self.handleMouseOver(evt);}, false);
         addEvent(tableElem, 'dblclick', function(evt) {self.handleMouseDblClick(evt);}, false);
         addEvent(tableElem, 'mouseout', function(evt) {self.handleMouseOut(evt);}, false);
     }

     LayoutSection.prototype.handleMouseClick = function(evt) {
        var evt= getEvent(evt);
        if (evt.ctrlKey) {
            this.toggleSelected(true);
        } else {

        }
     }

     LayoutSection.prototype.handleMouseDblClick = function(evt) {
         CrtLayoutElement.openPropertiesEdit(evt);
     }

    LayoutSection.getSection = function(rowNum,colNum) {
        return LayoutSection.sections[rowNum][colNum];
    }

     LayoutSection.prototype.handleMouseUp = function(evt) {


     }

     LayoutSection.prototype.handleMouseDown = function(evt) {
       var evt = getEvent(evt);
       if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
            this.toggleSelected(false);
       }
       CrtLayoutElement.mouseDown = true;
    }

    LayoutSection.prototype.handleMouseOut = function(evt) {
        document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
        clearTimeout(this.timeOut);
        this.mousingOver = false;
    }


    LayoutSection.prototype.handleMouseOver = function(evt) {
        var evt = getEvent(evt);
        this.posX = getMouseX(evt);
        this.posY = getMouseY(evt);
        if (!CrtLayoutElement.dragMove && !this.mousingOver) {
            var self = this;
            this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
            this.mousingOver = true;
        }

    }

    LayoutSection.prototype.setupMouseOverDiv = function(evt) {
        var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
        var html = '';
        var posx = this.posX+10;
        var posy = this.posY-60;
        html += '<div class="mouseOverHeader">'+ this.labelName + '</div>';
        html += '<div class="mouseOverBody">' + LC.getLabel("CrtLayout","layoutSecHover");
        html += '</div>';
        moElem.innerHTML = html;

        moElem.style.left = posx+"px";
        moElem.style.top = posy+"px";
        moElem.style.display = 'block';
        return moElem;
    }

LayoutSection.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
}

LayoutSection.prototype.createMoveableItem = function() {
    return new MoveableItem(this.sectionId, this.labelName, this.labelName, this.labelName, 'SECTION', this, true, true, false, false);
}

LayoutSection.prototype.removeSelection = function(noBucketRemove) {
    if (!noBucketRemove && this.moveableItem) {
        this.moveableItem.removeSelection();
    }
    this.moveableItem = null;
    this.removeSelectionFormatting();
}

LayoutSection.prototype.remove = function() {
    this.removeSelection();

    for (var j = 0; j < this.numRows; j++) {
        for (var k = 0; k < this.numCols; k++) {
            var field = this.layoutItems[j][k];
                if (!field.isEmpty) {
                    field.addSelection();
                }
        }
    }

    //move all the fields back
    if (CrtLayoutElement.currentDisplayedSec) {
        CrtLayoutElement.currentDisplayedSec.moveCells();
    }

    MoveableItem.clearSelectedItems();
    this.isEmpty = true;

    //reorder sections
    for (var i=0; i<CrtLayoutElement.layoutSecPos.length;i++) {
        if (this.sectionId == CrtLayoutElement.layoutSecPos[i]) {
            CrtLayoutElement.layoutSecPos.splice(i,1);
            break;
        }
    }

    //remove the element
    var parentNode = document.getElementById(this.sectionId).parentNode;
    parentNode.removeChild(document.getElementById(this.sectionId));
    //remove the section separator
    parentNode.removeChild(document.getElementById(this.getSectionSepId()));

}


LayoutSection.prototype.addSelection = function() {
    var addSelection;
    this.moveableItem = this.createMoveableItem();
    addSelection = this.moveableItem.addSelection();
    //are we mixing the selection Bucket?
    if (addSelection) {
        this.addSelectionFormatting();
    }
}

LayoutSection.prototype.removeSelectionFormatting = function() {
    this.isSelected = false;
    this.render();

}

LayoutSection.prototype.addSelectionFormatting = function() {
    this.isSelected = true;
    this.render();
}

LayoutSection.prototype.render = function() {
    var headerElem = document.getElementById(this.sectionHeaderId);
    headerElem.innerHTML = this.labelName;
    headerElem.className = CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION;
    if (this.isSelected) {
        headerElem.className += ' '+CrtLayoutElement.CSS_CLASS_SELECTED_SECTION;
    }
}



     function setFieldAttributes(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, defaultChecked) {
        var item = new LayoutItem(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, false, null, defaultChecked);
        item.insertField();
     }

     function setEmptyFieldAttributes(sectionId,elementId,rowPos,colPos,rowObj) {
        new LayoutItem(sectionId,elementId,null,null,null,null,null,rowPos,colPos,true,false, true, rowObj,false).insertField();
     }


    function LayoutItem(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, isEmpty, rowObj, defaultChecked) {
         this.sectionId = sectionId;
         this.rowPos = rowPos;
         this.colPos = colPos;
         if (elementId == null && fieldId == null) {
             this.itemElem  = rowObj.insertCell(rowObj.cells.length);
             this.itemId = this.createNewCellId();
             this.itemElem.id = this.itemId;
         }
         else {
             this.itemId = elementId;
         }

         this.isEmpty = isEmpty;
         this.fieldId = fieldId;
         this.customName = customName;
         this.fieldName = escapeHTML(fieldName);

         this.isSelected = false;

         this.type = type;
         this.inLayout = inLayout;
         this.isLookup = isLookup;
         this.defaultChecked = defaultChecked;

         //this takes too long to set for lookup fields -- set it when we actually hover
         this.displayName = this.isLookup ? null : displayName;
    }


    LayoutItem.prototype.setupMouseOverDiv = function(evt) {
        var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
        var html = '';
        var posx = this.posX+10;
        var posy = this.posY-60;
        html += '<div class="mouseOverHeader">'+ this.fieldName + (this.isLookup ? ' ' + LC.getLabel("CRTLookupLayer","viaLookupParen") : '') + '</div>';
        if (!this.displayName) {
            this.displayName = CrtLayoutElement.getDisplayPath(this.fieldId,true);
        }
        html += '<div class="mouseOverBody">' + LC.getLabel("CrtLayout","CustomLabel") + ': '+ (this.customName ? this.customName : this.displayName) + '<br>';
        html += LC.getLabel("CrtLayout","defaultState") +' ';
        if (this.defaultChecked) {
              html += LC.getLabel("CrtLayout","checked");
        } else {
            html += LC.getLabel("CrtLayout","unchecked");
        }
        html += ' <br> ';
        html += LC.getLabel("CrtLayout","sourceObject") + ' ';
        //get source object
        var primObjId = this.isLookup ? CrtLayoutElement.getPrimObjId(this.fieldId,'.') : CrtLayoutElement.getPrimObjId(this.fieldId,CrtLayoutElement.FIELD_SEP);
        var sourceObject = CrtLayoutElement.getPrimObjMetaMap()[primObjId].label;
        if (this.isLookup) {
            html += CrtLayoutElement.getLookupFieldFromPath(CrtLayoutElement.getPath(this.fieldId)).lookupLabel + '<br>(' +LC.getLabel("CrtLayout","associatedWith")+' ' + sourceObject +')';
        } else {
            html += sourceObject;
        }
        html += '<br>';
        if (this.isLookup) {
            html += '<br>';
            html += LC.getLabel("CrtLayout","lookupPath") + ' ' + CrtLayoutElement.getDisplayPath(this.fieldId,false);
            html += '<br>';
        }
        moElem.innerHTML = html;

        moElem.style.left = posx+"px";
        moElem.style.top = posy+"px";
        moElem.style.display = 'block';
        return moElem;
    }

    function MoveableItem(itemId, fieldName, displayName, customName, type, fieldObj, inLayout, isSection, isLookup, defaultChecked) {
        this.itemId = itemId;
        this.fieldName = fieldName;
        this.displayName = displayName;
        this.customName = customName;
        this.type = type;
        this.fieldObj = fieldObj;
        this.inLayout = inLayout;
        this.isSection = isSection;
        this.isLookup = isLookup;
        this.defaultChecked = defaultChecked;
    }

    //insert a field into the Layout Section Object
    LayoutItem.prototype.insertField = function() {
        CrtLayoutElement.layoutSections[this.sectionId].insertField(this);
    }

    //format a field - set background color
    LayoutItem.prototype.formatField = function() {
        if (!this.itemElem) {
            this.itemElem = document.getElementById(this.itemId);
        }
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_CELL;
        if (!this.isEmpty) {
             className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM;
             if (this.isSelected) {
                className += ' ' + CrtLayoutElement.CSS_CLASS_SELECTED_ITEM;
             }
             var innerHTML = '';
             var formattedName = this.formatName(this.fieldName);
             if (this.defaultChecked) {
                 innerHTML += CrtLayoutElement.DFLT_CHECKED_ICON_URL;
             }
             if (this.isLookup) {
                innerHTML += CrtLayoutElement.LOOKUP_ICON_URL;
            }
            if (innerHTML != '') {
                innerHTML += ('&nbsp;' + formattedName);
            } else {
                innerHTML = formattedName;
            }
            this.itemElem.innerHTML = innerHTML;
        } else {
            this.setCellToEmpty();
        }
        this.itemElem.className = className;
    }

    LayoutItem.prototype.formatName = function(fieldName) {
        if (!fieldName) {
            return '';
        }
        //truncate more characters if we have the other icons on the tiles also
        var maxLength = CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH - (this.defaultChecked ? 3 : 0) - (this.isLookup ? 2 : 0);

        if (fieldName.length > maxLength) {
            return fieldName.substring(0,maxLength-2)+"...";
        }
        else {
            return fieldName;
        }
    }

    LayoutItem.prototype.handleMouseOut = function() {
        if (this.isEmpty) {
            return;
        }
        document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
        clearTimeout(this.timeOut);
        this.mousingOver = false;
    }

    LayoutItem.prototype.handleMouseDown = function(evt) {
       if (this.isEmpty) {
           return;
       }
       var evt = getEvent(evt);
       if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
            this.toggleSelected(false);
       }
       CrtLayoutElement.mouseDown = true;
    }

    LayoutItem.prototype.handleMouseOver = function(evt) {
        var evt = getEvent(evt);
        this.posX = getMouseX(evt);
        this.posY = getMouseY(evt);
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && !MoveableItem.currentSelectedObj.isSection) {
           var sectionObj = CrtLayoutElement.getLayoutSection(this.sectionId);
           CrtLayoutElement.clearHighlights();
           var sepObj = sectionObj.layoutSeparators[this.rowPos][this.colPos];
           sepObj.setHighlighted(true);
        } else {
            if (!this.isEmpty && !CrtLayoutElement.dragMove && !this.mousingOver) {
                 var self = this;
                 this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
                 this.mousingOver = true;
            }
        }
    }

    LayoutSection.prototype.getSepCell = function(rowPos,colPos) {
        return this.layoutSeparators[rowPos][colPos];
    }

    CrtLayoutElement.getLayoutSection = function(sectionId) {
        return CrtLayoutElement.layoutSections[sectionId];
    }

    LayoutItem.prototype.handleMouseDblClick = function(evt) {
        if (this.isEmpty) {
            return;
        }
        CrtLayoutElement.openPropertiesEdit(evt);
    }


    LayoutItem.prototype.handleMouseClick = function(evt) {
        if (this.isEmpty) {
            return;
        }
        var evt = getEvent(evt);
        if (evt.shiftKey && MoveableItem.currentSelectedObj) {
            LayoutItem.multiSelect(this);
        } else if (evt.ctrlKey) {
            this.toggleSelected(true);
        } else {

        }
     }

     LayoutItem.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
     }

    //remove all selected elements
    MoveableItem.clearSelectedItems = function() {
        var selB = MoveableItem.selectedBucket;
        for (var i = 0; i < MoveableItem.selectedBucket.length; i++) {
            MoveableItem.selectedBucket[i].fieldObj.removeSelection(true);
        }
        MoveableItem.selectedBucket = [];
        MoveableItem.currentSelectedObj = null;
    }

    LayoutItem.prototype.removeSelectionFormatting = function() {
        this.isSelected = false;
        this.formatField();
    }

    LayoutItem.prototype.createMoveableItem = function() {
        return new MoveableItem(this.fieldId, this.fieldName, this.displayName, this.customName, this.type, this, true, false, this.isLookup, this.defaultChecked)
    }

    LayoutItem.prototype.removeSelection = function(noBucketRemove) {
        if (!noBucketRemove && this.moveableItem) {
            this.moveableItem.removeSelection();
        }
        this.moveableItem = null;
        this.removeSelectionFormatting();
    }

    LayoutItem.prototype.addSelectionFormatting = function() {
        this.isSelected = true;
        this.formatField();
    }

    LayoutItem.prototype.addSelection = function() {
        var addSelection;
        if (this.isEmpty) {
            return;
        }
        this.moveableItem = this.createMoveableItem();
        addSelection = this.moveableItem.addSelection();
        //are we mixing the selection Bucket?
        if (addSelection) {
            this.addSelectionFormatting();
        }
    }

    MoveableItem.prototype.addSelection = function() {
        //make sure we are not mixing sections and items
        if (MoveableItem.currentSelectedObj && (this.isSection != MoveableItem.currentSelectedObj.isSection)) {
            return false;
        }
        if (isIE5) {
            MoveableItem.selectedBucket = MoveableItem.selectedBucket.concat(this);
        } else {
            MoveableItem.selectedBucket.push(this);
        }

        MoveableItem.currentSelectedObj = this;
        return true;
    }

    MoveableItem.prototype.removeSelection = function() {
         for (var i = 0; i < MoveableItem.selectedBucket.length; i++) {
            if (MoveableItem.selectedBucket[i].itemId == this.itemId) {
                MoveableItem.selectedBucket.splice(i, 1);
            }
        }
        if (MoveableItem.currentSelectedObj == this) {
            MoveableItem.currentSelectedObj = null;
            if (MoveableItem.selectedBucket.length > 0) {
                MoveableItem.currentSelectedObj = MoveableItem.selectedBucket[MoveableItem.selectedBucket.length-1];
            }
        }
    }


    //handleMultiSelect with shift key
    LayoutItem.multiSelect = function(itemObj) {
        //if in different sections, return
        if (MoveableItem.currentSelectedObj.fieldObj.sectionId != itemObj.sectionId) {
            return;
        }
        var previousSelectedItem = MoveableItem.currentSelectedObj;
        var rowNum1 = previousSelectedItem.fieldObj.rowPos;
        var rowNum2 = itemObj.rowPos;
        var colNum1 = previousSelectedItem.fieldObj.colPos;
        var colNum2 = itemObj.colPos;
        var startRow = Math.min(rowNum1, rowNum2);
        var endRow =  Math.max(rowNum1, rowNum2);
        var startCol =  Math.min(colNum1, colNum2);
        var endCol =  Math.max(colNum1, colNum2);
        if (startRow == endRow && startCol == endCol) {
            itemObj.removeSelection(false);
            return;
        }
        var moving = MoveableItem.selectedBucket;
        MoveableItem.clearSelectedItems();
        CrtLayoutElement.clearTextSelection();
        for (var i = startRow; i <= endRow; i++ ) {
            for (var j = startCol; j <= endCol; j++) {
                 CrtLayoutElement.layoutSections[itemObj.sectionId].getItem(i,j).addSelection();
            }
        }

        MoveableItem.currentSelectedObj = previousSelectedItem;
    }

   CrtLayoutElement.save = function() {
        var xml = CrtLayoutElement.toXML();
        var submitForm = document.forms[CrtLayoutElement.XML_FORM_NAME];
        submitForm.val.value = xml;
        submitForm.submit();
   }

   CrtLayoutElement.toXML = function() {
        var xml = '<' + CrtLayoutElement.ROOT_CONTAINER + '>\n';

       for (var i=0; i<CrtLayoutElement.layoutSecPos.length; i++) {
            xml += CrtLayoutElement.layoutSections[CrtLayoutElement.layoutSecPos[i]].toXml();
        }

        xml += '</' + CrtLayoutElement.ROOT_CONTAINER + '>\n';
        return xml;
    }


    CrtLayoutElement.escapeXML = function(v) {
        v = v.replace(/&/g, '\&amp;');
        v = v.replace(/"/g, '\&quot;');
        v = v.replace(/'/g, "\'");
        v = v.replace(/</g, '&lt;');
        v = v.replace(/>/g, '&gt;');

        return v;
    }

   LayoutSection.prototype.toXml = function() {
        var xml = '<' + CrtLayoutElement.SECTION + ' ';
        //add sectionId
        xml += CrtLayoutElement.SECTION_ID + '=' + '"' + CrtLayoutElement.escapeXML(this.sectionValue) + '" ';
       //add sectionName
        xml += CrtLayoutElement.SECTION_NAME + '=' + '"' + CrtLayoutElement.escapeXML(this.labelName) + '" >\n';
        //iterate over all layout items and add them to xml
        for (var i=0; i < this.numRows; i++) {
            for (var j=0; j< this.numCols; j++) {
                if (!this.getItem(i,j).isEmpty) {
                    xml += '\t';
                    xml += this.getItem(i,j).toXml();
                }
            }
        }

        xml += '</' + CrtLayoutElement.SECTION + '>\n';
        return xml;
   }

   LayoutItem.prototype.toXml = function() {
        var xml = '<' + CrtLayoutElement.ITEM + ' ';
        //add itemId
        xml += CrtLayoutElement.ITEM_ID + '=' + '"' + CrtLayoutElement.escapeXML(this.fieldId) + '" ';
        //add itemName
        xml += CrtLayoutElement.ITEM_NAME + '=' + '"' + CrtLayoutElement.escapeXML(this.fieldName) + '" ';
        //add default selected
        xml += CrtLayoutElement.ITEM_DEFAULT_CHECKED + '=' + '"' + this.defaultChecked + '" ';
        //add custom label
        if (this.customName != null) {
            xml += CrtLayoutElement.ITEM_CUSTOMLABEL + '=' + '"' + CrtLayoutElement.escapeXML(this.customName) + '" ';
        }
        //add itemType
        xml += CrtLayoutElement.ITEM_TYPE + '=' + '"' + this.type + '" >';

        xml += '</' + CrtLayoutElement.ITEM + '>\n';
        return xml;
   }

   LayoutSection.prototype.getItem = function(rowNum,colNum) {
        return this.layoutItems[rowNum][colNum];
    }

    CrtLayoutElement.isMouseDown = function() {
        return CrtLayoutElement.mouseDown;
    }

     function LayoutSectionSeparator(divId, sectionId) {
         this.divId = divId;
         this.sectionId = sectionId;
         this.attachEvents();
         this.setHighlighted(false);
     }

     LayoutSectionSeparator.prototype.setHighlighted = function(isHighlighted) {
           this.isHighlighted = isHighlighted;
           this.formatSeparator();
           if (isHighlighted) {
                   CrtLayoutElement.highlightSec = this;
           } else {
                   CrtLayoutElement.highlightSec = null;
           }
     }

    LayoutSectionSeparator.prototype.attachEvents = function() {
         var self = this;
         addEvent(document.getElementById(self.divId), 'mouseover', function(evt) {self.handleMouseOver(evt);}, false);
    }

    LayoutSectionSeparator.prototype.handleMouseOver = function() {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && MoveableItem.currentSelectedObj.isSection) {
            if (CrtLayoutElement.highlightSec) {
                CrtLayoutElement.highlightSec.setHighlighted(false);
            }
            this.setHighlighted(true);
        }
    }

    //format a section separator
    LayoutSectionSeparator.prototype.formatSeparator = function() {
        var itemElem = document.getElementById(this.divId);
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR;
        if (this.isHighlighted) {
            className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR_HIGHLIGHT;
        }
        itemElem.className = className;
    }

     function setSeparatorAttributes(sectionId,elementId, rowPos, colPos, rowObj) {
        new LayoutItemSeparator(sectionId,elementId, rowPos,colPos, rowObj).insertField();
     }


     function LayoutItemSeparator(sectionId, elementId, rowPos, colPos, rowObj) {
         this.sectionId = sectionId;
         this.rowPos = rowPos;
         this.colPos = colPos;
         if (elementId == null) {
             this.itemElem  = rowObj.insertCell(rowObj.cells.length);
             this.id = this.createNewCellId();
             this.itemElem.id = this.id;
         }
         else {
            this.id = elementId;
         }
    }

    //insert a field into the Layout Section Object
    LayoutItemSeparator.prototype.insertField = function() {
        CrtLayoutElement.layoutSections[this.sectionId].insertSeparatorCell(this);
    }

    LayoutItemSeparator.prototype.handleMouseUp = function(evt) {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove) {
            var evt = getEvent(evt);
            CrtLayoutElement.layoutSections[this.sectionId].moveCells(this.rowPos,this.colPos);
            this.setHighlighted(false);
        }
    }

    LayoutItemSeparator.prototype.handleMouseOver = function() {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && !MoveableItem.currentSelectedObj.isSection) {
            if (LayoutItemSeparator.highlightSep) {
                LayoutItemSeparator.highlightSep.setHighlighted(false);
            }
            this.setHighlighted(true);
        }
      }

       LayoutItemSeparator.prototype.setHighlighted = function(isHighlighted) {
           this.isHighlighted = isHighlighted;
           this.formatSeparator();
           if (isHighlighted) {
                   LayoutItemSeparator.highlightSep = this;
           } else {
                   LayoutItemSeparator.highlightSep = null;
           }
       }


    //format a separator
    LayoutItemSeparator.prototype.formatSeparator = function() {
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR;
        if (this.isHighlighted) {
            className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR_HIGHLIGHT;
        }
        if (!this.itemElem) {
            this.itemElem = document.getElementById(this.id);
        }
        this.itemElem.className = className;
    }

    function escapeQuotes(v) {
        if (v && v.replace){
            v = v.replace(/'/g, "\'");
            v = v.replace(/"/g, '&quot;');
        }
        return v;
    }

    function doNothing(evt) {
        evt = getEvent(evt);
        eventCancelBubble(evt);
    }

   CrtLayoutElement.preview = function(url) {
        document.submitForm.val.value = CrtLayoutElement.toXML();
        openPopupFocus('', 'crtlayoutpreview', 700, 500,'location=no,dependent=no,resizable=yes,toolbar=no,status=no,directories=no,menubar=no,scrollbars=yes', true, false, false);
        borrowForm('submitForm', url, 'crtlayoutpreview');
   }

   CrtLayoutElement.getLookupFieldFromPath = function(path) {
    var primObjMData = CrtLookups.primaryObjects;
    var fieldsMData = CrtLookups.fields;

    var iFieldSep = path.lastIndexOf('.');
    var iSep = path.indexOf('.');
    var table = primObjMData[path.substring(0,iSep)].table;
    var lookup;
    while (iSep != iFieldSep) {
        lookup = path.substring(iSep+1,path.indexOf('.',iSep+1));
        table = fieldsMData[table][lookup].lookup;
        iSep = path.indexOf('.',iSep+1);
    }
    lookup = path.substring(iSep+1);
    return fieldsMData[table][lookup];
}



    CrtLayoutElement.getPath  = function(value) {
        return value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP));
    }

    //if isDisplayName, we use ":" separator notation, ">>" otherwise
    CrtLayoutElement.getDisplayPath = function(value, isDisplayName) {
        var path = '';
        path += CrtLayoutElement.getPrimObjMetaMap()[CrtLayoutElement.getPrimObjId(value,'.')].label + (isDisplayName ? ': ' : ' >> ');
        var table = CrtLayoutElement.getPrimObjMetaMap()[CrtLayoutElement.getPrimObjId(value,'.')].table;
        value = value.substring(value.indexOf('.')+1);
        var separator = isDisplayName ? ': ' : ' > ';
        var pathLabel;
        while (value.indexOf('.') > -1) {
            table = CrtLookups.fields[table];
            path += table[value.substring(0,value.indexOf('.'))].label + separator;
            table = table[value.substring(0,value.indexOf('.'))].lookup;
            value = value.substring(value.indexOf('.')+1);
        }
        table = CrtLookups.fields[table];
        path += table[value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP))].label + separator;
        table = table[value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP))].lookup;

        path += CrtLookups.fields[table][value.substring(value.indexOf(CrtLayoutElement.FIELD_SEP)+1,value.indexOf(CrtLayoutElement.COL_SEP))].label;
        return path;
    }

    //return the AvailabaleSection based on the fieldValue we are given
CrtLayoutElement.getSectionFromFieldValue = function(fieldValue) {
    //kind of HACK way of knowing whether something is a lookup item for not...looking for path separator
    if (fieldValue.indexOf('.') > -1) {
        var primId = CrtLayoutElement.getPrimObjId(fieldValue,'.');
        return CrtLayoutElement.availableSections[CrtLookupSection.getSectionIdFromPrim(primId)];
    } else {
        var primId = CrtLayoutElement.getPrimObjId(fieldValue,CrtLayoutElement.FIELD_SEP);
        return CrtLayoutElement.availableSections[primId];
    }
}

CrtLayoutElement.getPrimObjId = function(path,separator) {
    if (!path) {
        return;
    }
    var iSep= path.indexOf(separator);
    if (iSep > 0) {
        path = path.substring(0,iSep);
        return path;
    } else {
        return null;
    }
}

   CrtLayoutElement.scrollAvailableSection = function(evt){
        var cru = document.getElementById(CrtLayoutElement.SECTION_AVAIL_WRAPPER_ID);
        if (cru) {
            var topValue;
             if(!CrtLayoutElement.availableSectionPosInited) {
                CrtLayoutElement.availableSectionInitPosY = getObjY(cru);
                cru.style.top = '0px';
                CrtLayoutElement.availableSectionPosInited = true;
                return;
            }
            var initLeftHeight = document.getElementById(CrtLayoutElement.LEFT_SECTION_ID).offsetHeight;
            var initRightHeight = document.getElementById(CrtLayoutElement.SECTION_AVAIL_WRAPPER_ID).offsetHeight;
            maxTopValue = initLeftHeight;
            //don't scroll it till it goes offscreen
            if(CrtLayoutElement.availableSectionInitPosY+5 < getScrollY()){
                topValue = getScrollY();
                if (topValue + initRightHeight - 295 < initLeftHeight) {
                   cru.style.top = topValue - 295 + "px";
                //if we are at the bottom of the layout sections, then no more scrolling
                } else {
                    cru.style.top = initLeftHeight-initRightHeight + "px";
                }
            } else {
                cru.style.top = "0px";
            }
        }

    }


/**
  Used for delete confirmations on related lists
  Implemented primarily as a demo of the js/localization binding

  @author polcari
  @since 144
*/

function confirmDelete(msg) {
  if (!msg) {
      msg = LC.getLabel("Global", "are_you_sure");
  }
  return Modal.confirm(msg);
}
// Display the div the corresponds to the selectd value of the SelectElement.  Hide the divs for
// all unselected values.
// The divIds should be provided in the same order that the SelectElement values are generated.
function SelectElementDependency(selectElementId, /* array */ divIds) {
	this.divIds = divIds;
	this.selectElementId = selectElementId;

    var self = this;

	this.changeVisibleDiv = function() {
		var selectedIndex = document.getElementById(self.selectElementId).selectedIndex;

		for (var i = 0; i < divIds.length; i++) {
			var displayValue;
			if (i == selectedIndex)
				displayValue = 'block';
			else
				displayValue = 'none';

			document.getElementById(self.divIds[i]).style.display = displayValue;
		}
	}

	// initialize so the correct the element is shown on the page
    this.changeVisibleDiv();

    addEvent(document.getElementById(this.selectElementId), 'change', this.changeVisibleDiv, false);
}

/**
 * CRT Object selection UI
 *
 * @author tkim
 * @since 148
 */
 
/**
 * This JS class manages the object selection picklists
 */
CrtObjects.DOT_SEPARATOR = CrtConstants.PICKLIST_VALUE_TABLE_FIELD_SEPARATOR;
CrtObjects.ID_SEPARATOR = CrtConstants.PICKLIST_VALUE_ID_SEPARATOR;

CrtObjects.init = function(relationships) {
    var picks = new Array();
    for(var iPicklist = 0; iPicklist < CrtConstants.MAX_OBJECTS; iPicklist++) {
        var pick = document.getElementById(CrtConstants.OBJECT_PREFIX + iPicklist);
        picks[iPicklist] = pick;
    }
    return new CrtObjects(relationships, picks);
}

/**
  we require a map, given as JSON:

  Map<String, Array of Relationship> map from Object to Array of Relationship
  Relationship = tuple (name/value, label)

    var relationships = {
        "Account" : [
            { value : "Contact.Account", label: "Contacts" },
            { value : "Opportunity.Account", label: "Opportunities } ],
        "Contact": [
        ]
    };

For a given relationship value, for example, "Contact.Account", the substring
preceding the dot is necessarily another element in the map.

*/
function CrtObjects(relationships, picks) {
    this.relationships = relationships;
    this.picks = picks;
    this.originalValues = CrtObjects.getSelectedValues(picks);

// for debugging:
/*
    var self = this;
    for(var iPicklist = 0; iPicklist < picks.length; iPicklist++) {
        addEvent(this.picks[iPicklist], 'change', this.getUpdatePicklistsClosure(iPicklist), false);
    } */
}

// public
CrtObjects.prototype.getPicklist = function(iPicklist) {
    return this.picks[iPicklist];
}

// public
CrtObjects.prototype.getValue = function(iPicklist) {
    return CrtObjects.getSelectedValue(this.picks[iPicklist]);
}

/** this is necessary to make iPicklist effectively like a final variable
    by taking a snapshot of the stack frame */
CrtObjects.prototype.getUpdatePicklistsClosure = function(iPicklist) {
    var self = this;
    return function() { self.updatePicklists(iPicklist) };
}

/**
 if picklist i changes, then:
     if this is not the last picklist:
         - set all picklists j > i to null value (or maybe to a previous value?)
         - set the options for the next picklist i+1 to the relationship values
 */
CrtObjects.prototype.updatePicklists = function(iPicklist) {
    // clear all picklists j > i
    for(var j = iPicklist + 1; j < CrtConstants.MAX_OBJECTS; j++) {
       this.picks[j].options.length = 1; // leave the --None-- option
    }

    if (iPicklist < (CrtConstants.MAX_OBJECTS - 1)) {
        // set the options for the next picklist i+1 to the relationships
        var value = CrtObjects.getSelectedValue(this.picks[iPicklist]);
        if (value != '') {
	        var object = this.parseObject(CrtObjects.getSelectedValue(this.picks[iPicklist]));
	        var rels = this.relationships[object];
            for(var iRel = 0; iRel < rels.length; iRel++) {
                var rel = rels[iRel];
                var relValue = this.swapOriginalValue(iPicklist + 1, rel.value);
                var options = this.picks[iPicklist + 1].options;
                options[options.length] = new Option(rel.label, relValue);
            }
        }
    }
}

/* restore the original value that includes the ID, if this is the same as the original value */
CrtObjects.prototype.swapOriginalValue = function(iChildPicklist, relationshipValue) {
    var ret = relationshipValue;
    // is the parent set to the original value?  only do the swap if the parent
    // is also set to an original value.  if the parent set to a new value then
    // the child never corresponds to the original value.
    var parentPicklistValue = CrtObjects.getSelectedValue(this.picks[iChildPicklist - 1]);
    if (parentPicklistValue.indexOf(CrtObjects.ID_SEPARATOR) >= 0) {
        // if the parent has an ID, then it must be an original value
        // so test this child relationship for swap
        var originalChildValue = this.originalValues[iChildPicklist];
        originalChildValue = originalChildValue.substring(0, originalChildValue.indexOf(CrtObjects.ID_SEPARATOR)); // strip the ID for the test
        if (relationshipValue == originalChildValue) {
            ret = this.originalValues[iChildPicklist];
        }
    }
    return ret;
}

// private
// get the selected value of a select element
CrtObjects.getSelectedValue = function(selectElement) {
    return selectElement.selectedIndex < 0 ? null : selectElement.options[selectElement.selectedIndex].value;
}

// private
CrtObjects.getSelectedValues = function(picks) {
    var originalValues = new Array();
    for(var iPick = 0; iPick < picks.length; iPick++) {
        originalValues[iPick] = CrtObjects.getSelectedValue(picks[iPick]);
    }
    return originalValues;
}

// private
// grab the object from a string like "Contact.Account" or "Contact.Account|071xxxxxx"
CrtObjects.prototype.parseObject = function(picklistValue) {
    var value;
    var iDot = picklistValue.indexOf(CrtObjects.DOT_SEPARATOR);
    var iPipe = picklistValue.indexOf(CrtObjects.ID_SEPARATOR);
    if (iDot >= 0) {
        value = picklistValue.substring(0, iDot);
    } else if (iPipe >= 0) {
        // No dot (first picklist of root objects) so just take the value, minus the pipe-ID part
        value = picklistValue.substring(0, iPipe);
    } else {
        // Not even a pipe, so take the whole thing
        value = picklistValue;
    }
    return value;
}
    /** @author zzhou
     *  @since 150
     * Used for ForecastRoleUserPage to enable/disable the Forecast Share options for a FM */

	function ForecastRoleUser() {};
    ForecastRoleUser.checkDisplayAllowSharing = function() {
        var selectedElement = document.getElementById(ForecastRoleUser.pUSER)
        //if no user is selected, we hide the Forecast Sharing div and disable the checkboxes
        if (selectedElement.options[selectedElement.selectedIndex].value == '') {
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[0].disabled=true;
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[1].disabled=true;
            document.getElementById(ForecastRoleUser.FORECAST_SHARE_RADIO).style.visibility = 'hidden';
        } else {
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[0].disabled=false;
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[1].disabled=false;
            document.getElementById(ForecastRoleUser.FORECAST_SHARE_RADIO).style.visibility = 'visible';
        }
    }

    //confirm fct share removal
    ForecastRoleUser.confirmRemoveShares = function(hadMgr) {
        var selectedElement = document.getElementById(ForecastRoleUser.pUSER);
        return selectedElement.options[selectedElement.selectedIndex].value != '' || !hadMgr || window.confirm(LC.getLabel("ForecastSharingPref","confirmAssignNoMgr"));
    }
/** 
 * 
 * Auto-Complete Lookup functionality using script injection technique.
 * To use this script, create a layout section header name with the value:
 * 
 *     <script src="/appex/autocomplete/ac.js"></script>AutoComplete
 *     
 * Presuming, of course, that the file exists in the specified directory.
 * This script also relies on the following scripts to be available:
 * 
 *     /soap/ajax/8.0/connection.js
 *
 * These scripts are included dynamically. (See the code below for more 
 * information.
 *
 */

//////////////////////////////////////////
// AutoComplete object handles query for Entities
// matching lookup type and partial string.
//////////////////////////////////////////

AutoComplete = function(el){

    this.baseName = this.getBaseName(el);
    this.type = this.getLookupType(el);
    this.lookupInput = this.getLookupInput(el);

    this.lookupInput.onkeyup = AutoComplete.prototype.onKeyUp;
    this.lookupInput.onfocus = AutoComplete.prototype.onFocus;
    this.lookupInput.onblur = AutoComplete.prototype.onBlur;
    this.hasFocus = false;

    this.valQueried = null;
    this.records;
    this.selected = -1;
    
    this.entityName;
    this.entityNameFields;
    
    if (this.type == '001'){
        this.entityName = 'Account';
        this.entityNameFields = ['Name'];
    } else if (this.type == '003') {
        this.entityName = 'Contact';
        this.entityNameFields = ['FirstName', 'LastName'];
    } else if (this.type == '005') {
        this.entityName = 'User';
        this.entityNameFields = ['FirstName', 'LastName', 'Alias'];
    }
    
}

// static variables
AutoComplete.prototype.RECORD_HEIGHT = 17;
AutoComplete.prototype.MIN_LENGTH_THRESHOLD = 3;
AutoComplete.prototype.TYPING_THRESHOLD_MILLIS = 200;
AutoComplete.prototype.HIGHLIGHT_COLOR = "#AACCFF";
AutoComplete.prototype.IS_IE = document.all;

// class variables
AutoComplete.prototype.AUTOCOMPLETE_MAP = [];
AutoComplete.prototype.IS_PROCESSING = false;
AutoComplete.prototype.FORM_NAME = 'editPage';

AutoComplete.prototype.getBaseName = function(el){
    if (!el) return this.baseName;
    var name = el.name;
    var idx = name.indexOf('_');
    if (idx > -1){
        return name.substring(0, idx);
    } else {
        return name;
    }
}

AutoComplete.prototype.isLookup = function(el){
    return el.name.indexOf('_lkid') > 0;
}

AutoComplete.prototype.getLookupInput = function(el){
    if (!el) return this.lookupInput;
    var base = this.getBaseName(el);
    return document.getElementById(base);
}

AutoComplete.prototype.getLookupType = function(el){
    if (!el) return this.type;
    var type;
    var base = this.getBaseName(el);
    var name = base +  "_lktp";
    var el = document.getElementById(name);
    if (el){
        type = el.value;
    }    
    return type;
}

AutoComplete.prototype.doLookup = function(val){

    if (!this.hasFocus || AutoComplete.prototype.IS_PROCESSING) return;

    // validate name parts before doing query
    var nameParts = this.parseName(val);
    if (!nameParts || nameParts.length == 0){
        return;
    }

    // mark as processing so we don't run multiple queries at a time
    AutoComplete.prototype.IS_PROCESSING = true;

    // keep last queried so we can do client-side subfiltering
    this.valQueried = val;
    
    var soql = "SELECT Id";

    for (var i = 0; i < this.entityNameFields.length; i++){
        soql += ", " + this.entityNameFields[i];
    }

    soql += " FROM " + this.entityName + " WHERE ";

    // for single-name entities, query single field as complete string
    if (this.entityNameFields.length == 1){
    
        soql += this.entityNameFields[0] + " like '" + val + "%' ";
    
    // for person-name entities, query for variations on the name
    } else {
        for (var i = 0; i < this.entityNameFields.length; i++){
            for (var j = 0; j < nameParts.length; j++){
                var part = nameParts[j];
                if (part){
                    soql += this.entityNameFields[i] + " like '" + part + "%' ";
                    if (i != this.entityNameFields.length - 1 || j != nameParts.length - 1){
                        soql += " OR "
                    }
                }
            }
        }
    }

    this.records = AutoComplete.prototype.query(soql).records;
    this.displayResults(this.records, val);
    
    AutoComplete.prototype.IS_PROCESSING = false;
    
}

AutoComplete.prototype.parseName = function(val){
    var partsTemp;
    if (val){
        partsTemp = val.split(' ');
    } else {
        partsTemp = [];
    }
    
    var parts = [];
    for (var i = 0; i < partsTemp.length; i++){
        var part = partsTemp[i];
        part = part.replace(' ', '');
        if (part){
            parts.push(part);
        }
    }
    return parts;
}

AutoComplete.prototype.displayResults = function(records, value){

    if (records && records.length > 0){

        var baseName = this.getBaseName();

        var html = [];
        html.push("<table width='100%' cellpadding='0' cellspacing='0' border='0'>");
        for (var i = 0; i < records.length; i++){
            var record = records[i];
            var id = ApiUtils.getId(record);
            html.push("<tr><td style='cursor: pointer;' onmouseover='AutoComplete.prototype.setSelected(\""+baseName+"\", "+i+");this.style.backgroundColor=\""+AutoComplete.prototype.HIGHLIGHT_COLOR+"\";' onmouseout='this.style.backgroundColor=\"\";'>");
            html.push("<div style='height:"+AutoComplete.prototype.RECORD_HEIGHT+"px;' id='"+id+"'>");
            var name = this.getName(record);
            html.push(this.highlightMatch(name, value));
            html.push("</div>");
            html.push("</td></tr>");
        }
        html.push("</table>");

        var boxName = this.getBaseName();
        var box = AutoComplete.prototype.getBox(boxName);
        if (!box){
            box = AutoComplete.prototype.makeBox(boxName, records.length * AutoComplete.prototype.RECORD_HEIGHT, 200);
    	    var inputEl = this.getLookupInput();
    	    var top = getObjY(inputEl) + 20;
    	    var left = getObjX(inputEl);
    	    AutoComplete.prototype.moveBox(boxName, top, left);
        } else {
            AutoComplete.prototype.resizeBox(baseName, records.length * AutoComplete.prototype.RECORD_HEIGHT, 200);
        }
        box.innerHTML = html.join('');    
        this.displaySuggestions(true);
    }    

}

AutoComplete.prototype.getName = function(record){
    var name = "";
    for (var i = 0; i < this.entityNameFields.length; i++){
        var value = record.get(this.entityNameFields[i]);
        if (value){
            name += value + " ";
        }
    }
    return name;
}

AutoComplete.prototype.highlightMatch = function(name, value){
    if (!name || !value) return "";
    
    var nameLower = name.toLowerCase();
    var valueLower = value.toLowerCase();
    
    var idx = nameLower.indexOf(valueLower);
    if (idx == -1){
        return name;
    } else {
        var before = name.substring(0, idx);
        var middle = name.substring(idx, idx + value.length);
        var after = name.substring(idx + value.length);
        var match = before + "<b>" + middle + "</b>" + after;
        return match;
    }
}

AutoComplete.prototype.doFilter = function(val){

    var filteredRecords = [];
    for (var i = 0; i < this.records.length; i++){
        var record = this.records[i];
        if (this.isMatch(record, val)){
            filteredRecords.push(record);
        }
    }
    
    if (filteredRecords && filteredRecords.length > 0){
        this.displayResults(filteredRecords, val);
    } else {
        this.doClear();
    }
	        
}

// similar to doLookup() code
AutoComplete.prototype.isMatch = function(record, val){

    var value = null;

    // for single-name entities, match single field as complete string
    if (this.entityNameFields.length == 1){
        value = record.get(this.entityNameFields[0]);
    // for person-name entities, query for variations on the name
    } else {
        value = this.getName(record);
    }
    
    return (value && value.toLowerCase().indexOf(val.toLowerCase()) > -1);
    
}

AutoComplete.prototype.doClear = function(){
    this.displaySuggestions(false);
    this.selected = -1;
}

AutoComplete.prototype.displaySuggestions = function(isVisible){
    AutoComplete.prototype.showBox(this.getBaseName(), isVisible);    
}

AutoComplete.prototype.selectItem = function(selectedIndex){

    var baseName = this.getBaseName();
    var id = null;
    var name = null;
            
    var box = AutoComplete.prototype.getBox(baseName);
    if (box && selectedIndex >= 0){
         var content = box.childNodes[0].childNodes[0];
     	 if (content && content.rows && selectedIndex < content.rows.length){
            var row = content.rows[selectedIndex];
			if (row){
			    var cell = row.cells[0];
                var div = cell.getElementsByTagName("div")[0];
                if (div){
                    id = div.id;
                }
			}
    	}
    }
    
    if (id){
        for (var i = 0; i < this.records.length; i++){
            var rec = this.records[i];
            if (id == ApiUtils.getId(rec)){
                name = this.getName(rec);
                break;
            } 
        }
    }

    // found an ID and a name; load the picklist
    if (id && name){
        lookupPick(AutoComplete.prototype.FORM_NAME, baseName+'_lkid', baseName, '', id, name, '', '');
    }    

    // item selected; clear the suggestion box
    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[baseName];
    if (autoComplete){
        autoComplete.doClear();
    }
    
}

//////////////////////////////
// Event hooks on lookup input element.
//////////////////////////////

AutoComplete.prototype.onKeyUp = function(event){

    if (!event){
        event = window.event;
    }

    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[this.name];
    if (!autoComplete){
        return;
    }

    var val = this.value;
    
    var isKeyPress = (event && event.keyCode);
    if (AutoComplete.prototype.IS_PROCESSING) {
        return;
    } else if (isKeyPress && AutoComplete.prototype.isEnter(event)) {
        // BUGBUG: how do we avoid submitting form on [ENTER] before
        // executing the onBlur()?
        return;
    } else if (isKeyPress && AutoComplete.prototype.isNavigation(event)) {
        AutoComplete.prototype.handleNav(this.name, event);
        return;
    } else if (isKeyPress && AutoComplete.prototype.isTypingFast(this.name, event)){
        return;
    } else if (isKeyPress && AutoComplete.prototype.isIgnore(event)) {
    	return;
    } else if (isKeyPress && AutoComplete.prototype.isEscape(event)){
        autoComplete.doClear();
    	return;
    }

    if (val != null && val.length >= AutoComplete.prototype.MIN_LENGTH_THRESHOLD){
    
        // initial query
        if (autoComplete.valQueried == null || val.toLowerCase().indexOf(autoComplete.valQueried.toLowerCase()) == -1){
            autoComplete.doLookup(val);
        // subquery; filter results
        } else {
            autoComplete.doFilter(val);
        }
            
   } else if (val == null || val.length <= AutoComplete.prototype.MIN_LENGTH_THRESHOLD){
       autoComplete.valQueried = null;
       autoComplete.doClear();
   }

}

AutoComplete.prototype.onFocus = function(event){

    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[this.name];
    if (!autoComplete){
        return;
    }
    autoComplete.hasFocus = true;

}

AutoComplete.prototype.onBlur = function(event){

    if (!event){
        event = window.event;
    }

    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[this.name];
    if (!autoComplete){
        return;
    }

    autoComplete.hasFocus = false;

    if (AutoComplete.prototype.TIMEOUT_ID){    
        clearTimeout(AutoComplete.prototype.TIMEOUT_ID);
    }
    
    // leaving input and is NOT ignore and NOT escape: select the highlighted item
    if (event && !AutoComplete.prototype.isIgnore(event) && !AutoComplete.prototype.isEscape(event) && autoComplete.selected >= 0){
        autoComplete.selectItem(autoComplete.selected);
        
    // otherwise: clear the complete suggestion w/ slight delay to allow
    // possible onclick to pass through to the suggestion div
    } else {
        setTimeout("AutoComplete.prototype.AUTOCOMPLETE_MAP['"+this.name+"'].doClear()", 200);
    }
    
}

//////////////////////////////
// Interaction with suggestion box.
//////////////////////////////

// sets selected index of a given auto-complete object. 
AutoComplete.prototype.setSelected = function(baseName, idx){
    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[baseName];
    if (!autoComplete){
        return;
    } else {
        autoComplete.selected = idx;
    }
    
}

// handle up/down for auto-complete
AutoComplete.prototype.handleNav = function(name, event){

    var autoComplete = AutoComplete.prototype.AUTOCOMPLETE_MAP[name];
    if (!autoComplete){
        return;
    }

    var code = event.keyCode;
    var isDown = (code == 40);
    
    var newSelected = autoComplete.selected;

      var box = AutoComplete.prototype.getBox(autoComplete.getBaseName());
      if (box){
      
          var content = box.childNodes[0].childNodes[0];
          if (content && content.rows){

              if (isDown){
                  if (autoComplete.selected < content.rows.length - 1){
                      newSelected++;
                  }
              } else {
                  if (autoComplete.selected > 0){
                      newSelected--;
                  }
              }
              
              if (autoComplete.selected >= 0){
                  var oldRow = content.rows[autoComplete.selected];
                  if (oldRow && oldRow.childNodes[0]){
                      oldRow.childNodes[0].onmouseout();
                  }
              }

			  if (newSelected >= 0){
                  var newRow = content.rows[newSelected];
                  if (newRow && newRow.childNodes[0]){
                      newRow.childNodes[0].onmouseover();
                  }
                  autoComplete.selected = newSelected;
		      }                  

		}           
     
    }
    
}

//////////////////////////
// Typing helpers.
//////////////////////////

// fast typing gets delayed complete
AutoComplete.prototype.LAST_DATE = null;
AutoComplete.prototype.TIMEOUT_ID = null;

// if typing fast, will delay onKeyUp() until after typing is slowed
AutoComplete.prototype.isTypingFast = function(name, event){
    
    // clear existing timeout to avoid flood of delayed onKeyUp calls
    if (AutoComplete.prototype.TIMEOUT_ID){    
        clearTimeout(AutoComplete.prototype.TIMEOUT_ID);
    }
    
	var d = new Date();
	if (AutoComplete.prototype.LAST_DATE == null){
	    AutoComplete.prototype.LAST_DATE = d;
	    return true;
	} else {
	    var diff = d.getTime() - AutoComplete.prototype.LAST_DATE.getTime();
	    AutoComplete.prototype.LAST_DATE = d;
	    if (diff < AutoComplete.prototype.TYPING_THRESHOLD_MILLIS){
	        var delayedExec = "document.getElementById('"+name+"').onkeyup();";
	        AutoComplete.prototype.TIMEOUT_ID = setTimeout(delayedExec, AutoComplete.prototype.TYPING_THRESHOLD_MILLIS);
	        return true;
	    } else {
	        return false;
	    }
	}
}

AutoComplete.prototype.isNavigation = function(event){
    var code = event.keyCode;
    return (code == 38 || code == 40);
}

// 9 is TAB; 16 is SHIFT-TAB
AutoComplete.prototype.isIgnore = function(event){
    var code = event.keyCode;
    return (code == 9 || code == 16 || (code >= 33 && code <= 46) || (code >= 112 && code <= 123));
}

AutoComplete.prototype.isEscape = function(event){
    var code = event.keyCode;
    return code == 27;
}

AutoComplete.prototype.isEnter = function(event){
    var code = event.keyCode;
    return code == 13;
}

/////////////////////////
// Query Helpers
/////////////////////////

AutoComplete.prototype.query = function(soql){

    try {
        var qr = sforce.connection.query(soql);
        var results = new Object();
        results.size = qr.size;
        results.records = qr.getArray("records");
        return results;
    } catch (fault){
        alert("error: " + fault);
    }
}

//////////////////////////
// Box helpers.
//////////////////////////

AutoComplete.prototype.makeBox = function(name, height, width) {

    // iframe shim b/c IE has input elements show throw plain DIVs
    if (AutoComplete.prototype.IS_IE){
        var iframe = document.createElement("iframe");
        iframe.id = name+"I";
        iframe.style.display = "block";
        iframe.style.position = "absolute";
        iframe.style.padding = "3px";
        iframe.style.height = height + "px";
        iframe.style.width = width + "px";
        iframe.style.backgroundColor = "#ffffCC";
        document.body.appendChild(iframe);
    }

    // div for the contents
    var div = document.createElement("div");
    div.id = name+"D";
    div.style.border = "1px solid #666";
    div.style.display = "block";
    div.style.position = "absolute";
    div.style.padding = "2px";
    div.style.height = height + "px";
    div.style.width = width + "px";
    div.style.backgroundColor = "#ffffCC";
    document.body.appendChild(div);
    
    return div;

}

AutoComplete.prototype.getBox = function(name){
    return document.getElementById(name+'D');

}

AutoComplete.prototype.resizeBox = function(name, height, width) {

    var iframe = document.getElementById(name+'I');
    if (iframe){
        iframe.style.height = height + "px";
        iframe.style.width = width + "px";
    }

    var box = document.getElementById(name+'D');
    if (box){
        box.style.height = height + "px";
        box.style.width = width + "px";
    }
}

AutoComplete.prototype.moveBox = function(name, top, left){

    var iframe = document.getElementById(name+'I');
    if (iframe){
        iframe.style.top = top + "px";
        iframe.style.left = left + "px";
        iframe.style.zIndex = 10;
    }

    var box = document.getElementById(name+'D');
    if (box){
        box.style.top = top + "px";
        box.style.left = left + "px";
        box.style.zIndex = 20;
    }

}

AutoComplete.prototype.showBox = function(name, isVisible){
    var disp = isVisible ? "block" : "none";
    var iframe = document.getElementById(name+'I');
    if (iframe){
        iframe.style.display = disp;
    }

    var box = document.getElementById(name+'D');
    if (box){
        box.style.display = disp;
    }
}

//////////////////////////
// Initialization helpers.
//////////////////////////

AutoComplete.prototype.loadAutoComplete = function(formName){

    if (!formName){
        AutoComplete.prototype.FORM_NAME = "editPage";
    }
    
    // initialize sforce connection
    var apiSession = getCookie("sid");
    var apiURL = ApiUtils.getApiURL(true, "7.0");
    sforce.connection.init(apiSession, apiURL, true);

    var els = document.getElementsByTagName("input");
    for (var i = 0; i < els.length; i++){
        var el = els[i];
        if (AutoComplete.prototype.isLookup(el)){
            var autoComplete = new AutoComplete(el);
            AutoComplete.prototype.AUTOCOMPLETE_MAP[autoComplete.getBaseName()] = autoComplete;
        }
    }
}






/**
 * SearchSettingsPage helper that provides check all functionality.
 * Keeps a counter on the number of checkboxes that are checked to prevent scanning all checkboxes on every click
 * @author mpaksoy
 * @since 154
 */
SearchSettingsPage = {
    totalCounts : {},
    currentCounts : {},

    toggleCheckboxes : function(checkboxid, suffix) {
        if (!checkboxid || !suffix) return;

        var editform = document.getElementById(EditPageConstants.pEDIT_PAGE);
        var checkbox = document.getElementById(checkboxid);

        if (checkbox && editform) {
            var cbVal = checkbox.checked;
            var total = 0;
            for (var i=0; i < editform.elements.length; i++) {
                var elem = editform.elements[i];
                if (elem && (elem != checkbox) && elem.id && (elem.type == 'checkbox')) {
                    var ind = elem.id.indexOf(suffix);
                    if ((ind >= 0) && ((ind + suffix.length) == elem.id.length)) {
                        elem.checked = cbVal;
                        total++;
                    }
                }
            }

            SearchSettingsPage.totalCounts[suffix] =  total;
            if (checkbox.checked) {
                SearchSettingsPage.currentCounts[suffix] =  total;
            } else {
                SearchSettingsPage.currentCounts[suffix] =  0;
            }
        }
    },

    updateParentCheckbox : function(thisCbId, parentCbId, suffix) {
        if (!thisCbId || !parentCbId || !suffix) return;

        var editform = document.getElementById(EditPageConstants.pEDIT_PAGE);
        var thisCb = document.getElementById(thisCbId);
        var parentCb = document.getElementById(parentCbId);

        if (editform && thisCb && parentCb) {
            // init values as necessary
            if (!SearchSettingsPage.isCountInitialized(suffix)) {
                SearchSettingsPage.initCounts(parentCb, suffix);
            } else {
                if (thisCb.checked) {
                    SearchSettingsPage.currentCounts[suffix] += 1;
                } else {
                    SearchSettingsPage.currentCounts[suffix] -= 1;
                }
            }
            // if change reaffirms current parent checkbox state, don't need to do anything else
            if (thisCb.checked != parentCb.checked) {
                // if I unchecked a box, but the parent is still checked, clear parent checkbox.
                if (!thisCb.checked) {
                    parentCb.checked = false;
                } else if(SearchSettingsPage.isAllChecked(suffix)) {
                    parentCb.checked = true;
                }
            }
        }
    },

    getCurCount : function(suffix) {
        var curcount = SearchSettingsPage.currentCounts[suffix];
        // Not found in hash;
        if (!curcount && (curcount !== 0)) return -1;
        return curcount;
    },

    getTotalCount : function(suffix) {
        var curcount = SearchSettingsPage.totalCounts[suffix];
        // Not found in hash;
        if (!curcount && (curcount !== 0)) return -1;
        return curcount;
    },

    isCountInitialized : function(suffix) {
        return ((SearchSettingsPage.getCurCount(suffix) != -1) && (SearchSettingsPage.getTotalCount(suffix) != -1));
    },

    initCounts : function(parentCbRef, suffix) {
        var editform = document.getElementById(EditPageConstants.pEDIT_PAGE);

        var totalCount=0;
        var checkedCount=0;
        for (var i=0; i < editform.elements.length; i++) {
            var elem = editform.elements[i];
            if (elem && (elem != parentCbRef) && elem.id && (elem.type == 'checkbox')) {
                var ind = elem.id.indexOf(suffix);
                if ((ind >= 0) && ((ind + suffix.length) == elem.id.length)) {
                    totalCount++;
                    if (elem.checked) checkedCount++;
                }
            }
        }

        SearchSettingsPage.totalCounts[suffix] = totalCount;
        SearchSettingsPage.currentCounts[suffix] = checkedCount;
    },

    isAllChecked : function(suffix) {
        return SearchSettingsPage.getCurCount(suffix) == SearchSettingsPage.getTotalCount(suffix);
    },
    
    toggleDefaultEntitySection : function() {
    	var parentCb = document.getElementById(SearchSettingsConstants['SIDEBAR_SEARCH_ENTITY_PICKER_ID']);
        var searchDefaultSettings = document.getElementById(SearchSettingsConstants['DEFAULT_SEARCH_ENTITY_CHECKBOX_ID']);
        
        if (parentCb && searchDefaultSettings) {
        	searchDefaultSettings.disabled = !parentCb.checked;
        	SearchSettingsPage.toggleDefaultEntityPicker();
        }
    },
    
    toggleDefaultEntityPicker : function() {
    	var checkbox = document.getElementById(SearchSettingsConstants['DEFAULT_SEARCH_ENTITY_CHECKBOX_ID']);
    	var picklist = document.getElementById(SearchSettingsConstants['DEFAULT_SEARCH_ENTITY_PICKLIST_ID']);
    	
    	if (checkbox && picklist) {
			picklist.disabled = !checkbox.checked || checkbox.disabled;
    	}
    }
}

/*
* @author axing
* @since 148
*/
function ApexPage() {}

ApexPage.prototype = new GenericSfdcPage();

/**
 * A simple overlay screen for displaying a loading/saving method during ajax calls.
 * Currently used in check syntax links for S-Controls and Validation rules, as
 * well as for tag headers on detail pages during saving.
 *
 * @author agusev, emoses, jbergan
 */
function LoadingScreen(theDiv, waitingText, id){
    this.div = theDiv;
    this.text = waitingText;
    this.id = id;
}

LoadingScreen.prototype = {
    show : function() {
        if (!this.transparantElement){
            //Lazily create the div.
            this.createElements();
        }
        this.transparantElement.style.display = 'block';
        this.opaqueElement.style.display = 'block';
    },

    hide : function() {
        if (this.transparantElement) {
            this.transparantElement.style.display = 'none';
            this.opaqueElement.style.display = 'none';
        }
    },

    createElements : function() {
        // During construction in Safari, this is undefined, so it has
        // to be checked when show() is called.
        if (XBrowser.getCurrentStyle(this.div, "position") == "static"){
            this.div.style.position = 'relative';
        }

        // We have one overlay that is partially transparant, and one
        // that is not, so that the description will be opaque.
        this.transparantElement = this.createLoadingElement(this.div);
        this.transparantElement.className = 'waitingSearchDiv waitingSearchDivOpacity';
        this.opaqueElement = this.createLoadingElement(this.div);
        this.opaqueElement.className = 'waitingSearchDiv';
		if (this.id) {
	        this.opaqueElement.id = this.id;
		}

        // The loading description must be on a non-transparant div
        // because otherwise it will have the same opacity as the overlay,
        // and it doesn't look right to have semi-transparant text over text.
        this.addLoadingDescription(this.text, this.opaqueElement);
    },

    createLoadingElement : function(element) {
        var loading = document.createElement('div');

        // 100% is ideal, if it works, since it handles resizing correctly
        // and excludes the border of the element.
        loading.style.width = '100%';
        loading.style.height = '100%';
        if (XBrowser.userAgent.isIE) {
            // IE defaults to left being further left (-5 or so)
            loading.style.left = 0;
            // IE doesn't properly draw '100%' for height on the first try.
            loading.style.height = this.div.clientHeight + "px";
        }

        // Appending the overlay last helps work out the sizing done above
        element.appendChild(loading);
        return loading;
    },

    addLoadingDescription : function(description, element) {
        // On IE, a span ends up showing as two separate sections
        // (img and text) in some contexts.
        var newWaitingHolder = document.createElement('div');
        element.appendChild(newWaitingHolder);
        newWaitingHolder.className = 'waitingHolder';
        var limitedOffset = (element.offsetHeight)/5;
        if (limitedOffset > 100) {
            limitedOffset = 100;
        }
        newWaitingHolder.style.top =  limitedOffset + "px";

        var newWaitingImage = document.createElement('img');
        newWaitingHolder.appendChild(newWaitingImage);
        newWaitingImage.src = UserContext.getUrl('/img/loading.gif');
        newWaitingImage.className  = 'waitingImage';

        var newWaitingDescription = document.createElement('span');
        newWaitingHolder.appendChild(newWaitingDescription);
        newWaitingDescription.innerHTML =  description;
        newWaitingDescription.className  = 'waitingDescription';

		// for IE7, set the style to be position:absolute and width:auto, because the newWaitingImage.offsetWidth and newWaitingDescription.offsetWidth
		// might be 0
        if (XBrowser.userAgent.isIE7){
	        newWaitingHolder.style.position = 'absolute';
	        newWaitingHolder.style.width = 'auto';
		} else {
	        // This is a bit kludgy, but given the variety of widths this is used in,
	        // a straight percentage (as in the css) doesn't work.  Also, the extra 20
	        // is for safari, which otherwise ends up with too small a value for some reason.

	        newWaitingHolder.style.width = (newWaitingImage.offsetWidth + newWaitingDescription.offsetWidth + 20) + "px";
		}
        return newWaitingHolder;
    }
}


SearchHistory.LIST_URL = 'listUrl';
SearchHistory.ACTION_URL = 'actionUrl';
SearchHistory.LIST_QS = 'listQS';
SearchHistory.LIST_ID = 'listId';

function SearchHistory() {
	
	this.actionUrl = null;
	this.listUrl = null;
	this.listQs = null;
	this.listId = null;
}
SearchHistory.prototype.readFromQs = function (queryString){
	this.actionUrl = SearchPage.prototype.decodeForSearch(queryString.get(SearchHistory.ACTION_URL));
	this.listUrl = SearchPage.prototype.decodeForSearch(queryString.get(SearchHistory.LIST_URL));
	this.listQs = SearchPage.prototype.decodeForSearch(queryString.get(SearchHistory.LIST_QS));
	this.listId = SearchPage.prototype.decodeForSearch(queryString.get(SearchHistory.LIST_ID));
}
	
//setters
SearchHistory.prototype.setActionUrl = function (newActionUrl) {
	this.actionUrl = newActionUrl;
}

SearchHistory.prototype.setListUrl  = function (newListUrl) {
	this.listUrl = newListUrl;
}

SearchHistory.prototype.setListQs = function (newListQs) {
	this.listQs = newListQs;
}

SearchHistory.prototype.setListId =  function (newListId) {
	this.listId = newListId;
}

//getters
SearchHistory.prototype.getActionUrl = function () {
	return this.actionUrl;
}

SearchHistory.prototype.getListUrl = function () {
	return this.listUrl;
}

SearchHistory.prototype.getListQs =  function () {
	return this.listQs;
}

SearchHistory.prototype.getListId =  function () {
	return this.listId;
}

SearchHistory.prototype.toString = function () {
	
	var qs = new QueryString("");
	if(this.actionUrl && this.actionUrl.length > 0){
		qs.add(SearchHistory.ACTION_URL, SearchPage.prototype.encodeForSearch(this.actionUrl));
	}
	if(this.listUrl && this.listUrl.length > 0) {
		qs.add(SearchHistory.LIST_URL, SearchPage.prototype.encodeForSearch(this.listUrl));
	}
	if(this.listQs && this.listQs.length > 0) {
		qs.add(SearchHistory.LIST_QS, SearchPage.prototype.encodeForSearch(this.listQs));
	}
	if(this.listId && this.listId.length > 0){
		qs.add(SearchHistory.LIST_ID, SearchPage.prototype.encodeForSearch(this.listId));
	}
	var historyDescriptor = qs.toString();
	return historyDescriptor.substring(1, historyDescriptor.length);
	
}
/**
 * Simplified version of hash map
 * undefined value is not allowed, null or undefined key is not allowed
 * feel free to enhance it
 */
function Map() {
	this.size = 0;
	this.map = new Object();
}

Map.prototype.put = function (key, val) {
	// key not null or undefined, value is not undefined
	if (!key || typeof(val) == 'undefined' ) {
		return;
	}
	if (!(key in this.map)) {
		this.size++;
	}
	this.map[key] = val;
}

Map.prototype.remove = function (key) {
	if (key in this.map) {
		delete(this.map[key]);
		this.size--;
	}
}
function Scontrol() {}

Scontrol.prototype.getSelectedRecordIdsFromForm = function(form, keyPrefix) {
	var selected = [];

	// Get the values directly from the form
	if (form) {
		// Find selected rows with matching key prefix
	    for (i = 0; i < form.elements.length; i++) {
	    	var element = form.elements[i];
	        if ((element.name == "ids") && element.checked) {
	        	var value = element.value;
	        	if (value.substr(0, 3) == keyPrefix) {
					selected.push(value);
				}
	        }
	    }		
	} else {
		alert('Unable to find a form for this button');
	}
			
	return selected;
}
var FilterLookupPage = function(){}

FilterLookupPage.prototype.checked = new Array();

FilterLookupPage.prototype.checkAll = function(val)
{
  for(var i = 0; ; i++)
  {
    var chkbox = document.getElementById("chkbox"+i);
    if (!chkbox) break;
    chkbox.checked = val;
    FilterLookupPage.prototype.checked[i] = (val ? chkbox.value : null);
  }
}

//For boolean fields, we replace the filter value. For enums, we append 
FilterLookupPage.prototype.transfer = function(isBooleanField)
{
    var valueElem = opener.document.getElementById(opener.filterLookupValueElem);
    var string = valueElem.value;
    //Thanks chops!
    if (isBooleanField){
    	if (document.getElementById('chkbox0').checked){
    		string = document.getElementById('chkbox0').value;
    	} else if (document.getElementById('chkbox1').checked){ 
    		string = document.getElementById('chkbox1').value;
    	}
	} else {
        for(var i in FilterLookupPage.prototype.checked) {
            var value = FilterLookupPage.prototype.checked[i];
            if (value != null) {
    		    if (string.length > 0) {
    		        string = string + ", ";
    		    }
    		    if (value.indexOf(",") >= 0) {
    		        value = "\"" + value + "\"";
    		    }
    		    string = string + value;
    		}
    	}
    	if (string.length > valueElem.maxLength){
    		string = string.substring(0,valueElem.maxLength);
    	}
	}
    valueElem.value = string;
	self.close();
	return false;
}

FilterLookupPage.prototype.doCheckbox = function(i) {
    var chkbox = document.getElementById("chkbox"+i);
    if (chkbox.checked) {
        FilterLookupPage.prototype.checked[i] = chkbox.value;
    } else {
        FilterLookupPage.prototype.checked[i] = null;
    }
}

FilterLookupPage.prototype.initBoolean = function() {
	for (i = 0; i < 2; i++){
    	var chkbox = document.getElementById("chkbox"+i);
		chkbox.checked = chkbox.value == opener.document.getElementById(opener.filterLookupValueElem).value;
	}
}
    
function EncryptedTextInputElement(id, maxLength, isMasked){
	if (!isMasked) return;
	this.maxLength = maxLength;
	this.element = getElementByIdCS(id);
	if (!this.element) return;
	
	this.wasCleared = false;
	this.origValue = this.element.value;
	
	var self = this;
	
	this.handleOnFocus = function(e){
		if (self.wasCleared){
			return;
		}
		self.element.select();
	}
	
	this.handleKey = function(e){
		if (!self.wasCleared){
			var code = getEvent(e).keyCode;
			if (!(code === KEY_ENTER || code === KEY_TAB || code === KEY_PAGEUP || code === KEY_PAGEDOWN)){
				self.element.value = "";
				self.element.maxLength = self.maxLength;
				self.wasCleared = true;
			}
		}
	}
	
	this.handleBlur = function(e){
		if (self.element.value === self.origValue){
			self.wasCleared = false;
		}
	}
	
	addEvent(this.element, 'focus', this.handleOnFocus, true);
	addEvent(this.element, 'blur', this.handleBlur, true)
	addEvent(this.element, 'keypress', this.handleKey, true);
}
/**
  This is used to retrieve labels

  @author polcari
  @since 144
*/

function LC() {}

/* This function name is referenced in the dynamicJSLibrary. */
LC.getLabel = function() {
  var retVal = '';
  var args = this.getLabel.arguments;
  if (args[0] && args[1]) {
    retVal = LC.labels[args[0]][args[1]];
  }
  for (i = 2; i < args.length; i++) {  
    //substitutions are done client-side.
    var regexp = new RegExp('\\{'+(i - 2)+'\\}', 'g');
    retVal = retVal.replace(regexp, args[i]);
  }
  return retVal;
}

/*
 * maybe pull a list of  ISO 639 and ISO 3166 codes here?
 */
LC.isEnglishLanguage = function() {
    return UserContext.initialized && UserContext.language == "en_US";
}

LC.isUSLocale = function() {
    return UserContext.initialized && UserContext.locale == "en_US";
}

LC.isEnglishUS = function() {
    return LC.isEnglishLanguage() && LC.isUSLocale();
}

/**
 * XBrowser is a singleton object for all cross-browser utility functions.
 *
 * @author mooney
 * @since 146
 */
var XBrowser = {
    /* simple user agent parsing, use object detection in most cases */
    userAgent : {
        isIE : navigator.userAgent.indexOf("MSIE") != -1,
        isIE6 : navigator.userAgent.indexOf("MSIE 6") != -1,
        isIE7 : navigator.userAgent.indexOf("MSIE 7") != -1,
        isOpera : navigator.userAgent.indexOf("Opera") != -1,
        isSafari : navigator.userAgent.indexOf("AppleWebKit") != -1,
        isFirefox : navigator.userAgent.indexOf("Firefox/") != -1,
        isNetscape : navigator.userAgent.indexOf("Netscape/") != -1
    },

    /**
     * transforms CSS property names from IE format to Mozilla/Opera format
     * i.e. XBrowser.dashify("fontColor") == "font-color"
     */
    dashify : function(str){
        return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
    },

    /**
     * Retrieves the current state for a style property
     */
    getCurrentStyle : function(element, styleProp) {
        if (element.currentStyle) {
            //IE
            return element.currentStyle[styleProp];
        } else if (document.defaultView && document.defaultView.getComputedStyle) {
            //Mozilla & Opera
            return document.defaultView.getComputedStyle(element, null).getPropertyValue(XBrowser.dashify(styleProp));
        }
        // Safari :(
        return null;
    },
    
    /**
     * Retreive the CSS style as set on the element with the 'style' HTML attribute.
     * NOTE: This is different from computed style, which usually is not all defined on the
     * element and is inherited from css classes etc.
     * See getCurrentStyle for getting computed style.
     */
    getElementStyle : function(element, styleProp) {
        if (element.currentStyle) { // IE
            return element.currentStyle[styleProp];
        } else if (element.style.getPropertyValue) { // DOM
            return element.style.getPropertyValue(styleProp);
        }
        return null;
    },

    /**
     * Get the actual height of the element in pixels. Uses offsetHeight and corrects for the padding.
     * NOTE: if the padding is not set in pixels will just return offsetHeight.
     * @param useScrollHeight if set to true, use scrollHeight instead of offsetHeight for height calculation
     */
    getActualHeight : function(/*DOMElement*/ element, /* boolean */ useScrollHeight) {
        var regex = /.*px$/;
        var height = useScrollHeight ? element.scrollHeight : element.offsetHeight;
        var paddingTop = XBrowser.getCurrentStyle(element, 'paddingTop');
        var paddingBottom = XBrowser.getCurrentStyle(element, 'paddingBottom');

        if ((!regex.exec(paddingTop)) || (!regex.exec(paddingBottom))) { // can only handle px padding
            return height;
        }
        paddingTop = paddingTop.substring(0, paddingTop.length - 2);
        paddingBottom = paddingBottom.substring(0, paddingBottom.length - 2);
        return height - paddingTop - paddingBottom;
    },

    /**
     * Creats a new XMLHttpRequest and returns it.
     */
    createHttpRequest : function() {
        if (window.XMLHttpRequest) {
            return new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                return new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    return new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e) {
                }
            }
        }
        return null;
    },

    /**
     * Convenience method which opens an XMLHttpRequest to the specified page, then passes the
     * result to the specified function, or to the specified error handler if an HTTP error occurs
     * 
     * @param url URL to make the request to [String]
     * @param handler Callback to execute after the request returns success [function(request)]
     * @param errorHandler Callback to execute if the request return failure [optional, function(request)]
     * @param method HTTP method to call (GET, POST, PUT, DELETE) [optional, String, default: "GET"]
     * @param body The body of the request [optional, String]
     */
    getHttpResponse : function(url, handler, /* optional */ errorHandler, /*optional*/ method, /*optional*/ body) {
        var request = XBrowser.createHttpRequest();
        var theMethod = method || "GET";
        request.open(theMethod, url, true);
        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                if (request.status == 200) {
                    handler(request);
                } else if (errorHandler) {
                    errorHandler(request);
                }
            }
        };
        if (body && method == "POST"){
            request.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=ISO-8859-13');
        }
        request.send(body);
        
        return request;
    },

    /**
     * Convenience method to execute a POST XmlHttpRequest
     * 
     * @param url URL to make the request to [String]
     * @param handler Callback to execute after the request returns success [function(request)]
     * @param postBody The body of the request [optional, String]
     * @param errorHandler Callback to execute if the request return failure [optional, function(request)]
     */    
    postHttpResponse : function(url, handler, postBody, /*optional*/ errorHandler) {
        return XBrowser.getHttpResponse(url, handler, errorHandler, "POST", postBody);
    },
    
    /**
     * Build a post-style request from a JS Object.  ex: { a: "b", c: "2" } -> "a=b&c=2"
     * @throws URIError from ecodeURIComponent
     */
    buildPost : function(map){
        var arr = [];
        var first = true;
        for (var key in map){
            if (!first){
                arr.push("&");
            }
            first = false;
            if (map[key] instanceof Array) {
                var valueArray = map[key]; 
                if (valueArray.length == 0) {
                    arr.push(key);
                    arr.push("=");
                } else {
                    for (var i = 0; i < valueArray.length; i++) {
                        if (i > 0) {
                            arr.push("&");
                        }
                        arr.push(key);
                        arr.push("=");
                        arr.push(encodeURIComponent(valueArray[i]));
                    }
                }
            } else {
                arr.push(key);
                arr.push("=");
                arr.push(encodeURIComponent(map[key]));
            }
        }
        return arr.join("");
    },

    /**
     * Convenience method to retrieve a script at url and execute it, calling handler after the script has been run.
     * 
     * @param url the url of the script to run
     * @param handler function reference to be called once the script has been loaded
     */
    createDynamicScript : function(url, handler) {
        var script = document.createElement("script");
        if (handler) {
            if (window.ActiveXObject) {
                /* IE uses onreadystatechanged, when loading from the server it fires twice with
                 * readyState values of "loading" and then "loaded", but when loading from the
                 * cache it only fires once with a readyState of "complete"
                 */
                script.onreadystatechange = function() {
                    if (this.readyState == "complete" || this.readyState == "loaded") {
                        handler();
                    }
                };
            } else {
                script.onload = handler;
            }
        }
        script.type = "text/javascript"
        script.src = url;
        document.body.appendChild(script);
    },

    // fix for IE6 CSS background image cache bug (#98786)
    turnOnBackgroundImageCache : function() {
        try {
            document.execCommand("BackgroundImageCache", false, true);
        } catch (error) {
            // not in IE6
        }
    }

};

/**
 * add the Node interface to IE
 */
if (!window.Node) {
    var Node = {
		ELEMENT_NODE : 1,
		ATTRIBUTE_NODE : 2,
		TEXT_NODE : 3,
		CDATA_SECTION_NODE : 4,
		ENTITY_REFERENCE_NODE : 5,
		ENTITY_NODE : 6,
		PROCESSING_INSTRUCTION_NODE : 7,
		COMMENT_NODE : 8,
		DOCUMENT_NODE : 9,
		DOCUMENT_TYPE_NODE : 10,
		DOCUMENT_FRAGMENT_NODE : 11,
		NOTATION_NODE : 12
    };
}

/*
 * @author ldelascurain
 * @since 150
 *
 */

function FieldTreeController( container, rootNodeList, elementName, insertCurlyBangDelims, afterInsertCallback, formulaType, servletUrl){

    this.tree = new FieldTree( rootNodeList, formulaType, servletUrl);
    this.selects = [document.getElementById(FieldTreeConstants.SELECT_ID + "0")];
    this.elementName = elementName;
    this.insertCurlyBangDelims = insertCurlyBangDelims;
    this.container = container;
    this.afterInsertCallback = afterInsertCallback;
    
    var depthRE = /(\d+)$/;

    var self = this;

    this.handleSelectClick = function(e){
        var target = getEventTarget(getEvent(e));
        var match = depthRE.exec(target.name);
        if (!match){
            return;
        }
        var selectDepth = parseInt(match[1]);
        var selectedKey = target.options[target.selectedIndex].value;

        self.moveSelectionTo(selectDepth, selectedKey);
    }

    addEvent(this.container.firstChild.firstChild, 'change', this.handleSelectClick, false);
    this.hideSelects();
};

FieldTreeController.prototype.setScrollDiv = function(div){
	this.scrollDiv = div;
};

FieldTreeController.prototype.ajaxRefreshNode = function(refreshedNode){
	if (refreshedNode === this.tree.currentNode){
		this.eraseSelects(this.tree.currentDepth);
		this.buildSelect(refreshedNode.children, this.tree.currentDepth);
		this.scrollRight();
	}
};

FieldTreeController.prototype.moveSelectionTo = function(selectDepth, selectedKey){
    //TODO:  fix for change to "none"
    if (!selectedKey){
        return;
    }

    if (selectDepth < this.tree.currentDepth){
        this.tree.ascend(selectDepth);
    }

    var selectedNode = this.tree.getNodeFromCurrentList(selectedKey);

    if (!(selectedNode.isLeaf)){
    	var self = this;
        this.buildSelect(this.tree.getChildren(selectedNode, function(refreshedNode) {self.ajaxRefreshNode(refreshedNode);}), selectDepth + 1);
        this.tree.descend(selectedNode.key);
   	    this.scrollRight();
    }
    else {
        // Add the Insert code
        var insertString = selectedNode.getLabelToInsert();
        var extraAttributes = selectedNode.getExtraAttributes();
        this.buildInsert(insertString, selectDepth + 1, extraAttributes);
   	    this.scrollRight();
    }
}

FieldTreeController.prototype.focusTop = function(){
    var topSelect = this.selects[0];
    if(topSelect){
        topSelect.focus();
    }
}

FieldTreeController.prototype.reset = function(){
    this.tree.ascend(0);
    this.selects = [document.getElementById(FieldTreeConstants.SELECT_ID + "0")];

    var topSelect = this.selects[0];
    if (topSelect.options.length > 0){
        topSelect.selectedIndex = 0;
        this.moveSelectionTo(0, topSelect.options[0].value);
    }
}

FieldTreeController.prototype.buildSelect = function( nodeList, index ){

    var map = [];
    for(var i=0;i<nodeList.length;i++){
        var nodeLabel = nodeList[i].isLeaf ? nodeList[i].labelName : (nodeList[i].labelName + " &gt;");
        map[i] = [nodeLabel, nodeList[i].key];
    }

    this.eraseSelects(index);

    var attributeMap = {"size":"9", "name":FieldTreeConstants.SELECT_ID + this.selects.length, "class":"fieldTreeSelect"};
    var selectHTML = Util.createDynamicSelect(attributeMap, map, false);

    var wrapper = document.createElement("TD");
    wrapper.id = "selectWrapper" + this.selects.length;
    wrapper.className = "selectWrapper";
    this.container.appendChild(wrapper);
    wrapper.innerHTML = selectHTML;
    wrapper.isDynamicSelect = true;
    this.selects.push(wrapper.firstChild);


    addEvent(this.selects[index], 'change', this.handleSelectClick, false);
}

FieldTreeController.prototype.buildInsert = function( insertString, index, extraAttributes ){
    var insertInfoHTML = LC.getLabel("NewFormulaEditor", "SelectedInfo");
    var insertText = LC.getLabel("Buttons", "ins");
    var insertStringHTML = insertString;
    var insertButtonHTML = "<input type='button' id='fieldInsertButton' name='insertButton' class='btn' value='" + insertText + "' />";
    var self = this;

    if (this.selects[index]) {
        this.eraseSelects(index);
    }
    var insertBox = document.createElement("TD");
    this.container.appendChild(insertBox);
    insertBox.id = "insertBox";

    var wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperInfo" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertInfoHTML;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperInfo";

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperString" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertStringHTML;
    wrapper.isDynamicSelect = true;
    wrapper.className = "insertWrapperString";

    this.selects.push(wrapper.firstChild);

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperAttributes" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = extraAttributes;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperAttributes";

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperButton" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertButtonHTML;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperButton";

    addEvent(document.getElementById("fieldInsertButton"), "click", function(){self.insertCode(self.elementName, insertString, self.insertCurlyBangDelims);}, false);

}

FieldTreeController.prototype.eraseSelects = function(index){
    var i = this.selects.length;
    while (i > index ){
        i--;
        var element = this.selects[i].parentNode;
        while (element.nodeName != "TD"){
            element = element.parentNode;
        }
        this.container.removeChild(element);
        this.selects.pop();
    }
}

FieldTreeController.prototype.insertCode = function(elementName, insertString, insertCurlyBangDelims){
    FormulaEditor.insertCode( elementName, insertString, insertCurlyBangDelims);
    if (this.afterInsertCallback){
        this.afterInsertCallback();
    }
}

FieldTreeController.prototype.scrollRight = function(){
	var container = this.scrollDiv || this.container;
	if (container.clientWidth == 0){
		//IE fix
		container = container.parentNode;
	}
    container.scrollLeft = container.scrollWidth - container.clientWidth;
}

FieldTreeController.prototype.showSelects = function(){
    for (var i=0; i< this.selects.length; i++ ){
        this.selects[i].style.display = "inline";
    }
}

FieldTreeController.prototype.hideSelects = function(){
    for (var i=0; i< this.selects.length; i++ ){
        var element = this.selects[i];
        if (element!=null && element.nodeName == "SELECT"){
            element.style.display = "none";
        }
    }
}

/**
 * Javascript object and controls for the inline date picker
 * @author jmooney
 * @since 148
 */
function DatePicker() {
    this.today = DateUtil.getDateTimeFromUserLocale(UserContext.today);
    this.calendarDiv = document.getElementById(DatePickerIds.DOM_ID);
    this.shim = new iframeShim(this.calendarDiv);
    this.table = document.getElementById(DatePickerIds.TABLE_ID);
    this.monthPicker = document.getElementById(DatePickerIds.MONTH_PICKER);
    this.yearPicker = document.getElementById(DatePickerIds.YEAR_PICKER);
    this.callOnChange = false;
    this.myField = null;
    this.myElement = null;
    this.currentDate = null;
    this.hasTime = false;
    this.addedFields = {};
    var self = this;
    addEvent(document, "click", function() { self.hide(); }, false);
    addEvent(this.calendarDiv, "click", function(e) { self.cancelHide(e); }, false);
    addEvent(this.monthPicker, "change", function() { self.generateMonth(); }, false);
    addEvent(this.yearPicker, "change", function() { self.generateMonth(); }, false);
}

/**
 * sets the month and year to the passed in date. If the year is not in the dropdown already
 * it will add it in the correct place.
 */
DatePicker.prototype.setMyDate = function(date) {
    var found = false;
    for (var i = 0; i < this.yearPicker.options.length; i++) {
        var year = parseInt(this.yearPicker[i].value);
        if (year > date.getFullYear()) {
            // need to insert the year
            Util.insertOption(this.yearPicker, new Option(date.getFullYear(), date.getFullYear(), false, true), i);
            found = true;
            break;
        } else if (parseInt(this.yearPicker[i].value) == date.getFullYear()) {
            // found it
            this.yearPicker.selectedIndex = i;
            found = true;
            break;
        }
    }
    if (!found) {
        // need to insert the year at the end
        this.yearPicker.options[this.yearPicker.options.length] = new Option(date.getFullYear(), date.getFullYear(), false, true);
    }

    this.monthPicker.selectedIndex = date.getMonth();
}

/**
 * view the previous month
 */
DatePicker.prototype.prevMonth = function() {
    if (this.monthPicker.selectedIndex == 0) {
        var prevYear = parseInt(this.yearPicker[this.yearPicker.selectedIndex].value) - 1;
        if (this.yearPicker.selectedIndex == 0 || prevYear != this.yearPicker[this.yearPicker.selectedIndex - 1].value) {
            var d = new Date();
            d.setFullYear(prevYear);
            d.setMonth(11);
            this.setMyDate(d);
        } else {
            this.yearPicker.selectedIndex--;
            this.monthPicker.selectedIndex = 11;
        }
    } else {
        this.monthPicker.selectedIndex--;
    }
    this.generateMonth();
}

/**
 * view the next month
 */
DatePicker.prototype.nextMonth = function() {
    if (this.monthPicker.selectedIndex == 11) {
        var nextYear = parseInt(this.yearPicker[this.yearPicker.selectedIndex].value) + 1;
        if (this.yearPicker.selectedIndex == this.yearPicker.length - 1 || nextYear != this.yearPicker[this.yearPicker.selectedIndex + 1].value) {
            var d = new Date();
            d.setFullYear(nextYear);
            d.setMonth(0);
            this.setMyDate(d);
        } else {
             this.yearPicker.selectedIndex++;
             this.monthPicker.selectedIndex = 0;
        }
    } else {
        this.monthPicker.selectedIndex++;
    }
    this.generateMonth();
}

/**
 * generates the days for the current selected month.
 */
DatePicker.prototype.generateMonth = function() {
    var month = parseInt(this.monthPicker[this.monthPicker.selectedIndex].value);
    var d = new Date();
    d.setDate(1);
    var year = parseInt(this.yearPicker[this.yearPicker.selectedIndex].value);
    d.setFullYear(year);
    d.setMonth(month);
    // java days are indexed from 1-7, javascript 0-6
    var startPoint = UserContext.startOfWeek - d.getDay();
    if (startPoint > 1) startPoint -= 7;
    d.setDate(startPoint);
    document.getElementById("calRow5").style.display = "";
    document.getElementById("calRow6").style.display = "";
    var dayCells = this.table.getElementsByTagName("td");
    for (var i = 0; i < dayCells.length; i++) {
        var dayOfWeek = d.getDay();
        var week = i / 7;
        var clazz;
        if (dayOfWeek == 0 || dayOfWeek == 6) {
            clazz = "weekend";
        } else {
            clazz = "weekday";
        }
        if (d.getMonth() == month - 1 || d.getFullYear() == year - 1) {
            clazz += " prevMonth"
        } else if (d.getMonth() == month + 1 || d.getFullYear() == year + 1) {
            if (i % 7 == 0) {
                // done, hide the remaining rows.
                document.getElementById("calRow6").style.display = "none";
                if (i / 7 == 4) {
                     document.getElementById("calRow5").style.display = "none";
                }
                break;
            }
            clazz += " nextMonth"
        }
        if (DateUtil.equals(d, this.today)) {
            clazz += " todayDate";
        }
        if (DateUtil.equals(d, this.currentDate)) {
            clazz += " selectedDate"
        }
        dayCells[i].className = clazz;
        dayCells[i].innerHTML = d.getDate();
        d.setDate(d.getDate() + 1);
    }
}

DatePicker.prototype.selectDate = function(value) {
    var selectedDate;
    if ("today" == value) {
        this.currentDate = this.today;
        selectedDate = this.hasTime ? DateUtil.getDateTimeStringFromUserLocale(this.today) : DateUtil.getDateStringFromUserLocale(this.today);
        this.setMyDate(this.today);
        this.generateMonth();
    } else {
        var d = new Date(this.today.getTime());
        // set the date to the 1st to avoid month wrapping
        d.setDate(1);
        d.setFullYear(parseInt(this.yearPicker[this.yearPicker.selectedIndex].value));
        var month = parseInt(this.monthPicker[this.monthPicker.selectedIndex].value);
        if (value.className.indexOf("nextMonth") != -1) {
            month++;
        } else if (value.className.indexOf("prevMonth") != -1) {
            month--;
        }
        d.setMonth(month);
        d.setDate(value.innerHTML);
        selectedDate = this.hasTime ? DateUtil.getDateTimeStringFromUserLocale(d) : DateUtil.getDateStringFromUserLocale(d);
        this.hide();
    }
    DatePicker.insertDate(selectedDate, this.myField.id, this.callOnChange);
}

DatePicker.prototype.position = function() {
    // have to position the calendar relative to its relatively positioned parent (the body div)
    var x = 0;
    var y = 0;
    var element = this.myElement;
    while (element != null && element != this.calendarDiv.offsetParent) {
        x += element.offsetLeft;
        y += element.offsetTop;
        element = element.offsetParent;
    }
    // to check the picker isn't off the bottom of the page we need to calculate the position relative to the top of the page
    if (getObjY(this.myElement) + this.calendarDiv.offsetHeight > getScrollY() + getWindowHeight()) {
        y -= this.calendarDiv.offsetHeight;
    } else {
        y += this.myElement.offsetHeight;
    }
    this.shim.setStyle("left", x + "px");
    this.shim.setStyle("top", y + "px");
}

DatePicker.prototype.show = function(callOnChange, myField, hasTime, myElement) {
    this.callOnChange = callOnChange;
    this.hasTime = hasTime;
    this.myField = getElementByIdCS(myField);
	if (myElement)
    	this.myElement = myElement;
	else
		this.myElement = getElementByIdCS(myField);
    var self = this;
    if (this.myField.type != "hidden") {
        if (this.addedFields[myField] !== this.myField) {
            // gotta detect if field was deleted and replaced by a new one but still has the same dom id
            // remove the reference to the deleted field and re-add the events.
            this.addedFields[myField] = null;
        }
        if (!this.addedFields[myField]) {
            this.addedFields[myField] = this.myField;
            addEvent(this.myField, "click", function(e) { self.cancelHide(e); }, false);
            addEvent(this.myField, "keydown", function(e) { self.handleKeyPress(e); }, false);
            if (!hasTime && LC.isEnglishLanguage()) {
				var blurHandler;
            	if (LC.isEnglishUS()) {
            		blurHandler = function() { DateUtil.checkYear(self.myField, self.callOnChange); };
            	} else {
            		blurHandler = function() { DateUtil.evaluateShortcut(self.myField, self.callOnChange); };
            	}
                addEvent(this.myField, "blur", blurHandler, false);
            }
        }
    }

    // try to parse the date in the field, with or without time
    var time = hasTime ? DateUtil.getDateFromFormat(this.myField.value, UserContext.dateTimeFormat) :
                         DateUtil.getDateFromFormat(this.myField.value, UserContext.dateFormat);
    if (time != 0) {
        // parse successful
        this.currentDate = new Date(time);
        this.setMyDate(this.currentDate);
    } else {
        // couldn't parse, use today's date
        this.setMyDate(this.today);
    }
    this.generateMonth();

    this.shim.setStyle("display", "block");
    this.position();
}

DatePicker.prototype.cancelHide = function(e) {
    eventCancelBubble(e);
    return false;
}

DatePicker.prototype.handleKeyPress = function(e) {
    var key = getEvent(e).keyCode;
    if (key == KEY_ESC || key == KEY_TAB) {
        this.hide();
    } else if (key == KEY_ENTER && !this.hasTime) {
    	if (LC.isEnglishUS()) {
    		DateUtil.checkYear(this.myField);
    	} else if (LC.isEnglishLanguage()) {
	        DateUtil.evaluateShortcut(this.myField);
    	}
    }
}

DatePicker.prototype.hide = function() {
    this.shim.setStyle("display", "none");
}
// static date picker object, lazily create 1 per page
DatePicker.datePicker = null;

DatePicker.pickDate = function(callOnChange, field, hasTime, element) {
    if (!DatePicker.datePicker) {
    	DatePicker.datePicker = new DatePicker();
    }
    DatePicker.datePicker.show(callOnChange, field, hasTime, element);
}

DatePicker.insertDate = function(value, field, callOnChange) {
    var element = getElementByIdCS(field);
    if (!element.disabled && element.value != value) {
        element.value = value;
        if (callOnChange && element.onchange) {
            element.onchange();
        }
    }
}



var Captcha = {
    formName : "",
    submitButtonName : "",
    publicKey : "",
    recaptchaLang : "",
    
    dialog : null,
    
    verified : false,

    // called when you click on the captcha button
    click : function(formName, submitButtonName, publicKey, helpHref, recaptchaLang) {
        Captcha.formName = formName;
        Captcha.submitButtonName = submitButtonName;
        Captcha.publicKey = publicKey;
        Captcha.recaptchaLang = recaptchaLang;
        
    	if (Captcha.verified) {
    		Captcha.proceed();
    		return;
    	}
    	
    	if (typeof Recaptcha == "undefined") {
    	    // recaptcha.js failed to load, recaptcha.net might be down
    	    Captcha.submitClientError();
    	    return;
    	}
    	
    	if (!Captcha.dialog) {
        	Captcha.dialog = new SimpleDialog("captcha_dialog", true);
        	Captcha.dialog.enter = Captcha.submit;
        	Captcha.dialog.setupDefaultButtons();
        	Captcha.dialog.overrideButton(0, LC.getLabel("Buttons", "submit"), "Captcha.submit()");
        	Captcha.dialog.setWidth('350px');
        	Captcha.dialog.register(); // this calls createDialog
        	var html = [];
        	html.push('<div id="recaptcha_widget">');
        	html.push(LC.getLabel("CaptchaElement", "dialog"));
        	html.push('<div id="recaptcha_image"></div>');
        	html.push('<div id="incorrect" style="display:none;color:red">');html.push(LC.getLabel("CaptchaElement", "incorrect"));html.push('</div>');
        	html.push('<table class="captchaContent" border="0" cellpadding="0" cellspacing="0">');
        	html.push('  <tr><td><span class="recaptcha_only_if_image">');html.push(LC.getLabel("CaptchaElement", "imagePrompt"));html.push('</span>');
        	html.push('          <span class="recaptcha_only_if_audio">');html.push(LC.getLabel("CaptchaElement", "audioPrompt"));html.push('</span>');
        	html.push('          <input id="recaptcha_response_field" name="recaptcha_response_field" type="text">');
        	html.push('      </td>');
        	html.push('      <td style="width:25px;border-left:none;cursor:pointer">');
        	html.push('          <img src="' + UserContext.getUrl("/img/recaptcha_refresh.gif") + '" alt="' + LC.getLabel("CaptchaElement", "refresh") + '" title="' + LC.getLabel("CaptchaElement", "refresh") + '" onclick="Recaptcha.reload()">');
        	html.push('          <img class="recaptcha_only_if_image" src="' + UserContext.getUrl("/img/recaptcha_audio.gif") + '" alt="' + LC.getLabel("CaptchaElement", "audio") + '" title="' + LC.getLabel("CaptchaElement", "audio") + '" onclick="Recaptcha.switch_type(\'audio\')">');
        	html.push('          <img class="recaptcha_only_if_audio" src="' + UserContext.getUrl("/img/recaptcha_text.gif") + '" alt="' + LC.getLabel("CaptchaElement", "image") + '" title="' + LC.getLabel("CaptchaElement", "text") + '" onclick="Recaptcha.switch_type(\'image\')">');
            if (helpHref != null && helpHref.length > 0) {
            	html.push('          <img src="' + UserContext.getUrl("/img/recaptcha_help.gif") + '" alt="' + LC.getLabel("Buttons", "help") + '" title="' + LC.getLabel("Buttons", "help") + '" onclick="' + helpHref + '">');
            }
        	html.push('      </td>');
        	html.push('  </tr>');
        	html.push('  <tr><td colspan="2" style="border:0px">');
        	Captcha.dialog.createButtons(html);
        	html.push('<a id="moreinfo" style="float:right" href="#" onclick="Captcha.toggleMoreinfo(true)">');html.push(LC.getLabel("CaptchaElement", "moreinfo"));html.push('</a>');
        	html.push('  </td></tr>');
        	html.push('  <tr><td colspan="2" style="border:0px">');
        	html.push('    <div id="about" style="display:none"><img src="img/reCAPTCHAlogo.png" style="float:left;padding-right:5px">');
        	html.push('      <div style="font-size:85%">Security test provided by <a href="http://www.recaptcha.net" target="_blank">reCAPTCHA&trade;</a>');
        	html.push('      <br>The words above come from scanned books.  By typing them, you help to digitize old texts.</div>');
        	html.push('      <a style="float:right" href="#" onclick="Captcha.toggleMoreinfo(false)">');html.push(LC.getLabel("CaptchaElement", "lessinfo"));html.push('</a>');
        	html.push('    </div>');
        	html.push('  </td></tr>');
        	
        	html.push('</table>');
        	html.push('</div>');
        	
        	Captcha.dialog.setContentInnerHTML(html.join(""));
    	}
    	Captcha.dialog.show();
    	
        Captcha.displayOnly();
    },
    
    toggleMoreinfo : function(show) {
    	if (show) {
            document.getElementById('about').style.display = 'block';
            document.getElementById('moreinfo').style.display = 'none';
    	} else {
            document.getElementById('about').style.display = 'none';
            document.getElementById('moreinfo').style.display = 'inline';
    	}
    },
    
    displayOnly : function() {
        Recaptcha.create(Captcha.publicKey, null,
            { callback: Recaptcha.focus_response_field,
              theme: 'custom',
              lang: Captcha.recaptchaLang });
    },
    
    hide : function() {
        Captcha.dialog.hide();
    },

    // handles Captcha form submit
    submit : function() {
        if (!Captcha.checkRecaptchaConnected()) {
            Captcha.submitClientError();
        } else {
            Captcha.verify();
        }
        return false;
    },

    verify : function() {
        var challenge = Recaptcha.get_challenge();
        var response = Recaptcha.get_response();
        Recaptcha.destroy();
        Captcha.callVerifier(challenge, response, "false", Captcha.verifyResultCallback);
    },
    
    verifyResultCallback : function(response) {
        var responseText = response.responseText;
        var json = Util.evalAjaxServletOutput(responseText);
        if (json[CaptchaVerifierServlet.VALID_KEY] == true) {
            // proceed with the submit, which will now work
            Captcha.verified = true;
            Captcha.hide();
            Captcha.proceed();
        } else {
            // On failure, re-display the captcha
            document.getElementById('incorrect').style.display = 'block';
            Captcha.displayOnly();
        }
    },
    
    proceed : function() {
        if (Captcha.formName) {
	        document.forms[Captcha.formName][Captcha.submitButtonName].click();
    	} else {   
    	    window.location = document.getElementById(Captcha.submitButtonName).href;
    	}
    },
    
    submitClientError : function() {
        Captcha.callVerifier("", "", "true", Captcha.proceed);
    },
    
    callVerifier : function(chal, resp, clientError, callback) {
        var params = { };
        params[CaptchaVerifierServlet.CHALLENGE_PARAM] = chal;
        params[CaptchaVerifierServlet.RESPONSE_PARAM] = resp;
        params[CaptchaVerifierServlet.CLIENT_ERROR_PARAM] = clientError;
        var ajaxServletUrl = UrlMap.convertClassNameToUrl(CaptchaVerifierServlet.SERVLET_NAME, null);
        XBrowser.postHttpResponse(ajaxServletUrl, callback, XBrowser.buildPost(params));
    },
    
    checkRecaptchaConnected : function() {
        var imageHtml = document.getElementById('recaptcha_image').innerHTML;
        return !!imageHtml;
    }
}

var CampaignInfluenceSetupUi = {};

CampaignInfluenceSetupUi.setAutomaticAssociation = function(enabled) {
    var i = 1;
    var nextField = document.getElementById('fcol'+i);
    var nextOp = document.getElementById('fop'+i);
    var nextVal = document.getElementById('fval'+i);

    while (nextField) {
        nextField.disabled = !enabled;
        nextOp.disabled = !enabled;
        nextVal.disabled = !enabled;
        i++;
        nextField = document.getElementById('fcol'+i);
        nextOp = document.getElementById('fop'+i);
        nextVal = document.getElementById('fval'+i);
    }

    var bool = document.getElementById('bool_filter');
    if (bool) bool.disabled = !enabled;

    var timeframe = document.getElementById('citf');
    if (timeframe) timeframe.disabled = !enabled;
}
function ActionOverrideUi() {}

ActionOverrideUi.prototype.visiblePicklist = null;

ActionOverrideUi.prototype.setVisiblePicklist = function(toDisplay) {
    if (ActionOverrideUi.prototype.visiblePicklist != null) {
        document.getElementById(ActionOverrideUi.prototype.visiblePicklist).className = 'hidden';
    }
    document.getElementById(toDisplay).className = null;
    ActionOverrideUi.prototype.visiblePicklist = toDisplay;
}


/*
 * Copyright, 1999-2006, SALESFORCE.com
 * All Rights Reserved
 * Company Confidential
 *
 * JavaScript Utilities. 
 * REQUIRES: DOJO-0.4.1.
 * WILL BE REMOVED - WILL TRY TO UTILIZE EXISTING FUNCTIONS IF AVAILABLE
 * @author dkothule
 * @since 148
 */

/**
 * Modify date object to parse ISO8601 format:
 */
Date.prototype.setISO8601 = function (string) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    this.setTime(Number(time));
}
Date.prototype.toISO8601String = function (format, offset) {
    /* accepted values for the format [1-6]:
     1 Year:
       YYYY (eg 1997)
     2 Year and month:
       YYYY-MM (eg 1997-07)
     3 Complete date:
       YYYY-MM-DD (eg 1997-07-16)
     4 Complete date plus hours and minutes:
       YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
     5 Complete date plus hours, minutes and seconds:
       YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
     6 Complete date plus hours, minutes, seconds and a decimal
       fraction of a second
       YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
       
       offset indicates the timezone which in the form +HH:MM or -HH:MM
    */
    if (!format) { var format = 6; }
    if (!offset) {
        var offset = 'Z';
        var date = this;
    } else {
        var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
        var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
        offsetnum *= ((d[1] == '-') ? -1 : 1);
        var date = new Date(Number(Number(this) + (offsetnum * 60000)));
    }

    var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }

    var str = "";
    str += date.getUTCFullYear();
    if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
    if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
    if (format > 3) {
        str += "T" + zeropad(date.getUTCHours()) +
               ":" + zeropad(date.getUTCMinutes());
    }
    if (format > 5) {
        var secs = Number(date.getUTCSeconds() + "." +
                   ((date.getUTCMilliseconds() < 100) ? '0' : '') +
                   zeropad(date.getUTCMilliseconds()));
        str += ":" + zeropad(secs);
    } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }

    if (format > 3) { str += offset; }
    return str;
}
/**
 * JSUtils: Utility functions.
 */
var JSUtils = {
		/** 
		 * getTiomeZoneString - returns the current timezone string:
		 */
		getTimeZoneString: function(){
			var str = new Date().toString();
			var pos = str.lastIndexOf("(");
			if(pos != -1){
				str = str.substring(pos + 1);
				pos = str.indexOf(")");
				str = pos != -1? str.substring(0, pos) : str;
			}else{
				var words = str.split(' ');
				if(words != null && words.length == 6){
					str = words[words.length - 2];
				}else{
					str = "Local Timezone";
				}
			}
			return str;
		},
		
		/**
		 * Converts the ISO8601 string into a javascript date object.
		 */
		iso8601StringToDate: function(iso8601String){
			var date = new Date(); 
			date.setISO8601(iso8601String);
			return date;
		},
		
		/**
		 * Formats the timestamp in javascript date object to displayable string.
		 */
		formatTimestamp: function(timestamp) {
			if(timestamp == null){
				return "";
			}
			var strTimestamp = "";
			num = timestamp.getMonth() + 1;
			strTimestamp += " " + (num >= 10? "" : "0") + num;
			num = timestamp.getDate();
			strTimestamp += "/" + (num>= 10? "" : "0") + num;
			num = timestamp.getFullYear();
			strTimestamp += "/" + num;
			num = timestamp.getHours();
			strTimestamp += " " + (num>= 10? "" : "0") + num;
			num = timestamp.getMinutes();
			strTimestamp += ":" + (num>= 10? "" : "0") + num;
			num = timestamp.getSeconds();
			strTimestamp += "." + (num>= 10? "" : "0") + num;
			return strTimestamp;
		},
		
		/**
		 * Format numbers to add comma separator.
		 * @param {int} numbers
		 */
		formatNumbers: function (numbers){
			var nStr =  numbers + '';
			x = nStr.split('.');
			x1 = x[0];
			x2 = x.length > 1 ? '.' + x[1] : '';
			var rgx = /(\d+)(\d{3})/;
			while (rgx.test(x1)) {
				x1 = x1.replace(rgx, '$1' + ',' + '$2');
			}
			return x1 + x2;	
		}, /*::Method:formatNumbers*/
		
		/**
		 * Compare two strings.
		 * @param {string} str1 First string
		 * @param {string} str2 Second string.
		 * @type {int}
		 */
		strCompare: function(str1, str2){
			if(str1 > str2){
				return 1;
			}else if(str1 < str2){
				return -1;
			}else{
				return 0;
			}
		},/*::Method::strCompare*/
		
		/**
		 * Trim whitespace from 'str'. If 'wh' > 0,
		 * only trim from start, if 'wh' < 0, only trim
		 * from end, otherwise trim both ends
		 */
		trim: function(str, wh){
			if(!str.replace){ return str; }
			if(!str.length){ return str; }
			var re = (wh > 0) ? (/^\s+/) : (wh < 0) ? (/\s+$/) : (/^\s+|\s+$/g);
			return str.replace(re, "");
		}, /*::Method::trim*/
		
		/**
		 * Trim whitespaces at begining.
		 */
		ltrim: function(str){
			return JSUtils.trim(str, 1);
		}, /*::Method::ltrim*/
		
		/**
		 * Trim whitespace at the end.
		 */
		rtrim: function(str){
			return JSUtils.trim(str, -1);
		},/*::Method::rtrim*/
		
		unescapeChar: function(str, c) {
			var cur = new String;
			var inEscape = false;
			
			for (var i = 0; i < str.length; i++) {
				var ch = str.charAt(i);
				if (inEscape) { // escaped character
					cur = cur + ch;
					inEscape = false;
				} else if (ch == c) { // escaping
					inEscape = true;
				} else {
					cur = cur + ch;
				}
			}
			if (inEscape) return null;
			return cur;
		},/*::Method::unescapeChar*/
		
		
		splitWithQuoteAndEsc: function(str, split) {
	        var result = [];
	        var cur = new String;
	        var inQuote = false;
	        var inEscape = false;
	
	        for (var i = 0; i < str.length; i++) {
	            var ch = str.charAt(i);
	            if (inEscape) {  // escaped character
	                switch (ch) {
	                case 'n':
	                    cur = cur + '\n'; break;
	                case 'r':
	                    cur = cur + '\r'; break;
	                case 't':
	                    cur = cur + '\t'; break;
	                default:
	                    cur = cur + ch;
	                }
	                inEscape = false;
	            } else if (ch == '\\') {  // Escaping
	                inEscape = true;
	            } else if (ch == '\"') {  // Quoting
	                inQuote = !inQuote;
	            } else if (!inQuote && ch == split) {  // A delimiter
	                result.push(cur);
	                cur = new String;
	            } else {  // normal
	                cur = cur + ch;
	            }
	        }
	        if (inEscape || inQuote) {
	            return null;
	        }
	        result.push(cur);
	        return result;
		},/*::Method::splitWithQuoteAndEsc*/
		
		KEY_DEL 		: 46,
		KEY_ESC			: 27,
		KEY_BACKSPACE	: 8,
		KEY_ENTER		: 13, //0x0D
		/**
		 * Returns the event key code
		 */
		getEventKeyCode: function(e){
			var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE // MSIE : Firefox
			var keyChar = (window.event)? event.keyCode : e.keyCode;
			return (keyChar);
		},		
		
		/**
		 * Checks if the given event is an ESC key event or not.
		 * @param {event} e Event to be checked for.
		 */
		isESCKeyEvent: function (e){
			var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE // MSIE : Firefox
			var keyChar = (window.event)? event.keyCode : e.keyCode;
			return (keyChar == Esc);
		}, /*::Method::isESCKeyEvent*/
		
		/**
		 * Checks if the given event key contains a valid ASCII character or not.
		 * @param {event} e Event to be checked for.
		 */
		isASCIIKeyEvent: function(e){
			var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE // MSIE : Firefox
			var keyChar = (window.event)? event.keyCode : e.keyCode;
			return (keyChar >= 32 && keyChar <= 126);
		},
		
		/**
		 * Return the element from document with given id.
		 * @param {string} or {object} elementId to be searched for
		 * @return element if the argument is of type string with id of element;
		 *   		otherwise returns the argument itself;
		 * @type {object}
		 */
		getById: function(elementId){
			if(elementId && (typeof elementId == "string" || elementId instanceof String)){
				return document.getElementById(elementId);
			}else{
				return elementId;
			}
		}, /*::Method::getById*/
		
		/**
		 * Return the first matching element from document where the name 
		 * matches the elementName.
		 * @param {string} elementName Name of the element to search.
		 * @return element object if found; otherwise null;
		 * @type {object} 
		 */
		getByName: function(elementName){
			if(elementName == null) { return null;}
			if(typeof(elementName) == 'string'){
				var el = document.getElementsByName(elementName);
				if(el != null && el.length > 0){
					return el[0];
				}else{
					return null;
				}
			}else{
				return elementName;
			}
		}, /*::Method::getByName*/
		
		/**
		 * clearList
		 * Clears each list box that was passed to this method.
		 * Variable arguments can be passed with either list element or 
		 * an id of the list element (SELECT).
		 * Example: clearList(firstListObj, 'secondListId', thirdListObj).
		 * @param {...} args list1, list2...listn
		 */
		clearList: function() {
			for (var i = 0; i < arguments.length; i++) {
		    	var element = JSUtils.getById(arguments[i]);
		        if (element && element.options) {
		            element.options.length = 0;
		            element.selectedIndex = -1;
		        }
		    }
		}, /*::Method::clearList*/

		/**
		 * Clears the list from given index.
		 * @param list List Object
		 * @param fromIndex index to start removing items from (inclusive)
		 */
		clearListFrom: function(list, fromIndex){
			if(fromIndex == null || fromIndex <= 0){
				JSUtils.clearList(list);
				return;
			}
	    	var element = JSUtils.getById(list);
	        if (element && element.options && element.options.length > fromIndex && fromIndex > 0) {
	        	element.options.length = fromIndex;
	            element.selectedIndex = fromIndex - 1;
	        }
		},
		
		/**
		 * Populate the list box with provided data. 
		 * @param {array} data The multi-dimensional array [][2], 
		 *  with first item of an array item as label and second as value. 
		 *  Example: [['California', 'CA'],['Pittsburgh', 'PA']]
		 *	or		 [{label:'California', value:'CA'}, {label:'Pittsburgh', value:'PA'}]
		 *  or 		 ['California', 'Pittsburgh', 'New York']
		 *  or		 [10, 20, 30, 40, 50]
		 */
		setListData: function(listId, data){
			var list = JSUtils.getById(listId);
			if(list && data && data.length && data.length > 0){
				var text, value, item;
				for(var i=0; i < data.length; i++){
					item = data[i];
					if(item){
						//name, label pair
						//name, value pair
						//label, value pair
						//name list
						//number list
						//multi dimentional
						if(item.name != null && item.label != null){
							text = item.label;
							value = item.name;
						}else if(item.name != null && item.value != null){
							text = item.name;
							value = item.value;
						}else if(item.label != null && item.value != null){
							text = item.label;
							value = item.value;
						}else if(typeof(item) == 'string' || typeof(item) == 'number'){
							text = item.toString();
							value = text;
						}else{
							text = item.length > 0? item[0] : item.toString();
							value = item.length > 1? item[1] : text;
						}
						list.options[list.length] 
								= JSUtils.newOption(text, value);
					}
				}
			}
		}, /*::Method::setListData*/
		
		/**
		 * Removes the selected option(s) from the list box. 
		 * An optional boolean flag removeAll can be passed with value "true"
		 * to remove all selected options if it is multi-select list;
		 * otherwise by default it removes only one element.
		 * @param {object} list The List Element
		 * @param {boolean} removeAll Indicates if multiple option removal.
		 */
		removeSelectedOption: function(list, removeAll){
			list = JSUtils.getById(list);
			var idx = list? list.selectedIndex : -1;
			while(idx != -1){
				list.options[idx] = null;
				if(removeAll != null && removeAll == true){
					idx = list.selectedIndex;
				}else{
					return;
				}
			}
		}, /*::Method::removeSelectedOption*/
		
		/**
		 * Select the given option in given list.
		 * @param {object} list The list to select
		 * @param {object} option Option to select in in (text:, value:} format.
		 * @return Selects and returns the index of selected option if found;
		 *	  		otherwise -1;
		 * @type {int}
		 */
		selectOption: function(list, option){
			list = JSUtils.getById(list);
			if(list){
				var idx = JSUtils.indexOfOption(list, option);
				if(idx != -1){
					list.options[idx].selected = true;
					return idx;
				}
			}
			return -1;
		}, /*::Method::selectOption*/
		
		/**
		 * Unselect the given option in given list.
		 * @param {object} list The list object
		 * @param {object} option Option to unselect in in (text:, value:} format.
		 * @return Unselects and returns the index of option if found;
		 *	  		otherwise -1;
		 * @type {int}
		 */
		unselectOption: function(list, option){
			list = JSUtils.getById(list);
			if(list){
				var idx = JSUtils.indexOfOption(list, option);
				if(idx != -1){
					list.options[idx].selected = false;
					return idx;
				}
			}
			return -1;
		}, /*::Method::unselectOption*/
		
		/**
		 * Selects all the option in given list.
		 * @param {object} list The list object.
		 */
		selectAll: function(list){
			list = JSUtils.getById(list);
			if(list && list.options && list.options.length > 0){
				for(var i=0; i < list.options.length; i++){
					list.options[i].selected = true;
				}
			}
		}, /*::Method::selectAll*/
		
		/**
		 * Unselects all the option in given list.
		 * @param {object} list The list object.
		 */
		unselectAll: function(list){
			list = JSUtils.getById(list);
			if(list && list.options && list.options.length > 0){
				for(var i=0; i < list.options.length; i++){
					list.options[i].selected = false;
				}
			}
		}, /*::Method::unselectAll*/
		
		/**
		 * appendOption()
		 * Adds a new option to the list.
		 * @param {object} list The list object
		 * @param {string} optText The display text for the option.
		 * @param {string} optValue The actual value of the option.
		 * @return Returns the newly created option.
		 * @type {object}
		 */
		appendOption: function (list, optText, optValue){
			list = JSUtils.getById(list);
			if(!list){ return null;}
			var newOpt = JSUtils.newOption(optText, optValue);	
			list.options[list.length] = newOpt;
			return list.options[list.length-1];
		}, /*::Method::appendOption*/
		
		/**
		 * newOption()
		 * Creates a new option with given text and value.
		 * @param {string} optText The display text.
		 * @param {string} optValue The value of the option.
		 * @return Returns newly created option.
		 * @type {object}
		 */
		newOption: function(optText, optValue) {
			var newOpt = document.createElement("OPTION");
			newOpt.text = optText;
			newOpt.value = optValue;
			return newOpt;
		}, /*::Method::newOption*/
		
		/**
		 * setSelectedIndex
		 * @param {object} list The SELECT object
		 * @param {int} index Index of new selection.
		 */
		setSelectedIndex: function(list, index){
			list = JSUtils.getById(list);
			if(list && list.options && list.options.length > index){
				list.options[index].selected = true;
			}
		}, /*::Method::setSelectedIndex*/
		
		/**
		 * Returns the index of selected option in the list.
		 * @return selected index if selected; otherwise -1
		 * @type {int}
		 */
		getSelectedIndex: function(list){
			list = JSUtils.getById(list);
			if(list){
				return list.selectedIndex;
			}
			return -1;
		},  /*::Method::getSelectedIndex*/
		
		/**
		 * Returns the selected option in the list.
		 * @return selected option if selected; otherwise null.
		 * @type {object}
		 */
		getSelectedOption: function(list){
			list = JSUtils.getById(list);
			if(list && list.options && list.selectedIndex >=0 ){
				return list.options[list.selectedIndex];
			}
			return null;
		}, /*::Method::getSelectedOption*/
		
		/**
		 * Returns the selected option value in the list.
		 * @return selected option value if selected; otherwise null.
		 * @type {string}
		 */
		getSelectedValue: function(list){
			var opt = JSUtils.getSelectedOption(list);
			return opt == null? null : opt.value;
		}, /*::Method::getSelectedValue*/
		
		/**
		 * Returns the selected option text in the list.
		 * @return selected option text if selected; otherwise null.
		 * @type {string}
		 */
		getSelectedText: function(list){
			var opt = JSUtils.getSelectedOption(list);
			return opt == null? null : opt.text;
		}, /*::Method::getSelectedValue*/
		
		/**
		 * Returns the index of given option in the list.
		 * Example: JSUtils.indexOfOption(list, {value:"USA"})
		 * @return index of option if found; otherwise -1;
		 * @type {int}
		 */
		indexOfOption: function(list, option){
			if(option == null) {return -1; }
			var check;
			if(option.text == null && option.value != null){
				check = 0; //value only
			}else if(option.text != null && option.value == null){
				check = 1; //text only
			}else if(option.text != null && option.value != null){
				check = 2; //text and value
			}else {
				return -1; //invalid
			}
			list = JSUtils.getById(list);
			if(list && list.options && list.options.length > 0){
				for(var i=0; i < list.options.length; i++){
					switch(check){
						case 0:
							if(list.options[i].value == option.value){
								return i;
							}
							break;
						case 1:
							if(list.options[i].text == option.text){
								return i;
							}
							break;
						case 2:
							if(	list.options[i].value == option.value &&
								list.options[i].text == option.text){
								return i;
							}
							break;
					}
				}
			}
			return -1;
		},/*::Method::indexOfOption*/

		/**
		 * Set the innerHTML for the give object ID.
		 */
		setInnerHTML: function(objectId, value){
			var obj = JSUtils.getById(objectId);
			if(obj != null){
				obj.innerHTML = value;
			}
		},

		/**
		 * Gets the innerHTML for the give object ID.
		 */
		getInnerHTML: function(objectId){
			var obj = JSUtils.getById(objectId);
			return obj == null? null : obj.innerHTML;
		},
		
		/**
		 * Set the "value" attribute of the given element with given text.
		 * @param {object} input The input element.
		 * @value {string} value The text value.
		 */
		setTextValue: function(input, value){
			input = JSUtils.getById(input);
			if(input){
				try{input.value = value == null? "" : value;}catch(e){}
			}
		}, /*::Method::setTextValue*/
		
		/**
		 * Get the text value of "value" attribute from given object.
		 * @param {object} input The input element.
		 * @return Returns the text value of "value" attribute; otherwise null.
		 * @type {string}
		 */
		getTextValue: function(input){
			input = JSUtils.getById(input);
			return input? input.value : null;
		}, /*::Method::getTextValue*/
		
		/**
		 * Set the "style" attribute with given text. 
		 * Example: JSUtils.setStyleText("nodeId", "background-color:#FFFFFF;padding:5px");
		 */
		setStyleText: function(node, styleText){
			node = JSUtils.getById(node);
			try {
	 			node.style.cssText = styleText;
			} catch (e) {
				node.setAttribute("style", styleText);
			}
		},
		
		/**
		 * Set the value of checkbox.
		 * @param {object} checkbox The checkbox element.
		 * @param {boolean} check The new value of checkbox [true | false]
		 */
		setCheckbox: function(checkbox, check){
			checkbox = JSUtils.getById(checkbox);
			if(checkbox){
				checkbox.checked = check;
			}
		}, /*::Method::setCheckbox*/
		
		/**
		 * Determines if the checkbox is checked or not.
		 * @param {object} checkbox The checkbox element
		 * @return Returns true if the checkbox is checked; false otherwise.
		 * @type {boolean}
		 */
		isCheckboxChecked: function(checkbox){
			checkbox = JSUtils.getById(checkbox);
			return (checkbox && checkbox.checked);
		}, /*::Method::isCheckboxChecked*/
		
		/**
		 * Sets the focus on given element.
		 * @param {object} element The element to focus on.
		 */
		setFocus: function(element){
			element = JSUtils.getById(element);
			if(element){
				try{ element.focus(); }catch(e){}
			}
		}, /*::Method::setFocus*/
		
		/**
		 * Show (unhide) the given element.
		 * @param {object} element The element to make visible.
		 */
		show: function(){
			for (var i = 0; i < arguments.length; i++) {
				try{ dojo.style.show(arguments[i]); }catch(e){}
			}
		}, /*::Method::showObject*/
		
		/**
		 * Extended version of Show (unhide) the given element.
		 * This is used where dojo version (show) is not useful.
		 * @param {object} element The element to make visible.
		 */
		showEx: function(){
			var obj;
			for (var i = 0; i < arguments.length; i++) {
				obj = JSUtils.getById(arguments[i]);
				if(obj){
					try{
						obj.style.display = "";
						obj.style.visibility ="visible";
					}catch(e){}
				}
			}
		}, /*::Method::showObject*/
		
		/**
		 * Hides an element.
		 * @param {object} element An element to hide.
		 */
		hide: function(){
			for (var i = 0; i < arguments.length; i++) {
				try{ dojo.style.hide(arguments[i]); }catch(e){ dojo.debug(e);}
			}
		}, /*::Method::hide*/
		
		/**
		 * Hides an element.
		 * This is used where dojo version (hide) is not useful.
		 * @param {object} element An element to hide.
		 */
		hideEx: function(){
			var obj;
			for (var i = 0; i < arguments.length; i++) {
				obj = JSUtils.getById(arguments[i]);
				if(obj){
					try{
						obj.style.display = "none";
						obj.style.visibility = "hidden";
					}catch(e){}
				}
			}
		},/*::Method::hide*/
		
		/**
		 * Set the tab index for given elements in specified order.
		 * @param elements is an array of {name: "xxx", tabindex: xx}
		 */
		setTabIndex: function(elements){
			if(elements && elements.length && elements.length > 0){
				var el;
				for(var i=0; i < elements.length; i++){
					try{
						el = JSUtils.getById(elements[i].name);
						if(el) el.setAttribute("tabindex", elements[i].tabindex);
					}catch(e){
						dojo.debug(e);
					}
				}
			}
		},/*::Method:setTabIndex*/
		
		reloadPage: function(){
			try{
				window.location.reload();
			}catch(e){
				window.location.href=window.location.href
			}
		},/*::reloadPage():*/
		
		/**
		 * @param arg = {id, label, title, visible, onclick}
		 */
		setButtonProperties: function(){
			var btnVal, btnTitle;
			for (var i = 0; i < arguments.length; i++) {
				var btnProp = arguments[i];
				if(btnProp != null){
					if(btnProp.id){
						var btnObj = JSUtils.getById(btnProp.id);
						if(btnObj){
							btnVal = btnProp.label;
							btnTitle = btnProp.title? btnProp.title : btnVal;
							if(btnVal){
								btnObj.value = btnVal;
							}
							if(btnTitle){
								btnObj.title = btnTitle;
							}
							if(btnProp.onclick){
								btnObj.onclick = btnProp.onclick;
							}
							if(btnProp.visible){
								JSUtils.show(btnObj);
							}else{
								JSUtils.hide(btnObj);
							}
						}
					}
				}
			}
		}/*::setButtonProperties():*/
};/*::Class::JSUtils*/	

function ManageableInfoElement(dhtml_id){
	if (!dhtml_id) return;
	
	var outer = document.getElementById(dhtml_id);
	if (!outer) return;

	var elements = getElementsByClassName(ManageableInfo.MORE_INFO_CLASS, outer, "div");

	if (!elements || elements.length < 1) return;
	var moreInfo = elements[0];
	
	var self = this;
	this.isHidden = true;
	
	this.onLinkClickHandler = function(){
		if (self.isHidden){
			moreInfo.style.display = 'block';
			self.link.innerHTML = LC.getLabel("ManageableInfo", "LessInfo");
			self.isHidden = false;
		} else {
			moreInfo.style.display = 'none';
			self.link.innerHTML = LC.getLabel("ManageableInfo", "MoreInfo");
			self.isHidden = true;
		}
	}

	
	var linkArr = outer.getElementsByTagName("a");
	if (linkArr && linkArr.length > 0){
		this.link = linkArr[0]
		addEvent(this.link, 'click', this.onLinkClickHandler, false);
	}
}
var PortalStyleConfigEditor = {
    themes: {},
    themeLoader: null,
    previewUrls: {},
    inputs: []
};

PortalStyleConfigEditor.updateAllPreviews = function () {
    for (key in this.previewUrls) {
        this.updatePreview(this.previewUrls[key], key);
    }
};


PortalStyleConfigEditor.ThemeLoader = function (id) {
    this.id = id;
    this.select = document.getElementById(id);

    var self = this;
    this.handleChange = function (e) {
        self.loadTheme();
    }

    this.init();
};

PortalStyleConfigEditor.ThemeLoader.prototype.loadTheme = function () {
    var newTheme = this.select.value;
    var styleMap = PortalStyleConfigEditor.themes[newTheme];
    for (key in styleMap) {
        var field = document.getElementById(key);
        field.value = styleMap[key];
        if (field.updateColor) {
            field.updateColor();
        }
    }
    this.select.value = newTheme;
    PortalStyleConfigEditor.updateAllPreviews();
};

PortalStyleConfigEditor.ThemeLoader.prototype.reset = function () {
    this.select.value = "";
};

PortalStyleConfigEditor.ThemeLoader.prototype.init = function () {
    addEvent(this.select, 'change', this.handleChange, false);
    PortalStyleConfigEditor.themeLoader = this;
};

PortalStyleConfigEditor.FontSizeInputElement = function (id) {
    this.id = id;
    this.input = document.getElementById(id);

    var self = this;
    this.handleChange = function (e) {
        self.formatInput();
    };

    this.init();
};

PortalStyleConfigEditor.FontSizeInputElement.prototype.formatInput = function () {
    var fontSize = this.input.value;
    if ("%" != fontSize.charAt(fontSize.length - 1)) {
        this.input.value = fontSize + "%";
    }
};

PortalStyleConfigEditor.FontSizeInputElement.prototype.init = function () {
    addEvent(this.input, "change", this.handleChange, false);
};

PortalStyleConfigEditor.CssWidthInputElement = function (id) {
    this.id = id;
    this.select = document.getElementById(id);
};

PortalStyleConfigEditor.FontFamilyInputElement = function (id) {
    this.id = id;
    this.select = document.getElementById(id);
};


PortalStyleConfigEditor.BorderStyleInputElement = function (id) {
    this.id = id;
    this.input = document.getElementById(id);
};

PortalStyleConfigEditor.getPostBody = function () {
    var params = {};
    for (var i = 0; i < this.inputs.length; i++) {
        var input = this.inputs[i];
        params[input.id] = input.value;
    }

    return XBrowser.buildPost(params);
};

PortalStyleConfigEditor.updatePreview = function (url, target) {
    var handler = function (r) {
        var iframe = document.getElementById(target);
        var doc = iframe.contentWindow || iframe.contentDocument;
        if (doc.document) { doc = doc.document;}
        doc.body.innerHTML = "";
        doc.write(r.responseText);
        doc.close();
        iframe.style.height = doc.body.offsetHeight + "px";
    };
    var postBody = this.getPostBody();
    XBrowser.postHttpResponse(url, handler, postBody);
};

PortalStyleConfigEditor.init = function () {
    var tmp = document.getElementById(EditPageConstants.pEDIT_PAGE).elements;
    var handler = function (e) {
        PortalStyleConfigEditor.themeLoader.reset();
        PortalStyleConfigEditor.updateAllPreviews();
    };
    for (var i = 0; i < tmp.length; i++) {
        var field = tmp[i];
        if (0 == field.id.indexOf(PortalStyleConfigEditorConstants.PARAM_PREFIX)
            && field.id != this.themeLoader.id) {
            addEvent(field, "change", handler);
            this.inputs.push(field);
        }
    }
};

/*
 * @author apalke
 * @since 156
 *
 * Shared functions used by the apex calendars
 */

function CalFunctions(){};

CalFunctions.listviewComponentId = null;

CalFunctions.setListviewComponentId = function(id) {
    CalFunctions.listviewComponentId = id;
}

CalFunctions.isListviewPage = function() {
    return CalFunctions.listviewComponentId != null && CalFunctions.listviewComponentId.length != 0;
}

CalFunctions.returnUrlProvider = function() {
    if (CalFunctions.isListviewPage()) {
        var u = ListViewport.instances[CalFunctions.listviewComponentId].retURL;
        if (u != null) {
            return encodeURIComponent(u);
        }
    }
    return window.sfdcPage.getHrefAsRetURL();
}

// used by + links on weekly
CalFunctions.fixAddItemLink = function(link) {
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        link.href = CalFunctions.mungeRetUrl(link.href);
    }
}

// used by click and create full edit link
CalFunctions.fixReturnUrl = function(url) {
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        return CalFunctions.mungeRetUrl(url);
    }
    return url;
}

// used by event hover edit button
CalFunctions.fixReturnUrlAndNavigateToUrl = function(url) {
    var newUrl = url;
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        newUrl = CalFunctions.mungeRetUrl(url);
    }
    navigateToUrl(newUrl);
}

CalFunctions.mungeRetUrl = function(url) {
    var retUrl = CalFunctions.returnUrlProvider();
    var linkUri = QueryString.getURI(url);
    var linkQs = QueryString.createQueryString(url);
    // if it's a recordtype link, we need to change the retURL in save_new_url param
    var saveNewUrl = linkQs.get(EditPageConstants.pSAVE_NEW_URL);
    if (saveNewUrl != null) {
        // replace the retURL value in save_new_url
        var snUri = QueryString.getURI(saveNewUrl);
        var snQs = QueryString.createQueryString(saveNewUrl);
        snQs.remove(UiData.pRET_URL);
        snQs.add(UiData.pRET_URL, decodeURIComponent(retUrl));
        // replace the save_new_url value in link
        linkQs.remove(EditPageConstants.pSAVE_NEW_URL);
        linkQs.add(EditPageConstants.pSAVE_NEW_URL, snUri + snQs.toString());
    }
    // replace the retURL in link
    linkQs.remove(UiData.pRET_URL);
    linkQs.add(UiData.pRET_URL, decodeURIComponent(retUrl));
    return linkUri + linkQs.toString();
}

//Called when re-rendering is completed
CalFunctions.onCompleteRerender = function() {
	if(InlineScheduler.scheduler != undefined && InlineScheduler.scheduler != null) {
		InlineScheduler.scheduler.postRefreshCalendar();
	}
	Hover.clearHovers();
}

//Actions to be performed before the DOM update when refreshing the calendar
CalFunctions.onBeforeDOMUpdate = function() {
	Hover.clearHovers();
}

/**
 * Javascript object and controls for the inline color picker
 * @author rchen
 * @since 148
 */
 function ColorPicker() {
     this.pickerDiv = document.getElementById(ColorPickerConstants.DOM_ID);
     this.colorView = document.getElementById(ColorPickerConstants.COLOR_VIEW_ID);
     this.hexView = document.getElementById(ColorPickerConstants.HEX_VIEW_ID);
     this.shim = new iframeShim(this.pickerDiv);
     this.field = null;
     this.addedFields = {};
     var self = this;
     addEvent(document, "click", function () { self.hide(); }, false);
     addEvent(this.pickerDiv, "click", function (e) { ColorPicker.cancelHide(e); }, false);
}

ColorPicker.prototype.position = function () {
    // Get field's position relative to the offsetParent
    var x = 0;
    var y = 0;
    var elem = this.field;
    // TODO: RPC: Can this be done by getting absolute offset of the field and my element?
    while (elem != null && elem != this.pickerDiv.offsetParent) {
        x += elem.offsetLeft;
        y += elem.offsetTop;
        elem = elem.offsetParent;
    }

    // X - The default is to have the left match the field's left. If that won't work,
    // align the right sides.
    // Y - The default is to be flush with the bottom of the field. If that won't work,
    // place it flush with the top
    var pickerHeight = this.pickerDiv.offsetHeight;
    var pickerWidth = this.pickerDiv.offsetWidth;
    if (getObjX(this.field) + pickerWidth > getScrollX() + getWindowWidth()) {
        x -= pickerWidth - this.field.offsetWidth;
    }
    if (getObjY(this.field) + pickerHeight > getScrollY() + getWindowHeight()) {
        y -= pickerHeight;
    } else {
        y += this.field.offsetHeight;
    }

    this.shim.setStyle("left", x + "px");
    this.shim.setStyle("top", y + "px");
}

ColorPicker.prototype.hide = function () {
    this.shim.setStyle("display", "none");
}

ColorPicker.prototype.show = function (fieldId) {
    this.field = document.getElementById(fieldId);
    this.updateView(this.field.value);
    this.shim.setStyle("display", "block");
    if (!this.addedFields[fieldId]) {
        this.addedFields[fieldId] = true;
        var self = this;
        addEvent(this.field, "keydown", function (e) { self.handleKeyPress(e); }, false);
    }
    this.position();
}

ColorPicker.prototype.handleKeyPress = function(e) {
    var key = getEvent(e).keyCode;
    if (key == KEY_ESC) {
        this.hide();
    }
}

ColorPicker.prototype.selectBasic = function (value) {
    if (!this.field.disabled && this.field.value != value) {
        // Assign new value
        this.field.value = ColorPicker.formatHex(value);

        // Fire events
        if (this.field.fireEvent) {
            this.field.fireEvent('onchange');
        } else if (this.field.dispatchEvent) {
            var e = document.createEvent("HTMLEvents");
            e.initEvent('change', true, true);
            this.field.dispatchEvent(e);
        }
    }
    this.hide();
}

ColorPicker.prototype.updateView = function (hex) {
    var fHex = ColorPicker.formatHex(hex);
    this.colorView.style.backgroundColor = fHex;
    this.hexView.value = fHex;
}

// Lazily instantiated singleton
ColorPicker.singleton = null;

ColorPicker.cancelHide = function (e) {
    eventCancelBubble(e);
    return false;
}

ColorPicker.pick = function (fieldId, event) {
    if (!ColorPicker.singleton) {
        ColorPicker.singleton = new ColorPicker();
    }
    ColorPicker.singleton.show(fieldId);
    if (event) {
        ColorPicker.cancelHide(event);
    }
}

ColorPicker.formatHex = function (hex) {
    var newHex = ('#' == hex.charAt(0)) ? hex : '#' + hex;
    // Attempt to expand 3 hex to 6 hex
    if (newHex.match(/^#[0-9a-f]{3}$/i)) {
        var r = newHex.charAt(1);
        var g = newHex.charAt(2);
        var b = newHex.charAt(3);
        newHex = '#' + r + r + g + g + b + b;
    } else if (!newHex.match(/^#[0-9a-f]{6}$/i)) {
        newHex = '#FFFFFF';
    }
    return newHex;
}

ColorPicker.hiOn = function (elem, boxColor) {
    hiOn(elem);
    elem.style.backgroundColor = '#000000';
    ColorPicker.singleton.updateView(boxColor);
}

ColorPicker.hiOff = function (elem, boxColor) {
    hiOff(elem);
    elem.style.backgroundColor = ColorPicker.formatHex(boxColor);
}

/**
 * Represents a field in a detail element. Handles opening the field for editing, undo, retrieving value for save...
 * Fields are created onload so they can use the DOM.
 * 
 * @author jmooney
 * @since 150
 */
function InlineEditField() {
    this.id = null;
    this.tableCell = null;
    this.readDiv = null;
    this.created = false;
    this.editDiv = null;
    this.state = InlineEditState.NONE;
    this.required = false;
    this.label = null;
    this.initialValue = null;
    this.initialHTML = null;
    this.currentValue = null;
    this.changed = false;
    this.undoButton = null;
    this.error = null;
    this.errorDiv = null;
    this.compound = false;
    this.waitForLoad = false;
    this.controllerId = null;
    this.saveOnEnter = false;
}

// overlay for compound fields and dependencies
InlineEditField.overlay = null;

/**
 * common initializer for all fields
 */
InlineEditField.prototype.init = /* final */ function(id, state, required, isColumn, initialValue) {
    this.id = id;
    this.state = state;
    this.required = required;
    this.isColumn = isColumn;
    if (initialValue === undefined || initialValue === null) {
        this.initialValue = "";
    } else {
        this.initialValue = initialValue;
    }
    this.currentValue = this.initialValue;
    if (!this.isColumn) {
        this.tableCell = getElementByIdCS(id + InlineEditConstants.CELL_ID);
        this.readDiv = getElementByIdCS(id + InlineEditConstants.INNER_ID);
        if (!this.tableCell || !this.readDiv) {
            this.state = InlineEditState.NONE;
            return;
        }
        this.initialHTML = this.readDiv.innerHTML;
    }
}

/* abstract methods that need to be overridden */

InlineEditField.prototype.isDifferentValue = function(newValue) { }

InlineEditField.prototype.openField = function() { }

InlineEditField.prototype.showEdit = function() { }

InlineEditField.prototype.hideEdit = function() { }

InlineEditField.prototype.closeField = function() { }

InlineEditField.prototype.createEditElements = function() { }

InlineEditField.prototype.getValueFromEdit = function() { return null; }

InlineEditField.prototype.updateReadElement = function() { }

InlineEditField.prototype.formatValue = function() { }

InlineEditField.prototype.updateEditElement = function() { }

InlineEditField.prototype.addSaveData = function(saveData) { }

InlineEditField.prototype.createDummy = function() { }

InlineEditField.prototype.load = function() { }

/**
 * @returns true if this field should post values on save
 */
InlineEditField.prototype.doPost = function() {
    return this.state == InlineEditState.EDIT || this.state == InlineEditState.POSTONLY;
}

/**
 * resets this field back to its initial value
 */
InlineEditField.prototype.reset = function() { }

/**
 * strip out < > and replace newlines with <br>
 */
InlineEditField.prototype.cleanValue = function(value) {
    if (value && value.replace) {
        return value.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>').replace(/"/g, "&quot;");
    }
    return value;
}

/**
 * get the value to use when a field has been nulled out, usually "Deleted" in italics
 */
InlineEditField.prototype.getDeletedValue = function() {
    return this.isColumn ? "" : "<em>" + LC.getLabel("Global", "deleted") + "</em>";
}

/**
 * strip < > out of a string
 */
InlineEditField.prototype.cleanValueNoBR = function(value) {
    if (value && value.replace) {
        return value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    }
    return value;
}

/**
 * creates the undo button
 */
InlineEditField.prototype.createUndoButton = function() {
    this.undoButton = document.createElement("a");
    this.undoButton.className = "inlineEditUndoLink";
    this.undoButton.title = LC.getLabel("Icons", "inlineEditUndo");
    this.undoButton.href = "javascript:sfdcPage.inlineEditData.resetFieldById('" + this.id + "');";
    this.undoButton.innerHTML = "<img width='16px' height='16px' src='s.gif' alt='" + LC.getLabel("Icons", "inlineEditUndo") + "' class='inlineEditUndo'>";
}

/**
 * Attempts to get the field label from the label cell in the detail element.
 */
InlineEditField.prototype.getFieldLabel = function() {
    var labelNode = this.tableCell.previousSibling;
    while (labelNode && labelNode.nodeType != Node.TEXT_NODE) {
        labelNode = labelNode.firstChild;
    }
    return labelNode ? labelNode.nodeValue : "";
}

/**
 * sets a validation error on this field
 */
InlineEditField.prototype.setError = function(message) {
    this.error = message;
    if (!this.errorDiv) {
        this.errorDiv = document.createElement("div");
        this.errorDiv.className = "errorMsg";
        this.errorDiv.innerHTML = this.error;
        this.tableCell.appendChild(this.errorDiv);
    } else {
        this.errorDiv.innerHTML = this.error;
        this.errorDiv.style.display = "block";
    }
}

/**
 * clears any validation errors on this field
 */
InlineEditField.prototype.clearError = function() {
    if (this.errorDiv) {
        this.errorDiv.style.display = "none";
    }
    this.error = null;
}

/**
 * get the css class for this field's state
 */
InlineEditField.prototype.getCSSClass = function() {
    return this.state.cssClass;
}

/**
 * get the mouseover css class for this state
 */
InlineEditField.prototype.getCSSHoverClass = function() {
    return this.state.cssClass + "On";
}


/*  -----   STATIC FUNCTIONS   -----  */

/**
 * create a field from the field data struct
 */
InlineEditField.createField = function(fieldData) {
    var fieldType = InlineEditField.resolveSwitchableField(fieldData);
    var fieldId = fieldData[InlineEditConstants.FIELD_ID];
    var state = InlineEditState[fieldData[InlineEditConstants.FIELD_STATE]];
    var required = fieldData[InlineEditConstants.FIELD_REQUIRED];
    var initialValue = fieldData[InlineEditConstants.FIELD_VALUE];
    var extraData = {};
    if (fieldType && fieldType.inlineEditExtraData) {
        for (var i = 0; i <  fieldType.inlineEditExtraData.length; i++) {
            extraData[fieldType.inlineEditExtraData[i]] = fieldData[fieldType.inlineEditExtraData[i]];
        }
    }
    try {
        if (fieldType && fieldType.inlineEditFieldObject && fieldId && state) {
            var ctor = fieldType.inlineEditFieldConstructor();
            return new ctor(fieldId, state, required, false, initialValue, extraData);
            //return eval("new " + fieldType.inlineEditFieldObject + "(fieldId, state, required, false, initialValue, extraData)");
        }
    } catch(e) {
        // squash js error, field won't be editable
    }
    return null;
}

/**
 * resolves switchable personname fields for Account name
 */
InlineEditField.resolveSwitchableField = function(fieldData) {
    var type = ColumnType[fieldData[InlineEditConstants.FIELD_TYPE]];
    if (type == ColumnType.SWITCHABLE_PERSONNAME) {
        return ColumnType[fieldData[InlineEditConstants.OVERRIDE_TYPE]];
    }
    return type;
}

var Util = {
    makeOptionString : function(labelText, value, array){
        if (!array){
            return "<option value='" + value + "'>" + labelText + "</option>";
        } else {
            array.push('<option value="')
            array.push(value);
            array.push('">');
            array.push(labelText);
            array.push('</option>');
        }
    },
    
    scriptCache : {},

    evalScriptsUnderElement : function(element){
        var scriptTags = element.getElementsByTagName("script");
        var srcScripts = [];
        for (var i = 0; i < scriptTags.length; i++) {
        	var src = scriptTags[i].src;
        	if (src && !Util.scriptCache[src]) {
        		XBrowser.createDynamicScript(src);
        		Util.scriptCache[src] = true;
        		srcScripts.push(scriptTags[i]);
	     	} else {
	            eval(scriptTags[i].innerHTML);
        	}
        }
        for (var i = 0; i < srcScripts.length; i++) {
   			srcScripts[i].parentNode.removeChild(srcScripts[i]);	
        }
    },

    /**
     * Load javascript of the element
     */
    evalScriptsUnderElementWithSrc : function(element){
        // local function of parsing javascript
        var _parseScripts = function(){
            // get the colletion of script elements
            var scriptTags = element.getElementsByTagName("script");

            // get the header element
            var docHead = document.getElementsByTagName("head")[0];

            // for each script element, check if it is linked to external js file like <script src=...> or, a local script body
            for(var scriptIndex = 0; scriptIndex < scriptTags.length; scriptIndex++){
                // create a new script element and assign the type
                var newScript = document.createElement("script");
                newScript.type = scriptTags[scriptIndex].type;

                // if the script is linked to external js file, the src value is not null. In this case, using AJAX to fecth the script body and evaluate
                if (scriptTags[scriptIndex].src) {
                    // using AJAX to get the script body
                    var xmlHttp = XBrowser.createHttpRequest();
                    xmlHttp.open("GET" ,scriptTags[scriptIndex].src ,false);
                    xmlHttp.send(null);

                    // eval the script
                    eval(xmlHttp.responseText);
                    newScript.src = scriptTags[scriptIndex].src;

                    // add it to header
                    docHead.appendChild(newScript);
                } else if(scriptTags[scriptIndex].text) {
                    // if the script is local script, eval the script and add it to header
                    eval(scriptTags[scriptIndex].text);
                    newScript.text = scriptTags[scriptIndex].text;
                    docHead.appendChild(newScript);
                } else {}
            }
        }
        // set timeout to give DOM opportunity to catch up
        setTimeout(_parseScripts, 0);
    },

    evalAjaxServletOutput : function(jsonStr){
        if (!jsonStr){
            return null;
        } else if (jsonStr.substring(0, AjaxServlet.CSRF_PROTECT.length) !== AjaxServlet.CSRF_PROTECT){
            //If it doesn't start with CSRF_PROTECT, it didn't come from AjaxServlet...something's wrong
            throw "CSRF protect string not added to servlet response.";
        } else  {
            return eval('('+jsonStr.substring(AjaxServlet.CSRF_PROTECT.length, jsonStr.length) + ')');
        }
    },

    refreshDynamicSelect : function(/*SelectElement*/selectElement, /*list of [label, value]*/options, /*boolean*/ showNone, /*str*/valToMatch){
        var selectedIndex = 0;
        var optionsArr = ["<select name='", selectElement.name, "' id='", selectElement.id, "' class='", selectElement.className, "' title='", selectElement.title, "'"];
        // otherAtributes contains optional attributes for select elements, they are retained if they are set for the original element
        var otherAttributes = ["size","multiple"];
        for (var i = 0; i < otherAttributes.length; i++){
            var param=otherAttributes[i];
            if (selectElement[param]) {
                optionsArr.push(" ");
                optionsArr.push(param);
                optionsArr.push("='");
                optionsArr.push(selectElement[param]);
                optionsArr.push("'");
            }
        }
        optionsArr.push(">");

        var indexNum = 0;
        if (showNone){
            Util.makeOptionString(LC.getLabel("SelectElement", "Required"), '', optionsArr);
            indexNum++;
        }
        for (var i = 0; i < options.length; i++){
            var newVal = options[i][1];
            Util.makeOptionString(options[i][0], newVal, optionsArr);
            if (valToMatch && (newVal === valToMatch)){
                selectedIndex = indexNum;
            }
            indexNum++;
        }
        optionsArr.push("</select>");
        var selParent = selectElement.parentNode;
        if (!selParent.isDynamicSelect){
            var wrapperSpan = document.createElement("SPAN");
            wrapperSpan.isDynamicSelect = true;
            selParent.insertBefore(wrapperSpan, selectElement);
            selParent.removeChild(selectElement);
            selParent = wrapperSpan;
        }
        selParent.innerHTML = optionsArr.join("");
        var newSel = selParent.firstChild;
        if (valToMatch){
            newSel.selectedIndex = selectedIndex;
        }
        return newSel;
     },
 /**
  * Will return a string that can be used as the innerHTML of another element, which will
  * create a select element with the desired attributes and options
  */
    createDynamicSelect : function(/*attribute map*/attributeMap, /*list of [label, value]*/options, /*boolean*/ showNone) {
        var optionsArr = ["<select"];
        for (var key in attributeMap){
                optionsArr.push(" ");
                optionsArr.push(key);
                optionsArr.push("='");
                optionsArr.push(attributeMap[key]);
                optionsArr.push("'");
        }
        optionsArr.push(">");

        if (showNone){
            Util.makeOptionString(LC.getLabel("SelectElement", "Required"), '', optionsArr);
        }
        for (var i = 0; i < options.length; i++){
            var newVal = options[i][1];
            Util.makeOptionString(options[i][0], newVal, optionsArr);
        }
        optionsArr.push("</select>");

        return optionsArr.join("");
    },

    /**
     * convenience method to add Options to SelectElements
     */
    insertOption : function(/*Select Element*/ selectElement, /* Option Element */ optionElement, /* int */index) {
        if (selectElement.currentStyle) {
            selectElement.add(optionElement, index);
        } else {
            selectElement.add(optionElement, selectElement.options[index]);
        }
    },

    /**
     * converts a list of options in [label, value] format into the format used by the picklist/MSP code
     */
    convertOptionsForPicklistData : function(/* list of [label, value] */ options) {
        var ret = [];
        for (var i = 0; i < options.length; i++) {
            ret.push(options[i][1]);
            ret.push(options[i][0]);
        }
        return ret;
    },

    /**
     * animates an HTMLElement by continuously altering a specified CSS value
     *
     * a sample argument template for your coding convenience:
     * {"obj":object, "prop":"propertyName", "start":start, "target":target, "f":function(n) {return n}, "maxinc":maxinc, "aftereach": function(){...}, "after":function(){...}}
     *
     * NOTE: for opacity, specify a value between 0 and 100 (IE style), not between 0.0 and 1.0 (Firefox style)
     *
     */
    animate : function(args) {
        var obj = args["obj"];						/* element */
        var prop = args["prop"];					/* css property to change, as a string */
        var value = parseInt(args["start"]);		/* start value */
        var target = args["target"];				/* target value */
        var f = args["f"] || function(n){return n};	/* optional approach function, defaults to linear */
        var inc = args["inc"] || 1;					/* optional current increment (specify to give starting speed) */
        var maxinc = args["maxinc"] || Infinity;	/* optional maximum increment (i.e., when to stop acceleration) */
        var after = args["after"];					/* optional function to call when animation is complete */
        var aftereach = args["aftereach"];			/* optional function to call after each frame of animation */

        if (target < value) {
            var dest = value - f(inc);
            value = (dest < target) ? target : dest;
        }
        else if (target > value) {
            var dest = value + f(inc);
            value = (dest > target) ? target : dest;
        }

        if(prop=="opacity") {
            obj["style"][prop] = value / 100;
            obj["style"]["filter"] = "alpha(opacity="+value+")";
        } else {
            obj["style"][prop] = value + "px";
        }

        if (!(inc >= maxinc))
            inc++;

        if (value != target) {
            if (aftereach)
                aftereach();
            setTimeout(function () { Util.animate({"obj":obj, "prop":prop, "start":value, "target":target, "f":f, "aftereach":aftereach, "after":after, "inc":inc}) }, 20);
        } else {
            if (aftereach)
                aftereach();
            if (after)
                setTimeout(after, 50);
        }
    }
}

function MaskTypeSelector(targetDivId, typeSelectId, charSelectId, maskData){
	this.targetDiv = document.getElementById(targetDivId);
	this.typeSelect = document.getElementById(typeSelectId);
	this.charSelect = document.getElementById(charSelectId);
	this.maskData = maskData;
	
	var self = this;
	
	this.handleSelectChange = function(e){
		var typeValue = self.typeSelect.options[self.typeSelect.selectedIndex].value;
		var charValue = self.charSelect.options[self.charSelect.selectedIndex].value;
		
		if (!(typeValue && charValue)){
			self.targetDiv.innerHTML = "";
			return;
		}
		
		var example = self.maskData[typeValue];
		example = example.replace(/X/g, charValue);
		self.targetDiv.innerHTML = example;
	};

	addEvent(this.typeSelect, 'change', this.handleSelectChange, false);
	addEvent(this.charSelect, 'change', this.handleSelectChange, false);
	
	this.handleSelectChange();
}
////////////////////////////////
// Dynamically load CSS Skin
////////////////////////////////

function DynamicCss (){
    this.cssLinks = [];
}

DynamicCss.prototype.addCssUrl = function(url, mediaType) {
    this.cssLinks.push(new DynamicCss.CssLink(url, mediaType));
}

DynamicCss.prototype.writeCss = function(apiVersion, doc) {
    for (var i = 0; i < this.cssLinks.length; i++) {
        doc.write(this.cssLinks[i].getLink(apiVersion));
    }
}

DynamicCss.addCssUrl = function(url, mediaType) {
    DynamicCss.instance.addCssUrl(url, mediaType);
}

DynamicCss.writeCss = function(apiVersion, doc, dontClose) {
    DynamicCss.instance.writeCss(apiVersion, doc);
    if (!dontClose) {
        doc.close();
    }
}


// load one CSS file
DynamicCss.loadCSS = function(headElem, cssUri) {
    var commonCSSLink = document.createElement("link");
    commonCSSLink.setAttribute("type", "text/css");
    commonCSSLink.setAttribute("href", cssUri);
    commonCSSLink.setAttribute("rel", "stylesheet");
    headElem.appendChild(commonCSSLink);
}

// load a set of CSS style sheets for a theme
DynamicCss.loadSkin = function(getUserInfoResult, version) {
    var headElem = DynamicCss.getHead();
    if (headElem) {
        var uiSkin = "Theme2";
        if (getUserInfoResult && getUserInfoResult.userUiSkin) {
            uiSkin = getUserInfoResult.userUiSkin;
        }
        var base;
        if (version){
            base = UserContext.getUrl("/sCSS/") + version;
        } else {
            base = UserContext.getUrl("/dCSS");
        }
        base = base + "/" + uiSkin + "/default";
        DynamicCss.loadCSS(headElem, base + "/common.css");
        DynamicCss.loadCSS(headElem, base + "/custom.css");
    }
}

DynamicCss.getHead = function(){
    var headElems = document.getElementsByTagName("head");
    var headElem = (headElems && headElems.length == 1) ? headElems[0] : null;
    return headElem;
}

DynamicCss.CssLink = function(url, mediaType) {
    this.url = url;
    if (mediaType) {
        this.mediaType = mediaType;
    } else {
        this.mediaType = null;
    }
}

DynamicCss.CssLink.prototype.getUrl = function() { 
    return this.url;
}

DynamicCss.CssLink.prototype.getMediaType = function() { 
    return this.mediaType;
}

DynamicCss.CssLink.prototype.getLink = function(apiVersion) {
    var strBuf = [];
    strBuf.push("<link type='text/css' rel='stylesheet' href='");
    var url = this.getUrl();
    if (apiVersion) {
        if (!DynamicCss.CssLink.URL_VERSION_REGEX) {
            DynamicCss.CssLink.URL_VERSION_REGEX = new RegExp("sCSS/[^/]*");
        }
        var repStr = "sCSS/" + apiVersion;
        url = url.replace(DynamicCss.CssLink.URL_VERSION_REGEX, repStr);
    }
    strBuf.push(url);
    strBuf.push("'");
    if (this.getMediaType()) {
        strBuf.push(" media='");
        strBuf.push(this.getMediaType());
        strBuf.push("'");
    }
    strBuf.push(">");
    return strBuf.join('');
}


DynamicCss.instance = new DynamicCss();  //singleton

/* This file contains Ext extensions which are specific to the new list views in 154. */

if (window.Ext) {

// NAMESPACING
Ext.ns('Sfdc', 'Sfdc.grid');

/**
 * @class Sfdc.grid.GridView
 * @extends Ext.grid.GridView
 */
Sfdc.grid.GridView = Ext.extend(Ext.grid.GridView, {
    // we are not using the Ext.data.Store sort implementation--this maintains sort state
    sortState : { field: null,
                  dir: null
                },
    
    // private
    onRowSelect : function(row){
        var recordId = this.grid.store.getAt(row).id;
        var checkbox = getElementByIdCS(recordId);
        if (checkbox) {
            checkbox.checked = true;
            updateToggleAllBox(checkbox.form,'ids');
        }
        this.addRowClass(row, "x-grid3-row-selected");
        this.grid.viewport.paginator.selectedOnThisPage++;
    },

    // private
    onRowDeselect : function(row){
        var recordId = this.grid.store.getAt(row).id;
        var checkbox = getElementByIdCS(recordId);
        if (checkbox) {
            checkbox.checked = false;
            updateToggleAllBox(checkbox.form,'ids');
        }
        this.removeRowClass(row, "x-grid3-row-selected");
        this.grid.viewport.paginator.selectedOnThisPage--;
    },
    
    /* ADDING DOM IDS */
    // private
    initTemplates : function(){
        var ts = this.templates || {};
        if(!ts.master){
            ts.master = new Ext.Template(
                    '<div class="x-grid3" hidefocus="true">',
                        '<div class="x-grid3-viewport">',
                            '<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset">{header}</div></div><div class="x-clear"></div></div>',
                            '<div class="x-grid3-scroller"><div class="x-grid3-body">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',
                        "</div>",
                        '<div class="x-grid3-resize-marker">&#160;</div>',
                        '<div class="x-grid3-resize-proxy">&#160;</div>',
                    "</div>"
                    );
        }

        if(!ts.header){
            ts.header = new Ext.Template(
                    '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                    '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
                    "</table>"
                    );
        }

        if(!ts.hcell){
            ts.hcell = new Ext.Template(
                    '<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id}" style="{style}"><div {tooltip} {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" style="{istyle}">', this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
                    '{value}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
                    "</div></td>"
                    );
        }

        if(!ts.body){
            ts.body = new Ext.Template('{rows}');
        }

        if(!ts.row){
            ts.row = new Ext.Template(
                    '<div class="x-grid3-row {alt}" style="{tstyle}"><table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                    '<tbody><tr>{cells}</tr>',
                    (this.enableRowBody ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>' : ''),
                    '</tbody></table></div>'
                    );
        }

        if(!ts.cell){
            ts.cell = new Ext.Template(
                    '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
                    '<div class="x-grid3-cell-inner x-grid3-col-{id}" id="{domId}" {attr}>{value}</div>',
                    "</td>"
                    );
        }

        for(var k in ts){
            var t = ts[k];
            if(t && typeof t.compile == 'function' && !t.compiled){
                t.disableFormats = true;
                t.compile();
            }
        }

        this.templates = ts;

        this.tdClass = 'x-grid3-cell';
        this.cellSelector = 'td.x-grid3-cell';
        this.hdCls = 'x-grid3-hd';
        this.rowSelector = 'div.x-grid3-row';
        this.colRe = new RegExp("x-grid3-td-([^\\s]+)", "");
    },
    
    // private
    doRender : function(cs, rs, ds, startRow, colCount, stripe){
        var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1;
        var tstyle = 'width:'+this.getTotalWidth()+';';
        // buffers
        var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;
        for(var j = 0, len = rs.length; j < len; j++){
            r = rs[j]; cb = [];
            var rowIndex = (j+startRow);
            for(var i = 0; i < colCount; i++){
                c = cs[i];
                p.domId = r.id + "_" + c.id;
                p.id = c.id;
                p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
                p.attr = p.cellAttr = "";
                p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
                p.style = c.style;
                if(p.value == undefined || p.value === "") p.value = "&#160;";
                if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
                    p.css += ' x-grid3-dirty-cell';
                }
                cb[cb.length] = ct.apply(p);
            }
            var alt = [];
            if(stripe && ((rowIndex+1) % 2 == 0)){
                alt[0] = "x-grid3-row-alt";
            }
            if(r.dirty){
                alt[1] = " x-grid3-dirty-row";
            }
            rp.cols = colCount;
            if(this.getRowClass){
                alt[2] = this.getRowClass(r, rowIndex, rp, ds);
            }
            rp.alt = alt.join(" ");
            rp.cells = cb.join("");
            buf[buf.length] =  rt.apply(rp);
        }
        return buf.join("");
    },

    getColumnStyle : function(col, isHeader) {
        return Sfdc.grid.GridView.superclass.getColumnStyle.call(this, col, false);
    },
    
    /* resizes columns to the width of the longest data in the column
     * ** ONLY WORKS IF COLUMN IS *THINNER* THAN WIDEST DATA **
     */
    sizeColumnToContent: function(colIndex) {
        var maxwidth = 0;
        var extra = 8;
        
        var rows = this.getRows().length;
        for (var i=0; i<rows; i++) {
            var cellChild = this.getCell(i, colIndex).firstChild;
            var w = cellChild.scrollWidth;
            if (w == cellChild.clientWidth) {
            	// don't do anything if column is already wide enough
            	continue;
            }
            if (w > maxwidth) {
                maxwidth = w;
            }
        }
        
        if (maxwidth == 0) {
        	return;
        }
        
        this.grid.getColumnModel().setColumnWidth(colIndex, maxwidth+extra);
    }
});

/**
 * @class Sfdc.grid.CheckboxSelectionModel
 * @extends Ext.grid.RowSelectionModel
 */
Sfdc.grid.CheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {    
    header: "<input type='checkbox' id='allBox' value='' onclick='return false'/>",
    /**
     * @cfg {Number} width The default width in pixels of the checkbox column (defaults to 20).
     */
    width: 20,
    /**
     * @cfg {Boolean} sortable True if the checkbox column is sortable (defaults to false).
     */
    sortable: false,

    // private
    fixed:true,
    dataIndex: '',
    id: 'checkbox',
    
    // private
    renderer : function(v, p, record){
        var html = [];
        html.push("<input id='");
        html.push(record.id);
        html.push("' value='");
        html.push(record.id);
        html.push("'");
        html.push(" type='checkbox'");
        html.push(" class='checkbox'");
        html.push(" name='ids'");
        html.push(" onclick='return false;'/>");
        return html.join('');
    },

	    // private
    initEvents : function(){
        Sfdc.grid.CheckboxSelectionModel.superclass.initEvents.call(this);
        this.grid.on('render', function(){
            var view = this.grid.getView();
            view.mainBody.on('mousedown', this.onMouseDown, this);
            Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);

        }, this);

        this.on("beforerowselect", this.onBeforeRowSelect, this);
    },
    
    maxSelections : 200,
    
    /**
     * Selects a row.
     * @param {Number} row The index of the row to select
     * @param {Boolean} keepExisting (optional) True to keep existing selections
     */
    selectRow : function(index, keepExisting, preventViewNotify){
        if(this.locked || (index < 0 || index >= this.grid.store.getCount())) return false;
        if (this.isSelected(index)) return true;
        var r = this.grid.store.getAt(index);
        if(r && this.fireEvent("beforerowselect", this, index, keepExisting, r) !== false){
            if(!keepExisting || this.singleSelect){
                this.clearSelections();
            }
            this.selections.add(r);
            this.last = this.lastActive = index;
            if(!preventViewNotify){
                this.grid.getView().onRowSelect(index);
            }
            this.fireEvent("rowselect", this, index, r);
            this.fireEvent("selectionchange", this);
            this.grid.viewport.paginator.setSelectCount(this.selections.length);
        } else {
            return false;
        }
        
        return true;
    },

    /**
     * Deselects a row.
     * @param {Number} row The index of the row to deselect
     */
    deselectRow : function(index, preventViewNotify){
        if(this.locked || !this.isSelected(index)) return;
        this.last = index;
        var r = this.grid.store.getAt(index);
        if(r){
            this.selections.removeKey(r.id);
            if(!preventViewNotify){
                this.grid.getView().onRowDeselect(index);
            }
            this.fireEvent("rowdeselect", this, index, r);
            this.fireEvent("selectionchange", this);
            this.grid.viewport.paginator.setSelectCount(this.selections.length);
        }
    },
    
    /**
     * Selects multiple rows.
     * @param {Array} rows Array of the indexes of the row to select
     * @param {Boolean} keepExisting (optional) True to keep existing selections
     */
    selectRows : function(rows, keepExisting){
        if(!keepExisting){
            this.clearSelections();
        }
        for(var i = 0, len = rows.length; i < len; i++){
            if (!this.selectRow(rows[i], true)) {
                break;
            }
        }
    },

    /**
     * Selects a range of rows. All rows in between startRow and endRow are also selected.
     * @param {Number} startRow The index of the first row in the range
     * @param {Number} endRow The index of the last row in the range
     * @param {Boolean} keepExisting (optional) True to retain existing selections
     */
    selectRange : function(startRow, endRow, keepExisting){
        if(this.locked) return;
        if(!keepExisting){
            this.clearSelections();
        }
        if(startRow <= endRow){
            for(var i = startRow; i <= endRow; i++){
                if(!this.selectRow(i, true)) {
                    break;
                }
            }
        }else{
            for(var i = startRow; i >= endRow; i--){
                if(!this.selectRow(i, true)) {
                    break;
                }
            }
        }
    },
    
    /**
     * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
     * @param {Number} startRow The index of the first row in the range
     * @param {Number} endRow The index of the last row in the range
     */
    deselectRange : function(startRow, endRow, preventViewNotify){
        if(this.locked) return;
        if(startRow <= endRow) {
            for(var i = startRow; i <= endRow; i++){
                this.deselectRow(i, preventViewNotify);
            }
        } else {
            for(var i = startRow; i >= endRow; i--){
                this.deselectRow(i, preventViewNotify);
            }
        }
    },
    
    /**
     * Clears all selections across all pages.
     */
    clearAllSelections : function() {
        this.clearSelections();
        this.selections.clear();
        this.grid.viewport.paginator.setSelectCount(0);
        this.grid.viewport.paginator.selectedOnThisPage = 0;
    },
    
    /**
     * Clears selections on this page.
     */
    clearSelections : function(){
        for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
            this.deselectRow(i);
        }
        
        this.last = false;
    },

    /**
     * Selects all rows on this page.
     */
    selectAll : function(){
        if(this.locked) return;
        for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
            if (!this.selectRow(i, true)) {
                break;   
            }
        }
    },
    
    onBeforeRowSelect : function(sm, index, keepExisting, r) {
        if(this.selections.length >= this.maxSelections) {
            alert(LC.getLabel("List", "selectionLimit", this.maxSelections));
            return false;
        }
    },
    
    /* we are only allowing selection via checkbox.  blow away row selection. */
    handleMouseDown : function(g, rowIndex, e){
        return;
    },
    
    // private
    onEditorKey : function(field, e){
        return;
    },

    // private
    onMouseDown : function(e, t){
        if(e.button === 0 && t.className == 'checkbox'){ // Only fire if left-click
            e.stopEvent();
            var row = e.getTarget('.x-grid3-row');
            
            if(row){
                var index = row.rowIndex;
                
                if(e.shiftKey && this.last !== false){
                    var last = this.last;
                    
                    if (this.isSelected(last)) {
                        this.selectRange(last, index, true);
                    } else {
                        this.deselectRange(last, index);
                    }
                    this.last = last; // reset the last
                } else {
                    if(this.isSelected(index)){
                        this.deselectRow(index);
                    }else{
                        this.selectRow(index, true);
                    }
                }
            }
        }
    },

    // private
    onHdMouseDown : function(e, t){
        if(e.button === 0) {
            if(t.id == 'allBox'){
                e.stopEvent();
                if(t.checked){
                    this.clearSelections();
                }else{
                    this.selectAll();
                }
            }
        }
    },
    
    // private
    onRefresh : function(){
        var all = getElementByIdCS("allBox");
        if (all) {
            all.checked = false;
        }
        
        var ds = this.grid.store, index;
        var s = this.getSelections();
        
		if (this.grid.viewport.paginator) {
	        this.grid.viewport.paginator.selectedOnThisPage = 0;
        }

        var offPageHTML = [];
        for(var i = 0, len = s.length; i < len; i++){
            var r = s[i];
            if((index = ds.indexOfId(r.id)) != -1){
                this.grid.getView().onRowSelect(index);
            } else {
            	offPageHTML.push("<input type='hidden' name='ids' value='");
            	offPageHTML.push(s[i].id);
            	offPageHTML.push("'/>");
            }
        }
		this.grid.viewport.offPageIds.innerHTML = offPageHTML.join('');
        
        if(s.length != this.selections.getCount()){
            this.fireEvent("selectionchange", this);
        }
        this.last = false;
        
        if (this.grid.viewport.paginator) {
	        this.grid.viewport.paginator.draw(this.grid.viewport.paginator.totalRecords === 0);
        }
    }
});

}

/**
 * MRU hover detail object.
 * @author mooney
 * @since 146
 */
function MRUHoverDetail(id) {
    this.id = id;
    this.mruItem = getElementByIdCS("mru" + id);
    this.hover = document.createElement("div");
    this.hover.id = id + "Hover";
    this.hover.className = "mruHoverDetail";
    this.hover.innerHTML = "<div class=\"bPageBlock secondaryPalette\"><div class=\"pbBody\">" + LC.getLabel("Global", "loading") + "</div></div>";
    this.mruItem.appendChild(this.hover);
    this.originalClass = this.mruItem.className;
    var width = this.mruItem.offsetWidth;
    // IE6 calculates the width incorrectly, add in 30 pixels for the mruIcon and its margin
    if (this.mruItem.currentStyle && XBrowser.userAgent.isIE6) {
       width -= 30;
    }
    this.hover.style.left = width + "px";
    this.hover = new iframeShim(this.hover);
    this.fadingOut = null;
    this.fadingIn = null;
    this.loaded = false;
}

MRUHoverDetail.SHOW_DELAY = 800;
MRUHoverDetail.HIDE_DELAY = 400;
// the URL for bulk loading all the MRU hovers
MRUHoverDetail.loaderURL = null;
// boolean for if the request has been sent already
MRUHoverDetail.sentRequest = false;
// response from the bulk loader servlet
MRUHoverDetail.response = null;
// map from id to hover object
MRUHoverDetail.hovers = {};
// id of the currently open hover
MRUHoverDetail.openHover = null;

// static function to retrieve a hover detail using a 15 char ID
MRUHoverDetail.getHover = function(id) {
    if (MRUHoverDetail.hovers[id]) {
        return MRUHoverDetail.hovers[id];
    }
    var hover = new MRUHoverDetail(id);
    MRUHoverDetail.hovers[id] = hover;
    return hover;
}

// static function to load the hover details
MRUHoverDetail.bulkLoad = function() {
    if (!MRUHoverDetail.sentRequest && MRUHoverDetail.loaderURL != null) {
        MRUHoverDetail.sentRequest = true;
        XBrowser.getHttpResponse(MRUHoverDetail.loaderURL,
            function(request) {
                MRUHoverDetail.response = request.responseText;
                // if a hover detail is already open then load it now
                if (MRUHoverDetail.openHover != null) {
                	MRUHoverDetail.hovers[MRUHoverDetail.openHover].load();
                }
            },
            function(request) {
                MRUHoverDetail.response = request.responseText;
                if (MRUHoverDetail.openHover != null) {
                	MRUHoverDetail.hovers[MRUHoverDetail.openHover].load();
                }
            }
        );
    }
}
// show the hover detail
MRUHoverDetail.prototype.show = function() {
    if (this.fadingOut) {
        clearTimeout(this.fadingOut);
        this.fadingOut = null;
	} else {
        var self = this;
	    this.fadingIn = setTimeout( function() { self.showNow(); }, MRUHoverDetail.SHOW_DELAY);
    }
}

MRUHoverDetail.prototype.showNow = function() {
    if (!MRUHoverDetail.sentRequest) {
    	if (MRUHoverDetail.loaderURL != null) {
            MRUHoverDetail.bulkLoad();
    	} else {
    		// we haven't loaded, and we have no URL to load from, so don't display anything.
    		// onunload should null out the URL, so this is mostly to prevent sending a request after
    		// the user navigates away from this page
    		return;
    	}
    }
	MRUHoverDetail.openHover = this.id;
	if (!this.loaded && MRUHoverDetail.response != null) {
		this.load();
	}
    this.hover.setStyle("display", "block");
    if (this.mruItem.currentStyle && XBrowser.userAgent.isIE6) {
        // something wrong with the offsetLeft calc for this in IE6, override it manually for now
        this.hover.iframe.style.left = this.hover.div.style.left;
    }
    this.mruItem.className = this.originalClass + " secondaryPalette";
    this.fadingIn = null;
}

// hide the hover detail
MRUHoverDetail.prototype.hide = function(id) {
    if (this.fadingIn) {
        clearTimeout(this.fadingIn);
        this.fadingIn = null;
    } else {
        var self = this;
        this.fadingOut = setTimeout(function() { self.hideNow(); }, MRUHoverDetail.HIDE_DELAY);
    }
}

MRUHoverDetail.prototype.hideNow = function() {
	MRUHoverDetail.openHover = null;
    this.hover.setStyle("display", "none");
    this.mruItem.className = this.originalClass;
    this.fadingOut = null;
}

// loads the mini detail from the responseText
MRUHoverDetail.prototype.load = function() {
    var startTag = "<" + this.id + ">";
    var endTag = "</" + this.id + ">";
    var start = MRUHoverDetail.response.indexOf(startTag);
    var end = MRUHoverDetail.response.indexOf(endTag);
    if (start != -1 && end != -1) {
    	this.hover.div.innerHTML = MRUHoverDetail.response.slice(start + startTag.length, end);
    	Util.evalScriptsUnderElement(this.hover.div);
    	this.loaded = true;
    }
}

var MOUSE_OVER_FADE_MAP = [];

/* This should be called from onMouseOver */
function addMouseOver(div, /*optional*/hotSpot){
  for (var i = 0; i < MOUSE_OVER_FADE_MAP.length; i++){
    if (MOUSE_OVER_FADE_MAP[i] === div){
      return;
    }
  }

  var inner;
  for (var i = 0; i < div.childNodes.length; i++){
    if (div.childNodes[i].className == MouseOverElement.DEFAULT_CLASS_INNER) {
      inner = div.childNodes[i];
      break;
    }
  }
  if (!inner) return;
  var foo;
  if (hotSpot){
    foo = new MouseOverFade(hotSpot, inner);
  } else {
    foo = new MouseOverFade(div, inner);
  }
  foo.handleMouseOver();
  MOUSE_OVER_FADE_MAP.push(div);
}

function MouseOverFade(hotSpot, divToFade){
  	this.mover = new MouseOverFadeHandler(hotSpot, divToFade, true);
  	
  	var self = this;
  	
  this.handleMouseOver = function(e){
    self.mover.fadeIn();
  };

  this.handleMouseOut = function(e){
    self.mover.fadeOut();
  };

  this.init();
}

MouseOverFade.prototype.init = function(){
    addEvent(this.mover.controller, 'mouseover', this.handleMouseOver, false);
    addEvent(this.mover.controller, 'mouseout', this.handleMouseOut, false);
    addEvent(this.mover.div, 'mouseover', this.handleMouseOver, false);
    addEvent(this.mover.div, 'mouseout', this.handleMouseOut, false);
};

function MouseOverFadeHandler(hotSpot, divToFade, saveOrigPos){
  this.controller = hotSpot
  this.div = divToFade;
  this.shim = new iframeShim(divToFade);
  this.saveOrigPos = saveOrigPos;

  var self = this;
  
  this.setPosition = function(object) {
  		if (!object){
  			object = self.shim;
  		}
		object.setStyle('display', 'block');
		if (self.saveOrigPos){
		     if (!self.origL){
		          self.origL = self.div.style.left;
		      } else {
		          object.setStyle('left', self.origL);
		      }
		}

        var calloutLeft = getOffsetLeft(self.div);
        var calloutRight = calloutLeft + self.div.offsetWidth;
        var windowRight = getScrollX() + getWindowWidth() - 15;

        if (calloutLeft < 0) {
            object.setStyle('left', "0");
        } else if (calloutRight > windowRight){
            object.setStyle('left', (self.div.offsetLeft - (calloutRight - windowRight) - 20) + "px");
        } 
        
        //Now the bottom
        if (self.saveOrigPos){
	        if (!self.origTop){
	        	self.origTop = self.div.style.top;
	        } else {
	        	object.setStyle('top', self.origTop);
	        }
        }
        
        var calloutTop = getObjY(self.div);
        var calloutBottom = calloutTop + self.div.offsetHeight;
        var windowBottom = getScrollY() + getWindowHeight() - 15; //15 for scrollbars


        if (calloutTop < 0){
        	object.setStyle('top', '0');
        } else if (calloutBottom > windowBottom ){
        	object.setStyle('top', (self.div.offsetTop - (calloutBottom - windowBottom) - 15) + 'px');
        } 
    }
    
  this.mover = new Fader(
    this.shim,
    function(object, currVal) { return object.getOpacity() <= 0; },
    function(object, currVal) {	 return object.getOpacity() >= 0.99; },
    30,
    function(currVal, sign) { return currVal += sign*0.2; },
    function(object, nextVal) { object.setOpacity(nextVal); },
    0,
    function(object) {object.setOpacity(0); object.setStyle('display', 'none');},
    function(object) {object.setOpacity(0.99); object.setStyle('display', 'block');},
	this.setPosition
  ); 
  
  this.fadeIn = function(){
  	self.mover.fadeIn();
  }
  
  this.fadeOut = function(){
  	self.mover.fadeOut();
  }
}
function Attachments() {}

var hasPendingAttachments = false;

function addPendingAttachment(attId) {
   document.getElementById(Activity.pNEW_ATTACHMENTS).value=document.getElementById(Activity.pNEW_ATTACHMENTS).value + attId + ',';
   hasPendingAttachments = true;
   displayAttachmentWarning(true);
}

function removePendingAttachment(attId, listDomId) {
   var att = document.getElementById(Activity.pNEW_ATTACHMENTS);
   if(att) {
       var attStr = new String(att.value);
       att.value = attStr.replace(attId +',', '');
       hasPendingAttachments = (att.value.length >= 15);
       if(!hasPendingAttachments) {
           displayAttachmentWarning(false);
       }
       var extraParamNames = null;
       var attIds = document.getElementById(Activity.pNEW_ATTACHMENTS);
       if (attIds) {
           extraParamNames = new Array(attIds.id);
       }
       var rl = sfdcPage.getRelatedListById(listDomId);
       if(rl) {
           rl.refresh(extraParamNames, attIds ? new Array(attIds.value) : null);
       }
   }
}

function displayAttachmentWarning(showWarning){
    var aw = document.getElementById(Activity.pATT_WARNING);
    if (aw) {
        if (showWarning){
            aw.style.display='block';
        } else {
            aw.style.display='none';
        }
    }

}

/**
 * attachments is a comma-separated list of ids. (stupid, yes.)
 * returns object based on PromoteTransientAttachments.formatResults().
 */
Attachments.prototype.promoteAttachments = function(sessionId, parentId, attachments, checkSize){

    var promotionResult = null;

    if (sessionId && parentId && (attachments || checkSize)){

        var qs = new QueryString("");
        qs.add("sid", sessionId);
        qs.add("pid", parentId);
        qs.add("att", attachments);
        if (checkSize){
            qs.add("check", "1");
        }

        var promoteURL = UserContext.getUrl("/servlet/promoteAtt") + qs.toString();
        var response = DesktopAjax.prototype.doGet(promoteURL);
        if (response){
            promotionResult = eval("(" + response + ")");
        }
        
    }
    
    return promotionResult;
}

var TimePickerInputElement = {};

// onfocus to the input field show the picker and clears the field if HH:MM text persent
TimePickerInputElement.FocusInput = function (inputId) {
    var inputElement = document.getElementById(inputId);

    inputElement.className = "timeInputActive";

	// show blank input value if value is HH:MM when the field is onFocus
    if (inputElement.value == TimePickerInputElementConstants.EMPTY_TIME_STANDIN) {
        inputElement.value = "";
        inputElement.select();
    } else if (inputElement.value != '') {
        inputElement.select();
    }
}

TimePickerInputElement.BlurInput = function (inputId) {
    var inputElement = document.getElementById(inputId);

    //if the field is empty populate it with HH:MM value 
    if (inputElement.value == '') {
        inputElement.className = "timeInputInactive";
        inputElement.value = TimePickerInputElementConstants.EMPTY_TIME_STANDIN;
    }
}


//  Javascript functionality for the tagging setup.
//

var TagSettingsPage = function(){}

// Static function used by the tagging setup page
TagSettingsPage.toggleTags = function(elemId, item) {
  var section = document.getElementById(elemId);
  if (item.checked) {
    section.style.display='block';
  }
  else {
    section.style.display='none';
  }
}

/**
 * JS functionality for the Google Talk sidebar gadget (see SidebarModuleGoogleTalkElement.java)
 * @author byang
 * @since 152
 **/
function GoogleTalk(gadget, resizeBar, gadgetUrl) {
    this.gadget = gadget;
    this.gadgetUrl = gadgetUrl;
    this.resizeBar = resizeBar;
    this.resizeBarOrigHeight = resizeBar.style.height;
    this.mouseStatus = 'up';
    this.popupWindow = function() {};
    this.showOnExitOverlay = true;

    var cookieHeight = getCookie(GoogleTalkConstants.HEIGHT_COOKIE);
    this.expandedHeight = cookieHeight == null || cookieHeight == 0 ?
        GoogleTalkConstants.EXPANDED_HEIGHT : cookieHeight;

    // For some reason, in IE6, if the talk gadget is loaded before bodyOnLoad() is executed,
    // the JS gets crossed-up and nothing works.  So, the loading is deferred until GoogleTalk
    // is registered, which happens in bodyOnLoad() (see SidebarGoogleTalkGadget.java)
    if (this.gadget.height != GoogleTalkConstants.COLLAPSED_HEIGHT) {
        this.gadget.src = this.gadgetUrl;
    }

    /**
     * Shows/hides the gadget.  Also shows/hides the resize bar
     **/
    GoogleTalk.prototype.toggle = function(hiddenLinks, shownLinks) {
        var isExpanding = this.gadget.height == GoogleTalkConstants.COLLAPSED_HEIGHT;

        this.gadget.height = (isExpanding ? this.expandedHeight : GoogleTalkConstants.COLLAPSED_HEIGHT);

        // this is important: by blanking out the source of the iframe, we disconnect from Google Talk
        if (isExpanding) {
            this.gadget.src = this.gadgetUrl;
        } else {
            this.gadget.src = UrlMap.getURL("BlankPage");
        }

        // set a cookie denoting that the user has collapsed or expanded the gadget
        var expires = new Date();
        expires.setTime(expires.getTime() + (3650*24*60*60*1000));
        setCookie(GoogleTalkConstants.COLLAPSED_COOKIE, isExpanding ? '0' : '1', expires);

        // toggle the links that are shown
        if (isExpanding) {
            shownLinks.style.display = 'inline';
            hiddenLinks.style.display = 'none';
        } else {
            shownLinks.style.display = 'none';
            hiddenLinks.style.display = 'inline';
        }

        // hide the resize bar
        this.resizeBar.style.display = isExpanding ? 'block' : 'none';

        // force resize handling in the console
        if (typeof resizeFramesToFit != 'undefined') {
            resizeFramesToFit();
        }
    }

    /**
     * Resizes the gadget while the user is dragging
     **/
    GoogleTalk.prototype.resize = function(e) {
        if(this.mouseStatus == 'down'){
            var curevent = (typeof event == 'undefined' ? e : event);
            // get new mouse position and calculate movement in pixels
            var newPos = curevent.clientY;
            var newHeight=parseInt(this.curHeight + parseInt(newPos - this.curPos));
            //conditional to set minimum height to 5
            newHeight = ( newHeight < GoogleTalkConstants.MIN_EXPANDED_HEIGHT ? GoogleTalkConstants.MIN_EXPANDED_HEIGHT : newHeight);
            //set the new height of the div
            this.gadget.height = newHeight;
        }
    }

    /**
     * Initiates resizing
     **/
    GoogleTalk.prototype.setStartDrag = function(e) {
        //for handling events in ie vs. w3c
        var curevent = (typeof event == 'undefined' ? e : event);

        // some trickery to allow the user ample space to drag their mouse without killing the drag by mousing over the gadget
        this.resizeBar.style.height = '39px';
        var newHeight = this.gadget.height - 35;
        this.gadget.height = newHeight > GoogleTalkConstants.MIN_EXPANDED_HEIGHT ? newHeight : GoogleTalkConstants.MIN_EXPANDED_HEIGHT ;

        //sets mouse flag as down
        this.mouseStatus = 'down';
        //gets position of click
        this.curPos = curevent.clientY;

        this.curHeight = parseInt(this.gadget.height);

        // make the entire page area register the resize events
        document.body.onmousemove = function(e) { GoogleTalk.prototype.theGadget.resize(e); };
        document.body.onmouseup = function(e) { GoogleTalk.prototype.theGadget.setEndDrag(e); };
    }

    /**
     * Ends resizing
     **/
    GoogleTalk.prototype.setEndDrag = function(e) {
        if(this.mouseStatus == 'down') {
            //sets mouse flag as down
            this.mouseStatus='up';
            this.resizeBar.style.height = this.resizeBarOrigHeight;

            var expires = new Date();
            expires.setTime(expires.getTime() + (3650*24*60*60*1000));
            setCookie(GoogleTalkConstants.HEIGHT_COOKIE, this.gadget.height, expires);

            this.expandedHeight = this.gadget.height;
        }
    }

    GoogleTalk.prototype.popout = function(e) {
        //if (typeof(this.popupWindow.focus) != 'undefined' && !this.popupWindow.closed) {
            //this.popupWindow.focus();
        //} else {
            this.popupWindow = window.open(this.gadgetUrl, 'gTalkPopup', 'toolbar=no,width=300,height=600,resizable=yes,toolbars=no,status=no,scrollbars=yes,menubar=no,directories=yes,location=yes,dependant=no', false, false);
        //}
    }


    // used in bbutils.js
    GoogleTalk.prototype.hide = function() {
        this.gadget.height = 0;
    }

    GoogleTalk.prototype.show = function() {
        this.gadget.height = this.expandedHeight;
    }

    GoogleTalk.prototype.isShown = function() {
        return this.gadget.height != GoogleTalkConstants.COLLAPSED_HEIGHT;
    }
}

ColorInput = function (id) {
    this.id = id;
    this.box = document.createElement("div");
    this.box.innerHTML = "<span></span>"; // Get IE to respect the height set for the DIV
    this.input = document.getElementById(id);

    var self = this;
    this.handleChange = function (e) {
        self.formatInput();
        self.updateColor();
    };

    this.init();
};

ColorInput.prototype.updateColor = function () {
    var color = this.input.value;
    if (color.match(/^(#[0-9a-f]{6})$/i)) {
        delStyleClass(this.box, ColorInputConstants.ERROR_COLOR_BOX_CSS);
        this.box.style.backgroundColor = color;
    } else {
        this.box.style.backgroundColor = "#FFFFFF";
        addStyleClass(this.box, ColorInputConstants.ERROR_COLOR_BOX_CSS);
    }
};

ColorInput.prototype.formatInput = function () {
    // Correct missing #
    var color = this.input.value;
    if ("#" != color.charAt(0) && 6 == color.length) {
        color = "#" + color;
    }

    // Uppercase
    color = color.toUpperCase();

    // Convert 3 hex to 6 hex
    if (color.match(/^#[0-9a-f]{3}$/i)) {
        var r = color.charAt(1);
        var g = color.charAt(2);
        var b = color.charAt(3);
        color = '#' + r + r + g + g + b + b;
    }

    this.input.value = color;
};

ColorInput.prototype.init = function () {
    // Prep box
    addStyleClass(this.box, ColorInputConstants.COLOR_BOX_CSS);
    this.updateColor();
    this.input.parentNode.insertBefore(this.box, this.input);

    // Add handler
    var self = this;
    addEvent(this.input, "change", this.handleChange, false);
    var handlePick = function (e) {
        ColorPicker.pick(self.id, e);
    };
    addEvent(this.box, "click", handlePick, false);
    addEvent(this.input, "focus", handlePick, false);
    addEvent(this.input, "click", ColorPicker.cancelHide, false);

    // Add a reference to functions
    this.input.updateColor = function() {self.updateColor(); };
};

/**
 *  Javascript object for BannerElement.
 *  @author mooney
 *  @since 144
 *  @param id The id of the banner div
 */ 
function Banner(id) {
    this.bannerDiv = document.getElementById(id);
    this.bannerY = Banner.BANNER_END;
    this.fadingIn = null;
    this.fadingOut = null;
    this.clicked = false;
    var self = this;
    if (getCookie("sawBanner") != id) {
        this.shim = new iframeShim(this.bannerDiv);
        addEvent(this.bannerDiv, 'click', function() { self.click(); }, false);
        //addEvent(this.bannerDiv, 'mouseover', function() { self.interrupt(); }, false);
        //addEvent(this.bannerDiv, 'mouseout', function() { self.goAway(); }, false);
        this.shim.setStyle('display', 'block');
        this.fadeIn();
        //this.goAway();
    }
}

Banner.BANNER_END = -50;
Banner.BANNER_START = 0;
Banner.BANNER_STEP = -5;
Banner.BANNER_STEP_DELAY = 40;
Banner.BANNER_DELAY = 4000;
Banner.COOKIE_LIFE = 90;

// the user clicked on the banner, so make it go away right now and not come back for 90 days
Banner.prototype.click = function() {
    if (this.fadingIn) {
        clearTimeout(this.fadingIn);
        this.fadingIn = null;
    }
    this.clicked = true;
    var expires = new Date();
    expires.setDate(expires.getDate() + Banner.COOKIE_LIFE);
    setCookie("sawBanner", this.bannerDiv.id, expires);
    this.fadeOut();
}

// sets the delay for the banner to go away
Banner.prototype.goAway = function() {
    if (!this.clicked) {
        var self = this;
        this.fadingOut = setTimeout(function() { self.fadeOut(); }, Banner.BANNER_DELAY);
    }
}

// called when the user hovers on the banner, interrupts the call to hide it and fades in
Banner.prototype.interrupt = function() {
    if (!this.clicked && this.fadingOut) {
        var self = this;
        clearTimeout(this.fadingOut);
        this.fadingOut = null;
        this.fadingIn = setTimeout(function() { self.fadeIn(); }, 0);
    }
}

// slides the banner off the screen
Banner.prototype.fadeOut = function() {
    if (this.fadingOut) {
        clearTimeout(this.fadingOut);
        this.fadingOut = null;
    }
    if (this.bannerY > Banner.BANNER_END) {
        var self = this;
        this.bannerY += Banner.BANNER_STEP;
        this.shim.setStyle('top', this.bannerY + 'px');
        this.fadingOut = setTimeout(function() { self.fadeOut(); }, Banner.BANNER_STEP_DELAY);
    }
}

// slides the banner onto the screen
Banner.prototype.fadeIn = function() {
    if (this.fadingIn) {
        clearTimeout(this.fadingIn);
        this.fadingIn = null;
    }
    if (this.bannerY < Banner.BANNER_START) {
        var self = this;
        this.bannerY -= Banner.BANNER_STEP;
        this.shim.setStyle('top', this.bannerY + 'px');
        this.fadingIn = setTimeout(function() { self.fadeIn(); }, Banner.BANNER_STEP_DELAY);
    }
}

/**
	@param object		required. object, The object to be faded
	@param testMin		required. function(object, currVal), should return true if the object is completely faded out
	@param testMax  	required. function(object, currVal), should return true if the object is completely faded in
	@param timestep 	required. number, The interval between steps, in milliseconds
	@param nextStep		required. function(currVal, sign), given the current value and a direction, return the next value.
								  sign will be positive for fadeIn, negative for fadeOut.  Any return value will be saved 
								  to currVal.
	@param increment	requried. function(object, nextVal) the increment function.  Should change the property
							      of the object to nextVal (which is the value returned by nextStep).  
	@param initVal		optional. number, an initial value for currVal.
	@param finalMin		optional. function(object),  Will be called at the end of fadeOut
	@param finalMax		optional. function(object), Will be called at the end of fadeIn
    @param startIn      optional. function(object), Wtill be called before a jumpIn or fadeIn
*/
function Fader(object, testMin, testMax, timestep, nextStep, increment, initVal, finalMin, finalMax, startIn) {	
	var self = this;
	
	if (!(object && testMin && testMax && timestep && nextStep && increment)){
		//required arguments
		return null;
	}
	
	this.object = object;
	this.testMin = testMin;
	this.testMax = testMax;
	this.timestep = timestep;
	this.nextStep = nextStep;
	this.increment = increment;
	this.currVal = initVal;
	this.finalMin = finalMin;
	this.finalMax = finalMax;
	this.startIn = startIn;
	
	this.inId = -1;
	this.outId = -1;
	
	this.position = 'out';
	
	this.fadeIn = function(){
		if (self.startIn) self.startIn(this.object);
		if (self.outId >= 0){
			clearInterval(self.outId);
			self.outId = -1;
		}
		if (this.inId < 0){
			self.inId = setInterval(fadeInCaller, self.timestep);
			self.position = 'moving_in';
 		} 
	}
	
	this.fadeOut = function() {
		if (self.inId >= 0){
			clearInterval(self.inId);
			self.inId = -1;
		}
		if (self.outId < 0){
			self.outId = setInterval(fadeOutCaller, self.timestep);
			self.position = 'moving_out';
 		} 
	}
	
	function fadeInCaller(){
		self.fadeInHelp();
	}
	
	function fadeOutCaller(){
		self.fadeOutHelp();
	}
	
	this.isMoving = function() {
		return (this.inId >= 0 || this.outId >= 0);
	}
	
	/*
	return one of 'in', 'out', 'moving_in', 'moving_out', or 'stopped'
	*/
	this.getPosition = function(){
		return self.position;
	}
}

Fader.prototype.fadeInHelp = function() {
	var nextVal = this.nextStep(this.currVal, 1);
	if (this.testMax(this.object, nextVal)){
		var finalVal = this.finalMax && this.finalMax(this.object);
		if (typeof finalVal == "number") { this.currVal = finalVal; }
		clearInterval(this.inId);
		this.inId = -1;
		this.position = 'in';
		return;
	} 
	this.increment(this.object, nextVal);
	this.currVal = nextVal;
};

Fader.prototype.fadeOutHelp = function() {
	var nextVal = this.nextStep(this.currVal, -1);
	if (this.testMin(this.object, nextVal)){
		var finalVal = this.finalMin && this.finalMin(this.object);
		if (typeof finalVal == "number") { this.currVal = finalVal; }
		clearInterval(this.outId);
		this.outId = -1;
		this.position = 'out';
		return;
	}
	this.increment(this.object, nextVal);
	this.currVal = nextVal;
};

Fader.prototype.stopFade = function() {
	if (this.inId >= 0){
		clearInterval(this.inId);
		this.inId = -1;
	}
	if (this.outId >= 0){
		clearInterval(this.outId);
		this.outId = -1;
	}
	this.position = 'stopped';
};

Fader.prototype.jumpIn = function() {
	if (this.startIn) this.startIn(this.object);
	var newCur = null;
	if (this.finalMax) {newCur = this.finalMax(this.object); }
	if (newCur !== null) { this.currVal = newCur;}
	this.position = 'in';
};

Fader.prototype.jumpOut = function() {
	var newCur = null;
	if (this.finalMin) {newCur = this.finalMin(this.object);}
	if (newCur !== null) { this.currVal = newCur; }
	this.position = 'out'
};
	
function LMACheckboxesManager() {
	var self = this;
	
	this.radios = document.getElementsByName(DeveloperSettings.LICENSE_MGR_CHOICE_STR);
	
	this.divNames = [];
	for (var i = 0; i < arguments.length; i++){
		this.divNames[i] = arguments[i];
	}
	
	this.onClickHandler = function(e){
		self.setVisibility(getEventTarget(getEvent(e)).value);
	}
	
	for (var i = 0; i < this.radios.length; i++){
		addEvent(this.radios[i], 'click', this.onClickHandler, false);
		if (this.radios[i].checked){
			this.setVisibility(this.radios[i].value);
		}
	}
}

LMACheckboxesManager.prototype.setVisibility = function(radioName){
	for (var i = 0; i < this.divNames.length; i++){
		document.getElementById(this.divNames[i] + DeveloperSettings.DIV_SUFFIX).style.display = 
			(this.divNames[i] === radioName ? 'block' : 'none');
	}
}
/**
 * MenuButton (mutton) basically mimics a SelectElement. In accessible mode it is a SelectElement.
 *
 * @author jmooney
 * @since 148
 */
function MenuButton(id, hasDefaultAction) {
    this.id = id;
    this.hasDefaultAction = hasDefaultAction;
    if (this.id) {
        if (this.hook_isAccessibleMode()) {
            this.initAccessibilityMode(this.id);
            return;
        }
        this.parentDiv = document.getElementById(id);
        this.buttonDiv = document.getElementById(id + MenuButtonElement.BUTTON);
        this.menuDiv = document.getElementById(id + MenuButtonElement.MENU);
        this.buttonWidth = MenuButton.DEFAULT_ARROW;
        this.shim = new iframeShim(this.menuDiv);
        var self = this;
        addEvent(document, 'click', function(e) {self.hideOthers(e); }, false);
        addEvent(document, 'keydown', function(e) { self.handleKeyPress(e); }, false);
        addEvent(this.parentDiv, 'click', function(e) { self.handleDivClick(e); }, false);
        addEvent(this.menuDiv, 'click', function(e) { return self.handleMenuClick(e); }, false);
    }
}

MenuButton.DEFAULT_ARROW = 17;

// checks for a default action and opens or closes the menu
MenuButton.prototype.handleDivClick = function(e) {
    if (this.hasDefaultAction) {
        // determine if the click was on the arrow or the text
        var x = 0;
        if (e.offsetX) { // IE
            x = e.offsetX - e.srcElement.offsetLeft;
        } else if (e.layerX) { // FF
            var elem = e.target;
            x = e.pageX - getObjX(e.target);
        }
        if (this.defaultActionCondition(x, e)) {
            this.defaultAction();
            return;
        }
    }
    if (XBrowser.getCurrentStyle(this.menuDiv, "display") == "none") {
        this.show();
    } else {
        this.hide();
    }
}

MenuButton.prototype.handleMenuClick = function(e){
	this.hide();
	eventCancelBubble(e);
}

MenuButton.prototype.defaultActionCondition = function (xLocation, event) {
    return (xLocation < this.buttonDiv.offsetWidth - this.buttonWidth);
}

MenuButton.prototype.hook_isAccessibleMode = function() {
    return UserContext.isAccessibleMode;
}

MenuButton.prototype.defaultAction = function() {
    // clicked the text, do the default
    var link = this.menuDiv.childNodes[0];
    if (link.target) {
        // if the link has a target look for it by name
        var targets = document.getElementsByName(link.target);
        // target could be another window, only set it if its a frame
        if (targets && targets[0].src) {
            targets[0].src = link.href;
        } // else nothing we can do
    } else {
        navigateToUrl(link.href);
    }
}

// show the menu
MenuButton.prototype.show = function() {
    this.shim.setStyle("display", "block");
    this.position();
    this.show_hook();
}

MenuButton.prototype.show_hook = function() {}

MenuButton.prototype.getMenuWidth = function() {
    return this.buttonDiv.offsetWidth - 2; // subtract 2 for the borders
}

// positions the menu correctly
MenuButton.prototype.position = function() {
    this.menuDiv.style.width = "";
    // first we set the width so that nothing wraps
    var width = this.getMenuWidth();
    for (var i = 0; i < this.menuDiv.childNodes.length; i++) {
        var node = this.menuDiv.childNodes[i];
        if (node.nodeType == Node.ELEMENT_NODE) {
            if (node.offsetWidth > width) {
                width = node.offsetWidth;
            }
        }
    }
     this.shim.setStyle("width", width + "px");
    // if the parent div is inline, position the menu below the button
    if (XBrowser.getCurrentStyle(this.parentDiv, "display") == "inline") {
        this.parentDiv.style.position = "relative";
        var y = this.buttonDiv.offsetHeight;

        if (this.parentDiv.currentStyle) {
            for (var i = 0; i < this.menuDiv.childNodes.length; i++) {
                var node = this.menuDiv.childNodes[i];
                if (node.nodeType == Node.ELEMENT_NODE) {
                    node.style.width = width + "px";
                }
            }
        }
        this.shim.setStyle("top", y + "px");
    }
}

// hide the menu
MenuButton.prototype.hide = function(ignoreHideHook) {
    if (XBrowser.getCurrentStyle(this.menuDiv, "display") != "none") {
        this.shim.setStyle("display", "none");
        this.parentDiv.style.position = "";
        if (!ignoreHideHook) {
            this.hide_hook();
        }
    }
}

MenuButton.prototype.hide_hook = function() {}

// hide if we aren't the target of the event
MenuButton.prototype.hideOthers = function(e) {
    var target = getEventTarget(e);
    if (target != this.buttonDiv && target != this.parentDiv) {
        this.hide(true);
    }
}

// esc closes the menu
MenuButton.prototype.handleKeyPress = function(e) {
    var key = e.keyCode;
    if (key == KEY_ESC) {
        this.hide();
    }
}

// add an options to a mutton, you should call position after adding options to resize the menu if it is open
MenuButton.prototype.addOption = function(disp, href, css, target) {
    // can't do this in accessible mode
    if (!this.hook_isAccessibleMode()) {
        var link = document.createElement("a");
        if (css) link.className = css;
        if (target) link.target = target;
        link.href = href;
        link.innerHTML = disp;
        this.menuDiv.appendChild(link);
    }
}

MenuButton.prototype.initAccessibilityMode = function(id) {
    var go = document.getElementById(id + MenuButtonElement.GO_BUTTON);
    addEvent(go, 'click', function() {
        var select = document.getElementById(id + MenuButtonElement.SELECT);
        var where = select.options[select.selectedIndex].value;
        if (where != "")
            navigateToUrl(where);
    }, false);
}

/**
 *  ActivityReminder, the main class for the popup timer & window logic.
 *
 *  @author beidson
 *  @since 144
 */

/**
 * There's only 1 reminder per page, so ActivityReminder is
 * all static methods.
 */
var ActivityReminder = {};

// Used for primitive inter-window communication (from popup to any other main sfdc window):
ActivityReminder._REMINDER_COOKIE = 'reminderCookie';
ActivityReminder._REMINDER_INTERVAL = 5000;

// Used for primitive inter-window communication (to prevent dup popups from multiple windows)
ActivityReminder._LOCK_COOKIE = 'reminderLockCookie';

/**
 * Initialize the popup timer.<b>
 * If isPopup is set, it is for the reminder popup itself,
 * which does some extra setup.
 */
ActivityReminder.initialize = function(popupSchedule, isPopup, isRefresh) {
    // If isPopup, we're the popup window itself:
    ActivityReminder._isPopup = isPopup;

    ActivityReminder._launched = new Date().getTime();
    ActivityReminder._currentSchedule = popupSchedule;
    ActivityReminder._checkScheduleUpdates();

    if (ActivityReminder._isPopup) {
        if (!isRefresh) {
            ActivityReminder._isBlur = false;
            addEvent(window, 'focus', ActivityReminder._wasFocused, false);
            addEvent(window, 'blur', ActivityReminder._wasBlured, false);
            setTimeout('ActivityReminder._pseudoFlash()', 500);
        }

        // Start the countdown:
        ActivityReminder._popupCountdown();

        ActivityReminder._setupMeetingSummary();

        ActivityReminder._setupSnoozeDismiss();

        ActivityReminder._updateSchedule();

        ActivityReminder._closeIfEmpty();

        // IE/CSS limitation:
        window.onresize = ActivityReminder._resizeToFitHorizontalChange;
        ActivityReminder._resizeToFitHorizontal();

        // Can get out of sync:
        updateToggleAllBox(document.forms.reminder, 'ids');
    }
}

ActivityReminder._checkScheduleUpdates = function() {
    // Check if another window, including the popup itself, refreshed the schedule cookie
    // (This is particularly important after a 'snooze' where the user may not actually
    // refresh the main window, but the user does close the reminder window)
    var rc = getCookie(ActivityReminder._REMINDER_COOKIE);
    // Parse it:
    if (rc) {
        ActivityReminder._currentSchedule = rc.split(',');
        // we (someone) got it, so delete just after the interval so other windows can get it:
        setTimeout("deleteCookie(ActivityReminder._REMINDER_COOKIE)", ActivityReminder._REMINDER_INTERVAL);
    }
    // See if any reminders went off:
    var now = new Date().getTime();
    var anyScheduled = false;
    var kept = new Array();
    for (var i=0; i<ActivityReminder._currentSchedule.length; i++) {
        if (Number(ActivityReminder._currentSchedule[i]) <= (now + ActivityReminder._REMINDER_INTERVAL * 2)) {
            // Now that the meeting is < the polling interval away, go ahead & schedule it directly:
            if (!anyScheduled) {
                ActivityReminder._schedule(ActivityReminder._currentSchedule[i]);
                anyScheduled = true;
            }
        } else {
            kept.push(ActivityReminder._currentSchedule[i]);
        }
    }
    // And clean up:
    ActivityReminder._currentSchedule = kept;

    setTimeout("ActivityReminder._checkScheduleUpdates()", ActivityReminder._REMINDER_INTERVAL);
}


ActivityReminder._schedule = function(time) {
    var milliseconds = Number(time) - new Date().getTime();
    // Don't schedule negative reminders, schedule them for now:
    if (milliseconds < 2000) {
        milliseconds = 2000; // 2s is attempt to allow non-standard browser hooks a chance to register prior to firing the popup (bug #206335)
    }
    if (ActivityReminder._isPopup) {
        milliseconds += 10000; // The popup can refresh itself, but if there's a main window open,
                               // give it a 10 second head start to actually do the refresh.
    }
    var timeSinceStart = Number(time) - ActivityReminder._launched;
    if (!ActivityReminder._isPopup && timeSinceStart <= (-2 * 60 * 60 * 1000)) {
        // If the reminder is more than two hours in the past, there's no point in re-checking the event before showing the popup.
        // More importantly, for users with popup blocking (who will ALWAYS have lots of past reminders),
        // we don't want to hit the refresh page... instead it'll just attempt to launch the popup,
        // which will get blocked.

        // We use two hours buffer because of pages views the following scenario:
        // 1) See reminder popup
        // 2) Dismiss all (or snooze, etc.)
        // 3) Hit back button to a previously viewed SFDC page
        // 4) Popup window opens/closes (because the previous page had the old reminder schedule)
        // The doesn't totally solve the issue, but it mitigates it --- the previous page view must have been > 2 hrs. ago.
        setTimeout("ActivityReminder._showPopup(false)", milliseconds);
    } else {
        setTimeout("ActivityReminder._showPopupIfRequired()", milliseconds);
    }
}

ActivityReminder._updateSchedule = function() {
    var scheduleCookieVal = ActivityReminder._currentSchedule.join(',');
    // Send it via cookie (all SFDC windows should get this):
    var dieDate = new Date(new Date().getTime() + ActivityReminder._REMINDER_INTERVAL * 2);
    setCookie(ActivityReminder._REMINDER_COOKIE, scheduleCookieVal, dieDate);
}

// Shows the popup (if necesary; may have been cancelled, etc.)
ActivityReminder._showPopupIfRequired = function() {
    var fn = function(responseStr) {
        // Check that we needed to popup:
        var txt = responseStr.indexOf(ActivityReminderConstants.REMINDERS_OK);
        if (txt < 0) {
            // Nope, it didn't give the signal.
            txt = responseStr.indexOf(ActivityReminderConstants.REMINDERS_NONE);
            if (txt < 0) {
                // Didn't get the signal at all... something wrong on the server, most likely a session timeout.
                // Just show the popup which will show the login page:
                ActivityReminder._showPopup();
            }
            // In we got the none signal, there are no events now; it was cancelled, just do nothing.
        } else {
            // Everything normal, show the popup
            ActivityReminder._showPopup();
        }
    };
    // Do a quick check to see if we still really need to popup:
    // (ideally this could be combined with the call to
    // display the page)
    var at = new Date().getTime();
    makeAjaxRequest(UrlMap.convertClassNameToUrl(ActivityReminderRefreshPage.pCLASS_NAME) + '?at=' + at, fn);
}

ActivityReminder._showPopup = function(isTest) {
    // Crude (semi reliable) lock to reduce chance of 2 browser windows opening 2 popups
    // (open with a name can still create dup windows if called simultaneously)
    var rc = getCookie(ActivityReminder._LOCK_COOKIE);
    if (rc) {
        // Already being shown.
        return;
    }
    var dieDate = new Date(new Date().getTime() + 5000); // expire quickly.
    setCookie(ActivityReminder._LOCK_COOKIE, 'shown', dieDate);

    // Ok, open the popup (or refresh the already-open one):
    var locval = isFirefox ? 'yes' : 'no'; // firefox changes the title if we don't show a location bar.
    var at = new Date().getTime();
    var teststr = isTest==true ? '&test=1' : '';
    var useScrollbars = (isNetscape && !isIE) ? 'yes' : 'no';
    var height = 320;
    if (isNetscape && isIE) height += 40; // Netscape/IE popup windows come up shorter for whatever reason.
    var parentWin = window.parent; // for desktop pages.
    var win = parentWin.open(UrlMap.convertClassNameToUrl(ActivityReminderPage.pCLASS_NAME) + '?at=' + at + teststr,
        'Reminder',
        'width=450,height=' + height + ',status=no,location=' + locval + ',dependent=no,resizable=yes,toolbar=no,directories=no,menubar=no,scrollbars=' + useScrollbars,
        false);
    var opened = win && !win.closed;
    // Note: firefox ignores status=no for security reasons...
    if (isTest && !opened) {
        // popup blocking.
        alert(LC.getLabel("Page_ActivityReminder", "popup_blocked"));
        return;
    }
    if (opened) {
        // for re-opens, need to pop to the front. Would like to flash, but doesn't seem to be a way.
        win.focus();
    }
}

ActivityReminder._popupCountdown = function() {
    // Update the remaining/overdue time display:
    var now = new Date().getTime();
    for (var i=0;;i++) {
        var el = document.getElementById(ActivityReminderConstants.DUE_MINUTES_ID + i);
        if (!el) {
            break;
        }
        var time = el.getAttribute(ActivityReminderConstants.DUE_TIME_ATTR);
        if (time != 0) {
            var away = time - now;
            ActivityReminder._updateTime(el, away);
        }
    }

    // Snooze options may have changed:
    ActivityReminder._enableSnoozeOptions();

    // refresh the countdown every 30 seconds.
    setTimeout("ActivityReminder._popupCountdown()", 30000);
}

// Updates 1 reminder due in field with the proper
// text for the current due in value.
ActivityReminder._updateTime = function(el, awayMillis) {
    var awayMins = Math.round(awayMillis / (1000*60));
    var textNode = el.firstChild;
    var overDue;
    if (awayMins < 0) {
       overDue = true;
       awayMins = -awayMins;
    } else {
       overDue = false;
    }

    var msg = ActivityReminder._formatDuration(awayMins, overDue);
    if (overDue) {
        msg = LC.getLabel("Page_ReminderSettings", "overdue", msg);
    }
    textNode.nodeValue = msg;
}

ActivityReminder._formatDuration = function(awayMins, overDue) {
    if (awayMins >= 60) {
        var awayHours = overDue ? Math.floor(awayMins / 60) : Math.ceil(awayMins / 60);
        if (awayHours >= 24) {
            var awayDays = Math.floor(awayHours / 24);
            if (awayDays == 1) {
                return LC.getLabel("Page_ReminderSettings", "day", awayDays);
            } else {
                return LC.getLabel("Page_ReminderSettings", "days", awayDays);
            }
        } else {
            if (awayHours == 1) {
                return LC.getLabel("Page_ReminderSettings", "hour", awayHours);
            } else {
                return LC.getLabel("Page_ReminderSettings", "hours", awayHours);
            }
        }
    } else {
        if (awayMins == 1) {
            return LC.getLabel("Page_ReminderSettings", "minute", awayMins);
        } else {
            return LC.getLabel("Page_ReminderSettings", "minutes", awayMins);
        }
    }
}

// Shows an activity link in the opener (if it still exists)
// or a new window.
ActivityReminder.showLink = function(url) {
    ActivityReminder._stopFlash = true; // Just kill flashing if user has clicked here.
    var openerClosed = true;
    try {
        // IE throws when accessing closed when opener gone.
        openerClosed = !window.opener || window.opener.closed || window.opener==window;
    } catch (e) {
    }
    if (openerClosed) {
        window.open(url, null, '', false);
    } else {
        // See if we're on a desktop.
        var mainFrame = window.opener.document.getElementById('mainFrame');
        if (mainFrame && mainFrame.tagName == 'IFRAME') {
            // Not available: showLoading('mainLoader', mainFrame);
            mainFrame.src = url + '?' + Desktop.IS_DESKTOP + '=mn';
        } else {
            window.opener.location = url;
        }
    }
}

// If there are no more reminders left after snooze/dismiss,
// then close the window.
ActivityReminder._closeIfEmpty = function() {
    var ct = 0;
    for (var i=0;;i++) {
        var item = document.getElementById("ids" + i);
        if (item) {
            ct++;
        } else {
            break;
        }
    }
    if (!ct) {
        // no more remain (dismiss 10ms later, o.w. form won't submit)
	    setTimeout("window.close()", 10);
    }
}

ActivityReminder._setupMeetingSummary = function() {
    // Mouse over any row selects the meeting summary:
    var r = getElementsByClassName('dataRow');
    for (rownum in r) {
        var row = r[rownum];
        var makeHandler = function(rn) {
            return function(event) {
                // The global handler, below, will
                // default the selection (when the
                // mouse isn't over a row).
                eventCancelBubble(event); // stop it.
                ActivityReminder._displayMeeting(rn);
            }
        };
        addEvent(row, 'mouseover', makeHandler(rownum));
    }
    var reminderForm = document.getElementById(ActivityReminderConstants.REMINDER_ID);
    var defaultSelector = function(event) {
        ActivityReminder._displayMeeting(); // no args.
    }
    // When the mouse isn't over one of the rows, have
    // it select the default (checked) one:
    addEvent(reminderForm, 'mouseover', defaultSelector);

    // Do initial selection:
    ActivityReminder._displayMeeting();
}

ActivityReminder._displayMeeting = function(rownum) {
    // If rownum not specified, use the first selected checkbox
    if (typeof rownum == 'undefined') {
        for (var i=0; ;i++) {
            var sel = document.getElementById("ids" + i);
            if (!sel) {
                rownum = 0; // just pick the first one, consistent w/ the initial display.
                break;
            }
            if (sel.checked) {
                rownum = i;
                break;
            }
        }
    }
    for (var i=0; ;i++) {
        var summary = document.getElementById(ActivityReminderConstants.SUMMARY_ID + i);
        if (!summary) {
            break;
        }
        summary.style.display = i==rownum ? 'block' : 'none';
    }
}

ActivityReminder._setupSnoozeDismiss = function() {
    for (var i=0; ;i++) {
        var sel = document.getElementById("ids" + i);
        if (!sel) {
            break;
        }
        addEvent(sel, 'click', ActivityReminder._reenableSnoozeDismiss);
    }
    var allBox = document.getElementById('allBox');
    if (allBox) { // If there are no items, can be empty.
        addEvent(allBox, 'click', ActivityReminder._reenableSnoozeDismiss);
    }
    ActivityReminder._reenableSnoozeDismiss();
}

ActivityReminder.updateBrowserTime = function() {
    // Sends the browsers time down for snooze command:
    document.getElementById(ActivityReminderConstants.pSNOOZED_AT).value = new Date().getTime();
}

ActivityReminder._reenableSnoozeDismiss = function() {
    var anyChecked = false;
    for (var i=0; ;i++) {
        var sel = document.getElementById("ids" + i);
        if (!sel) {
            break;
        }
        if (sel.checked) {
            anyChecked = true;
            break;
        }
    }
    var btnCls = anyChecked ? 'btn' : 'btnDisabled';
    document.getElementById(ActivityReminderConstants.SNOOZE_ID).disabled = !anyChecked;
    document.getElementById(ActivityReminderConstants.SNOOZE_ID).className = btnCls;
    document.getElementById(ActivityReminderConstants.SNOOZE_TIME_ID).disabled = !anyChecked;
    document.getElementById(ActivityReminderConstants.DISMISS_ID).disabled = !anyChecked;
    document.getElementById(ActivityReminderConstants.DISMISS_ID).className = btnCls;
    ActivityReminder._enableSnoozeOptions();
}

ActivityReminder._enableSnoozeOptions = function() {
    // Figure out nearest selected activity:
    var now = new Date().getTime();
    var minTimeAway;
    for (var i=0;;i++) {
        var el = document.getElementById(ActivityReminderConstants.DUE_MINUTES_ID + i);
        if (!el) {
            break;
        }
        var sel = document.getElementById("ids" + i);
        if (!sel.checked) {
            continue;
        }
        var time = el.getAttribute(ActivityReminderConstants.DUE_TIME_ATTR);
        var isAllDay = el.getAttribute(ActivityReminderConstants.ALL_DAY_ATTR);
        var away = time - now;
        if (!minTimeAway || minTimeAway > away) {
            minTimeAway = away;
        }
        if (isAllDay == "true") {
            minTimeAway = 0; // All day events/tasks can't be snoozed for 15 minutes before.
        }
    }

    // Figure out nearest selected activity:
    var snooze = document.getElementById(ActivityReminderConstants.SNOOZE_TIME_ID);
    var options = snooze.childNodes;

    var removedCurrentSelected = false;
    // Add/remove all the appropriate 'before' times:
    var leadOptions = [0, 5, 10, 15];
    for (var i=0; i < leadOptions.length; i++) {
        var val = leadOptions[i];
        var options = snooze.childNodes;

        // Find the existing one, if any:
        var existingOption = null;
        for (var li=options.length-1; li >= 0; li--) {
            var option = options[li];
            if (option.text && option.value == -val) {
                existingOption = option;
                break;
            }
        }
        if ((val + 1.5) * 60 * 1000 <= minTimeAway) { // 1.5 extra minutes since < 1 minute will reshow immediately.
            if (!existingOption) {
                var option = document.createElement('option');
                var label;
                if (val==0) {
                    label = LC.getLabel('Page_ReminderSettings', 'hours_before', val);
                } else {
                    label = LC.getLabel('Page_ReminderSettings', 'minutes_before', val);
                }
                var opttxt = document.createTextNode(label);
                option.appendChild(opttxt);
                option.value = -val; // negative indicates lead time.
                snooze.insertBefore(option, snooze.firstChild);
                removedCurrentSelected = true;
            }
        } else {
            // Should not be here:
            if (existingOption) {
                if (existingOption.selected == true) {
                    removedCurrentSelected = true;
                }
                snooze.removeChild(existingOption);
            }
        }
    }
    if (removedCurrentSelected == true) {
        // reselect the first one:
        var options = snooze.childNodes;
        for (var i=0; i< options.length; i++) {
            var option = options[i];
            if (option.text) {
                option.selected = 'true';
                break;
            }
        }
    }
}

ActivityReminder.selectAll = function() {
    for (var i=0; ;i++) {
        var sel = document.getElementById("ids" + i);
        if (!sel) {
            break;
        }
        sel.checked = true;
    }
}

ActivityReminder._wasFocused = function() {
    ActivityReminder._isBlur = false;
}

ActivityReminder._wasBlured = function() {
    ActivityReminder._isBlur = true;
}

ActivityReminder._pseudoFlash = function() {
    if (!ActivityReminder._originalTitle) {
        ActivityReminder._originalTitle = document.title;
    }
    var flashCount = ActivityReminder._flashCount;
    if (!flashCount) {
        flashCount = 1;
    } else {
        flashCount++;
    }
    ActivityReminder._flashCount = flashCount;
    var flashLimit = isNetscape ? 6 : 12; // Netscape grabs focus on setTitle, so flash shorter.
    // Netscape blur/focus events don't work well...
    if ((ActivityReminder._isBlur != true || ActivityReminder._stopFlash == true || isNetscape) && ActivityReminder._flashCount > flashLimit) {
        // Ok, the user has seen it, restore title & finish.
        document.title = ActivityReminder._originalTitle;
        return;
    }
    // Keep flashing:
    if (flashCount % 2 == 1) {
        document.title = LC.getLabel("Page_ActivityReminder", "new_flash");
    } else {
        document.title = ActivityReminder._originalTitle;
    }
    setTimeout('ActivityReminder._pseudoFlash()', 500);
}

ActivityReminder.testPopup = function() {
    // Note, 1500 below is not just a random #, Firefox won't consider it a popup unless the
    // # is > 1000 (it seems)
    setTimeout('ActivityReminder._showPopup(true)', 1500);
}

ActivityReminder._resizeToFitHorizontalChange = function() {
    if (!isIE) return;
    if (document.documentElement.clientWidth == ActivityReminder._oldWidth) {
        // need to prune for real changes.
        return;
    }
    ActivityReminder._oldWidth = document.documentElement.clientWidth;
    var els = getElementsByClassName('maxHorizontal');
    var clearedAny = false;
    for (var elnum in els) {
        var el = els[elnum];
        if (el.style.width && el.style.width != null) {
            el.style.width = null;
            clearedAny = true;
        }
    }
    if (clearedAny) {
        // Because we have already altered the document (by setting stylesheet),
        // we clear the style change (above), allow the browser (IE) to recompute the
        // size... then (later) we re-compute the max size fix.
        // This breaks badly if we don't do it later in a timeout -- the layout computations
        // seem to be in a partially complete state otherwise.
        window.setTimeout('ActivityReminder._resizeToFitHorizontal()', 100);
    }
}

ActivityReminder._resizeToFitHorizontal = function() {
    if (isNetscape && !isIE) { // Netscape not in IE mode:
        // Update stylesheet for netscape.
        var els = getElementsByClassName('maxHorizontal');
        var maxFoundWidth = 0;
        for (var elnum in els) {
            var el = els[elnum];
            var curWidth = el.offsetWidth;
            el.style.width = '200px'; // Table layout didn't work.
            el.style.overflow = 'hidden';
        }
        if (els[0]) {
            // Netscape doesn't support scrolling tbody.
            var tbody = els[0].parentNode.parentNode.parentNode;
            tbody.style.height = 'auto';
        }
        return;
    }
    if (!isIE) return;
    // With IE tables, it ignores whether overflow-x is set to hidden for any div inside a td, and just
    // uses as much horz. space as required.  Firefox will, if overflow-x is set to hidden, take up as much
    // horz. space as available & then hide the rest.
    // CSS doesn't seem to specify what to do here, but Firefox's behavior
    // is obviously much nicer.

    // Use the width of the related list el as the guide for how much space the table is taking up:
    var relatedListEl = getElementsByClassName('bRelatedList')[0];
    var relatedListTableEl = getElementsByClassName('list')[0];
    // In IE6, the relatedListEl has the full used width, but in IE7 only the table has it.
    // Because of other differences in sizing, use offset width (which will be greater in IE6).
    var tableBasedOffsetWidth = relatedListTableEl.offsetWidth + 4; // extra pixels for borders, etc.
    var offsetWidth;
    if (relatedListEl.offsetWidth < tableBasedOffsetWidth) {
        // oversize IE7
        offsetWidth = tableBasedOffsetWidth;
    } else {
        // not oversized or IE6.
        offsetWidth = relatedListEl.offsetWidth;
    }

    var extraWidth = document.documentElement.clientWidth - offsetWidth;
    var minWidth = 100;
    if (extraWidth != 0) {
        var newWidth;
        var els = getElementsByClassName('maxHorizontal');
        var maxFoundWidth = 0;
        for (var elnum in els) {
            var el = els[elnum];
            var curWidth = el.offsetWidth;
            maxFoundWidth = Math.max(maxFoundWidth, curWidth);
        }
        newWidth = Math.max(minWidth, maxFoundWidth + extraWidth);
        for (var elnum in els) {
            var el = els[elnum];
            var curWidth = el.offsetWidth;
            el.style.width = newWidth + 'px';
        }
    }
}

/**
* Contains general utility function for traversing & manipulating the DOM
*
* @author mpolcari
* @since 142.ml
*/
function DomUtil() {}

/**
* applies a function (funk) to node & all of its children
* this results in a depth-first search which
* ends when funk returns a true value
*
* It is a half-assed X-path
*/
DomUtil.walkDomTreeApplyingFunction = function(node, funk) {
  if (!node) return null;
  var ans = funk(node);
  if (ans) {
     return ans;
  } else if (node.firstChild) {
    for (var i = 0; i < node.childNodes.length; i++) {
      ans = DomUtil.walkDomTreeApplyingFunction(node.childNodes[i], funk);
      if (ans) {
        return ans;
      }
    }
  }
  return null;
}

/* stops at the first one */
DomUtil.findDescendantWithProperty = function(startNode, property, value, caseInSensitive) {
  if (caseInSensitive) {
    var lowerVal = value.toLowerCase();
    return DomUtil.walkDomTreeApplyingFunction(startNode, function(node) {
      if (node[property] && node[property].toLowerCase && (node[property].toLowerCase() == lowerVal)) {
        return node;
      } else {
        return null;
      }
    });
  } else {
    return DomUtil.walkDomTreeApplyingFunction(startNode, function(node) {
      if ((node[property] == value)) {
        return node;
      } else {
        return null;
      }
    });
  }
}

/* similar to getElementsByTagName, but just returns the first one */
DomUtil.findDescendantWithTag = function(startNode, tagType) {
  return DomUtil.findDescendantWithProperty(startNode, 'tagName', tagType, true);
}

/* returns only the first one we encounter in a depth-first search */
DomUtil.findDescendantWithClassName = function(startNode, className) {
  if (!className) return;
  var spacedClass = ' ' + className + ' ';
  return DomUtil.walkDomTreeApplyingFunction(startNode, function(node) {
      if (node.className && ((' ' + node.className + ' ').indexOf(spacedClass) > -1)) {
        return node;
      } else {
        return null;
      }
    });
}

/* imports a shallow copy of the node.  If you want a deep copy, copy the innerHTML */
DomUtil.importNode = function(node, targetDocument) {
  if (!node) { Gack.sendGack("invalid Node"); return; }
  if (targetDocument.importNode) { //every reasonable browser on the planet
    return targetDocument.importNode(node, false);
  } else { //ie6
    var copy = targetDocument.createElement(node.tagName);
    for (var at = 0; at < node.attributes.length; at++) {
       if (node.attributes[at].specified) {
           copy.setAttribute(node.attributes[at].name, node.attributes[at].value);
        }
    }
    return copy;
  }
}

DomUtil.copyScripts = function (srcDoc, targetDoc) {
      var targetHead = targetDoc.body.parentNode.firstChild;
      var scripts = srcDoc.getElementsByTagName("SCRIPT");
      var scriptElement;
      for (var i = 0, script; i < scripts.length; i++){
        script = scripts[i];
        if (script.src) { //just copy in functions.js and its ilk
          scriptElement = targetDoc.createElement("script");
          scriptElement.src = script.src
          targetHead.appendChild(scriptElement);
       //   iFrameHead.appendChild(DomUtil.importNode(script, iFrameDoc));  this wasn't working in ffox ?
        }
      }
}

DomUtil.copyCSS = function (srcDoc, targetDoc, apiVersion) {
      var targetHead = targetDoc.body.parentNode.firstChild;
      for (var i = 0, sheet; i < srcDoc.styleSheets.length; i++){
        sheet = srcDoc.styleSheets[i];
        var newNode;
        if (sheet.ownerNode) {
          newNode = DomUtil.importNode(sheet.ownerNode, targetDoc);
        } else {
          newNode = DomUtil.importNode(sheet.owningElement, targetDoc);
        }
        if (apiVersion && newNode.href && newNode.href.replace) {
          newNode.href = newNode.href.replace('/sCSS/', '/sCSS' + apiVersion + '/');
        }
        targetHead.appendChild(newNode);
      }
}

DomUtil.copyScriptsCssBodyClass = function (srcDoc, targetDoc) { //Copy css styleSheets, script includes, & body.className
  DomUtil.copyCSS(srcDoc, targetDoc);
  DomUtil.copyScripts(srcDoc, targetDoc);
  targetDoc.body.className = srcDoc.body.className;
}

DomUtil.setHelpLink = function (doc, url, helpTarget, helpSection) {
  if (helpTarget && helpSection){
     url = UserContext.getUrl("/help/doc/user_ed.jsp?loc=help&target=")+helpTarget+"&section="+helpSection;
  }
  var link = DomUtil.findDescendantWithClassName(doc, 'helpLink');
  if (link){
    var par = link.parentNode;
    if (par && par.href && par.href.indexOf("openPopupFocusEscapePounds") > 0){
        par.href = par.href.replace(/'.*?'/, "'"+url+"'");
    }
  }
}


/**
 *  ActivityHover.js, extends Hover class, and is used for Activities such as Events and Tasks
 *
 *  @author eli
 *  @since 146 (rewrite of 144 code in functions.js)
 */

ActivityHover.prototype = new Hover();

function ActivityHover() {
}

ActivityHover.getHover = function(elementId) {
    var hover = Hover.hoverMap[elementId];
    if (typeof hover == 'undefined') {
		return Hover.createHover(new ActivityHover(), elementId);
    }
    return hover;
}

ActivityHover.prototype.loadHook_afterLoad = function() {
    var contentObj = getElementByIdCS(this.eid + "_content");
    var pbSubsectionObj = DomUtil.findDescendantWithClassName(contentObj, 'pbSubsection');
    if (pbSubsectionObj) {
        var detailListObj = DomUtil.findDescendantWithClassName(pbSubsectionObj, 'detailList');

        // Increase width of hover if the contents are too big to fit inside
        if (Hover.getElementWidth(detailListObj) > Hover.getElementWidth(pbSubsectionObj)) {
            var diff = Hover.getElementWidth(detailListObj) - Hover.getElementWidth(pbSubsectionObj);
            contentObj.style.width = (Hover.getElementWidth(contentObj) + diff) + 'px';
            pbSubsectionObj.style.width = Hover.getElementWidth(detailListObj) + 'px';
        }
    }
}

ActivityHover.prototype.setXPos = function(x) {
	var minX = this.getMinX();
	var maxX = this.getMaxX();

    /** Implements a 75px wide 'safezone' where a hover will never appear so that it doesn't cover up the element
     *  If maxX is below this safezone position, then the maxX is adjusted to the left of the element,
     *  and if x is below the safezone line, then we move that as our mouse position. Then if x>maxX, we move x back down
     *  to the max so the hover doesn't go too far right or cover up our safezone.
     *  Also implements an expanding hover that will expand in case the contents do not fit inside the box. This will happen in
     *  the case of long character strings that dont break up into mulitple lines.
     */
    var srcEleWidth = this.xObjRight-this.xObjLeft;
    var offset = (srcEleWidth < 75) ? srcEleWidth : 75;

    var maximum = Math.max(this.xObjLeft - minX, maxX + Hover.getElementWidth(this.ele) - this.xObjLeft - offset);
    if (maximum < 200) maximum = 200;

    if (Hover.getElementWidth(this.ele) > maximum) {
        var contentObj = getElementByIdCS(this.eid + "_content");
        var pbSubsectionObj = DomUtil.findDescendantWithClassName(contentObj, 'pbSubsection');
        // Skip over this code if there is no detail layout hover
        if (pbSubsectionObj) {
            var contentSubsectionDiff = Hover.getElementWidth(contentObj) - Hover.getElementWidth(pbSubsectionObj);
            var hoverContentDiff = Hover.getElementWidth(this.ele)-Hover.getElementWidth(contentObj);
            contentObj.style.width = (maximum - hoverContentDiff) + 'px';
            pbSubsectionObj.style.width = (Hover.getElementWidth(contentObj) - contentSubsectionDiff) + 'px';
            /* This prevents bad behavior on extremely small screens. If the hover did not get reduced to the correct width
             * it'll expand the contents to the size of the hover.
             */
            if (Hover.getElementWidth(this.ele) > maximum) {
                contentObj.style.width = (Hover.getElementWidth(this.ele)-hoverContentDiff) + 'px';
                pbSubsectionObj.style.width = (Hover.getElementWidth(contentObj) - contentSubsectionDiff) + 'px';
            }
            // recalculate maxX since width changed
            maxX = assureInt((Hover.documentBody && Hover.documentBody.clientWidth)? Hover.documentBody.clientWidth : window.innerWidth) +
                assureInt(window.pageXOffset || (Hover.documentBody? Hover.documentBody.scrollLeft : 0) || 0) - Hover.getElementWidth(this.ele);
        }
    }
    if (maxX < this.xObjLeft+offset) maxX = this.xObjLeft - Hover.getElementWidth(this.ele);
    if (x < this.xObjLeft+offset) x = this.xObjLeft+offset;

    if (x > maxX) x = Math.max(minX, maxX);
    this.xCoord = x;
}

/**
 * TreeNodeElement.js works like a class with lots of static methods.
 */

var TreeNodeElement = function(){}

// static definitions of images used in TreeNodeElement
TreeNodeElement.prototype.collapsedWidget = new Image(20, 16);
TreeNodeElement.prototype.collapsedWidget.src = UserContext.getUrl("/img/tree/plus.gif");
TreeNodeElement.prototype.collapsedWidgetStart = new Image(20, 16);
TreeNodeElement.prototype.collapsedWidgetStart.src = UserContext.getUrl("/img/tree/plusStart.gif");
TreeNodeElement.prototype.collapsedWidgetEnd = new Image(20, 16);
TreeNodeElement.prototype.collapsedWidgetEnd.src = UserContext.getUrl("/img/tree/plusEnd.gif");
TreeNodeElement.prototype.expandedWidget = new Image(20, 16);
TreeNodeElement.prototype.expandedWidget.src = UserContext.getUrl("/img/tree/minus.gif");
TreeNodeElement.prototype.expandedWidgetStart = new Image(20, 16);
TreeNodeElement.prototype.expandedWidgetStart.src = UserContext.getUrl("/img/tree/minusStart.gif");
TreeNodeElement.prototype.expandedWidgetEnd = new Image(20, 16);
TreeNodeElement.prototype.expandedWidgetEnd.src = UserContext.getUrl("/img/tree/minusEnd.gif");

// retrieve matching version of 'minus' images
TreeNodeElement.prototype.getExpandedWidgetState = function(imgURL) {
    if (imgURL.indexOf("Start") != -1) {
        return TreeNodeElement.prototype.expandedWidgetStart.src;
    }
    if (imgURL.indexOf("End") != -1) {
        return TreeNodeElement.prototype.expandedWidgetEnd.src;
    }
    return TreeNodeElement.prototype.expandedWidget.src;
}

// retrieve matching version of 'plus' images
TreeNodeElement.prototype.getCollapsedWidgetState = function(imgURL) {
    if (imgURL.indexOf("Start") != -1) {
        return TreeNodeElement.prototype.collapsedWidgetStart.src;
    }
    if (imgURL.indexOf("End") != -1) {
        return TreeNodeElement.prototype.collapsedWidgetEnd.src;
    }
    return TreeNodeElement.prototype.collapsedWidget.src;
}

TreeNodeElement.prototype.toggle = function(img, blockNum) {
   var obj = document.getElementById(blockNum);
   if (obj != null) {
       visible=(obj.style.display != "none")
       if (visible) {  //Toggle to invisible
         obj.style.display="none";
         img.src = TreeNodeElement.prototype.getCollapsedWidgetState(img.src);
       }
       else {
          obj.style.display="block";
          img.src =  TreeNodeElement.prototype.getExpandedWidgetState(img.src);
       }
   }
}

function LayoutMappingHelper() {
}

LayoutMappingHelper.getCellId = function (profileId, recordTypeId) {
	return profileId + "_" + recordTypeId;
}

LayoutMappingHelper.getCellProfileId = function (cell) {
	var id = cell.id;
	if (!id) {
		return null;
	}
	return id.substring(0, id.indexOf("_"));
}

LayoutMappingHelper.getCellRecordTypeId = function (cell) {
	var id = cell.id;
	if (!id) {
		return null;
	}
	return id.substring(id.indexOf("_") + 1);
}

LayoutMappingHelper.selectCellById = function (id) {
	var el = getElementByIdCS(id);
	if (el) {
		if (el.className.indexOf("selectedCell") < 0) {
			el.className += " selectedCell";
			// el.style.backgroundColor = '#D0D0FF';
		}
	}
}

LayoutMappingHelper.deselectCellById = function (id) {
	var el = getElementByIdCS(id);
	if (el) {
		el.className = el.className.replace(/selectedCell/,"");
	}
}


LayoutMappingHelper.changeCellById = function (id) {
	var el = getElementByIdCS(id);
	if (el) {
		if (el.className.indexOf("changedCell") < 0) {
			el.className += " changedCell";
		}
	}
}


LayoutMappingHelper.resetCellById = function (id) {
	var el = getElementByIdCS(this.getCellId(profileId, recordTypeId));
	if (el) {
		el.className = el.className.replace(/selectedCell/,"");
		el.className = el.className.replace(/changedCell/,"");
	}
}

LayoutMappingHelper.getIndex = function (idNameArr, id) {
	if (!idNameArr || !idNameArr.length || idNameArr.length == 0) {
		return -1;
	}
	for (var i = 0; i < idNameArr.length; i++) {
		if (idNameArr[i].id == id) {
			return i;
		}
	}
	return -1;
}

LayoutMappingHelper.isProfileHeader = function (id) {
	if (!id) {
		return false;
	}
	if (id.indexOf('00e') == 0) {
		return true;
	}
	return false;
}
/**
 * RoleTreeNodeElement handles loading/caching of roles in tree. 
 */

var RoleTreeNodeElement = function(){
    this.openRoleList = new Array(); 
    this.downloadedRoles = new Array();
    this.downloadedAll = false;
    this.treeFormName = null;
}

// called from various java files, typically in a Java-defined
// javascript call, "initializeRoles()"
RoleTreeNodeElement.prototype.init = function(isDownloadedAll, openRoleNodes) {

    this.downloadedAll = isDownloadedAll;
    if (openRoleNodes != null){
        this.openRoleList = openRoleNodes.split(":");
        this.downloadedRoles = openRoleNodes.split(":");
    }
}

RoleTreeNodeElement.prototype.addToOpenRoles = function(item) {
    for (var i = 0; i < this.openRoleList.length; i++) {
        if (this.openRoleList[i] == null || this.openRoleList[i] == '') {
            this.openRoleList[i] = item;    
            this.updateCookiesRole();
            return;     
        }
    }
    this.openRoleList[this.openRoleList.length] = item;
    this.updateCookiesRole();
}

RoleTreeNodeElement.prototype.isInDownloadedRoles = function(item) {
    if (item == '000000000000000') {
        return true;
    }
    
    for (var i = 0; i < this.downloadedRoles.length; i++) {
        if (this.downloadedRoles[i] == item) {
            return true;
        }
    }
    return false;
}    

RoleTreeNodeElement.prototype.removeFromOpenRoles = function(item) {   
    for (var i = 0; i < this.openRoleList.length; i++) {
        if (this.openRoleList[i] == item) {
            this.openRoleList[i] = null;            
        }
    }
    this.updateCookiesRole();
}

RoleTreeNodeElement.prototype.updateCookiesRole = function() {
    var stringlist = "";
    for (var i = 0; i < this.openRoleList.length; i++) {
        if (this.openRoleList[i] != null && this.openRoleList[i] != '') {
            stringlist = stringlist + this.openRoleList[i] + ":";
        }
    }
    Cookies.prototype.SetCookie(RoleTreeCookieConstants.COOKIE_KEY, stringlist, null, "/");     
}

RoleTreeNodeElement.prototype.toggleRoles = function(img, blockNum, roleId) {
   var obj = document.getElementById(blockNum);
   if (obj != null) {
       visible=(obj.style.display != "none")
       if (visible) {  //Toggle to invisible
         obj.style.display = "none";
         img.src = TreeNodeElement.prototype.getCollapsedWidgetState(img.src);
         this.removeFromOpenRoles (roleId);
       }
       else {
          this.addToOpenRoles (roleId);  
          if (this.downloadedAll || this.isInDownloadedRoles (roleId)) {
              obj.style.display = "block";
              img.src = TreeNodeElement.prototype.getExpandedWidgetState(img.src);
          } else {
              this.refreshTree();
          }
       }
   }
}

RoleTreeNodeElement.prototype.collapseAllRoles = function() {
    Cookies.prototype.SetCookie(RoleTreeCookieConstants.COOKIE_KEY, "", null, "/");     
    this.refreshTree();
}

RoleTreeNodeElement.prototype.expandAllRoles = function() {
    Cookies.prototype.SetCookie(RoleTreeCookieConstants.COOKIE_KEY, "EXPANDALL", null, "/");     
    this.refreshTree();
} 

// This is called staticall from TerritoryTreeMultiSelect.java 
// and SelectTargetTerritoryStage.java
RoleTreeNodeElement.prototype.setTreeFormName = function(name) {
	this.treeFormName = name;
}

RoleTreeNodeElement.prototype.refreshTree = function() {
	if (this.treeFormName == null) {
    	window.location.replace(window.location.href);
	} else {
		window.document.forms[this.treeFormName].submit();
	}
}

/**
 * @author zzhou
 * @since 150
 *
 * the javascript for the Forecast Sharing enabling/disabling dialog boxes on the Forecast Settings page
 **/

   function FctSettingsPage() {}
   function FctShareDialog() {}

   FctSettingsPage.fctShareFormSubmit = false;
   FctShareDialog.allowMgrShare = '0';

   //check to see if we submit the form or not
   FctSettingsPage.submitCheck = function(url,isFctShareEnabled) {
        if (validateForm()) {
            FctSettingsPage.fctShareFormSubmit = (isFctShareEnabled == document.getElementById(ForecastSettings.pFORECAST_SHARING).checked);
            if (FctSettingsPage.fctShareFormSubmit) {
                return true;
            } else {
                openPopupFocus(url, 'fctSharingDialog', 300, 500,'height=350,width=600,location=no,dependent=no,resizable=no,toolbar=no,status=yes,directories=no,menubar=no,scrollbars=no', true, true, true);
                return false;
            }
        } else {
            return false;
        }
   }

   FctShareDialog.checkSaveButton = function(checkCheckBox) {
        var checked;
        if (checkCheckBox) {
            checked = document.getElementById(ForecastSharingPrefPopup.DISABLE_CHECKBOX).checked;
        } else {
            checked = document.getElementsByName(ForecastSharingPrefPopup.CAN_SHARE_RADIO)[0].checked || document.getElementsByName(ForecastSharingPrefPopup.CAN_SHARE_RADIO)[1].checked;
        }

        //check if any of the input values are checked so that we allow the user to save by enabling the save button
        if (checked) {
            document.getElementsByName("save")[0].className = 'btn';
            document.getElementsByName("save")[0].disabled = false;
            document.getElementsByName("save")[0].onclick = function() {FctShareDialog.saveResult(true)};
            if (!checkCheckBox) {
                FctShareDialog.allowMgrShare = document.getElementsByName(ForecastSharingPrefPopup.CAN_SHARE_RADIO)[1].checked ? '1' : '0';
            }
        } else {
            document.getElementsByName("save")[0].className = 'btnDisabled';
            document.getElementsByName("save")[0].disabled = true;
        }
   }

   FctShareDialog.saveResult = function(doSave) {
        if (doSave) {
            window.opener.FctSettingsPage.submit(FctShareDialog.allowMgrShare);
        }
        window.close();
   }

   FctSettingsPage.submit = function(allowMgrShare) {
        //simluate clicking on the button to save
        var qs = new QueryString("");
        document.getElementById(ForecastSettings.pALLOW_FM_SHARING).value = allowMgrShare;
        qs.add(EditPageConstants.pSAVE, "Save");
        document.forms[EditPageConstants.pEDIT_PAGE].action += qs.toString();
        document.forms[EditPageConstants.pEDIT_PAGE].submit();
   }




function BrowserSettingsWarning() {
	var warning = this;
	if (window.sfdcPage) {
		window.sfdcPage.appendToOnloadQueue(function() {warning.init();});
	}
}
		
BrowserSettingsWarning.DO_NOT_ASK_AGAIN_EXPIRY = 60; // 2 months

BrowserSettingsWarning.prototype.init = function() {
	var browserSettingsWarning = this;
	var neverAgain = document.getElementById(BrowserSettingsWarningElement.NEVER_SHOW_AGAIN_ID);
	addEvent(neverAgain, "click" , function(e) {
		 browserSettingsWarning.neverShowAgain(); 
		 return false;
		 }, false);
	var moreInfo =  document.getElementById(BrowserSettingsWarningElement.MORE_INFO_ID);
	addEvent(moreInfo, "click" , function(e) {
		 Cookies.prototype.SetCookie(BrowserSettingsWarningElement.cBrowserSettings, "0", new Date(), "/");
		 browserSettingsWarning.hideElement(); 
		 }, false);
}

BrowserSettingsWarning.prototype.neverShowAgain = function() {
	var expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + BrowserSettingsWarning.DO_NOT_ASK_AGAIN_EXPIRY);
						//	name, value, expires, path, domain
	Cookies.prototype.DeleteCookie(BrowserSettingsWarningElement.cBrowserSettings);
	Cookies.prototype.SetCookie(BrowserSettingsWarningElement.cBrowserSettings, "-1", expiryDate, "/");
	this.hideElement();
}

BrowserSettingsWarning.prototype.hideElement = function() {
	document.getElementById(BrowserSettingsWarningElement.BROWSER_SETTINGS_WARNING_ID).style.display = 'none';
}
/**
 * Extension of Paginator.js that includes a hover
 * toolbar.  Used in the ListViewport.
 * 
 * @author jtroup
 * @since 154
 */
function ListPaginator(args) {
	this.init(args);
}

ListPaginator.prototype = new Paginator();

ListPaginator.opts = [10, 25, 50, 100, 200];
ListPaginator.rppId = "_rpp";
ListPaginator.selectionId = "_selection";
ListPaginator.target = "_target";

ListPaginator.prototype.init = function(args) {
	this.listDomId = args["listDomId"];
	this.id = this.listDomId + "_paginator";
	
	Paginator.addPaginator(this);

	this.containerIds = args["containerIds"];
	this.handler = args["handler"];

	this.ref = "Paginator.instances['" + this.id + "']";
	this.listRef = "ListViewport.instances['" + this.listDomId + "']";

    var self = this;
    var f = function(e) {
                var target = getEventTarget(e);
                if (target.id != self.id + ListPaginator.rppId + ListPaginator.target &&
                	target.parentNode.id != self.id + ListPaginator.rppId + ListPaginator.target) {
                    ListPaginator.hideSelector(self.id + ListPaginator.rppId + ListPaginator.target);
                }
                if (target.id != self.id + ListPaginator.selectionId + ListPaginator.target &&
                	target.parentNode.id != self.id + ListPaginator.selectionId + ListPaginator.target) {
                    ListPaginator.hideSelector(self.id + ListPaginator.selectionId + ListPaginator.target);
                }
            }
    addEvent(document.body, "mousedown", f, true);

	this.selectedOnThisPage = 0;
	this.selectCount = 0;

	this.setState(args);
}

ListPaginator.prototype.setSelectCount = function(num) {
	this.selectCount = num;
	
	this.draw();
}

ListPaginator.prototype.setState = function(args) {
    this.currentPage = parseInt(args["currentPage"]) || this.currentPage || 1;
    this.recordsPerPage = parseInt(args["recordsPerPage"]) || this.recordsPerPage || 50;
    this.totalRecords = parseInt(args["totalRecords"]);
    this.capped = args["capped"];
    this.hasCheckbox = args["hasCheckbox"];
    
    if (!this.capped) {
        this.totalPages = Math.ceil(this.totalRecords / this.recordsPerPage);
    } else {
        this.totalPages = null;
    }

    this.startingRecord = (this.currentPage-1)*this.recordsPerPage + 1;

    if (!args["nodraw"]) {
        var self = this;
        if (this.totalRecords === 0) {
        	window.sfdcPage.appendToOnloadQueue(function() {self.draw(true);});
        } else {
        	window.sfdcPage.appendToOnloadQueue(function() {self.draw();});
        }
    }
}

ListPaginator.prototype.draw = function(empty) {
	var html = [];
    html.push("<div class='paginator'>");

	html.push("<span class='left'>");
	if (empty) {
		html.push("&nbsp;");
	} else {
		html.push(this.getRecordCounts());
		if (this.hasCheckbox) {
			html.push(this.getSelectedCount());
		}
	}
	html.push("</span>");
	
	if (empty) {
		html.push("&nbsp;");
	} else {
		html.push(this.getPrevNextLinks());		
	}

	html.push("<span class='right'>");
	if (empty) {
		html.push("&nbsp;");
	} else {
		html.push(this.getPageXofY());
	}
	html.push("</span>");

	html.push("</div>");
	html.push("<div class='clearingBox'/>");

	for(var i=0; i < this.containerIds.length; i++) {
		document.getElementById(this.containerIds[i]).innerHTML = html.join('');
	}
}

ListPaginator.keyHandle = function(e) {
    if (window.ActiveXObject && e.keyCode == KEY_ENTER) {
        getEventTarget(e).onchange();
    }
}

ListPaginator.prototype.getPageXofY = function() {
	var html = [];
	html.push(LC.getLabel("Paginator", "page"));
	if (this.totalPages) {
		html.push("<input class='pageInput' maxlength='4' onchange=\"");
		html.push(this.ref);
		html.push(".goToPage(this.value)\"");
		html.push(" onkeydown=\"");
        html.push("ListPaginator.keyHandle(event)\"");
		html.push(" value='");
		html.push(this.currentPage);
		html.push("'>");
		html.push(LC.getLabel("Paginator", "of", this.totalPages));
	} else {
		html.push("&nbsp;");
		html.push(this.currentPage);
	}
	return html.join('');
}

ListPaginator.prototype.getRecordCounts = function() {
	if (this.totalRecords === 0) {
		return "0";
	} else {
		var html = [];
		html.push("<span class='selectorTarget'");
		html.push(" id='")
		html.push(this.id + ListPaginator.rppId + ListPaginator.target);
		html.push("'");
		html.push(" onmousedown=\"");
		html.push("ListPaginator.showSelector('");
		html.push(this.id + ListPaginator.rppId + ListPaginator.target);
		html.push("')\"");
		html.push(" onmouseover=\"");
		html.push("ListPaginator.hoverSelector(this)");
		html.push("\"");
		html.push(" onmouseout=\"");
		html.push("ListPaginator.unhoverSelector(this)");
		html.push("\"");
		html.push(">");
		html.push(this.startingRecord);
		html.push("-");
	
		this.lastRecord = 0;
		if(!this.capped) {
			this.lastRecord = Math.min((this.startingRecord + this.recordsPerPage - 1),this.totalRecords);
		} else {
			this.lastRecord = this.startingRecord + this.recordsPerPage - 1;
		}
		html.push(this.lastRecord);
		if (!this.capped) {
			html.push(" ");
			html.push(LC.getLabel("Paginator", "of", this.totalRecords));
		} else {
		    html.push(" ");
            html.push(LC.getLabel("Paginator", "of", this.totalRecords + "+"));
		}
		html.push(this.getRppSelector());
		html.push("<img class='selectArrow' src='" + UserContext.getUrl('/s.gif') + "' />");
		html.push("</span>");
	
		return html.join('');
	}
}

ListPaginator.prototype.getPrevNextLinks = function() {
	var html = [];
	var jscall = "";

	html.push("<span class='prevNextLinks'>");

	html.push("<span class='prevNext'>");
	// <<
	if (this.currentPage != 1) {
		jscall = this.ref + ".goToPage(1)";
		html.push("<a href=\"javascript:");
		html.push(jscall);
		html.push("\">");
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='first'>");
		html.push("</a>");
	} else {
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='firstoff'>");
	}
	html.push("</span>");

	html.push("<span class='prevNext'>");
	// < Previous
	if (this.currentPage != 1) {
		jscall = this.ref + ".goToPage(" + (this.currentPage-1) + ")";
		html.push("<a href=\"javascript:");
		html.push(jscall);
		html.push("\">");
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='prev'>");
		html.push(LC.getLabel("Paginator", "previous"));
		html.push("</a>")
	} else {
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='prevoff'>");
		html.push(LC.getLabel("Paginator", "previous"));
	}
	html.push("</span>");

	html.push("<span class='prevNext'>");
	// Next >
	if (this.capped || (this.totalPages && this.currentPage != this.totalPages)) {
		jscall = this.ref + ".goToPage(" + (this.currentPage+1) + ")";
		html.push("<a href=\"javascript:");
		html.push(jscall);
		html.push("\">");
		html.push(LC.getLabel("Paginator", "next"));
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='next'>");
		html.push("</a>");
	} else {
		html.push(LC.getLabel("Paginator", "next"));
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='nextoff'>");
	}
	html.push("</span>");

	html.push("<span class='prevNext'>");
	// >>
	if (this.totalPages && this.currentPage != this.totalPages) {
		jscall = this.ref + ".goToPage(" + this.totalPages + ")";
		html.push("<a href=\"javascript:");
		html.push(jscall);
		html.push("\">");
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='last'>");
		html.push("</a>");
	} else {
		html.push("<img src='" + UserContext.getUrl('/s.gif') + "' class='lastoff'>");
	}
	html.push("</span>");

	html.push("</span>");

	return html.join('');
}

ListPaginator.prototype.getSelectedCount = function() {
	var html = [];
	html.push("<span class='selectorTarget selectCount");
	if (this.selectCount > 0) {
		html.push(" selectCountHi");
	}
	html.push("' id='")
	html.push(this.id + ListPaginator.selectionId + ListPaginator.target);
	html.push("'");
	html.push(" onmousedown=\"");
	html.push("ListPaginator.showSelector('");
	html.push(this.id + ListPaginator.selectionId + ListPaginator.target);
	html.push("')\"");
	html.push(" onmouseover=\"");
	html.push("ListPaginator.hoverSelector(this)");
	html.push("\"");
	html.push(" onmouseout=\"");
	html.push("ListPaginator.unhoverSelector(this)");
	html.push("\"");
	html.push(">");
	html.push(this.selectCount);
	html.push(" ");
	html.push(LC.getLabel("Paginator", "selected"));
	html.push(this.getSelectionSelector());
	html.push("<img class='selectArrow' src='" + UserContext.getUrl('/s.gif') + "' />");
	html.push("</span>");
	
	return html.join('');
}

ListPaginator.prototype.goToPage = function (pageNum) {
	if (isNaN(pageNum) || pageNum < 1) {
		pageNum = 1;
    } else if (this.totalPages && pageNum > this.totalPages) {
		pageNum = this.totalPages;
	}

	if (this.handler)
		this.handler(pageNum);
}

ListPaginator.prototype.getRppSelector = function() {
    var html = [];
   	html.push("<table cellpadding='0' cellspacing='0' class='selector rpp' id='");
   	html.push(this.id + ListPaginator.rppId + "'>");

	var opts = ListPaginator.opts;
	for (var i=0; i<opts.length; i++) {
	    var selected = opts[i] == this.recordsPerPage;
        var clazz = selected ? 'optSelected' : 'optUnselected';
        
       	html.push("<tr");
       	html.push(" class='opt ");
       	html.push(clazz);
       	html.push("'");
        html.push(" onmouseover=\"");
		html.push("if (this.className.indexOf('optHover') < 0) { this.className += ' optHover' }");
        html.push("\"");
		html.push(" onmouseout=\"");
		html.push("this.className = this.className.replace('optHover', '')");
		html.push("\"");
		html.push(" onmousedown=\"");
        html.push(this.listRef);
        html.push(".getListData({")
        html.push("rowsPerPage: ");
        html.push(opts[i]);
        html.push(", rolodexIndex: ");
        html.push(this.listRef);
        html.push(".rolodexIndex")
        html.push("})");
		html.push("\">");
        html.push("<td class='optUnselected'>");
        html.push(LC.getLabel("Paginator", "display"));
        html.push("</td>");
        html.push("<td class='rppOpt'>");
       	html.push(opts[i]);
       	html.push("</td>");
        html.push("<td class='optUnselected'>");
        html.push(LC.getLabel("Paginator", "rpp"));
        html.push("</td>");
       	html.push("</tr>");
	}
   	
   	html.push("</table>");
	
	return html.join('');
}

ListPaginator.prototype.getSelectionSelector = function() {
    var html = [];
    var smRef = this.listRef + ".grid.getSelectionModel()";
    
    var recordsOnPage = this.lastRecord - this.startingRecord + 1;
    var notSelectedOnPage = recordsOnPage - this.selectedOnThisPage;
    
    var opts = [{label: LC.getLabel("Paginator", "select_page", "+" + notSelectedOnPage), handler: smRef + ".selectAll()"},
                {label: LC.getLabel("Paginator", "deselect_page", "-" + this.selectedOnThisPage), handler: smRef + ".clearSelections()"},
                {label: LC.getLabel("Paginator", "clear_all_selections", "-" + this.selectCount), handler: smRef + ".clearAllSelections()"}];
    
    html.push("<div class='selector selection' id='");
    html.push(this.id + ListPaginator.selectionId + "'>");
    for (var i=0; i< opts.length; i++) {
        html.push("<div");
        html.push(" class='opt'");
        html.push(" onmouseover=\"");
    	html.push("if (this.className.indexOf('optHover') < 0) { this.className += ' optHover' }");
        html.push("\"");
    	html.push(" onmouseout=\"");
    	html.push("this.className = this.className.replace('optHover', '')");
    	html.push("\"");
    	html.push(" onmousedown=\"");
        html.push(opts[i].handler);
    	html.push("\">");
    	html.push(opts[i].label);
    	html.push("</div>");
    }
	html.push("</div>");
	
	return html.join('');
}

ListPaginator.showSelector = function(id) {
	var el = document.getElementById(id);
	if (el && el.className.indexOf(" selectorOpen") < 0) {
        el.className += " selectorOpen";
	}
}

ListPaginator.hideSelector = function(id) {
	var el = document.getElementById(id);
	if (el) {
	    el.className = el.className.replace(" selectorOpen", "");
	}
}

ListPaginator.hoverSelector = function(el) {
    if (el.className.indexOf(" selectorHover") < 0) {
        el.className += " selectorHover";
    }
}

ListPaginator.unhoverSelector = function(el) {
    el.className = el.className.replace(" selectorHover", "");
}

/**
 * Utility to save open/closed state of setup in browser cookies. 
 * The starting state of the setup tree is initialized in 
 * SetupPageHeader.java, which generates the value for openListSetup below.
 */

var SetupTreeNode = function(){}

// this variable is also referenced in SetupPageHeader.java
SetupTreeNode.prototype.openListSetup = new Array();

SetupTreeNode.prototype.addToOpenSetup = function(item) {
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] == null) {
            SetupTreeNode.prototype.openListSetup[i] = item;    
            SetupTreeNode.prototype.updateCookiesSetup();
            return;     
        }
    }
    SetupTreeNode.prototype.openListSetup[SetupTreeNode.prototype.openListSetup.length] = item;
    SetupTreeNode.prototype.updateCookiesSetup();
}

SetupTreeNode.prototype.removeFromOpenSetup = function(item) {   
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] == item) {
            SetupTreeNode.prototype.openListSetup[i] = null;            
        }
    }
    SetupTreeNode.prototype.updateCookiesSetup();
}

// class structure: parent->setupFolder->setupLeaf
SetupTreeNode.prototype.getNodes = function(){
	var allNodes = new Array();
	
	var parents = getElementsByClassName('parent');
	allNodes = allNodes.concat(parents);

	var leaves = getElementsByClassName('setupLeaf');
	allNodes = allNodes.concat(leaves);
	
	return allNodes;
	
}

SetupTreeNode.prototype.search = function(){
	if (SetupTreeNode.prototype.isTypingFast()){
		return;
	}
	var val = SetupTreeNode.prototype.getSearchTerm();
	if (!val) {
		SetupTreeNode.prototype.reset();
		return;
	}
	var vals = val.split(' ');
	if (!vals || vals.length == 0){
		return;
	}
	var elements = SetupTreeNode.prototype.getNodes();
	for (var i = 0; elements && i < elements.length; i++){
		var obj = elements[i];
		var topic = obj.id;
	    SetupTreeNode.prototype.searchNode(obj, topic, vals);
	}
}


SetupTreeNode.prototype.searchNode = function(obj, topic, vals){
    if (obj != null) {
    	var containsText = true;
    	var txt = obj.getAttribute(SetupSearchElement.ATT_SEARCH_TEXT);
    	if (!txt){
    		containsText = false;
    	} else {
	    	for (var j = 0; j < vals.length; j++){
	    		if (txt.indexOf(vals[j]) == -1){
	    			containsText = false;
	    			break;
	    		}
	    	}
    	}
        if (containsText) {
        	HTMLTreeNode.prototype.setVisible(obj, true);
        	if (obj.className == 'parent'){
        		obj = HTMLTreeNode.prototype.getNodeChild(topic);
        		HTMLTreeNode.prototype.open(obj, topic);
        	}
        } else {
        	HTMLTreeNode.prototype.setVisible(obj, false);
        	if (obj.className == 'parent'){
        		obj = HTMLTreeNode.prototype.getNodeChild(topic);
        		HTMLTreeNode.prototype.close(obj, topic);
        	}
        }
    }
}

SetupTreeNode.prototype.reset = function(){
	document.getElementById(SetupSearchElement.SETUP_SEARCH_PARAM).value = '';
	var elements = SetupTreeNode.prototype.getNodes();
	for (var i = 0; elements && i < elements.length; i++){
		var obj = elements[i];
	    HTMLTreeNode.prototype.setVisible(obj, true);
	}
}

SetupTreeNode.prototype.getSearchTerm = function(){
	var term = document.getElementById(SetupSearchElement.SETUP_SEARCH_PARAM).value;
	if (term){
		term = term.toLowerCase();
	}
	return term;
}

SetupTreeNode.prototype.updateCookiesSetup = function() {
    var stringlist = "";
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] != null) {
            stringlist = stringlist + SetupTreeNode.prototype.openListSetup[i] + ":";
        }
    }
            
    Cookies.prototype.SetCookie(SetupTreeNodeConstants.COOKIE_KEY, stringlist, null, "/");     
}

SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS = 250;
SetupTreeNode.prototype.LAST_DATE = null;
SetupTreeNode.prototype.TIMEOUT_ID = null;

// if typing fast, will delay search() until after typing is slowed
SetupTreeNode.prototype.isTypingFast = function(){
    
    // clear existing timeout to avoid flood of delayed search calls
    if (SetupTreeNode.prototype.TIMEOUT_ID){    
        clearTimeout(SetupTreeNode.prototype.TIMEOUT_ID);
    }
    
	var d = new Date();
	if (SetupTreeNode.prototype.LAST_DATE == null){
	    SetupTreeNode.prototype.LAST_DATE = d;
	    return true;
	} else {
	    var diff = d.getTime() - SetupTreeNode.prototype.LAST_DATE.getTime();
	    SetupTreeNode.prototype.LAST_DATE = d;
	    if (diff < SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS){
	        var delayedExec = "SetupTreeNode.prototype.search();";
	        SetupTreeNode.prototype.TIMEOUT_ID = setTimeout(delayedExec, SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS);
	        return true;
	    } else {
	        return false;
	    }
	}
	
}


/**
 * JS code to handle filtering/querying in a SelectFilterElement.
 */
var SelectFilterElement = function(ctlName, ctlOption, target, targetOption, existing, max, useJs){

    this.controllerName = ctlName;
    this.controllerOption = ctlOption;
    this.targetName = target;
    this.targetOption = targetOption;
    this.existingName = existing;

    // array of selected Option objects
    this.selectedOptions = new Array();

    // array of array of all Option objects
    this.allOptions = new Array();
    this.maxValues = max;
    this.searchQueueCount = 0;
    this.useJsSearch = useJs;
    this.searchStringChanged = false;
    this.itemAdded = false;
}

SelectFilterElement.prototype.getSearchElementId = function(){
    return 'searchValue_' + this.controllerName;
}

SelectFilterElement.prototype.addOptions = function(array){
	for (var i = 0; i < array.length; i++){
		this.addOption.apply(this, array[i]);
	}
}

SelectFilterElement.prototype.addOption = function(type, label, key, searchValue, existingValues) {

    var opt = new Option(label, key);
    opt.searchValue = searchValue;
    var optionsArray = this.allOptions[type];
    if (!optionsArray){
        optionsArray = new Array();
        this.allOptions[type] = optionsArray;
    }
    optionsArray[optionsArray.length] = opt;

    if (existingValues && this.selectedOptions != null && this.selectedOptions[key]) {
        existingValues.options[existingValues.options.length] = new Option(label, key);
    }

}

// doing queueSearch only applies to js searching. otherwise,
// sever-side search results in LOTS of posts to server.
SelectFilterElement.prototype.queueSearch = function() {
    this.searchQueueCount++;
    var callback = this.getJavascriptVarName() + '.doSearch()';
    setTimeout(callback, 300);
}

SelectFilterElement.prototype.doSearch = function() {

    this.searchQueueCount--;
    if (this.searchQueueCount > 0) return;
    // Reset the queue when we do a search
    this.searchQueueCount = 0;

    if (this.useJsSearch){
        this.doSearchJS();
    } else {
        this.doSearchServer();
    }
}

// does a "search" by filtering the values in the select element
SelectFilterElement.prototype.doSearchJS = function() {

    var controller = document.getElementById(this.controllerName);
    var targetField = document.getElementById(this.targetName);
    var existing = document.getElementById(this.existingName);

    var searchEl = document.getElementById(this.getSearchElementId());
    var searchValue = searchEl.value ? searchEl.value.toLowerCase() : "";
    if (searchValue.length == 0) {
        // Just run the whole filter if the input length is 0
        this.filter();
        return;
    }

    targetField.options.length = 0;

    var numMatched = 0;
    var numAdded = 0;
    var optionsOfType = this.allOptions[controller.value];
    if (optionsOfType){
        for (var i = 0; i < optionsOfType.length && numAdded < this.maxValues+1; i++) {
            var option = optionsOfType[i];

            if (existing && this.selectedOptions[option.value]){
                numMatched++;
                continue;
            }

            var match =
                !option.searchValue
                || option.searchValue.length == 0
                || option.searchValue.indexOf(searchValue) == 0
                || option.searchValue.indexOf(' ' + searchValue) > -1;

            if (match){
                if (numAdded < this.maxValues){
                    targetField.options[numAdded] = option;
                }
                numMatched++;
                numAdded++;
            }
        }
    }

    var tooManyValues = numMatched > this.maxValues;
    this.showErrorMessage(tooManyValues);

    if (targetField.options.length == 0) {
        targetField.options[0] = new Option(LC.getLabel("SelectElement", "Required"), '000000000000000');
    }

}

// does a "search" by posting back to the server.
SelectFilterElement.prototype.doSearchServer = function() {
    var form = document.forms[SelectFilterElement.FORMNAME];
    
    // DuelingListBoxesElement may set javascript to be executed
    // on the form.onsubmit(), so we call it before we submit.
    if (form.onsubmit){
        form.onsubmit();
    }

    form.submit();
}

SelectFilterElement.FORMNAME = EditPageConstants.pEDIT_PAGE

SelectFilterElement.prototype.handleKeyDown = function(evt) {
    evt = getEvent(evt);
    // Enter key
    if (evt.keyCode == 13 || evt.which == 13) {
        this.queueSearch();
        return false;
    } else {
        this.searchStringChanged = true;
    }
    return true;
}

SelectFilterElement.prototype.handlePropertyChange = function(){
    if (this.useJsSearch){
        this.queueSearch();
    }
}

SelectFilterElement.prototype.showErrorMessage = function(showMsg, errorMessage) {
    var searchEl = document.getElementById(this.getSearchElementId());
    var err = document.getElementById('error_' + this.targetName);
    if (searchEl && err) {
        if (showMsg) {
            err.style.visibility = 'visible';
            err.innerHTML = errorMessage ? errorMessage : LC.getLabel("Search_Filter", "too_many", this.maxValues, this.maxValues);
        } else {
            err.style.visibility = 'hidden';
        }
    }
}

SelectFilterElement.prototype.filter = function() {

// alert(this.targetName + " " + this.existingName);

    var controller = document.getElementById(this.controllerName);
    var targetField = document.getElementById(this.targetName);
    var searchEl = document.getElementById(this.getSearchElementId());
    if (this.useJsSearch && searchEl && searchEl.value.length != 0) {
        searchEl.value = '';
    }

    targetField.options.length = 0;

    // this value is initialized in selectfilterelement.jsp
    if (SelectFilterElement.prototype.NONE_LABEL) {
        targetField.options[0] = new Option(SelectFilterElement.prototype.NONE_LABEL, '000000000000000');
    }

    var counter = 0;
    var numAdded = 0;
    var optionsOfType = this.allOptions[controller.value];
    if (optionsOfType){

        // if there's a set of already-selected options, then we test
        // against that set before adding them to the target.
        var testForAlreadySelected = this.existingName;

        if (testForAlreadySelected){
            this.initSelectedOptionsFromUi();
        }

        // populating target field based on the options loaded with addOption().
        for (var i = 0; i < optionsOfType.length && (!searchEl || numAdded < this.maxValues+1); i++) {

            var option = optionsOfType[i];

            // If there existing values are there, check against the map before adding
            if (testForAlreadySelected && this.selectedOptions[option.value]) {
                continue;
            }

            counter++;

            // If search exists, then they only get up to maxValues
            if (!searchEl || numAdded < this.maxValues) {
                targetField.options[targetField.options.length] = option;
                numAdded++;
            }
        }

    }

    var tooManyValues = counter > this.maxValues;
    this.showErrorMessage(tooManyValues);

    if (targetField.options.length == 0) {
        targetField.options[0] = new Option(LC.getLabel("SelectElement", "Required"), '000000000000000');
    }
}

// After every change, we re-initialize the map so we can have fast lookup on it
SelectFilterElement.prototype.initSelectedOptionsFromUi = function() {

    if (this.existingName){

        this.selectedOptions = new Array();

        var existing = document.getElementById(this.existingName);
        if (existing){
            for (var i = 0; i < existing.options.length; i++) {
                if (existing.options[i].value.length > 0) {
                    this.selectedOptions[existing.options[i].value] = true;
                }
            }
        }
    }

}

// called from SelectFilterElement.java, when setting bodyOnLoad()
SelectFilterElement.prototype.init = function() {

    // The filter needs to be run at lease once.
    this.filter();

    // If existing is there, make sure we set the onchange event so we can keep track
    // of what is selected.
    if (this.existingName){
        var existing = document.getElementById(this.existingName);
        if (existing){
            existing.selectFilterEl = this;
            existing.onchange = function(){
                this.selectFilterEl.initSelectedOptionsFromUi();
            };
        }
    }

    // Initialize the default controller option
    if (this.controllerOption && this.controllerName){
        var controller = document.getElementById(this.controllerName);
        if (controller.options != null && controller.options != undefined) {
            for (var i = 0; i < controller.options.length; i++) {
                if (controller.options[i].value == this.controllerOption) {
                    controller.options[i].selected = true;
                }
            }
        }
    }

    // Initialize the default target option
    if (this.targetOption){
        var targetField = document.getElementById(this.targetName);
        for (var i = 0; i < targetField.options.length; i++) {
            if (targetField.options[i].value == this.targetOption) {
                targetField.options[i].selected = true;
            }
        }
    }

}

// name as defined in SelectFilterElement.getJavascriptVarName().
SelectFilterElement.prototype.getJavascriptVarName = function(){
    return this.targetName + 'Var';
}

// filtering the drop-down based on the controller is really just showing
// the right corresponding drop-down and hiding the others.
SelectFilterElement.prototype.filterDropdown = function(name, currTypeSelect) {
    var selected = currTypeSelect.selectedIndex;
    for (var i = 0; i < currTypeSelect.options.length; i++){
        var option = currTypeSelect.options[i].value;
        var optionList = name + '_' + option;
        var currSelect = document.getElementById(optionList);
        if (i == selected){
            currSelect.style.display = 'inline';
        } else {
            currSelect.style.display = 'none';
        }
    }
}

SelectFilterElement.prototype.moveLeft = function() {
    this.filter();
}

SelectFilterElement.prototype.beforeMoveRight = function() {
    this.itemAdded = true;
}


/**
 * Preference bit vectors in js, stores index, name, and current value. Setting a preference
 * to a different value will automatically make an asynchronous request to save the value to the
 * db. Since only a few preferences are accessible/settable through javascript there's no need to
 * compress them into bit vectors. This only handles boolean preferences right now.
 * 
 * @author jmooney
 * @since 150
 */
function PreferenceBits(/* array of {index, name, value} */ preferences) {
    this.bitsByName = {};
    for (var i = 0; i < preferences.length; i++) {
        var pref = preferences[i];
        this.bitsByName[pref.name] = {index: pref.index, val: pref.value };
    }
}

PreferenceBits.prototype.getBoolean = function(/* string */ name) {
    return this.bitsByName[name].val;
}

PreferenceBits.prototype.getIndexByName = function(/* string */ name) {
    return this.bitsByName[name].index;
}

PreferenceBits.prototype.setBoolean = function(/* string */ name, /* boolean */ val) {
    if (typeof val == "boolean") {
        var current = this.bitsByName[name];
        if (current && current.val != val) {
            this.bitsByName[name].val = val;
            this.save(name);
        }
    }
}

PreferenceBits.prototype.save = function(name) {
    var pref = this.bitsByName[name];
    if (pref) {
        // don't care about the response
        XBrowser.postHttpResponse(UserContext.getUrl("/_ui/common/request/servlet/PreferenceServlet"),
                                  function(response) {},
                                  XBrowser.buildPost({val: pref.val, bit: pref.index}));
    }
}

/**
 * Lookup schema

/**

  we require a map, give as JSON:

  CrtLookups.fields = {
      "Account": {
          "Name" : { label: "Account Name", lookup : null },
          "Owner" : { label: "Account Owner", lookup : "User", lookupLabel: "User"} },
      "User": {
      }
  };

  CrtLookups.primaryObjects = {
      "070..." : { table: "Account", label: "Accounts" },
      "070..." : { table: "Contact", label: "Contacts", detailField: "Account" }
  }

  detail field is used to filter out the lookup that simply points back to
  the parent object

  CrtLookups.initialState = [
      { path: "070abc.Owner.Role", field: "", colId: "073x..."}
  ];


*/

// selected state, which flattens the CrtLookupNode data.  used as input and output
// objectPath = "070abc000001.Owner.Role.Parent"
function CrtField(objectPath, field) {
    this.objectPath = objectPath;
    this.field = field;
}

function CrtFieldCollection() {
    this.fieldsMap = {};
}

CrtFieldCollection.prototype.addField = function(path, fieldName) {
    var field = new CrtField(path, fieldName);
    this.fieldsMap[field.objectPath + '|' + field.field] = field;
}

CrtFieldCollection.prototype.removeField = function(path, fieldName) {
    delete this.fieldsMap[path + '|' + fieldName];
}

CrtFieldCollection.prototype.hasField = function(path, fieldName) {
    var field = this.fieldsMap[path + '|' + fieldName];
    if (field && field != null) {
        return true;
    } else {
        return false;
    }
}

CrtFieldCollection.prototype.clone = function() {
    var copy = new CrtFieldCollection();
    for(var key in this.fieldsMap) {
        copy.fieldsMap[key] = this.fieldsMap[key];
    }
    return copy;
}

// do we really need table and label?  should we just have a pointer to the static fields record?  yes/maybe
function CrtLookupNode(crtObjectId, fieldFromParent, table, label) {
    this.crtObjectId = crtObjectId;
    this.table = table;
    this.label = label;
    this.fieldFromParent = fieldFromParent;
}

CrtLookupsUi.init = function(fields, primaryObjects) {
    var ui = new CrtLookupsUi(fields, primaryObjects);
    return ui;
}

function CrtLookupsUi(fields, primaryObjects) {
    this.fields = fields; // metadata
    this.primaryObjects = primaryObjects;

    this.lookupElem = document.getElementById('lookupBox');
    this.pathElem = document.getElementById('pathBox');

    this.initialSelectedFields = new CrtFieldCollection();
    this.selectedFields = this.initialSelectedFields.clone();
}

CrtLookupsUi.prototype.openOverlayWithPrimary = function() {
    //remove all selection in the layout
    MoveableItem.clearSelectedItems();

    // Parse the picklist value to determine the primaryObject
    var object = CrtObjects.getSelectedValue(document.getElementById(CrtLayoutElement.FIELD_TYPE_SELECT_NAME));
    var iUnderscore = object.indexOf('_');
    if (iUnderscore > -1) {
        object = object.substring(0, iUnderscore);
    }

    // Get the appropriate metadata for the primary object
    this.primaryObjId = object;
    var primaryObject = this.primaryObjects[object];

    // Bring up the overlay
    if (!CrtLookupsUi.lookup) {
        CrtLookupsUi.lookup = document.getElementById('lookupLayer1');
        CrtLookupsUi.lookup = new iframeShim(CrtLookupsUi.lookup);
    }

    //set the lookup header labels
    var headerElem = document.getElementById(CrtLookupConstants.LOOKUP_HEADER);
    var viaLookup = LC.getLabel("CRTLookupLayer","viaLookup");
    var html = '';
    html += '<h3>'+LC.getLabel("CRTLookupLayer","layerHeader")+ ' <span id="headerPrimObj">' + primaryObject.label + '</span> '+ viaLookup +'</h3>';
    html += '<p>' + LC.getLabel("CRTLookupLayer","layerDesc") + ' "' + primaryObject.label + '".' + '</p>';
    headerElem.innerHTML = html;

    this.showGrayout(true);

    //reposition the lookup layer to the center of the window when we open the overlay
    this.repositionLookup();

    CrtLookupsUi.lookup.setStyle('visibility', 'visible');
    //mac needs to set display as well or else scrollbar problems
    CrtLookupsUi.lookup.setStyle('display', 'block');

    //set initial state path to colId Map
    if (CrtLayoutElement.initialStateColIdMap == null) {
        CrtLayoutElement.initialStateColIdMap = {};
        for (var i=0; i< CrtLookups.initialState.length; i++) {
            CrtLayoutElement.initialStateColIdMap[CrtLookups.initialState[i].path+CrtLayoutElement.FIELD_SEP+CrtLookups.initialState[i].field] = CrtLookups.initialState[i].colId;
        }
    }

    //set the initial selected fields for this primary object
    if (CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)]) {
        this.initialSelectedFields = CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)].getFieldCollection();
        this.selectedFields = this.initialSelectedFields.clone();
    } else {
        this.initialSelectedFields = new CrtFieldCollection();
        this.selectedFields = this.initialSelectedFields.clone();
    }

    // Initialize our state
    this.path = [];
    this.path.push(new CrtLookupNode(object, null, primaryObject.table, primaryObject.label));
    this.currentTable = primaryObject.table;

    // Render
    this.renderPrimary();

}

CrtLookupsUi.GRAYOUT = 'grayout';

CrtLookupsUi.prototype.repositionLookup = function() {
    var scrollPos = getScrollY()+ getWindowHeight() / 600 * 200;
    CrtLookupsUi.lookup.setStyle('top',scrollPos+'px');
}

CrtLookupsUi.prototype.showGrayout = function(show) {
    var grayout = document.getElementById('overlayLayer1');
    if (!grayout) {
        var body = document.getElementsByTagName("body")[0];
        var node = document.createElement('div');
        node.className = 'overlayLayer';
        node.id = CrtLookupsUi.GRAYOUT;
        //body.appendChild(node);
        body.insertBefore(node, body.firstChild);
        grayout = document.getElementById(CrtLookupsUi.GRAYOUT);
    }
    if (show) {
        var pageDims = this.getPageSizeWithScroll();
        var left = -1 * getObjX(grayout);
        var top = -1 * getObjY(grayout);
        grayout.style.left = left + 'px';
        grayout.style.top = top + 'px';
        grayout.style.width = pageDims[0] + 'px';
        grayout.style.height = pageDims[1] + 'px';
        grayout.style.visibility = 'visible';
    } else {
        grayout.style.visibility = 'hidden';
    }
}

CrtLookupsUi.prototype.getPageSizeWithScroll = function() {
    if (window.innerHeight && window.scrollMaxY) {// Firefox
        yWithScroll = window.innerHeight + window.scrollMaxY;
        xWithScroll = window.innerWidth + window.scrollMaxX;
    } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
        yWithScroll = document.body.scrollHeight;
        xWithScroll = document.body.scrollWidth;
    } else { // works in Explorer 6 Strict, Mozilla (not FF) and Safari
        yWithScroll = document.body.offsetHeight;
        xWithScroll = document.body.offsetWidth;
    }
    var arrayPageSizeWithScroll = [xWithScroll,yWithScroll];
    return arrayPageSizeWithScroll;
}

CrtLookupsUi.prototype.getInitialFieldCollection = function() {
   var lookups = new CrtFieldCollection();
   for (var i=0; i< CrtLookups.initialState.length; i++) {
       lookups.addField(CrtLookups.initialState[i].path,CrtLookups.initialState[i].field);
       CrtLayoutElement.initialStateColIdMap[CrtLookups.initialState[i].path+CrtLayoutElement.FIELD_SEP+CrtLookups.initialState[i].field] = CrtLookups.initialState[i].columnId;
   }

   return lookups;
}

CrtFieldCollection.prototype.getAllFieldKeys = function() {
    var fieldKeys = [];
    for (var fieldKey in this.fieldsMap) {
        fieldKeys.push(fieldKey);
    }
    return fieldKeys;
}

CrtFieldCollection.prototype.size = function() {
    var size=0;
    for (var i in this.fieldsMap) {
        if (this.fieldsMap[i]) {
            size++;
        }
    }
    return size;

}
CrtFieldCollection.prototype.isEmpty = function() {
    var isEmpty = true;
    for (var i in this.fieldsMap) {
        if (this.fieldsMap[i]) {
            isEmpty = false;
        }
    }
    return isEmpty;
}



//subtracts the input fields from this collection
//return a new collection
CrtFieldCollection.prototype.subtract = function(fieldsToSubtract) {
    var remainingFields = this.clone();
    var fieldKeys = fieldsToSubtract.getAllFieldKeys();
    for (var i=0; i<fieldKeys.length; i++) {
        if (remainingFields.fieldsMap[fieldKeys[i]]) {
            delete remainingFields.fieldsMap[fieldKeys[i]];
        }
    }
    return remainingFields;
}

CrtFieldCollection.prototype.getField = function(fieldKey) {
    return this.fieldsMap[fieldKey];
}

CrtLookupsUi.prototype.saveOverlay = function() {
    var removedFields= this.initialSelectedFields.subtract(this.selectedFields);
    if (!removedFields.isEmpty()) {
        this.removeFields(removedFields);
    }
    var newlyAddedFields = this.selectedFields.subtract(this.initialSelectedFields);
    if (!newlyAddedFields.isEmpty()) {
        this.addFields(newlyAddedFields);
    }

    //render the lookup Section
    var lookupSection = CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)];
    if (lookupSection) {
        lookupSection.renderFields();
        lookupSection.swapToSectionDiv();
    }
    this.closeOverlay();

}

CrtLookupsUi.prototype.closeOverlay = function() {
    this.showGrayout(false);
    CrtLookupsUi.lookup.setStyle('visibility', 'hidden');
    CrtLookupsUi.lookup.setStyle('display', 'none');
}

CrtLookupsUi.prototype.removeFields = function(removedFields) {
    //get the lookupSection object
    var lookupSection = CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)];

    //if we have no selected any fields, remove the entire section
    if (lookupSection) {
        if (this.selectedFields.isEmpty()) {
            //remove the section element and object and options picklist
            lookupSection.remove();
            delete CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)];
            return;
        }
        //else just remove the fields
        else {
            lookupSection.removeFieldCollection(removedFields);
        }
    }

}

CrtLookupsUi.prototype.addFields = function(addedFields) {
     //get the lookupSection object
     var lookupSection = CrtLayoutElement.availableSections[CrtLayoutElement.getLookupSectionId(this.primaryObjId)];

      //if we don't have a lookup section, we have to make a new picklist option and construct the section
      if(!lookupSection) {
        var selectedElement = document.getElementById(CrtLayoutElement.FIELD_TYPE_SELECT_NAME);
        var primObjDivId = selectedElement.options[selectedElement.selectedIndex].value;
        //header title
        //HACK getting it from the parent select element value
        var headerTitle = selectedElement.options[selectedElement.selectedIndex].text+' ' +LC.getLabel("CRTLookupLayer","viaLookupParen");
        var lookupSectionId = CrtLayoutElement.getLookupSectionId(this.primaryObjId);
        var lookupDivId = CrtLayoutElement.getLookupDivId(lookupSectionId);

        lookupSection = new CrtLookupSection(lookupSectionId, lookupDivId, headerTitle);
        lookupSection.addPicklist(primObjDivId);
      }
      lookupSection.insertFieldCollection(addedFields,this.primaryObjects,this.fields);
}

CrtLayoutElement.getLookupSectionId = function(primObjId) {
    return primObjId + "_" + LookupsUi.LOOKUPS;
}

CrtLayoutElement.getLookupDivId = function(sectionId) {
    return sectionId+CrtLayoutElement.SECTION_DIV_SUFFIX+LookupsUi.LOOKUPS;
}
CrtLookupsUi.prototype.renderPrimary = function() {
    this.setLinksDisabled(true);
    var html = '';

    var primaryObject = this.primaryObjects[this.primaryObjId];

    // Presume that this.currentTable is a primary table
    var fields = this.getFields(this.currentTable);
    for(var fieldName in fields) {
        var field = fields[fieldName];
        if (field.lookup && fieldName != primaryObject.detailField) {
            html += '<br><a href="javascript: CrtLookups.ui.navigateAhead(\'' + fieldName + '\');"> ' + field.label + ' &#187; </a>';
        }
    }
    this.lookupElem.innerHTML = html;
    this.renderPath();
}

/**
 * Given the current path, navigate through a field to go deeper.
 */
CrtLookupsUi.prototype.navigateAhead = function(fieldName) {
    var field = this.getField(this.currentTable, fieldName);
    this.path.push(new CrtLookupNode(null /* todo; how to find id's? */, fieldName, field.lookup, field.label));
    this.currentTable = field.lookup;
    this.renderLookups();
}

/**
 * Navigate to a specific point on the current path.  Since the current
 * path is a stack, any point on the path is navigable by popping the stack.
 */
CrtLookupsUi.prototype.navigateBreadcrumb = function(iBreadcrumb) {
    this.path.length = iBreadcrumb + 1; // pop everything up to the breadcrumb
    if (this.path.length == 1) {
        var node = this.path[0];
        this.currentTable = node.table;
        this.renderPrimary();
    } else {
        var node = this.path[iBreadcrumb];
        var previousNode = this.path[iBreadcrumb - 1];
        this.currentTable = this.getField(previousNode.table, node.fieldFromParent).lookup;
        this.renderLookups();
    }
}

// renders this.currentTable
CrtLookupsUi.prototype.renderLookups = function() {
    this.renderCheckBoxes();
    this.setLinksDisabled(false);
    this.renderPath();
}

CrtLookupsUi.prototype.renderCheckBoxes = function() {
    var html = '';
    var fields = this.getFields(this.currentTable);
    for(var fieldName in fields) {
        var field = fields[fieldName];
        var checked = (this.isSelected(fieldName) ? 'checked' : '');
        if (field.lookup) {
            html += '<input type=checkbox ' + checked + ' onclick="CrtLookups.ui.toggleField(this, \'' + fieldName + '\');"> ' + field.label;
            if (this.path.length <= CrtLookupConstants.LOOKUP_DEPTH_LIMIT) {
                 html += ' &nbsp; <a href="javascript: CrtLookups.ui.navigateAhead(\'' + fieldName + '\');"> ' + LC.getLabel("CRTLookupLayer","viewRelatedFields") + '</a>';
            }
            html += '<br>';
        } else {
            html += '<input type=checkbox ' + checked + ' onclick="CrtLookups.ui.toggleField(this, \'' + fieldName + '\');"> ' + field.label + '<br>';
        }
    }
    this.lookupElem.innerHTML = html;
}

CrtLookupsUi.prototype.setLinksDisabled = function(disabled) {
    var controlElem = document.getElementById(CrtLookupConstants.CONTROL_ELEM_1);
    var innerHTML = '';

    //this label has to be called separately or else we get undefine for some weird reason
    var clearAll = LC.getLabel("CRTLookupLayer","ClearAll");
    if (disabled) {
        controlElem.className = 'crtDisabledLink';

        innerHTML = LC.getLabel("Report","SelectAll") + ' | ' + clearAll;
    } else {
        controlElem.className = '';
        innerHTML = '<a href="javascript: CrtLookups.ui.selectAll();">'+LC.getLabel("Report","SelectAll")+'</a> | <a href="javascript: CrtLookups.ui.clearAll();">'+clearAll+'</a>';
    }
    controlElem.innerHTML = innerHTML;
}

CrtLookupsUi.prototype.selectAll = function() {
    var fields = this.getFields(this.currentTable);
    for (var fieldName in fields) {
        if (!this.selectedFields.hasField(this.getFlatPath(), fieldName)) {
            this.selectedFields.addField(this.getFlatPath(), fieldName);
        }
    }
    this.renderCheckBoxes();
}

CrtLookupsUi.prototype.clearAll = function() {
    var fields = this.getFields(this.currentTable);
    for (var fieldName in fields) {
        if (this.selectedFields.hasField(this.getFlatPath(), fieldName)) {
            this.selectedFields.removeField(this.getFlatPath(), fieldName);
        }
    }

    this.renderCheckBoxes();
}

CrtLookupsUi.prototype.renderPath = function() {
    var html = '<b>'+LC.getLabel("CRTLookupLayer","Path")+ ': </b>&nbsp;';

    var previousTable;
    for(var i = 0; i < this.path.length; i++) {
        var node = this.path[i];

        // Get the labels of the path elements
        var nodeText;
        if (node.fieldFromParent == null) {
            nodeText = this.primaryObjects[node.crtObjectId].label;
            previousTable = node.table;
        } else {
            var field = this.getField(previousTable, node.fieldFromParent);
            nodeText = field.label;
            previousTable = field.lookup;
        }

        var delimiter = '';
        if (i == 1) delimiter = '&#187;';
        if (i > 1) delimiter = '>';
        html += ' ' + delimiter + ' <a href="javascript: CrtLookups.ui.navigateBreadcrumb(' + i + ');">' + nodeText + '</a>';
    }
    if (this.path.length > CrtLookupConstants.LOOKUP_DEPTH_LIMIT) {
        html += '<div class="maxLimit">'+LC.getLabel("CRTLookupLayer","maxDepthLimit") + "</div>";
    }

    this.pathElem.innerHTML = html;
}

CrtLookupsUi.prototype.toggleField = function(checkbox, fieldName) {
    if (checkbox.checked) {
        this.selectedFields.addField(this.getFlatPath(), fieldName);
    } else {
        this.selectedFields.removeField(this.getFlatPath(), fieldName);
    }
}

CrtLookupsUi.prototype.isSelected = function(fieldName) {
    return this.selectedFields.hasField(this.getFlatPath(), fieldName);
}

CrtLookupsUi.prototype.getFlatPath = function() {
    var flatPath;
    for(var i = 0; i < this.path.length; i++) {
        var node = this.path[i];
        if (node.fieldFromParent == null) {
            flatPath = node.crtObjectId;
        } else {
            flatPath += '.' + node.fieldFromParent;
        }
    }
    return flatPath;
}

CrtLookupsUi.prototype.getFields = function(table) {
    return this.fields[table];
}

CrtLookupsUi.prototype.getField = function(tableName, fieldName) {
    return this.fields[tableName][fieldName];
}

/**
 * Holds data about fields on a detail page for inline editing.
 * 
 * @author jmooney
 * @since 150
 */
function InlineEditData(json) {
    this.isEditable = json[InlineEditConstants.EDITABLE];
    this.sysMod = json[InlineEditConstants.LAST_MOD];
    this.id = json[InlineEditConstants.ENTITY_ID];
    this.csrf_token = json[CSRFConstants.CSRF_TOKEN];
    this.fields = {};
    this.dependencyGroups = [];
    this.hasCompoundFields = false;
    this.allFieldData = json[InlineEditConstants.FIELD_DATA];
    this.dynamicDataUrl = json[InlineEditConstants.DYNAMIC_DATA];
    this.loadedDynamicData = false;
    this.sentRequest = false;
    this.currentField = null;
    sfdcPage.initInlineEdit(this);
}

InlineEditData.prototype.init = function() {
    this.createFields();
    if (this.hasCompoundFields) {
        InlineEditField.overlay = new InlineEditDialog();
        InlineEditField.overlay.register();
    }
    var self = this;
    addEvent(document, "click", function() { self.closeCurrentField(); }, false);
}

InlineEditData.prototype.createFields = function() {
    if (this.allFieldData) {
        for (var i = 0; i < this.allFieldData.length; i++) {
            var fieldData = this.allFieldData[i];
            var field = InlineEditField.createField(fieldData);
            this.fields[fieldData.fieldId] = field;
            if (field) {
                if (field.compound) {
                    this.hasCompoundFields = true;
                }
            }
        }
        // create dependencies after all fields are loaded
        for (var i in this.fields) {
            var f = this.fields[i];
            if (f && f.controllerId) {
                this.createDependency(f);
                this.hasCompoundFields = true;
            }
        }
    }
}

InlineEditData.prototype.createDependency = function(field) {
    if (field.group) {
        // already in a group, nothing to do
        return;
    }
    // try to find existing group of a controller, and add to that group
    var f = this.getField(field.controllerId);
    var existingGroup = null;
    while (f != null) {
        existingGroup = f.group;
        if (existingGroup) {
            break;
        }
        f = this.getField(f.controllerId);
    }
    if (existingGroup) {
        // found a group, add fields until we get back to f
        var temp = field;
        var start = existingGroup.length;
        while (temp != f) {
            existingGroup.splice(start, 0, temp.id);
            temp.group = existingGroup;
            if (temp instanceof BooleanField) {
                // tell boolean fields to wait for the rest of the dependency to load
                temp.waitForLoad = true;
            }
            temp = this.getField(temp.controllerId);
        }
    } else {
        // have to create a new group
        var newGroup = [];
        var temp = field;
        while (temp != null) {
            newGroup.unshift(temp.id);
            temp.group = newGroup;
            if (temp instanceof BooleanField) {
                // tell boolean fields to wait for the rest of the dependency to load
                temp.waitForLoad = true;
            }
            temp = this.getField(temp.controllerId);
        }
        this.dependencyGroups.push(newGroup);
    }
}

InlineEditData.prototype.openField = function(field) {
    if (field.group) {
        field = this.fields[field.group[0]];
    } else if (!this.isCurrentField(field)) {
        this.closeCurrentField();
    }
    this.currentField = field;
    if (field.waitForLoad && !this.loadedDynamicData) {
        this.loadDynamicData();
        return;
    } else if (field.group) {
        this.openGroup(field.group);
    } else {
        field.openField();
    }
}

InlineEditData.prototype.openGroup = function(group) {
    var first = this.fields[group[0]];
    if (!first.created) {
        var div = document.createElement("div");
        div.className = "inlineEditDiv";
        document.body.appendChild(div);
        // create a table for the edit elements in the group
        var html = [];
        html.push("<table border=0>");
        for (var i = 0; i < group.length; i++) {
            var f = this.fields[group[i]];
            html.push("<tr><td class='labelCol'>");
            html.push(f.getFieldLabel());
            html.push("</td><td></td></tr>");
            if (f.state == InlineEditState.EDIT) {
                f.createEditDiv();
            } else {
                f.createDummy();
            }
        }
        html.push("</table>");
        div.innerHTML = html.join('');
        // after creating all select elements we can load the dependencies and insert into the table
        for (var i = 0; i < group.length; i++) {
            var f = this.fields[group[i]];
            var node;
            if (f.state == InlineEditState.EDIT) {
                f.load();
                div.firstChild.rows[i].lastChild.appendChild(f.editDiv);
            } else {
                div.firstChild.rows[i].lastChild.innerHTML = f.initialHTML;
            }
        }
        InlineEditField.overlay.addField(first.id, div, LC.getLabel("DependentElement", "dependentFields"));
    }
    InlineEditField.overlay.setActiveField(first.id);
    InlineEditField.overlay.setMaxWidth(400);
    InlineEditField.overlay.show();
}

InlineEditData.prototype.isCurrentField = function(field) {
    return this.currentField && this.currentField == field && !this.currentField.group;
}

InlineEditData.prototype.closeCurrentField = function() {
    if (this.currentField) {
        if (this.currentField.group) {
            this.closeGroup(this.currentField.group);
            this.currentField = null;
        } else {
            this.currentField.closeField();
            this.currentField = null;
        }
    }
}

InlineEditData.prototype.closeGroup = function(group) {
    for (var i = 0; i < group.length; i++) {
        var f = this.fields[group[i]];
        if (f.state == InlineEditState.EDIT) {
            var newValue = f.getValueFromEdit();
            if (f.isDifferentValue(newValue)) {
                if (!f.changed) {
                    f.changed = true;
                    addStyleClass(f.readDiv, "inlineEditModified");
                }
                f.currentValue = newValue;
                f.updateReadElement();
                if (f.changed) {
                    f.readDiv.appendChild(f.undoButton);
                    f.undoButton.style.display = "inline";
                }
            } else if (f.changed) {
                f.changed = false;
                f.currentValue = newValue;
                delStyleClass(f.readDiv, "inlineEditModified");
                f.updateReadElement();
                f.undoButton.style.display = "none";
            }
        }
    }
    InlineEditField.overlay.hide();
}

InlineEditData.prototype.resetCurrentField = function() {
    this.resetField(this.currentField);
    this.currentField = null;
}

InlineEditData.prototype.resetFieldById = function(id) {
    this.resetField(this.fields[id]);
}

InlineEditData.prototype.resetField = function(field) {
    if (field) {
        if (field.group) {
            this.resetGroup(field.group);
        } else {
            field.reset();
        }
    }
}

InlineEditData.prototype.resetGroup = function(group) {
    for (var i = 0; i < group.length; i++) {
        var f = this.fields[group[i]];
        if (f.state == InlineEditState.EDIT) {
            f.reset();
        }
    }
    InlineEditField.overlay.hide();
}

InlineEditData.prototype.getField = function(id) {
    if (id) {
        return this.fields[id];
    }
    return null;
}

InlineEditData.prototype.save = function() {
    if (this.isEditable) {
        this.closeCurrentField();
        var saveData = {};
        saveData[InlineEditConstants.ENTITY_ID] = this.id;
        saveData[InlineEditConstants.LAST_MOD] = this.sysMod;
        saveData[CSRFConstants.CSRF_TOKEN] = this.csrf_token;
        saveData[EditPageConstants.pSAVE] = "1"
        for (var id in this.fields) {
            var field = this.fields[id];
            // don't post data from read only fields, but do post from none fields because they are usually editable
            if (field && field.doPost()) {
                field.clearError();
                field.addSaveData(saveData);
            }
        }
        var self = this;
        XBrowser.postHttpResponse(UserContext.getUrl("/ui/common/InlineEditEntitySave"),
                                  function(response) { self.handleResponse(response.responseText); },
                                  XBrowser.buildPost(saveData),
                                  // check the errorMsg??
                                  function(response) {
                                      var url = escape(window.location.pathname+window.location.search);
                                      window.location.replace(UserContext.getUrl("/ex/errorduringprocessing.jsp?retURL=") + url);
                                  }
                                  );
    }
}

InlineEditData.prototype.handleResponse = function(responseText) {
    var response = Util.evalAjaxServletOutput(responseText);
    if (response[InlineEditConstants.SUCCESS]) {
        sfdcPage.refreshDetail();
    } else {
    	this.csrf_token = response[CSRFConstants.CSRF_TOKEN];
        this.handleErrors(response);
    }
}

InlineEditData.prototype.handleErrors = function(response) {
    sfdcPage.setError(response[InlineEditConstants.NON_SPECIFIC_ERRORS]);
    var specific = response[InlineEditConstants.VALIDATION_ERRORS];
    var first;
    for (var id in specific) {
        var f = this.getField(id);
        // error could be on a field that isn't on the page if somebody changed metadata after page 
        if (f) {
            // try to find the first simple field with an error and open it
            if (!f.overlay && !f.group) {
                // all fields have same offsetParent so use local y coord
                if (!first || first.tableCell.offsetTop > f.tableCell.offsetTop) {
                    first = f;
                }
            }
            f.setError(specific[id]);
        }
    }
    if (first) {
        this.openField(first);
    }
}

InlineEditData.prototype.revert = function() {
    if (this.isEditable) {
        this.closeCurrentField();
        var resetGroups = {};
        for (var id in this.fields) {
            var field = this.fields[id];
            if (field) {
                if (field.changed) {
                    // groups need to be reset separately
                    if (field.group) {
                        resetGroups[field.group[0]] = true;
                    } else {
                        field.reset();
                    }
                } else {
                    field.clearError();
                }
            }
        }
        for (var id in resetGroups) {
            this.resetGroup(this.fields[id].group);
        }
    }
}

InlineEditData.prototype.loadDynamicData = function() {
    if (!this.sentRequest) {
        this.sentRequest = true;
        var self = this;
        XBrowser.createDynamicScript(this.dynamicDataUrl, function() { self.dynamicDataLoaded(); });
    }
}

InlineEditData.prototype.dynamicDataLoaded = function() {
    if (!this.loadedDynamicData) {
        this.loadedDynamicData = true;
        if (this.currentField.waitForLoad) {
            this.openField(this.currentField);
        }
    }
}


	var CustomFieldRelatedList = {
		_mapCDTToComponents : {},
		_setupPlusGif : "",
		_setupMinusGif : "",

		registerCDT : function(cdtId, componentIds, setupPlusGif, setupMinusGif) {
			this._mapCDTToComponents[cdtId] = componentIds;
			this._setupPlusGif = setupPlusGif;
			this._setupMinusGif = setupMinusGif;
			var twisty = document.getElementById(cdtId + "_twisty");
			if (twisty) {
				addEvent(twisty, "click", this.onClickCDTTwisty, false);
			}
		},
     
     	onClickCDTTwisty : function (e) {
     		var twisty = getEventTarget(e);
			if (twisty == null) {
				return;
			} 
			var expanding = false;
			if (twisty.src.indexOf(CustomFieldRelatedList._setupPlusGif) != -1) {
				twisty.src = CustomFieldRelatedList._setupMinusGif;
				expanding = true;
			} else {
				twisty.src = CustomFieldRelatedList._setupPlusGif;
			}
			var cdtId = twisty.id.split("_")[0];
    		var arrCompRowIds = CustomFieldRelatedList._mapCDTToComponents[cdtId];
    		for (compRow = 0; compRow < arrCompRowIds.length; compRow++) {
    			if (document.getElementById(arrCompRowIds[compRow])) {
    				toggleDisplay(document.getElementById(arrCompRowIds[compRow]), expanding);
    			}
    		}
     	}
		

};
/**
  A MotifElement just tracks the relevent peices of the MotifElement

  @author polcari
  @since 144

  @paramName  This is the parameter name which prepends in the inputElements
*/

function MotifElement(id, descCellId, iconId, _motifKey) {
  if (arguments.length > 0) {
    this.init(id, descCellId, iconId, _motifKey);
  }
}

MotifElement.prototype.init	= function(id, descCellId, iconId, _motifKey) {
    this.motifElement = document.getElementById(id);
    this.motifDescCell = document.getElementById(descCellId);
    this.motifIcon = document.getElementById(iconId);
    this.motifKey = _motifKey;

    this.motifElement.motifElement = this;
}

MotifElement.prototype.getDescription = function() {
  return this.motifDescCell.firstChild.nodeValue;
}
/**
  A select element with details displayed on the right

  @author eli
  @since 148

*/
function MailmergeTemplateSelectElement(_id, _items, _fileDownloadUrl) {
  this.id = _id;
  this.items = _items;
  this.fileDownloadUrl = _fileDownloadUrl;
  var element = this;
  sfdcPage.appendToOnloadQueue(function() {element.init()});
}

MailmergeTemplateSelectElement.prototype.init = function() {
  var selectEle = document.getElementById(this.id);
  var mmtseEle = this;
  var previewEle = document.getElementById(MailmergeTemplateSelectElementConst.TEMPLATE_VIEW_BUTTON + '_' + this.id);
  if (previewEle) {
	  addEvent(previewEle, 'mouseup', function() {MailmergeTemplateSelectElement.showPreview(mmtseEle.fileDownloadUrl, selectEle);}, false);
  }
  addEvent(selectEle, 'mousemove', function() {MailmergeTemplateSelectElement.showDetails(mmtseEle.id, selectEle, mmtseEle.items);}, false);
  addEvent(selectEle, 'change', function() {MailmergeTemplateSelectElement.showDetails(mmtseEle.id, selectEle, mmtseEle.items);}, false);
  MailmergeTemplateSelectElement.showDetails(mmtseEle.id, selectEle, mmtseEle.items);
}

MailmergeTemplateSelectElement.showDetails = function(_id, selectEle, items) {
  if (selectEle.selectedIndex < 0)
  	return;
  var selectedOption = selectEle.options[selectEle.selectedIndex];
  var templateItem = (selectedOption) ? items[selectedOption.value] : null;
  if (templateItem == null)
  	return;
  var tName = templateItem[MailmergeTemplateSelectElementConst.TEMPLATE_TITLE];
  var description = templateItem[MailmergeTemplateSelectElementConst.TEMPLATE_DESCRIPTION];
  document.getElementById(MailmergeTemplateSelectElementConst.TEMPLATE_TITLE + '_' + _id).innerHTML = tName;
  document.getElementById(MailmergeTemplateSelectElementConst.TEMPLATE_DESCRIPTION + '_' + _id).innerHTML = description;
}

MailmergeTemplateSelectElement.showPreview = function(url, selectEle) {
  if (selectEle.selectedIndex < 0)
  	return;
  window.open(url + "?file=" + selectEle.options[selectEle.selectedIndex].value, '_blank');
}
/**
 * Functional Dialog with a scrollable content area and a summary. Can be movable but not resizable.
 * 
 * @author jmooney
 * @since 150
 */

function FunctionalDialog(id, isModal, title, isMovable) {
    this.id = id;
    this.isModal = isModal;
    this.isMovable = isMovable;
    this.extraClass = "functionalDialog";
    this.width = OverlayDialog.MAX_WIDTH;
    this.maxHeight = OverlayDialog.MAX_HEIGHT;
    this.setupDefaultButtons();
    this.title = title;
    this.hasSummaryElement = true;
    this.addEvents();
}

FunctionalDialog.prototype = new OverlayDialog();

FunctionalDialog.MAX_HEIGHT = 600;
FunctionalDialog.MIN_HEIGHT = 120;

FunctionalDialog.prototype.setMaxHeight = function(maxHeight) {
    this.maxHeight = maxHeight > FunctionalDialog.MAX_HEIGHT ? FunctionalDialog.MAX_HEIGHT : maxHeight;
}

FunctionalDialog.prototype.setInnerHeight = function() {
    // gotta add a bit for the scrollbars
    var inner = this.getContentElement();
    var height = inner.offsetHeight + (Math.min(this.maxHeight, getWindowHeight() - 40) - this.dialog.offsetHeight);
    inner.style.height = Math.max(FunctionalDialog.MIN_HEIGHT, height) + "px";
}

FunctionalDialog.prototype.createContent = function() {
    var content = document.getElementById(this.id + "Content");
    var html = [];
    html.push("<h2 id='");
    html.push(this.id);
    html.push("Header'>");
    html.push(this.header);
    html.push("</h2>");
    if (this.info) {
        html.push("<p id='");
        html.push(this.id);
        html.push("Info'>");
        html.push(this.info);
        html.push("</p>");
    }
    html.push("<div class='");
    if (this.hasSummaryElement) {
        html.push("scrollableArea");
    } else {
        html.push("scrollableAreaBottomBorder");
    }
        
    html.push("' id='");
    html.push(this.id);
    html.push("Inner'></div>");
    if (this.hasSummaryElement) {
        html.push("<div id='");
        html.push(this.id);
        html.push("Split' class='split'><img src='" + UserContext.getUrl('/img/overlaypointer.gif') + "' class='pointer'></div><div class='summaryArea' id='");
        html.push(this.id);
        html.push("Summary'></div>");
    }

    this.createButtons(html);
    content.innerHTML = html.join("");
}

/**
 * convenience method to set the innerHTML of the scrollable content area
 */
FunctionalDialog.prototype.setContentInnerHTML = function(html) {
    this.getContentElement().innerHTML = html;
}

/**
 * convenience method to import another node into the scrollable content area
 */
FunctionalDialog.prototype.importContentNode = function(element) {
    this.setContentInnerHTML("");
    this.getContentElement().appendChild(element);
}

/**
 * returns the content element
 */
FunctionalDialog.prototype.getContentElement = function() {
    return document.getElementById(this.id + "Inner");
}

/**
 * convenience method to set the innerHTML of the summary
 */
FunctionalDialog.prototype.setSummaryInnerHTML = function(html) {
    this.getSummaryElement().innerHTML = html;
}

/**
 * convenience method to import nodes into the summary area
 */
FunctionalDialog.prototype.importSummaryNode = function(element) {
    this.setSummaryInnerHTML("");
    this.getSummaryElement().appendChild(element);
}

/**
 * returns the summary element
 */
FunctionalDialog.prototype.getSummaryElement = function() {
    return document.getElementById(this.id + "Summary");
}

/**
 * Hide summary element and related split element.
 */
FunctionalDialog.prototype.hideSummaryElement = function() {
    if (!this.hasSummaryElement) return; // don't need to do anything

    this.hasSummaryElement = false;
    var summary = this.getSummaryElement();
    var split = document.getElementById(this.id + "Split");
    var inner = this.getContentElement();
    if (summary && split && inner) {
        summary.style.display = 'none';
        split.style.display = 'none';
        inner.className = "scrollableAreaBottomBorder";
    }
}

var RuleFilterPage = {};

RuleFilterPage.toggleReassignElements = function (baseName, baseTemplateName) {
    var isChecked = document.getElementById(baseName+RuleFilterPageConstants.NO_REASSIGN_SUFFIX).checked

    document.getElementById(baseName).disabled = isChecked;
    document.getElementById(baseName + MultiLookupInputElement.MULTI_LOOKUP_SELECT_SUFFIX).disabled = isChecked;
    document.getElementById(baseName + LookupInputElement.pLOOKUP_WIDGET).style.display = (isChecked) ? 'none' : 'inline';
    document.getElementById(baseName).parentNode.parentNode.firstChild.style.display = (isChecked) ? 'none' : 'inline';
    document.getElementById(baseTemplateName).disabled = isChecked;
    document.getElementById(baseTemplateName + LookupInputElement.pLOOKUP_WIDGET).style.display = (isChecked) ? 'none' : 'inline';
};

/**
 * @author zzhou
 * since 148
 * AvailableSection fields javascript code; also see AvailableSection.js, CrtLayout.js, Lookups.js
 */

CrtLayoutElement.initAvailField = function(sectionId, fieldValue, fieldLabel, inLayout, isLookup) {
    var availField = new AvailableField(sectionId,fieldValue,fieldLabel, inLayout, isLookup);
    CrtLayoutElement.availableSections[sectionId].addField(availField);
}

function AvailableField(sectionId,fieldValue,fieldLabel, inLayout, isLookup) {
    this.id = fieldValue;
    this.sectionId = sectionId;
    this.fieldValue = fieldValue;
    this.fieldLabel = escapeHTML(fieldLabel);
    this.isSelected = false;
    this.pageNum = 1;
    this.inLayout = inLayout;
    this.isLookup = isLookup;
    //this takes too long to set for lookup fields -- set it when we actually hover
    this.displayName = this.isLookup ? null : this.fieldLabel;

    //TODO type
    this.type = 's';
    this.mousingOver = false;

}

AvailableField.prototype.getFieldValue = function() {
    return this.fieldValue;
}

AvailableField.prototype.render = function() {
    var className = 'availField';
    if (this.inLayout) {
        className += ' usedAvailField';
    } else {
        className += ' unusedAvailField';
    }
    if (this.isSelected) {
        className += ' ' +CrtLayoutElement.CSS_CLASS_SELECTED_ITEM;
    }
    if (!this.elem) {
        this.elem = document.getElementById(this.id);
    }
    if (this.elem) {
        this.elem.className = className;
    }

}

AvailableField.prototype.formatDName = function() {
    if (this.fieldLabel.length > CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH) {
        return this.fieldLabel.substring(0,CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH-2)+"...";
    }
    else {
        return this.fieldLabel;
    }
}

AvailableField.prototype.setToUsed = function() {
    var self = this;
    self.inLayout = true;
    if (this.mouseOverDiv) {
        this.mouseOverDiv.innerHTML = '';
        this.mouseOverDiv.style.display = 'none';
        this.mouseOverDiv = null;
        this.mousingOver = false;
    }
}

AvailableField.prototype.setToAvailable = function() {
    this.inLayout = false;
}

AvailableField.prototype.handleMouseOver = function(evt) {
    var evt = getEvent(evt);
    this.posX = getMouseX(evt);
    this.posY = getMouseY(evt);
    if (!this.inLayout && !CrtLayoutElement.dragMove && !this.mousingOver) {
        var self = this;
        this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
        this.mousingOver = true;
    }
}

AvailableField.prototype.handleMouseOut = function (evt) {
    if (this.inLayout) {
        return;
    }
    document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
    clearTimeout(this.timeOut);
    this.mousingOver = false;
}

AvailableField.prototype.handleMouseDown = function(evt) {
      if (this.inLayout) {
          CrtLayoutElement.clearTextSelection();
          return;
      }
      var evt = getEvent(evt);
      if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
          this.toggleSelected(false);
      }
      CrtLayoutElement.mouseDown = true;
}

AvailableField.prototype.handleMouseClick = function(evt) {
    if (this.inLayout) {
        CrtLayoutElement.clearTextSelection();
        return;
    }
    var evt = getEvent(evt);
    if (evt.ctrlKey) {
        this.toggleSelected(true);
    } else {

    }
}

AvailableField.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
}

//remove this field from the layout; used currently by the lookup sections
AvailableField.prototype.removeFromLayout = function() {
    if (this.inLayout) {
        var itemObj = CrtLayoutElement.lookupItemPosMap[this.fieldValue];
        //set this cell to empty and return the id of the table to reformat
        itemObj.handleMoved();
    }
}

AvailableField.prototype.removeSelection = function(noBucketRemove) {
    if (!noBucketRemove) {
        this.moveableItem.removeSelection();
    }
    this.moveableItem = null;
    this.removeSelectionFormatting();
}

AvailableField.prototype.removeSelectionFormatting = function() {
    this.isSelected = false;
    this.render();
}

AvailableField.prototype.handleMoved = function() {
    this.setToUsed();
    this.removeSelectionFormatting();
}

AvailableField.prototype.addSelection = function() {
    var addSelection;
    this.moveableItem = this.createMoveableItem();
    addSelection = this.moveableItem.addSelection();
    //are we mixing the selection Bucket?
    if (addSelection) {
        this.addSelectionFormatting();
    }
}

AvailableField.prototype.createMoveableItem = function() {
    return new MoveableItem(this.fieldValue,this.fieldLabel,this.displayName, null, this.type, this, false, false, this.isLookup, false);
}

AvailableField.prototype.addSelectionFormatting = function() {
    this.isSelected = true;
    this.render();
}

AvailableField.prototype.handleMoveTo = function() {
    this.setToAvailable();
    this.render();
}

AvailableField.prototype.setupMouseOverDiv = function(evt) {
    var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
    var html = '';
    var posx = this.posX-210;
    var posy = this.posY-80;
    html += '<div class="mouseOverHeader">'+ this.fieldLabel + (this.isLookup ? ' ' + LC.getLabel("CRTLookupLayer","viaLookupParen") : '') + '</div>';
    if (!this.displayName) {
        this.displayName = CrtLayoutElement.getDisplayPath(this.fieldValue,true);
    }
    html += '<div class="mouseOverBody">'+LC.getLabel("CrtLayout","CustomLabel")+': '+ this.displayName + '<br>';
    if (this.isLookup) {
        html += '<br>';
        html += LC.getLabel("CrtLayout","lookupPath") + ' ' + CrtLayoutElement.getDisplayPath(this.fieldValue,false);
        html += '<br>';
    }
    html += '<br>' + LC.getLabel("CrtLayout","availFieldHover");
    moElem.innerHTML = html;
    moElem.style.display = 'block';
    moElem.style.left = posx+"px";
    moElem.style.top = posy+"px";
    return moElem;
}

/**
 * Function to handle the Save and Cancel functionality on the Email Address Edit page related
 * to Email Author.
 * @author ccopek
 * @since 150
 */

function EmailAddrEdit() {}

EmailAddrEdit.prototype.changeToCancelRetURL = function() {
    var qs = new QueryString("");
    qs.add(EmailAddrEditConstants.pSAVE_CANCEL, "true");

    document.editPage.elements['retURL'].value = UrlMap.getURL("EmailAuthorPopupCloser") + qs.toString();
 }
/*
 * @author ji.wang
 * @since 156
 *
 * Static functions used by Activity and Event page
 */

/**
 * Object definition of ActivityFunction
 */
function ActivityFunction() {
    leadPrefix = null;
    whatNameId = null;
    whatIdId = null;
    whatLinkId = null;
    whatLookupId = null;
    isVisibleInSelfServiceId = null;
}

/**
 * Init HTML fields by passed in json object
 */
ActivityFunction.initWhatFieldsWithJsonObj = function (jsonObj) {
    ActivityFunction.initWhatFields(jsonObj[EventUi.LEAD_PREFIX_PARAM_NAME],
                        jsonObj[EventUi.WHAT_NAME_PARAM_NAME],
                        jsonObj[EventUi.WHAT_ID_PARAM_NAME],
                        jsonObj[EventUi.WHAT_LINK_PARAM_NAME],
                        jsonObj[EventUi.WHAT_TYPE_PARAM_NAME],
                        jsonObj[EventUi.VISIBLE_IN_SS_PARAM_NAME]);
}

/**
 * Init static variables of ActivityFunction
 */
ActivityFunction.initWhatFields = function (leadPrefix, whatNameId, whatIdId, whatLinkId, whatLookupId, isVisibleInSelfServiceId) {
    ActivityFunction.leadPrefix = leadPrefix;
    ActivityFunction.whatNameId = whatNameId;
    ActivityFunction.whatIdId = whatIdId;
    ActivityFunction.whatLinkId = whatLinkId;
    ActivityFunction.whatLookupId = whatLookupId;
    ActivityFunction.isVisibleInSelfServiceId = isVisibleInSelfServiceId;
}

/**
 * disable Element of whatName, whatLink and whatLookup
 */
ActivityFunction.dswt = function () {
    var whatNameElem = document.getElementById(ActivityFunction.whatNameId);
    var whatLinkElem = document.getElementById(ActivityFunction.whatLinkId);
    var whatLookupElem = document.getElementById(ActivityFunction.whatLookupId);

    if (whatNameElem) {
       whatNameElem.disabled=true;
    }
    if (whatLinkElem) {
       whatLinkElem.style.display='none';
    }
    if (whatLookupElem) {
        whatLookupElem.disabled=true;
    }
}

/**
 * Enable Element of whatName, whatLink and whatLookup
 */
ActivityFunction.enwt = function () {
    var whatNameElem = document.getElementById(ActivityFunction.whatNameId);
    var whatLinkElem = document.getElementById(ActivityFunction.whatLinkId);
    var whatLookupElem = document.getElementById(ActivityFunction.whatLookupId);

    if (whatNameElem) {
       whatNameElem.disabled=false;
    }
    if (whatLinkElem) {
       whatLinkElem.style.display='';
    }
    if (whatLookupElem) {
        whatLookupElem.disabled=false;
    }
}

/**
 * Adjust Element display according the value of whatName and whatId
 */
ActivityFunction.adjwht = function (whoTypeId) {
    var whatNameElem = document.getElementById(ActivityFunction.whatNameId);
    var whatIdElem = document.getElementById(ActivityFunction.whatIdId);

    if (document.getElementById(whoTypeId).value == ActivityFunction.leadPrefix) {
        if (whatNameElem) {
            whatNameElem.value='';
        }
        if (whatIdElem) {
            whatIdElem.value='';
        }
        ActivityFunction.dswt();
    }