/* -*- Mode: java; tab-width: 2; c-label-minimum-indentation: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Cyrus: comparator-i;ascii-numeric fileinto reject vacation imapflags notify envelope relational regex subaddress copy */ var sieveCapabilities = []; var filter; var selectedRuleDiv = null; var selectedActionDiv = null; var fieldLabels; var methodLabels; var operatorLabels; var operatorRequirements; var methodRequirements; var flagLabels; var mailboxes = []; function onLoadHandler() { setupConstants(); setupEventHandlers(); if (window.opener) sieveCapabilities = window.opener.getSieveCapabilitiesFromEditor(); if (!window.opener || filterId == "new") { setupNewFilterData(); } else { filter = window.opener.getFilterFromEditor(filterId).evalJSON(); } if (!window.opener || window.opener.userMailboxes) { setupFilterViews(); } else { loadMailboxes(); } } function loadMailboxes() { var url = ApplicationBaseURL + "Mail/0/mailboxes"; triggerAjaxRequest(url, onLoadMailboxesCallback); } function onLoadMailboxesCallback(http) { if (http.readyState == 4) { // log("http.status: " + http.status); if (http.status == 200) { checkAjaxRequestsState(); if (http.responseText.length > 0) { var jsonResponse = http.responseText.evalJSON(true); window.opener.setupMailboxesFromJSON(jsonResponse); } } setupFilterViews(); } } function setupConstants() { fieldLabels = { "subject": _("Subject"), "from": _("From"), "to": _("To"), "cc": _("Cc"), "to_or_cc": _("To or Cc"), "size": _("Size (Kb)"), "header": _("Header") }; methodLabels = { "addflag": _("Flag the message with:"), "discard": _("Discard the message"), "fileinto": _("File the message in:"), "keep": _("Keep the message"), "redirect": _("Forward the message to:"), "reject": _("Send a reject message:"), "vacation": _("Send a vacation message"), "stop": _("Stop processing filter rules") }; operatorLabels = { "under": _("is under"), "over": _("is over"), "is": _("is"), "is_not": _("is not"), "contains": _("contains"), "contains_not": _("does not contain"), "matches": _("matches"), "matches_not": _("does not match"), "regex": _("matches regex"), "regex_not": _("does not match regex") }; flagLabels = { "seen": _("Seen"), "deleted": _("Deleted"), "answered": _("Answered"), "flagged": _("Flagged"), "junk": _("Junk"), "not_junk": _("Not Junk") }; for (var i = 1; i < 6; i++) { var key = "label" + i; flagLabels[key] = _("Label " + i); } } function setupEventHandlers() { var filterName = $($("mainForm").filterName); if (filterName) { var boundCB = onFilterNameChange .bindAsEventListener(filterName); filterName.observe("change", boundCB); } var matchTypeSelect = $("matchType"); if (matchTypeSelect) { var boundCB = onMatchTypeChange .bindAsEventListener(matchTypeSelect); matchTypeSelect.observe("change", boundCB); } var filterRules = $("filterRules"); var boundCB = onFilterRulesDivClick .bindAsEventListener(filterRules); filterRules.observe("click", boundCB); var ruleAdd = $("ruleAdd"); if (ruleAdd) { var boundCB = onRuleAddClick.bindAsEventListener(ruleAdd); ruleAdd.observe("click", boundCB); } var ruleDelete = $("ruleDelete"); if (ruleDelete) { var boundCB = onRuleDeleteClick.bindAsEventListener(ruleDelete); ruleDelete.observe("click", boundCB); } var filterActions = $("filterActions"); var boundCB = onFilterActionsDivClick .bindAsEventListener(filterActions); filterActions.observe("click", boundCB); var actionAdd = $("actionAdd"); if (actionAdd) { var boundCB = onActionAddClick.bindAsEventListener(actionAdd); actionAdd.observe("click", boundCB); } var actionDelete = $("actionDelete"); if (actionDelete) { var boundCB = onActionDeleteClick .bindAsEventListener(actionDelete); actionDelete.observe("click", boundCB); } } function onFilterNameChange(event) { filter.name = this.value; } function onMatchTypeChange() { var matchType = this.value; filter.match = matchType; var container = $("filterRulesContainer"); var otherContainer = $("filterActionsContainer"); var otherContainerTop; if (matchType == "allmessages") { container.hide(); otherContainerTop = 130; } else { container.show(); otherContainerTop = 240; } otherContainer.setStyle({ top: otherContainerTop + "px" }); } function onFilterRulesDivClick(event) { setSelectedRuleDiv(null); Event.stop(event); } function onFilterActionsDivClick(event) { setSelectedActionDiv(null); Event.stop(event); } function createFilterRule() { return { field: "subject", operator: "contains", value: "" }; } function createFilterAction() { return { method: "fileinto", argument: "INBOX" }; } function setupNewFilterData() { var newFilterTemplate = $({ name: _("Untitled Filter"), match: "any", active: true }); newFilterTemplate.rules = $([ createFilterRule() ]); newFilterTemplate.actions = $([ createFilterAction() ]); filter = newFilterTemplate; } function setupFilterViews() { var filterName = $("mainForm").filterName; if (filterName) { filterName.value = filter.name; if (filterId == "new") { filterName.focus(); $(filterName).selectText(0, filterName.value.length); } } var matchTypeSelect = $("matchType"); if (matchTypeSelect) { matchTypeSelect.value = filter.match; } if (filter.match != "allmessages") { var filterRules = $("filterRules"); if (filterRules && filter.rules) { for (var i = 0; i < filter.rules.length; i++) { appendRule(filterRules, filter.rules[i]); } } } onMatchTypeChange.apply(matchTypeSelect); var filterActions = $("filterActions"); if (filterActions && filter.actions) { for (var i = 0; i < filter.actions.length; i++) { appendAction(filterActions, filter.actions[i]); } } } function appendRule(container, rule) { var ruleDiv = createElement("div", null, "rule", { rule: rule }, null, container); var boundCB = onRuleDivClick.bindAsEventListener(ruleDiv); ruleDiv.observe("click", boundCB); ensureRuleRepresentation(ruleDiv); return ruleDiv; } function onRuleDivClick(event) { setSelectedRuleDiv(this); Event.stop(event); } function setSelectedRuleDiv(newDiv) { if (selectedRuleDiv) { selectedRuleDiv.removeClassName("_selected"); } selectedRuleDiv = newDiv; if (selectedRuleDiv) { selectedRuleDiv.addClassName("_selected"); } } function ensureRuleRepresentation(container) { ensureFieldRepresentation(container); ensureOperatorRepresentation(container); ensureValueRepresentation(container); } function ensureFieldRepresentation(container) { var fieldSpans = container.select("SPAN.fieldContainer"); var fieldSpan; if (fieldSpans.length) fieldSpan = fieldSpans[0]; else { while (container.firstChild) { container.removeChild(container.firstChild); } fieldSpan = createElement("span", null, "fieldContainer", null, null, container); } ensureFieldSelectRepresentation(container, fieldSpan); ensureFieldCustomHeaderRepresentation(container, fieldSpan); } function ensureFieldSelectRepresentation(container, fieldSpan) { var fields = [ "subject", "from", "to", "cc", "to_or_cc", "size", "header" ]; var selects = fieldSpan.select("SELECT"); var select; if (selects.length) select = selects[0]; else { select = createElement("select"); select.rule = container.rule; var boundCB = onFieldSelectChange.bindAsEventListener(select); select.observe("change", boundCB); for (var i = 0; i < fields.length; i++) { var field = fields[i]; var fieldOption = createElement("option", null, null, { value: field }, null, select); fieldOption.appendChild(document .createTextNode(fieldLabels[field])); } fieldSpan.appendChild(select); } select.value = container.rule.field; container.rule.field = select.value; } function onFieldSelectChange(event) { this.rule.field = this.value; var fieldSpan = this.parentNode; var container = fieldSpan.parentNode; ensureFieldCustomHeaderRepresentation(container, fieldSpan); ensureOperatorRepresentation(container); ensureValueRepresentation(container); } function ensureFieldCustomHeaderRepresentation(container, fieldSpan) { var headerInputs = fieldSpan.select("INPUT"); var headerInput = null; if (headerInputs.length) { headerInput = headerInputs[0]; } if (container.rule.field == "header") { if (!headerInput) { headerInput = createElement("input", null, null, { type: "text" }, null, fieldSpan); headerInput.rule = container.rule; if (!container.rule.custom_header) container.rule.custom_header = ""; headerInput.value = container.rule.custom_header; var boundCB = onFieldCustomHeaderChange.bindAsEventListener(headerInput); headerInput.observe("change", boundCB); headerInput.focus(); } } else { if (headerInput) { if (container.rule.custom_header) container.rule.custom_header = null; fieldSpan.removeChild(headerInput); } } } function onFieldCustomHeaderChange(event) { this.rule.custom_header = this.value; } function ensureOperatorRepresentation(container) { var operatorSpans = container.select("SPAN.operatorContainer"); var operatorSpan; if (operatorSpans.length) operatorSpan = operatorSpans[0]; else operatorSpan = createElement("span", null, "operatorContainer", null, null, container); ensureOperatorSelectRepresentation(container, operatorSpan); } function ensureOperatorSelectRepresentation(container, operatorSpan) { var operators = determineOperators(container.rule.field); var ruleField = container.rule.field; var selects = operatorSpan.select("SELECT"); var select = null; if (selects.length) { select = selects[0]; if ((ruleField == "size" && !select.sizeOperator) || (ruleField != "size" && select.sizeOperator)) { operatorSpan.removeChild(select); select = null; } } if (!select) { select = createElement("select"); select.rule = container.rule; select.sizeOperator = (ruleField == "size"); var boundCB = onOperatorSelectChange.bindAsEventListener(select); select.observe("change", boundCB); for (var i = 0; i < operators.length; i++) { var operator = operators[i]; var operatorOption = createElement("option", null, null, { value: operator }, null, select); operatorOption.appendChild(document .createTextNode(operatorLabels[operator])); } operatorSpan.appendChild(select); } if (container.rule.operator && operators.indexOf(container.rule.operator) == -1) { container.rule.operator = operators[0]; } select.value = container.rule.operator; container.rule.operator = select.value; } function onOperatorSelectChange(event) { this.rule.operator = this.value; var valueSpans = this.parentNode.parentNode.select("SPAN.valueContainer"); if (valueSpans.length) { var valueInputs = valueSpans[0].select("INPUT"); if (valueInputs.length) { valueInputs[0].focus(); } } } function determineOperators(field) { var operators; if (field == "size") { operators = [ "under", "over" ]; } else { var baseOperators = [ "is", "contains", "matches" ]; if (sieveCapabilities.indexOf("regex") > -1) { baseOperators.push("regex"); } operators = []; for (var i = 0; i < baseOperators.length; i++) { operators.push(baseOperators[i]); operators.push(baseOperators[i] + "_not"); } } return operators; } function ensureValueRepresentation(container) { var valueSpans = container.select("SPAN.valueContainer"); var valueSpan; if (valueSpans.length) valueSpan = valueSpans[0]; else valueSpan = createElement("span", null, "valueContainer", null, null, container); ensureValueInputRepresentation(container, valueSpan); } function ensureValueInputRepresentation(container, valueSpan) { var inputs = valueSpan.select("INPUT"); var input; if (inputs.length) { input = inputs[0]; } else { input = createElement("input", null, "textField"); input.rule = container.rule; var boundCB = onValueInputChange.bindAsEventListener(input); input.observe("change", boundCB); valueSpan.appendChild(input); } input.value = container.rule.value; ensureFieldValidity(input); } function ensureFieldValidity(input) { var valid = ensureFieldIsNotEmpty(input); if (valid && input.rule.field == "size") { valid = ensureFieldIsNumerical(input); } return valid; } function onValueInputChange(event) { if (ensureFieldValidity(this)) this.rule.value = this.value; else this.rule.value = ""; } function ensureFieldIsNumerical(input) { var valid = !isNaN(input.value); if (valid) { input.removeClassName("_invalid"); } else { input.addClassName("_invalid"); } return valid; } function ensureFieldIsNotEmpty(input) { var valid = !input.value.blank(); if (valid) { input.removeClassName("_invalid"); } else { input.addClassName("_invalid"); } return valid; } function appendAction(container, action) { var actionDiv = createElement("div", null, "action", { action: action }, null, container); var boundCB = onActionDivClick.bindAsEventListener(actionDiv); actionDiv.observe("click", boundCB); ensureActionRepresentation(actionDiv); return actionDiv; } function onActionDivClick(event) { setSelectedActionDiv(this); Event.stop(event); } function setSelectedActionDiv(newSpan) { if (selectedActionDiv) { selectedActionDiv.removeClassName("_selected"); } selectedActionDiv = newSpan; if (selectedActionDiv) { selectedActionDiv.addClassName("_selected"); } } function ensureActionRepresentation(container) { ensureMethodRepresentation(container); ensureArgumentRepresentation(container); } function ensureMethodRepresentation(container) { var methodSpans = container.select("SPAN.methodContainer"); var methodSpan; if (methodSpans.length) methodSpan = methodSpans[0]; else { while (container.firstChild) { container.removeChild(container.firstChild); } methodSpan = createElement("span", null, "methodContainer", null, null, container); } ensureMethodSelectRepresentation(container, methodSpan); } function ensureMethodSelectRepresentation(container, methodSpan) { var methods = [ "redirect", "discard", "keep" ]; if (sieveCapabilities.indexOf("reject") > -1) { methods.push("reject"); } if (sieveCapabilities.indexOf("fileinto") > -1) { methods.push("fileinto"); } if (sieveCapabilities.indexOf("imapflags") > -1) { methods.push("addflag"); } methods.push("stop"); /* TODO: those are currently unimplemented */ // if (sieveCapabilities.indexOf("notify") > -1) { // methods.push("notify"); // } // if (sieveCapabilities.indexOf("vacation") > -1) { // methods.push("vacation"); // } var selects = methodSpan.select("SELECT"); var select; if (selects.length) select = selects[0]; else { select = createElement("select"); select.action = container.action; var boundCB = onMethodSelectChange.bindAsEventListener(select); select.observe("change", boundCB); for (var i = 0; i < methods.length; i++) { var method = methods[i]; var methodOption = createElement("option", null, null, { value: method }, null, select); methodOption.appendChild(document .createTextNode(methodLabels[method])); } methodSpan.appendChild(select); } select.value = container.action.method; } function onMethodSelectChange(event) { this.action.method = this.value; var methodSpan = this.parentNode; var container = methodSpan.parentNode; ensureArgumentRepresentation(container); } function ensureArgumentRepresentation(container) { var argumentWidgetMethods = { "addflag": ensureFlagArgRepresentation, "fileinto": ensureMailboxArgRepresentation, "redirect": ensureRedirectArgRepresentation, "reject": ensureRejectArgRepresentation, "vacation": ensureVacationArgRepresentation }; var widgetMethod = argumentWidgetMethods[container.action.method]; var spanClass = container.action.method + "Argument"; var argumentSpans = container.select("SPAN.argumentContainer"); var argumentSpan; if (argumentSpans.length) { argumentSpan = argumentSpans[0]; if (argumentSpan && (!widgetMethod || !argumentSpan.hasClassName(spanClass))) { container.removeChild(argumentSpan); container.action.argument = null; argumentSpan = null; } } else argumentSpan = null; if (!argumentSpan && widgetMethod) { argumentSpan = createElement("span", null, ["argumentContainer", spanClass], null, null, container); widgetMethod(container, argumentSpan); } } function ensureFlagArgRepresentation(container, argumentSpan) { var flags = [ "seen", "deleted", "answered", "flagged", "junk", "not_junk" ]; for (var i = 1; i < 6; i++) { flags.push("label" + i); } var selects = argumentSpan.select("SELECT"); var select; if (selects.length) select = selects[0]; else { select = createElement("select"); select.action = container.action; var boundCB = onFlagArgumentSelectChange.bindAsEventListener(select); select.observe("change", boundCB); for (var i = 0; i < flags.length; i++) { var flag = flags[i]; var flagOption = createElement("option", null, null, { value: flag }, null, select); var label = flagLabels[flag]; flagOption.appendChild(document.createTextNode(label)); } argumentSpan.appendChild(select); } /* 1) initialize the value if null 2) set the SELECT to the corresponding value 3) if value was not null in 1, we must ensure the SELECT contains it */ if (!container.action.argument) container.action.argument = "seen"; select.value = container.action.argument; container.action.argument = select.value; } function onFlagArgumentSelectChange(event) { this.action.argument = this.value; } function ensureMailboxArgRepresentation(container, argumentSpan) { var selects = argumentSpan.select("SELECT"); var select; if (selects.length) select = selects[0]; else { select = createElement("select"); select.action = container.action; if (!container.action.argument) container.action.argument = "INBOX"; var boundCB = onMailboxArgumentSelectChange.bindAsEventListener(select); select.observe("change", boundCB); var mailboxes = (window.opener ? window.opener.userMailboxes : ["INBOX" ]); for (var i = 0; i < mailboxes.length; i++) { var mailbox = mailboxes[i]; var mboxOption = createElement("option", null, null, { value: mailbox }, null, select); mboxOption.appendChild(document.createTextNode(mailbox)); } argumentSpan.appendChild(select); } select.value = container.action.argument; container.action.argument = select.value; } function onMailboxArgumentSelectChange(event) { this.action.argument = this.value; } function ensureRedirectArgRepresentation(container, argumentSpan) { var emailInputs = argumentSpan.select("INPUT"); var emailInput = null; if (emailInputs.length) { emailInput = emailInputs[0]; } if (!emailInput) { emailInput = createElement("input", null, "textField", { type: "text" }, null, argumentSpan); emailInput.action = container.action; if (!container.action.argument) container.action.argument = ""; var boundCB = onEmailArgumentChange.bindAsEventListener(emailInput); emailInput.observe("change", boundCB); emailInput.focus(); } emailInput.value = container.action.argument; } function onEmailArgumentChange(event) { this.action.argument = this.value; } function ensureRejectArgRepresentation(container, argumentSpan) { var msgAreas = argumentSpan.select("TEXTAREA"); var msgArea = null; if (msgAreas.length) { msgArea = msgAreas[0]; } if (!msgArea) { msgArea = createElement("textarea", null, null, { action: container.action }, null, argumentSpan); if (!container.action.argument) container.action.argument = ""; var boundCB = onMsgArgumentChange.bindAsEventListener(msgArea); msgArea.observe("change", boundCB); msgArea.focus(); } msgArea.value = container.action.argument; } function onMsgArgumentChange(event) { this.action.argument = this.value; } function ensureVacationArgRepresentation(container, argumentSpan) { } function onRuleAddClick(event) { var filterRules = $("filterRules"); if (filterRules) { var newRule = createFilterRule(); if (!filter.rules) filter.rules = []; filter.rules.push(newRule); var newRuleDiv = appendRule(filterRules, newRule); setSelectedRuleDiv(newRuleDiv); filterRules.scrollTop = newRuleDiv.offsetTop; } Event.stop(event); } function onRuleDeleteClick(event) { if (selectedRuleDiv) { var ruleIndex = filter.rules.indexOf(selectedRuleDiv.rule); filter.rules.splice(ruleIndex, 1); var nextSelected = selectedRuleDiv.next(); if (!nextSelected) nextSelected = selectedRuleDiv.previous(); selectedRuleDiv.parentNode.removeChild(selectedRuleDiv); setSelectedRuleDiv(nextSelected); } Event.stop(event); } function onActionAddClick(event) { var filterActions = $("filterActions"); if (filterActions) { var newAction = createFilterAction(); filter.actions.push(newAction); var newActionDiv = appendAction(filterActions, newAction); setSelectedActionDiv(newActionDiv); filterActions.scrollTop = newActionDiv.offsetTop; } Event.stop(event); } function onActionDeleteClick(event) { if (selectedActionDiv) { var actionIndex = filter.actions.indexOf(selectedActionDiv.action); filter.actions.splice(actionIndex, 1); var nextSelected = selectedActionDiv.next(); if (!nextSelected) nextSelected = selectedActionDiv.previous(); selectedActionDiv.parentNode.removeChild(selectedActionDiv); setSelectedActionDiv(nextSelected); } Event.stop(event); } function savePreferences(event) { var valid = true; var container = $('filterRulesContainer'); if (container.visible()) { var rules = container.select("DIV#filterRules DIV.rule"); if (rules.length == 0) { onRuleAddClick(event); valid = false; } else { var inputs = $$("DIV#filterRules input"); inputs.each(function(input) { if (input.hasClassName("_invalid")) valid = false; }); } } var actions = $$("DIV#filterActions DIV.action"); if (actions.length == 0) { onActionAddClick(event); valid = false; } if (valid) { if (window.opener) { window.opener.updateFilterFromEditor(filterId, Object.toJSON(filter)); } window.close(); } return false; } // function configureDragHandles() { // var handle = $("splitter"); // if (handle) { // handle.addInterface(SOGoDragHandlesInterface); // handle.upperBlock = $("filterRulesContainer"); // handle.lowerBlock = $("filterActionsContainer"); // } // } document.observe("dom:loaded", onLoadHandler);