Merge branch 'master' into load
This commit is contained in:
Коммит
e67217c6da
2
Jakefile
2
Jakefile
|
@ -124,7 +124,7 @@ function runAndComplete(cmds, task) {
|
|||
});
|
||||
}
|
||||
|
||||
mkSimpleTask('build/genmeta.js', [ 'tools', ], "tools/genmeta.ts");
|
||||
mkSimpleTask('build/genmeta.js', [ 'tools', 'generated/help.cache' ], "tools/genmeta.ts");
|
||||
file('build/api.js', expand([ "build/genmeta.js", "lib" ]), { async: true }, function () {
|
||||
console.log("[P] generating build/api.js, localization.json and topiclist.json");
|
||||
runAndComplete([
|
||||
|
|
|
@ -530,6 +530,7 @@ module TDev {
|
|||
public generalFlags = PropertyFlags.None;
|
||||
public _isImmutable = false;
|
||||
|
||||
public minSkill = 0;
|
||||
public _stemName:string;
|
||||
public isData:boolean;
|
||||
public isBuiltin:boolean;
|
||||
|
@ -574,6 +575,8 @@ module TDev {
|
|||
public isExtensionEnabled() { return false }
|
||||
public isImmutable() { return this._isImmutable }
|
||||
|
||||
// 1 block, 2 coder, 3 pro
|
||||
public md_skill(sk: number) { this.minSkill = sk; }
|
||||
public md_stem(n: string) { this._stemName = n; }
|
||||
public md_obsolete() { this.isObsolete = true; }
|
||||
public md_isData() { this.isData = true; }
|
||||
|
|
11
ast/ast.ts
11
ast/ast.ts
|
@ -2134,7 +2134,8 @@ module TDev.AST {
|
|||
this.version = App.currentVersion;
|
||||
}
|
||||
|
||||
static metaMapping = [ "showAd", "isLibrary", "allowExport", "isCloud", "hasIds" ];
|
||||
// split screen is used as a hit when loaded in the editor, serialized when publishing
|
||||
static metaMapping = [ "showAd", "isLibrary", "allowExport", "isCloud", "hasIds", "splitScreen" ];
|
||||
|
||||
public nodeType() { return "app"; }
|
||||
public things:Decl[] = [];
|
||||
|
@ -2189,7 +2190,8 @@ module TDev.AST {
|
|||
public isDocsTopic() { return this.comment && /#docs/i.test(this.comment); }
|
||||
public isTutorial() { return this.isDocsTopic() && this.allActions().some(a => /^#\d/.test(a.getName())) }
|
||||
public allowExport:boolean;
|
||||
public hasIds:boolean;
|
||||
public hasIds: boolean;
|
||||
public splitScreen: boolean;
|
||||
private stillParsing:boolean = true;
|
||||
public accept(v:NodeVisitor) { return v.visitApp(this); }
|
||||
public children() { return this.things; }
|
||||
|
@ -4214,6 +4216,10 @@ module TDev.AST {
|
|||
});
|
||||
}
|
||||
|
||||
secondaryRun(app: App)
|
||||
{
|
||||
}
|
||||
|
||||
run(app: App)
|
||||
{
|
||||
DeepVisitor.clearVisitorState(app);
|
||||
|
@ -4237,6 +4243,7 @@ module TDev.AST {
|
|||
this.useAction(a);
|
||||
})
|
||||
|
||||
this.secondaryRun(app);
|
||||
|
||||
this.traverseActions();
|
||||
|
||||
|
|
|
@ -1380,7 +1380,9 @@ module TDev.AST
|
|||
var code = ""
|
||||
|
||||
function localName(l:LocalDef) {
|
||||
return Api.runtimeName(l.getName().replace(/[?]/g, ""))
|
||||
var r = Api.runtimeName(l.getName().replace(/[?]/g, ""))
|
||||
if (r == "s" || r == "lib") return "_" + r
|
||||
return r
|
||||
}
|
||||
|
||||
function unterm(t:JsExpr)
|
||||
|
@ -3106,5 +3108,14 @@ module TDev.AST
|
|||
{
|
||||
this.options.usedProperties[p.usageKey().toLowerCase()] = true
|
||||
}
|
||||
|
||||
secondaryRun(app: App)
|
||||
{
|
||||
app.libraries().forEach(l => {
|
||||
if (l.isTutorial()) {
|
||||
l.getPublicActions().forEach(a => this.runOnDecl(a))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -739,8 +739,7 @@ module TDev.AppExport
|
|||
return wa
|
||||
}
|
||||
|
||||
function chooseWebsiteCoreAsync(azureResults:any[]):Promise
|
||||
{
|
||||
function chooseWebsiteCoreAsync(azureResults: any[]): Promise {
|
||||
var r = new PromiseInv()
|
||||
var m = new ModalDialog()
|
||||
|
||||
|
@ -756,13 +755,25 @@ module TDev.AppExport
|
|||
var keys = Object.keys(auths).map(k => auths[k])
|
||||
keys.sort((a, b) => Util.stringCompare(a.website, b.website))
|
||||
|
||||
// populate data from local editor if any
|
||||
if (LocalShell.mgmtUrl("")) {
|
||||
var wa = <Azure.WebsiteAuth> {
|
||||
deploymentKey: LocalShell.deploymentKey(),
|
||||
key: 'custom:local',
|
||||
website: 'local',
|
||||
webspace: 'custom',
|
||||
destinationAppUrl: LocalShell.url()
|
||||
};
|
||||
keys.splice(0, 0, wa);
|
||||
}
|
||||
|
||||
var boxes = keys.map(wa =>
|
||||
websiteBox(wa)
|
||||
.withClick(() => {
|
||||
m.dismiss()
|
||||
r.success(setDeploymentWebsiteAsync(wa))
|
||||
})
|
||||
)
|
||||
m.dismiss()
|
||||
r.success(setDeploymentWebsiteAsync(wa))
|
||||
})
|
||||
)
|
||||
|
||||
if (getManagementCerificate()) {
|
||||
if (!azureResults)
|
||||
|
@ -1238,16 +1249,6 @@ module TDev.AppExport
|
|||
wa.destinationAppUrl = wa.destinationAppUrl.replace(/\/*$/, "/")
|
||||
m.add(div("wall-dialog-header", lf("hooray! your web site is deployed")));
|
||||
m.add(div('share-url', HTML.mkA('', wa.destinationAppUrl, 'tdwebapp', wa.destinationAppUrl)));
|
||||
|
||||
var lnk = RT.Link.mk(wa.destinationAppUrl, RT.LinkKind.hyperlink)
|
||||
lnk.set_title(wa.website + " #touchdevelop")
|
||||
var options = <RT.ShareManager.ShareOptions> {
|
||||
header: "share this web site",
|
||||
noDismiss: true,
|
||||
justButtons: true
|
||||
};
|
||||
RT.ShareManager.addShareButtons(m, lnk, options)
|
||||
|
||||
m.addOk("close", () => {
|
||||
m.dismiss();
|
||||
});
|
||||
|
|
|
@ -2412,18 +2412,18 @@ module TDev
|
|||
});
|
||||
} else {
|
||||
var maxScore = 1;
|
||||
var singl:AST.SingletonDef[] = Calculator.sortDecls(api.getSingletons());
|
||||
var singl: AST.SingletonDef[] = Calculator.sortDecls(api.getSingletons().filter(sg => sg.isBrowsable()));
|
||||
var skill = AST.blockMode ? 1 : AST.legacyMode ? 2 : 3;
|
||||
var libSingl:IntelliItem = null;
|
||||
singl.forEach((s:AST.SingletonDef) => {
|
||||
if (s.isBrowsable()) {
|
||||
var sc = s.usage.count() + 1e-20;
|
||||
sc *= s.usageMult();
|
||||
var e = this.mkIntelliItem(sc, Ticks.calcIntelliSingleton);
|
||||
if (sc > maxScore) maxScore = sc;
|
||||
e.decl = s;
|
||||
if (s.getName() == AST.libSymbol)
|
||||
libSingl = e;
|
||||
}
|
||||
var sc = s.usage.count() + 1e-20;
|
||||
sc *= s.usageMult();
|
||||
var e = this.mkIntelliItem(sc, Ticks.calcIntelliSingleton);
|
||||
if (sc > maxScore) maxScore = sc;
|
||||
if (skill < s.getKind().minSkill) e.score -= 1e10;
|
||||
e.decl = s;
|
||||
if (s.getName() == AST.libSymbol)
|
||||
libSingl = e;
|
||||
});
|
||||
|
||||
var libs = Script.libraries().filter(l => l.isBrowsable()).map(l => {
|
||||
|
@ -3873,9 +3873,9 @@ module TDev
|
|||
TheEditor.adjustCodeViewSize(this.stmt);
|
||||
}
|
||||
|
||||
private sortedIntelliItems()
|
||||
private sortedIntelliItems() : IntelliItem[]
|
||||
{
|
||||
var items0 = this.currentIntelliItems;
|
||||
var items0 = this.currentIntelliItems.filter(ii => ii.score > 0);
|
||||
var usedProfile = false;
|
||||
if (TheEditor.intelliProfile) {
|
||||
var prof = TheEditor.intelliProfile;
|
||||
|
|
|
@ -605,10 +605,6 @@ module TDev
|
|||
return TheEditor.debugSupported();
|
||||
}
|
||||
|
||||
public publishRunHelpLink(title: string) {
|
||||
return Editor.mkHelpLink("publishing run", title);
|
||||
}
|
||||
|
||||
public fixErrorIn(stableName:string, error:string)
|
||||
{
|
||||
this.hideWallAsync().then(() => {
|
||||
|
@ -3046,6 +3042,11 @@ module TDev
|
|||
else return Promise.as();
|
||||
}).then(() => {
|
||||
if (!Script) return;
|
||||
// if the script is not edited and it requires split screen, load split screen mode from meta
|
||||
if (header.status === "published" && !!Script.splitScreen) {
|
||||
Util.log('published script used split mode, splitting...');
|
||||
this.setSplitScreen(true);
|
||||
}
|
||||
|
||||
this.currentRt = new Runtime();
|
||||
this.setupPlayButton();
|
||||
|
@ -4401,6 +4402,8 @@ module TDev
|
|||
{
|
||||
Ticker.dbg("Editor.saveStateAsync");
|
||||
if (!!Script) {
|
||||
if (opts.forPublishing)
|
||||
Script.splitScreen = !!Script.editorState.splitScreen
|
||||
if (!opts.isRevert && !!this.currentCodeView)
|
||||
this.currentCodeView.commit();
|
||||
Script.setStableNames();
|
||||
|
@ -5427,6 +5430,7 @@ module TDev
|
|||
isRevert?: boolean;
|
||||
clearScript?: boolean;
|
||||
wasUpgraded?: boolean;
|
||||
forPublishing?: boolean;
|
||||
}
|
||||
|
||||
export class SearchForNode
|
||||
|
|
|
@ -20,13 +20,22 @@ module TDev.Browser {
|
|||
}
|
||||
|
||||
export var hubThemes: StringMap<HubTheme> = {
|
||||
'minecraft': {
|
||||
description: 'Learn to code with Mineacraft',
|
||||
logoArtId: 'eopyzwpm',
|
||||
wallpaperArtId: 'abqqsurv',
|
||||
tutorialsTopic: 'ysxp',
|
||||
requiresShell: true,
|
||||
scriptSearch: '#minecraft',
|
||||
},
|
||||
'arduino': {
|
||||
description: 'Environment to program Arduino boards',
|
||||
description: 'Program Arduino boards',
|
||||
logoArtId: 'kzajxznr',
|
||||
wallpaperArtId: 'kzajxznr',
|
||||
tutorialsTopic: 'arduinotutorials',
|
||||
requiresShell: true
|
||||
}
|
||||
requiresShell: true,
|
||||
scriptSearch: '#arduino',
|
||||
},
|
||||
};
|
||||
|
||||
export enum EditorMode {
|
||||
|
@ -475,23 +484,35 @@ module TDev.Browser {
|
|||
if ((h[1] == "follow" || h[1] == "follow-tile") && /^\w+$/.test(h[2])) {
|
||||
// temporary fix
|
||||
if (h[2] == 'jumpingbird') h[2] = 'jumpingbirdtutorial';
|
||||
Util.log('follow: {0}', h[2]);
|
||||
this.browser().clearAsync(true)
|
||||
.done(() => {
|
||||
.done(() => {
|
||||
// try finding built-in topic first
|
||||
var bt = HelpTopic.findById(h[2]);
|
||||
if (bt)
|
||||
if (bt) {
|
||||
Util.log('found built-in topic');
|
||||
TopicInfo.mk(bt).follow();
|
||||
else
|
||||
}
|
||||
else {
|
||||
TheApiCacheMgr.getAsync(h[2], true)
|
||||
.then((res: JsonIdObject) => {
|
||||
if (res && res.kind == "script" && res.id != (<JsonScript>res).updateid) {
|
||||
Util.log('follow topic updated to ' + (<JsonScript>res).updateid);
|
||||
return TheApiCacheMgr.getAsync((<JsonScript>res).updateid, true);
|
||||
}
|
||||
else return Promise.as(res);
|
||||
})
|
||||
.done(j => {
|
||||
if (j && j.kind == "script") {
|
||||
var ti = TopicInfo.mk(HelpTopic.fromJsonScript(j))
|
||||
if (j && j.kind == "script") {
|
||||
var ti = TopicInfo.mk(HelpTopic.fromJsonScript(j))
|
||||
ti.follow();
|
||||
} else Util.setHash("hub");
|
||||
}, e => {
|
||||
} else Util.setHash("hub");
|
||||
}, e => {
|
||||
Util.log('follow route error: {0}, {1}' + h[2], e.message);
|
||||
Util.setHash("hub");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -753,7 +774,7 @@ module TDev.Browser {
|
|||
})
|
||||
}
|
||||
|
||||
public tutorialsByUpdateIdAsync()
|
||||
public tutorialsByUpdateIdAsync(): Promise // StringMap<AST.HeaderWithState>
|
||||
{
|
||||
return this.browser().getTutorialsStateAsync().then((headers:AST.HeaderWithState[]) => {
|
||||
var res = {}
|
||||
|
@ -807,7 +828,7 @@ module TDev.Browser {
|
|||
// - once this is done, we call [finish]
|
||||
// - because we may have found the tutorial we wanted in the process, we
|
||||
// return a new value for [top]
|
||||
private findTutorial(templateId: string, finish) {
|
||||
private findTutorial(templateId: string, finish: (res: { app: AST.App; headers: StringMap<AST.HeaderWithState> }, top: HelpTopic) => void) {
|
||||
var top = HelpTopic.findById("t:" + templateId)
|
||||
|
||||
if (!this.headerByTutorialId || Date.now() - this.headerByTutorialIdUpdated > 3000) {
|
||||
|
@ -816,7 +837,7 @@ module TDev.Browser {
|
|||
}
|
||||
|
||||
if (top) {
|
||||
Promise.join([Promise.as(null), this.headerByTutorialId]).done(res => finish(res, top));
|
||||
Promise.join([Promise.as(null), this.headerByTutorialId]).done(res => finish({ app: res[0], headers: res[1] }, top));
|
||||
} else {
|
||||
var fetchingId = null
|
||||
var fetchId = id => {
|
||||
|
@ -830,7 +851,7 @@ module TDev.Browser {
|
|||
fetchId(j.updateid);
|
||||
else {
|
||||
top = HelpTopic.fromJsonScript(j);
|
||||
Promise.join([top.initAsync(), this.headerByTutorialId]).done(res => finish(res, top));
|
||||
Promise.join([top.initAsync(), this.headerByTutorialId]).done(res => finish({ app: res[0], headers: res[1] }, top));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -869,20 +890,20 @@ module TDev.Browser {
|
|||
{
|
||||
var tileOuter = div("tutTileOuter")
|
||||
|
||||
var startTutorial = (top, header: Cloud.Header) => {
|
||||
var startTutorial = (top : HelpTopic, header: Cloud.Header) => {
|
||||
Util.log("tutorialTile.start: " + templateId)
|
||||
if (f)
|
||||
f(header);
|
||||
this.startTutorial(top, header);
|
||||
};
|
||||
|
||||
var finish = (res, top: HelpTopic) => {
|
||||
var finish = (res: { app: AST.App; headers: StringMap<AST.HeaderWithState> }, top: HelpTopic) => {
|
||||
var isHelpTopic = !!top;
|
||||
var tile = div("tutTile")
|
||||
tileOuter.setChildren([tile])
|
||||
|
||||
var app:AST.App = res[0]
|
||||
var progs = res[1]
|
||||
var app:AST.App = res.app
|
||||
var progs = res.headers
|
||||
|
||||
var titleText = top.json.name.replace(/ (tutorial|walkthrough)$/i, "");
|
||||
var descText = top.json.description.replace(/ #(docs|tutorials|stepbystep)\b/ig, " ")
|
||||
|
@ -1037,7 +1058,8 @@ module TDev.Browser {
|
|||
bySection[k].forEach((template: ScriptTemplate) => {
|
||||
var icon = div("sdIcon");
|
||||
icon.style.backgroundColor = ScriptIcons.stableColorFromName(template.title);
|
||||
icon.setChildren([HTML.mkImg("svg:" + template.icon + ",white")]);
|
||||
// missing icons
|
||||
// icon.setChildren([HTML.mkImg("svg:" + template.icon + ",white")]);
|
||||
|
||||
var nameBlock = div("sdName", lf_static(template.title, true));
|
||||
var hd = div("sdNameBlock", nameBlock);
|
||||
|
@ -1826,12 +1848,12 @@ module TDev.Browser {
|
|||
// Copied from [tutorialTitle], and (hopefully) simplified.
|
||||
this.findTutorial(id, (res, topic: HelpTopic) => {
|
||||
var key = topic.updateKey();
|
||||
var header = res[1][key]; // may be null or undefined
|
||||
var header = res.headers[key]; // may be null or undefined
|
||||
k({
|
||||
title: topic.json.name.replace(/ (tutorial|walkthrough)$/i, ""),
|
||||
header: header,
|
||||
topic: topic,
|
||||
app: res[0],
|
||||
app: res.app,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1858,6 +1880,7 @@ module TDev.Browser {
|
|||
: HTML.cssImage(HTML.proxyResource(tutorial.topic.json.screenshot));
|
||||
btn.style.backgroundSize = "cover";
|
||||
}
|
||||
ScriptInfo.addTutorialProgress(btn, tutorial.header);
|
||||
buttons.push(btn);
|
||||
|
||||
if (buttons.length == 6) {
|
||||
|
|
|
@ -5440,11 +5440,32 @@ module TDev { export module Browser {
|
|||
div("hubTileTitleBar",
|
||||
div("hubTileTitle", spanDirAuto(this.app.getName())),
|
||||
div("hubTileSubtitle",
|
||||
div("hubTileAuthor", spanDirAuto(this.jsonScript.username), nums)))])
|
||||
div("hubTileAuthor", spanDirAuto(this.jsonScript.username), nums)))])
|
||||
ScriptInfo.addTutorialProgress(d, this.cloudHeader);
|
||||
});
|
||||
return d;
|
||||
}
|
||||
|
||||
static addTutorialProgress(d: HTMLElement, header : Cloud.Header) {
|
||||
if (!header || !header.guid) return;
|
||||
World.getInstalledEditorStateAsync(header.guid).done(text => {
|
||||
if (!text) return;
|
||||
var prog = <AST.AppEditorState>JSON.parse(text);
|
||||
var num = prog.tutorialNumSteps - (prog.tutorialStep || 0);
|
||||
if (prog.tutorialId && num > 0) {
|
||||
var starSpan = span("bold",((prog.tutorialStep || 0) + 1) + "★");
|
||||
var ofSteps = prog.tutorialNumSteps ? " of " + (prog.tutorialNumSteps + 1) : "";
|
||||
d.appendChild(div("tutProgress",
|
||||
((prog.tutorialStep && (prog.tutorialStep == prog.tutorialNumSteps)) ?
|
||||
div(lf("steps done"), lf("done!"), div("label", starSpan))
|
||||
:
|
||||
div("steps", starSpan, ofSteps,
|
||||
div("label", lf("tutorial progress"))))
|
||||
))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public willWork() {
|
||||
return !this.app || this.app.supportsAllPlatforms(api.core.currentPlatform);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ module TDev
|
|||
{
|
||||
if (!app) app = Script
|
||||
|
||||
TheEditor.saveStateAsync({ forReal: true }).then(() => {
|
||||
TheEditor.saveStateAsync({ forReal: true, forPublishing: true }).then(() => {
|
||||
TheEditor.queueNavRefresh();
|
||||
World.getInstalledHeaderAsync(app.localGuid).then((h: Cloud.Header) => {
|
||||
if (h.status == "published") {
|
||||
|
@ -195,13 +195,13 @@ module TDev
|
|||
this.editor.showAppLog(app);
|
||||
}));
|
||||
if (!isParent && TheEditor.widgetEnabled("errorsButton"))
|
||||
addBtn(HTML.mkRoundButton("svg:SmilieSad,black", lf("errors"), Ticks.sideErrors, () => {
|
||||
addBtn(HTML.mkRoundButton("svg:SmilieSad,black", lf("errors"), Ticks.sideErrors,() => {
|
||||
this.editor.typeCheckNow();
|
||||
this.editor.searchFor(":m");
|
||||
}));
|
||||
|
||||
if (onlyParent && isBeta && TheEditor.widgetEnabled("deployButton") &&
|
||||
(Azure.getWebsiteAuthForApp(app) || app.usesCloudLibs() || Script.usesCloudLibs())) {
|
||||
addBtn(HTML.mkRoundButton("svg:cloudupload,black", lf("deploy"), Ticks.sideDeployWebSite,() => {
|
||||
if (onlyParent && TheEditor.widgetEnabled("deployButton")) {
|
||||
addBtn(HTML.mkRoundButton("svg:cloudupload,black", lf("export"), Ticks.sideDeployWebSite,() => {
|
||||
TDev.RT.App.clearLogs();
|
||||
var wa = Azure.getWebsiteAuthForApp(app)
|
||||
var recompile = Promise.as()
|
||||
|
@ -217,18 +217,21 @@ module TDev
|
|||
Script = res.prevScript
|
||||
})
|
||||
|
||||
recompile
|
||||
.then(() => AppExport.deployLocalWebappAsync(app, wa))
|
||||
.then(
|
||||
() => AppExport.showStatus(wa),
|
||||
err => {
|
||||
if (app == Script)
|
||||
AppExport.setupAzure()
|
||||
else
|
||||
ModalDialog.info(lf("deployment not configured"),
|
||||
if (app.isCloud) {
|
||||
recompile
|
||||
.then(() => AppExport.deployLocalWebappAsync(app, wa))
|
||||
.done(
|
||||
() => AppExport.showStatus(wa),
|
||||
err => {
|
||||
if (app == Script)
|
||||
AppExport.setupAzure()
|
||||
else
|
||||
ModalDialog.info(lf("deployment not configured"),
|
||||
lf("Go to the main script and try to deploy from there."))
|
||||
})
|
||||
.done()
|
||||
});
|
||||
} else {
|
||||
recompile.done(() => AppExport.deployCordova(app, this.editor.getBaseScriptId()));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -765,40 +765,56 @@ module TDev
|
|||
// create a new tracking pixel and add it to the tree
|
||||
var trackUrl = this.topic.pixelTrackingUrl();
|
||||
if (trackUrl) {
|
||||
// generate new id on demand
|
||||
var anon = Script.editorState.tutorialAnonymousId;
|
||||
if (!anon) anon = Script.editorState.tutorialAnonymousId = Util.guidGen();
|
||||
trackUrl += "?scriptid=" + this.progressId + "&index=" + prog.index + "&total=" + prog.numSteps + "&completed=" + !!prog.completed + "&time=" + prog.lastUsed + "&anonid=" + anon;
|
||||
var pixel = <HTMLImageElement> document.createElement("img");
|
||||
pixel.className = "tracking-pixel";
|
||||
pixel.src = trackUrl;
|
||||
pixel.onload = (el) => pixel.removeSelf();
|
||||
pixel.onerror = (el) => pixel.removeSelf();
|
||||
elt("root").appendChild(pixel);
|
||||
var anon = this.loadAnonymousId();
|
||||
if (anon) {
|
||||
trackUrl += "?scriptid=" + this.progressId + "&index=" + prog.index + "&total=" + prog.numSteps + "&completed=" + !!prog.completed + "&time=" + prog.lastUsed + "&anonid=" + anon;
|
||||
var pixel = <HTMLImageElement> document.createElement("img");
|
||||
pixel.className = "tracking-pixel";
|
||||
pixel.src = trackUrl;
|
||||
pixel.onload = (el) => pixel.removeSelf();
|
||||
pixel.onerror = (el) => pixel.removeSelf();
|
||||
elt("root").appendChild(pixel);
|
||||
}
|
||||
}
|
||||
|
||||
// pushing directly into event hubs
|
||||
var eventHubsInfo = this.topic.eventHubsTracking();
|
||||
if (eventHubsInfo) {
|
||||
var anon = Script.editorState.tutorialAnonymousId;
|
||||
if (!anon) anon = Script.editorState.tutorialAnonymousId = Util.guidGen();
|
||||
var client = new XMLHttpRequest();
|
||||
var url = 'https://' + eventHubsInfo.namespace + '.servicebus.windows.net/' + eventHubsInfo.hub + '/publishers/' + anon + '/messages?timeout=60&api-version=2014-01';
|
||||
Util.log('event hubs: ' + url);
|
||||
client.open('POST', url);
|
||||
client.setRequestHeader('Authorization', eventHubsInfo.token);
|
||||
client.setRequestHeader("Content-Type", 'application/atom+xml;type=entry;charset=utf-8');
|
||||
client.send(JSON.stringify({
|
||||
anonid: anon,
|
||||
scriptid: this.progressId,
|
||||
index: prog.index,
|
||||
total: prog.numSteps,
|
||||
completed: !!prog.completed,
|
||||
time: prog.lastUsed
|
||||
}));
|
||||
var anon = this.loadAnonymousId();
|
||||
if (anon) {
|
||||
var client = new XMLHttpRequest();
|
||||
var url = 'https://' + eventHubsInfo.namespace + '.servicebus.windows.net/' + eventHubsInfo.hub + '/publishers/' + anon + '/messages?timeout=60&api-version=2014-01';
|
||||
Util.log('event hubs: ' + url);
|
||||
client.open('POST', url);
|
||||
client.setRequestHeader('Authorization', eventHubsInfo.token);
|
||||
client.setRequestHeader("Content-Type", 'application/atom+xml;type=entry;charset=utf-8');
|
||||
client.send(JSON.stringify({
|
||||
anonid: anon,
|
||||
scriptid: this.progressId,
|
||||
index: prog.index,
|
||||
total: prog.numSteps,
|
||||
completed: !!prog.completed,
|
||||
time: prog.lastUsed
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private loadAnonymousId(): string {
|
||||
if (!Script || !this.topic.json) return "";
|
||||
|
||||
var anon = Script.editorState.tutorialAnonymousId;
|
||||
if (!anon) {
|
||||
var ids = JSON.parse(localStorage["tutorialAnonymousIds"] || "{}");
|
||||
anon = ids[this.topic.json.userid];
|
||||
if (!anon) {
|
||||
anon = Script.editorState.tutorialAnonymousId = ids[this.topic.json.userid] = Util.guidGen();
|
||||
localStorage["tutorialAnonymousIds"] = JSON.stringify(ids);
|
||||
}
|
||||
}
|
||||
return anon;
|
||||
}
|
||||
|
||||
public showDiff()
|
||||
{
|
||||
var s = this.steps[this.currentStep]
|
||||
|
@ -847,10 +863,15 @@ module TDev
|
|||
|
||||
private nowPublish()
|
||||
{
|
||||
if (!Cloud.getUserId() || !Cloud.isOnline() || !Cloud.canPublish() || !Script)
|
||||
TheEditor.leaveTutorial(); // always leave tutorial
|
||||
|
||||
// not generally signed in
|
||||
if (!Cloud.getUserId() || !Cloud.isOnline() || !Cloud.canPublish() || !Script) return;
|
||||
|
||||
// author explicitely wanted to skip step
|
||||
if (!this.topic || /none/i.test(this.topic.nextTutorials()[0]))
|
||||
return;
|
||||
|
||||
TheEditor.leaveTutorial();
|
||||
World.getInstalledHeaderAsync(Script.localGuid).done((h: Cloud.Header) => {
|
||||
if (h.status == "published") return Promise.as();
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -307,6 +307,7 @@ module TDev.RT {
|
|||
}
|
||||
|
||||
//? Interact with the app runtime
|
||||
//@ skill(3)
|
||||
export module App
|
||||
{
|
||||
export function createInfoMessage(s: string) : LogMessage {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Browse and review scripts from the bazaar
|
||||
//@ skill(3)
|
||||
export module Bazaar
|
||||
{
|
||||
//? Returns a user object for a specified user id
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
module TDev.RT {
|
||||
//? Arithmetic and bitwise operations on 32 bit integers
|
||||
//@ skill(3)
|
||||
export module Bits
|
||||
{
|
||||
//? Add two unsigned 32 bit numbers
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
module TDev { export module RT {
|
||||
|
||||
//? Current box element in the page.
|
||||
//@ skill(2)
|
||||
export module Box
|
||||
{
|
||||
var R = HTML;
|
||||
|
@ -387,7 +388,7 @@ module TDev { export module RT {
|
|||
}
|
||||
|
||||
//? Current html element in the page.
|
||||
//@ betaOnly
|
||||
//@ betaOnly skill(2)
|
||||
export module Dom {
|
||||
//? Use CSS for layout and import additional CSS stylesheets. Use string art resource to import urls.
|
||||
//@ betaOnly
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
|
||||
|
||||
|
||||
//? A cloud data session
|
||||
//@ ctx(general) stem("session") cap(cloudData) serializable
|
||||
export class CloudSession
|
||||
|
@ -143,7 +140,7 @@ module TDev.RT {
|
|||
}
|
||||
|
||||
//? Cloud session management
|
||||
//@ cap(cloudData)
|
||||
//@ cap(cloudData) skill(3)
|
||||
export module CloudData {
|
||||
|
||||
|
||||
|
|
|
@ -308,41 +308,23 @@ module TDev.RT {
|
|||
|
||||
//? Ask user to pick an entry from this collection
|
||||
//@ uiAsync returns(T)
|
||||
public pick_entry(text: string, r: ResumeCtx) {
|
||||
public pick_entry(text: string, r: ResumeCtx) {
|
||||
var rt = r.rt;
|
||||
var getView = (o:any) => {
|
||||
var getView = (o: any) => {
|
||||
if (o.getIndexCard) return o.getIndexCard(r.stackframe)
|
||||
else if (o.getViewCore) return o.getViewCore(r.stackframe, null)
|
||||
else if (o.toString) return o.toString()
|
||||
else return o + ""
|
||||
};
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var m = new ModalDialog();
|
||||
var chosen = null;
|
||||
var btns = this.a.map((o: any) => div('modalDialogChooseItem', getView(o)).withClick(() => {
|
||||
chosen = o;
|
||||
m.dismiss();
|
||||
}));
|
||||
m.add([div("wall-dialog-header", text)/* ,div("wall-dialog-body", caption)*/]);
|
||||
m.onDismiss = () => r.resumeVal(chosen);
|
||||
m.choose(btns);
|
||||
} else {
|
||||
var btnsDiv: HTMLElement;
|
||||
var btns2 = this.a.map((o: any) => {
|
||||
var btn = HTML.mkButtonElt("wall-button", getView(o));
|
||||
Util.clickHandler(btn, () =>
|
||||
{
|
||||
r.resumeVal(o);
|
||||
btnsDiv.removeSelf();
|
||||
});
|
||||
return btn;
|
||||
});
|
||||
var elt = div("wall-dialog",
|
||||
[div("wall-dialog-header", text),
|
||||
/*div("wall-dialog-body", caption),*/
|
||||
btnsDiv = div("wall-dialog-buttons", btns2)]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
}
|
||||
var m = new ModalDialog();
|
||||
var chosen = null;
|
||||
var btns = this.a.map((o: any) => div('modalDialogChooseItem', getView(o)).withClick(() => {
|
||||
chosen = o;
|
||||
m.dismiss();
|
||||
}));
|
||||
m.add([div("wall-dialog-header", text)/* ,div("wall-dialog-body", caption)*/]);
|
||||
m.onDismiss = () => r.resumeVal(chosen);
|
||||
m.choose(btns);
|
||||
}
|
||||
|
||||
//? Computes the sum of the key of the elements in the collection
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
|
||||
//? Create collections of items.
|
||||
//@ robust
|
||||
//@ robust skill(3)
|
||||
module TDev.RT.Collections
|
||||
{
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Correctness helpers
|
||||
//@ skill(3)
|
||||
export module Contract
|
||||
{
|
||||
//? Specifies a precondition contract for the action; if the condition is false, execution fails. Does nothing for published scripts.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
|
||||
//? Create collections of items.
|
||||
//@ robust
|
||||
//@ robust skill(2)
|
||||
module TDev.RT.Create
|
||||
{
|
||||
//? Creates an empty collection of arbitrary type
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Create invalid values
|
||||
//@ skill(3)
|
||||
export module Invalid
|
||||
{
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@ module TDev.RT {
|
|||
}
|
||||
|
||||
//? Translation, speech to text, ...
|
||||
//@ skill(2)
|
||||
export module Languages
|
||||
{
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? OneDrive, OneNote operations
|
||||
//@ skill(3)
|
||||
export module CloudStorage {
|
||||
//? Prompts the user to upload a picture to OneDrive. If the filename is empty, a default filename gets generated.
|
||||
//@ async returns(CloudPicture) cap(cloudservices)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Geo coordinates
|
||||
//@ skill(3)
|
||||
export module Locations
|
||||
{
|
||||
|
||||
//? Creates a new geo coordinate location
|
||||
export function create_location(latitude:number, longitude:number) : Location_ { return Location_.mk(latitude, longitude, undefined, undefined, undefined, undefined, undefined) }
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Maps, location to address, address to location
|
||||
//@ skill(3)
|
||||
export module Maps
|
||||
{
|
||||
//? Creates a Bing map. Use 'post to wall' to display it.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
module TDev.RT {
|
||||
//? Pictures and music...
|
||||
//@ skill(2)
|
||||
export module Media
|
||||
{
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Phone numbers, vibrate, etc...
|
||||
//@ skill(2)
|
||||
export module Phone
|
||||
{
|
||||
//? Starts a phone call
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Play, stop or resume songs, ...
|
||||
//@ skill(3)
|
||||
export module Player
|
||||
{
|
||||
var _rt: Runtime;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev { export module RT {
|
||||
//? Access to the radio
|
||||
//@ skill(3)
|
||||
export module Radio
|
||||
{
|
||||
//? Indicates if the radio is on
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Emails, sms, contacts, calendar, ...
|
||||
//@ skill(2)
|
||||
export module Social
|
||||
{
|
||||
|
||||
//? Opens the mail client
|
||||
//@ flow(SinkSharing) uiAsync
|
||||
export function send_email(to:string, subject:string, body:string, r : ResumeCtx) : void
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? 2D barcodes, QR codes and NFC tags
|
||||
//@ skill(3)
|
||||
export module Tags
|
||||
{
|
||||
export var sendNFC = (writeTag:boolean, type : string, value: string, sent : (id : number) => void, transferred : () => void) =>
|
||||
|
|
|
@ -12,7 +12,7 @@ module TDev.RT {
|
|||
}
|
||||
|
||||
//? tiles and notifications for Windows and Windows Phone
|
||||
//@ cap(tiles)
|
||||
//@ cap(tiles) skill(3)
|
||||
export module Tiles
|
||||
{
|
||||
export var updateTileAsync = (fragment : string, data : ITileData) : Promise =>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? time and dates
|
||||
//@ robust
|
||||
//@ robust skill(2)
|
||||
export module Time
|
||||
{
|
||||
var _rt : Runtime;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
///<reference path='refs.ts'/>
|
||||
module TDev.RT {
|
||||
//? Support for interactive tutorials.
|
||||
//@ skill(3)
|
||||
export module Tutorial
|
||||
{
|
||||
//? Signal that the step is done.
|
||||
|
|
358
lib/Wall.ts
358
lib/Wall.ts
|
@ -24,133 +24,64 @@ module TDev.RT {
|
|||
//? Prompts the user with a ok button
|
||||
//@ tandre2
|
||||
//@ uiAsync
|
||||
export function prompt(text:string, r: ResumeCtx) : void
|
||||
{
|
||||
export function prompt(text: string, r: ResumeCtx): void {
|
||||
var rt = r.rt;
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var m = new ModalDialog();
|
||||
m.add([body(text),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => m.dismiss())])
|
||||
]);
|
||||
m.onDismiss = () => r.resume();
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[body(text),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => {
|
||||
Screen.popModalHash("wall");
|
||||
r.resume();
|
||||
})])
|
||||
]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
r.resume();
|
||||
});
|
||||
}
|
||||
var m = new ModalDialog();
|
||||
m.add([body(text),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok",() => m.dismiss())])
|
||||
]);
|
||||
m.onDismiss = () => r.resume();
|
||||
m.show();
|
||||
}
|
||||
|
||||
//? Prompts the user with ok and cancel buttons
|
||||
//@ returns(boolean)
|
||||
//@ tandre2
|
||||
//@ uiAsync
|
||||
export function ask_boolean(text:string, caption:string, r:ResumeCtx)
|
||||
{
|
||||
export function ask_boolean(text: string, caption: string, r: ResumeCtx) {
|
||||
var rt = r.rt;
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var value = false;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("no"), () => {
|
||||
value = false;
|
||||
m.dismiss();
|
||||
}),
|
||||
R.mkButton(lf("yes"), () => {
|
||||
value = true;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("no", () => {
|
||||
Screen.popModalHash("wall");
|
||||
r.resumeVal(false)
|
||||
}, true),
|
||||
R.mkButtonOnce("yes", () => {
|
||||
Screen.popModalHash("wall");
|
||||
r.resumeVal(true)
|
||||
}, true)])
|
||||
]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
r.resumeVal(false);
|
||||
});
|
||||
}
|
||||
var value = false;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("no"),() => {
|
||||
value = false;
|
||||
m.dismiss();
|
||||
}),
|
||||
R.mkButton(lf("yes"),() => {
|
||||
value = true;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
}
|
||||
|
||||
//? Prompts the user to input a number
|
||||
//@ returns(number)
|
||||
//@ tandre2
|
||||
//@ uiAsync
|
||||
export function ask_number(text:string, r:ResumeCtx)
|
||||
{
|
||||
export function ask_number(text: string, r: ResumeCtx) {
|
||||
var rt = r.rt;
|
||||
var t = R.mkTextInput("number", lf("enter a decimal number"));
|
||||
t.value = "";
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var value = 0;
|
||||
var m = new ModalDialog();
|
||||
m.add([
|
||||
body(text),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"), () => {
|
||||
value = t.valueAsNumber;
|
||||
if (!isFinite(value)) value = parseFloat(t.value); // Firefox
|
||||
if (!isFinite(value)) value = undefined;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[body(text),
|
||||
div("wall-dialog-input", t),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => {
|
||||
Screen.popModalHash("wall");
|
||||
btns.removeSelf();
|
||||
var x = t.valueAsNumber;
|
||||
if (!isFinite(x)) x = parseFloat(t.value); // Firefox
|
||||
if (!isFinite(x)) x = undefined;
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(x));
|
||||
})])
|
||||
]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
Util.setTimeout(500, () => r.resumeVal(undefined));
|
||||
});
|
||||
}
|
||||
var value = 0;
|
||||
var m = new ModalDialog();
|
||||
m.add([
|
||||
body(text),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"),() => {
|
||||
value = t.valueAsNumber;
|
||||
if (!isFinite(value)) value = parseFloat(t.value); // Firefox
|
||||
if (!isFinite(value)) value = undefined;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
Util.setKeyboardFocus(t);
|
||||
}
|
||||
|
||||
|
@ -158,48 +89,22 @@ module TDev.RT {
|
|||
//@ returns(string)
|
||||
//@ tandre2
|
||||
//@ uiAsync
|
||||
export function ask_string(text:string, r:ResumeCtx)
|
||||
{
|
||||
export function ask_string(text: string, r: ResumeCtx) {
|
||||
var rt = r.rt;
|
||||
var t = R.mkTextArea("variableDesc");
|
||||
t.value = "";
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var value = "";
|
||||
var m = new ModalDialog();
|
||||
m.add([body(text),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"), () => {
|
||||
value = t.value;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[body(text),
|
||||
div("wall-dialog-input", t),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => {
|
||||
Screen.popModalHash("wall");
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
var v = t.value;
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(v));
|
||||
})])
|
||||
]);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(""));
|
||||
});
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
}
|
||||
var value = "";
|
||||
var m = new ModalDialog();
|
||||
m.add([body(text),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"),() => {
|
||||
value = t.value;
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
Util.setKeyboardFocusTextArea(t);
|
||||
}
|
||||
|
||||
|
@ -226,37 +131,18 @@ module TDev.RT {
|
|||
//@ returns(number)
|
||||
//@ tandre2
|
||||
//@ uiAsync
|
||||
export function pick_string(text:string, caption:string, values:Collection<string>, r:ResumeCtx)
|
||||
{
|
||||
export function pick_string(text: string, caption: string, values: Collection<string>, r: ResumeCtx) {
|
||||
var rt = r.rt;
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var m = new ModalDialog();
|
||||
var index = -1;
|
||||
var btns = values.a.map((st: string, i: number) => div('modalDialogChooseItem', st).withClick(() => {
|
||||
index = i;
|
||||
m.dismiss();
|
||||
}));
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption)]);
|
||||
m.onDismiss = () => r.resumeVal(index);
|
||||
m.choose(btns);
|
||||
} else {
|
||||
var btnsDiv : HTMLElement;
|
||||
var btns2 = values.a.map((st:string, i:number) => R.mkButton(st, () => {
|
||||
r.resumeVal(i);
|
||||
Screen.popModalHash("wall");
|
||||
btnsDiv.removeSelf();
|
||||
}));
|
||||
var elt = div("wall-dialog",
|
||||
[div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
btnsDiv = div("wall-dialog-buttons", btns2)]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btnsDiv.removeSelf();
|
||||
r.resumeVal(-1);
|
||||
});
|
||||
}
|
||||
var m = new ModalDialog();
|
||||
var index = -1;
|
||||
var btns = values.a.map((st: string, i: number) => div('modalDialogChooseItem', st).withClick(() => {
|
||||
index = i;
|
||||
m.dismiss();
|
||||
}));
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption)]);
|
||||
m.onDismiss = () => r.resumeVal(index);
|
||||
m.choose(btns);
|
||||
}
|
||||
|
||||
//? Prompts the user to pick a time. Returns a datetime whose time is set, the date is undefined.
|
||||
|
@ -270,53 +156,25 @@ module TDev.RT {
|
|||
var t = R.mkTextInput("time", lf("enter a time"));
|
||||
t.style.borderStyle = 'hidden';
|
||||
t.style.borderColor = 'red';
|
||||
t.onkeyup = (ev : Event) => {
|
||||
t.onkeyup = (ev: Event) => {
|
||||
t.style.borderStyle = String_.to_time(t.value) != null ? 'hidden' : 'solid';
|
||||
};
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var value: DateTime = undefined;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"), () => {
|
||||
var tt = String_.to_time(t.value);
|
||||
if (tt != null)
|
||||
value = Time.today().add_seconds(tt);
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => {
|
||||
Screen.popModalHash("wall");
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
var tt = String_.to_time(t.value);
|
||||
var ti = (tt != null) ? Time.today().add_seconds(tt) : undefined;
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(ti));
|
||||
})])
|
||||
]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(undefined));
|
||||
});
|
||||
}
|
||||
var value: DateTime = undefined;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
body("Enter a time like 15:43 or 3:43pm or 15:43:20 or 3:43:20pm"),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"),() => {
|
||||
var tt = String_.to_time(t.value);
|
||||
if (tt != null)
|
||||
value = Time.today().add_seconds(tt);
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
Util.setKeyboardFocus(t);
|
||||
}
|
||||
|
||||
|
@ -334,45 +192,19 @@ module TDev.RT {
|
|||
t.onkeyup = (ev: Event) => {
|
||||
t.style.borderStyle = DateTime.parse(t.value) != null ? 'hidden' : 'solid';
|
||||
};
|
||||
if (rt.useModalWallDialogs()) {
|
||||
var value: DateTime = undefined;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"), () => {
|
||||
value = DateTime.parse(t.value);
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
} else {
|
||||
var btns;
|
||||
var elt = div("wall-dialog",
|
||||
[div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
btns = div("wall-dialog-buttons",
|
||||
[R.mkButtonOnce("ok", () => {
|
||||
Screen.popModalHash("wall");
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
var dt = DateTime.parse(t.value);
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(dt));
|
||||
})])
|
||||
]);
|
||||
rt.postHtml(elt, rt.current.pc);
|
||||
Screen.pushModalHash("wall", () => {
|
||||
btns.removeSelf();
|
||||
t.blur();
|
||||
t.setAttribute("readonly", "true");
|
||||
// popup keyboard takes a while to dissapear in wp
|
||||
Util.setTimeout(500, () => r.resumeVal(undefined));
|
||||
});
|
||||
}
|
||||
var value: DateTime = undefined;
|
||||
var m = new ModalDialog();
|
||||
m.add([div("wall-dialog-header", text),
|
||||
body(caption),
|
||||
div("wall-dialog-input", t),
|
||||
div("wall-dialog-buttons",
|
||||
[R.mkButton(lf("ok"),() => {
|
||||
value = DateTime.parse(t.value);
|
||||
m.dismiss();
|
||||
})])
|
||||
]);
|
||||
m.onDismiss = () => r.resumeVal(value);
|
||||
m.show();
|
||||
Util.setKeyboardFocus(t);
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ module TDev.RT {
|
|||
}
|
||||
|
||||
//? Search and browse the web...
|
||||
//@ skill(2)
|
||||
export module Web {
|
||||
export interface MessageWaiter {
|
||||
origin: string;
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
"type": "MIT"
|
||||
}],
|
||||
"bugs":"http://github.com/microsoft/TouchDevelop/issues",
|
||||
"repositories": [{
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/microsoft/TouchDevelop.git",
|
||||
"path": "node-webkit"
|
||||
}],
|
||||
},
|
||||
"dependencies": {
|
||||
"faye-websocket": "0.8.1"
|
||||
"faye-websocket": "0.9.*"
|
||||
}
|
||||
}
|
||||
|
|
31
rt/rt.ts
31
rt/rt.ts
|
@ -314,6 +314,7 @@ module TDev
|
|||
public webState: RT.Web.State = <any>{};
|
||||
|
||||
private state: RtState = RtState.Stopped;
|
||||
private stateMsg: string = undefined;
|
||||
// when an event is executing, no other event can start
|
||||
private eventExecuting = false;
|
||||
// used to prevent recursive invocations of mainLoop
|
||||
|
@ -456,8 +457,6 @@ module TDev
|
|||
else return [r.result];
|
||||
}
|
||||
|
||||
private isReplaying = false;
|
||||
|
||||
private eventCategory: string = null;
|
||||
private eventVariable: string = null;
|
||||
public setNextEvent(c: string, v: string) {
|
||||
|
@ -469,19 +468,6 @@ module TDev
|
|||
this.eventVariable = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private replayStartTime: number;
|
||||
private currentOffset: number;
|
||||
public startReplay() {
|
||||
this.isReplaying = true;
|
||||
this.replayStartTime = new Date().getTime();
|
||||
}
|
||||
public stopReplayAsync() {
|
||||
var p = this.stopAsync();
|
||||
this.isReplaying = false;
|
||||
return p;
|
||||
}
|
||||
public currentTime() {
|
||||
return Util.perfNow();
|
||||
}
|
||||
|
@ -526,13 +512,6 @@ module TDev
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Wall methods
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
public useModalWallDialogs(): boolean {
|
||||
|
||||
if (this.rendermode)
|
||||
Util.userError(lf("cannot ask user in page display code"));
|
||||
return this.host.isFullScreen() ||
|
||||
!this.mayPostToWall(this.getCurrentPage());
|
||||
}
|
||||
|
||||
public mayPostToWall(p: WallPage): boolean {
|
||||
return !this.headlessPluginMode && (!p.isAuto() || this.rendermode || p.crashed)
|
||||
|
@ -1089,6 +1068,7 @@ module TDev
|
|||
HistoryMgr.instance.clearModalStack();
|
||||
}
|
||||
if (this.state != RtState.Stopped) {
|
||||
this.setState(RtState.Stopped, "stopAsync");
|
||||
if (!isPause) {
|
||||
this.versionNumber++;
|
||||
if (this.eventQ) this.eventQ.clear();
|
||||
|
@ -1099,7 +1079,6 @@ module TDev
|
|||
ProgressOverlay.hide()
|
||||
this.asyncStack = [];
|
||||
this.asyncTasks = [];
|
||||
this.setState(RtState.Stopped, "stopAsync");
|
||||
this.compiled.stopFn(this);
|
||||
if (!isPause && !this.resumeAllowed && !this.handlingException) {
|
||||
var profilingData = this.compiled._getProfilingResults();
|
||||
|
@ -1490,6 +1469,7 @@ module TDev
|
|||
if (this.state == RtState.Stopped || s == RtState.Stopped)
|
||||
Util.log("runtime state: {0} -> {1}, {2}", this.state, s, msg)
|
||||
this.state = s;
|
||||
this.stateMsg = msg;
|
||||
}
|
||||
|
||||
private getResumeCtxCore(isBlocking: boolean, cont: IContinuationFunction) {
|
||||
|
@ -2053,8 +2033,8 @@ module TDev
|
|||
return;
|
||||
}
|
||||
|
||||
// var lastBreak = Date.now();
|
||||
var continueLater = false;
|
||||
var continueLaterVersion = 0;
|
||||
var numCheck = 0;
|
||||
|
||||
this.mainLoopRunning = true;
|
||||
|
@ -2102,6 +2082,7 @@ module TDev
|
|||
var now = Date.now();
|
||||
if (now - this.lastBreak > (Browser.isNodeJS ? 1000 : 50)) {
|
||||
continueLater = true;
|
||||
continueLaterVersion = this.versionNumber;
|
||||
break;
|
||||
}
|
||||
numCheck = 0;
|
||||
|
@ -2112,7 +2093,7 @@ module TDev
|
|||
}
|
||||
|
||||
this.mainLoopRunning = false;
|
||||
if (continueLater) {
|
||||
if (continueLater && continueLaterVersion == this.versionNumber && this.state != RtState.Stopped) {
|
||||
this.setState(RtState.Paused, "continue later");
|
||||
var ver = this.versionNumber;
|
||||
var curr = this.current
|
||||
|
|
|
@ -47,7 +47,7 @@ module TDev {
|
|||
|
||||
export function canSplitScreen()
|
||||
{
|
||||
return !phoneMode && windowWidth*1.2 > windowHeight;
|
||||
return !phoneMode && !portraitMode && windowWidth*1.2 > windowHeight;
|
||||
}
|
||||
|
||||
export function setSplitScreen(isSplit:boolean)
|
||||
|
|
13
rt/util.ts
13
rt/util.ts
|
@ -749,13 +749,20 @@ module TDev{
|
|||
}
|
||||
|
||||
export function userError(msg:string, pc = "", statusCode?:number) : any
|
||||
{
|
||||
{
|
||||
var e = new Error(msg);
|
||||
(<any>e).programCounter = pc;
|
||||
(<any>e).isUserError = true;
|
||||
if (statusCode)
|
||||
(<any>e).statusCode = 500;
|
||||
throw e;
|
||||
(<any>e).statusCode = statusCode;
|
||||
try {
|
||||
throw e;
|
||||
}
|
||||
catch (err) {
|
||||
Util.log('error: {0}, {1}, {2}', msg, pc, statusCode);
|
||||
Util.log(err.stack + "");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export function syntaxError(msg:string, declName:string) : any
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
///<reference path='../typings/node/node.d.ts'/>
|
||||
|
||||
import fs = require('fs');
|
||||
|
||||
var fileLog: (msg: string) => void = undefined;
|
||||
if (process.env["TD_SHELL_LOG_FILE"]) {
|
||||
var logPath = process.env["TD_SHELL_LOG_FILE"];
|
||||
fileLog = (msg) => {
|
||||
var fl = fs.openSync(logPath, "a");
|
||||
var b = new Buffer(msg + '\r\n');
|
||||
fs.writeSync(fl, b, 0, b.length, 0);
|
||||
fs.closeSync(fl);
|
||||
}
|
||||
}
|
||||
|
||||
import url = require('url');
|
||||
import http = require('http');
|
||||
import https = require('https');
|
||||
|
@ -53,10 +65,9 @@ class Logger {
|
|||
logIdx = -1;
|
||||
logMsgs:LogMessage[] = [];
|
||||
logSz = 1000;
|
||||
|
||||
constructor(public level:number)
|
||||
{
|
||||
}
|
||||
|
||||
constructor(public name : string, public level:number)
|
||||
{}
|
||||
|
||||
addMsg(s:string)
|
||||
{
|
||||
|
@ -64,6 +75,7 @@ class Logger {
|
|||
timestamp: Date.now(),
|
||||
msg: s
|
||||
}
|
||||
if (fileLog) fileLog(s);
|
||||
if (!inAzure) console.log(s)
|
||||
if (this.logIdx >= 0) {
|
||||
this.logMsgs[this.logIdx++] = m;
|
||||
|
@ -108,9 +120,9 @@ class Logger {
|
|||
}
|
||||
}
|
||||
|
||||
var error = new Logger(3)
|
||||
var info = new Logger(6)
|
||||
var debug = new Logger(7)
|
||||
var error = new Logger("error", 3)
|
||||
var info = new Logger("info", 6)
|
||||
var debug = new Logger("debug", 7)
|
||||
|
||||
class ApiRequest {
|
||||
data:any = {}
|
||||
|
@ -296,7 +308,6 @@ function downloadFile(u:string, f:(err:any, s:NodeBuffer, h?:any)=>void)
|
|||
|
||||
g.on('end', () => {
|
||||
var total = Buffer.concat(bufs)
|
||||
//console.log("download file: " + u + " " + total.length)
|
||||
f(null, total, (<any>res).headers)
|
||||
})
|
||||
|
||||
|
@ -652,7 +663,7 @@ function clone<T>(obj: T): T {
|
|||
function createProcess(d:RunCliOptions)
|
||||
{
|
||||
var isWin = /^win/.test(os.platform())
|
||||
debug.log("running: " + d.command + (d.args ? (" " + d.args.join(" ")) : ""))
|
||||
debug.log("running: " + (d.cwd || "") + ">" + d.command + (d.args ? (" " + d.args.join(" ")) : ""))
|
||||
var env = clone(d.env || process.env);
|
||||
if (pythonEnv) Object.keys(pythonEnv).forEach(k => env[k] = pythonEnv[k]);
|
||||
var proc = child_process.spawn(d.args ? d.command : isWin ? "cmd" : "sh", d.args || [isWin ? "/c" : "-c", d.command], {
|
||||
|
@ -1576,7 +1587,6 @@ function proxyEditor(cmds:string[], req, resp)
|
|||
s = (<any>s).replace(/(browsers|error)Url = .*/g, (a, b) => b + "Url = \"" + selfUrl + "/" + specRel + "/" + b + "\"")
|
||||
}
|
||||
s = s.replace(/localProxy = ".*"/, 'localProxy = "yes"')
|
||||
//console.log(specRel)
|
||||
if (rel == "local") {
|
||||
s = s.replace(/betaFriendlyId = ".*"/, "betaFriendlyId = \"(local)\"")
|
||||
} else if (specRel == "current") {
|
||||
|
@ -1886,7 +1896,7 @@ function respawnLoop()
|
|||
console.error("Too many failures, aborting. Please retry manually.");
|
||||
process.exit();
|
||||
} else {
|
||||
console.log("Failure, retrying in 5s...");
|
||||
debug.log("Failure, retrying in 5s...");
|
||||
setTimeout(startOne, 5000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -423,7 +423,8 @@ module TDev {
|
|||
time("readdb1");
|
||||
if (syncVersion != mySyncVersion) return canceled;
|
||||
data.items = data.indexTable.getItemsAsync(data.keys)
|
||||
data.scriptVersionsInCloudItems = data.scriptsTable.getItemsAsync(data.keys.map((guid) => guid + "-scriptVersionInCloud"));
|
||||
if (!Cloud.lite)
|
||||
data.scriptVersionsInCloudItems = data.scriptsTable.getItemsAsync(data.keys.map((guid) => guid + "-scriptVersionInCloud"));
|
||||
return Promise.join(data);
|
||||
}).then(function (data/*: SyncData*/) {
|
||||
time("readdb2");
|
||||
|
|
|
@ -3651,6 +3651,7 @@ var sectAzure = lf("web sites");
|
|||
var sectMakers = lf("makers");
|
||||
var sectTouchDevelop = lf("touchdevelop");
|
||||
var sectOthers = lf("others");
|
||||
var sectMinecraft = "Minecraft";
|
||||
|
||||
/*
|
||||
editorMode: 1 = block, 2 = coder, 3 = expert
|
||||
|
@ -3687,7 +3688,7 @@ var templates: ScriptTemplate[] = [{
|
|||
title: lf("blank turtle"),
|
||||
id: 'blankturtle',
|
||||
icon: 'Controller',
|
||||
name: 'ADJ drawing',
|
||||
name: 'ADJ turtle',
|
||||
description: lf("An turtle app."),
|
||||
section: sectBeginners,
|
||||
scriptid: 'oobxb',
|
||||
|
@ -3710,8 +3711,25 @@ var templates: ScriptTemplate[] = [{
|
|||
section: sectBeginners,
|
||||
scriptid: 'mdrw',
|
||||
editorMode: 1,
|
||||
},
|
||||
|
||||
}, {
|
||||
title: lf("blank minecraft pi"),
|
||||
id: 'blankminecraftpi',
|
||||
icon: 'NineColumn',
|
||||
name: 'ADJ craft',
|
||||
description: lf("A Minecraft Pi app."),
|
||||
section: sectMinecraft,
|
||||
scriptid: 'cptje',
|
||||
editorMode: 1,
|
||||
}, {
|
||||
title: lf("blank minecraft steve"),
|
||||
id: 'blankminecraftsteve',
|
||||
icon: 'NineColumn',
|
||||
name: 'ADJ steve',
|
||||
description: lf("A Minecraft Steve app."),
|
||||
section: sectMinecraft,
|
||||
scriptid: 'qzky',
|
||||
editorMode: 1,
|
||||
},
|
||||
/*{
|
||||
title: lf("blank boostrap app"),
|
||||
id: 'blankbootstrapapp',
|
||||
|
|
|
@ -5345,6 +5345,7 @@ img.tracking-pixel {
|
|||
|
||||
.tutProgress {
|
||||
background: #09b;
|
||||
color:white;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче