Move zooming into its own component, imported via HTML Imports.
Also, start building our own polyfill library (polyfill.js) using Grunt and Bower. Finally, refactor all the web pages so that the common header and footer material comes from templates. BUG=skia: R=mtklein@google.com Author: jcgregorio@google.com Review URL: https://codereview.chromium.org/292433002 git-svn-id: http://skia.googlecode.com/svn/trunk@14783 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
99bd7d8174
commit
015c08e5ca
@ -89,5 +89,6 @@ Do this step only once, but only after running webtry_setup.sh the first time
|
||||
Third Party Code
|
||||
----------------
|
||||
|
||||
* res/js/pointerevents.min.js - obtained from https://github.com/components/pointerevents-polyfill
|
||||
* res/js/polyfill.js - Various JS polyfill libraries. To rebuild or update
|
||||
see polyfill/README.md.
|
||||
|
||||
|
3
experimental/webtry/poly/.bowerrc
Normal file
3
experimental/webtry/poly/.bowerrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"directory": "../../../out/bower"
|
||||
}
|
64
experimental/webtry/poly/Gruntfile.js
Normal file
64
experimental/webtry/poly/Gruntfile.js
Normal file
@ -0,0 +1,64 @@
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
// Install all the packages listed in the bower.json file.
|
||||
shell: {
|
||||
bower_install: {
|
||||
command: 'bower install'
|
||||
}
|
||||
},
|
||||
// Copy all the bower files into a single directory.
|
||||
bower: {
|
||||
dev: {
|
||||
dest: '../../../out/grunt/third_party'
|
||||
}
|
||||
},
|
||||
// Concatenate all the files in third_party into a single file.
|
||||
concat: {
|
||||
dist: {
|
||||
src: [
|
||||
'../../../out/grunt/third_party/WeakMap.js',
|
||||
'../../../out/grunt/third_party/classlist.js',
|
||||
'../../../out/grunt/third_party/pointerevents-polyfill.js',
|
||||
'../../../out/grunt/third_party/MutationObserver.js',
|
||||
'../../../out/grunt/third_party/CustomElements.js',
|
||||
'../../../out/grunt/third_party/HTMLImports.js',
|
||||
],
|
||||
dest: '../../../out/grunt/src/<%= pkg.name %>.js'
|
||||
}
|
||||
},
|
||||
// Uglify the one big file into one smaller file.
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> built from /exerimental/webtry/poly <%= grunt.template.today("yyyy-mm-dd") %> */\n'
|
||||
},
|
||||
build: {
|
||||
src: '../../../out/grunt/src/<%= pkg.name %>.js',
|
||||
dest: '../res/js/<%= pkg.name %>.js'
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
simple: {
|
||||
src: '../../../out/grunt/src/<%= pkg.name %>.js',
|
||||
dest: '../res/js/<%= pkg.name %>.js'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Load the plugins for the above commands.
|
||||
grunt.loadNpmTasks('grunt-bower');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-cssmin');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-shell');
|
||||
|
||||
// By default run all the commands in the right sequence to build our custom minified polyfill.
|
||||
grunt.registerTask('default', ['shell:bower_install', 'bower', 'concat', 'uglify']);
|
||||
|
||||
// A target to build an unminified version, for debugging.
|
||||
grunt.registerTask('notmin', ['shell:bower_install', 'bower', 'concat', 'copy:simple']);
|
||||
|
||||
};
|
18
experimental/webtry/poly/README.md
Normal file
18
experimental/webtry/poly/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
polyfill.js
|
||||
===========
|
||||
|
||||
To rebuild or update res/js/polyfill.js you will need to have
|
||||
[node.js](http://nodejs.org/) installed. Once you have it installed run the
|
||||
following:
|
||||
|
||||
cd polyfill
|
||||
npm install
|
||||
grunt
|
||||
|
||||
If you want to create a verion of the polyfill.js that hasn't been minified,
|
||||
say for debugging purposes, then run:
|
||||
|
||||
|
||||
cd polyfill
|
||||
npm install
|
||||
grunt notmin
|
22
experimental/webtry/poly/bower.json
Normal file
22
experimental/webtry/poly/bower.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "polyfill",
|
||||
"version": "0.0.1",
|
||||
"authors": [
|
||||
"Joe Gregorio <jcgregorio@google.com>"
|
||||
],
|
||||
"description": "All the third party polyfills we use.",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"pointerevents-polyfill": "~0.2.0",
|
||||
"CustomElements": "~0.2.3",
|
||||
"HTMLImports": "~0.2.3"
|
||||
}
|
||||
}
|
17
experimental/webtry/poly/package.json
Normal file
17
experimental/webtry/poly/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "polyfill",
|
||||
"version": "0.0.1",
|
||||
"description": "All the dependencies we need to run grunt and build our minified polyfill JS library.",
|
||||
"main": "polyfill.js",
|
||||
"author": "jcgregorio@google.com",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-contrib-uglify": "~0.4.0",
|
||||
"grunt-bower": "~0.13.1",
|
||||
"grunt-contrib-concat": "~0.4.0",
|
||||
"grunt-shell": "~0.7.0",
|
||||
"grunt-contrib-copy": "~0.5.0",
|
||||
"grunt-contrib-cssmin": "~0.9.0"
|
||||
}
|
||||
}
|
@ -9,26 +9,6 @@ img {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAAXNSR0IArs4c6QAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAB3RJTUUH3gUBEi4DGRAQYgAAAB1JREFUGNNjfMoAAVJQmokBDdBHgPE/lPFsYN0BABdaAwN6tehMAAAAAElFTkSuQmCC");
|
||||
}
|
||||
|
||||
.zoom {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.zoomCanvas {
|
||||
position: absolute;
|
||||
width: vmin;
|
||||
height: vmin;
|
||||
top: 3em;
|
||||
right: 1em;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
#zoomCopy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zoomHex {
|
||||
text-shadow: 1px 1px #eee;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 18px;
|
||||
|
169
experimental/webtry/res/imp/zoom.html
Normal file
169
experimental/webtry/res/imp/zoom.html
Normal file
@ -0,0 +1,169 @@
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
/**
|
||||
* A reusable HTML Import to enable zooming on images.
|
||||
*
|
||||
* To use, simply include this HTML Import and add the class 'zoom' to any
|
||||
* images you want zoomable.
|
||||
*
|
||||
* <link rel='import' type='text/html' href='/res/imp/zoom.html'>
|
||||
*
|
||||
* <img src="http://..." class="zoom"/>
|
||||
*
|
||||
* Any number of images on a page can be zoomable.
|
||||
*
|
||||
* If you want to display the rgb colors of the pixel at the center of the
|
||||
* zoom then add an id of 'zoomHex' to any element that supports
|
||||
* textContent, such as a div, p, span, etc.
|
||||
*
|
||||
* <p id=zoomHex></p>
|
||||
*
|
||||
* Note that HTML Imports need to be polyfilled in the near term.
|
||||
*/
|
||||
(function () {
|
||||
function onLoad() {
|
||||
var PIXELS = 20; // The number of pixels in width and height in a zoom.
|
||||
var clientX = 0;
|
||||
var clientY = 0;
|
||||
var lastClientX = 0;
|
||||
var lastClientY = 0;
|
||||
var ctx = null; // The 2D canvas context of the zoom.
|
||||
var currentImage = null; // The img node we are zooming for, otherwise null.
|
||||
var hex = document.getElementById('zoomHex');
|
||||
var canvasCopy = null;
|
||||
function zoomMove(e) {
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
}
|
||||
function zoomMouseDown(e) {
|
||||
e.preventDefault();
|
||||
// Only do zooming on the primary mouse button.
|
||||
if (e.button != 0) {
|
||||
return
|
||||
}
|
||||
currentImage = e.target;
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
lastClientX = clientX-1;
|
||||
lastClientY = clientY-1;
|
||||
document.body.style.cursor = 'crosshair';
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = 1024;
|
||||
canvas.height = 1024;
|
||||
canvas.classList.add('zoomCanvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
this.parentNode.insertBefore(canvas, this);
|
||||
// Copy the image over to a canvas so we can read RGBA values for each point.
|
||||
if (hex) {
|
||||
canvasCopy = document.createElement('canvas');
|
||||
canvasCopy.width = currentImage.width;
|
||||
canvasCopy.height = currentImage.height;
|
||||
canvasCopy.id = 'zoomCopy';
|
||||
canvasCopy.getContext('2d').drawImage(currentImage, 0, 0, currentImage.width, currentImage.height);
|
||||
this.parentNode.insertBefore(canvasCopy, this);
|
||||
}
|
||||
document.body.addEventListener('pointermove', zoomMove, true);
|
||||
document.body.addEventListener('pointerup', zoomFinished);
|
||||
document.body.addEventListener('pointerleave', zoomFinished);
|
||||
// Kick off the drawing.
|
||||
setTimeout(drawZoom, 1);
|
||||
}
|
||||
function hexify(i) {
|
||||
var s = i.toString(16).toUpperCase();
|
||||
// Pad out to two hex digits if necessary.
|
||||
if (s.length < 2) {
|
||||
s = '0' + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function drawZoom() {
|
||||
if (currentImage) {
|
||||
// Only draw if the mouse has moved from the last time we drew.
|
||||
if (lastClientX != clientX || lastClientY != clientY) {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
var x = clientX - currentImage.x;
|
||||
var y = clientY - currentImage.y;
|
||||
var dx = Math.floor(ctx.canvas.width/PIXELS);
|
||||
var dy = Math.floor(ctx.canvas.height/PIXELS);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeStyle = '#000';
|
||||
// Draw out each pixel as a rect on the target canvas, as this works around
|
||||
// FireFox doing a blur as it copies from one canvas to another.
|
||||
var colors = canvasCopy.getContext('2d').getImageData(x, y, PIXELS, PIXELS).data;
|
||||
for (var i=0; i<PIXELS; i++) {
|
||||
for (var j=0; j<PIXELS; j++) {
|
||||
var offset = (j*PIXELS+i)*4; // Offset into the colors array.
|
||||
ctx.fillStyle = 'rgba(' + colors[offset] + ', ' + colors[offset+1] + ', ' + colors[offset+2] + ', ' + colors[offset+3]/255.0 + ')';
|
||||
ctx.fillRect(i*dx, j*dy, dx-1, dy-1);
|
||||
// Box and label one selected pixel with its rgba values.
|
||||
if (hex && i==PIXELS/2 && j == PIXELS/2) {
|
||||
ctx.strokeRect(i*dx, j*dy, dx-1, dy-1);
|
||||
hex.textContent = 'rgba('
|
||||
+ colors[offset] + ', '
|
||||
+ colors[offset+1] + ', '
|
||||
+ colors[offset+2] + ', '
|
||||
+ colors[offset+3] + ') '
|
||||
+ hexify(colors[offset])
|
||||
+ hexify(colors[offset+1])
|
||||
+ hexify(colors[offset+2])
|
||||
+ hexify(colors[offset+3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastClientX = clientX;
|
||||
lastClientY = clientY;
|
||||
}
|
||||
setTimeout(drawZoom, 1000/30);
|
||||
}
|
||||
}
|
||||
function zoomFinished() {
|
||||
currentImage = null;
|
||||
if (hex) {
|
||||
hex.textContent = '';
|
||||
}
|
||||
document.body.style.cursor = 'default';
|
||||
ctx.canvas.parentNode.removeChild(ctx.canvas);
|
||||
canvasCopy.parentNode.removeChild(canvasCopy);
|
||||
document.body.removeEventListener('pointermove', zoomMove, true);
|
||||
document.body.removeEventListener('pointerup', zoomFinished);
|
||||
document.body.removeEventListener('pointerleave', zoomFinished);
|
||||
}
|
||||
|
||||
var zoomables = document.body.querySelectorAll('.zoom');
|
||||
for (var i=0; i<zoomables.length; i++) {
|
||||
zoomables[i].addEventListener('pointerdown', zoomMouseDown);
|
||||
}
|
||||
}
|
||||
|
||||
// If loaded via HTML Imports then DOMContentLoaded will be long done.
|
||||
if (document.readyState != "loading") {
|
||||
onLoad();
|
||||
} else {
|
||||
this.addEventListener('DOMContentLoaded', onLoad);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style type="text/css" media="screen">
|
||||
.zoom {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.zoomCanvas {
|
||||
position: absolute;
|
||||
width: vmin;
|
||||
height: vmin;
|
||||
top: 3em;
|
||||
right: 1em;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
#zoomCopy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zoomHex {
|
||||
text-shadow: 1px 1px #eee;
|
||||
}
|
||||
</style>
|
||||
|
28
experimental/webtry/res/js/pointerevents.min.js
vendored
28
experimental/webtry/res/js/pointerevents.min.js
vendored
File diff suppressed because one or more lines are too long
3
experimental/webtry/res/js/polyfill.js
Normal file
3
experimental/webtry/res/js/polyfill.js
Normal file
File diff suppressed because one or more lines are too long
@ -3,157 +3,6 @@
|
||||
* the results.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A polyfill for HTML Templates.
|
||||
*
|
||||
* This just adds in the content attribute, it doesn't stop scripts
|
||||
* from running nor does it stop other side-effects.
|
||||
*/
|
||||
(function polyfillTemplates() {
|
||||
if('content' in document.createElement('template')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var templates = document.getElementsByTagName('template');
|
||||
for (var i=0; i<templates.length; i++) {
|
||||
var content = document.createDocumentFragment();
|
||||
while (templates[i].firstChild) {
|
||||
content.appendChild(templates[i].firstChild);
|
||||
}
|
||||
templates[i].content = content;
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* Enable zooming for any images with a class of 'zoom'.
|
||||
*/
|
||||
(function () {
|
||||
var PIXELS = 20; // The number of pixels in width and height in a zoom.
|
||||
var clientX = 0;
|
||||
var clientY = 0;
|
||||
var lastClientX = 0;
|
||||
var lastClientY = 0;
|
||||
var ctx = null; // The 2D canvas context of the zoom.
|
||||
var currentImage = null; // The img node we are zooming for, otherwise null.
|
||||
var hex = document.getElementById('zoomHex');
|
||||
var canvasCopy = null;
|
||||
|
||||
function zoomMove(e) {
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
}
|
||||
|
||||
function zoomMouseDown(e) {
|
||||
e.preventDefault();
|
||||
// Only do zooming on the primary mouse button.
|
||||
if (e.button != 0) {
|
||||
return
|
||||
}
|
||||
currentImage = e.target;
|
||||
clientX = e.clientX;
|
||||
clientY = e.clientY;
|
||||
lastClientX = clientX-1;
|
||||
lastClientY = clientY-1;
|
||||
document.body.style.cursor = 'crosshair';
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = 1024;
|
||||
canvas.height = 1024;
|
||||
canvas.classList.add('zoomCanvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
this.parentNode.insertBefore(canvas, this);
|
||||
|
||||
// Copy the image over to a canvas so we can read RGBA values for each point.
|
||||
if (hex) {
|
||||
canvasCopy = document.createElement('canvas');
|
||||
canvasCopy.width = currentImage.width;
|
||||
canvasCopy.height = currentImage.height;
|
||||
canvasCopy.id = 'zoomCopy';
|
||||
canvasCopy.getContext('2d').drawImage(currentImage, 0, 0, currentImage.width, currentImage.height);
|
||||
this.parentNode.insertBefore(canvasCopy, this);
|
||||
}
|
||||
|
||||
document.body.addEventListener('pointermove', zoomMove, true);
|
||||
document.body.addEventListener('pointerup', zoomFinished);
|
||||
document.body.addEventListener('pointerleave', zoomFinished);
|
||||
|
||||
// Kick off the drawing.
|
||||
setTimeout(drawZoom, 1);
|
||||
}
|
||||
|
||||
function hexify(i) {
|
||||
var s = i.toString(16).toUpperCase();
|
||||
// Pad out to two hex digits if necessary.
|
||||
if (s.length < 2) {
|
||||
s = '0' + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function drawZoom() {
|
||||
if (currentImage) {
|
||||
// Only draw if the mouse has moved from the last time we drew.
|
||||
if (lastClientX != clientX || lastClientY != clientY) {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
var x = clientX - currentImage.x;
|
||||
var y = clientY - currentImage.y;
|
||||
var dx = Math.floor(ctx.canvas.width/PIXELS);
|
||||
var dy = Math.floor(ctx.canvas.height/PIXELS);
|
||||
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeStyle = '#000';
|
||||
|
||||
// Draw out each pixel as a rect on the target canvas, as this works around
|
||||
// FireFox doing a blur as it copies from one canvas to another.
|
||||
var colors = canvasCopy.getContext('2d').getImageData(x, y, PIXELS, PIXELS).data;
|
||||
for (var i=0; i<PIXELS; i++) {
|
||||
for (var j=0; j<PIXELS; j++) {
|
||||
var offset = (j*PIXELS+i)*4; // Offset into the colors array.
|
||||
ctx.fillStyle = 'rgba(' + colors[offset] + ', ' + colors[offset+1] + ', ' + colors[offset+2] + ', ' + colors[offset+3]/255.0 + ')';
|
||||
ctx.fillRect(i*dx, j*dy, dx-1, dy-1);
|
||||
// Box and label one selected pixel with its rgba values.
|
||||
if (hex && i==PIXELS/2 && j == PIXELS/2) {
|
||||
ctx.strokeRect(i*dx, j*dy, dx-1, dy-1);
|
||||
hex.textContent = 'rgba('
|
||||
+ colors[offset] + ', '
|
||||
+ colors[offset+1] + ', '
|
||||
+ colors[offset+2] + ', '
|
||||
+ colors[offset+3] + ') '
|
||||
+ hexify(colors[offset])
|
||||
+ hexify(colors[offset+1])
|
||||
+ hexify(colors[offset+2])
|
||||
+ hexify(colors[offset+3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastClientX = clientX;
|
||||
lastClientY = clientY;
|
||||
}
|
||||
setTimeout(drawZoom, 1000/30);
|
||||
}
|
||||
}
|
||||
|
||||
function zoomFinished() {
|
||||
currentImage = null;
|
||||
if (hex) {
|
||||
hex.textContent = '';
|
||||
}
|
||||
document.body.style.cursor = 'default';
|
||||
ctx.canvas.parentNode.removeChild(ctx.canvas);
|
||||
canvasCopy.parentNode.removeChild(canvasCopy);
|
||||
document.body.removeEventListener('pointermove', zoomMove, true);
|
||||
document.body.removeEventListener('pointerup', zoomFinished);
|
||||
document.body.removeEventListener('pointerleave', zoomFinished);
|
||||
}
|
||||
|
||||
this.addEventListener('DOMContentLoaded', function() {
|
||||
var zoomables = document.body.querySelectorAll('.zoom');
|
||||
for (var i=0; i<zoomables.length; i++) {
|
||||
zoomables[i].addEventListener('pointerdown', zoomMouseDown);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* All the functionality is wrapped up in this anonymous closure, but we need
|
||||
@ -167,180 +16,188 @@
|
||||
* that are included in this workspace. That variable is used to
|
||||
* populate the history list.
|
||||
*/
|
||||
(function(workspaceName) {
|
||||
var run = document.getElementById('run');
|
||||
var permalink = document.getElementById('permalink');
|
||||
var embed = document.getElementById('embed');
|
||||
var embedButton = document.getElementById('embedButton');
|
||||
var code = document.getElementById('code');
|
||||
var output = document.getElementById('output');
|
||||
var stdout = document.getElementById('stdout');
|
||||
var img = document.getElementById('img');
|
||||
var tryHistory = document.getElementById('tryHistory');
|
||||
var parser = new DOMParser();
|
||||
var tryTemplate = document.getElementById('tryTemplate');
|
||||
(function() {
|
||||
function onLoad() {
|
||||
var run = document.getElementById('run');
|
||||
var permalink = document.getElementById('permalink');
|
||||
var embed = document.getElementById('embed');
|
||||
var embedButton = document.getElementById('embedButton');
|
||||
var code = document.getElementById('code');
|
||||
var output = document.getElementById('output');
|
||||
var stdout = document.getElementById('stdout');
|
||||
var img = document.getElementById('img');
|
||||
var tryHistory = document.getElementById('tryHistory');
|
||||
var parser = new DOMParser();
|
||||
var tryTemplate = document.getElementById('tryTemplate');
|
||||
|
||||
var editor = CodeMirror.fromTextArea(code, {
|
||||
theme: "default",
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "text/x-c++src",
|
||||
indentUnit: 4,
|
||||
});
|
||||
var editor = CodeMirror.fromTextArea(code, {
|
||||
theme: "default",
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "text/x-c++src",
|
||||
indentUnit: 4,
|
||||
});
|
||||
|
||||
// Match the initial textarea size.
|
||||
editor.setSize(editor.defaultCharWidth() * code.cols,
|
||||
editor.defaultTextHeight() * code.rows);
|
||||
// Match the initial textarea size.
|
||||
editor.setSize(editor.defaultCharWidth() * code.cols,
|
||||
editor.defaultTextHeight() * code.rows);
|
||||
|
||||
function beginWait() {
|
||||
document.body.classList.add('waiting');
|
||||
run.disabled = true;
|
||||
}
|
||||
|
||||
|
||||
function endWait() {
|
||||
document.body.classList.remove('waiting');
|
||||
run.disabled = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback when there's an XHR error.
|
||||
* @param e The callback event.
|
||||
*/
|
||||
function xhrError(e) {
|
||||
endWait();
|
||||
alert('Something bad happened: ' + e);
|
||||
}
|
||||
|
||||
function clearOutput() {
|
||||
output.textContent = "";
|
||||
if (stdout) {
|
||||
stdout.textContent = "";
|
||||
function beginWait() {
|
||||
document.body.classList.add('waiting');
|
||||
run.disabled = true;
|
||||
}
|
||||
embed.style.display='none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an image in the workspace history is clicked.
|
||||
*/
|
||||
function historyClick() {
|
||||
beginWait();
|
||||
clearOutput();
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', historyComplete);
|
||||
req.addEventListener('error', xhrError);
|
||||
req.overrideMimeType('application/json');
|
||||
req.open('GET', this.getAttribute('data-try'), true);
|
||||
req.send();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for when the XHR kicked off in historyClick() returns.
|
||||
*/
|
||||
function historyComplete(e) {
|
||||
// The response is JSON of the form:
|
||||
// {
|
||||
// "hash": "unique id for a try",
|
||||
// "code": "source code for try"
|
||||
// }
|
||||
endWait();
|
||||
body = JSON.parse(e.target.response);
|
||||
code.value = body.code;
|
||||
editor.setValue(body.code);
|
||||
img.src = '/i/'+body.hash+'.png';
|
||||
if (permalink) {
|
||||
permalink.href = '/c/' + body.hash;
|
||||
function endWait() {
|
||||
document.body.classList.remove('waiting');
|
||||
run.disabled = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback when there's an XHR error.
|
||||
* @param e The callback event.
|
||||
*/
|
||||
function xhrError(e) {
|
||||
endWait();
|
||||
alert('Something bad happened: ' + e);
|
||||
}
|
||||
|
||||
function clearOutput() {
|
||||
output.textContent = "";
|
||||
if (stdout) {
|
||||
stdout.textContent = "";
|
||||
}
|
||||
embed.style.display='none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an image in the workspace history is clicked.
|
||||
*/
|
||||
function historyClick() {
|
||||
beginWait();
|
||||
clearOutput();
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', historyComplete);
|
||||
req.addEventListener('error', xhrError);
|
||||
req.overrideMimeType('application/json');
|
||||
req.open('GET', this.getAttribute('data-try'), true);
|
||||
req.send();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for when the XHR kicked off in historyClick() returns.
|
||||
*/
|
||||
function historyComplete(e) {
|
||||
// The response is JSON of the form:
|
||||
// {
|
||||
// "hash": "unique id for a try",
|
||||
// "code": "source code for try"
|
||||
// }
|
||||
endWait();
|
||||
body = JSON.parse(e.target.response);
|
||||
code.value = body.code;
|
||||
editor.setValue(body.code);
|
||||
img.src = '/i/'+body.hash+'.png';
|
||||
if (permalink) {
|
||||
permalink.href = '/c/' + body.hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given try image to the history of a workspace.
|
||||
*/
|
||||
function addToHistory(hash, imgUrl) {
|
||||
var clone = tryTemplate.content.cloneNode(true);
|
||||
clone.querySelector('img').src = imgUrl;
|
||||
clone.querySelector('.tries').setAttribute('data-try', '/json/' + hash);
|
||||
tryHistory.insertBefore(clone, tryHistory.firstChild);
|
||||
tryHistory.querySelector('.tries').addEventListener('click', historyClick, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for when the XHR returns after attempting to run the code.
|
||||
* @param e The callback event.
|
||||
*/
|
||||
function codeComplete(e) {
|
||||
// The response is JSON of the form:
|
||||
// {
|
||||
// "message": "you had an error...",
|
||||
// "img": "<base64 encoded image but only on success>"
|
||||
// }
|
||||
//
|
||||
// The img is optional and only appears if there is a valid
|
||||
// image to display.
|
||||
endWait();
|
||||
console.log(e.target.response);
|
||||
body = JSON.parse(e.target.response);
|
||||
output.textContent = body.message;
|
||||
if (stdout) {
|
||||
stdout.textContent = body.stdout;
|
||||
}
|
||||
if (body.hasOwnProperty('img')) {
|
||||
img.src = 'data:image/png;base64,' + body.img;
|
||||
} else {
|
||||
img.src = '';
|
||||
}
|
||||
// Add the image to the history if we are on a workspace page.
|
||||
if (tryHistory) {
|
||||
addToHistory(body.hash, 'data:image/png;base64,' + body.img);
|
||||
} else {
|
||||
window.history.pushState(null, null, '/c/' + body.hash);
|
||||
}
|
||||
if (permalink) {
|
||||
permalink.href = '/c/' + body.hash;
|
||||
}
|
||||
if (embed) {
|
||||
var url = document.URL;
|
||||
url = url.replace('/c/', '/iframe/');
|
||||
embed.value = '<iframe src="' + url + '" width="740" height="550" style="border: solid #00a 5px; border-radius: 5px;"/>'
|
||||
}
|
||||
if (embedButton && embedButton.hasAttribute('disabled')) {
|
||||
embedButton.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onSubmitCode() {
|
||||
beginWait();
|
||||
clearOutput();
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', codeComplete);
|
||||
req.addEventListener('error', xhrError);
|
||||
req.overrideMimeType('application/json');
|
||||
req.open('POST', '/', true);
|
||||
req.setRequestHeader('content-type', 'application/json');
|
||||
req.send(JSON.stringify({'code': editor.getValue(), 'name': workspaceName}));
|
||||
}
|
||||
run.addEventListener('click', onSubmitCode);
|
||||
|
||||
|
||||
function onEmbedClick() {
|
||||
embed.style.display='inline';
|
||||
}
|
||||
|
||||
if (embedButton) {
|
||||
embedButton.addEventListener('click', onEmbedClick);
|
||||
}
|
||||
|
||||
// Add the images to the history if we are on a workspace page.
|
||||
if (tryHistory && history) {
|
||||
for (var i=0; i<history.length; i++) {
|
||||
addToHistory(history[i].hash, '/i/'+history[i].hash+'.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given try image to the history of a workspace.
|
||||
*/
|
||||
function addToHistory(hash, imgUrl) {
|
||||
var clone = tryTemplate.content.cloneNode(true);
|
||||
clone.querySelector('img').src = imgUrl;
|
||||
clone.querySelector('.tries').setAttribute('data-try', '/json/' + hash);
|
||||
tryHistory.insertBefore(clone, tryHistory.firstChild);
|
||||
tryHistory.querySelector('.tries').addEventListener('click', historyClick, true);
|
||||
// If loaded via HTML Imports then DOMContentLoaded will be long done.
|
||||
if (document.readyState != "loading") {
|
||||
onLoad();
|
||||
} else {
|
||||
this.addEventListener('DOMContentLoaded', onLoad);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for when the XHR returns after attempting to run the code.
|
||||
* @param e The callback event.
|
||||
*/
|
||||
function codeComplete(e) {
|
||||
// The response is JSON of the form:
|
||||
// {
|
||||
// "message": "you had an error...",
|
||||
// "img": "<base64 encoded image but only on success>"
|
||||
// }
|
||||
//
|
||||
// The img is optional and only appears if there is a valid
|
||||
// image to display.
|
||||
endWait();
|
||||
console.log(e.target.response);
|
||||
body = JSON.parse(e.target.response);
|
||||
output.textContent = body.message;
|
||||
if (stdout) {
|
||||
stdout.textContent = body.stdout;
|
||||
}
|
||||
if (body.hasOwnProperty('img')) {
|
||||
img.src = 'data:image/png;base64,' + body.img;
|
||||
} else {
|
||||
img.src = '';
|
||||
}
|
||||
// Add the image to the history if we are on a workspace page.
|
||||
if (tryHistory) {
|
||||
addToHistory(body.hash, 'data:image/png;base64,' + body.img);
|
||||
} else {
|
||||
window.history.pushState(null, null, '/c/' + body.hash);
|
||||
}
|
||||
if (permalink) {
|
||||
permalink.href = '/c/' + body.hash;
|
||||
}
|
||||
if (embed) {
|
||||
var url = document.URL;
|
||||
url = url.replace('/c/', '/iframe/');
|
||||
embed.value = '<iframe src="' + url + '" width="740" height="550" style="border: solid #00a 5px; border-radius: 5px;"/>'
|
||||
}
|
||||
if (embedButton && embedButton.hasAttribute('disabled')) {
|
||||
embedButton.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onSubmitCode() {
|
||||
beginWait();
|
||||
clearOutput();
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', codeComplete);
|
||||
req.addEventListener('error', xhrError);
|
||||
req.overrideMimeType('application/json');
|
||||
req.open('POST', '/', true);
|
||||
req.setRequestHeader('content-type', 'application/json');
|
||||
req.send(JSON.stringify({'code': editor.getValue(), 'name': workspaceName}));
|
||||
}
|
||||
run.addEventListener('click', onSubmitCode);
|
||||
|
||||
|
||||
function onEmbedClick() {
|
||||
embed.style.display='inline';
|
||||
}
|
||||
|
||||
if (embedButton) {
|
||||
embedButton.addEventListener('click', onEmbedClick);
|
||||
}
|
||||
|
||||
|
||||
// Add the images to the history if we are on a workspace page.
|
||||
if (tryHistory && history) {
|
||||
for (var i=0; i<history.length; i++) {
|
||||
addToHistory(history[i].hash, '/i/'+history[i].hash+'.png');
|
||||
}
|
||||
}
|
||||
|
||||
})(workspaceName);
|
||||
})();
|
||||
|
@ -1,8 +1,5 @@
|
||||
|
||||
<section id=content>
|
||||
<script src="/res/js/cm/codemirror.js"></script>
|
||||
<script src="/res/js/cm/clike.js"></script>
|
||||
|
||||
<pre>
|
||||
<textarea spellcheck=false name='code' id='code' rows='15' cols='100'>{{.Code}}</textarea>
|
||||
</pre>
|
||||
|
6
experimental/webtry/templates/footercommon.html
Normal file
6
experimental/webtry/templates/footercommon.html
Normal file
@ -0,0 +1,6 @@
|
||||
<link rel='stylesheet' href='/res/css/webtry.css' type='text/css'>
|
||||
<link rel='stylesheet' href='/res/css/cm/codemirror.css' type='text/css'>
|
||||
<script src='/res/js/polyfill.js' type='text/javascript'></script>
|
||||
<script src='/res/js/cm/codemirror.js' type='text/javascript'></script>
|
||||
<script src='/res/js/cm/clike.js' type='text/javascript'></script>
|
||||
<script src='/res/js/webtry.js' type='text/javascript'></script>
|
2
experimental/webtry/templates/headercommon.html
Normal file
2
experimental/webtry/templates/headercommon.html
Normal file
@ -0,0 +1,2 @@
|
||||
<meta charset='utf-8' />
|
||||
<meta name=viewport content='width=device-width, initial-scale=1'>
|
@ -2,17 +2,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Skia WebTry</title>
|
||||
<meta charset='utf-8' />
|
||||
<script src="/res/js/pointerevents.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<link rel='stylesheet' href='/res/css/webtry.css' type='text/css' media='screen'>
|
||||
<link rel="stylesheet" href="/res/css/cm/codemirror.css" type="text/css" media="screen">
|
||||
{{template "headercommon.html" .}}
|
||||
<link rel='import' type='text/html' href='/res/imp/zoom.html'>
|
||||
</head>
|
||||
<body class=iframe>
|
||||
{{template "content.html" .}}
|
||||
<script type='text/javascript' charset='utf-8'>
|
||||
<script type='text/javascript'>
|
||||
// Not running in a workspace.
|
||||
var workspaceName = '';
|
||||
</script>
|
||||
<script src="/res/js/webtry.js" type="text/javascript" charset="utf-8"></script>
|
||||
{{template "footercommon.html" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,19 +2,17 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Skia WebTry</title>
|
||||
<meta charset='utf-8' />
|
||||
<script src="/res/js/pointerevents.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<link rel="stylesheet" href="/res/css/webtry.css" type="text/css" media="screen">
|
||||
<link rel="stylesheet" href="/res/css/cm/codemirror.css" type="text/css" media="screen">
|
||||
{{template "headercommon.html" .}}
|
||||
<link rel='import' type='text/html' href='/res/imp/zoom.html'>
|
||||
</head>
|
||||
<body>
|
||||
{{template "titlebar.html" .}}
|
||||
{{template "content.html" .}}
|
||||
|
||||
<script type='text/javascript' charset='utf-8'>
|
||||
<script type='text/javascript'>
|
||||
// Not running in a workspace.
|
||||
var workspaceName = "";
|
||||
var workspaceName = '';
|
||||
</script>
|
||||
<script src="/res/js/webtry.js" type="text/javascript" charset="utf-8"></script>
|
||||
{{template "footercommon.html" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -3,22 +3,23 @@
|
||||
<head>
|
||||
<title>Recent SkFiddles</title>
|
||||
<meta charset='utf-8' />
|
||||
<link rel="stylesheet" href="/res/css/webtry.css" type="text/css" media="screen">
|
||||
{{template "headercommon.html" .}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "titlebar.html" .}}
|
||||
<section id=content>
|
||||
<h1>Recent Activity</h1>
|
||||
<section>
|
||||
{{range .Tries}}
|
||||
<div class=tries>
|
||||
<h2><a href="/c/{{.Hash}}">{{.CreateTS}}</a></h2>
|
||||
<a href="/c/{{.Hash}}">
|
||||
<img width=128 height=128 src="/i/{{.Hash}}.png">
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</section>
|
||||
<h1>Recent Activity</h1>
|
||||
<section>
|
||||
{{range .Tries}}
|
||||
<div class=tries>
|
||||
<h2><a href="/c/{{.Hash}}">{{.CreateTS}}</a></h2>
|
||||
<a href="/c/{{.Hash}}">
|
||||
<img width=128 height=128 src="/i/{{.Hash}}.png">
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</section>
|
||||
</section>
|
||||
{{template "footercommon.html" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,15 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Workspace</title>
|
||||
<meta charset='utf-8' />
|
||||
<script src="/res/js/pointerevents.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<link rel='stylesheet' href='/res/css/webtry.css' type='text/css' media='screen'>
|
||||
<link rel="stylesheet" href="/res/css/cm/codemirror.css" type="text/css" media="screen">
|
||||
{{template "headercommon.html" .}}
|
||||
<link rel='import' type='text/html' href='/res/imp/zoom.html'>
|
||||
</head>
|
||||
<body>
|
||||
<template id=tryTemplate>
|
||||
<div class=tries data-try="">
|
||||
<img width=64 height=64 src="">
|
||||
<div class=tries data-try=''>
|
||||
<img width=64 height=64 src=''>
|
||||
</div>
|
||||
</template>
|
||||
{{template "titlebar.html" .}}
|
||||
@ -20,22 +18,22 @@
|
||||
<section id=tryHistory>
|
||||
</section>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<script type='text/javascript'>
|
||||
var history = {{.Tries}};
|
||||
</script>
|
||||
<script type='text/javascript' charset='utf-8'>
|
||||
<script type='text/javascript'>
|
||||
// Set the workspace name so run.js also updates the history.
|
||||
var workspaceName = "{{.Name}}";
|
||||
var workspaceName = '{{.Name}}';
|
||||
</script>
|
||||
<script src="/res/js/webtry.js" type="text/javascript" charset="utf-8"></script>
|
||||
{{else}}
|
||||
<section id=content>
|
||||
<h1>Create</h1>
|
||||
Create a new workspace:
|
||||
<form action="." method="POST" accept-charset="utf-8">
|
||||
<p><input type="submit" value="Create"></p>
|
||||
<form action='.' method='POST'>
|
||||
<p><input type='submit' value='Create'></p>
|
||||
</form>
|
||||
</section>
|
||||
{{end}}
|
||||
{{template "footercommon.html" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -140,6 +140,8 @@ func init() {
|
||||
filepath.Join(cwd, "templates/index.html"),
|
||||
filepath.Join(cwd, "templates/titlebar.html"),
|
||||
filepath.Join(cwd, "templates/content.html"),
|
||||
filepath.Join(cwd, "templates/headercommon.html"),
|
||||
filepath.Join(cwd, "templates/footercommon.html"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -147,6 +149,8 @@ func init() {
|
||||
iframeTemplate, err = htemplate.ParseFiles(
|
||||
filepath.Join(cwd, "templates/iframe.html"),
|
||||
filepath.Join(cwd, "templates/content.html"),
|
||||
filepath.Join(cwd, "templates/headercommon.html"),
|
||||
filepath.Join(cwd, "templates/footercommon.html"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -154,6 +158,8 @@ func init() {
|
||||
recentTemplate, err = htemplate.ParseFiles(
|
||||
filepath.Join(cwd, "templates/recent.html"),
|
||||
filepath.Join(cwd, "templates/titlebar.html"),
|
||||
filepath.Join(cwd, "templates/headercommon.html"),
|
||||
filepath.Join(cwd, "templates/footercommon.html"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -162,6 +168,8 @@ func init() {
|
||||
filepath.Join(cwd, "templates/workspace.html"),
|
||||
filepath.Join(cwd, "templates/titlebar.html"),
|
||||
filepath.Join(cwd, "templates/content.html"),
|
||||
filepath.Join(cwd, "templates/headercommon.html"),
|
||||
filepath.Join(cwd, "templates/footercommon.html"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
Loading…
Reference in New Issue
Block a user