Merge branch 'master' into cancel

pull/3/merge
Bartosz Leper 2015-07-08 18:54:07 +02:00
commit df3ab6c863
16 zmienionych plików z 487 dodań i 472 usunięć

112
blocks.js
Wyświetl plik

@ -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 () {
@ -1111,9 +1114,9 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
acos : ['acos'],
atan : ['atan'],
ln : ['ln'],
// log : 'log',
'e^' : ['e^']
// '10^' : '10^'
log : ['log'],
'e^' : ['e^'],
'10^' : ['10^']
},
true
);
@ -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) {

Wyświetl plik

@ -106,7 +106,7 @@ SymbolMorph, isNil*/
// Global stuff ////////////////////////////////////////////////////////
modules.byob = '2015-May-23';
modules.byob = '2015-June-25';
// Declarations

54
gui.js
Wyświetl plik

@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.gui = '2015-May-18';
modules.gui = '2015-June-25';
// Declarations
@ -82,6 +82,11 @@ var WardrobeMorph;
var SoundIconMorph;
var JukeboxMorph;
// Get the full url without "snap.html"
var baseUrl = document.URL.split('/');
baseUrl.pop(baseUrl.length - 1);
baseUrl = baseUrl.join('/') + '/';
// IDE_Morph ///////////////////////////////////////////////////////////
// I am SNAP's top-level frame, the Editor window
@ -304,7 +309,8 @@ IDE_Morph.prototype.openIn = function (world) {
}
throw new Error('unable to retrieve ' + url);
} catch (err) {
return;
myself.showMessage('unable to retrieve project');
return '';
}
}
@ -2491,13 +2497,10 @@ IDE_Morph.prototype.projectMenu = function () {
function () {
// read a list of libraries from an external file,
var libMenu = new MenuMorph(this, 'Import library'),
libUrl = 'http://snap.berkeley.edu/snapsource/libraries/' +
'LIBRARIES';
libUrl = baseUrl + 'libraries/' + 'LIBRARIES';
function loadLib(name) {
var url = 'http://snap.berkeley.edu/snapsource/libraries/'
+ name
+ '.xml';
var url = baseUrl + 'libraries/' + name + '.xml';
myself.droppedText(myself.getURL(url), name);
}
@ -2614,7 +2617,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 +2651,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'
@ -4216,8 +4219,7 @@ IDE_Morph.prototype.getURLsbeOrRelative = function (url) {
var request = new XMLHttpRequest(),
myself = this;
try {
request.open('GET', 'http://snap.berkeley.edu/snapsource/' +
url, false);
request.open('GET', baseUrl + url, false);
request.send();
if (request.status === 200) {
return request.responseText;
@ -4658,8 +4660,7 @@ ProjectDialogMorph.prototype.setSource = function (source) {
myself.nameField.setContents(item.name || '');
}
src = myself.ide.getURL(
'http://snap.berkeley.edu/snapsource/Examples/' +
item.name + '.xml'
baseUrl + 'Examples/' + item.name + '.xml'
);
xml = myself.ide.serializer.parse(src);
@ -4713,8 +4714,9 @@ ProjectDialogMorph.prototype.getLocalProjectList = function () {
ProjectDialogMorph.prototype.getExamplesProjectList = function () {
var dir,
projects = [];
//alert(baseUrl);
dir = this.ide.getURL('http://snap.berkeley.edu/snapsource/Examples/');
dir = this.ide.getURL(baseUrl + 'Examples/');
dir.split('\n').forEach(
function (line) {
var startIdx = line.search(new RegExp('href=".*xml"')),
@ -4733,8 +4735,8 @@ ProjectDialogMorph.prototype.getExamplesProjectList = function () {
}
}
);
projects.sort(function (x, y) {
return x.name < y.name ? -1 : 1;
projects = projects.sort(function (x, y) {
return x.name.toLowerCase() < y.name.toLowerCase() ? -1 : 1;
});
return projects;
};
@ -4833,10 +4835,7 @@ ProjectDialogMorph.prototype.openProject = function () {
if (this.source === 'cloud') {
this.openCloudProject(proj);
} else if (this.source === 'examples') {
src = this.ide.getURL(
'http://snap.berkeley.edu/snapsource/Examples/' +
proj.name + '.xml'
);
src = this.ide.getURL(baseUrl + 'Examples/' + proj.name + '.xml');
this.ide.openProjectString(src);
this.destroy();
} else { // 'local'
@ -5006,6 +5005,7 @@ ProjectDialogMorph.prototype.deleteProject = function () {
ProjectDialogMorph.prototype.shareProject = function () {
var myself = this,
ide = this.ide,
proj = this.listField.selected,
entry = this.listField.active;
@ -5036,6 +5036,15 @@ ProjectDialogMorph.prototype.shareProject = function () {
myself.ide.cloudError(),
[proj.ProjectName]
);
// Set the Shared URL if the project is currently open
if (proj.ProjectName === ide.projectName) {
var usr = SnapCloud.username,
projectId = 'Username=' +
encodeURIComponent(usr.toLowerCase()) +
'&ProjectName=' +
encodeURIComponent(proj.projectName);
location.hash = projectId;
}
},
myself.ide.cloudError()
);
@ -5046,6 +5055,7 @@ ProjectDialogMorph.prototype.shareProject = function () {
ProjectDialogMorph.prototype.unshareProject = function () {
var myself = this,
ide = this.ide,
proj = this.listField.selected,
entry = this.listField.active;
@ -5077,6 +5087,10 @@ ProjectDialogMorph.prototype.unshareProject = function () {
myself.ide.cloudError(),
[proj.ProjectName]
);
// Remove the shared URL if the project is open.
if (proj.ProjectName === ide.projectName) {
location.hash = '';
}
},
myself.ide.cloudError()
);

Wyświetl plik

@ -2516,3 +2516,14 @@ ______
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
=== Start with v4.0.1 ===
150626
------
* Morphic: Fix Inspector duplication, update documentation

7
index.html 100644
Wyświetl plik

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta HTTP-EQUIV="REFRESH" content="0.1; url=snap.html">
</head>
</html>

Wyświetl plik

@ -185,7 +185,7 @@ SnapTranslator.dict.fr = {
'translator_e-mail':
'i.scool@mac.com', // optional
'last_changed':
'2014-02-04', // this, too, will appear in the Translators tab
'2015-06-25', // this, too, will appear in the Translators tab
// GUI
// control bar:
@ -392,7 +392,7 @@ SnapTranslator.dict.fr = {
'clear':
'effacer tout',
'pen down':
'stylo en position d\u0027\u00EAcriture',
'stylo en position d\u0027\u00E9criture',
'pen up':
'relever le stylo',
'set pen color to %clr':
@ -419,6 +419,8 @@ SnapTranslator.dict.fr = {
'Quand %keyHat est press\u00E9',
'when I am clicked':
'Quand je suis press\u00E9 ',
'when I am %interaction':
'Quand je suis %interaction',
'when I receive %msgHat':
'Quand je re\u00E7ois %msgHat',
'broadcast %msg':
@ -447,6 +449,10 @@ SnapTranslator.dict.fr = {
'arr\u00EAter le bloc',
'stop script':
'arr\u00EAter le script',
'stop %stopOthersChoices':
'arr\u00EAter %stopOthersChoices',
'stop %stopChoices':
'arr\u00EAter %stopChoices',
'stop all %stop':
'arr\u00EAter tout %stop',
'run %cmdRing %inputs':
@ -469,8 +475,16 @@ SnapTranslator.dict.fr = {
'moi-m\u00EAme',
'delete this clone':
'supprime ce clone',
'pause all':
'mettre en pause',
'pause all %pause':
'mettre en pause %pause',
'all but this script':
'tout sauf ce lutin',
'other scripts in sprite':
'les autres scripts de ce lutin',
'this script':
'ce script',
'this block':
'ce bloc',
// sensing:
'touching %col ?':
@ -958,6 +972,8 @@ SnapTranslator.dict.fr = {
'tabulations',
'cr':
'retours de ligne',
'letter':
'lettres',
// About Snap
'About Snap':
@ -1162,5 +1178,133 @@ SnapTranslator.dict.fr = {
'last':
'dernier',
'any':
'n\u0027importe quel'
'n\u0027importe quel',
// miscellaneous
'find blocks...':
'chercher des blocs...',
'hide primitives':
'cacher les primitives',
'show primitives':
'montrer les primitives',
'Login...':
'Connexion...',
'Signup...':
'S\u0027enregistrer...',
'Reset Password...':
'Remise \u00E0 z\u00E9ro du mot de passe',
'show all':
'tout montrer',
'pic...':
'image...',
'open a new window\nwith a picture of the stage':
'ouvre une nouvelle fen\u00EAtre\navec une image de la sc\u00E8ne',
'scripts pic...':
'image des scripts...',
'open a new window\nwith a picture of all scripts':
'ouvre une nouvelle fen\u00EAtre\navec une image de tous les scripts',
'Stage size...':
'Taille de la sc\u00E8ne...',
'Zoom blocks...':
'Agrandir les blocs...',
'Plain prototype labels':
'\u00C9tiquettes simples de d\u00E9finition',
'uncheck to always show (+) symbols\nin block prototype labels':
'd\u00E9cocher pour montrer en permance le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
'check to hide (+) symbols\nin block prototype labels':
'cocher pour cacher le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
'check for flat ends of lines':
'cocher pour dessiner des fins de ligne plates',
'uncheck for round ends of lines':
'd\u00E9cocher pour dessiner des fins de lignes arrondies',
'Flat line ends':
'Fins de ligne plates',
'Codification support':
'Support de la \u00AB codification \u00BB',
'uncheck to disable\nblock to text mapping features':
'd\u00E9cocher pour d\u00E9activer\nla fonction de transformation :\nbloc vers texte',
'check for block\nto text mapping features':
'cocher pour activer\nla fonction de transformation :\nbloc vers texte',
'current %dates':
'date courante %dates',
'year':'ann\u00E9e',
'month':'mois',
'date':'jour',
'hour':'heure',
'minute':'minute',
'second':'seconde',
'time in milliseconds':
'heure en millisecondes',
'day of week':
'jour de la semaine',
'brightness':
'luminosit\u00E9',
'transparence':
'transparence',
'negative':
'n\u00E9gatif',
'comic':
'bande dessin\u00E9e',
'clicked':
'cliqu\u00E9',
'pressed':
'press\u00E9',
'dropped':
'd\u00E9pos\u00E9',
'mouse-entered':
'survol\u00E9',
'mouse-departed':
'quitt\u00E9',
'JavaScript function ( %mult%s ) { %code }':
'fonction JavaScript ( %mult%s ) { %code }',
// Copy / Paste
'Press CTRL+C one more time to effectively copy to clipboard.':
'Taper une nouvelle fois sur CTRL+C pour copier effectivement vers le presse-papier.',
'Press CTRL+V one more time to effectively paste from clipboard.':
'Taper une nouvelle fois sur CTRL+V pour coller effectivement depuis le presse-papier.',
'Press CTRL+X one more time to effectively cut to clipboard.':
'Taper une nouvelle fois sur CTRL+X pour couper effectivement vers le presse-papier.',
// Paint.js
'undo':'d\u00E9faire',
'Paintbrush tool\n(free draw)':
'Pinceau\n(dessin \u00E0 main lev\u00E9)',
'Stroked Rectangle\n(shift: square)':
'Rectangle\n(Maj: carr\u00E9)',
'Stroked Ellipse\n(shift: circle)':
'Ellipse\n(Maj: cercle)',
'Eraser tool':
'Gomme',
'Set the rotation center':
'Fixe le centre de rotation',
'Line tool\n(shift: vertical/horizontal)':
'Ligne\n(Maj: verticale/horizontale)',
'Filled Rectangle\n(shift: square)':
'Rectangle plein\n(Maj: carr\u00E9)',
'Filled Ellipse\n(shift: circle)':
'Ellipse pleine\n(Maj: cercle)',
'Fill a region':
'Remplir une r\u00E9gion',
'Pipette tool\n(pick a color anywhere)':
'Pipette\n(s\u00E9lectionnez une couleur n\u0027importe o\u00F9',
'grow':'agrandir',
'shrink':'r\u00E9duire',
'flip \u2194':
'miroir \u2194',
'flip \u2195':
'miroir \u2195',
'Brush size':
'Taille de pinceau',
'Constrain proportions of shapes?\n(you can also hold shift)':
'Contrainte sur les proportions de la forme ?\n(vous pouvez aussi maintenir appuy\u00E9 Maj)'
};

Wyświetl plik

@ -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();

Wyświetl plik

@ -42,7 +42,7 @@
/*global modules, contains*/
modules.locale = '2015-May-18';
modules.locale = '2015-June-25';
// Global stuff
@ -257,7 +257,7 @@ SnapTranslator.dict.fr = {
'translator_e-mail':
'i.scool@mac.com',
'last_changed':
'2014-02-04'
'2015-06-25'
};
SnapTranslator.dict.si = {

Wyświetl plik

@ -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.
@ -828,13 +828,13 @@
// use context to paint stuff here
};
If your new morph stores or references other morphs outside of the
submorph tree in other properties, be sure to also override the
If your new morph stores or references to other morphs outside of
the 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-26';
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,19 +2399,19 @@ 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) {
var children = this.children,
i = children.length;
this.bounds = this.bounds.translateBy(delta);
this.children.forEach(function (child) {
child.silentMoveBy(delta);
});
// ugly optimization avoiding forEach()
for (i; i > 0; i -= 1) {
children[i - 1].silentMoveBy(delta);
}
};
Morph.prototype.setPosition = function (aPoint) {
@ -2899,7 +2887,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 +2924,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 +2951,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 +3022,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 +3140,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 +3689,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 +3910,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 +4233,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 +5799,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 () {
@ -6563,7 +6505,7 @@ InspectorMorph.prototype.setExtent = function (aPoint) {
this.fixLayout();
};
//InspectorMorph editing ops:
// InspectorMorph editing ops:
InspectorMorph.prototype.save = function () {
var txt = this.detail.contents.children[0].text.toString(),
@ -6653,6 +6595,15 @@ InspectorMorph.prototype.step = function () {
this.fixLayout();
};
// InspectorMorph duplicating:
InspectorMorph.prototype.updateReferences = function (map) {
var active = this.list.activeIndex();
InspectorMorph.uber.updateReferences.call(this, map);
this.buildPanes();
this.list.activateIndex(active);
};
// MenuMorph ///////////////////////////////////////////////////////////
// MenuMorph: referenced constructors
@ -7024,7 +6975,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 +7353,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 +8097,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 +8442,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 +8546,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 +8890,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:
@ -9147,6 +9070,18 @@ ListMorph.prototype.setExtent = function (aPoint) {
ListMorph.uber.setExtent.call(this, aPoint);
};
ListMorph.prototype.activeIndex = function () {
return this.listContents.children.indexOf(this.active);
};
ListMorph.prototype.activateIndex = function (idx) {
var item = this.listContents.children[idx];
if (!item) {return; }
item.image = item.pressImage;
item.changed();
item.trigger();
};
// StringFieldMorph ////////////////////////////////////////////////////
// StringFieldMorph inherit from FrameMorph:
@ -9243,20 +9178,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,55 +9305,19 @@ 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.prototype.fullChanged = HandMorph.prototype.changed;
// HandMorph navigation:
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;
return this.world.topMorphAt(this.bounds.origin) || this.world;
};
/*
alternative - more elegant and possibly more
performant - solution for morphAtPointer.
Has some issues, commented out for now
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));
});
};
*/
HandMorph.prototype.allMorphsAtPointer = function () {
var morphs = this.world.allChildren(),
myself = this;
@ -9971,16 +9856,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 +9884,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

Wyświetl plik

@ -7,9 +7,9 @@
written by Jens Mönig
jens@moenig.org
Copyright (C) 2012 by Jens Mönig
Copyright (C) 2015 by Jens Mönig
this documentation last changed: April 07, 2013
this documentation last changed: June 26, 2015
This file is part of Snap!.
@ -465,9 +465,15 @@
MyMorph.prototype.mouseMove = function(pos) {};
The only optional parameter of such a method is a Point object
All of these methods have as optional parameter a Point object
indicating the current position of the Hand inside the World's
coordinate system.
coordinate system. The
mouseMove(pos, button)
event method has an additional optional parameter indicating the
currently pressed mouse button, which is either 'left' or 'right'.
You can use this to let users interact with 3D environments.
Events may be "bubbled" up a morph's owner chain by calling
@ -522,6 +528,12 @@
a duplicate of the template whose "isDraggable" flag is true and
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.
Dragging is indicated by adding a drop shadow to the morph in hand.
If a morph follows the hand without displaying a drop shadow it is
merely being moved about without changing its parent (owner morph),
@ -817,13 +829,13 @@
// use context to paint stuff here
};
If your new morph stores or references other morphs outside of the
submorph tree in other properties, be sure to also override the
If your new morph stores or references to other morphs outside of
the 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
@ -1015,16 +1027,17 @@
programming hero.
I have originally written morphic.js in Florian Balmer's Notepad2
editor for Windows and later switched to Apple's Dashcode. I've also
come to depend on both Douglas Crockford's JSLint, Mozilla's Firebug
and Google's Chrome to get it right.
editor for Windows, later switched to Apple's Dashcode and later
still to Apple's Xcode. I've also come to depend on both Douglas
Crockford's JSLint, Mozilla's Firebug and Google's Chrome to get
it right.
IX. contributors
----------------------
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.

Wyświetl plik

@ -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());
@ -3509,7 +3509,10 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) {
if (morph.selector) {
if (morph.selector === 'receiveMessage') {
event = morph.inputs()[0].evaluate();
return event === message || (event instanceof Array);
return event === message
|| (event instanceof Array
&& message !== '__shout__go__'
&& message !== '__clone__init__');
}
if (morph.selector === 'receiveGo') {
return message === '__shout__go__';
@ -6429,7 +6432,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);

Wyświetl plik

@ -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

Wyświetl plik

@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/
// Global stuff ////////////////////////////////////////////////////////
modules.store = '2015-April-26';
modules.store = '2015-June-25';
// XML_Serializer ///////////////////////////////////////////////////////

Wyświetl plik

@ -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;
@ -339,7 +339,7 @@ ThreadManager.prototype.findProcess = function (block) {
*/
Process.prototype = {};
Process.prototype.contructor = Process;
Process.prototype.constructor = Process;
Process.prototype.timeout = 500; // msecs after which to force yield
Process.prototype.isCatchingErrors = true;
@ -2122,14 +2122,14 @@ Process.prototype.reportMonadic = function (fname, n) {
case 'ln':
result = Math.log(x);
break;
case 'log':
result = 0;
case 'log': // base 10
result = Math.log(x) / Math.LN10;
break;
case 'e^':
result = Math.exp(x);
break;
case '10^':
result = 0;
result = Math.pow(10, x);
break;
default:
nop();
@ -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;
};

Wyświetl plik

@ -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;

129
xml.js 100644 → 100755
Wyświetl plik

@ -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');