Skip to content
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

Start when the DOM is interactive #131

Merged
merged 7 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ const config = {
autoWatch: false,

files: [
{ pattern: "packages/*/**/test/index.ts" }
{ pattern: "packages/*/**/test/index.ts" },
{ pattern: "packages/*/**/test/fixtures/**/*", included: false },
],

proxies: {
"/core/": "/base/packages/@stimulus/core/test/fixtures/"
},

preprocessors: {
"packages/**/*.ts": ["webpack"]
"packages/**/*.ts": ["webpack"],
"packages/*/**/test/fixtures/**/*.js": ["webpack"],
},

mime: {
Expand Down
13 changes: 12 additions & 1 deletion packages/@stimulus/core/src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export class Application implements ErrorHandler {
this.router = new Router(this)
}

start() {
async start() {
await domReady()
this.router.start()
}

Expand Down Expand Up @@ -64,3 +65,13 @@ export class Application implements ErrorHandler {
console.error(`%s\n\n%o\n\n%o`, message, error, detail)
}
}

function domReady(): Promise<any> {
return new Promise(resolve => {
if (document.readyState == "loading") {
document.addEventListener("DOMContentLoaded", resolve)
} else {
resolve()
}
})
}
52 changes: 52 additions & 0 deletions packages/@stimulus/core/test/cases/application_start_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { DOMTestCase } from "@stimulus/test"

export default class ApplicationStartTests extends DOMTestCase {
iframe: HTMLIFrameElement

async setup() {
this.iframe = document.createElement("iframe")
this.iframe.src = "/core/application_start/index.html"
this.fixtureElement.appendChild(this.iframe)
}

async "test starting an application when the document is loading"() {
const message = await this.messageFromStartState("loading")
this.assertIn(message.connectState, ["interactive", "complete"])
this.assert.equal(message.targetCount, 3)
}

async "test starting an application when the document is interactive"() {
const message = await this.messageFromStartState("interactive")
this.assertIn(message.connectState, ["interactive", "complete"])
this.assert.equal(message.targetCount, 3)
}

async "test starting an application when the document is complete"() {
const message = await this.messageFromStartState("complete")
this.assertIn(message.connectState, ["complete"])
this.assert.equal(message.targetCount, 3)
}

private messageFromStartState(startState: string): Promise<any> {
return new Promise(resolve => {
const receiveMessage = event => {
if (event.source == this.iframe.contentWindow) {
const message = JSON.parse(event.data)
if (message.startState == startState) {
removeEventListener("message", receiveMessage)
resolve(message)
}
}
}
addEventListener("message", receiveMessage)
})
}

private assertIn(actual: any, expected: any[]) {
const state = expected.indexOf(actual) > -1
const message = `${JSON.stringify(actual)} is not in ${JSON.stringify(expected)}`
this.assert.ok(state, message)
}
}


21 changes: 21 additions & 0 deletions packages/@stimulus/core/test/fixtures/application_start/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Application, Controller } from "@stimulus/core"

export function startApplication() {
const startState = document.readyState

class PostMessageController extends Controller {
itemTargets: Element[]

static targets = [ "item" ]

connect() {
const connectState = document.readyState
const targetCount = this.itemTargets.length
const message = JSON.stringify({ startState, connectState, targetCount })
parent.postMessage(message, location.origin)
}
}

const application = Application.start()
application.register("a", PostMessageController)
}
22 changes: 22 additions & 0 deletions packages/@stimulus/core/test/fixtures/application_start/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="index.js"></script>
</head>
<body>
<div data-controller="a">
<span data-target="a.item"></span>
<span data-target="a.item"></span>
<script>
// If "a" controller is loaded while the document is loading,
// synchronously accessing `this.itemTargets` will only return
// the first two target elements. The third hasn't been parsed
// yet because the browser's still working through this script.
// See: https://github.com/stimulusjs/stimulus/issues/97
1 + 1
</script>
<span data-target="a.item"></span>
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "@stimulus/polyfills"
import { startApplication } from "./helpers"

startApplication()
addEventListener("DOMContentLoaded", startApplication)
addEventListener("load", startApplication)
8 changes: 5 additions & 3 deletions packages/@stimulus/mutation-observers/src/element_observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export class ElementObserver {

start() {
if (!this.started) {
this.mutationObserver.observe(this.element, { attributes: true, childList: true, subtree: true })
this.started = true
this.mutationObserver.observe(this.element, { attributes: true, childList: true, subtree: true })
this.refresh()
}
}
Expand Down Expand Up @@ -59,8 +59,10 @@ export class ElementObserver {
// Mutation record processing

private processMutations(mutations: MutationRecord[]) {
for (const mutation of mutations) {
this.processMutation(mutation)
if (this.started) {
for (const mutation of mutations) {
this.processMutation(mutation)
}
}
}

Expand Down