diff --git a/apps/tests/xml-declaration/examples/test-page.xml b/apps/tests/xml-declaration/examples/test-page.xml
new file mode 100644
index 000000000..56c40b5e3
--- /dev/null
+++ b/apps/tests/xml-declaration/examples/test-page.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/apps/tests/xml-declaration/xml-declaration-tests.ts b/apps/tests/xml-declaration/xml-declaration-tests.ts
index aa7f93fd9..5e71f8e14 100644
--- a/apps/tests/xml-declaration/xml-declaration-tests.ts
+++ b/apps/tests/xml-declaration/xml-declaration-tests.ts
@@ -24,6 +24,7 @@ import viewModule = require("ui/core/view");
import platform = require("platform");
import gesturesModule = require("ui/gestures");
import segmentedBar = require("ui/segmented-bar");
+import { Source } from "utils/debug";
export function test_load_IsDefined() {
TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!");
@@ -974,3 +975,14 @@ export function test_TabViewHasCorrectParentChain() {
model.set("testPassed", false);
helper.navigateToModuleAndRunTest(("." + moduleName + "/mymodulewithxml/TabViewParentChain"), model, testFunc);
}
+
+export function test_hasSourceCodeLocations() {
+ var basePath = "xml-declaration/";
+ var page = builder.load(__dirname + "/examples/test-page.xml");
+ var grid = page.getViewById("grid");
+ var gridSource = Source.get(grid);
+ TKUnit.assertEqual(gridSource.toString(), "file:///app/" + basePath + "examples/test-page.xml:2:3");
+ var label = page.getViewById("label");
+ var labelSource = Source.get(label);
+ TKUnit.assertEqual(labelSource.toString(), "file:///app/" + basePath + "examples/test-page.xml:3:5");
+}
diff --git a/ui/builder/builder.ts b/ui/builder/builder.ts
index b3df917f7..f1c642310 100644
--- a/ui/builder/builder.ts
+++ b/ui/builder/builder.ts
@@ -44,10 +44,13 @@ function parseInternal(value: string, context: any, uri?: string): ComponentModu
var ui: xml2ui.ComponentParser;
var errorFormat = (debug && uri) ? xml2ui.SourceErrorFormat(uri) : xml2ui.PositionErrorFormat;
+ var componentSourceTracker = (debug && uri) ? xml2ui.ComponentSourceTracker(uri) : () => {
+ // no-op
+ };
(start = new xml2ui.XmlStringParser(errorFormat))
.pipe(new xml2ui.PlatformFilter())
- .pipe(new xml2ui.XmlStateParser(ui = new xml2ui.ComponentParser(context, errorFormat)));
+ .pipe(new xml2ui.XmlStateParser(ui = new xml2ui.ComponentParser(context, errorFormat, componentSourceTracker)));
start.parse(value);
@@ -225,6 +228,19 @@ namespace xml2ui {
}
}
+ interface SourceTracker {
+ (component: any, p: xml.Position): void;
+ }
+
+ export function ComponentSourceTracker(uri): SourceTracker {
+ return (component: any, p: xml.Position) => {
+ if (!Source.get(component)) {
+ var source = p ? new Source(uri, p.line, p.column) : new Source(uri, -1, -1);
+ Source.set(component, source);
+ }
+ }
+ }
+
export class PlatformFilter extends XmlProducerBase implements XmlProducer, XmlConsumer {
private currentPlatformContext: string;
@@ -293,6 +309,7 @@ namespace xml2ui {
elementName: string;
templateItems: Array;
errorFormat: ErrorFormatter;
+ sourceTracker: SourceTracker;
}
/**
@@ -380,13 +397,14 @@ namespace xml2ui {
if (this._templateProperty.name in this._templateProperty.parent.component) {
var context = this._context;
var errorFormat = this._templateProperty.errorFormat;
+ var sourceTracker = this._templateProperty.sourceTracker;
var template: Template = () => {
var start: xml2ui.XmlArgsReplay;
var ui: xml2ui.ComponentParser;
(start = new xml2ui.XmlArgsReplay(this._recordedXmlStream, errorFormat))
// No platform filter, it has been filtered allready
- .pipe(new XmlStateParser(ui = new ComponentParser(context, errorFormat)));
+ .pipe(new XmlStateParser(ui = new ComponentParser(context, errorFormat, sourceTracker)));
start.replay();
@@ -418,11 +436,13 @@ namespace xml2ui {
private parents = new Array();
private complexProperties = new Array();
- private error;
+ private error: ErrorFormatter;
+ private sourceTracker: SourceTracker;
- constructor(context: any, errorFormat: ErrorFormatter) {
+ constructor(context: any, errorFormat: ErrorFormatter, sourceTracker: SourceTracker) {
this.context = context;
this.error = errorFormat;
+ this.sourceTracker = sourceTracker;
}
public parse(args: xml.ParserEvent): XmlStateConsumer {
@@ -450,7 +470,8 @@ namespace xml2ui {
name: name,
elementName: args.elementName,
templateItems: [],
- errorFormat: this.error
+ errorFormat: this.error,
+ sourceTracker: this.sourceTracker
});
}
@@ -472,6 +493,7 @@ namespace xml2ui {
}
if (componentModule) {
+ this.sourceTracker(componentModule.component, args.position);
if (parent) {
if (complexProperty) {
// Add component to complex property of parent component.
diff --git a/ui/core/view-common.ts b/ui/core/view-common.ts
index 6be4d7523..d812361aa 100644
--- a/ui/core/view-common.ts
+++ b/ui/core/view-common.ts
@@ -17,6 +17,7 @@ import * as visualStateConstants from "ui/styling/visual-state-constants";
import * as bindableModule from "ui/core/bindable";
import * as visualStateModule from "../styling/visual-state";
import * as animModule from "ui/animation";
+import { Source } from "utils/debug";
var bindable: typeof bindableModule;
function ensureBindable() {
@@ -1151,11 +1152,18 @@ export class View extends ProxyObject implements definition.View {
}
public toString(): string {
+ var str = this.typeName;
if (this.id) {
- return this.typeName + `<${this.id}>`;
+ str += `<${this.id}>`;
+ } else {
+ str += `(${this._domId})`;
+ }
+ var source = Source.get(this);
+ if (source) {
+ str += `@${source};`;
}
- return this.typeName + `(${this._domId})`;
+ return str;
}
public _setNativeViewFrame(nativeView: any, frame: any) {
diff --git a/ui/core/view.ios.ts b/ui/core/view.ios.ts
index a1948a03f..dd1754b09 100644
--- a/ui/core/view.ios.ts
+++ b/ui/core/view.ios.ts
@@ -137,7 +137,7 @@ export class View extends viewCommon.View {
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((this._privateFlags & PFLAG_MEASURED_DIMENSION_SET) !== PFLAG_MEASURED_DIMENSION_SET) {
- throw new Error("onMeasure() did not set the measured dimension by calling setMeasuredDimension()");
+ throw new Error("onMeasure() did not set the measured dimension by calling setMeasuredDimension() " + this);
}
}
}