Skip to content

Commit

Permalink
Share Sandcastle code using URL instead of gists.
Browse files Browse the repository at this point in the history
Anonymous gist creation will be removed - #6232

Instead of publishing gists, when we share we now encode the code into
the URL fragment, in compressed Base64 encoded form.  (see code comments
for the exact format)

Existing gists still load as before.
  • Loading branch information
shunter committed Mar 16, 2018
1 parent 21f3495 commit 30c047e
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 118 deletions.
197 changes: 88 additions & 109 deletions Apps/Sandcastle/CesiumSandcastle.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@
/*global hello_world_index*/// defined in gallery/gallery-index.js, created by build
/*global sandcastleJsHintOptions*/// defined by jsHintOptions.js, created by build
require({
baseUrl : '../../Source',
packages : [{
name : 'dojo',
location : '../ThirdParty/dojo-release-1.10.4/dojo'
baseUrl: '../../Source',
packages: [{
name: 'dojo',
location: '../ThirdParty/dojo-release-1.10.4/dojo'
}, {
name : 'dijit',
location : '../ThirdParty/dojo-release-1.10.4/dijit'
name: 'dijit',
location: '../ThirdParty/dojo-release-1.10.4/dijit'
}, {
name : 'Sandcastle',
location : '../Apps/Sandcastle'
name: 'Sandcastle',
location: '../Apps/Sandcastle'
}, {
name : 'Source',
location : '.'
name: 'Source',
location: '.'
}, {
name: 'CesiumUnminified',
location : '../Build/CesiumUnminified',
location: '../Build/CesiumUnminified',
main: 'Cesium'
}, {
name : 'CodeMirror',
location : '../ThirdParty/codemirror-4.6'
name: 'CodeMirror',
location: '../ThirdParty/codemirror-4.6'
}, {
name: 'ThirdParty',
location: '../Apps/Sandcastle/ThirdParty'
}]
}, [
"dijit/Dialog",
Expand All @@ -48,9 +51,10 @@ require({
'dojo/when',
'Sandcastle/LinkButton',
'Source/Core/defined',
'Source/Core/getBaseUri',
'Source/Core/Resource',
'Source/Cesium',
'ThirdParty/pako.min',
'ThirdParty/clipboard.min',
'CodeMirror/addon/hint/show-hint',
'CodeMirror/addon/hint/javascript-hint',
'CodeMirror/mode/javascript/javascript',
Expand Down Expand Up @@ -94,12 +98,16 @@ require({
when,
LinkButton,
defined,
getBaseUri,
Resource,
Cesium
Cesium,
pako,
ClipboardJS
) {
'use strict';

// attach clipboard handling to our Copy button
var clipboardjs = new ClipboardJS('.copyButton');

//In order for CodeMirror auto-complete to work, Cesium needs to be defined as a global.
if (!defined(window.Cesium)) {
window.Cesium = Cesium;
Expand Down Expand Up @@ -176,12 +184,6 @@ require({
var newDemo;
var demoHtml = '';
var demoCode = '';
var previousCode = '';
var previousHtml = '';
var runGist = false;
var gistCode;
var gistHtml;
var sandcastleUrl = '';

var defaultHtml = '<style>\n@import url(../templates/bucket.css);\n</style>\n<div id=\"cesiumContainer\" class=\"fullSize\"></div>\n<div id=\"loadingOverlay\"><h1>Loading...</h1></div>\n<div id=\"toolbar\"></div>';

Expand Down Expand Up @@ -696,18 +698,14 @@ require({
}

var queryObject = {};
var gistId = ioQuery.queryToObject(window.location.search.substring(1)).gist;
if (window.location.search) {
queryObject = ioQuery.queryToObject(window.location.search.substring(1));
if (defined(gistId)) {
queryObject.gistId = gistId;
}
} else {
}
if (!defined(queryObject.src)) {
queryObject.src = 'Hello World.html';
}
if (!defined(queryObject.label)) {
queryObject.label = 'Showcases';
if (defined(gistId)) {
queryObject.gistId = gistId;
}
}

function loadFromGallery(demo) {
Expand All @@ -716,13 +714,6 @@ require({
registry.byId('description').set('value', decodeHTML(demo.description).replace(/\\n/g, '\n'));
registry.byId('label').set('value', decodeHTML(demo.label).replace(/\\n/g, '\n'));

if (demo.name === 'Gist Import') {
jsEditor.setValue(gistCode);
htmlEditor.setValue(gistHtml);
document.title = 'Gist Import - Cesium Sandcastle';
CodeMirror.commands.runCesium(jsEditor);
return;
}
return requestDemo(demo.name).then(function(value) {
demo.code = value;

Expand All @@ -744,45 +735,52 @@ require({
var scriptCode = scriptMatch[1];
demoCode = scriptCode.replace(/\s/g, '');

if (defined(queryObject.gistId)) {
Resource.fetchJsonp('https://api.github.com/gists/' + queryObject.gistId + '?access_token=dd8f755c2e5d9bbb26806bb93eaa2291f2047c60')
function applyLoadedDemo(code, html) {
jsEditor.setValue(code);
htmlEditor.setValue(html);
demoCode = code.replace(/\s/g, '');
demoHtml = html.replace(/\s/g, '');
CodeMirror.commands.runCesium(jsEditor);
clearRun();
}

var json, code, html;
if (defined(queryObject.gist)) {
Resource.fetchJsonp('https://api.github.com/gists/' + queryObject.gist + '?access_token=dd8f755c2e5d9bbb26806bb93eaa2291f2047c60')
.then(function(data) {
var files = data.data.files;
var code = files['Cesium-Sandcastle.js'].content;
var htmlFile = files['Cesium-Sandcastle.html'];
var html = defined(htmlFile) ? htmlFile.content : defaultHtml; // Use the default html for old gists
jsEditor.setValue(code);
htmlEditor.setValue(html);
demoCode = code.replace(/\s/g, '');
demoHtml = html.replace(/\s/g, '');
gistCode = code;
gistHtml = html;
previousCode = code;
previousHtml = html;
sandcastleUrl = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId;
CodeMirror.commands.runCesium(jsEditor);
clearRun();
applyLoadedDemo(code, html);
}).otherwise(function(error) {
appendConsole('consoleError', 'Unable to GET from GitHub API. This could be due to too many request, try again in an hour or copy and paste the code from the gist: https://gist.github.com/' + gistId , true);
appendConsole('consoleError', 'Unable to GET from GitHub API. This could be due to too many request, try again in an hour or copy and paste the code from the gist: https://gist.github.com/' + queryObject.gist , true);
console.log(error);
});
} else if (defined(queryObject.code)) {
//The code query parameter is a Base64 encoded JSON string with `code` and `html` properties.
var json = JSON.parse(window.atob(queryObject.code));
var code = json.code;
var html = json.html;

jsEditor.setValue(code);
htmlEditor.setValue(html);
demoCode = code.replace(/\s/g, '');
demoHtml = html.replace(/\s/g, '');
gistCode = code;
gistHtml = html;
previousCode = code;
previousHtml = html;
sandcastleUrl = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&code=' + code;
CodeMirror.commands.runCesium(jsEditor);
clearRun();
json = JSON.parse(window.atob(queryObject.code));
code = json.code;
html = json.html;

applyLoadedDemo(code, html);
} else if (window.location.hash.indexOf('#c=') === 0) {
// data stored in the hash as:
// Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
var base64String = window.location.hash.substr(3);
// restore padding
while (base64String.length % 4 !== 0) {
base64String += '=';
}
var jsonString = pako.inflate(atob(base64String), { raw: true, to: 'string' });
// we save a few bytes by omitting the leading [" and trailing "] since they are always the same
jsonString = '["' + jsonString + '"]';
json = JSON.parse(jsonString);
// index 0 is code, index 1 is html
code = json[0];
html = json[1];

applyLoadedDemo(code, html);
} else {
jsEditor.setValue(scriptCode);
}
Expand Down Expand Up @@ -932,49 +930,36 @@ require({
}
}

function getBaseUrl() {
// omits query string and hash
return location.protocol + '//' + location.host + location.pathname;
}

registry.byId('buttonShareDrop').on('click', function() {
var textArea = document.getElementById('link');
textArea.value = '\n\n';
var code = jsEditor.getValue();
var html = htmlEditor.getValue();
if (code === previousCode && html === previousHtml) {
textArea.value = sandcastleUrl;
textArea.select();
return;
}
previousCode = code;
previousHtml = html;
var data = {
public : true,
files : {
'Cesium-Sandcastle.js' : {
content : code
},
'Cesium-Sandcastle.html' : {
content : html
}
}
};

var resource = new Resource('https://api.github.com/gists');
return resource.post(JSON.stringify(data)).then(function(content) {
sandcastleUrl = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + JSON.parse(content).id;
textArea.value = sandcastleUrl;
textArea.select();
}).otherwise(function(error) {
appendConsole('consoleError', 'Unable to POST to GitHub API. This could be due to too many POST requests, try again in an hour.', true);
console.log(error);
});
// data stored in the hash as:
// Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
var jsonString = JSON.stringify([code, html]);
// we save a few bytes by omitting the leading [" and trailing "] since they are always the same
jsonString = jsonString.substr(2, jsonString.length - 4);
var base64String = btoa(pako.deflate(jsonString, { raw: true, to: 'string', level: 9 }));
base64String = base64String.replace(/\=+$/, ''); // remove padding

var shareUrlBox = document.getElementById('shareUrl');
shareUrlBox.value = getBaseUrl() + '#c=' + base64String;
shareUrlBox.select();
});

registry.byId('buttonImport').on('click', function() {
gistId = document.getElementById("gistId").value;
var gistId = document.getElementById("gistId").value;
var gistParameter = '&gist=';
var gistIndex = gistId.indexOf(gistParameter);
if (gistIndex !== -1) {
gistId = gistId.substring(gistIndex + gistParameter.length);
}
window.location.href = getBaseUri(window.location.href) + '?src=Hello%20World.html&label=Showcases&gist=' + gistId;
window.location.href = getBaseUrl() + '?gist=' + gistId;
});

registry.byId('buttonNew').on('click', function() {
Expand Down Expand Up @@ -1002,7 +987,6 @@ require({
});
// Clicking the 'Run' button simply reloads the iframe.
registry.byId('buttonRun').on('click', function() {
runGist = true;
CodeMirror.commands.runCesium(jsEditor);
});

Expand All @@ -1021,7 +1005,7 @@ require({
}

registry.byId('dropDownSaveAs').on('show', function() {
var currentDemoName = ioQuery.queryToObject(window.location.search.substring(1)).src;
var currentDemoName = queryObject.src;
currentDemoName = currentDemoName.replace('.html', '');
var description = encodeHTML(registry.byId('description').get('value').replace(/\n/g, '\\n')).replace(/\"/g, '&quot;');
var label = encodeHTML(registry.byId('label').get('value').replace(/\n/g, '\\n')).replace(/\"/g, '&quot;');
Expand Down Expand Up @@ -1122,18 +1106,11 @@ require({

// Select the demo to load upon opening based on the query parameter.
if (defined(queryObject.src)) {
var gistDemo = {
name : 'Gist Import',
code : demo.code,
description: 'Code imported from GitHub Gist'
};
if (demo.name === queryObject.src.replace('.html', '')) {
loadFromGallery(demo).then(function() {
if (defined(queryObject.gistId)) {
window.history.replaceState(gistDemo, gistDemo.name, '?src=Hello World.html&label=' + queryObject.label + '&gist=' + queryObject.gistId);
if (defined(queryObject.gist)) {
document.title = 'Gist Import - Cesium Sandcastle';
} else {
window.history.replaceState(demo, demo.name, '?src=' + demo.name + '.html&label=' + queryObject.label);
document.title = demo.name + ' - Cesium Sandcastle';
}
});
Expand Down Expand Up @@ -1222,15 +1199,17 @@ require({
if (mouse.isMiddle(e)) {
window.open('gallery/' + demo.name + '.html');
} else {
delete queryObject.gistId;
delete queryObject.code;
var htmlText = (htmlEditor.getValue()).replace(/\s/g, '');
var jsText = (jsEditor.getValue()).replace(/\s/g, '');
var confirmChange = true;
if (demoHtml !== htmlText || demoCode !== jsText) {
confirmChange = window.confirm('You have unsaved changes. Are you sure you want to navigate away from this demo?');
}
if (confirmChange) {
delete queryObject.gist;
delete queryObject.code;
history.replaceState(null, document.title, window.location.pathname + window.location.search);

loadFromGallery(demo).then(function() {
var demoSrc = demo.name + '.html';
if (demoSrc !== window.location.search.substring(1)) {
Expand Down
Loading

0 comments on commit 30c047e

Please sign in to comment.