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 --- github.js | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 github.js (limited to 'github.js') diff --git a/github.js b/github.js new file mode 100644 index 0000000..a3b3223 --- /dev/null +++ b/github.js @@ -0,0 +1,273 @@ +/* + + github.js + + a GitHubBackend backend API for SNAP! + + written by Gubolin, based on cloud.js by Jens Mönig + + Copyright (C) 2014 by Jens Mönig, Gubolin + + This file is part of Snap!. + + Snap! is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +*/ + +// Global settings ///////////////////////////////////////////////////// + +/*global modules, IDE_Morph, SnapSerializer, nop, +localize*/ + +modules.github = '2014-July-31'; + +// Global stuff + +var GitHubBackend; + +var GitHub = new GitHubBackend(); + +// GitHubBackend ///////////////////////////////////////////////////////////// + +function GitHubBackend(url) { + this.gh = null; + this.username = null; + this.password = null; // TODO saved as plain text +} + +GitHubBackend.prototype.clear = function () { + this.gh = null; + this.username = null; + this.password = null; +}; + +// GitHubBackend: Snap! API + +GitHubBackend.prototype.getProject = function ( + userName, + projectName, + callBack, + errorCall +) { + var myself = this; + + if (myself.gh === null) { + myself.gh = new Octokit(); + } + + var repo = myself.gh.getRepo(userName, projectName); + var branch = repo.getBranch(); // master (default) + var media, pdata; + + branch.read('snap.xml', false).then( + function (sourceContent) { + branch.read('media.xml', false).then( // true for binary + function (mediaContent) { + callBack.call( + null, + sourceContent.content, + mediaContent.content + ); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); +}; + +GitHubBackend.prototype.login = function ( + username, + password, + validateData, + callBack, + errorCall +) { + var myself = this; + var me; + + myself.gh = new Octokit({ + username: username, + password: password + }); + + if (validateData === true) { + me = myself.gh.getUser(); + if (me !== null) { + me.getInfo().then( + function(info) { + myself.username = username; + myself.password = password; + + callBack.call(myself); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } else { + errorCall.call(myself, localize('Something went wrong :('), 'GitHub'); + } + } else { + myself.username = username; + myself.password = password; + + callBack.call(myself); + } +}; + +GitHubBackend.prototype.saveProject = function (ide, callBack, errorCall) { + var myself = this, + pdata, + media; + var repoName = ide.projectName.replace(/[^\w-]/g, ''); // TODO validation of project name + + ide.serializer.isCollectingMedia = true; + pdata = ide.serializer.serialize(ide.stage); + media = ide.hasChangedMedia ? + ide.serializer.mediaXML(ide.projectName) : null; + ide.serializer.isCollectingMedia = false; + ide.serializer.flushMedia(); + + // check if serialized data can be parsed back again + try { + ide.serializer.parse(pdata); + } catch (err) { + ide.showMessage('Serialization of program data failed:\n' + err); + throw new Error('Serialization of program data failed:\n' + err); + } + if (media !== null) { + try { + ide.serializer.parse(media); + } catch (err) { + ide.showMessage('Serialization of media failed:\n' + err); + throw new Error('Serialization of media failed:\n' + err); + } + } + ide.serializer.isCollectingMedia = false; + ide.serializer.flushMedia(); + + myself.getProjectList( + function (projects) { + var exists = false; + + projects.forEach(function (project) { + if (project.ProjectName.indexOf(repoName) > -1) { + exists = true; + return; + } + }); + + if (exists === false){ + myself.gh.getUser().createRepo(repoName, { // these should be discussed + 'description': 'Snap! Project - http://snap.berkeley.edu/snapsource/snap.html#github:Username=' + myself.username + '&projectName=' + repoName, + 'has_wiki': 'false', + 'has_downloads': 'false', + 'auto_init': true, + 'license_template': 'mit' // discuss + }).then( + function () {}, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } + + if (myself.gh !== null) { + var repo = myself.gh.getRepo(myself.username, ide.projectName); + var branch = repo.getBranch(); // master (default) + var message = ''; // TODO optional: specify message + + var contents = { + 'snap.xml': pdata, + 'media.xml': media, // may be binary + 'README.md': ide.projectNotes + }; + + branch.writeMany(contents, message).then( + function () { + callBack.call(); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } + }, + function (error) { + errorCall.call(null, error, 'GitHub'); + } + ); +}; + +GitHubBackend.prototype.getProjectList = function (callBack, errorCall) { + var myself = this; + + if (myself.gh !== null) { + myself.gh.getUser().getRepos().then( + function (repos) { + var snapProjects = []; + + var modCallBack = (function () { + var called = 0; + return function () { + if (++called == repos.length) { + callBack.call(myself, snapProjects); + } + }; + })(); + + repos.forEach(function (repo) { + if (repo.description.indexOf('Snap! Project') > -1) { // TODO nicer detection + var project, ghrepo, branch; + + ghrepo = myself.gh.getRepo(repo.owner.login, repo.name); + branch = ghrepo.getBranch(); // master (default) + + branch.read('README.md', false).then( + function (notesContent) { + project = { + 'ProjectName': repo.name, + 'Notes': notesContent.content, + 'Updated': repo.updated_at.replace(/T/, ' ').replace(/Z/, '') // TODO this could be better + }; + + snapProjects.push(project); + modCallBack(); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } else { + modCallBack(); + } + }); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } else { + errorCall.call(myself, localize('Please login'), 'GitHub'); + } +}; + +GitHubBackend.prototype.logout = function (callBack) { + this.clear(); +}; -- cgit v1.3.1 From a3d195b69ecc1b2a35699606eed0ed42b0c8a729 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Thu, 31 Jul 2014 11:49:06 +0200 Subject: show error message when an unlogged user accesses the GitHub project list --- github.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'github.js') diff --git a/github.js b/github.js index a3b3223..84c8630 100644 --- a/github.js +++ b/github.js @@ -218,8 +218,14 @@ GitHubBackend.prototype.saveProject = function (ide, callBack, errorCall) { GitHubBackend.prototype.getProjectList = function (callBack, errorCall) { var myself = this; - if (myself.gh !== null) { - myself.gh.getUser().getRepos().then( + if (myself.gh !== null){ + var user = myself.gh.getUser(); + + if (user === null) { + errorCall.call(myself, localize('Please login'), 'GitHub'); + } + + user.getRepos().then( function (repos) { var snapProjects = []; -- cgit v1.3.1 From 6c49b91f05262e4ce4ce992e0ab8d5275c0ef0bd Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sat, 2 Aug 2014 10:27:11 +0200 Subject: prettify error message when not logged in --- github.js | 12 ++++++++++-- gui.js | 10 ++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'github.js') diff --git a/github.js b/github.js index 84c8630..9534d64 100644 --- a/github.js +++ b/github.js @@ -222,7 +222,8 @@ GitHubBackend.prototype.getProjectList = function (callBack, errorCall) { var user = myself.gh.getUser(); if (user === null) { - errorCall.call(myself, localize('Please login'), 'GitHub'); + myself.message('You are not logged in'); + return; } user.getRepos().then( @@ -270,10 +271,17 @@ GitHubBackend.prototype.getProjectList = function (callBack, errorCall) { } ); } else { - errorCall.call(myself, localize('Please login'), 'GitHub'); + myself.message('You are not logged in'); + return; } }; GitHubBackend.prototype.logout = function (callBack) { this.clear(); }; + +// GitHub: user messages (to be overridden) + +GitHubBackend.prototype.message = function (string) { + alert(string); +}; diff --git a/gui.js b/gui.js index cbc3353..843f1ef 100644 --- a/gui.js +++ b/gui.js @@ -268,6 +268,16 @@ IDE_Morph.prototype.openIn = function (world) { }, 2000); }; + GitHub.message = function (string) { + var m = new MenuMorph(null, string), + intervalHandle; + m.popUpCenteredInWorld(world); + intervalHandle = setInterval(function () { + m.destroy(); + clearInterval(intervalHandle); + }, 2000); + }; + // prevent non-DialogBoxMorphs from being dropped // onto the World in user-mode world.reactToDropOf = function (morph) { -- cgit v1.3.1 From 3571c41da1d30e61e8436079073ebcbfe50ac8de Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sat, 2 Aug 2014 10:51:02 +0200 Subject: allow setting a commit message when saving to GitHub --- github.js | 4 ++-- gui.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) (limited to 'github.js') diff --git a/github.js b/github.js index 9534d64..6f0ce6e 100644 --- a/github.js +++ b/github.js @@ -131,7 +131,7 @@ GitHubBackend.prototype.login = function ( } }; -GitHubBackend.prototype.saveProject = function (ide, callBack, errorCall) { +GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, errorCall) { var myself = this, pdata, media; @@ -191,7 +191,7 @@ GitHubBackend.prototype.saveProject = function (ide, callBack, errorCall) { if (myself.gh !== null) { var repo = myself.gh.getRepo(myself.username, ide.projectName); var branch = repo.getBranch(); // master (default) - var message = ''; // TODO optional: specify message + var message = commitMessage; var contents = { 'snap.xml': pdata, diff --git a/gui.js b/gui.js index 843f1ef..85b46a3 100644 --- a/gui.js +++ b/gui.js @@ -2356,6 +2356,9 @@ IDE_Morph.prototype.projectMenu = function () { menu.addItem('New', 'createNewProject'); menu.addItem('Open...', 'openProjectsBrowser'); menu.addItem('Save', "save"); + if (GitHub.username) { + menu.addItem('Save with commit message', 'commitProjectToGitHub'); + } if (shiftClicked) { menu.addItem( 'Save to disk', @@ -3931,12 +3934,13 @@ IDE_Morph.prototype.saveProjectToCloud = function (name) { } }; -IDE_Morph.prototype.saveProjectToGitHub = function (name) { +IDE_Morph.prototype.saveProjectToGitHub = function (name, commitMessage) { var myself = this; if (name) { this.showMessage('Saving project\nto GitHub...'); this.setProjectName(name); GitHub.saveProject( + commitMessage, this, function () {myself.showMessage('saved.', 2); }, this.githubError() @@ -3944,6 +3948,62 @@ IDE_Morph.prototype.saveProjectToGitHub = function (name) { } }; +IDE_Morph.prototype.commitProjectToGitHub = function () { + var dialog = new DialogBoxMorph().withKey('commitMessage'), + frame = new ScrollFrameMorph(), + text = new TextMorph(''), + ok = dialog.ok, + myself = this, + size = 120, + world = this.world(); + + frame.padding = 6; + frame.setWidth(size); + frame.acceptsDrops = false; + frame.contents.acceptsDrops = false; + + text.setWidth(size - frame.padding * 2); + text.setPosition(frame.topLeft().add(frame.padding)); + text.enableSelecting(); + text.isEditable = true; + + frame.setHeight(size); + frame.fixLayout = nop; + frame.edge = InputFieldMorph.prototype.edge; + frame.fontSize = InputFieldMorph.prototype.fontSize; + frame.typeInPadding = InputFieldMorph.prototype.typeInPadding; + frame.contrast = InputFieldMorph.prototype.contrast; + frame.drawNew = InputFieldMorph.prototype.drawNew; + frame.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; + + frame.addContents(text); + text.drawNew(); + + dialog.ok = function () { + myself.saveProjectToGitHub( + myself.projectName, + text.text + ); + + ok.call(this); + }; + + dialog.justDropped = function () { + text.edit(); + }; + + dialog.labelString = 'Commit message'; + dialog.createLabel(); + dialog.addBody(frame); + frame.drawNew(); + dialog.addButton('ok', 'OK'); + dialog.addButton('cancel', 'Cancel'); + dialog.fixLayout(); + dialog.drawNew(); + dialog.popUp(world); + dialog.setCenter(world.center()); + text.edit(); +}; IDE_Morph.prototype.exportProjectMedia = function (name) { var menu, media; this.serializer.isCollectingMedia = true; -- cgit v1.3.1 From 66f94a7cef1dc132b2db38ea8fcb6d66eb96fc8d Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sat, 2 Aug 2014 11:45:33 +0200 Subject: save GitHub project in one file (now media loads properly); make it easier to open projects by other users --- github.js | 25 +++++++------------------ gui.js | 29 ++++++++++++++--------------- 2 files changed, 21 insertions(+), 33 deletions(-) (limited to 'github.js') diff --git a/github.js b/github.js index 6f0ce6e..573f4d4 100644 --- a/github.js +++ b/github.js @@ -68,21 +68,12 @@ GitHubBackend.prototype.getProject = function ( var repo = myself.gh.getRepo(userName, projectName); var branch = repo.getBranch(); // master (default) - var media, pdata; branch.read('snap.xml', false).then( function (sourceContent) { - branch.read('media.xml', false).then( // true for binary - function (mediaContent) { - callBack.call( - null, - sourceContent.content, - mediaContent.content - ); - }, - function (error) { - errorCall.call(this, error, 'GitHub'); - } + callBack.call( + null, + sourceContent.content ); }, function (error) { @@ -133,16 +124,15 @@ GitHubBackend.prototype.login = function ( GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, errorCall) { var myself = this, - pdata, - media; + data; + var pdata, media; var repoName = ide.projectName.replace(/[^\w-]/g, ''); // TODO validation of project name ide.serializer.isCollectingMedia = true; pdata = ide.serializer.serialize(ide.stage); media = ide.hasChangedMedia ? ide.serializer.mediaXML(ide.projectName) : null; - ide.serializer.isCollectingMedia = false; - ide.serializer.flushMedia(); + data = '' + pdata + media + ''; // check if serialized data can be parsed back again try { @@ -194,8 +184,7 @@ GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, er var message = commitMessage; var contents = { - 'snap.xml': pdata, - 'media.xml': media, // may be binary + 'snap.xml': data, 'README.md': ide.projectNotes }; diff --git a/gui.js b/gui.js index 85b46a3..21ea4d9 100644 --- a/gui.js +++ b/gui.js @@ -401,20 +401,14 @@ IDE_Morph.prototype.openIn = function (world) { GitHub.getProject( dict.Username, dict.projectName, - function (projectData) { + function (code) { var msg; myself.nextSteps([ function () { msg = myself.showMessage('Opening GitHub project...'); }, function () { - if (projectData.indexOf(' Date: Fri, 12 Sep 2014 14:42:43 +0200 Subject: update octokit, fix a first-commit bug --- github.js | 52 ++++++++++++++++++++++++++++------------------------ octokit.js | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) (limited to 'github.js') diff --git a/github.js b/github.js index 573f4d4..c261cbb 100644 --- a/github.js +++ b/github.js @@ -27,8 +27,7 @@ // Global settings ///////////////////////////////////////////////////// -/*global modules, IDE_Morph, SnapSerializer, nop, -localize*/ +/*global modules, localize*/ modules.github = '2014-July-31'; @@ -40,7 +39,7 @@ var GitHub = new GitHubBackend(); // GitHubBackend ///////////////////////////////////////////////////////////// -function GitHubBackend(url) { +function GitHubBackend() { this.gh = null; this.username = null; this.password = null; // TODO saved as plain text @@ -163,40 +162,45 @@ GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, er } }); + function pushChanges () { + if (myself.gh !== null) { + var repo = myself.gh.getRepo(myself.username, ide.projectName); + var branch = repo.getBranch(); // master (default) + var message = commitMessage; + + var contents = { + 'snap.xml': data, + 'README.md': ide.projectNotes + }; + + branch.writeMany(contents, message).then( + function () { + callBack.call(); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } + } + if (exists === false){ myself.gh.getUser().createRepo(repoName, { // these should be discussed - 'description': 'Snap! Project - http://snap.berkeley.edu/snapsource/snap.html#github:Username=' + myself.username + '&projectName=' + repoName, + 'description': 'Snap! Project - http://gubolin.github.io/snap/index.html#github:Username=' + myself.username + '&projectName=' + repoName, 'has_wiki': 'false', 'has_downloads': 'false', 'auto_init': true, 'license_template': 'mit' // discuss }).then( - function () {}, + pushChanges, function (error) { errorCall.call(this, error, 'GitHub'); } ); + } else { + pushChanges(); } - if (myself.gh !== null) { - var repo = myself.gh.getRepo(myself.username, ide.projectName); - var branch = repo.getBranch(); // master (default) - var message = commitMessage; - - var contents = { - 'snap.xml': data, - 'README.md': ide.projectNotes - }; - - branch.writeMany(contents, message).then( - function () { - callBack.call(); - }, - function (error) { - errorCall.call(this, error, 'GitHub'); - } - ); - } }, function (error) { errorCall.call(null, error, 'GitHub'); diff --git a/octokit.js b/octokit.js index d7d66ce..579cef9 160000 --- a/octokit.js +++ b/octokit.js @@ -1 +1 @@ -Subproject commit d7d66ce448edc4eb58664721c5b73655ebe172a5 +Subproject commit 579cef9893626da93ab8afbd601e4a3cf0d6d278 -- cgit v1.3.1 From 0772e7d750532a91fc89c9bb131229a7fb989b91 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Fri, 12 Sep 2014 19:54:58 +0200 Subject: support merging [WIP] --- .gitmodules | 3 +++ github.js | 71 ++++++++++++++++++++++++++++++++++++++++++------------------- gui.js | 18 +++++++++++++--- snap.html | 1 + 4 files changed, 68 insertions(+), 25 deletions(-) (limited to 'github.js') diff --git a/.gitmodules b/.gitmodules index 417778f..510117d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "vkBeautify"] path = vkBeautify url = https://github.com/vkiryukhin/vkBeautify +[submodule "diff-merge"] + path = diff-merge + url = https://github.com/nighca/diff-merge diff --git a/github.js b/github.js index c261cbb..f231e6d 100644 --- a/github.js +++ b/github.js @@ -57,7 +57,8 @@ GitHubBackend.prototype.getProject = function ( userName, projectName, callBack, - errorCall + errorCall, + commitSha ) { var myself = this; @@ -67,12 +68,19 @@ GitHubBackend.prototype.getProject = function ( var repo = myself.gh.getRepo(userName, projectName); var branch = repo.getBranch(); // master (default) - - branch.read('snap.xml', false).then( - function (sourceContent) { - callBack.call( - null, - sourceContent.content + branch.getCommits({}).then( + function (commits) { + branch.read('snap.xml', false).then( + function (sourceContent) { + callBack.call( + null, + sourceContent.content, + commits[0].sha + ); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } ); }, function (error) { @@ -100,7 +108,7 @@ GitHubBackend.prototype.login = function ( me = myself.gh.getUser(); if (me !== null) { me.getInfo().then( - function(info) { + function() { myself.username = username; myself.password = password; @@ -121,7 +129,7 @@ GitHubBackend.prototype.login = function ( } }; -GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, errorCall) { +GitHubBackend.prototype.saveProject = function (commitMessage, parentCommitSha, lastCommit, ide, callBack, errorCall) { var myself = this, data; var pdata, media; @@ -162,27 +170,46 @@ GitHubBackend.prototype.saveProject = function (commitMessage, ide, callBack, er } }); - function pushChanges () { + pushChanges = function () { if (myself.gh !== null) { var repo = myself.gh.getRepo(myself.username, ide.projectName); var branch = repo.getBranch(); // master (default) var message = commitMessage; - var contents = { - 'snap.xml': data, - 'README.md': ide.projectNotes + writeChanges = function (code, pcSha) { + if (pcSha !== parentCommitSha && data !== code) { + var compareResult = window.diff.compare(lastCommit, data, '\n'); // get diff from last push + data = window.diff.merge(code, compareResult); // apply it to the latest code + console.log(data); + } + + var contents = { + 'snap.xml': data, + 'README.md': ide.projectNotes + }; + + branch.writeMany(contents, message, pcSha).then( + function () { + callBack.call(); + }, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); }; - branch.writeMany(contents, message).then( - function () { - callBack.call(); - }, - function (error) { - errorCall.call(this, error, 'GitHub'); - } - ); + if (parentCommitSha !== null) { // repo was just created + myself.getProject(myself.username, ide.projectName, + writeChanges, + function (error) { + errorCall.call(this, error, 'GitHub'); + } + ); + } else { + writeChanges(data, parentCommitSha); + } } - } + }; if (exists === false){ myself.gh.getUser().createRepo(repoName, { // these should be discussed diff --git a/gui.js b/gui.js index 6ae7222..1cc8468 100644 --- a/gui.js +++ b/gui.js @@ -221,6 +221,8 @@ IDE_Morph.prototype.init = function (isAutoFill) { this.stageRatio = 1; // for IDE animations, e.g. when zooming this.loadNewProject = false; // flag when starting up translated + this.parentCommitSha = null; // for GitHub + this.lastCommit = null; // for GitHub this.shield = null; // initialize inherited properties: @@ -401,13 +403,15 @@ IDE_Morph.prototype.openIn = function (world) { GitHub.getProject( dict.Username, dict.projectName, - function (code) { + function (code, pcSha) { var msg; myself.nextSteps([ function () { msg = myself.showMessage('Opening GitHub project...'); }, function () { + myself.parentCommitSha = pcSha; + myself.lastCommit = code; myself.rawOpenCloudDataString(code); myself.hasChangedMedia = true; }, @@ -3935,13 +3939,17 @@ IDE_Morph.prototype.saveProjectToGitHub = function (name, commitMessage) { this.setProjectName(name); GitHub.saveProject( commitMessage, + this.parentCommitSha, + this.lastCommit, this, function () { GitHub.getProject( GitHub.username, name, - function (code) { + function (code, pcSha) { myself.source = 'github'; + myself.parentCommitSha = pcSha; + myself.lastCommit = code; myself.droppedText(code); }, myself.githubError() @@ -5072,8 +5080,10 @@ ProjectDialogMorph.prototype.rawOpenGitHubProject = function (proj, user) { GitHub.getProject( user, proj.ProjectName, - function (code) { + function (code, pcSha) { myself.ide.source = 'github'; + myself.ide.parentCommitSha = pcSha; + myself.ide.lastCommit = code; myself.ide.droppedText(code); }, myself.ide.githubError() @@ -5171,6 +5181,8 @@ ProjectDialogMorph.prototype.saveGitHubProject = function () { this.ide.showMessage('Committing project\nto GitHub...'); GitHub.saveProject( null, + this.ide.parentCommitSha, + this.ide.lastCommit, this.ide, function () { myself.ide.source = 'github'; diff --git a/snap.html b/snap.html index 733b571..63bdebd 100755 --- a/snap.html +++ b/snap.html @@ -22,6 +22,7 @@ +