blob: a1077be5455f386eb83bd1ea3452391f2413fcc4 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library trydart.iframe_error_handler;
// TODO(ahe): Remove this import if issue 17936 is fixed.
import 'dart:js' as hack;
import 'dart:html' show
Event,
IFrameElement,
window;
import 'dart:async' show
Stream,
StreamController;
class ErrorMessage {
final String message;
final String filename;
final num lineno;
final num colno;
final String stack;
ErrorMessage(
this.message, this.filename, this.lineno, this.colno, this.stack);
String toString() {
String result = filename == null ? '' : filename;
if (lineno != null && lineno != 0 && !lineno.isNaN) {
result += ':$lineno';
}
if (colno != null && colno != 0 && !colno.isNaN) {
result += ':$colno';
}
if (message != null && !message.isEmpty) {
if (!result.isEmpty) {
result += ': ';
}
result += message;
}
if (stack != null && !stack.isEmpty) {
if (!result.isEmpty) {
result += '\n';
}
result += stack;
}
return result;
}
}
Stream<ErrorMessage> errorStream(IFrameElement iframe) {
StreamController<ErrorMessage> controller =
new StreamController<ErrorMessage>();
void onError(
String message,
String filename,
int lineno,
[int colno,
error]) {
// See:
// https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
String stack;
if (error != null) {
var jsStack = error['stack'];
if (jsStack != null) {
stack = hack.context.callMethod('String', [jsStack]);
}
}
controller.add(new ErrorMessage(message, filename, lineno, colno, stack));
}
void installErrorHandler() {
// This method uses dart:js to install an error event handler on the content
// window of [iframe]. This is a workaround for http://dartbug.com/17936.
var iframeProxy = new hack.JsObject.fromBrowserObject(iframe);
var contentWindowProxy = iframeProxy['contentWindow'];
if (contentWindowProxy == null) {
String message =
'No contentWindow, call this method *after* adding iframe to'
' document.';
window.console.error(message);
throw message;
}
// Note: we have two options, use "iframe.contentWindow.onerror = ..." or
// "iframe.contentWindow.addEventListener('error', ...)". The former seems
// to provide more details on both Chrome and Firefox (which provides no
// information at all in error events).
contentWindowProxy['onerror'] = onError;
}
iframe.onLoad.listen((Event event) => installErrorHandler());
installErrorHandler();
return controller.stream;
}