From 8362eac883a067e04633190ff98d060d7b627ca2 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Thu, 31 Jul 2014 11:34:37 +0200 Subject: merge Snap!Cloud and GitHub; fix some bugs --- gui.js | 721 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 705 insertions(+), 16 deletions(-) (limited to 'gui.js') diff --git a/gui.js b/gui.js index a4e1dd5..cbc3353 100644 --- a/gui.js +++ b/gui.js @@ -63,13 +63,13 @@ Costume, CostumeEditorMorph, MorphicPreferences, touchScreenSettings, standardSettings, Sound, BlockMorph, ToggleMorph, InputSlotDialogMorph, ScriptsMorph, isNil, SymbolMorph, BlockExportDialogMorph, BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph, -SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, +SnapCloud, GitHub, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio, SpeechBubbleMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2014-July-30'; +modules.gui = '2014-July-31'; // Declarations @@ -240,6 +240,7 @@ IDE_Morph.prototype.openIn = function (world) { // get persistent user data, if any if (localStorage) { usr = localStorage['-snap-user']; + ghusr = localStorage['-snap-ghuser']; if (usr) { usr = SnapCloud.parseResponse(usr)[0]; if (usr) { @@ -247,6 +248,13 @@ IDE_Morph.prototype.openIn = function (world) { function() {}, myself.cloudError()); } } + if (ghusr) { + ghusr = SnapCloud.parseResponse(ghusr)[0]; + if (ghusr) { + GitHub.login(ghusr.username, ghusr.password, false, + function() {}, myself.githubError()); + } + } } // override SnapCloud's user message with Morphic @@ -338,11 +346,12 @@ IDE_Morph.prototype.openIn = function (world) { this.parent.add(this.shield); myself.showMessage('Fetching project\nfrom the cloud...'); + // make sure to lowercase the username dict = SnapCloud.parseDict(location.hash.substr(9)); - dict.Username = dict.Username; + dict.Username = dict.Username.toLowerCase(); SnapCloud.getPublicProject( - dict, + SnapCloud.encodeDict(dict), function (projectData) { var msg; myself.nextSteps([ @@ -370,10 +379,51 @@ IDE_Morph.prototype.openIn = function (world) { }, this.cloudError() ); + } else if (location.hash.substr(0, 8) === '#github:') { + this.shield = new Morph(); + this.shield.color = this.color; + this.shield.setExtent(this.parent.extent()); + this.parent.add(this.shield); + myself.showMessage('Fetching project\nfrom GitHub...'); + + dict = SnapCloud.parseDict(location.hash.substr(8)); + + GitHub.getProject( + dict.Username, + dict.projectName, + function (projectData) { + var msg; + myself.nextSteps([ + function () { + msg = myself.showMessage('Opening GitHub project...'); + }, + function () { + if (projectData.indexOf(' 50) { + response = response.substring(0, 50) + '...'; + } + new DialogBoxMorph().inform( + 'GitHub', + (url ? url + '\n' : '') + + response, + myself.world(), + myself.cloudIcon(null, new Color(180, 0, 0)) + ); + }; +}; + IDE_Morph.prototype.cloudIcon = function (height, color) { var clr = color || DialogBoxMorph.prototype.titleBarColor, isFlat = MorphicPreferences.isFlat, @@ -3827,6 +4182,31 @@ IDE_Morph.prototype.cloudIcon = function (height, color) { return icon; }; +IDE_Morph.prototype.setCloudURL = function () { + new DialogBoxMorph( + null, + function (url) { + SnapCloud.url = url; + } + ).withKey('cloudURL').prompt( + 'Cloud URL', + SnapCloud.url, + this.world(), + null, + { + 'Snap!Cloud' : + 'https://snapcloud.miosoft.com/miocon/app/' + + 'login?_app=SnapCloud', + 'local network lab' : + '192.168.2.107:8087/miocon/app/login?_app=SnapCloud', + 'local network office' : + '192.168.186.146:8087/miocon/app/login?_app=SnapCloud', + 'localhost dev' : + 'localhost/miocon/app/login?_app=SnapCloud' + } + ); +}; + // IDE_Morph synchronous Http data fetching IDE_Morph.prototype.getURL = function (url) { @@ -3923,7 +4303,7 @@ ProjectDialogMorph.prototype.init = function (ide, task) { // additional properties: this.ide = ide; this.task = task || 'open'; // String describing what do do (open, save) - this.source = ide.source || 'local'; // or 'cloud' or 'examples' + this.source = ide.source || 'local'; // 'or 'cloud' or 'github' or 'examples' this.projectList = []; // [{name: , thumb: , notes:}] this.handle = null; @@ -3934,6 +4314,8 @@ ProjectDialogMorph.prototype.init = function (ide, task) { this.notesText = null; this.notesField = null; this.deleteButton = null; + this.shareButton = null; + this.unshareButton = null; // initialize inherited properties: ProjectDialogMorph.uber.init.call( @@ -3981,6 +4363,7 @@ ProjectDialogMorph.prototype.buildContents = function () { } this.addSourceButton('cloud', localize('Cloud'), 'cloud'); + this.addSourceButton('github', localize('GitHub'), 'github'); this.addSourceButton('local', localize('Browser'), 'storage'); if (this.task === 'open') { this.addSourceButton('examples', localize('Examples'), 'poster'); @@ -4073,6 +4456,10 @@ ProjectDialogMorph.prototype.buildContents = function () { this.addButton('saveProject', 'Save'); this.action = 'saveProject'; } + this.shareButton = this.addButton('shareProject', 'Share'); + this.unshareButton = this.addButton('unshareProject', 'Unshare'); + this.shareButton.hide(); + this.unshareButton.hide(); this.deleteButton = this.addButton('deleteProject', 'Delete'); this.addButton('cancel', 'Cancel'); @@ -4225,6 +4612,20 @@ ProjectDialogMorph.prototype.setSource = function (source) { } ); return; + case 'github': + msg = myself.ide.showMessage('Updating\nproject list...'); + this.projectList = []; + GitHub.getProjectList( + function (projectList) { + myself.installGitHubProjectList(projectList); + msg.destroy(); + }, + function (err, lbl) { + msg.destroy(); + myself.ide.githubError().call(null, err, lbl); + } + ); + return; case 'examples': this.projectList = this.getExamplesProjectList(); break; @@ -4277,7 +4678,7 @@ ProjectDialogMorph.prototype.setSource = function (source) { } myself.edit(); }; - } else { // 'examples', 'cloud' is initialized elsewhere + } else { // 'examples', 'cloud' and 'github' is initialized elsewhere this.listField.action = function (item) { var src, xml; if (item === undefined) {return; } @@ -4302,6 +4703,8 @@ ProjectDialogMorph.prototype.setSource = function (source) { }; } this.body.add(this.listField); + this.shareButton.hide(); + this.unshareButton.hide(); if (this.source === 'local') { this.deleteButton.show(); } else { // examples @@ -4371,6 +4774,83 @@ ProjectDialogMorph.prototype.installCloudProjectList = function (pl) { return x.ProjectName < y.ProjectName ? -1 : 1; }); + this.listField.destroy(); + this.listField = new ListMorph( + this.projectList, + this.projectList.length > 0 ? + function (element) { + return element.ProjectName; + } : null, + [ // format: display shared project names bold + [ + 'bold', + function (proj) {return proj.Public === 'true'; } + ] + ], + function () {myself.ok(); } + ); + this.fixListFieldItemColors(); + this.listField.fixLayout = nop; + this.listField.edge = InputFieldMorph.prototype.edge; + this.listField.fontSize = InputFieldMorph.prototype.fontSize; + this.listField.typeInPadding = InputFieldMorph.prototype.typeInPadding; + this.listField.contrast = InputFieldMorph.prototype.contrast; + this.listField.drawNew = InputFieldMorph.prototype.drawNew; + this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; + + this.listField.action = function (item) { + if (item === undefined) {return; } + if (myself.nameField) { + myself.nameField.setContents(item.ProjectName || ''); + } + if (myself.task === 'open') { + myself.notesText.text = item.Notes || ''; + myself.notesText.drawNew(); + myself.notesField.contents.adjustBounds(); + myself.preview.texture = item.Thumbnail || null; + myself.preview.cachedTexture = null; + myself.preview.drawNew(); + (new SpeechBubbleMorph(new TextMorph( + localize('last changed') + '\n' + item.Updated, + null, + null, + null, + null, + 'center' + ))).popUp( + myself.world(), + myself.preview.rightCenter().add(new Point(2, 0)) + ); + } + if (item.Public === 'true') { + myself.shareButton.hide(); + myself.unshareButton.show(); + } else { + myself.unshareButton.hide(); + myself.shareButton.show(); + } + myself.buttons.fixLayout(); + myself.fixLayout(); + myself.edit(); + }; + this.body.add(this.listField); + this.shareButton.show(); + this.unshareButton.hide(); + this.deleteButton.show(); + this.buttons.fixLayout(); + this.fixLayout(); + if (this.task === 'open') { + this.clearDetails(); + } +}; + +ProjectDialogMorph.prototype.installGitHubProjectList = function (pl) { + var myself = this; + this.projectList = pl || []; + this.projectList.sort(function (x, y) { + return x.ProjectName < y.ProjectName ? -1 : 1; + }); + this.listField.destroy(); this.listField = new ListMorph( this.projectList, @@ -4443,6 +4923,8 @@ ProjectDialogMorph.prototype.openProject = function () { this.ide.source = this.source; if (this.source === 'cloud') { this.openCloudProject(proj); + } else if (this.source === 'github') { + this.openGitHubProject(proj); } else if (this.source === 'examples') { src = this.ide.getURL( 'http://snap.berkeley.edu/snapsource/Examples/' + @@ -4468,20 +4950,58 @@ ProjectDialogMorph.prototype.openCloudProject = function (project) { ]); }; +ProjectDialogMorph.prototype.openGitHubProject = function (project) { + var myself = this; + myself.ide.nextSteps([ + function () { + myself.ide.showMessage('Fetching project\nfrom GitHub...'); + }, + function () { + myself.rawOpenGitHubProject(project); + } + ]); +}; + ProjectDialogMorph.prototype.rawOpenCloudProject = function (proj) { var myself = this; - SnapCloud.getProject( - {'projectname': proj.ProjectName, 'username': SnapCloud.username}, + SnapCloud.reconnect( + function () { + SnapCloud.callService( + 'getProject', + function (response) { + SnapCloud.disconnect(); + myself.ide.source = 'cloud'; + myself.ide.droppedText(response[0].SourceCode); + if (proj.Public === 'true') { + location.hash = '#present:Username=' + + encodeURIComponent(SnapCloud.username) + + '&ProjectName=' + + encodeURIComponent(proj.ProjectName); + } + }, + myself.ide.cloudError(), + [proj.ProjectName] + ); + }, + myself.ide.cloudError() + ); + this.destroy(); +}; + +ProjectDialogMorph.prototype.rawOpenGitHubProject = function (proj) { + var myself = this; + GitHub.getProject( + GitHub.username, + proj.ProjectName, function (code, media) { - myself.ide.source = 'cloud'; + myself.ide.source = 'github'; myself.ide.droppedText(media); myself.ide.droppedText(code); }, - myself.ide.cloudError() + myself.ide.githubError() ); this.destroy(); }; - ProjectDialogMorph.prototype.saveProject = function () { var name = this.nameField.contents().text.text, notes = this.notesText.text, @@ -4508,6 +5028,25 @@ ProjectDialogMorph.prototype.saveProject = function () { this.ide.setProjectName(name); myself.saveCloudProject(); } + } else if (this.source === 'github') { + if (detect( + this.projectList, + function (item) {return item.ProjectName === name; } + )) { + this.ide.confirm( + localize( + 'Are you sure you want to replace' + ) + '\n"' + name + '"?', + 'Replace Project', + function () { + myself.ide.setProjectName(name); + myself.saveGitHubProject(); + } + ); + } else { + this.ide.setProjectName(name); + myself.saveGitHubProject(); + } } else { // 'local' if (detect( this.projectList, @@ -4549,6 +5088,156 @@ ProjectDialogMorph.prototype.saveCloudProject = function () { this.destroy(); }; +ProjectDialogMorph.prototype.saveGitHubProject = function () { + var myself = this; + this.ide.showMessage('Committing project\nto GitHub...'); + GitHub.saveProject( + this.ide, + function () { + myself.ide.source = 'github'; + myself.ide.showMessage('saved.', 2); + }, + this.ide.githubError() + ); + this.destroy(); +}; + +ProjectDialogMorph.prototype.deleteProject = function () { + var myself = this, + proj, + idx, + name; + + if (this.source === 'github') { + // TODO: not implemented + } else if (this.source === 'cloud') { + proj = this.listField.selected; + if (proj) { + this.ide.confirm( + localize( 'Are you sure you want to delete' + ) + '\n"' + proj.ProjectName + '"?', + 'Delete Project', + function () { + SnapCloud.reconnect( + function () { + SnapCloud.callService( + 'deleteProject', + function () { + SnapCloud.disconnect(); + myself.ide.hasChangedMedia = true; + idx = myself.projectList.indexOf(proj); + myself.projectList.splice(idx, 1); + myself.installCloudProjectList( + myself.projectList + ); // refresh list + }, + myself.ide.cloudError(), + [proj.ProjectName] + ); + }, + myself.ide.cloudError() + ); + } + ); + } + } else { // 'local, examples' + if (this.listField.selected) { + name = this.listField.selected.name; + this.ide.confirm( + localize( + 'Are you sure you want to delete' + ) + '\n"' + name + '"?', + 'Delete Project', + function () { + delete localStorage['-snap-project-' + name]; + myself.setSource(myself.source); // refresh list + } + ); + } + } +}; + +ProjectDialogMorph.prototype.shareProject = function () { + var myself = this, + proj = this.listField.selected, + entry = this.listField.active; + + if (proj) { + this.ide.confirm( + localize( + 'Are you sure you want to publish' + ) + '\n"' + proj.ProjectName + '"?', + 'Share Project', + function () { + myself.ide.showMessage('sharing\nproject...'); + SnapCloud.reconnect( + function () { + SnapCloud.callService( + 'publishProject', + function () { + SnapCloud.disconnect(); + proj.Public = 'true'; + myself.unshareButton.show(); + myself.shareButton.hide(); + entry.label.isBold = true; + entry.label.drawNew(); + entry.label.changed(); + myself.buttons.fixLayout(); + myself.drawNew(); + myself.ide.showMessage('shared.', 2); + }, + myself.ide.cloudError(), + [proj.ProjectName] + ); + }, + myself.ide.cloudError() + ); + } + ); + } +}; + +ProjectDialogMorph.prototype.unshareProject = function () { + var myself = this, + proj = this.listField.selected, + entry = this.listField.active; + + + if (proj) { + this.ide.confirm( + localize( + 'Are you sure you want to unpublish' + ) + '\n"' + proj.ProjectName + '"?', + 'Unshare Project', + function () { + myself.ide.showMessage('unsharing\nproject...'); + SnapCloud.reconnect( + function () { + SnapCloud.callService( + 'unpublishProject', + function () { + SnapCloud.disconnect(); + proj.Public = 'false'; + myself.shareButton.show(); + myself.unshareButton.hide(); + entry.label.isBold = false; + entry.label.drawNew(); + entry.label.changed(); + myself.buttons.fixLayout(); + myself.drawNew(); + myself.ide.showMessage('unshared.', 2); + }, + myself.ide.cloudError(), + [proj.ProjectName] + ); + }, + myself.ide.cloudError() + ); + } + ); + } +}; + ProjectDialogMorph.prototype.edit = function () { if (this.nameField) { this.nameField.edit(); -- cgit v1.3.1