diff --git a/ast/help.ts b/ast/help.ts index c7154ed9b..308a0ad81 100644 --- a/ast/help.ts +++ b/ast/help.ts @@ -392,7 +392,7 @@ module TDev { { id: "art", name: "TouchDevelop Art", - description: lf("Cover art ({0}/...)", Cloud.config.primaryCdnUrl), + description: lf("Cover art ({0}/...)", Cloud.config.newCdnUrl), parseIds: text => { var links = []; if (text) @@ -402,8 +402,8 @@ module TDev { }); return links; }, - idToUrl: id => Cloud.config.primaryCdnUrl + "/pub/" + id, - idToHTMLAsync: id => Promise.as(HTML.mkImg(Cloud.config.primaryCdnUrl + "/pub/" + id, '', lf("open"))) + idToUrl: id => Cloud.config.newCdnUrl + "/pub/" + id, + idToHTMLAsync: id => Promise.as(HTML.mkImg(Cloud.config.newCdnUrl + "/pub/" + id, '', lf("open"))) }, { id: "youtube", name: "YouTube", diff --git a/editor/default.ts b/editor/default.ts index d52b50749..c06aa6936 100644 --- a/editor/default.ts +++ b/editor/default.ts @@ -495,6 +495,8 @@ module TDev } var cfg = (window).tdConfig if (cfg) Object.keys(cfg).forEach(k => Cloud.config[k] = cfg[k]) + if (!Cloud.config.newCdnUrl) + Cloud.config.newCdnUrl = Cloud.config.primaryCdnUrl } mx = /microbit=(\w+)/.exec(document.URL) diff --git a/editor/editor.ts b/editor/editor.ts index f412b881a..114708e23 100644 --- a/editor/editor.ts +++ b/editor/editor.ts @@ -176,8 +176,6 @@ module TDev public additionalFullScreenButtons(): HTMLElement[] { var btns = []; - if (ScriptEditorWorldInfo.status == "published" && TheEditor.widgetEnabled("wallScreenshot")) - btns.push(HTML.mkRoundButton("svg:camera,currentColor", lf("screenshot"), Ticks.wallScreenshot, () => this.takeScreenshot())); if (Browser.serialLog) btns.push(HTML.mkRoundButton("svg:CommandLine,currentColor", lf("serial"), Ticks.wallSerial, () => this.showSerialView())) return btns; @@ -195,82 +193,12 @@ module TDev } public takeScreenshot() { - if (!Script) return; - if (ScriptEditorWorldInfo.status !== "published") { - ModalDialog.info(lf("Oops, your script is not published"), - lf("You need to publish your script in order to upload screenshots.")); - return; - } - if (Cloud.anonMode(lf("publishing screenshots"))) return; - - var baseId = ScriptEditorWorldInfo.baseId; - RT.ScreenshotManager.toScreenshotURLAsync(this, false) - .done((data: string) => { - if (!data) { - ModalDialog.info(lf("Oops, we could not take the screenshot"), - lf("You are probably using a picture downloaded from the web on the board. Your web browser and the web site prevent cross-origin resource sharing (CORS).")); - return; - } - - var contentType = data.match(/^data:(image\/(png|jpeg));base64,/i)[1]; - Util.log('content type: ' + contentType); - var base64content = Util.base64EncodeToBase64(data, contentType); - if (base64content && base64content.length > 2000000) { - var m = new ModalDialog(); - m.add([ - div("wall-dialog-header", lf("Oops, we can't take a screenshot now")), - div("wall-dialog-body", lf("The encoded screenshot is too big.")), - ]); - m.show(); - } else if (base64content && baseId) { - var previewImage = HTML.mkImg(data); - previewImage.setAttribute('class', 'wall-media'); - var m = new ModalDialog(); - m.add([ - div("wall-dialog-header", lf("wall screenshot")), - div("wall-dialog-body", lf("Publish your screenshot to the cloud so that everybody can enjoy it.")), - div("wall-dialog-buttons", - HTML.mkButton(lf("publish"), () => { - m.dismiss(); - HTML.showProgressNotification(lf("uploading screenshot...")); - Cloud.postPrivateApiAsync(baseId + "/screenshots", - { - kind: "screenshot", - contentType: contentType, - content: base64content, - userplatform: Browser.platformCaps - }).done((resp : JsonScreenShot) => { - HTML.showProgressNotification(lf("screenshot uploaded"), true); - Cloud.postCommentAsync(baseId, lf("{0} added a screenshot {1}", ((window).userName || ""), "/" + resp.id)) - .done(() => { },() => { }); - Browser.Hub.askToEnableNotifications(); - }, e => { - HTML.showProgressNotification(lf("screenshot upload failed"), true); - Cloud.handlePostingError(e, lf("post screenshot")); - }); - })), - previewImage - ]); - m.setScroll(); - m.show(); - } else { - var m = new ModalDialog(); - m.add([ - div("wall-dialog-header", lf("Oops, we can't take a screenshot now.")), - div("wall-dialog-body", lf("Unfortunately, we can only take screenshots of full screen boards.")), - ]); - m.show(); - } - }); } public notifyStopAsync() : Promise { TheEditor.stopPlayTime(); this.currentRt.editorObj = undefined; - if (ScriptEditorWorldInfo && - ScriptEditorWorldInfo.status !== "published") - this.takeScreenshotMaybe(); return super.notifyStopAsync().then(v => { if (TheEditor.stepTutorial) TheEditor.stepTutorial.notify("runStop"); if (this.currentRt.headlessPluginMode && @@ -312,32 +240,6 @@ module TDev // Update edit mode. (When live mode, updateEditMode is called in SideEditorHost.notifyStopAsync()) if (!this.currentRt.liveMode()) LayoutMgr.instance.updateEditMode(this.currentRt); - - // take screenshots periodically - var takePoll = () => { - if (this.takeScreenshotMaybe()) - Util.setTimeout(TheEditor.hasLastScreenshot() ? 5000 : 3000, takePoll); - } - if (ScriptEditorWorldInfo && - ScriptEditorWorldInfo.status !== "published") - Util.setTimeout(2000, takePoll); - } - - private takeScreenshotMaybe(): boolean { - if (Cloud.isRestricted()) return false; - if (this.currentRt && !this.currentRt.isStopped()) { - if (!TheEditor.hasLastScreenshot() || Math.random() < 0.4) { - if (Browser.screenshots && Browser.isHosted) - TDev.RT.ScreenshotManager.toScreenshotURLAsync(this.currentRt.host, true) - .done(url => TheEditor.setLastScreenshotDataUri(url)); - else { - var canvas = this.toScreenshotCanvas(); - TheEditor.setLastScreenshotCanvas(canvas); - } - return true; - } - } - return false; } public notifyBreakpointHit(bp: string) { diff --git a/editor/hub.ts b/editor/hub.ts index 4036bbe34..d65f66629 100644 --- a/editor/hub.ts +++ b/editor/hub.ts @@ -288,139 +288,6 @@ module TDev.Browser { description: lf("All options turned on"), editorMode: editorModes['pro'] }, - 'minecraft': { - name: "Minecraft", - description: lf("Learn to code with Minecraft"), - logoArtId: 'eopyzwpm', - tutorialsTopic: 'minecrafttutorials', - scriptSearch: '#minecraft', - scriptTemplates: ['blankminecraft', 'blankcreeper'], - noAnimations: true, - editorMode: { - id: 'minecraft', - name: lf("minecraft"), - descr: lf("Drag and drop blocks, simplified interface, great for beginners!"), - astMode: 2, - artId: 'brfljsds', - widgets: { - // edit - addNewButton: true, - undoButton: true, - changeSkillLevel: true, - async: true, - // refactoring - updateButton: true, - promoteRefactoring: true, - fixItButton: true, - splitScreen: false, - splitScreenOnLoad: true, - // searchArtRefactoring: true, - // calcSearchArt: true, - scriptProperties: true, - scriptPropertiesIcons: true, - // statements - copyPaste: true, - selectStatements: true, - stringConcatProperty: true, - show: true, - "return": true, - gotoNavigation: true, - // sections - dataSection: true, - // artSection: true, - librariesSection: true, - // ui - wallScreenshot: true, - wallHeart: true, - startTutorialButton: true, - nextTutorialsList: true, - // hub - hubTutorials: true, - // hubShowcase : true, - publicationComments: true, - translateComments: true, - - whileConditionDefault: "true", - whileBodyDefault: "skip; minecraft->pause(20);", - forConditionDefault: "5", - ifConditionDefault: "true", - - scriptSocialLinks: true, - scriptAddToChannel: true, - } - } - }, - 'rpi': { - name: "Raspberry Pi", - description: lf("Learn to code with Raspberry Pi"), - logoArtId: 'eopyzwpm', - tutorialsTopic: 'minecraftpitutorials', - scriptTemplates: ['blankminecraftpi'], - noAnimations: true, - lowMemory: true, - editorMode: editorModes['block'], - }, - 'arduino': { - name: "Arduino", - description: lf("Program Arduino boards"), - logoArtId: 'kzajxznr', - wallpaperArtId: 'kzajxznr', - tutorialsTopic: 'arduinotutorials', - scriptSearch: '#arduino', - scriptTemplates: ['blankarduino', 'blankesplore'], - intelliProfileId: 'kbmkc', - editorMode: editorModes['classic'], - }, - 'engduino': { - name: "Engduino", - description: lf("Programming the Engduino"), - logoArtId: 'qmjzqlkc', - wallpaperArtId: 'qmjzqlkc', - scriptSearch: '#engduino', - scriptTemplates: ['blankengduino'], - intelliProfileId: 'kbmkc', - editorMode: editorModes['classic'], - }, - 'microbit': { - name: 'BBC micro:bit', - description: ' ', - scriptSearch: '#microbit', - scriptTemplates: ['blankmicrobit'], - intelliProfileId: 'upfje', - editorMode: { - id: 'microbit', - name: 'Micro Bit', - descr: lf("Micro Bit mode!"), - astMode: 2, - widgets: { - hubTutorials: true, - addNewButton: true, - undoButton: true, - promoteRefactoring: true, - copyPaste: true, - comment: true, - dataSection: true, - gotoNavigation: true, - splitScreenOnLoad: true, - updateButton: true, - forceMainAsAction: true, - singleReturnValue: true, - integerNumbers: true, - codeSearch: true, - librariesSection: true, - scriptPropertiesSettings: true, - editorRunOnLoad: true, - whileConditionDefault: "true", - whileBodyDefault: "skip; basic->pause(20);", - forConditionDefault: "5", - "return": true, - "break": true, - scriptPrintScript: true, - scriptPrintTopic: true, - tutorialGoToPreviousStep: true, - } - }, - }, 'restricted': { name: "Restricted", description: lf("Opinionated restricted mode"), @@ -1564,18 +1431,17 @@ module TDev.Browser { extends Screen { constructor() { super() - this.topContainer = div(null, this.logo, this.meBox, this.notificationBox); + this.topContainer = div(null, this.logo, this.notificationBox); this.topBox = div(null, this.topContainer); this.eol = document.createElement("a"); this.eol.className = "eol"; - this.eol.innerText = "Touch Develop retirement postponed until June 22, 2019. Sign-in and access to cloud assets to be removed on May 23, 2018. Learn more."; + this.eol.innerText = "Touch Develop will retire on June 22, 2019. Sign-in and access to cloud assets was removed on May 23, 2018. Learn more."; this.eol.href = "https://makecode.com/touchdevelop"; this.theRoot = div("hubRoot", this.bglogo, this.mainContent, this.topBox); } private mainContent = div("hubContent"); private logo = div("hubLogo", SVG.getTopLogo()); private bglogo = div("hubBgLogo", HTML.mkImg("svg:touchDevelop,currentColor", '', '', true)); - private meBox = div("hubMe"); private eol: HTMLAnchorElement; private notificationBox = div("notificationBox"); private topBox: HTMLElement; @@ -2334,46 +2200,6 @@ module TDev.Browser { }); } - private temporaryRequestedSignin = false; - private showingTemporarySignin = false; - private showTemporaryNotice() { - if ((!Storage.temporary || this.showingTemporarySignin) || - !EditorSettings.widgets().showTemporaryNotice || - ModalDialog.currentIsVisible()) return; - - // if only and not signed in, request to sign in - if (!this.temporaryRequestedSignin - && Cloud.isOnline() - && Cloud.isAccessTokenExpired()) { - this.temporaryRequestedSignin = true; - this.showingTemporarySignin = true; - var d = new ModalDialog(); - d.add(div('wall-dialog-header', lf("Sign in to avoid losing your scripts!"))); - d.add(div('wall-dialog-body', lf("Your browser does not allow Touch Develop to store web site data. This usually happens if run in Private Mode (Safari), in InPrivate mode (Internet Explorer) or your security settings prevent data storage."))); - d.add(div('wall-dialog-body', lf("When you sign in, Touch Develop will save your scripts in the cloud."))); - d.add(div("wall-dialog-buttons", - HTML.mkButton(lf("skip this"), () => { - this.showingTemporarySignin = false; - d.canDismiss = true; - d.dismiss(); - }), - HTML.mkButton(lf("sign in"), () => { - this.showingTemporarySignin = false; - if (Login.show()) { - d.canDismiss = true; - d.dismiss(); - } - }) - )); - d.fullWhite() - d.canDismiss = false; - d.show(); - } else { - if (EditorSettings.widgets().showTemporaryNotice) - Storage.showTemporaryWarning(); - } - } - static userPictureChooser(fbButton:boolean, onUpd:()=>void) { var preview = document.createElement("img"); @@ -2463,7 +2289,7 @@ module TDev.Browser { var updated = false; if (finish === undefined && !notificationsOnly) finish = () => { - if (updated && !Storage.showTemporaryWarning()) + if (updated) Util.setTimeout(500, () => window.location.reload()); }; var dialogBody = div(null) @@ -2700,7 +2526,6 @@ module TDev.Browser { public showSections(skipSync = false) { this.show(); - this.showTemporaryNotice(); this.showSectionsCoreAsync(skipSync).done(); } @@ -2763,10 +2588,6 @@ module TDev.Browser { } var docsEl: HTMLElement; - var ccgaEl: HTMLElement; - var whatsNew: HTMLElement; - var begginersEl : HTMLElement; - //var advancedEl:HTMLElement; var rate, settings: HTMLElement; var searchEl: HTMLElement; var elements = [ @@ -2774,15 +2595,6 @@ module TDev.Browser { docsEl = toTutBtn(this.mkFnBtn(lf("Docs"), () => { Util.navigateNewWindow(Cloud.config.helpPath); }, Ticks.hubDocs, true, 2)), - whatsNew = toTutBtn(this.mkFnBtn(lf("What's new"), () => { - Util.navigateNewWindow(Cloud.config.topicPath + "whatsnew"); - }, Ticks.hubDocsWhatsNew, true)), - begginersEl = toTutBtn(this.mkFnBtn(lf("Getting started"), () => { - Util.navigateNewWindow(Cloud.config.topicPath + "gettingstarted"); - }, Ticks.hubBeginnersGettingStarted, true)), - ccgaEl = toTutBtn(this.mkFnBtn(lf("Teach Creative Coding!"), () => { - Util.navigateNewWindow("/ccga"); - }, Ticks.hubCCGA, true)), // this button says "Search", which means "search" not "search docs" - "Help" is for that searchEl = this.mkFnBtn(lf("Search everything"), () => { this.hide(); this.browser().showList("search"); }, Ticks.hubChatSearch, false), this.createSkillButton(), @@ -2794,7 +2606,6 @@ module TDev.Browser { searchEl.appendChild(div("hubTileSearch", HTML.mkImg("svg:search,white"))); (searchEl).breakBefore = 1; docsEl.appendChild(div("hubTileSearch", HTML.mkImg("svg:search,white"))); - whatsNew.appendChild(div("hubTileSearch hubTileSearchSmall", HTML.mkImg("svg:star,white"))); settings.appendChild(div("hubTileSearch hubTileSearchSmall", HTML.mkImg("svg:settings,white"))); if (rate) rate.className += " exportBtn"; @@ -2812,14 +2623,6 @@ module TDev.Browser { sects["tutorials"] = { title: lf("tutorials") }; if (widgets.hubLearn) sects["learn"] = { title: lf("learn") }; - if (widgets.hubChannels) - sects["channels"] = { title: lf("channels") }; - if (widgets.hubShowcase) - sects["showcase"] = { title: lf("showcase") }; - if (widgets.hubTopAndNew) - sects["top"] = { title: lf("top & new") }; - if (widgets.hubMyArt) - sects["myart"] = { title: lf("my art") }; if (SizeMgr.portraitMode) { this.vertical = true; @@ -2849,7 +2652,6 @@ module TDev.Browser { var sectWidth = (name:string):number => sectWidths['default'] this.logo.style.display = ""; - this.meBox.style.display = ""; // h=26em @@ -2959,18 +2761,6 @@ module TDev.Browser { } this.mainContent.setChildren(divs); - - if (Cloud.getUserId()) { - var uid = this.browser().getUserInfoById("me", "me"); - this.meBox.setChildren([uid.mkSmallBox()]); - this.browser().addNotificationCounter(this.notificationBox); - } else { - var loginBtn = HTML.mkButtonElt("wall-button login-button", SVG.getLoginButton()) - this.meBox.setChildren(loginBtn.withClick(() => { - Login.show(); - })) - this.notificationBox.setChildren([]); - } } private docTopics:any[]; diff --git a/editor/recordProperties.ts b/editor/recordProperties.ts index 44bca1104..e3f1571bc 100644 --- a/editor/recordProperties.ts +++ b/editor/recordProperties.ts @@ -250,9 +250,6 @@ module TDev }, { name: "local", tick: Ticks.recordPersLocal - }, { - name: "replicated", - tick: Ticks.recordPersCloud }]; static servicePersistenceLabels = [{ @@ -269,22 +266,13 @@ module TDev }, { name: "server-local", tick: Ticks.recordPersLocal - }, { - name: "fully replicated", - tick: Ticks.recordPersCloud - } /*, { - name: "partially replicated", - tick: Ticks.recordPersPartial - } */]; + }]; static cloudlibraryVarPersistenceLabels = [{ name: "temporary", tick: Ticks.recordPersTemporary }, { name: "server-local", tick: Ticks.recordPersLocal - }, { - name: "replicated", - tick: Ticks.recordPersCloud }]; diff --git a/editor/scriptList.ts b/editor/scriptList.ts index acc9d1aa7..30dc296c2 100644 --- a/editor/scriptList.ts +++ b/editor/scriptList.ts @@ -918,31 +918,6 @@ module TDev.Browser { this.searchOnline = null; var sd = searchDiv; - if (bugStatus) { - var bugCompare = (a: BrowserPage, b: BrowserPage) => { - if (a instanceof CommentInfo) { - if (b instanceof CommentInfo) { - return (a).bugCompareTo(b, bugOrder) - } else return -1; - } else { - return b instanceof CommentInfo ? 1 : 0 - } - }; - - if (bugUser) { - var bu = bugUser == "me" ? Cloud.getUserId() - : bugUser == "none" ? "" - : bugUser; - items = items.filter(i => { - var j: JsonComment = TheApiCacheMgr.getCached(i.publicId) - if (j && (j.assignedtoid || "") != bu) - return false - return true - }) - } - items.sort(bugCompare) - } - var elts: HTMLElement[] = items.map(addEntry); if (xcont) { searchDiv = div(null, HTML.mkButton(lf("load more"), () => { searchFrom("continuation=" + xcont + "&") })); @@ -1114,8 +1089,7 @@ module TDev.Browser { if (Cloud.hasAccessToken() && Cloud.getUserId()) { World.syncAsync(true, undefined, false, () => { - Cloud.isOnlineWithPingAsync() - .done((isOnline: boolean) => Cloud.showSigninNotification(isOnline)); + // ignore }, (seconds) => { var delta = ""; @@ -1403,9 +1377,7 @@ module TDev.Browser { public getAnyInfoByEtag(e: JsonEtag): BrowserPage { if (!e) return null; else if (e.kind == "script") return this.getScriptInfoById(e.id); - else if (e.kind == "forum") return this.getForumInfo(); else if (e.kind == "user") return this.getUserInfoById(e.id, ""); - else if (e.kind == "comment") return this.getCommentInfoById(e.id); else if (e.kind == "art") return this.getArtInfoById(e.id); else if (e.kind == "screenshot") return this.getScreenshotInfoById(e.id); else if (e.kind == "document") return this.getDocumentInfo(e); @@ -1421,15 +1393,6 @@ module TDev.Browser { return this.getAnyInfoByEtag((e)); } - public getForumInfo() { - var si = this.getLocation("theForum"); - if (!si) { - si = new ForumInfo(this); - this.saveLocation(si); - } - return si; - } - private showInstalledAsync() { this.showList("installed-scripts"); return Promise.wrap(null); @@ -2033,16 +1996,6 @@ module TDev.Browser { return si; } - public getCommentInfoById(id: string) { - var si = this.getLocation(id); - if (!si) { - si = new CommentInfo(this); - si.loadFromWeb(id); - this.saveLocation(si); - } - return si; - } - public getSpecificInfoById(id: string, cl: any) { var si = this.getLocation(id); if (!si) { @@ -2588,10 +2541,6 @@ module TDev.Browser { if (!window.localStorage["everLoggedIn"]) return; this.offlineErrorReported = true; - if (Cloud.isTouchDevelopOnline()) { - HTML.showProgressNotification(Util.fmt("cannot reach {0}{1}; are you offline or not signed in?", - Cloud.getServiceUrl(), dbg ? ("/" + entry.path) : "")) - } } private decompressLists() { @@ -3042,9 +2991,6 @@ module TDev.Browser { var c = b.lastScore - a.lastScore; if (c != 0) return c; - if (a instanceof CommentInfo && b instanceof CommentInfo) { - } - if (a instanceof ScriptInfo && b instanceof ScriptInfo) return ScriptInfo.compareScripts(a, b); else @@ -3144,34 +3090,6 @@ module TDev.Browser { public shareButtons(): HTMLElement[] { var btns: HTMLElement[] = []; - - var id = this.getPublicationId(); - if (!id) return btns; - - var url = Cloud.config.shareUrl + "/" + id; - var text = this.twitterMessage(); - - if (EditorSettings.widgets().scriptEmail) - btns.push(div("sdAuthorLabel sdShareIcon phone-hidden", HTML.mkImg("svg:email,currentColor,clip=100")).withClick(() => { TDev.RT.ShareManager.shareLinkAsync(TDev.RT.Web.link_url(text, url), "email") })); - - if (!Cloud.isRestricted()) { - btns.pushRange(["twitter", "facebook"].map(network => - div("sdAuthorLabel sdShareIcon phone-hidden", HTML.mkImg("svg:" + network + ",currentColor,clip=100")).withClick(() => { TDev.RT.ShareManager.shareLinkAsync(TDev.RT.Web.link_url(text, url), network) }) - )); - } - if (this.parent instanceof ScriptInfo && EditorSettings.widgets().scriptAddToChannel) { - btns.unshift(div("sdAuthorLabel sdShareIcon", HTML.mkImg("svg:list,currentColor,clip=100", '', lf("add to channel"))).withClick(() => { - Meta.chooseListAsync({ - header: lf("add to channel"), - custombuttons: [ - HTML.mkButton(lf("create channel"), () => this.browser().createChannel()) - ] - }).done((info: ChannelInfo) => { - var si = (this.parent); - if (info) info.addScriptAsync(si).done(); - }); - })); - } return btns; } } @@ -3578,14 +3496,7 @@ module TDev.Browser { constructor(par: ScriptInfo) { super(par, lf("This tab contains additional information about this script"), - ScreenShotTab, - ScriptHeartsTab, - ChannelListTab, - TagsTab, - ArtTab, - ConsumersTab, - SuccessorsTab, - DerivativesTab); + ArtTab); } public bgIcon() { @@ -3610,934 +3521,10 @@ module TDev.Browser { public getId() { return "insights"; } } - export class CommentsTab - extends ListTab { - private seenComments: any = {} - - static topCommentInitialText: string = undefined; - - constructor(par: BrowserPage, private canDeleteAny: () => boolean = undefined, private headerRenderer: (el: HTMLElement) => void = undefined) { - super(par, "/comments") - } - public getId() { return this.forumId || "comments"; } - public getName() { return this.forumName || lf("comments"); } - public needsJsonScript() { return true; } - public getPreciseCount(): number { return !this.script() || !this.script().jsonScript ? -1 : this.script().jsonScript.comments; } - private _topContainer: HTMLElement; - - public isForum() { return !!this.forumName; } - - public forumName: string; - public forumId: string; - - public getParentId() { - if (this.isForum()) return this.forumId; - if (this.parent.publicId) return this.parent.publicId; - if (this.parent instanceof ScriptInfo) { - var sc = this.script(); - return sc.getPublicationIdOrBaseId(); - } - Util.check(false, "unknown id"); - return undefined; - } - - public getUrl() { - if (this.forumName) return this.forumId ? this.forumId + "/comments?bylatestnestedcomments=true" : "comments"; - return this.getParentId() + "/comments?bylatestnestedcomments=true"; - } - - public bgIcon() { return "svg:Email"; } - public noneText() { return this.parent instanceof UserInfo ? lf("no comments written by this user") : lf("no comments, tap to write some!"); } - - public resetEltsSoFar() { - this.seenComments = {} - } - - static bugStatuses = { - "bug": { icon: "bug", name: "bug" }, - "feature": { icon: "chip", name: "feature" }, - "fixed": { icon: "bandage", name: "fixed" }, - "postponed": { icon: "Alram" /* sic! */, name: "postponed" }, - "notabug": { icon: "Butterfly", name: "not a bug" }, - "duplicate": { icon: "twobugs", name: "duplicate" }, - } - static bugUsers = ["gxfb", "wonm", "ajlk", "bqsl", "ikyp", "pboj", "jeiv", "expza"] - - public finalListElt(): HTMLElement { - if (!this.isForum() && this.parent instanceof ScriptInfo) { - - var versionDepth = 0; - var js = this.script().jsonScript - if (js.id && js.rootid == js.id) - return div(null) - var cont = div(null) - var getFor = (id: string, skipComments = false) => { - Util.assert(!!id, "missing comment id"); - TheApiCacheMgr.getAsync(Cloud.lite ? id : id + "/base", true).done(resp => { - versionDepth++; - if (!resp) return - var d = div("sdLoadingMore", lf("loading comments for /{0}...", resp.id)) - var loadMore = (cont: string) => { - var dd = div(null, HTML.mkButton(lf("load more"), () => { - dd.setChildren(lf("loading...")) - TheApiCacheMgr.getAnd(resp.id + "/comments?continuation=" + cont, (lst: JsonList) => { - if (!lst) lst = { items: [], etags: undefined, continuation: undefined }; - dd.setChildren(lst.items.map(j => this.tabBox(j))) - if (lst.continuation) - dd.appendChild(loadMore(lst.continuation)) - }) - })) - return dd - } - - TheApiCacheMgr.getAnd(resp.id + "/comments", (lst: JsonList) => { - d.className = "" - if (lst && lst.items.length > 0) { - var ch = lst.items.map(j => this.tabBox(j)) - //ch.unshift(div("sdHeading", lf("comments on base /{0}", resp.id))) - if (lst.continuation) - ch.push(loadMore(lst.continuation)) - d.setChildren(ch) - } else { - d.setChildren([]) - } - }) - - var si = this.browser().getScriptInfo(resp) - var hd = si.mkSmallBox(); - hd.className += " sdBaseHeader" - if (EditorSettings.widgets().commentHistory) { - var btn = div("sdBaseCorner", - div(null, HTML.mkButton(lf("diff curr"), () => this.script().diffToId(resp.id))), - div(null, HTML.mkButton(lf("diff prev"), () => si.diffToBase()))) - hd.appendChild(btn) - } else hd.setFlag("slim", true); - cont.appendChild(div(null, hd, d)) - - if (resp.rootid != resp.id) { - if (versionDepth < 5) getFor(Cloud.lite ? resp.baseid : resp.id) - else { - var loadMoreVersion = HTML.mkButton(lf("load more"), () => { - loadMoreVersion.removeSelf(); - versionDepth = 0; - getFor(Cloud.lite ? resp.baseid : resp.id); - }); - cont.appendChild(loadMoreVersion); - } - } - }) - } - - - if (Cloud.lite) - // the call to /family is there to prefetch typical parents - TheApiCacheMgr.getAsync(this.getParentId() + "/family?count=10&etagsmode=includeetags", true) - .done((prefetch) => { - if (prefetch) - prefetch.items.forEach((e, i) => { - TheApiCacheMgr.store(e.id, e, prefetch.etags && prefetch.etags[i] ? prefetch.etags[i].ETag : null, true); - }) - - if (this.parent.publicId) { - if (!js.id) - return cont; // script deleted? - if (js.baseid) getFor(js.baseid) - } - else - getFor(this.getParentId(), true) - }) - else - getFor(this.getParentId()) - - return cont - } else { - return div(null) - } - } - - private mkCommentPostWidget(reply: boolean, id: string, initialText: string = null): HTMLElement { - Util.assert(!!id, "missing comment id"); - - if (Cloud.isRestricted() && !Cloud.hasPermission("post-comment")) return div(''); - - var text = HTML.mkTextArea(); - var postBtn = div(null); - text.rows = 1; - text.placeholder = reply ? lf("Reply...") : lf("Post a comment..."); - var postDiv: HTMLElement = div("commentPost", div(null, text), postBtn); - - var post = () => { - if (text.value.length < 2) return; - if (Cloud.anonMode(lf("posting comments"))) return; - var cmt = - { - time: Util.now() * 1000, - userid: "me", - username: "", - publicationid: id, - publicationname: this.parent.getName(), - text: text.value, - nestinglevel: this.parent.getPublicationId() == id ? 0 : 1, - positivereviews: 0, - comments: 0 - }; - var req = { kind: "comment", text: text.value, userplatform: Browser.platformCaps }; - Cloud.postPrivateApiAsync(id + "/comments", req) - .done((resp: JsonComment) => { - cmtBox.setFlag("working", false); - if (reply) - postDiv.setChildren([cmtBox, inner]); - else - postDiv.setChildren([inner, cmtBox]); - if (resp.id) { - TheApiCacheMgr.invalidate(id); - TheApiCacheMgr.store(resp.id, resp); - cmtBox.setChildren([this.commentBox(resp)]); - Browser.Hub.askToEnableNotifications(); - - - if (bugsEnabled) { - var bugId = id - if (!reply) bugId = resp.id - - var bugReq = { assignedtoid: undefined, resolved: undefined } - Util.getHashTags(req.text).forEach((h) => { - h = h.toLowerCase() - var m = /^assignedto(\w+)$/.exec(h) - if (m) bugReq.assignedtoid = m[1] - if (CommentsTab.bugStatuses.hasOwnProperty(h)) - bugReq.resolved = h - }) - - if (bugReq.assignedtoid || bugReq.resolved) { - return Cloud.postPrivateApiAsync(bugId, bugReq).then((resp) => { - TheApiCacheMgr.invalidate(bugId); - // debugger; - }) - } - } - } - }, (e: any) => { - cmtBox.setFlag("working", false); - postDiv.className = "commentPost"; - postDiv.setChildren([div(null, text), postBtn]); - if (e && e.status == 400) - ModalDialog.info(lf("couldn't post comment"), lf("Sorry, we could not post this comment.")); - else - Cloud.handlePostingError(e, lf("post comment")); - }); - - var cmtBox = div("sdCmtPosting", lf("posting...")); - cmtBox.setFlag("working", true); - postDiv.className = ""; - var inner = this.mkCommentPostWidget(reply, id); - postDiv.setChildren([cmtBox]); - } - - var addText = (s: string) => { - if (s) { - if (text.value) s = " " + s; - text.value += s + " "; - Util.setKeyboardFocusTextArea(text); - } - }; - - var attaching = false; - var attach = () => { - if (!attaching) { - attaching = true; - tick(Ticks.commentAttach); - Meta.chooseScriptAsync({ header: lf("pick a script to attach"), filter: s => !!s.publicId }) - .done(s => { - attaching = false; - if (s) { - var x = "/" + s.publicId - if (s.app) - x = "'" + s.app.getName() + "' " + x; - addText(x) - } - }); - } - }; - - var bug = () => { - tick(Ticks.commentBugTracking); - var m = new ModalDialog() - var boxes = [] - - var mkStatus = (info) => { - var e = new DeclEntry(info.name); - e.icon = "svg:" + info.icon + ",white" - e.description = "set status to " + info.name - boxes.push(e.mkBox().withClick(() => { - addText(Util.toHashTag(info.name)) - m.dismiss() - })) - } - - var mkUser = (name: string) => { - var ui = this.browser().getUserInfoById(name, name) - boxes.push(ui.mkSmallBox().withClick(() => { - addText(Util.toHashTag("assigned to " + name)) - m.dismiss() - })) - } - - var st = CommentsTab.bugStatuses - Object.keys(st).forEach(k => mkStatus(st[k])) - CommentsTab.bugUsers.forEach(mkUser) - - m.choose(boxes); - } - - var expand = () => { - if (text.rows <= 1) { - if (Cloud.anonMode(lf("posting comments"), expand)) return; - text.rows = 4; - postBtn.setChildren([ - bugsEnabled ? HTML.mkButton(lf("bug-tracking"), bug) : null, - HTML.mkButton(lf("attach"), attach), - HTML.mkButton(lf("post"), post)]); - } - } - - Util.onInputChange(text, expand); - text.addEventListener("click", expand, false); - - if (initialText) { - text.value = initialText; - Util.setTimeout(1, post); - } - - return postDiv; - } - - private addBugControls() { - var assignedto = "" - var assignedtoBtn = HTML.mkLinkButton(lf("any assignment"), () => { - var m = new ModalDialog() - var boxes = [] - - var add = (b: HTMLElement, f: () => void) => - boxes.push(b.withClick(() => { f(); m.dismiss(); })); - - var mkUser = (name: string) => { - var ui = this.browser().getUserInfoById(name, name) - add(ui.mkSmallBox(), () => { - assignedto = name; - assignedtoBtn.setChildren(ui.getTitle()) - }) - } - - var mkEntry = (name: string, at: string) => { - var e = new DeclEntry(name) - add(e.mkBox(), () => { - assignedto = at - assignedtoBtn.setChildren(name) - }) - } - - mkEntry("any assignment", "") - mkEntry("not yet assigned", "none") - - CommentsTab.bugUsers.forEach(mkUser) - - m.choose(boxes) - }) - - var order = "" - var orderBtn = HTML.mkLinkButton(lf("by votes"), () => { - if (order) { - order = "" - orderBtn.setChildren(lf("by votes")) - } else { - order = "recent"; - orderBtn.setChildren(lf("by time")) - } - }) - - var mk = (n: string) => - HTML.mkLinkButton(n + "s", () => { - var srch = "issue:" + n - if (assignedto) - srch += " assignedto:" + assignedto - if (order) - srch += " order:" + order - this.browser().searchFor(srch) - }); - this._topContainer = div(null, - div("smallText", - "show: ", - mk("bug"), - mk("feature"), - " filters: ", - assignedtoBtn, - orderBtn), - this._topContainer) - } - - public topContainer() { - if (!this._topContainer) { - if (this.forumName && !this.forumId) - this._topContainer = div(null); - else { - var t = CommentsTab.topCommentInitialText; - CommentsTab.topCommentInitialText = undefined; - this._topContainer = this.mkCommentPostWidget(false, this.getParentId(), t); - } - if (this.forumName == lf("issues")) - this.addBugControls(); - //if (this.isForum()) - // this._topContainer = div(null, ScriptInfo.labeledBox("forum", this.parent.mkSmallBox()), this._topContainer); - if (this.headerRenderer) { - var h = div(null); - this._topContainer = div(null, h, this._topContainer); - this.headerRenderer(h); - } - } - TheApiCacheMgr.invalidate(this.getUrl()); - return this._topContainer; - } - - public hideOnEmpty() { return false; } - - inlineText(cc: JsonIdObject) { - var c = cc; - return [span("sdBold", c.username), ": " + ListTab.limitLength(c.text, 60)]; - } - - private nestedCommentsCount(cont: string): number { - if (!cont) // first time querying - return Browser.isCellphone ? 2 : Browser.isMobile ? 3 : 5; - else // user asked for more - return Browser.isCellphone ? 5 : Browser.isMobile ? 10 : 15; - } - - private getNestedComments(elt: HTMLElement, id: string, cont: string) { - Util.assert(!!id, "missing nested replies"); - elt.setChildren([lf("loading replies...")]); - var count = this.nestedCommentsCount(cont); - TheApiCacheMgr.getAnd(id + "/comments?count=" + count + (cont ? "&continuation=" + cont : ""), (lst: JsonList) => { - if (!lst || !lst.items) lst = { items: [], etags: undefined, continuation: undefined }; - var items = lst.items; - if (!cont && items.length > count) // first load - { - var boxes = items.slice(0, count).map((cmt) => this.commentBox(cmt)); - boxes.reverse(); - var loadRemaining = () => { - var d: HTMLElement = div(null, HTML.mkButton(lf("load more replies"), () => { - var remainingBoxes = items.slice(count).map((cmt) => this.commentBox(cmt)); - remainingBoxes.reverse(); - if (!!lst.continuation) { - var d2: HTMLElement = div(null, HTML.mkButton(lf("load more replies"), () => { - this.getNestedComments(d2, id, lst.continuation); - })); - remainingBoxes.unshift(d2); - } - d.setChildren(remainingBoxes); - })); - boxes.unshift(d); - } - loadRemaining(); - elt.setChildren(boxes); - } else { - var boxes = items.map((cmt) => this.commentBox(cmt)); - boxes.reverse(); - var loadMore = () => { - if (!!lst.continuation) { - var d: HTMLElement = div(null, HTML.mkButton(lf("load more replies"), () => { - this.getNestedComments(d, id, lst.continuation); - })); - boxes.unshift(d); - } - } - loadMore() - elt.setChildren(boxes); - } - }); - } - - public tabBox(cc: JsonIdObject): HTMLElement { - var c = cc; - - if (!this.isForum()) - return this.commentBox(c, c.nestinglevel == 0); - - if (c.nestinglevel > 0) { - var r = div(null); - - if (!this.seenComments.hasOwnProperty(c.publicationid)) { - this.seenComments[c.publicationid] = 1; - TheApiCacheMgr.getAnd(c.publicationid, (pc: JsonComment) => { - r.setChildren([this.commentBox(pc, true)]); - }); - } - - return r; - } else { - if (this.seenComments.hasOwnProperty(c.id)) return div(null); - return this.commentBox(c, true); - } - } - - static translateCommentAsync(cid: string): Promise { // text - if (!Cloud.config.translateCdnUrl || !Cloud.config.translateApiUrl) return Promise.as(undefined); - var to = Util.getTranslationLanguage(); - var blobUrl = Cloud.config.translateCdnUrl + "/comments/" + to + "/" + cid; - return Util.httpGetTextAsync(blobUrl) - .then((blob) => blob, e => { - // requestion translation - var url = Cloud.config.translateApiUrl + '/translate_comment?commentId=' + cid + '&to=' + to; - return Util.httpGetJsonAsync(url).then((js) => js.translated, e => undefined); - }); - } - - public commentBox(c: JsonComment, includePosting = false): HTMLElement { - if (!c) return undefined; // deleted comment - - var uid = this.browser().getCreatorInfo(c); - var nestedComments = div(null); - var nestedPubs = div(null); - if (c.nestinglevel > 0 || c.comments == 0) nestedComments = null; - else { - TheApiCacheMgr.invalidate(c.id + "/comments"); - this.getNestedComments(nestedComments, c.id, null); - } - var textDiv = div('sdSmallerTextBox'); - var cmts = new MdComments(); - cmts.allowLinks = true; - cmts.allowImages = false; - cmts.allowVideos = false; - var formattedText = cmts.formatText(c.text) - Browser.setInnerHTML(textDiv, formattedText); - HTML.fixWp8Links(textDiv); - dirAuto(textDiv); - - // parsing any pub id - var pubRx = /(^|[^\w\/]|https?:\/\/tdev.ly|https?:\/\/(www\.)?touchdevelop.com)\/([a-z]{4,})/g; - var pubM = null; - var isPull = /#pullRequest/i.test(c.text) - while ((pubM = pubRx.exec(c.text)) != null) { - TheApiCacheMgr.getAsync(pubM[3], true) - .done( - j => { - var jd = this.browser().getAnyInfoByEtag(j); - if (jd) { - var box = jd.mkSmallBox() - nestedPubs.appendChild(box); - if (isPull && jd instanceof ScriptInfo) { - box.appendChild( - div("sdBaseCorner", HTML.mkButton(lf("pull"), () => (jd).mergeScript()))) - } - } - }, - e => { }); - } - // parsing user id - var userRx = /(^|[^\w@])@([a-z]{4,})/g; - var userM = null; - while ((userM = userRx.exec(c.text)) != null) { - TheApiCacheMgr.getAsync(userM[2], true) - .done( - j => { - var jd = this.browser().getAnyInfoByEtag(j); - if (jd) nestedPubs.appendChild(jd.mkSmallBox()); - }, - e => { }); - } - - // parsing social network links - socialNetworks(EditorSettings.widgets()).filter(sn => !!sn.idToHTMLAsync) - .forEach(sn => sn.parseIds(c.text) - .forEach(ytid => sn.idToHTMLAsync(ytid) - .done(d => { if (d) nestedPubs.appendChild(d); }))); - - var translateBtn: HTMLElement = null; - var translateCmt = () => { - translateBtn.setFlag("working", true); - CommentsTab.translateCommentAsync(c.id) - .done(translated => { - var trDiv = div('translated', translated || ':( ' + lf("Sorry, we could not translate this message.")); - dirAuto(trDiv); - translateBtn.setFlag("working", false); - translateBtn.removeSelf(); - textDiv.appendChild(trDiv); - }); - } - translateBtn = EditorSettings.widgets().translateComments ? div("sdCmtBtn", HTML.mkImg("svg:Recycle,#000", '', '', true), lf("translate")).withClick(translateCmt) : null; - - var delBtn: HTMLElement = null; - var deleteCmt = () => { - if (Cloud.anonMode(lf("deleting comments"))) return; - ModalDialog.ask(lf("are you sure you want to delete this comment?"), lf("delete it"), () => { - delBtn.setFlag("working", true); - Cloud.deletePrivateApiAsync(c.id).done(() => { - r.removeSelf(); - }, (e: any) => { - delBtn.setFlag("working", false); - Cloud.handlePostingError(e, "delete comment"); - }); - }); - } - - var reportAbuse = () => { - AbuseReportInfo.abuseOrDelete(c.id) - } - - if (c.userid == Cloud.getUserId() || (this.canDeleteAny && this.canDeleteAny())) { - delBtn = div("sdCmtBtn", HTML.mkImg("svg:Trash,#000", '', '', true), lf("delete")).withClick(deleteCmt); - } else { - delBtn = div("sdCmtBtn", HTML.mkImg("svg:SmilieSad,#000", '', '', true), lf("abuse")).withClick(reportAbuse); - } - - var likeBtn = div("sdCmtBtnOuter"); - function setLikeBtn(s: number, h: string, f: () => void) { - var btn: HTMLElement; - if (s < 0) - btn = div("sdCmtBtn", HTML.mkImg("svg:wholeheart,#000"), h) - else - btn = div("sdCmtBtn", HTML.mkImg("svg:wholeheart,#a00"), h) - if (Math.abs(s) < 2) btn.setFlag("working", true); - likeBtn.setChildren([btn.withClick(f)]); - } - ScriptInfo.setupLike(c.id, setLikeBtn); - - var r = div("sdCmt", uid.thumbnail(), - div("sdCmtTopic", - span("sdBold", c.username), - c.resolved ? div("sdCmtResolved", c.resolved + (c.assignedtoid ? " (" + c.assignedtoid + ")" : "")) : null, - this.parent.getPublicationId() == c.publicationid || this.forumId == c.publicationid || c.nestinglevel > 0 ? null - : [" on ", div("sdCmtScriptName", c.publicationname).withClick(() => { - var b = this.browser(); - b.loadDetails(b.getReferencedPubInfo(c)) - }) - ]), - textDiv, - div("sdCmtMeta", - Util.timeSince(c.time), - c.positivereviews > 0 ? " " + c.positivereviews + "♥ " : null, - c.comments > 0 ? " " + c.comments + " replies " : null, - span("sdCmtId", " /" + c.id), - div("sdCmtBtns", translateBtn, likeBtn, delBtn)), - nestedPubs, - nestedComments, - includePosting ? this.mkCommentPostWidget(true, c.id) : null - ); - if (c.nestinglevel == 0) { - r.className += " sdCmtTop"; - if (!includePosting) { - r.style.cursor = "pointer"; - r.withClick(() => { - var b = this.browser(); - b.loadDetails(b.getCommentInfoById(c.id)); - }); - } - } else { - r.className += " sdCmtNested"; - } - return r; - } - } - - export class SuccessorsTab - extends ListTab { - constructor(par: BrowserPage) { - super(par, "/successors") - } - public getId() { return "forks"; } - public getName() { return lf("forks"); } - - public bgIcon() { return "svg:code-fork"; } - public noneText() { return lf("no forks, install, edit and re-publish script to create one!"); } - // public bgIcon() => "svg:WritePage"; - inlineText(cc: JsonIdObject) { - var c = cc; - return [c.name == this.script().app.getName() ? null : c.name, " by\u00A0", span("sdBold", c.username)]; - } - - public tabBox(cc: JsonIdObject): HTMLElement { - var c = cc; - return this.browser().getScriptInfo(c).mkSmallBox(); - } - } - interface JsonScriptWithBase extends JsonScript { baseid: string; } - export class DerivativesTab - extends BrowserTab { - constructor(par: BrowserPage) { - super(par) - } - public getId() { return "derivatives"; } - public getName() { return lf("derivatives"); } - - public bgIcon() { return "svg:Binoculars"; } - - public initTab() { - var infos: StringMap = {} - var boxes: HTMLElement[] = [] - var numQueries = 0 - var numDiffs = 0 - - var statDiv = div("sdInlineHelp") - boxes.push(statDiv) - - var updateStats = (done = false) => { - statDiv.setChildren(Util.fmt("{2}. {0} server request(s), {1} diff(s) computed", numQueries, numDiffs, done ? "Done" : "Working")) - } - - var addDiffAsync = (scr: JsonScriptWithBase) => { - // find first script up with a different update id - var diffTo = scr.baseid - while (infos.hasOwnProperty(diffTo)) { - var par = infos[diffTo] - if (par.updateid != scr.updateid) - break - diffTo = par.baseid - } - - return Promise.join([ScriptCache.getScriptAsync(diffTo), ScriptCache.getScriptAsync(scr.id)]).then(scrs => { - if (!scrs[0] || !scrs[1]) return; - - function prep(s: string) { - var app = AST.Parser.parseScript(s, []) - //app.isTopLevel = true; - //AST.TypeChecker.tcScript(app, true); - return app; - } - var a0 = prep(scrs[0]) - var a1 = prep(scrs[1]) - AST.Diff.diffApps(a0, a1, { - useStableNames: true - }) - var st = AST.Diff.DiffStat.run(a1) - - var info = this.browser().getScriptInfoById(scr.id) - var box = div(null, info.mkSmallBox()) - box.appendChild(HTML.mkButton(lf("diff"), () => info.diffToId(diffTo))) - var addNum = (n: number, sym: string, title: string) => { box.appendChildren([ScriptInfo.mkNum(n, sym, title)]) } - - addNum(st.numOtherChanges, "svg:Wrench", lf("other")) - addNum(st.numCommentChanges, "svg:callout", lf("comments")) - addNum(st.numArtChanges, "svg:Clover", lf("art changes")) - addNum(st.numStringChanges, "svg:ABC", lf("string changes")) - addNum(st.numNumberChanges, "svg:123", lf("number changes")); - - (box).score = [st.numOtherChanges, st.numCommentChanges + st.numStringChanges + st.numNumberChanges, - st.numArtChanges, -scr.time] - var cmpBox = (a, b) => { - if (!a.score) return -1 - if (!b.score) return 1 - for (var i = 0; i < a.score.length; ++i) { - var d = b.score[i] - a.score[i] - if (d) return d - } - return 0 - } - - boxes.push(box) - boxes.sort(cmpBox) - this.tabContent.setChildren(boxes) - - numDiffs++ - updateStats() - }) - } - - var processAsync: (p: string) => Promise = (parid: string) => { - var withContAsync = (cont: string) => - TheApiCacheMgr.getAsync(parid + "/successors?count=100" + cont) - .then((resp: JsonList) => { - numQueries++ - updateStats() - var promises: Promise[] = [] - resp.items.forEach((scr: JsonScriptWithBase) => { - scr.baseid = parid - infos[scr.id] = scr - if (scr.updateid == scr.id) - promises.push(addDiffAsync(scr)) - promises.push(processAsync(scr.id)) - }) - if (resp.continuation) - promises.push(withContAsync("&continuation=" + resp.continuation)) - return Promise.join(promises) - }) - return withContAsync("") - } - processAsync(this.parent.publicId).done(() => updateStats(true)) - - this.tabContent.setChildren(boxes) - } - } - - export class TagsTab extends ListTab { - tagBtns: any = {}; - ownTags: any = {}; - askedForTagList = false; - _topContainer: HTMLElement = null; - - constructor(par: BrowserPage) { - super(par, "/tags"); - } - - hideOnEmpty() { return false; } - - getId() { return "tags"; } - getName() { return lf("tags"); } - - private fullName(c: JsonTag) { return c.category ? c.category + " " + c.name : c.name; } - - inlineText(cc: JsonIdObject) { - var c = cc; - return [c.instances + "x ", span("sdBold", this.fullName(c))]; - } - - noneText() { return lf("no tags, tap to add some!"); } - - initInline() { - this.loadMoreElementsAnd(null, (tags: JsonTag[]) => { - this.setVisibility(true); - if (tags.length == 0) { - this.inlineContent.setChildren([div("sdTabTileNothing", span(null, this.noneText())), this.getTileLabel("")]) - } else { - tags.sort((a, b) => b.instances - a.instances); - var ptfn = this.fullName(tags[0]); - var prim = div("sdTabTilePrimaryTag " + (ptfn.length < 10 ? " sdTabTilePrimaryTagBig" : ""), span(null, ptfn)); - var ch = [prim]; - for (var i = 1; i < 2; i++) { - var t = tags[i]; - if (t) - ch.push(div("sdTabTileSecondaryTag", span(null, this.fullName(t)))) - } - ch.push(this.getTileLabel("")); - this.inlineContent.setChildren(ch); - } - }); - } - - - resetEltsSoFar() { - this.tagBtns = {} - } - - - topContainer(): HTMLElement { - if (this._topContainer) return this._topContainer; - - var tagContainer = div(null); - - var addTag = (e: JsonTag) => { - if (Cloud.anonMode(lf("adding tags"))) return; - - var id = e.id; - e = JSON.parse(JSON.stringify(e)); - e.instances = 1; - tagContainer.appendChild(this.tabBox(e)); - this.tagBtns[id].firstChild.setFlag("working", true); - - var req = { kind: "tag", id: id } - Cloud.postPrivateApiAsync(this.parent.getPublicationId() + "/tags", req) - .done((resp) => { - this.updateTagTo(id, true); - Browser.Hub.askToEnableNotifications(); - }, (e: any) => { - this.tagBtns[id].firstChild.setFlag("working", false); - Cloud.handlePostingError(e, "add tag"); - }); - } - - var btn = HTML.mkButton(lf("add new tag"), () => { - var done = false; - TheApiCacheMgr.getAnd("tags?count=1000", (lst: JsonList) => { - if (done) return; - done = true; - var seenTags: any = {} - var items = lst.items.filter((e: JsonTag) => { - if (this.tagBtns[e.id] || seenTags[e.id]) return false; - seenTags[e.id] = true; - return true; - }); - items.sort((a: JsonTag, b: JsonTag) => b.instances - a.instances); - var m = new ModalDialog(); - m.choose(items.map((e: JsonTag) => this.bareBox(e, null).withClick(() => { m.dismiss(); addTag(e) }))); - }); - }); - - return this._topContainer = div(null, div(null, btn), - Host.expandableTextBox(lf("tap a checkmark to add (or remove) your 'vote' to an existing tag")), tagContainer); - } - - private bareBox(c: JsonTag, btn: HTMLElement) { - return div("sdCmt", - btn, - div("sdCmtTopic", - span("sdBold", this.fullName(c)), - " x" + c.instances + "" - ), - Host.expandableTextBox(c.description)); - } - - updateTagTo(id: string, hasIt: boolean) { - var sid = this.parent.getPublicationId(); - TheApiCacheMgr.invalidate("me/tagged/" + sid); - TheApiCacheMgr.invalidate(sid + "/tags"); - this.ownTags[id] = hasIt; - this.updateTag(id); - } - - updateTag(id: string) { - var sid = this.parent.getPublicationId(); - var btn = this.tagBtns[id]; - if (!btn) return; - var hasIt = !!this.ownTags[id]; - var elt = div("sdIcon", HTML.mkImg("svg:Check," + (hasIt ? "black" : "#ddd") + ",clip=60")); - elt.withClick(() => { - elt.setFlag("working", true); - if (hasIt) { - if (Cloud.anonMode(lf("removing tags"))) return; - Util.httpRequestAsync(Cloud.getPrivateApiUrl(sid + "/" + id), "DELETE", undefined).then(() => { - this.updateTagTo(id, false); - }, (e: any) => { - elt.setFlag("working", false); - Cloud.handlePostingError(e, "remove tag"); - }).done(); - } else { - if (Cloud.anonMode(lf("adding tags"))) return; - var req = { kind: "tag", id: id } - Cloud.postPrivateApiAsync(sid + "/tags", req) - .done((resp) => { - this.updateTagTo(id, true); - Browser.Hub.askToEnableNotifications(); - }, (e: any) => { - elt.setFlag("working", false); - Cloud.handlePostingError(e, "add tag"); - }); - } - }); - btn.setChildren([elt]); - } - - tabBox(cc: JsonIdObject) { - var c = cc; - if (!this.askedForTagList) { - TheApiCacheMgr.getAnd("me/tagged/" + this.parent.getPublicationId(), (resp: JsonList) => { - this.ownTags = {} - resp.items.forEach((t: JsonTag) => { this.ownTags[t.id] = true }) - Object.keys(this.tagBtns).forEach((t) => this.updateTag(t)) - }) - } - - var btn = div("sdThumb"); - var d = this.bareBox(c, btn); - this.tagBtns[c.id] = btn; - this.updateTag(c.id); - - return d; - } - } - export class AbuseReportsTab extends ListTab { constructor(par: BrowserPage) { @@ -5235,10 +4222,7 @@ module TDev.Browser { public mkTabsCore(): BrowserTab[] { return [ this - // these need more work - // new CommentsTab(this), , new ScriptsTab(this, lf("no scripts using this art")) - // new SubscribersTab(this) , new AbuseReportsTab(this) ]; } @@ -5252,10 +4236,6 @@ module TDev.Browser { var cont = []; var audio = null; var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - // addNum(a.positivereviews, "♥"); - // if (sz > 1) { - // addNum(a.comments, "✉"); - // } var nums = div("hubTileNumbers", cont, div("hubTileNumbersOverlay")); //nums.style.background = d.style.background; @@ -5428,24 +4408,7 @@ module TDev.Browser { } private mkButtons(): HTMLElement { - var mkBtn = (icon: string, desc: string, key: string, f: () => void) => { - var b = HTML.mkButtonElt("sdBigButton sdBigButtonHalf", div("sdBigButtonIcon", HTML.mkImg(icon, '', '', true)), div("sdBigButtonDesc sdHeartCounter", desc)); - TheEditor.keyMgr.btnShortcut(b, key); - return b.withClick(f); - } - var heartButton: HTMLElement = span("sdHeart", ""); - var setBtn = (state: number, hearts: string, f: () => void) => { - var btn: HTMLElement; - if (state < 0) - btn = mkBtn("svg:wholeheart,white,opacity=0.3", hearts, null, f); - else - btn = mkBtn("svg:wholeheart,white", hearts, null, f); - heartButton.setChildren([btn]); - btn.setFlag("working", Math.abs(state) < 2); - } - - ScriptInfo.setupLike(this.publicId, setBtn); - return div("sdRunBtns", heartButton); + return div("sdRunBtns"); } public match(terms: string[], fullName: string) { @@ -6236,15 +5199,6 @@ module TDev.Browser { var cont = []; var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - if (big && !isTopic) { - if (!SizeMgr.phoneMode) - addNum(this.jsonScript.installations, "users", lf("users")); - addNum(this.jsonScript.runs, "runs", lf("runs")); - } else { - addNum(getScriptHeartCount(this.jsonScript), "♥", lf("favourites")); - if (EditorSettings.widgets().publicationComments) - addNum(this.jsonScript.comments, "✉", lf("comments")); - } if (this.app.isLibrary) { var sp = document.createElement('span'); sp.className = 'sdNumber symbol'; sp.innerHTML = ' ' + AST.libSymbol; @@ -6300,13 +5254,6 @@ module TDev.Browser { var cont = []; var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - addNum(getScriptHeartCount(this.jsonScript), "♥", lf("favourites")); - if (sz > 1) { - if (EditorSettings.widgets().publicationComments) - addNum(this.jsonScript.comments, "✉", lf("comments")); - //addNum(jsonScript.installations, "users"); - //addNum(jsonScript.runs, "runs"); - } var nums = div("hubTileNumbers", cont, div("hubTileNumbersOverlay")); //nums.style.background = this.app.htmlColor(); @@ -6364,21 +5311,16 @@ module TDev.Browser { return !this.app || this.app.supportsAllPlatforms(api.core.currentPlatform); } - private commentsTab: CommentsTab; public mkTabsCore(): BrowserTab[] { var r: BrowserTab[]; if (!this.publicId) r = [this, - new ScriptDetailsTab(this), - EditorSettings.widgets().scriptHistoryTab ? new HistoryTab(this) : null]; + new ScriptDetailsTab(this)]; else r = [ this, - new ScriptDetailsTab(this), - this.cloudHeader && EditorSettings.widgets().scriptHistoryTab ? new HistoryTab(this) : null, - EditorSettings.widgets().scriptInsightsTab ? new InsightsTab(this) : null, - Cloud.lite ? new AbuseReportsTab(this) : null, + new ScriptDetailsTab(this) ]; return r; } @@ -6424,23 +5366,10 @@ module TDev.Browser { } var likePub: HTMLElement; - - var setBtn = (state: number, hearts: string, f: () => void) => { - var btn: HTMLElement; - if (state < 0) - btn = mkBtn(Ticks.browseHeart, "svg:wholeheart,white,opacity=0.3", hearts, null, f); - else - btn = mkBtn(Ticks.browseUnHeart, "svg:wholeheart,white", hearts, null, f); - heartButton.setChildren([btn]); - btn.setFlag("working", Math.abs(state) < 2); - } - - if (this.publicId) { - var heartButton = span("sdHeart", ""); - likePub = heartButton; - ScriptInfo.setupLike(this.publicId, setBtn); - } else { + if (!this.publicId) { likePub = mkBtn(Ticks.browsePublish, "svg:Upload,white", lf("publish"), null, () => this.publishAsync(true).done()); + likePub.classList.add("sdUninstall"); + likePub.style.backgroundColor = "#ccc"; } var uninstall: HTMLElement; @@ -6613,7 +5542,6 @@ module TDev.Browser { var wontWork = div(null); var runBtns = div(null); var authorDiv = div(null); - var commentsDiv = div(null); var docsButtonDiv = div(null); this.tabContent.setChildren([ @@ -6623,7 +5551,6 @@ module TDev.Browser { descDiv, metaDiv, docsButtonDiv, - commentsDiv, wontWork, ]); @@ -6685,18 +5612,6 @@ module TDev.Browser { socialNetworks(EditorSettings.widgets()).filter(sn => !!sn.idToHTMLAsync && !!this.jsonScript.meta[sn.id]) .forEach(sn => sn.idToHTMLAsync(this.jsonScript.meta[sn.id]).done(d => { if (d) metaDiv.appendChild(d); })); } - - if (EditorSettings.widgets().publicationComments && this.getPublicationIdOrBaseId()) { - if (!this.commentsTab) { - this.commentsTab = new CommentsTab(this); - this.commentsTab.initElements(); - this.commentsTab.tabLoaded = true; - this.commentsTab.initTab(); - } - commentsDiv.setChildren([ - this.commentsTab.topContainer(), - this.commentsTab.tabContent]) - } }); this.getScriptTextAsync() @@ -7784,9 +6699,6 @@ module TDev.Browser { var cont = []; var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - addNum(u.receivedpositivereviews, "♥", lf("favourites")); - //addNum(u.subscribers, "svg:Person,white,clip=80"); does not scale properly - //addNum(u.features, "svg:Award,white,clip=110"); var nums = div("hubTileNumbers", cont, div("hubTileNumbersOverlay")); @@ -8059,8 +6971,7 @@ module TDev.Browser { constructor(par: UserInfo) { super(par, "More information about art, score, subscribers, subscriptions and given hearts.", - Cloud.lite ? ChannelListTab : null, - ArtTab, SubscribersTab, UserHeartsTab, SubscriptionsTab, ScreenShotTab); + ArtTab); } public bgIcon() { @@ -8085,44 +6996,6 @@ module TDev.Browser { public getId() { return "insights"; } } - export class ForumInfo - extends BrowserPage { - - constructor(par: Host) { - super(par) - this.publicId = "theForum"; - } - public persistentId() { return "forum:forum"; } - public getTitle() { return "Forum"; } - - public getId() { return "overview"; } - public getName() { return lf("overview"); } - - public mkBoxCore(big: boolean): HTMLElement { return div("hubSectionHeader", spanDirAuto(lf("the forums"))) } - - public mkTabsCore(): BrowserTab[] { - var tabs: CommentsTab[] = [ - new CommentsTab(this), - new CommentsTab(this), - new CommentsTab(this) - ]; - - tabs[0].forumName = lf("general"); - tabs[0].forumId = "bttt"; - - tabs[1].forumName = lf("issues"); - tabs[1].forumId = "atljilhp"; - - tabs[2].forumName = lf("everything"); - tabs[2].forumId = ""; - - return tabs; - } - - public initTab() { - } - } - export class AbuseReportInfo extends BrowserPage { constructor(par: Host) { @@ -8362,142 +7235,6 @@ module TDev.Browser { } } - export class CommentInfo - extends BrowserPage { - constructor(par: Host) { - super(par) - this._comments = new CommentsTab(this); - } - public persistentId() { return "comment:" + this.targetId(); } - public getTitle() { return "comment " + this.publicId; } - - public getId() { return "comment"; } - public getName() { return lf("comment"); } - - public loadFromWeb(id: string) { - this.publicId = id; - } - - public mkBoxCore(big: boolean) { - var icon = div("sdIcon", HTML.mkImg("svg:email,white")); - icon.style.background = "#1731B8"; - var textBlock = div("sdCommentBlockInner"); - var author = div("sdCommentAuthor"); - var hd = div("sdCommentBlock", textBlock, author); - - var numbers = div("sdNumbers"); - var addInfoInner = div("sdAddInfoInner", "/" + this.publicId); - var pubId = div("sdAddInfoOuter", addInfoInner); - var res = div("sdHeaderOuter", div("sdHeader", icon, div("sdHeaderInner", hd, pubId, numbers, this.reportAbuse(big)))); - - if (big) - res.className += " sdBigHeader"; - - return this.withUpdate(res, (u: JsonComment) => { - var del = (u) === false - - textBlock.setChildren([del ? lf("deleted comment") : u.text]); - author.setChildren(["-- ", u.username || ""]); - addInfoInner.setChildren(del ? [] : [Util.timeSince(u.time) + " on " + u.publicationname]); - if (del) { - icon.style.background = "#999"; - } - if (u.publicationname == "general discussion" || u.publicationname == "bug reports and feature requests") { - icon.setChildren([HTML.mkImg("svg:callout,white")]) - icon.style.background = "#080"; - } - if (u.resolved) { - var ic = CommentsTab.bugStatuses[u.resolved] - if (ic && ic.icon) - icon.setChildren([HTML.mkImg("svg:" + ic.icon + ",white")]) - } - - var cont = []; - var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - addNum(u.positivereviews, "♥", lf("favourites")); - addNum(u.comments, "replies", lf("replies")); - numbers.setChildren(cont); - }); - } - - public mkTile(sz: number) { - var d = div("hubTile hubTileSize" + sz); - return this.withUpdate(d, (u: JsonComment) => { - - var cont = []; - var addNum = (n: number, sym: string, title) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - addNum(u.positivereviews, "♥", lf("favourites")); - addNum(u.comments, lf("replies"), lf("replies")); - - var nums = div("hubTileNumbers", cont, div("hubTileNumbersOverlay")); - //nums.style.background = d.style.background; - - d.setChildren([div("hubTileIcon", HTML.mkImg("svg:callout,white")), - div("hubTileTitleBar", - div("hubTileTitle", "on " + spanDirAuto(u.publicationname)), - div("hubTileSubtitle", - div("hubTileAuthor", spanDirAuto(u.username), nums)))]) - }); - } - - public initTab() { - this._comments.initElements(); - this._comments.tabLoaded = true; - this._comments.initTab(); - - this.withUpdate(this.tabContent, (c: JsonComment) => { - this.tabContent.setChildren([ - ScriptInfo.labeledBox(lf("comment on"), this.browser().getReferencedPubInfo(c).mkSmallBox()), - this._comments.commentBox(c, true)]); - }); - } - - public mkBigBox(): HTMLElement { return null; } - - private _comments: CommentsTab; - - public mkTabsCore(): BrowserTab[] { return [this, new AbuseReportsTab(this)]; } - - public bugCompareTo(other: CommentInfo, order: string) { - var j0: JsonComment = TheApiCacheMgr.getCached(this.publicId) - var j1: JsonComment = TheApiCacheMgr.getCached(other.publicId) - if (j0) - if (j1) { - return (order == "recent" ? 0 : - (j1.positivereviews - j0.positivereviews) || - (j1.comments - j0.comments)) || - (j1.time - j0.time) - } else return -1; - else if (j1) return 1; - else return 0; - } - - public match(terms: string[], fullName: string) { - if (terms.length == 0) return 1; - - var json: JsonComment = TheApiCacheMgr.getCached(this.publicId); - if (!json) return 0; // not loaded yet - - var s = this.publicId + " " + json.publicationid + " " + json.username + " " + json.text; - return IntelliItem.matchString(s.toLowerCase(), terms, 100, 10, 1); - } - - public mkSmallBox(): HTMLElement { - return this.mkBoxCore(false).withClick(() => { - var json = TheApiCacheMgr.getCached(this.publicId); - if (!json || json.nestinglevel == 0) this.parentBrowser.loadDetails(this) - else this.parentBrowser.loadDetails(this.parentBrowser.getCommentInfoById(json.publicationid)); - }); - } - - private targetId(): string { - var json = TheApiCacheMgr.getCached(this.publicId); - if (!json || json.nestinglevel == 0) return this.publicId; - else return json.publicationid; - } - - } - export class TopicInfo extends BrowserPage { public topic: HelpTopic; @@ -8540,37 +7277,11 @@ module TDev.Browser { return btns; } - private likeBtn(showCount = false) { - var likeBtn = div(null); - var id = this.topic.json.id; - if (!id) return likeBtn; - - var setLikeBtn = (s: number, h: string, f: () => void) => { - var btn: HTMLElement; - if (s < 0) - btn = div("sdDocsBtn", HTML.mkImg("svg:wholeheart,#000")) - else - btn = div("sdDocsBtn", HTML.mkImg("svg:wholeheart,#EAC117")) - var ctnSpan = span('', ''); btn.appendChild(ctnSpan); - if (Math.abs(s) < 2) btn.setFlag("working", true); - likeBtn.setChildren([btn.withClick(f)]); - if (showCount) - TheApiCacheMgr.getAnd(id, (s: JsonScript) => { - if (!s) return; //deleted - var n = this.topic.fromJson ? getScriptHeartCount(s) : s.cumulativepositivereviews - ctnSpan.innerText = n + ""; - }) - } - ScriptInfo.setupLike(id, setLikeBtn); - return likeBtn; - } - public mkBoxCore(big: boolean): HTMLElement { if (this.topic.fromJson) { var r = this.browser().getScriptInfoById(this.topic.id).mkBoxExt(big, true); if (big) { r.className += " sdDocsHeader"; - r.appendChild(this.likeBtn(false)); } return r; } @@ -8588,15 +7299,12 @@ module TDev.Browser { div("sdHeader", icon, div("sdHeaderInner", hd, desc))); if (big) { res.className += " sdBigHeader sdDocsHeader"; - res.appendChild(this.likeBtn(true)); } else { res.style.paddingLeft = (1 + 1.5 * this.topic.nestingLevel) + "em" } return res; } - private commentsTab: CommentsTab; - public getPublicationId() { return this.topic.json.id; } public initTab() { @@ -8690,21 +7398,8 @@ module TDev.Browser { }) var requestDocs = null - var comments = div(null) - if (id) { - if (!this.commentsTab) { - this.commentsTab = new CommentsTab(this); - this.commentsTab.initElements(); - } - comments.setChildren([ - div("sdHeading", lf("comments")), - this.commentsTab.topContainer(), - this.commentsTab.tabContent]) - } - allBottomDiv.setChildren([ div("sdBottomButtons", btn2), - comments, requestDocs ]) @@ -8720,8 +7415,6 @@ module TDev.Browser { noChromeDiv, allBottomDiv ]) - if (this.commentsTab) - this.commentsTab.initTab(); } public match(terms: string[], fullName: string) { @@ -8772,8 +7465,7 @@ module TDev.Browser { div("sdRelatedBtns", HTML.mkButton(lf("open"), () => { var b = this.browser(); b.loadDetails(b.getScriptInfoById(c.id)); - }))), - this.likeBtn(true) + }))) ); return r; } @@ -9100,7 +7792,6 @@ module TDev.Browser { if (big) { res.className += " sdBigHeader sdDocsHeader"; - res.appendChild(this.likeBtn(false)); } @@ -9119,29 +7810,6 @@ module TDev.Browser { }); } - private likeBtn(showCount = false): HTMLElement { - var lbtn = div(null); - var id = this.publicId; - var setLikeBtn = (s: number, h: string, f: () => void) => { - var btn: HTMLElement; - if (s < 0) - btn = div("sdDocsBtn", HTML.mkImg("svg:wholeheart,#000")) - else - btn = div("sdDocsBtn", HTML.mkImg("svg:wholeheart,#EAC117")) - var ctnSpan = span('', ''); btn.appendChild(ctnSpan); - if (Math.abs(s) < 2) btn.setFlag("working", true); - lbtn.setChildren([btn.withClick(f)]); - if (showCount) - TheApiCacheMgr.getAnd(id, (s: JsonChannel) => { - if (!s) return; // deleted - var n = s.positivereviews; - ctnSpan.innerText = n + ""; - }) - } - ScriptInfo.setupLike(id, setLikeBtn); - return lbtn; - } - public mkTile(sz: number): HTMLElement { var d = div("hubTile hubTileSize" + sz); d.style.background = "#1731B8"; @@ -9150,12 +7818,6 @@ module TDev.Browser { var cont = []; var addNum = (n: number, sym: string, title: string) => { cont.push(ScriptInfo.mkNum(n, sym, title)) } - addNum(this.json.positivereviews, "♥", lf("favourites")); - if (sz > 1) { - if (EditorSettings.widgets().publicationComments) - addNum(this.json.comments, "✉", lf("comments")); - } - var nums = div("hubTileNumbers", cont, div("hubTileNumbersOverlay")); //nums.style.background = this.app.htmlColor(); diff --git a/editor/sideScriptNav.ts b/editor/sideScriptNav.ts index d4ba5799b..1aae49afd 100644 --- a/editor/sideScriptNav.ts +++ b/editor/sideScriptNav.ts @@ -204,17 +204,6 @@ module TDev this.editor.typeCheckNow(); this.editor.searchFor(":m"); })); - - if (onlyParent && this.editor.widgetEnabled("deployButton")) { - addBtn(HTML.mkRoundButton("svg:cloudupload,currentColor", lf("export"), Ticks.sideDeployWebSite, () => { - AppExport.exportBtn(app) - })); - } - - if (!isParent && TheEditor.widgetEnabled("pluginsButton")) - addBtn(HTML.mkRoundButton("svg:plug,currentColor", lf("plugins"), Ticks.sidePlugins, () => { - Plugins.runPlugin(); - })); if (!isParent && app.hasTests() && TheEditor.widgetEnabled("runTestsButton")) addBtn(HTML.mkRoundButton("svg:experiment,currentColor", lf("run tests"), Ticks.sideAllTests, () => { TestMgr.testCurrentScript() @@ -339,6 +328,7 @@ module TDev } var prog = Script; + /* var progDiv = declIt(prog); if (ScriptEditorWorldInfo.status === "published") { @@ -348,10 +338,9 @@ module TDev items[items.length - 1] = progDiv; } else if(!debugMode) { var pubbtn = HTML.mkRoundButton("svg:Upload,currentColor", lf("publish"), Ticks.sidePublish, () => { ScriptNav.publishScript() }); - TheEditor.keyMgr.btnShortcut(pubbtn, "Ctrl-S") progDiv = ScriptNav.addSideButton(progDiv, pubbtn); items[items.length - 1] = progDiv; - } + } */ if (!debugMode) items.push(this.scriptButtons(Script, false, !!TheEditor.parentScript)); diff --git a/editor/tutorial.ts b/editor/tutorial.ts index d6e1c4a8a..46f3f1fc3 100644 --- a/editor/tutorial.ts +++ b/editor/tutorial.ts @@ -977,54 +977,6 @@ module TDev private nowPublish() { 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; - - World.getInstalledHeaderAsync(Script.localGuid).done((h: Cloud.Header) => { - if (h.status == "published") return Promise.as(); - - var screenshotDataUri = TheEditor.lastScreenshotUri(); - var start = Util.now() - var m = new ModalDialog(); - this.disableUpdate = true; - - m.add(div('wall-dialog-header', lf("you did it!"))); - m.addHTML(lf("Publish your script, so that everyone can run it.")) - m.add(div('wall-dialog-buttons', - HTML.mkButton(lf("publish"), () => { - this.disableUpdate = false; - ScriptNav.publishScript(dbg ? false : true, uploadScreenshot ? screenshotDataUri : undefined) - this.update() - }), - HTML.mkButton(lf("maybe later"), () => { - this.disableUpdate = false; - m.dismiss(); - }) - )); - - var uploadScreenshot = true; - var uploadScreenshotCheck = HTML.mkCheckBox(lf("upload screenshot"), b => uploadScreenshot = b, uploadScreenshot); - if (screenshotDataUri) { - var previewImage = HTML.mkImg(screenshotDataUri); - previewImage.setAttribute('class', 'publishScreenshot'); - m.add(previewImage); - m.add(div('wall-dialog-body', uploadScreenshotCheck)); - m.setScroll(); - } - - m.fullWhite(); - - var d = Cloud.mkLegalDiv() - d.style.marginTop = "1em"; - d.style.opacity = "0.6"; - m.add(d); - m.show(); - }); } private addHocFinishPixel(m : ModalDialog) { diff --git a/lib/WebRequest.ts b/lib/WebRequest.ts index 78aa0a2be..0eb7fd392 100644 --- a/lib/WebRequest.ts +++ b/lib/WebRequest.ts @@ -157,8 +157,6 @@ module TDev.RT { return this.mkProxyCrash(proxyResponse); case 403: Cloud.accessTokenExpired(); - if (this._showNotifications) - HTML.showProxyNotification("Proxy Error: Could not perform web request; access denied; your access token might have expired.", this._url); return this.mkProxyCrash(proxyResponse); case 504: if (this._showNotifications) diff --git a/libnode/runtime.ts b/libnode/runtime.ts index 69378e70c..56514a7f4 100644 --- a/libnode/runtime.ts +++ b/libnode/runtime.ts @@ -727,7 +727,7 @@ module TDev.RT.Node { } Cloud.authenticateAsync = (activity:string, redirect = false, dontRedirect = false): Promise => { - return Promise.as(!!Cloud.getUserId()) + return Promise.as(false) } try { // TODO: find a better way to detect if this module is available var xmldom = require('xmldom'); diff --git a/package-lock.json b/package-lock.json index c1008a52e..3271b0312 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,12 @@ "integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=", "optional": true }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, "boom": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", @@ -60,6 +66,16 @@ "hoek": "0.9.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, "bufferjs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/bufferjs/-/bufferjs-3.0.1.tgz", @@ -113,6 +129,12 @@ "delayed-stream": "0.0.5" } }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, "configstore": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.1.7.tgz", @@ -198,6 +220,24 @@ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" }, + "filelist": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-0.0.6.tgz", + "integrity": "sha1-WKZBrR9XV0on/oekQO8xiDS1Vxk=", + "dev": true, + "requires": { + "minimatch": "3.0.4", + "utilities": "0.0.37" + }, + "dependencies": { + "utilities": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/utilities/-/utilities-0.0.37.tgz", + "integrity": "sha1-o0cNCn9ogULZ6KV87hEo8S4Z4ZY=", + "dev": true + } + } + }, "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -260,13 +300,16 @@ } }, "jake": { - "version": "0.7.20", - "resolved": "https://registry.npmjs.org/jake/-/jake-0.7.20.tgz", - "integrity": "sha1-c9L6Ny2bR18Rq+qm5/8w2VDBhrI=", + "version": "8.0.15", + "resolved": "https://registry.npmjs.org/jake/-/jake-8.0.15.tgz", + "integrity": "sha1-8Np9WOeQrBqPhubuDxk+XZIw6rs=", "dev": true, "requires": { - "minimatch": "0.2.14", - "utilities": "0.0.40" + "async": "0.9.2", + "chalk": "0.4.0", + "filelist": "0.0.6", + "minimatch": "3.0.4", + "utilities": "1.0.5" } }, "js-yaml": { @@ -306,12 +349,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", @@ -337,13 +374,12 @@ } }, "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -467,12 +503,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz", "integrity": "sha1-eUEYKz/8xYC/8cF5QqzfeVHA0hM=" }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "sntp": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", @@ -662,9 +692,9 @@ "integrity": "sha1-Tqq9HVw6yQ1iq0SFyZhCKGWgSxo=" }, "utilities": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/utilities/-/utilities-0.0.40.tgz", - "integrity": "sha1-MWhysoJFXV4oawKlz5HTH2UCemw=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utilities/-/utilities-1.0.5.tgz", + "integrity": "sha1-8rd6iPNRBzP8chW1xIalBKdaskU=", "dev": true }, "uuid": { diff --git a/rt/cloud.ts b/rt/cloud.ts index 0b8b7fc16..b4c6720b9 100644 --- a/rt/cloud.ts +++ b/rt/cloud.ts @@ -195,6 +195,7 @@ module TDev.Cloud { liteVersion: string; shareUrl: string; cdnUrl: string; + newCdnUrl?: string; translateCdnUrl: string; translateApiUrl: string; hashtag: string; @@ -301,7 +302,7 @@ module TDev.Cloud { if (!thumbContainer) thumbContainer = "pub" var tmp = stripCdnUrl(url) - if (tmp) return config.primaryCdnUrl + "/" + thumbContainer + "/" + tmp + if (tmp) return config.newCdnUrl + "/" + thumbContainer + "/" + tmp else return url } @@ -317,7 +318,7 @@ module TDev.Cloud { } export function artUrl(id: string, thumb = false): string { - return id ? HTML.proxyResource(Util.fmt("{0}/{1}/{2:uri}", Cloud.config.primaryCdnUrl, thumb ? "thumb" : "pub", id)) : undefined; + return id ? HTML.proxyResource(Util.fmt("{0}/{1}/{2:uri}", Cloud.config.newCdnUrl, thumb ? "thumb" : "pub", id)) : undefined; } export function setPermissions(perms:string = null) @@ -343,7 +344,9 @@ module TDev.Cloud { return !fullTD; } - export function getServiceUrl() { return config.rootUrl; } + export function getServiceUrl() { + return config.rootUrl; + } export function mkLegalDiv() { var link = (text: string, lnk: string) => @@ -356,79 +359,22 @@ module TDev.Cloud { export var authenticateAsync = (activity:string, redirect = false, dontRedirect = false, sensitive = false): Promise => { // boolean - - if (!sensitive && !Cloud.isAccessTokenExpired()) return Promise.as(true); - - function loginAsync() { - var loginUrl = Cloud.getServiceUrl() + "/oauth/dialog?response_type=token&" - + "client_id=webapp" - + "&identity_provider=" + encodeURIComponent(Cloud.getIdentityProvider() || ""); - return TDev.RT.Web.oauth_v2_async(loginUrl, "touchdevelop") - .then((or: TDev.RT.OAuthResponse) => { - if (or.is_error()) return false; - else { - var id = or.others().at('id'); - var oldid = Cloud.getUserId(); - if (oldid && id != oldid) { - // TODO: error message. - return false; - } - Cloud.setUserId(or.others().at('id')); - Cloud.setAccessToken(encodeURIComponent(or.access_token())); - Cloud.setIdentityProvider(or.others().at('identity_provider')); - return true; - } - }); - } - - return Cloud.isOnlineWithPingAsync() - .then((isOnline : boolean) => { - if (!isOnline) return Promise.as(false); - - var prevHash = (window.location.hash || "#").replace(/#/, ""); - var login = (TDev).Login; - if (login) { - if (!login.show || dontRedirect) - login = null; - if (!redirect && (!prevHash || /^(hub|list:.*:user:me:)/.test(prevHash))) - login = null; - } - - var r = new PromiseInv(); - - var m = new ModalDialog(); - if (sensitive) - m.addHTML( - lf("

we need you to sign in again

") + - "

" + - lf("Accessing private data requires verification of your sign in credentials.") + - "

" - ) - else - m.addHTML( - lf("

{0:q} requires sign in

", activity) + - (!(TDev).TheEditor ? "" : - "

" + - lf("You can run and save your scripts locally, but to access your scripts from all devices, you need to be signed in. After you sign in, we will save and sync your scripts between your devices.") + - "

") - ) - m.fullWhite(); - var ignoreDismiss = false; - m.add(div("wall-dialog-buttons", - HTML.mkButton(lf("maybe later"), () => { m.dismiss() }), - HTML.mkButton(lf("sign in"), () => { - ignoreDismiss = true; - m.dismiss() - if (login) login.show(); - else loginAsync().done(v => r.success(v)) - }))); - m.onDismiss = () => { - if (!ignoreDismiss) r.success(false); - }; - m.show(); - - return r; - }) + var r = new PromiseInv(); + var m = new ModalDialog(); + m.addHTML( + lf("

{0:q} is not supported anymore 

", activity) + + "

" + + lf("You can run and save your scripts locally, but cloud synchronization and publishing is not supported anymore.") + + "

" + ); + m.fullWhite(); + m.add(div("wall-dialog-buttons", + HTML.mkButton(lf("ok"), () => { m.dismiss() }) + )); + m.onDismiss = () => r.success(false); + m.show(); + + return r; } export function anonMode(activity:string, restart:()=>void = null, redirect = false) @@ -923,17 +869,6 @@ module TDev.Cloud { return e => handlePostingError(e, action) } - export function showSigninNotification(isOnline: boolean) { - if (isOnline) HTML.showWarningNotification(lf("You are not signed in."), { - els: [HTML.mkLinkButton(lf("sign in"), () => { - var login = (TDev).Login; - if (login && login.show) - login.show() - })] - }); - else HTML.showProgressNotification(lf("You appear to be offline.")); - } - export function handlePostingError(e: any, action: string, modal = true) { if (e) { if (e.status == 502) { @@ -950,11 +885,7 @@ module TDev.Cloud { else if (e.status == 403) { Cloud.accessTokenExpired(); // in lite, 403 always means missing or expired access token - if (localStorage['everLoggedIn']) - Cloud.isOnlineWithPingAsync() - .done(isOnline => Cloud.showSigninNotification(isOnline)); - else - authenticateAsync(action).done() + // in readonly, 403 means user has no access return; } else if (e.status == 419 || e.status == 402) { diff --git a/rt/storage.ts b/rt/storage.ts index 562bce22f..0cbfc7aff 100644 --- a/rt/storage.ts +++ b/rt/storage.ts @@ -28,17 +28,6 @@ module TDev { // this mode should only be allowed if no database was ever opened in this browser export var temporary = false; var temporaryRequestedSignin = false; - export function showTemporaryWarning() { - if (temporary) { - if (Cloud.isAccessTokenExpired()) - HTML.showWarningNotification(lf("Web site data not available, sign in to back up your scripts!"), { details: lf("Your browser does not allow Touch Develop to store data. This usually happens if run in Private Mode (Safari), in InPrivate mode (Internet Explorer) or your security settings prevent data storage. Sign in or change your browser settings to avoid loosing your work. All the changes not saved to the cloud will be lost when leaving this page.") }); - else if (Cloud.isOffline()) - HTML.showWarningNotification(lf("Web site data not available, connect to internet to back up your scripts!"), { details: lf("Your browser does not allow Touch Develop to store data. This usually happens if run in Private Mode (Safari), in InPrivate mode (Internet Explorer) or your security settings prevent data storage. Sign in or change your browser settings to avoid loosing your work. All the changes not saved to the cloud will be lost when leaving this page.") }); - return true; - } else { - return false; - } - } // uses an in-memory object or localstorage var memoryStorage: StringMap = {}; diff --git a/rt/util.ts b/rt/util.ts index 1e6580b8a..b2d541b0b 100644 --- a/rt/util.ts +++ b/rt/util.ts @@ -2809,7 +2809,7 @@ module TDev{ } } - if (willReload && !Storage.showTemporaryWarning()) { + if (willReload) { try { ProgressOverlay.show(lf("Whoops! Something went wrong.")) ProgressOverlay.setProgress("") diff --git a/runner/main.ts b/runner/main.ts index 400e9568e..ba242645c 100644 --- a/runner/main.ts +++ b/runner/main.ts @@ -117,17 +117,13 @@ module TDev { if (TDev.Browser.webAppImplicit) { // do not ask the authenticate var auth = TDev.Cloud.authenticateAsync; - TDev.Cloud.authenticateAsync = (reason: string) => { - if (reason == "leaderboard") - return Promise.as(!Cloud.isAccessTokenExpired()); - return auth(reason); - } + TDev.Cloud.authenticateAsync = (reason: string) => Promise.as(false); } } function initCompiledApp() { TDev.RuntimeSettings.askSourceAccess = false; - TDev.Cloud.authenticateAsync = (reason:string) => Promise.as(true); + TDev.Cloud.authenticateAsync = (reason:string) => Promise.as(false); TDev.RT.ArtCache.enabled = false; // disable art caching TDev.RT.ApiManager.getKeyAsync = (url: string): Promise => Promise.as(TDev.RT.ApiManager.keys[url] || undefined); TDev.RT.BingServices.searchAsync = function ( diff --git a/storage/world.ts b/storage/world.ts index 77c11ce8c..2b46137ac 100644 --- a/storage/world.ts +++ b/storage/world.ts @@ -744,6 +744,7 @@ module TDev { else if (status == 403) //(Cloud.isOnline() && /localhost/.test(document.URL)) // because of CORS on localhost when not logged in yet { + /* var message = status == 403 ? Cloud.hasAccessToken() ? onNotLoggedIn @@ -752,12 +753,10 @@ module TDev { : lf("cannot sync - you are not signed in") + info : lf("cannot sync") + info; HTML.showProgressNotification(message) + */ if (status == 403) { - if (!onNotLoggedIn) - Cloud.handlePostingError(e, lf("sync")) - else - Cloud.accessTokenExpired(); + Cloud.accessTokenExpired(); } if (onNotLoggedIn) onNotLoggedIn(); World.cancelContinuouslySync(); // stop continuously script @@ -812,7 +811,6 @@ module TDev { else if (status == 403 || (!Cloud.lite && Cloud.isOnline() && /localhost/.test(document.URL))) // because of CORS on localhost when not logged in yet { - HTML.showSaveNotification(lf("could not save - you are not signed in ({0:500})",status)); if (status == 403) Cloud.accessTokenExpired(); if (onNotLoggedIn) onNotLoggedIn(); diff --git a/tools/client.ts b/tools/client.ts index 900d48eb3..6ef8d456f 100644 --- a/tools/client.ts +++ b/tools/client.ts @@ -4113,10 +4113,8 @@ var sectTemplates = 'templates'; var sectBeginners = lf("beginners"); var sectCordova = lf("apps"); var sectAzure = lf("web apps"); -var sectMakers = lf("makers"); var sectTouchDevelop = lf("touch develop"); var sectOthers = lf("others"); -var sectMinecraft = "Minecraft"; /* editorMode: 1 = block, 2 = coder, 3 = expert @@ -4158,87 +4156,6 @@ var templates: ScriptTemplate[] = [{ section: sectBeginners, scriptid: 'oobxb', editorMode: 1, -}, { - title: lf("blank scratch"), - id: 'blankscratch', - icon: 'Controller', - name: 'ADJ app', - description: lf("An empty app using the scratch library."), - section: sectBeginners, - scriptid: 'rbhea', - editorMode: 1, -}, { - title: lf("blank pixel art"), - id: 'blankpixelart', - icon: 'NineColumn', - name: 'ADJ art', - description: lf("A pixel art app."), - section: sectBeginners, - scriptid: 'mdrw', - editorMode: 1, -}, { - title: lf("blank minecraft"), - id: 'blankminecraft', - icon: 'NineColumn', - name: 'ADJ craft', - description: lf("A Minecraft app."), - section: sectMinecraft, - scriptid: 'mbepa', - editorMode: 2, -}, { - title: lf("blank creeper"), - id: 'blankcreeper', - icon: 'NineColumn', - name: 'ADJ creeper', - description: lf("A Minecraft creeper app."), - section: sectMinecraft, - scriptid: 'ehtt', - editorMode: 2, -},{ - title: lf("blank minecraft pi"), - id: 'blankminecraftpi', - icon: 'NineColumn', - name: 'ADJ craft', - description: lf("A Minecraft Pi app."), - section: sectMinecraft, - scriptid: 'uggce', - editorMode: 2, -}, { - title: lf("blank docs"), - id: 'blankdocs', - icon: 'Controller', - name: 'ADJ docs', - description: lf("An empty documentation page."), - section: sectTouchDevelop, - scriptid: 'krvn', - editorMode: 3, -}, { - title: lf("blank tutorial"), - id: 'blanktutorial', - icon: 'Controller', - name: 'ADJ tutorial', - description: lf("An empty interactive tutorial."), - section: sectTouchDevelop, - scriptid: 'yujva', - editorMode: 3, -}, { - title: lf("blank script plugin"), - id: 'blankscriptplugin', - icon: 'Brush', - name: 'ADJ plugin', - description: lf("An empty script editor plugin."), - section: sectTouchDevelop, - scriptid: 'tiwt', - editorMode: 3, -}, { - title: lf("physics game starter"), - id: 'physicsgamestarter', - icon: 'Controller', - name: 'ADJ game', - description: lf("Boiler plate code to create a game."), - section: sectOthers, - scriptid: 'kkwd', - editorMode: 2, }]; export function main()