diff options
| -rw-r--r-- | blocks.js | 106 | ||||
| -rw-r--r-- | byob.js | 2 | ||||
| -rw-r--r-- | gui.js | 6 | ||||
| -rwxr-xr-x | history.txt | 7 | ||||
| -rw-r--r-- | lists.js | 5 | ||||
| -rw-r--r-- | morphic.js | 336 | ||||
| -rw-r--r-- | objects.js | 14 | ||||
| -rw-r--r-- | paint.js | 4 | ||||
| -rw-r--r-- | store.js | 2 | ||||
| -rw-r--r-- | threads.js | 35 | ||||
| -rw-r--r-- | widgets.js | 4 | ||||
| -rwxr-xr-x[-rw-r--r--] | xml.js | 129 |
12 files changed, 228 insertions, 422 deletions
@@ -155,8 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2015-June-08'; - +modules.blocks = '2015-June-25'; var SyntaxElementMorph; var BlockMorph; @@ -360,6 +359,10 @@ SyntaxElementMorph.prototype.init = function () { this.cachedInputs = null; }; +// SyntaxElementMorph stepping: + +SyntaxElementMorph.prototype.step = null; + // SyntaxElementMorph accessing: SyntaxElementMorph.prototype.parts = function () { @@ -1417,16 +1420,19 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { new Point() : this.embossing; part.drawNew(); } else { - part = new StringMorph(spec); - part.fontName = this.labelFontName; - part.fontStyle = this.labelFontStyle; - part.fontSize = this.fontSize; - part.color = new Color(255, 255, 255); - part.isBold = true; - part.shadowColor = this.color.darker(this.labelContrast); - part.shadowOffset = MorphicPreferences.isFlat ? - new Point() : this.embossing; - part.drawNew(); + part = new StringMorph( + spec, // text + this.fontSize, // fontSize + this.labelFontStyle, // fontStyle + true, // bold + false, // italic + false, // isNumeric + MorphicPreferences.isFlat ? + new Point() : this.embossing, // shadowOffset + this.color.darker(this.labelContrast), // shadowColor + new Color(255, 255, 255), // color + this.labelFontName // fontName + ); } return part; }; @@ -2058,7 +2064,8 @@ BlockMorph.prototype.setSpec = function (spec) { } part = myself.labelPart(word); myself.add(part); - if (!(part instanceof CommandSlotMorph)) { + if (!(part instanceof CommandSlotMorph || + part instanceof StringMorph)) { part.drawNew(); } if (part instanceof RingMorph) { @@ -2225,7 +2232,7 @@ BlockMorph.prototype.userMenu = function () { ); if (this instanceof CommandBlockMorph && this.nextBlock()) { menu.addItem( - this.thumbnail(0.5, 60, false), + this.thumbnail(0.5, 60), function () { var cpy = this.fullCopy(), nb = cpy.nextBlock(), @@ -3103,38 +3110,34 @@ BlockMorph.prototype.mouseClickLeft = function () { // BlockMorph thumbnail -BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) { - var block = this.fullCopy(), - nb = block.nextBlock(), +BlockMorph.prototype.thumbnail = function (scale, clipWidth) { + var nb = this.nextBlock(), fadeout = 12, ext, trgt, ctx, gradient; - if (nb) {nb.destroy(); } - if (!noShadow) {block.addShadow(); } - ext = block.fullBounds().extent(); - if (!noShadow) { - ext = ext.subtract(this.shadowBlur * - (useBlurredShadows && !MorphicPreferences.isFlat ? 1 : 2)); - } + + if (nb) {nb.isVisible = false; } + ext = this.fullBounds().extent(); trgt = newCanvas(new Point( - Math.min(ext.x * scale, clipWidth || ext.x), + clipWidth ? Math.min(ext.x * scale, clipWidth) : ext.x * scale, ext.y * scale )); ctx = trgt.getContext('2d'); ctx.scale(scale, scale); - ctx.drawImage(block.fullImage(), 0, 0); + ctx.drawImage(this.fullImage(), 0, 0); // draw fade-out - if (trgt.width === clipWidth) { + if (clipWidth && ext.x * scale > clipWidth) { gradient = ctx.createLinearGradient( trgt.width / scale - fadeout, 0, trgt.width / scale, 0 ); - gradient.addColorStop(0, new Color(255, 255, 255, 0).toString()); - gradient.addColorStop(1, 'white'); + gradient.addColorStop(0, 'transparent'); + gradient.addColorStop(1, 'black'); + ctx.globalCompositeOperation = 'destination-out'; ctx.fillStyle = gradient; ctx.fillRect( trgt.width / scale - fadeout, @@ -3143,6 +3146,7 @@ BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) { trgt.height / scale ); } + if (nb) {nb.isVisible = true; } return trgt; }; @@ -6917,7 +6921,8 @@ InputSlotMorph.prototype.setChoices = function (dict, readonly) { // InputSlotMorph layout: InputSlotMorph.prototype.fixLayout = function () { - var contents = this.contents(), + var width, height, arrowWidth, + contents = this.contents(), arrow = this.arrow(); contents.isNumeric = this.isNumeric; @@ -6934,35 +6939,32 @@ InputSlotMorph.prototype.fixLayout = function () { arrow.setSize(this.fontSize); arrow.show(); } else { - arrow.setSize(0); arrow.hide(); } - this.setHeight( - contents.height() - + this.edge * 2 - // + this.typeInPadding * 2 - ); + arrowWidth = arrow.isVisible ? arrow.width() : 0; + + height = contents.height() + this.edge * 2; // + this.typeInPadding * 2 if (this.isNumeric) { - this.setWidth(contents.width() - + Math.floor(arrow.width() * 0.5) - + this.height() - + this.typeInPadding * 2 - ); + width = contents.width() + + Math.floor(arrowWidth * 0.5) + + height + + this.typeInPadding * 2; } else { - this.setWidth(Math.max( + width = Math.max( contents.width() - + arrow.width() + + arrowWidth + this.edge * 2 + this.typeInPadding * 2, contents.rawHeight ? // single vs. multi-line contents - contents.rawHeight() + arrow.width() - : contents.height() / 1.2 + arrow.width(), + contents.rawHeight() + arrowWidth + : contents.height() / 1.2 + arrowWidth, this.minWidth // for text-type slots - )); + ); } + this.setExtent(new Point(width, height)); if (this.isNumeric) { contents.setPosition(new Point( - Math.floor(this.height() / 2), + Math.floor(height / 2), this.edge ).add(new Point(this.typeInPadding, 0)).add(this.position())); } else { @@ -6972,10 +6974,12 @@ InputSlotMorph.prototype.fixLayout = function () { ).add(new Point(this.typeInPadding, 0)).add(this.position())); } - arrow.setPosition(new Point( - this.right() - arrow.width() - this.edge, - contents.top() - )); + if (arrow.isVisible) { + arrow.setPosition(new Point( + this.right() - arrowWidth - this.edge, + contents.top() + )); + } if (this.parent) { if (this.parent.fixLayout) { @@ -106,7 +106,7 @@ SymbolMorph, isNil*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2015-May-23'; +modules.byob = '2015-June-25'; // Declarations @@ -69,7 +69,7 @@ SpeechBubbleMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2015-May-18'; +modules.gui = '2015-June-25'; // Declarations @@ -2614,7 +2614,7 @@ IDE_Morph.prototype.aboutSnap = function () { module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, world = this.world(); - aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n' + aboutTxt = 'Snap! 4.0.1\nBuild Your Own Blocks\n\n' + 'Copyright \u24B8 2015 Jens M\u00F6nig and ' + 'Brian Harvey\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n' @@ -2648,7 +2648,7 @@ IDE_Morph.prototype.aboutSnap = function () { creditsTxt = localize('Contributors') + '\n\nNathan Dinsmore: Saving/Loading, Snap-Logo Design, ' - + 'countless bugfixes' + + '\ncountless bugfixes and optimizations' + '\nKartik Chandra: Paint Editor' + '\nMichael Ball: Time/Date UI, many bugfixes' + '\n"Ava" Yuan Yuan: Graphic Effects' diff --git a/history.txt b/history.txt index 1262a28..9d9c00c 100755 --- a/history.txt +++ b/history.txt @@ -2516,3 +2516,10 @@ ______ 150608 ------ * Blocks: Fixed #820 + +150625 +------ +* Morphic, Objects, Blocks, XML: Optimizations and dramatic speed-up. Thanks, Nathan!! +* Objects: push maximum clone count up to 1000, tweak Note::play + +=== Release v4.0.1 === @@ -7,7 +7,7 @@ written by Jens Mönig and Brian Harvey jens@moenig.org, bh@cs.berkeley.edu - Copyright (C) 2014 by Jens Mönig and Brian Harvey + Copyright (C) 2015 by Jens Mönig and Brian Harvey This file is part of Snap!. @@ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph, StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph, MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/ -modules.lists = '2014-November-20'; +modules.lists = '2015-June-25'; var List; var ListWatcherMorph; @@ -634,6 +634,7 @@ ListWatcherMorph.prototype.setStartIndex = function (index) { }; ListWatcherMorph.prototype.fixLayout = function () { + if (!this.label) {return; } Morph.prototype.trackChanges = false; if (this.frame) { this.arrangeCells(); @@ -528,7 +528,7 @@ whose "isTemplate" flag is false, in other words: a non-template. When creating a copy from a template, the copy's - + reactToTemplateCopy is invoked, if it is present. @@ -832,9 +832,9 @@ submorph tree in other properties, be sure to also override the default - copyRecordingReferences() + updateReferences() - method accordingly if you want it to support duplication. + method if you want it to support duplication. (6) development and user modes @@ -1036,7 +1036,7 @@ ---------------------- Joe Otto found and fixed many early bugs and taught me some tricks. Nathan Dinsmore contributed mouse wheel scrolling, cached - background texture handling and countless bug fixes. + background texture handling, countless bug fixes and optimizations. Ian Reynolds contributed backspace key handling for Chrome. Davide Della Casa contributed performance optimizations for Firefox. @@ -1048,7 +1048,7 @@ /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, FileList, getBlurredShadowSupport*/ -var morphicVersion = '2015-May-01'; +var morphicVersion = '2015-June-25'; var modules = {}; // keep track of additional loaded modules var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug @@ -1243,19 +1243,9 @@ function getDocumentPositionOf(aDOMelement) { return pos; } -function clone(target) { - // answer a new instance of target's type - if (typeof target === 'object') { - var Clone = function () {nop(); }; - Clone.prototype = target; - return new Clone(); - } - return target; -} - function copy(target) { // answer a shallow copy of target - var value, c, property; + var value, c, property, keys, l, i; if (typeof target !== 'object') { return target; @@ -1266,18 +1256,16 @@ function copy(target) { } if (target instanceof target.constructor && target.constructor !== Object) { - c = clone(target.constructor.prototype); - for (property in target) { - if (Object.prototype.hasOwnProperty.call(target, property)) { - c[property] = target[property]; - } + c = Object.create(target.constructor.prototype); + keys = Object.keys(target); + for (l = keys.length, i = 0; i < l; i += 1) { + property = keys[i]; + c[property] = target[property]; } } else { c = {}; for (property in target) { - if (!c[property]) { - c[property] = target[property]; - } + c[property] = target[property]; } } return c; @@ -2212,7 +2200,7 @@ function Morph() { // Morph initialization: -Morph.prototype.init = function () { +Morph.prototype.init = function (noDraw) { Morph.uber.init.call(this); this.isMorph = true; this.bounds = new Rectangle(0, 0, 50, 40); @@ -2225,7 +2213,7 @@ Morph.prototype.init = function () { this.isTemplate = false; this.acceptsDrops = false; this.noticesTransparentClick = false; - this.drawNew(); + if (!noDraw) {this.drawNew(); } this.fps = 0; this.customContextMenu = null; this.lastTime = Date.now(); @@ -2411,12 +2399,9 @@ Morph.prototype.visibleBounds = function () { // Morph accessing - simple changes: Morph.prototype.moveBy = function (delta) { - this.changed(); - this.bounds = this.bounds.translateBy(delta); - this.children.forEach(function (child) { - child.moveBy(delta); - }); - this.changed(); + this.fullChanged(); + this.silentMoveBy(delta); + this.fullChanged(); }; Morph.prototype.silentMoveBy = function (delta) { @@ -2899,7 +2884,7 @@ Morph.prototype.fullChanged = function () { }; Morph.prototype.childChanged = function () { - // react to a change in one of my children, + // react to a change in one of my children, // default is to just pass this message on upwards // override this method for Morphs that need to adjust accordingly if (this.parent) { @@ -2936,6 +2921,18 @@ Morph.prototype.addBack = function (aMorph) { this.addChildFirst(aMorph); }; +Morph.prototype.topMorphAt = function (point) { + var i, result; + if (!this.isVisible) {return null; } + for (i = this.children.length - 1; i >= 0; i -= 1) { + result = this.children[i].topMorphAt(point); + if (result) {return result; } + } + return this.bounds.containsPoint(point) && + (this.noticesTransparentClick || !this.isTransparentAt(point)) ? this + : null; +}; + Morph.prototype.topMorphSuchThat = function (predicate) { var next; if (predicate.call(null, this)) { @@ -2951,30 +2948,6 @@ Morph.prototype.topMorphSuchThat = function (predicate) { return null; }; -Morph.prototype.morphAt = function (aPoint) { - var morphs = this.allChildren().slice(0).reverse(), - result = null; - morphs.forEach(function (m) { - if (m.fullBounds().containsPoint(aPoint) && - (result === null)) { - result = m; - } - }); - return result; -}; - -/* - alternative - more elegant and possibly more - performant - solution for morphAt. - Has some issues, commented out for now - -Morph.prototype.morphAt = function (aPoint) { - return this.topMorphSuchThat(function (m) { - return m.fullBounds().containsPoint(aPoint); - }); -}; -*/ - Morph.prototype.overlappedMorphs = function () { //exclude the World var world = this.world(), @@ -3046,45 +3019,54 @@ Morph.prototype.fullCopy = function () { Other properties are also *shallow* copied, so you must override to deep copy Arrays and (complex) Objects */ - var dict = {}, c; - c = this.copyRecordingReferences(dict); + var map = new Map(), c; + c = this.copyRecordingReferences(map); c.forAllChildren(function (m) { - m.updateReferences(dict); + m.updateReferences(map); }); return c; }; -Morph.prototype.copyRecordingReferences = function (dict) { +Morph.prototype.copyRecordingReferences = function (map) { /* Recursively copy this entire composite morph, recording the correspondence between old and new morphs in the given dictionary. This dictionary will be used to update intra-composite references in the copy. See updateReferences(). - Note: This default implementation copies ONLY morphs in the - submorph hierarchy. If a morph stores morphs in other properties - that it wants to copy, then it should override this method to do so. - The same goes for morphs that contain other complex data that - should be copied when the morph is duplicated. + + Note: This default implementation copies ONLY morphs. If a morph + stores morphs in other properties that it wants to copy, then it + should override this method to do so. The same goes for morphs that + contain other complex data that should be copied when the morph is + duplicated. */ var c = this.copy(); - dict[this] = c; + map.set(this, c); this.children.forEach(function (m) { - c.add(m.copyRecordingReferences(dict)); + c.add(m.copyRecordingReferences(map)); }); return c; }; -Morph.prototype.updateReferences = function (dict) { +Morph.prototype.updateReferences = function (map) { /* Update intra-morph references within a composite morph that has been copied. For example, if a button refers to morph X in the orginal composite then the copy of that button in the new composite should refer to the copy of X in new composite, not the original X. */ - var property; - for (property in this) { - if (this[property] && this[property].isMorph && dict[property]) { - this[property] = dict[property]; + var properties = Object.keys(this), + l = properties.length, + property, + value, + reference, + i; + for (i = 0; i < l; i += 1) { + property = properties[i]; + value = this[property]; + if (value && value.isMorph) { + reference = map.get(value); + if (reference) { this[property] = reference; } } } }; @@ -3155,9 +3137,7 @@ Morph.prototype.slideBackTo = function (situation, inSteps) { this.fps = 0; this.step = function () { - myself.fullChanged(); - myself.silentMoveBy(new Point(xStep, yStep)); - myself.fullChanged(); + myself.moveBy(new Point(xStep, yStep)); stepCount += 1; if (stepCount === steps) { situation.origin.add(myself); @@ -3706,6 +3686,10 @@ function ShadowMorph() { this.init(); } +ShadowMorph.prototype.topMorphAt = function () { + return null; +}; + // HandleMorph //////////////////////////////////////////////////////// // I am a resize / move handle that can be attached to any Morph @@ -3923,20 +3907,6 @@ HandleMorph.prototype.mouseLeave = function () { this.changed(); }; -// HandleMorph duplicating: - -HandleMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = HandleMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - return c; -}; - // HandleMorph menu: HandleMorph.prototype.attach = function () { @@ -4260,20 +4230,6 @@ ColorPaletteMorph.prototype.updateTarget = function () { } }; -// ColorPaletteMorph duplicating: - -ColorPaletteMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = ColorPaletteMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - return c; -}; - // ColorPaletteMorph menu: ColorPaletteMorph.prototype.developersMenu = function () { @@ -5840,23 +5796,6 @@ SliderMorph.prototype.updateTarget = function () { } }; -// SliderMorph duplicating: - -SliderMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = SliderMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.target && dict[this.target]) { - c.target = (dict[this.target]); - } - if (c.button && dict[this.button]) { - c.button = (dict[this.button]); - } - return c; -}; - // SliderMorph menu: SliderMorph.prototype.developersMenu = function () { @@ -7024,7 +6963,7 @@ StringMorph.prototype.init = function ( this.markedBackgoundColor = new Color(60, 60, 120); // initialize inherited properties: - StringMorph.uber.init.call(this); + StringMorph.uber.init.call(this, true); // override inherited properites: this.color = color || new Color(0, 0, 0); @@ -7402,6 +7341,11 @@ StringMorph.prototype.selectionStartSlot = function () { }; StringMorph.prototype.clearSelection = function () { + if (!this.currentlySelecting && + this.startMark === 0 && + this.endMark === 0) { + return; + } this.currentlySelecting = false; this.startMark = 0; this.endMark = 0; @@ -8141,20 +8085,6 @@ TriggerMorph.prototype.createLabel = function () { this.add(this.label); }; -// TriggerMorph duplicating: - -TriggerMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = TriggerMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.label && dict[this.label]) { - c.label = (dict[this.label]); - } - return c; -}; - // TriggerMorph action: TriggerMorph.prototype.trigger = function () { @@ -8500,15 +8430,19 @@ FrameMorph.prototype.fullDrawOn = function (aCanvas, aRect) { }); }; -// FrameMorph scrolling optimization: +// FrameMorph navigation: -FrameMorph.prototype.moveBy = function (delta) { - this.changed(); - this.bounds = this.bounds.translateBy(delta); - this.children.forEach(function (child) { - child.silentMoveBy(delta); - }); - this.changed(); +FrameMorph.prototype.topMorphAt = function (point) { + var i, result; + if (!(this.isVisible && this.bounds.containsPoint(point))) { + return null; + } + for (i = this.children.length - 1; i >= 0; i -= 1) { + result = this.children[i].topMorphAt(point); + if (result) {return result; } + } + return this.noticesTransparentClick || + !this.isTransparentAt(point) ? this : null; }; // FrameMorph scrolling support: @@ -8600,20 +8534,6 @@ FrameMorph.prototype.reactToGrabOf = function () { this.adjustBounds(); }; -// FrameMorph duplicating: - -FrameMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = FrameMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.frame && dict[this.scrollFrame]) { - c.frame = (dict[this.scrollFrame]); - } - return c; -}; - // FrameMorph menus: FrameMorph.prototype.developersMenu = function () { @@ -8958,32 +8878,23 @@ ScrollFrameMorph.prototype.mouseScroll = function (y, x) { // ScrollFrameMorph duplicating: -ScrollFrameMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = ScrollFrameMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.contents && dict[this.contents]) { - c.contents = (dict[this.contents]); - } - if (c.hBar && dict[this.hBar]) { - c.hBar = (dict[this.hBar]); - c.hBar.action = function (num) { - c.contents.setPosition( - new Point(c.left() - num, c.contents.position().y) +ScrollFrameMorph.prototype.updateReferences = function (map) { + var myself = this; + ScrollFrameMorph.uber.updateReferences.call(this, map); + if (this.hBar) { + this.hBar.action = function (num) { + myself.contents.setPosition( + new Point(myself.left() - num, myself.contents.position().y) ); }; } - if (c.vBar && dict[this.vBar]) { - c.vBar = (dict[this.vBar]); - c.vBar.action = function (num) { - c.contents.setPosition( - new Point(c.contents.position().x, c.top() - num) + if (this.vBar) { + this.vBar.action = function (num) { + myself.contents.setPosition( + new Point(myself.contents.position().x, myself.top() - num) ); }; } - return c; }; // ScrollFrameMorph menu: @@ -9243,20 +9154,6 @@ StringFieldMorph.prototype.mouseClickLeft = function (pos) { } }; -// StringFieldMorph duplicating: - -StringFieldMorph.prototype.copyRecordingReferences = function (dict) { - // inherited, see comment in Morph - var c = StringFieldMorph.uber.copyRecordingReferences.call( - this, - dict - ); - if (c.text && dict[this.text]) { - c.text = (dict[this.text]); - } - return c; -}; - // BouncerMorph //////////////////////////////////////////////////////// // I am a Demo of a stepping custom Morph @@ -9384,54 +9281,18 @@ HandMorph.prototype.changed = function () { if (this.world !== null) { b = this.fullBounds(); if (!b.extent().eq(new Point())) { - this.world.broken.push(this.fullBounds().spread()); + this.world.broken.push(b.spread()); } } - }; -// HandMorph navigation: +HandMorph.prototype.fullChanged = HandMorph.prototype.changed; -HandMorph.prototype.morphAtPointer = function () { - var morphs = this.world.allChildren().slice(0).reverse(), - myself = this, - result = null; - - morphs.forEach(function (m) { - if (m.visibleBounds().containsPoint(myself.bounds.origin) && - result === null && - m.isVisible && - (m.noticesTransparentClick || - (!m.isTransparentAt(myself.bounds.origin))) && - (!(m instanceof ShadowMorph)) && - m.allParents().every(function (each) { - return each.isVisible; - })) { - result = m; - } - }); - if (result !== null) { - return result; - } - return this.world; -}; - -/* - alternative - more elegant and possibly more - performant - solution for morphAtPointer. - Has some issues, commented out for now +// HandMorph navigation: HandMorph.prototype.morphAtPointer = function () { - var myself = this; - return this.world.topMorphSuchThat(function (m) { - return m.visibleBounds().containsPoint(myself.bounds.origin) && - m.isVisible && - (m.noticesTransparentClick || - (! m.isTransparentAt(myself.bounds.origin))) && - (! (m instanceof ShadowMorph)); - }); + return this.world.topMorphAt(this.bounds.origin) || this.world; }; -*/ HandMorph.prototype.allMorphsAtPointer = function () { var morphs = this.world.allChildren(), @@ -9971,16 +9832,6 @@ HandMorph.prototype.destroyTemporaries = function () { }); }; -// HandMorph dragging optimization - -HandMorph.prototype.moveBy = function (delta) { - Morph.prototype.trackChanges = false; - HandMorph.uber.moveBy.call(this, delta); - Morph.prototype.trackChanges = true; - this.fullChanged(); -}; - - // WorldMorph ////////////////////////////////////////////////////////// // I represent the <canvas> element @@ -10009,6 +9860,7 @@ WorldMorph.prototype.init = function (aCanvas, fillPage) { this.isDraggable = false; this.currentKey = null; // currently pressed key code this.worldCanvas = aCanvas; + this.noticesTransparentClick = true; // additional properties: this.stamp = Date.now(); // reference in multi-world setups @@ -105,7 +105,7 @@ InspectorMorph, ListMorph, Math, MenuItemMorph, MenuMorph, Morph, MorphicPreferences, MouseSensorMorph, Node, Object, PenMorph, Point, Rectangle, ScrollFrameMorph, ShadowMorph, SliderButtonMorph, SliderMorph, String, StringFieldMorph, StringMorph, TextMorph, -TriggerMorph, WorldMorph, clone, contains, copy, degrees, detect, +TriggerMorph, WorldMorph, contains, copy, degrees, detect, document, getDocumentPositionOf, isNaN, isObject, isString, newCanvas, nop, parseFloat, radians, standardSettings, touchScreenSettings, useBlurredShadows, version, window, modules, IDE_Morph, VariableDialogMorph, @@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.objects = '2015-May-18'; +modules.objects = '2015-June-25'; var SpriteMorph; var StageMorph; @@ -583,7 +583,7 @@ SpriteMorph.prototype.initBlocks = function () { }, /* migrated to a newer block version: - + receiveClick: { type: 'hat', category: 'control', @@ -2718,7 +2718,7 @@ SpriteMorph.prototype.remove = function () { SpriteMorph.prototype.createClone = function () { var stage = this.parentThatIsA(StageMorph); - if (stage && stage.cloneCount <= 300) { + if (stage && stage.cloneCount <= 1000) { this.fullCopy().clonify(stage); } }; @@ -3008,7 +3008,7 @@ SpriteMorph.prototype.applyGraphicsEffects = function (canvas) { var i; if (value !== 0) { for (i = 0; i < p.length; i += 4) { - p[i] += value; //255 = 100% of this color + p[i] += value; //255 = 100% of this color p[i + 1] += value; p[i + 2] += value; } @@ -3290,7 +3290,7 @@ SpriteMorph.prototype.nestingBounds = function () { // SpriteMorph motion primitives -Morph.prototype.setPosition = function (aPoint, justMe) { +SpriteMorph.prototype.setPosition = function (aPoint, justMe) { // override the inherited default to make sure my parts follow // unless it's justMe var delta = aPoint.subtract(this.topLeft()); @@ -6429,7 +6429,7 @@ Note.prototype.play = function () { if (!this.oscillator.stop) { this.oscillator.stop = this.oscillator.noteOff; } - this.oscillator.type = 0; + this.oscillator.type = 'sine'; this.oscillator.frequency.value = Math.pow(2, (this.pitch - 69) / 12) * 440; this.oscillator.connect(this.gainNode); @@ -5,7 +5,7 @@ inspired by the Scratch paint editor. written by Kartik Chandra - Copyright (C) 2014 by Kartik Chandra + Copyright (C) 2015 by Kartik Chandra This file is part of Snap!. @@ -69,7 +69,7 @@ // Global stuff //////////////////////////////////////////////////////// -modules.paint = '2014-September-29'; +modules.paint = '2015-June-25'; // Declarations @@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2015-April-26'; +modules.store = '2015-June-25'; // XML_Serializer /////////////////////////////////////////////////////// @@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/ // Global stuff //////////////////////////////////////////////////////// -modules.threads = '2015-May-01'; +modules.threads = '2015-June-25'; var ThreadManager; var Process; @@ -2640,31 +2640,30 @@ Process.prototype.reportTimer = function () { }; // Process Dates and times in Snap -// Map block options to built-in functions -var dateMap = { - 'year' : 'getFullYear', - 'month' : 'getMonth', - 'date': 'getDate', - 'day of week' : 'getDay', - 'hour' : 'getHours', - 'minute' : 'getMinutes', - 'second' : 'getSeconds', - 'time in milliseconds' : 'getTime' -}; - Process.prototype.reportDate = function (datefn) { - var inputFn = this.inputOption(datefn), - currDate = new Date(), - func = dateMap[inputFn], - result = currDate[func](); + var currDate, func, result, + inputFn = this.inputOption(datefn), + // Map block options to built-in functions + dateMap = { + 'year' : 'getFullYear', + 'month' : 'getMonth', + 'date': 'getDate', + 'day of week' : 'getDay', + 'hour' : 'getHours', + 'minute' : 'getMinutes', + 'second' : 'getSeconds', + 'time in milliseconds' : 'getTime' + }; if (!dateMap[inputFn]) { return ''; } + currDate = new Date(); + func = dateMap[inputFn]; + result = currDate[func](); // Show months as 1-12 and days as 1-7 if (inputFn === 'month' || inputFn === 'day of week') { result += 1; } - return result; }; @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph, ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences, ScrollFrameMorph*/ -modules.widgets = '2014-February-13'; +modules.widgets = '2015-June-25'; var PushButtonMorph; var ToggleButtonMorph; @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2014 by Jens Mönig + Copyright (C) 2015 by Jens Mönig This file is part of Snap!. @@ -57,15 +57,17 @@ Nathan Dinsmore contributed to the design and implemented a first working version of a complete XMLSerializer. I have taken much of the overall design and many of the functions and methods in this file from - Nathan's fine original prototype. + Nathan's fine original prototype. Recently Nathan has once again + worked his magic on the parser and optimized it by an order of + magnitude. */ -/*global modules, isString, detect, Node, isNil*/ +/*global modules, detect, Node, isNil*/ // Global stuff //////////////////////////////////////////////////////// -modules.xml = '2014-January-09'; +modules.xml = '2015-June-25'; // Declarations @@ -85,7 +87,8 @@ function ReadStream(arrayOrString) { // ReadStream constants: -ReadStream.prototype.space = /[\s]/; +ReadStream.prototype.nonSpace = /\S|$/g; +ReadStream.prototype.nonWord = /[\s\>\/\=]|$/g; // ReadStream accessing: @@ -115,46 +118,26 @@ ReadStream.prototype.atEnd = function () { // ReadStream accessing String contents: -ReadStream.prototype.upTo = function (regex) { - var i, start; - if (!isString(this.contents)) {return ''; } - i = this.contents.substr(this.index).search(regex); - if (i === -1) { - return ''; - } - start = this.index; - this.index += i; - return this.contents.substring(start, this.index); +ReadStream.prototype.upTo = function (str) { + var i = this.contents.indexOf(str, this.index); + return i === -1 ? '' : this.contents.slice(this.index, this.index = i); }; -ReadStream.prototype.peekUpTo = function (regex) { - if (!isString(this.contents)) {return ''; } - var i = this.contents.substr(this.index).search(regex); - if (i === -1) { - return ''; - } - return this.contents.substring(this.index, this.index + i); +ReadStream.prototype.peekUpTo = function (str) { + var i = this.contents.indexOf(str, this.index); + return i === -1 ? '' : this.contents.slice(this.index, i); }; ReadStream.prototype.skipSpace = function () { - if (!isString(this.contents)) {return ''; } - var ch = this.peek(); - while (this.space.test(ch) && ch !== '') { - this.skip(); - ch = this.peek(); - } + this.nonSpace.lastIndex = this.index; + var result = this.nonSpace.exec(this.contents); + if (result) this.index = result.index; }; ReadStream.prototype.word = function () { - var i, start; - if (!isString(this.contents)) {return ''; } - i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/); - if (i === -1) { - return ''; - } - start = this.index; - this.index += i; - return this.contents.substring(start, this.index); + this.nonWord.lastIndex = this.index; + var result = this.nonWord.exec(this.contents); + return result ? this.contents.slice(this.index, this.index = result.index) : ''; }; // XML_Element /////////////////////////////////////////////////////////// @@ -166,7 +149,7 @@ ReadStream.prototype.word = function () { // XML_Element inherits from Node: -XML_Element.prototype = new Node(); +XML_Element.prototype = Object.create(Node.prototype); XML_Element.prototype.constructor = XML_Element; XML_Element.uber = Node.prototype; @@ -190,9 +173,7 @@ XML_Element.prototype.init = function (tag, contents, parent) { XML_Element.uber.init.call(this); // override inherited properties - if (parent instanceof XML_Element) { - parent.addChild(this); - } + if (parent) parent.addChild(this); }; // XML_Element DOM navigation: (aside from what's inherited from Node) @@ -318,51 +299,18 @@ XML_Element.prototype.escape = function (string, ignoreQuotes) { }; XML_Element.prototype.unescape = function (string) { - var stream = new ReadStream(string), - result = '', - ch, - esc; - - function nextPut(str) { - result += str; - stream.upTo(';'); - stream.skip(); - } - - while (!stream.atEnd()) { - ch = stream.next(); - if (ch === '&') { - esc = stream.peekUpTo(';'); - switch (esc) { - case 'apos': - nextPut('\''); - break; - case 'quot': - nextPut('\"'); - break; - case 'lt': - nextPut('<'); - break; - case 'gt': - nextPut('>'); - break; - case 'amp': - nextPut('&'); - break; - case '#xD': - nextPut('\n'); - break; - case '#126': - nextPut('~'); - break; - default: - result += ch; - } - } else { - result += ch; + return string.replace(/&(amp|apos|quot|lt|gt|#xD|#126);/g, function(_, name) { + switch (name) { + case 'amp': return '&'; + case 'apos': return '\''; + case 'quot': return '"'; + case 'lt': return '<'; + case 'gt': return '>'; + case '#xD': return '\n'; + case '#126': return '~'; + default: console.warn('unreachable'); } - } - return result; + }); }; // XML_Element parsing: @@ -375,10 +323,7 @@ XML_Element.prototype.parseString = function (string) { }; XML_Element.prototype.parseStream = function (stream) { - var key, - value, - ch, - child; + var key, value, ch, child; // tag: this.tag = stream.word(); @@ -395,9 +340,7 @@ XML_Element.prototype.parseStream = function (stream) { stream.skipSpace(); ch = stream.next(); if (ch !== '"' && ch !== "'") { - throw new Error( - 'Expected single- or double-quoted attribute value' - ); + throw new Error('Expected single- or double-quoted attribute value'); } value = stream.upTo(ch); stream.skip(1); @@ -407,7 +350,7 @@ XML_Element.prototype.parseStream = function (stream) { } // empty tag: - if (stream.peek() === '/') { + if (ch === '/') { stream.skip(); if (stream.next() !== '>') { throw new Error('Expected ">" after "/" in empty tag'); |
