通常,您希望在更改首选项时对其进行验证。这就是onchange
属性(和相应的change
事件)有利于:
<preference name="preference.name" onchange="validate(this);"/>
在首选项值更改后触发该事件。有两个缺点:
- 如果
instantApply
新的偏好值已经被保存,来不及验证和拒绝。
- 对于文本字段,每次输入新字符时都会保存首选项。如果您在用户仍在键入时报告验证失败,这将变得很难看。
您可以通过拦截实际输入字段的更改事件来解决第一个问题。例如,对于文本字段,您可以:
<input preference="preference.name"
oninput="if (!validate(this)) event.stopPropagation();"
onchange="if (!validate(this)) { event.stopPropagation(); this.focus(); }"/>
因此,未正确验证的更改不会冒泡到<prefpane>
元素并且不会被保存。要监听的事件是:对于文本字段,对于按钮和复选框,input
对于元素。change
command
select
<colorpicker>
第二个问题很棘手。您仍然希望在输入发生时验证输入,但是立即显示消息将是糟糕的 UI。我认为最好的解决方案是最初假设每个输入字段仍在“进行中”。blur
当您第一次看到该字段上的事件时,您只会设置一个值已完成的标志。那时您可以在必要时显示验证消息(理想情况下,您的首选项页面中会显示红色文本,而不是模式提示)。
所以要指出最终解决方案的样子(未经测试的代码,但我过去使用过类似的东西):
<description id="error" hidden="true">Invalid preference value</description>
<input preference="preference.name"
_errorText="error"
onblur="validate(event);"
oninput="validate(event);"
onchange="validate(event);/>
<script>
function validate(event)
{
// Perform actual validation
var field = event.target;
var valid = isValid(field);
// If this is the blur event then the element is no longer "in progress"
if (event.type == "blur")
{
field._inputDone = true;
if (!valid)
field.focus();
}
// Prevent preferences changing to invalid value
if (!valid)
event.stopPropagation();
// Show or hide error text
var errorText = document.getElementById(field.getAttribute("_errorText"));
errorText.hidden = valid || !field._inputDone;
}
</script>