kopia lustrzana https://github.com/backface/turtlestitch
New feature: Export Project Summary
* opens a new browser tab on an editable HTML document containing an overview of the current project which can be further processed (saved, edited, printed, turned into a PDF) to create a project report. * now, when you export script pics attached comments get included. * also new: Support to detect and react to “any” keystroke (hat and sensing blocks)dev
rodzic
cd7f99534b
commit
2172084dae
64
blocks.js
64
blocks.js
|
@ -156,7 +156,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.blocks = '2015-September-23';
|
||||
modules.blocks = '2015-October-02';
|
||||
|
||||
var SyntaxElementMorph;
|
||||
var BlockMorph;
|
||||
|
@ -1073,6 +1073,7 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
|
|||
'right arrow': ['right arrow'],
|
||||
'left arrow': ['left arrow'],
|
||||
space : ['space'],
|
||||
any : ['any'],
|
||||
a : ['a'],
|
||||
b : ['b'],
|
||||
c : ['c'],
|
||||
|
@ -2312,7 +2313,7 @@ BlockMorph.prototype.userMenu = function () {
|
|||
menu.addItem(
|
||||
"script pic...",
|
||||
function () {
|
||||
window.open(myself.topBlock().fullImage().toDataURL());
|
||||
window.open(myself.topBlock().scriptPic().toDataURL());
|
||||
},
|
||||
'open a new window\nwith a picture of this script'
|
||||
);
|
||||
|
@ -3234,7 +3235,7 @@ BlockMorph.prototype.activeProcess = function () {
|
|||
return null;
|
||||
};
|
||||
|
||||
// BlockMorph thumbnail
|
||||
// BlockMorph thumbnail and script pic
|
||||
|
||||
BlockMorph.prototype.thumbnail = function (scale, clipWidth) {
|
||||
var nb = this.nextBlock(),
|
||||
|
@ -3276,6 +3277,31 @@ BlockMorph.prototype.thumbnail = function (scale, clipWidth) {
|
|||
return trgt;
|
||||
};
|
||||
|
||||
BlockMorph.prototype.scriptPic = function () {
|
||||
// answer a canvas image that also includes comments
|
||||
var scr = this.fullImage(),
|
||||
fb = this.stackFullBounds(),
|
||||
pic = newCanvas(fb.extent()),
|
||||
ctx = pic.getContext('2d');
|
||||
this.allComments().forEach(function (comment) {
|
||||
var anchor = comment.anchor;
|
||||
if (anchor) {
|
||||
ctx.drawImage(
|
||||
anchor.image,
|
||||
anchor.left() - fb.left(),
|
||||
anchor.top() - fb.top()
|
||||
);
|
||||
}
|
||||
ctx.drawImage(
|
||||
comment.fullImageClassic(),
|
||||
comment.left() - fb.left(),
|
||||
comment.top() - fb.top()
|
||||
);
|
||||
});
|
||||
ctx.drawImage(scr, 0, 0);
|
||||
return pic;
|
||||
};
|
||||
|
||||
// BlockMorph dragging and dropping
|
||||
|
||||
BlockMorph.prototype.rootForGrab = function () {
|
||||
|
@ -3358,6 +3384,22 @@ BlockMorph.prototype.stackHeight = function () {
|
|||
return Math.max(fb.bottom(), commentsBottom) - fb.top();
|
||||
};
|
||||
|
||||
BlockMorph.prototype.stackFullBounds = function () {
|
||||
var fb = this.fullBounds();
|
||||
this.allComments().forEach(function (comment) {
|
||||
fb.mergeWith(comment.bounds);
|
||||
});
|
||||
return fb;
|
||||
};
|
||||
|
||||
BlockMorph.prototype.stackWidth = function () {
|
||||
var fb = this.fullBounds(),
|
||||
commentsRight = Math.max(this.allComments().map(
|
||||
function (comment) {return comment.right(); }
|
||||
)) || this.right();
|
||||
return Math.max(fb.right(), commentsRight) - fb.left();
|
||||
};
|
||||
|
||||
BlockMorph.prototype.snap = function () {
|
||||
var top = this.topBlock();
|
||||
top.allComments().forEach(function (comment) {
|
||||
|
@ -5419,6 +5461,20 @@ ScriptsMorph.prototype.clearDropHistory = function () {
|
|||
this.lastNextBlock = null;
|
||||
};
|
||||
|
||||
// ScriptsMorph sorting blocks and comments
|
||||
|
||||
ScriptsMorph.prototype.sortedElements = function () {
|
||||
// return all scripts and unattached comments
|
||||
var scripts = this.children.filter(function (each) {
|
||||
return each instanceof CommentMorph ? !each.block : true;
|
||||
});
|
||||
scripts.sort(function (a, b) {
|
||||
// make sure the prototype hat block always stays on top
|
||||
return a instanceof PrototypeHatBlockMorph ? 0 : a.top() - b.top();
|
||||
});
|
||||
return scripts;
|
||||
};
|
||||
|
||||
// ScriptsMorph blocks layout fix
|
||||
|
||||
ScriptsMorph.prototype.fixMultiArgs = function () {
|
||||
|
@ -10984,7 +11040,7 @@ CommentMorph.prototype.userMenu = function () {
|
|||
menu.addItem(
|
||||
"comment pic...",
|
||||
function () {
|
||||
window.open(myself.fullImage().toDataURL());
|
||||
window.open(myself.fullImageClassic().toDataURL());
|
||||
},
|
||||
'open a new window\nwith a picture of this comment'
|
||||
);
|
||||
|
|
14
byob.js
14
byob.js
|
@ -106,7 +106,7 @@ SymbolMorph, isNil, CursorMorph*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.byob = '2015-July-28';
|
||||
modules.byob = '2015-October-02';
|
||||
|
||||
// Declarations
|
||||
|
||||
|
@ -341,6 +341,16 @@ CustomBlockDefinition.prototype.parseSpec = function (spec) {
|
|||
// CustomBlockDefinition picturing
|
||||
|
||||
CustomBlockDefinition.prototype.scriptsPicture = function () {
|
||||
return this.scriptsModel().scriptsPicture();
|
||||
};
|
||||
|
||||
CustomBlockDefinition.prototype.sortedElements = function () {
|
||||
return this.scriptsModel().sortedElements();
|
||||
};
|
||||
|
||||
CustomBlockDefinition.prototype.scriptsModel = function () {
|
||||
// answer a restored scripting area for the sake
|
||||
// of creating script pictures
|
||||
var scripts, proto, block, comment;
|
||||
|
||||
scripts = new ScriptsMorph();
|
||||
|
@ -372,7 +382,7 @@ CustomBlockDefinition.prototype.scriptsPicture = function () {
|
|||
});
|
||||
proto.children[0].fixLayout();
|
||||
scripts.fixMultiArgs();
|
||||
return scripts.scriptsPicture();
|
||||
return scripts;
|
||||
};
|
||||
|
||||
// CustomCommandBlockMorph /////////////////////////////////////////////
|
||||
|
|
183
gui.js
183
gui.js
|
@ -66,11 +66,11 @@ ScriptsMorph, isNil, SymbolMorph, BlockExportDialogMorph,
|
|||
BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph,
|
||||
SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512,
|
||||
sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio,
|
||||
SpeechBubbleMorph, ScriptFocusMorph*/
|
||||
SpeechBubbleMorph, ScriptFocusMorph, XML_Element*/
|
||||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.gui = '2015-September-07';
|
||||
modules.gui = '2015-October-02';
|
||||
|
||||
// Declarations
|
||||
|
||||
|
@ -2539,6 +2539,12 @@ IDE_Morph.prototype.projectMenu = function () {
|
|||
'show global custom block definitions as XML\nin a new browser window'
|
||||
);
|
||||
|
||||
menu.addItem(
|
||||
'Export summary...',
|
||||
function () {myself.exportProjectSummary(); },
|
||||
'open a new browser browser window\n with a summary of this project'
|
||||
);
|
||||
|
||||
if (shiftClicked) {
|
||||
menu.addItem(
|
||||
'Export all scripts as pic...',
|
||||
|
@ -3099,6 +3105,179 @@ IDE_Morph.prototype.exportScriptsPicture = function () {
|
|||
window.open(pic.toDataURL());
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.exportProjectSummary = function () {
|
||||
var html, head, meta, body, pname, notes, globalVars, globalBlocks;
|
||||
|
||||
function addNode(tag, node, contents) {
|
||||
if (!node) {node = body; }
|
||||
return new XML_Element(tag, contents, node);
|
||||
}
|
||||
|
||||
function add(contents, tag, node) {
|
||||
if (!tag) {tag = 'p'; }
|
||||
if (!node) {node = body; }
|
||||
return new XML_Element(tag, contents, node);
|
||||
}
|
||||
|
||||
function addImage(canvas, node, inline) {
|
||||
if (!node) {node = body; }
|
||||
var para = !inline ? addNode('p', node) : null,
|
||||
pic = addNode('img', para || node);
|
||||
pic.attributes.src = canvas.toDataURL();
|
||||
return pic;
|
||||
}
|
||||
|
||||
function addBlocks(definitions) {
|
||||
if (definitions.length) {
|
||||
add(localize('Blocks'), 'h3');
|
||||
SpriteMorph.prototype.categories.forEach(function (category) {
|
||||
var isFirst = true,
|
||||
ul;
|
||||
definitions.forEach(function (def) {
|
||||
var li;
|
||||
if (def.category === category) {
|
||||
if (isFirst) {
|
||||
add(
|
||||
localize(
|
||||
category[0].toUpperCase().concat(
|
||||
category.slice(1)
|
||||
)
|
||||
),
|
||||
'h4'
|
||||
);
|
||||
ul = addNode('ul');
|
||||
isFirst = false;
|
||||
}
|
||||
li = addNode('li', ul);
|
||||
addImage(def.templateInstance().scriptPic(), li);
|
||||
def.sortedElements().forEach(function (script) {
|
||||
addImage(
|
||||
script instanceof BlockMorph ?
|
||||
script.scriptPic()
|
||||
: script.fullImageClassic(),
|
||||
li
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pname = this.projectName || localize('untitled');
|
||||
|
||||
html = new XML_Element('html');
|
||||
html.attributes.contenteditable = 'true';
|
||||
|
||||
head = addNode('head', html);
|
||||
|
||||
meta = addNode('meta', head);
|
||||
meta.attributes['http-equiv'] = 'Content-Type';
|
||||
meta.attributes.content = 'text/html; charset=UTF-8';
|
||||
add(pname, 'title', head);
|
||||
|
||||
body = addNode('body', html);
|
||||
add(pname, 'h1');
|
||||
|
||||
/*
|
||||
if (SnapCloud.username) {
|
||||
add(localize('by ' + SnapCloud.username));
|
||||
}
|
||||
*/
|
||||
|
||||
add(this.serializer.app);
|
||||
addImage(this.stage.thumbnail(
|
||||
this.serializer.thumbnailSize.multiplyBy(2)
|
||||
));
|
||||
|
||||
// project notes
|
||||
notes = Process.prototype.reportTextSplit(this.projectNotes, 'line');
|
||||
notes.asArray().forEach(
|
||||
function (paragraph) {add(paragraph); }
|
||||
);
|
||||
|
||||
// sprites & stage
|
||||
this.sprites.asArray().concat([this.stage]).forEach(function (sprite) {
|
||||
var scripts = sprite.scripts.sortedElements(),
|
||||
varNames = sprite.variables.names(),
|
||||
cl = sprite.costumes.length(),
|
||||
ol;
|
||||
|
||||
add(sprite.name, 'h2');
|
||||
if (sprite instanceof SpriteMorph || sprite.costume) {
|
||||
addImage(sprite.image);
|
||||
}
|
||||
|
||||
// costumes
|
||||
if (cl > 1 || (sprite.getCostumeIdx() !== cl)) {
|
||||
add(localize('Costumes'), 'h3');
|
||||
ol = addNode('ol');
|
||||
sprite.costumes.asArray().forEach(function (costume) {
|
||||
var li = addNode('li', ol, costume.name);
|
||||
addNode('br', li);
|
||||
addImage(costume.thumbnail(new Point(40, 40)), li, true);
|
||||
});
|
||||
}
|
||||
|
||||
// sounds
|
||||
if (sprite.sounds.length()) {
|
||||
add(localize('Sounds'), 'h3');
|
||||
ol = addNode('ol');
|
||||
sprite.sounds.asArray().forEach(function (sound) {
|
||||
add(sound.name, 'li', ol);
|
||||
});
|
||||
}
|
||||
|
||||
// variables
|
||||
if (varNames.length) {
|
||||
add(localize('Variables'), 'h3');
|
||||
varNames.forEach(function (name) {
|
||||
addImage(
|
||||
SpriteMorph.prototype.variableBlock(name).scriptPic()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// scripts
|
||||
if (scripts.length) {
|
||||
add(localize('Scripts'), 'h3');
|
||||
scripts.forEach(function (script) {
|
||||
addImage(script instanceof BlockMorph ? script.scriptPic()
|
||||
: script.fullImageClassic());
|
||||
});
|
||||
}
|
||||
|
||||
// custom blocks
|
||||
addBlocks(sprite.customBlocks);
|
||||
});
|
||||
|
||||
// globals
|
||||
globalVars = this.stage.globalVariables().names();
|
||||
globalBlocks = this.stage.globalBlocks;
|
||||
|
||||
if (globalVars.length || globalBlocks.length) {
|
||||
addNode('hr');
|
||||
add(localize('For all Sprites'), 'h2');
|
||||
|
||||
// variables
|
||||
if (globalVars.length) {
|
||||
add(localize('Variables'), 'h3');
|
||||
globalVars.forEach(function (name) {
|
||||
addImage(
|
||||
SpriteMorph.prototype.variableBlock(name).scriptPic()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// custom blocks
|
||||
addBlocks(globalBlocks);
|
||||
}
|
||||
|
||||
window.open('data:text/html;charset=utf-8,' + encodeURIComponent(
|
||||
'<!DOCTYPE html>' + html.toString()
|
||||
));
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.openProjectString = function (str) {
|
||||
var msg,
|
||||
myself = this;
|
||||
|
|
|
@ -2579,3 +2579,9 @@ ______
|
|||
* Morphic, Objects: Improve display precision (stop rounding display coordinates)
|
||||
* Added “ceiling” function, thanks, Michael
|
||||
* Updated various translations
|
||||
|
||||
151002
|
||||
------
|
||||
* GUI, Blocks, BYOB: New “Export Project Summary” Feature, also: exporting script pics now includes attached comments
|
||||
* Blocks, Objects, Threads: Key hat block and key sensor support for “any” key
|
||||
* German translation update
|
||||
|
|
13
lang-de.js
13
lang-de.js
|
@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org', // optional
|
||||
'last_changed':
|
||||
'2015-09-23', // this, too, will appear in the Translators tab
|
||||
'2015-10-02', // this, too, will appear in the Translators tab
|
||||
|
||||
// GUI
|
||||
// control bar:
|
||||
|
@ -680,6 +680,15 @@ SnapTranslator.dict.de = {
|
|||
'Bl\u00f6cke exportieren...',
|
||||
'show global custom block definitions as XML\nin a new browser window':
|
||||
'zeigt globale Benutzerblockdefinitionen\nals XML im Browser an',
|
||||
'Export summary...':
|
||||
'Zusammenfassung exportieren...',
|
||||
'open a new browser browser window\n with a summary of this project':
|
||||
'eine Zusammenfassung diese Projects\nin einem neuen Browserfenster'
|
||||
+ 'anzeigen',
|
||||
'Blocks':
|
||||
'Bausteine',
|
||||
'For all Sprites':
|
||||
'F\u00fcr alle',
|
||||
'Import tools':
|
||||
'Tools laden',
|
||||
'load the official library of\npowerful blocks':
|
||||
|
@ -1302,5 +1311,5 @@ SnapTranslator.dict.de = {
|
|||
'last':
|
||||
'letztes',
|
||||
'any':
|
||||
'beliebiges'
|
||||
'beliebig'
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
/*global modules, contains*/
|
||||
|
||||
modules.locale = '2015-September-23';
|
||||
modules.locale = '2015-October-02';
|
||||
|
||||
// Global stuff
|
||||
|
||||
|
@ -149,7 +149,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org',
|
||||
'last_changed':
|
||||
'2015-09-23'
|
||||
'2015-10-02'
|
||||
};
|
||||
|
||||
SnapTranslator.dict.it = {
|
||||
|
|
|
@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.objects = '2015-September-23';
|
||||
modules.objects = '2015-October-02';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
@ -3673,7 +3673,8 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) {
|
|||
return this.scripts.children.filter(function (morph) {
|
||||
if (morph.selector) {
|
||||
if (morph.selector === 'receiveKey') {
|
||||
return morph.inputs()[0].evaluate()[0] === key;
|
||||
var evt = morph.inputs()[0].evaluate()[0];
|
||||
return evt === key || evt === 'any';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.threads = '2015-September-23';
|
||||
modules.threads = '2015-October-02';
|
||||
|
||||
var ThreadManager;
|
||||
var Process;
|
||||
|
@ -2636,6 +2636,9 @@ Process.prototype.reportKeyPressed = function (keyString) {
|
|||
if (this.homeContext.receiver) {
|
||||
stage = this.homeContext.receiver.parentThatIsA(StageMorph);
|
||||
if (stage) {
|
||||
if (this.inputOption(keyString) === 'any') {
|
||||
return Object.keys(stage.keysPressed).length > 0;
|
||||
}
|
||||
return stage.keysPressed[keyString] !== undefined;
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue