Merge remote-tracking branch 'jmoenig/master'

pull/29/head
Manuel Menezes de Sequeira 2016-11-24 21:36:28 +00:00
commit ad5e32203e
12 zmienionych plików z 2497 dodań i 115 usunięć

1
.gitignore vendored
Wyświetl plik

@ -1,2 +1,3 @@
.DS_Store .DS_Store
*.swp *.swp
.tern-port

479
blocks.js
Wyświetl plik

@ -149,7 +149,7 @@ isSnapObject, copy, PushButtonMorph, SpriteIconMorph, Process*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2016-October-31'; modules.blocks = '2016-November-24';
var SyntaxElementMorph; var SyntaxElementMorph;
var BlockMorph; var BlockMorph;
@ -1480,22 +1480,19 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
// allow GUI symbols as label icons // allow GUI symbols as label icons
// usage: $symbolName[-size-r-g-b], size and color values are optional // usage: $symbolName[-size-r-g-b], size and color values are optional
// If there isn't a symbol under that name, it just styles whatever is
// after "$", so you can add unicode icons to your blocks, for example
// ☺️
tokens = spec.slice(1).split('-'); tokens = spec.slice(1).split('-');
if (!contains(SymbolMorph.prototype.names, tokens[0])) { if (!contains(SymbolMorph.prototype.names, tokens[0])) {
part = new StringMorph(spec); part = new StringMorph(tokens[0]);
part.fontName = this.labelFontName; part.fontName = this.labelFontName;
part.fontStyle = this.labelFontStyle; part.fontStyle = this.labelFontStyle;
part.fontSize = this.fontSize; part.fontSize = this.fontSize * (+tokens[1] || 1);
part.color = new Color(255, 255, 255); } else {
part.isBold = true; part = new SymbolMorph(tokens[0]);
part.shadowColor = this.color.darker(this.labelContrast); part.size = this.fontSize * (+tokens[1] || 1.2);
part.shadowOffset = MorphicPreferences.isFlat ?
new Point() : this.embossing;
part.drawNew();
return part;
} }
part = new SymbolMorph(tokens[0]);
part.size = this.fontSize * (+tokens[1] || 1.2);
part.color = new Color( part.color = new Color(
+tokens[2] === 0 ? 0 : +tokens[2] || 255, +tokens[2] === 0 ? 0 : +tokens[2] || 255,
+tokens[3] === 0 ? 0 : +tokens[3] || 255, +tokens[3] === 0 ? 0 : +tokens[3] || 255,
@ -2381,8 +2378,15 @@ BlockMorph.prototype.userMenu = function () {
"duplicate", "duplicate",
function () { function () {
var dup = myself.fullCopy(), var dup = myself.fullCopy(),
ide = myself.parentThatIsA(IDE_Morph); ide = myself.parentThatIsA(IDE_Morph),
blockEditor = myself.parentThatIsA(BlockEditorMorph);
dup.pickUp(world); dup.pickUp(world);
// register the drop-origin, so the block can
// slide back to its former situation if dropped
// somewhere where it gets rejected
if (!ide && blockEditor) {
ide = blockEditor.target.parentThatIsA(IDE_Morph);
}
if (ide) { if (ide) {
world.hand.grabOrigin = { world.hand.grabOrigin = {
origin: ide.palette, origin: ide.palette,
@ -3491,12 +3495,14 @@ BlockMorph.prototype.reactToDropOf = function (droppedMorph) {
BlockMorph.prototype.situation = function () { BlockMorph.prototype.situation = function () {
// answer a dictionary specifying where I am right now, so // answer a dictionary specifying where I am right now, so
// I can slide back to it if I'm dropped somewhere else // I can slide back to it if I'm dropped somewhere else
var scripts = this.parentThatIsA(ScriptsMorph); if (!(this.parent instanceof TemplateSlotMorph)) {
if (scripts) { var scripts = this.parentThatIsA(ScriptsMorph);
return { if (scripts) {
origin: scripts, return {
position: this.position().subtract(scripts.position()) origin: scripts,
}; position: this.position().subtract(scripts.position())
};
}
} }
return BlockMorph.uber.situation.call(this); return BlockMorph.uber.situation.call(this);
}; };
@ -3709,6 +3715,20 @@ CommandBlockMorph.prototype.bottomAttachPoint = function () {
); );
}; };
CommandBlockMorph.prototype.wrapAttachPoint = function () {
var cslot = detect( // could be a method making uses of caching...
this.inputs(), // ... although these already are cached
function (each) {return each instanceof CSlotMorph; }
);
if (cslot && !cslot.nestedBlock()) {
return new Point(
cslot.left() + (cslot.inset * 2) + cslot.corner,
cslot.top() + (cslot.corner * 2)
);
}
return null;
};
CommandBlockMorph.prototype.dentLeft = function () { CommandBlockMorph.prototype.dentLeft = function () {
return this.left() return this.left()
+ this.corner + this.corner
@ -3722,16 +3742,27 @@ CommandBlockMorph.prototype.dentCenter = function () {
}; };
CommandBlockMorph.prototype.attachTargets = function () { CommandBlockMorph.prototype.attachTargets = function () {
var answer = []; var answer = [],
tp;
if (!(this instanceof HatBlockMorph)) { if (!(this instanceof HatBlockMorph)) {
tp = this.topAttachPoint();
if (!(this.parent instanceof SyntaxElementMorph)) { if (!(this.parent instanceof SyntaxElementMorph)) {
answer.push({ answer.push({
point: this.topAttachPoint(), point: tp,
element: this, element: this,
loc: 'top', loc: 'top',
type: 'block' type: 'block'
}); });
} }
if (ScriptsMorph.prototype.enableNestedAutoWrapping ||
!this.parentThatIsA(CommandSlotMorph)) {
answer.push({
point: tp,
element: this,
loc: 'wrap',
type: 'block'
});
}
} }
if (!this.isStop()) { if (!this.isStop()) {
answer.push({ answer.push({
@ -3780,7 +3811,8 @@ CommandBlockMorph.prototype.closestAttachTarget = function (newParent) {
), ),
dist, dist,
ref = [], ref = [],
minDist = 1000; minDist = 1000,
wrap;
if (!(this instanceof HatBlockMorph)) { if (!(this instanceof HatBlockMorph)) {
ref.push( ref.push(
@ -3789,6 +3821,15 @@ CommandBlockMorph.prototype.closestAttachTarget = function (newParent) {
loc: 'top' loc: 'top'
} }
); );
wrap = this.wrapAttachPoint();
if (wrap) {
ref.push(
{
point: wrap,
loc: 'wrap'
}
);
}
} }
if (!bottomBlock.isStop()) { if (!bottomBlock.isStop()) {
ref.push( ref.push(
@ -3798,10 +3839,14 @@ CommandBlockMorph.prototype.closestAttachTarget = function (newParent) {
} }
); );
} }
this.allAttachTargets(target).forEach(function (eachTarget) { this.allAttachTargets(target).forEach(function (eachTarget) {
ref.forEach(function (eachRef) { ref.forEach(function (eachRef) {
if (eachRef.loc !== eachTarget.loc) { // match: either both locs are 'wrap' or both are different,
// none being 'wrap' (can this be expressed any better?)
if ((eachRef.loc === 'wrap' && (eachTarget.loc === 'wrap')) ||
((eachRef.loc !== eachTarget.loc) &&
(eachRef.loc !== 'wrap') && (eachTarget.loc !== 'wrap'))
) {
dist = eachRef.point.distanceTo(eachTarget.point); dist = eachRef.point.distanceTo(eachTarget.point);
if ((dist < thresh) && (dist < minDist)) { if ((dist < thresh) && (dist < minDist)) {
minDist = dist; minDist = dist;
@ -3813,21 +3858,25 @@ CommandBlockMorph.prototype.closestAttachTarget = function (newParent) {
return answer; return answer;
}; };
CommandBlockMorph.prototype.snap = function () { CommandBlockMorph.prototype.snap = function (hand) {
var target = this.closestAttachTarget(), var target = this.closestAttachTarget(),
scripts = this.parentThatIsA(ScriptsMorph), scripts = this.parentThatIsA(ScriptsMorph),
before,
next, next,
offsetY, offsetY,
cslot,
affected; affected;
scripts.clearDropHistory(); scripts.clearDropInfo();
scripts.lastDroppedBlock = this; scripts.lastDroppedBlock = this;
if (target === null) { if (target === null) {
this.startLayout(); this.startLayout();
this.fixBlockColor(); this.fixBlockColor();
this.endLayout(); this.endLayout();
CommandBlockMorph.uber.snap.call(this); // align stuck comments CommandBlockMorph.uber.snap.call(this); // align stuck comments
if (hand) {
scripts.recordDrop(hand.grabOrigin);
}
return; return;
} }
@ -3860,10 +3909,38 @@ CommandBlockMorph.prototype.snap = function () {
this.setBottom(target.element.top() + this.corner - offsetY); this.setBottom(target.element.top() + this.corner - offsetY);
this.setLeft(target.element.left()); this.setLeft(target.element.left());
this.bottomBlock().nextBlock(target.element); this.bottomBlock().nextBlock(target.element);
} else if (target.loc === 'wrap') {
cslot = detect( // this should be a method making use of caching
this.inputs(), // these are already cached, so maybe it's okay
function (each) {return each instanceof CSlotMorph; }
);
// assume the cslot is (still) empty, was checked determining the target
before = (target.element.parent);
scripts.lastWrapParent = before;
// adjust position of wrapping block
this.moveBy(target.point.subtract(cslot.slotAttachPoint()));
// wrap c-slot around target
cslot.nestedBlock(target.element);
if (before instanceof CommandBlockMorph) {
before.nextBlock(this);
} else if (before instanceof CommandSlotMorph) {
before.nestedBlock(this);
}
// fix zebra coloring.
// this could probably be generalized into the fixBlockColor mechanism
target.element.blockSequence().forEach(
function (cmd) {cmd.fixBlockColor(); }
);
} }
this.fixBlockColor(); this.fixBlockColor();
this.endLayout(); this.endLayout();
CommandBlockMorph.uber.snap.call(this); // align stuck comments CommandBlockMorph.uber.snap.call(this); // align stuck comments
if (hand) {
scripts.recordDrop(hand.grabOrigin);
}
if (this.snapSound) { if (this.snapSound) {
this.snapSound.play(); this.snapSound.play();
} }
@ -3888,7 +3965,18 @@ CommandBlockMorph.prototype.userDestroy = function () {
this.userDestroyJustThis(); this.userDestroyJustThis();
return; return;
} }
var cslot = this.parentThatIsA(CSlotMorph);
var scripts = this.parentThatIsA(ScriptsMorph),
cslot = this.parentThatIsA(CSlotMorph);
// for undrop / redrop
if (scripts) {
scripts.clearDropInfo();
scripts.lastDroppedBlock = this;
scripts.recordDrop(this.situation());
scripts.dropRecord.action = 'delete';
}
this.destroy(); this.destroy();
if (cslot) { if (cslot) {
cslot.fixLayout(); cslot.fixLayout();
@ -3904,6 +3992,15 @@ CommandBlockMorph.prototype.userDestroyJustThis = function () {
above, above,
cslot = this.parentThatIsA(CSlotMorph); cslot = this.parentThatIsA(CSlotMorph);
// for undrop / redrop
if (scripts) {
scripts.clearDropInfo();
scripts.lastDroppedBlock = this;
scripts.recordDrop(this.situation());
scripts.dropRecord.lastNextBlock = nb;
scripts.dropRecord.action = 'delete';
}
this.topBlock().fullChanged(); this.topBlock().fullChanged();
if (this.parent) { if (this.parent) {
pb = this.parent.parentThatIsA(CommandBlockMorph); pb = this.parent.parentThatIsA(CommandBlockMorph);
@ -4525,7 +4622,7 @@ ReporterBlockMorph.prototype.snap = function (hand) {
return null; return null;
} }
scripts.clearDropHistory(); scripts.clearDropInfo();
scripts.lastDroppedBlock = this; scripts.lastDroppedBlock = this;
target = scripts.closestInput(this, hand); target = scripts.closestInput(this, hand);
@ -4555,6 +4652,9 @@ ReporterBlockMorph.prototype.snap = function (hand) {
this.fixBlockColor(); this.fixBlockColor();
this.endLayout(); this.endLayout();
ReporterBlockMorph.uber.snap.call(this); ReporterBlockMorph.uber.snap.call(this);
if (hand) {
scripts.recordDrop(hand.grabOrigin);
}
}; };
ReporterBlockMorph.prototype.prepareToBeGrabbed = function (handMorph) { ReporterBlockMorph.prototype.prepareToBeGrabbed = function (handMorph) {
@ -4693,6 +4793,16 @@ ReporterBlockMorph.prototype.ExportResultPic = function () {
ReporterBlockMorph.prototype.userDestroy = function () { ReporterBlockMorph.prototype.userDestroy = function () {
// make sure to restore default slot of parent block // make sure to restore default slot of parent block
// for undrop / redrop
var scripts = this.parentThatIsA(ScriptsMorph);
if (scripts) {
scripts.clearDropInfo();
scripts.lastDroppedBlock = this;
scripts.recordDrop(this.situation());
scripts.dropRecord.action = 'delete';
}
this.topBlock().fullChanged(); this.topBlock().fullChanged();
this.prepareToBeGrabbed(this.world().hand); this.prepareToBeGrabbed(this.world().hand);
this.destroy(); this.destroy();
@ -5159,7 +5269,10 @@ RingMorph.prototype.vanishForSimilar = function () {
|| (this.parent instanceof RingCommandSlotMorph)) { || (this.parent instanceof RingCommandSlotMorph)) {
return null; return null;
} }
if (block.selector === 'reportGetVar' || (block instanceof RingMorph)) { if (block.selector === 'reportGetVar' ||
block.selector === 'reportJSFunction' ||
(block instanceof RingMorph)
) {
this.parent.silentReplaceInput(this, block); this.parent.silentReplaceInput(this, block);
} }
}; };
@ -5215,6 +5328,7 @@ ScriptsMorph.prototype.cleanUpMargin = 20;
ScriptsMorph.prototype.cleanUpSpacing = 15; ScriptsMorph.prototype.cleanUpSpacing = 15;
ScriptsMorph.prototype.isPreferringEmptySlots = true; ScriptsMorph.prototype.isPreferringEmptySlots = true;
ScriptsMorph.prototype.enableKeyboard = true; ScriptsMorph.prototype.enableKeyboard = true;
ScriptsMorph.prototype.enableNestedAutoWrapping = false;
// ScriptsMorph instance creation: // ScriptsMorph instance creation:
@ -5234,6 +5348,7 @@ ScriptsMorph.prototype.init = function (owner) {
this.lastDropTarget = null; this.lastDropTarget = null;
this.lastPreservedBlocks = null; this.lastPreservedBlocks = null;
this.lastNextBlock = null; this.lastNextBlock = null;
this.lastWrapParent = null;
// keyboard editing support: // keyboard editing support:
this.focus = null; this.focus = null;
@ -5241,6 +5356,9 @@ ScriptsMorph.prototype.init = function (owner) {
ScriptsMorph.uber.init.call(this); ScriptsMorph.uber.init.call(this);
this.setColor(new Color(70, 70, 70)); this.setColor(new Color(70, 70, 70));
this.noticesTransparentClick = true; this.noticesTransparentClick = true;
// initialize "undrop" queue
this.recordDrop();
}; };
// ScriptsMorph deep copying: // ScriptsMorph deep copying:
@ -5347,6 +5465,10 @@ ScriptsMorph.prototype.showCommandDropFeedback = function (block) {
if (!target) { if (!target) {
return null; return null;
} }
if (target.loc === 'wrap') {
this.showCSlotWrapFeedback(block, target.element);
return;
}
this.add(this.feedbackMorph); this.add(this.feedbackMorph);
this.feedbackMorph.border = 0; this.feedbackMorph.border = 0;
this.feedbackMorph.edge = 0; this.feedbackMorph.edge = 0;
@ -5403,6 +5525,24 @@ ScriptsMorph.prototype.showCommentDropFeedback = function (comment, hand) {
this.feedbackMorph.changed(); this.feedbackMorph.changed();
}; };
ScriptsMorph.prototype.showCSlotWrapFeedback = function (srcBlock, trgBlock) {
var clr;
this.feedbackMorph.bounds = trgBlock.fullBounds()
.expandBy(BlockMorph.prototype.corner);
this.feedbackMorph.edge = SyntaxElementMorph.prototype.corner;
this.feedbackMorph.border = Math.max(
SyntaxElementMorph.prototype.edge,
3
);
this.add(this.feedbackMorph);
clr = srcBlock.color.lighter(40);
this.feedbackMorph.color = clr.copy();
this.feedbackMorph.color.a = 0.1;
this.feedbackMorph.borderColor = clr;
this.feedbackMorph.drawNew();
this.feedbackMorph.changed();
};
ScriptsMorph.prototype.closestInput = function (reporter, hand) { ScriptsMorph.prototype.closestInput = function (reporter, hand) {
// passing the hand is optional (when dragging reporters) // passing the hand is optional (when dragging reporters)
var fb = reporter.fullBoundsNoShadow(), var fb = reporter.fullBoundsNoShadow(),
@ -5552,6 +5692,7 @@ ScriptsMorph.prototype.userMenu = function () {
blockEditor, blockEditor,
myself = this, myself = this,
obj = this.owner, obj = this.owner,
hasUndropQueue,
stage = obj.parentThatIsA(StageMorph); stage = obj.parentThatIsA(StageMorph);
if (!ide) { if (!ide) {
@ -5560,15 +5701,30 @@ ScriptsMorph.prototype.userMenu = function () {
ide = blockEditor.target.parentThatIsA(IDE_Morph); ide = blockEditor.target.parentThatIsA(IDE_Morph);
} }
} }
if (this.dropRecord) {
if (this.dropRecord.lastRecord) {
hasUndropQueue = true;
menu.addItem(
'undrop',
'undrop',
'undo the last\nblock drop\nin this pane'
);
}
if (this.dropRecord.nextRecord) {
hasUndropQueue = true;
menu.addItem(
'redrop',
'redrop',
'redo the last undone\nblock drop\nin this pane'
);
}
if (hasUndropQueue) {
menu.addLine();
}
}
menu.addItem('clean up', 'cleanUp', 'arrange scripts\nvertically'); menu.addItem('clean up', 'cleanUp', 'arrange scripts\nvertically');
menu.addItem('add comment', 'addComment'); menu.addItem('add comment', 'addComment');
if (this.lastDroppedBlock) {
menu.addItem(
'undrop',
'undrop',
'undo the last\nblock drop\nin this pane'
);
}
menu.addItem( menu.addItem(
'scripts pic...', 'scripts pic...',
'exportScriptsPicture', 'exportScriptsPicture',
@ -5671,59 +5827,210 @@ ScriptsMorph.prototype.scriptsPicture = function () {
}; };
ScriptsMorph.prototype.addComment = function () { ScriptsMorph.prototype.addComment = function () {
new CommentMorph().pickUp(this.world()); var ide = this.parentThatIsA(IDE_Morph),
blockEditor = this.parentThatIsA(BlockEditorMorph),
world = this.world();
new CommentMorph().pickUp(world);
// register the drop-origin, so the element can
// slide back to its former situation if dropped
// somewhere where it gets rejected
if (!ide && blockEditor) {
ide = blockEditor.target.parentThatIsA(IDE_Morph);
}
if (ide) {
world.hand.grabOrigin = {
origin: ide.palette,
position: ide.palette.center()
};
}
}; };
ScriptsMorph.prototype.undrop = function () { ScriptsMorph.prototype.undrop = function () {
if (!this.lastDroppedBlock) {return; } if (!this.dropRecord || !this.dropRecord.lastRecord) {return; }
if (this.lastDroppedBlock instanceof CommandBlockMorph) { if (!this.dropRecord.situation) {
if (this.lastNextBlock) { this.dropRecord.situation =
this.add(this.lastNextBlock); this.dropRecord.lastDroppedBlock.situation();
}
this.dropRecord.lastDroppedBlock.slideBackTo(
this.dropRecord.lastOrigin,
null,
this.recoverLastDrop()
);
this.dropRecord = this.dropRecord.lastRecord;
};
ScriptsMorph.prototype.redrop = function () {
if (!this.dropRecord || !this.dropRecord.nextRecord) {return; }
this.dropRecord = this.dropRecord.nextRecord;
if (this.dropRecord.action === 'delete') {
this.recoverLastDrop(true);
this.dropRecord.lastDroppedBlock.destroy();
} else {
this.dropRecord.lastDroppedBlock.slideBackTo(
this.dropRecord.situation,
null,
this.recoverLastDrop(true)
);
}
};
ScriptsMorph.prototype.recoverLastDrop = function (forRedrop) {
// retrieve the block last touched by the user and answer a function
// to be called after the animation that moves it back right before
// dropping it into its former situation
var rec = this.dropRecord,
dropped,
onBeforeDrop,
parent;
if (!rec || !rec.lastDroppedBlock) {
throw new Error('nothing to undrop');
}
dropped = rec.lastDroppedBlock;
parent = dropped.parent;
if (dropped instanceof CommandBlockMorph) {
if (rec.lastNextBlock) {
if (rec.action === 'delete') {
if (forRedrop) {
this.add(rec.lastNextBlock);
}
} else {
this.add(rec.lastNextBlock);
}
} }
if (this.lastDropTarget) { if (rec.lastDropTarget) {
if (this.lastDropTarget.loc === 'bottom') { if (rec.lastDropTarget.loc === 'bottom') {
if (this.lastDropTarget.type === 'slot') { if (rec.lastDropTarget.type === 'slot') {
if (this.lastNextBlock) { if (rec.lastNextBlock) {
this.lastDropTarget.element.nestedBlock( rec.lastDropTarget.element.nestedBlock(
this.lastNextBlock rec.lastNextBlock
); );
} }
} else { // 'block' } else { // 'block'
if (this.lastNextBlock) { if (rec.lastNextBlock) {
this.lastDropTarget.element.nextBlock( rec.lastDropTarget.element.nextBlock(
this.lastNextBlock rec.lastNextBlock
); );
} }
} }
} else if (this.lastDropTarget.loc === 'top') { } else if (rec.lastDropTarget.loc === 'top') {
this.add(this.lastDropTarget.element); this.add(rec.lastDropTarget.element);
} else if (rec.lastDropTarget.loc === 'wrap') {
var cslot = detect( // could be cached...
rec.lastDroppedBlock.inputs(), // ...although these are
function (each) {return each instanceof CSlotMorph; }
);
if (rec.lastWrapParent instanceof CommandBlockMorph) {
if (forRedrop) {
onBeforeDrop = function () {
cslot.nestedBlock(rec.lastDropTarget.element);
};
} else {
rec.lastWrapParent.nextBlock(
rec.lastDropTarget.element
);
}
} else if (rec.lastWrapParent instanceof CommandSlotMorph) {
if (forRedrop) {
onBeforeDrop = function () {
cslot.nestedBlock(rec.lastDropTarget.element);
};
} else {
rec.lastWrapParent.nestedBlock(
rec.lastDropTarget.element
);
}
} else {
this.add(rec.lastDropTarget.element);
}
// fix zebra coloring.
// this could be generalized into the fixBlockColor mechanism
rec.lastDropTarget.element.blockSequence().forEach(
function (cmd) {cmd.fixBlockColor(); }
);
cslot.fixLayout();
} }
} }
} else { // ReporterBlockMorph } else if (dropped instanceof ReporterBlockMorph) {
if (this.lastDropTarget) { if (rec.lastDropTarget) {
this.lastDropTarget.replaceInput( rec.lastDropTarget.replaceInput(
this.lastDroppedBlock, rec.lastDroppedBlock,
this.lastReplacedInput rec.lastReplacedInput
); );
this.lastDropTarget.fixBlockColor(null, true); rec.lastDropTarget.fixBlockColor(null, true);
if (this.lastPreservedBlocks) { if (rec.lastPreservedBlocks) {
this.lastPreservedBlocks.forEach(function (morph) { rec.lastPreservedBlocks.forEach(function (morph) {
morph.destroy(); morph.destroy();
}); });
} }
} }
} else if (dropped instanceof CommentMorph) {
if (forRedrop && rec.lastDropTarget) {
onBeforeDrop = function () {
rec.lastDropTarget.element.comment = dropped;
dropped.block = rec.lastDropTarget.element;
dropped.align();
};
}
} else {
throw new Error('unsupported action for ' + dropped);
} }
this.lastDroppedBlock.pickUp(this.world()); this.clearDropInfo();
this.clearDropHistory(); dropped.prepareToBeGrabbed(this.world().hand);
if (dropped instanceof CommentMorph) {
dropped.removeShadow();
}
this.add(dropped);
parent.reactToGrabOf(dropped);
if (dropped instanceof ReporterBlockMorph && parent instanceof BlockMorph) {
parent.changed();
}
if (rec.action === 'delete') {
if (forRedrop && rec.lastNextBlock) {
if (parent instanceof CommandBlockMorph) {
parent.nextBlock(rec.lastNextBlock);
} else if (parent instanceof CommandSlotMorph) {
parent.nestedBlock(rec.lastNextBlock);
}
}
// animate "undelete"
if (!forRedrop) {
dropped.moveBy(new Point(-100, -20));
}
}
return onBeforeDrop;
}; };
ScriptsMorph.prototype.clearDropInfo = function () {
ScriptsMorph.prototype.clearDropHistory = function () {
this.lastDroppedBlock = null; this.lastDroppedBlock = null;
this.lastReplacedInput = null; this.lastReplacedInput = null;
this.lastDropTarget = null; this.lastDropTarget = null;
this.lastPreservedBlocks = null; this.lastPreservedBlocks = null;
this.lastNextBlock = null; this.lastNextBlock = null;
this.lastWrapParent = null;
};
ScriptsMorph.prototype.recordDrop = function (lastGrabOrigin) {
// support for "undrop" / "redrop"
var record = {
lastDroppedBlock: this.lastDroppedBlock,
lastReplacedInput: this.lastReplacedInput,
lastDropTarget: this.lastDropTarget,
lastPreservedBlocks: this.lastPreservedBlocks,
lastNextBlock: this.lastNextBlock,
lastWrapParent: this.lastWrapParent,
lastOrigin: lastGrabOrigin,
action: null,
situation: null,
lastRecord: this.dropRecord,
nextRecord: null
};
if (this.dropRecord) {
this.dropRecord.nextRecord = record;
}
this.dropRecord = record;
}; };
// ScriptsMorph sorting blocks and comments // ScriptsMorph sorting blocks and comments
@ -5860,7 +6167,6 @@ ArgMorph.prototype.reactToSliderEdit = function () {
} }
}; };
// ArgMorph drag & drop: for demo puposes only // ArgMorph drag & drop: for demo puposes only
ArgMorph.prototype.justDropped = function () { ArgMorph.prototype.justDropped = function () {
@ -8020,6 +8326,18 @@ TemplateSlotMorph.prototype.fixLayout = function () {
} }
}; };
// TemplateSlotMorph drop behavior:
TemplateSlotMorph.prototype.wantsDropOf = function (aMorph) {
return aMorph.selector === 'reportGetVar';
};
TemplateSlotMorph.prototype.reactToDropOf = function (droppedMorph) {
if (droppedMorph.selector === 'reportGetVar') {
droppedMorph.destroy();
}
};
// TemplateSlotMorph drawing: // TemplateSlotMorph drawing:
TemplateSlotMorph.prototype.drawNew = function () { TemplateSlotMorph.prototype.drawNew = function () {
@ -11829,7 +12147,7 @@ CommentMorph.prototype.show = function () {
// CommentMorph dragging & dropping // CommentMorph dragging & dropping
CommentMorph.prototype.prepareToBeGrabbed = function () { CommentMorph.prototype.prepareToBeGrabbed = function (hand) {
// disassociate from the block I'm posted to // disassociate from the block I'm posted to
if (this.block) { if (this.block) {
this.block.comment = null; this.block.comment = null;
@ -11852,19 +12170,22 @@ CommentMorph.prototype.snap = function (hand) {
if (!(scripts instanceof ScriptsMorph)) { if (!(scripts instanceof ScriptsMorph)) {
return null; return null;
} }
scripts.clearDropInfo();
scripts.clearDropHistory();
scripts.lastDroppedBlock = this;
target = scripts.closestBlock(this, hand); target = scripts.closestBlock(this, hand);
if (target !== null) { if (target !== null) {
target.comment = this; target.comment = this;
this.block = target; this.block = target;
if (this.snapSound) { if (this.snapSound) {
this.snapSound.play(); this.snapSound.play();
} }
scripts.lastDropTarget = {element: target};
} }
this.align(); this.align();
scripts.lastDroppedBlock = this;
if (hand) {
scripts.recordDrop(hand.grabOrigin);
}
}; };
// CommentMorph sticking to blocks // CommentMorph sticking to blocks
@ -12542,6 +12863,16 @@ ScriptFocusMorph.prototype.sortedScripts = function () {
return scripts; return scripts;
}; };
// ScriptFocusMorph undo / redo
ScriptFocusMorph.prototype.undrop = function () {
this.editor.undrop();
};
ScriptFocusMorph.prototype.redrop = function () {
this.editor.redrop();
};
// ScriptFocusMorph block types // ScriptFocusMorph block types
ScriptFocusMorph.prototype.blockTypes = function () { ScriptFocusMorph.prototype.blockTypes = function () {
@ -12685,6 +13016,12 @@ ScriptFocusMorph.prototype.reactToKeyEvent = function (key) {
return this.lastScript(); return this.lastScript();
case 'backspace': case 'backspace':
return this.deleteLastElement(); return this.deleteLastElement();
case 'ctrl z':
return this.undrop();
case 'ctrl shift z':
return this.redrop();
case 'ctrl [': // ignore the first press of the Mac cmd key
return;
default: default:
types = this.blockTypes(); types = this.blockTypes();
if (!(this.element instanceof ScriptsMorph) && if (!(this.element instanceof ScriptsMorph) &&

66
gui.js
Wyświetl plik

@ -72,7 +72,7 @@ isRetinaSupported, SliderMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.gui = '2016-October-31'; modules.gui = '2016-November-22';
// Declarations // Declarations
@ -454,6 +454,20 @@ IDE_Morph.prototype.openIn = function (world) {
}, },
this.cloudError() this.cloudError()
); );
} else if (location.hash.substr(0, 4) === '#dl:') {
myself.showMessage('Fetching project\nfrom the cloud...');
// make sure to lowercase the username
dict = SnapCloud.parseDict(location.hash.substr(4));
dict.Username = dict.Username.toLowerCase();
SnapCloud.getPublicProject(
SnapCloud.encodeDict(dict),
function (projectData) {
window.open('data:text/xml,' + projectData);
},
this.cloudError()
);
} else if (location.hash.substr(0, 6) === '#lang:') { } else if (location.hash.substr(0, 6) === '#lang:') {
urlLanguage = location.hash.substr(6); urlLanguage = location.hash.substr(6);
this.setLanguage(urlLanguage); this.setLanguage(urlLanguage);
@ -1023,7 +1037,7 @@ IDE_Morph.prototype.createPalette = function (forSearching) {
this.palette.enableAutoScrolling = false; this.palette.enableAutoScrolling = false;
this.palette.contents.acceptsDrops = false; this.palette.contents.acceptsDrops = false;
this.palette.reactToDropOf = function (droppedMorph) { this.palette.reactToDropOf = function (droppedMorph, hand) {
if (droppedMorph instanceof DialogBoxMorph) { if (droppedMorph instanceof DialogBoxMorph) {
myself.world().add(droppedMorph); myself.world().add(droppedMorph);
} else if (droppedMorph instanceof SpriteMorph) { } else if (droppedMorph instanceof SpriteMorph) {
@ -1034,11 +1048,25 @@ IDE_Morph.prototype.createPalette = function (forSearching) {
} else if (droppedMorph instanceof CostumeIconMorph) { } else if (droppedMorph instanceof CostumeIconMorph) {
myself.currentSprite.wearCostume(null); myself.currentSprite.wearCostume(null);
droppedMorph.destroy(); droppedMorph.destroy();
} else if (droppedMorph instanceof BlockMorph) {
if (hand && hand.grabOrigin.origin instanceof ScriptsMorph) {
hand.grabOrigin.origin.clearDropInfo();
hand.grabOrigin.origin.lastDroppedBlock = droppedMorph;
hand.grabOrigin.origin.recordDrop(hand.grabOrigin);
}
droppedMorph.destroy();
} else { } else {
droppedMorph.destroy(); droppedMorph.destroy();
} }
}; };
this.palette.contents.reactToDropOf = function (droppedMorph) {
// for "undrop" operation
if (droppedMorph instanceof BlockMorph) {
droppedMorph.destroy();
}
};
this.palette.setWidth(this.logo.width()); this.palette.setWidth(this.logo.width());
this.add(this.palette); this.add(this.palette);
return this.palette; return this.palette;
@ -1947,7 +1975,8 @@ IDE_Morph.prototype.applySavedSettings = function () {
plainprototype = this.getSetting('plainprototype'), plainprototype = this.getSetting('plainprototype'),
keyboard = this.getSetting('keyboard'), keyboard = this.getSetting('keyboard'),
tables = this.getSetting('tables'), tables = this.getSetting('tables'),
tableLines = this.getSetting('tableLines'); tableLines = this.getSetting('tableLines'),
autoWrapping = this.getSetting('autowrapping');
// design // design
if (design === 'flat') { if (design === 'flat') {
@ -2008,6 +2037,13 @@ IDE_Morph.prototype.applySavedSettings = function () {
TableMorph.prototype.highContrast = false; TableMorph.prototype.highContrast = false;
} }
// nested auto-wrapping
if (autoWrapping) {
ScriptsMorph.prototype.enableNestedAutoWrapping = true;
} else {
ScriptsMorph.prototype.enableNestedAutoWrapping = false;
}
// plain prototype labels // plain prototype labels
if (plainprototype) { if (plainprototype) {
BlockLabelPlaceHolderMorph.prototype.plainLabel = true; BlockLabelPlaceHolderMorph.prototype.plainLabel = true;
@ -2509,6 +2545,22 @@ IDE_Morph.prototype.settingsMenu = function () {
'check for alternative\nGUI design', 'check for alternative\nGUI design',
false false
); );
addPreference(
'Nested auto-wrapping',
function () {
ScriptsMorph.prototype.enableNestedAutoWrapping =
!ScriptsMorph.prototype.enableNestedAutoWrapping;
if (ScriptsMorph.prototype.enableNestedAutoWrapping) {
myself.saveSetting('autowrapping', true);
} else {
myself.removeSetting('autowrapping');
}
},
ScriptsMorph.prototype.enableNestedAutoWrapping,
'uncheck to confine auto-wrapping\nto top-level block stacks',
'check to enable auto-wrapping\ninside nested block stacks',
false
);
addPreference( addPreference(
'Project URLs', 'Project URLs',
function () { function () {
@ -3049,7 +3101,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world(); world = this.world();
aboutTxt = 'Snap! 4.0.9.1\nBuild Your Own Blocks\n\n' aboutTxt = 'Snap! 4.0.10 - dev -\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2016 Jens M\u00F6nig and ' + 'Copyright \u24B8 2016 Jens M\u00F6nig and '
+ 'Brian Harvey\n' + 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@ -3579,13 +3631,13 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
pname = this.projectName || localize('untitled'); pname = this.projectName || localize('untitled');
html = new XML_Element('html'); html = new XML_Element('html');
html.attributes.lang = SnapTranslator.language;
// html.attributes.contenteditable = 'true'; // html.attributes.contenteditable = 'true';
head = addNode('head', html); head = addNode('head', html);
meta = addNode('meta', head); meta = addNode('meta', head);
meta.attributes['http-equiv'] = 'Content-Type'; meta.attributes.charset = 'UTF-8';
meta.attributes.content = 'text/html; charset=UTF-8';
if (useDropShadows) { if (useDropShadows) {
css = 'img {' + css = 'img {' +
@ -3752,7 +3804,7 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
this.saveFileAs( this.saveFileAs(
'<!DOCTYPE html>' + html.toString(), '<!DOCTYPE html>' + html.toString(),
'text/html;charset=utf-8,', 'text/html;charset=utf-8',
pname, pname,
true // request opening a new window. true // request opening a new window.
); );

Wyświetl plik

@ -3090,3 +3090,48 @@ http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=rotation
161027 161027
------ ------
== v4.0.9 ==== == v4.0.9 ====
== v4.0.9.1 ====
161110
------
* new Galician translation, yay!! Thanks, tecnoloxia.org!
* Italian translation update
* German translation update
== v4.0.9.2 ====
*** in development ***
161107
------
* New C-Slot auto-wrapping / snapping feature (similar to Scratch)
161109
------
* Blocks, GUI: preference setting to enable auto-wrapping inside nested block stacks
* Blocks: Treat JS-function reporters the same as variable getters wrt rings
* German translation update
161114
------
* Blocks, Objects: Unlimited “Undrop / Redrop” of block drops per script pane and session (under construction)
* GUI: new url switch #dl: for downloading raw shared projects
161121
------
* Blocks: Delete variable getter blocks if the user drops them on template slots (e.g. script vars)
161122
------
* Blocks, GUI: “Undrop / Redrop” for deleting blocks via the context menu or in keyboard edit mode
* Morphic: support “onBeforeDrop” callback parameter in slideBackTo()
161123
------
* Blocks, Morphic: “Undrop / Redrop” support for sticky comments
161124
------
* Morphic, Store: work around a dreaded FF NS_ERROR_FAILURE for supporting retina
* Blocks: drag-origin support for blocks and comments duplicated inside a block editor

Wyświetl plik

@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
'translator_e-mail': 'translator_e-mail':
'jens@moenig.org', // optional 'jens@moenig.org', // optional
'last_changed': 'last_changed':
'2016-10-27', // this, too, will appear in the Translators tab '2016-11-22', // this, too, will appear in the Translators tab
// GUI // GUI
// control bar: // control bar:
@ -225,6 +225,8 @@ SnapTranslator.dict.de = {
'Skripte', 'Skripte',
'Costumes': 'Costumes':
'Kost\u00fcme', 'Kost\u00fcme',
'Backgrounds':
'Hintergr\u00fcnde',
'Sounds': 'Sounds':
'Kl\u00e4nge', 'Kl\u00e4nge',
@ -815,6 +817,8 @@ SnapTranslator.dict.de = {
'einschalten um IDE-\nAnimationen zu erlauben', 'einschalten um IDE-\nAnimationen zu erlauben',
'Flat design': 'Flat design':
'Helles Design', 'Helles Design',
'Nested auto-wrapping':
'Automatisches Umklammern',
'Keyboard Editing': 'Keyboard Editing':
'Tastaturunterstützung', 'Tastaturunterstützung',
'Table support': 'Table support':
@ -929,6 +933,8 @@ SnapTranslator.dict.de = {
'R\u00fcckg\u00e4ngig', 'R\u00fcckg\u00e4ngig',
'undo the last\nblock drop\nin this pane': 'undo the last\nblock drop\nin this pane':
'Setzen des letzten Blocks\nwiderrufen', 'Setzen des letzten Blocks\nwiderrufen',
'redrop':
'Wiederherstellen',
'scripts pic...': 'scripts pic...':
'Bild aller Scripte...', 'Bild aller Scripte...',
'open a new window\nwith a picture of all scripts': 'open a new window\nwith a picture of all scripts':

1909
lang-gl.js 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -185,7 +185,7 @@ SnapTranslator.dict.it = {
'translator_e-mail': 'translator_e-mail':
's_federici@yahoo.com, albertofirpo12@gmail.com, zairik@gmail.com', // optional 's_federici@yahoo.com, albertofirpo12@gmail.com, zairik@gmail.com', // optional
'last_changed': 'last_changed':
'2016-05-10', // this, too, will appear in the Translators tab '2016-10-31', // this, too, will appear in the Translators tab
// GUI // GUI
// control bar: // control bar:
@ -683,6 +683,11 @@ SnapTranslator.dict.it = {
'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!':
'Abilita i menu contestuali\ndi Morphic e l\'inspector,\n non user-friendly', 'Abilita i menu contestuali\ndi Morphic e l\'inspector,\n non user-friendly',
'Export summary...':
'Esporta sommario...',
'open a new browser browser window\n with a summary of this project':
'apre una nuova finestra del browser\ncon un sommario del progetto',
// project menu // project menu
'Project notes...': 'Project notes...':
'Note di Progetto...', 'Note di Progetto...',
@ -859,6 +864,12 @@ SnapTranslator.dict.it = {
'Supporto per le tabelle', 'Supporto per le tabelle',
'Table lines': 'Table lines':
'Tabelle con linee', 'Tabelle con linee',
'Visible stepping':
'Evidenzia esecuzione',
'uncheck to turn off\nvisible stepping':
'Deseleziona per disattivare la\nevidenziazione dell\'esecuzione',
'check to turn on\n visible stepping (slow)':
'Seleziona per attivare la\nevidenziazione dell\'esecuzione',
'check for multi-column\nlist view support': 'check for multi-column\nlist view support':
'attiva la vista multicolonna', 'attiva la vista multicolonna',
'uncheck to disable\nmulti-column list views': 'uncheck to disable\nmulti-column list views':

Wyświetl plik

@ -42,7 +42,7 @@
/*global modules, contains*/ /*global modules, contains*/
modules.locale = '2016-October-31'; modules.locale = '2016-November-22';
// Global stuff // Global stuff
@ -160,7 +160,7 @@ SnapTranslator.dict.de = {
'translator_e-mail': 'translator_e-mail':
'jens@moenig.org', 'jens@moenig.org',
'last_changed': 'last_changed':
'2016-10-27' '2016-11-22'
}; };
SnapTranslator.dict.it = { SnapTranslator.dict.it = {
@ -558,3 +558,14 @@ SnapTranslator.dict.et = {
'last_changed': 'last_changed':
'2016-05-03' '2016-05-03'
}; };
SnapTranslator.dict.gl = {
'language_name':
'Galego',
'language_translator':
'tecnoloxia',
'translator_e-mail':
'',
'last_changed':
'2016-11-09'
};

Wyświetl plik

@ -1,13 +0,0 @@
CACHE MANIFEST
snap.html
blocks.js
byob.js
gui.js
lists.js
morphic.js
objects.js
threads.js
widgets.js
store.js
xml.js
snap_logo_sm.png

Wyświetl plik

@ -1103,7 +1103,7 @@
/*global window, HTMLCanvasElement, FileReader, Audio, FileList*/ /*global window, HTMLCanvasElement, FileReader, Audio, FileList*/
var morphicVersion = '2016-October-27'; var morphicVersion = '2016-November-24';
var modules = {}; // keep track of additional loaded modules var modules = {}; // keep track of additional loaded modules
var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
@ -1508,9 +1508,9 @@ function enableRetinaSupport() {
return this._isRetinaEnabled; return this._isRetinaEnabled;
}, },
set: function(enabled) { set: function(enabled) {
var prevPixelRatio = getPixelRatio(this); var prevPixelRatio = getPixelRatio(this),
var prevWidth = this.width; prevWidth = this.width,
var prevHeight = this.height; prevHeight = this.height;
this._isRetinaEnabled = enabled; this._isRetinaEnabled = enabled;
if (getPixelRatio(this) != prevPixelRatio) { if (getPixelRatio(this) != prevPixelRatio) {
@ -1526,12 +1526,19 @@ function enableRetinaSupport() {
return uber.width.get.call(this) / getPixelRatio(this); return uber.width.get.call(this) / getPixelRatio(this);
}, },
set: function(width) { set: function(width) {
var pixelRatio = getPixelRatio(this); try { // workaround one of FF's dreaded NS_ERROR_FAILURE bugs
uber.width.set.call(this, width * pixelRatio); // this should be taken out as soon as FF gets fixed again
var context = this.getContext('2d'); var pixelRatio = getPixelRatio(this),
context.restore(); context;
context.save(); uber.width.set.call(this, width * pixelRatio);
context.scale(pixelRatio, pixelRatio); context = this.getContext('2d');
context.restore();
context.save();
context.scale(pixelRatio, pixelRatio);
} catch (err) {
console.log('Retina Display Support Problem', err);
uber.width.set.call(this, width);
}
} }
}); });
@ -1540,9 +1547,10 @@ function enableRetinaSupport() {
return uber.height.get.call(this) / getPixelRatio(this); return uber.height.get.call(this) / getPixelRatio(this);
}, },
set: function(height) { set: function(height) {
var pixelRatio = getPixelRatio(this); var pixelRatio = getPixelRatio(this),
context;
uber.height.set.call(this, height * pixelRatio); uber.height.set.call(this, height * pixelRatio);
var context = this.getContext('2d'); context = this.getContext('2d');
context.restore(); context.restore();
context.save(); context.save();
context.scale(pixelRatio, pixelRatio); context.scale(pixelRatio, pixelRatio);
@ -3605,7 +3613,7 @@ Morph.prototype.situation = function () {
return null; return null;
}; };
Morph.prototype.slideBackTo = function (situation, inSteps) { Morph.prototype.slideBackTo = function (situation, inSteps, onBeforeDrop) {
var steps = inSteps || 5, var steps = inSteps || 5,
pos = situation.origin.position().add(situation.position), pos = situation.origin.position().add(situation.position),
xStep = -(this.left() - pos.x) / steps, xStep = -(this.left() - pos.x) / steps,
@ -3621,6 +3629,8 @@ Morph.prototype.slideBackTo = function (situation, inSteps) {
stepCount += 1; stepCount += 1;
if (stepCount === steps) { if (stepCount === steps) {
situation.origin.add(myself); situation.origin.add(myself);
if (onBeforeDrop) {onBeforeDrop(); }
if (myself.justDropped) {myself.justDropped(); }
if (situation.origin.reactToDropOf) { if (situation.origin.reactToDropOf) {
situation.origin.reactToDropOf(myself); situation.origin.reactToDropOf(myself);
} }

Wyświetl plik

@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize, BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/ TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/
modules.objects = '2016-October-27'; modules.objects = '2016-November-22';
var SpriteMorph; var SpriteMorph;
var StageMorph; var StageMorph;
@ -5629,6 +5629,14 @@ StageMorph.prototype.fireKeyEvent = function (key) {
if (!ide.isAppMode) {ide.currentSprite.searchBlocks(); } if (!ide.isAppMode) {ide.currentSprite.searchBlocks(); }
return; return;
} }
if (evt === 'ctrl z') {
if (!ide.isAppMode) {ide.currentSprite.scripts.undrop(); }
return;
}
if (evt === 'ctrl shift z') {
if (!ide.isAppMode) {ide.currentSprite.scripts.redrop(); }
return;
}
if (evt === 'ctrl n') { if (evt === 'ctrl n') {
if (!ide.isAppMode) {ide.createNewProject(); } if (!ide.isAppMode) {ide.createNewProject(); }
return; return;

Wyświetl plik

@ -61,7 +61,7 @@ normalizeCanvas*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.store = '2016-October-27'; modules.store = '2016-November-24';
// XML_Serializer /////////////////////////////////////////////////////// // XML_Serializer ///////////////////////////////////////////////////////
@ -390,10 +390,12 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
if (model.pentrails) { if (model.pentrails) {
project.pentrails = new Image(); project.pentrails = new Image();
project.pentrails.onload = function () { project.pentrails.onload = function () {
normalizeCanvas(project.stage.trailsCanvas); if (project.stage.trailsCanvas) { // work-around a bug in FF
var context = project.stage.trailsCanvas.getContext('2d'); normalizeCanvas(project.stage.trailsCanvas);
context.drawImage(project.pentrails, 0, 0); var context = project.stage.trailsCanvas.getContext('2d');
project.stage.changed(); context.drawImage(project.pentrails, 0, 0);
project.stage.changed();
}
}; };
project.pentrails.src = model.pentrails.contents; project.pentrails.src = model.pentrails.contents;
} }
@ -1128,7 +1130,10 @@ SnapSerializer.prototype.loadInput = function (model, input, block) {
input.setColor(this.loadColor(model.contents)); input.setColor(this.loadColor(model.contents));
} else { } else {
val = this.loadValue(model); val = this.loadValue(model);
if (!isNil(val) && input.setContents) { if (!isNil(val) && !isNil(input) && input.setContents) {
// checking whether "input" is nil should not
// be necessary, but apparently is after retina support
// was added.
input.setContents(this.loadValue(model)); input.setContents(this.loadValue(model));
} }
} }