-
Notifications
You must be signed in to change notification settings - Fork 43
Do not autofocus in iframes + other fixes. #778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
af8bfa8
f12aeca
e28836a
7db14ea
eb8564e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,44 @@ | ||
/** | ||
* Patterns autofocus - enhanced autofocus form elements | ||
* | ||
* Copyright 2012-2013 Simplon B.V. - Wichert Akkerman | ||
*/ | ||
import $ from "jquery"; | ||
import registry from "../../core/registry"; | ||
import Base from "../../core/base"; | ||
|
||
var autofocus = { | ||
let scheduled_task = null; | ||
let registered_event_handler = false; | ||
|
||
export default Base.extend({ | ||
name: "autofocus", | ||
trigger: ":input.pat-autofocus,:input[autofocus]", | ||
|
||
init: function init() { | ||
init() { | ||
if (window.self !== window.top) { | ||
// Do not autofocus in iframes. | ||
return; | ||
} | ||
|
||
this.setFocus(this.trigger); | ||
$(document).on("patterns-injected", function (e) { | ||
autofocus.setFocus($(e.target).find(autofocus.trigger)); | ||
}); | ||
$(document).on("pat-update", function (e) { | ||
autofocus.setFocus($(e.target).find(autofocus.trigger)); | ||
}); | ||
}, | ||
setFocus: function (target) { | ||
var $all = $(target); | ||
var $visible = $all.filter(function () { | ||
if ($(this).is(":visible")) return true; | ||
}); | ||
setTimeout(function () { | ||
$visible.get(0) && $visible.get(0).focus(); | ||
}, 10); | ||
|
||
if (!registered_event_handler) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pilz: We want the global event handler registered only once. |
||
// Register the event handler only once. | ||
$(document).on("patterns-injected pat-update", (e) => { | ||
this.setFocus($(e.target).find(this.trigger)); | ||
}); | ||
registered_event_handler = true; | ||
} | ||
}, | ||
}; | ||
|
||
registry.register(autofocus); | ||
export default autofocus; | ||
setFocus(target) { | ||
// Exit if task is scheduled. setFocus operates on whole DOM anyways. | ||
if (scheduled_task) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pilz: If there is already a setFocus task scheduled, exit. No need to do it multiple times as this method operates on the whole DOM tree and is not scoped for the element itself. |
||
return; | ||
} | ||
const $all = $(target); | ||
const visible = [...$all].filter((it) => $(it).is(":visible")); | ||
const empty = visible.filter((it) => it.value === ""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pilz: this fix is for the documented behavior (in documentation.md + the index.html) to not autofocus if the input is not empty and there is another autofocus element. |
||
const el = empty[0] || visible[0]; | ||
if (el) { | ||
scheduled_task = setTimeout(() => { | ||
el.focus(); | ||
scheduled_task = null; | ||
}, 10); | ||
} | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import pattern from "./autofocus"; | ||
import utils from "../../core/utils"; | ||
|
||
describe("pat-autofocus", function () { | ||
beforeEach(function () { | ||
const el = document.createElement("div"); | ||
el.setAttribute("id", "lab"); | ||
document.body.append(el); | ||
}); | ||
|
||
afterEach(function () { | ||
document.body.innerHTML = ""; | ||
}); | ||
|
||
it("Focus the first element.", async (done) => { | ||
const container = document.querySelector("#lab"); | ||
container.innerHTML = ` | ||
<input name="i1" type="text" class="pat-autofocus"/> | ||
<input name="i2" type="text" class="pat-autofocus"/> | ||
<input name="i3" type="text" class="pat-autofocus"/> | ||
`; | ||
pattern.init(container); | ||
await utils.timeout(20); | ||
|
||
const should_be_active = document.querySelector("input[name=i1]"); | ||
expect(document.activeElement).toBe(should_be_active); | ||
|
||
done(); | ||
}); | ||
|
||
it("Focus the non-empty element, if available.", async (done) => { | ||
const container = document.querySelector("#lab"); | ||
container.innerHTML = ` | ||
<input name="i1" type="text" class="pat-autofocus" value="okay"/> | ||
<input name="i2" type="text" class="pat-autofocus"/> | ||
<input name="i3" type="text" class="pat-autofocus"/> | ||
`; | ||
pattern.init(container); | ||
await utils.timeout(20); | ||
|
||
const should_be_active = document.querySelector("input[name=i2]"); | ||
expect(document.activeElement).toBe(should_be_active); | ||
|
||
done(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
<title>Focus demo page</title> | ||
<link rel="stylesheet" href="/style/common.css" type="text/css" /> | ||
<script src="/dist/bundle.js" type="text/javascript"></script> | ||
<style type="text/css" media="screen"> | ||
form { | ||
margin-top: 400px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<form action=""> | ||
<label>Title | ||
<input class="pat-autofocus" type="text" /> | ||
</label> | ||
</form> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,24 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
<title>Focus demo page</title> | ||
<link rel="stylesheet" href="/style/common.css" type="text/css" /> | ||
<script | ||
src="/dist/bundle.js" | ||
type="text/javascript" | ||
charset="utf-8" | ||
></script> | ||
</head> | ||
<body> | ||
<form action=""> | ||
<fieldset class="horizontal"> | ||
<label> | ||
Title | ||
<input | ||
class="pat-autofocus" | ||
type="text" | ||
value="Prefilled title" /></label | ||
><br /> | ||
<label> | ||
Keywords | ||
<input | ||
class="pat-autofocus" | ||
type="text" | ||
placeholder="This field should get the focus" | ||
/></label> | ||
</fieldset> | ||
</form> | ||
</body> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||
<title>Focus demo page</title> | ||
<link rel="stylesheet" href="/style/common.css" type="text/css" /> | ||
<script src="/dist/bundle.js" type="text/javascript"></script> | ||
</head> | ||
<body> | ||
<form action=""> | ||
<fieldset class="horizontal"> | ||
<label>Title | ||
<input class="pat-autofocus" type="text" value="Prefilled title" /> | ||
</label> | ||
<br /> | ||
<label>Keywords | ||
<input class="pat-autofocus" type="text" placeholder="This field should get the focus" /> | ||
</label> | ||
</fieldset> | ||
</form> | ||
<p>Elements in the iframe below should not get the focus.</p> | ||
<iframe src="./index-iframed.html" frameborder="0" style="width: 400px; height: 300px; border: 1px solid black;"></iframe> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pilz: requested fix.