diff --git a/blocks.js b/blocks.js
index bb09c386..1c64eb6a 100644
--- a/blocks.js
+++ b/blocks.js
@@ -149,7 +149,7 @@ BlockEditorMorph, localize, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2016-February-24';
+modules.blocks = '2016-March-16';
var SyntaxElementMorph;
var BlockMorph;
@@ -2216,6 +2216,16 @@ BlockMorph.prototype.userMenu = function () {
top,
blck;
+ function addOption(label, toggle, test, onHint, offHint) {
+ var on = '\u2611 ',
+ off = '\u2610 ';
+ menu.addItem(
+ (test ? on : off) + localize(label),
+ toggle,
+ test ? onHint : offHint
+ );
+ }
+
menu.addItem(
"help...",
'showHelp'
@@ -2236,7 +2246,15 @@ BlockMorph.prototype.userMenu = function () {
}
if (this.isTemplate) {
if (!(this.parent instanceof SyntaxElementMorph)) {
- if (this.selector !== 'evaluateCustomBlock') {
+ if (this.selector === 'reportGetVar') {
+ addOption(
+ 'transient',
+ 'toggleTransientVariable',
+ myself.isTransientVariable(),
+ 'uncheck to save contents\nin the project',
+ 'check to prevent contents\nfrom being saved'
+ );
+ } else if (this.selector !== 'evaluateCustomBlock') {
menu.addItem(
"hide",
'hidePrimitive'
@@ -2430,6 +2448,20 @@ BlockMorph.prototype.hidePrimitive = function () {
ide.refreshPalette();
};
+BlockMorph.prototype.isTransientVariable = function () {
+ // private - only for variable getter template inside the palette
+ var varFrame = this.receiver().variables.silentFind(this.blockSpec);
+ return varFrame ? varFrame.vars[this.blockSpec].isTransient : false;
+};
+
+BlockMorph.prototype.toggleTransientVariable = function () {
+ // private - only for variable getter template inside the palette
+ var varFrame = this.receiver().variables.silentFind(this.blockSpec);
+ if (!varFrame) {return; }
+ varFrame.vars[this.blockSpec].isTransient =
+ !(varFrame.vars[this.blockSpec].isTransient);
+};
+
BlockMorph.prototype.deleteBlock = function () {
// delete just this one block, keep inputs and next block around
var scripts = this.parentThatIsA(ScriptsMorph),
diff --git a/gui.js b/gui.js
index 9df9e632..f284adb2 100644
--- a/gui.js
+++ b/gui.js
@@ -69,7 +69,7 @@ XML_Element, WatcherMorph, BlockRemovalDialogMorph, saveAs, TableMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2016-February-24';
+modules.gui = '2016-March-16';
// Declarations
@@ -2524,6 +2524,17 @@ IDE_Morph.prototype.settingsMenu = function () {
'check for sprite\ninheritance features',
false
);
+ addPreference(
+ 'Persist linked sublist IDs',
+ function () {
+ StageMorph.prototype.enableSublistIDs =
+ !StageMorph.prototype.enableSublistIDs;
+ },
+ StageMorph.prototype.enableSublistIDs,
+ 'uncheck to disable\nsaving linked sublist identities',
+ 'check to enable\nsaving linked sublist identities',
+ true
+ );
menu.popup(world, pos);
};
@@ -2796,7 +2807,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world();
- aboutTxt = 'Snap! 4.0.5\nBuild Your Own Blocks\n\n'
+ aboutTxt = 'Snap! 4.0.6\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2016 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@@ -3014,6 +3025,7 @@ IDE_Morph.prototype.newProject = function () {
StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
+ StageMorph.prototype.enableSublistIDs = false;
SpriteMorph.prototype.useFlatLineEnds = false;
this.setProjectName('');
this.projectNotes = '';
@@ -3521,6 +3533,7 @@ IDE_Morph.prototype.rawOpenProjectString = function (str) {
StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
+ StageMorph.prototype.enableSublistIDs = false;
if (Process.prototype.isCatchingErrors) {
try {
this.serializer.openProject(
@@ -3564,6 +3577,7 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
+ StageMorph.prototype.enableSublistIDs = false;
if (Process.prototype.isCatchingErrors) {
try {
model = this.serializer.parse(str);
diff --git a/history.txt b/history.txt
index 5485ea59..4133bdae 100755
--- a/history.txt
+++ b/history.txt
@@ -2874,3 +2874,11 @@ end - bulk of 151215
160306
------
* Objects: Reenable custom hat blocks when dropping a sprite
+
+160316
+------
+* Store, Objects, GUI: fixed #99 (saving linked lists)
+* Objects: fixed #1163
+* added web api / https reporter library
+* Blocks, Store: New “transient variable” feature
+* German translation update
diff --git a/lang-de.js b/lang-de.js
index 9d013954..b52fb771 100644
--- a/lang-de.js
+++ b/lang-de.js
@@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org', // optional
'last_changed':
- '2016-02-24', // this, too, will appear in the Translators tab
+ '2016-03-16', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -881,6 +881,12 @@ SnapTranslator.dict.de = {
'Umringen',
'unringify':
'Entringen',
+ 'transient':
+ 'nicht persistent',
+ 'uncheck to save contents\nin the project':
+ 'ausschalten, um den Inhalt\nim Projekt zu speichern',
+ 'check to prevent contents\nfrom being saved':
+ 'einschalten, um das Speichern des Inhalts\nim Projekt zu verhindern',
// custom blocks:
'delete block definition...':
diff --git a/libraries/LIBRARIES b/libraries/LIBRARIES
index a326ce14..3ce9dd9c 100644
--- a/libraries/LIBRARIES
+++ b/libraries/LIBRARIES
@@ -2,6 +2,7 @@ iteration-composition.xml Iteration, composition
list-utilities.xml List utilities
stream-tools.xml Streams (lazy lists)
variadic-reporters.xml Variadic reporters
+httpBlocks.xml Web services access (https)
word-sentence.xml Words, sentences
cases.xml Multi-branched conditional (switch)
leap-library.xml LEAP Motion controller
diff --git a/libraries/httpBlocks.xml b/libraries/httpBlocks.xml
new file mode 100644
index 00000000..a0086960
--- /dev/null
+++ b/libraries/httpBlocks.xml
@@ -0,0 +1,4 @@
+
GETGET
+POST
+PUT
+DELETEhttp://snap.berkeley.edu
\ No newline at end of file
diff --git a/locale.js b/locale.js
index eb0cc189..749df7fc 100644
--- a/locale.js
+++ b/locale.js
@@ -42,7 +42,7 @@
/*global modules, contains*/
-modules.locale = '2016-February-24';
+modules.locale = '2016-March-16';
// Global stuff
@@ -161,7 +161,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org',
'last_changed':
- '2016-02-24'
+ '2016-03-16'
};
SnapTranslator.dict.it = {
diff --git a/objects.js b/objects.js
index 8a58df8a..f7314b07 100644
--- a/objects.js
+++ b/objects.js
@@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph*/
-modules.objects = '2016-March-06';
+modules.objects = '2016-March-16';
var SpriteMorph;
var StageMorph;
@@ -2423,7 +2423,7 @@ SpriteMorph.prototype.blocksMatching = function (
// variable getters
varNames.forEach(function (vName) {
- var rel = relevance(labelOf(vName), search);
+ var rel = relevance(labelOf(vName.toLowerCase()), search);
if (rel !== -1) {
blocks.push([myself.variableBlock(vName), rel + '1']);
}
@@ -4726,6 +4726,7 @@ StageMorph.prototype.codeMappings = {};
StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
StageMorph.prototype.enableInheritance = false;
+StageMorph.prototype.enableSublistIDs = false;
// StageMorph instance creation
diff --git a/store.js b/store.js
index 9a636c81..3b663907 100644
--- a/store.js
+++ b/store.js
@@ -60,7 +60,7 @@ SyntaxElementMorph, Variable*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2016-February-24';
+modules.store = '2016-March-16';
// XML_Serializer ///////////////////////////////////////////////////////
@@ -414,6 +414,8 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
model.stage.attributes.codify === 'true';
StageMorph.prototype.enableInheritance =
model.stage.attributes.inheritance === 'true';
+ StageMorph.prototype.enableSublistIDs =
+ model.stage.attributes.sublistIDs === 'true';
model.hiddenPrimitives = model.project.childNamed('hidden');
if (model.hiddenPrimitives) {
@@ -773,13 +775,15 @@ SnapSerializer.prototype.loadVariables = function (varFrame, element) {
var myself = this;
element.children.forEach(function (child) {
- var value;
+ var v, value;
if (child.tag !== 'variable') {
return;
}
value = child.children[0];
- varFrame.vars[child.attributes.name] = new Variable(value ?
- myself.loadValue(value) : 0);
+ v = new Variable();
+ v.isTransient = (child.attributes.transient === 'true');
+ v.value = (v.isTransient || !value ) ? 0 : myself.loadValue(value);
+ varFrame.vars[child.attributes.name] = v;
});
};
@@ -1121,7 +1125,7 @@ SnapSerializer.prototype.loadInput = function (model, input, block) {
SnapSerializer.prototype.loadValue = function (model) {
// private
- var v, items, el, center, image, name, audio, option,
+ var v, lst, items, el, center, image, name, audio, option,
myself = this;
function record() {
@@ -1157,28 +1161,29 @@ SnapSerializer.prototype.loadValue = function (model) {
return model.contents === 'true';
case 'list':
if (model.attributes.hasOwnProperty('linked')) {
+ v = new List();
+ v.isLinked = true;
+ record();
+ lst = v;
items = model.childrenNamed('item');
- if (items.length === 0) {
- v = new List();
- record();
- return v;
- }
items.forEach(function (item) {
var value = item.children[0];
- if (v === undefined) {
- v = new List();
- record();
- } else {
- v = v.rest = new List();
- }
- v.isLinked = true;
if (!value) {
v.first = 0;
} else {
v.first = myself.loadValue(value);
}
+ var tail = model.childNamed('list') ||
+ model.childNamed('ref');
+ if (tail) {
+ v.rest = myself.loadValue(tail);
+ } else {
+ v.rest = new List();
+ v = v.rest;
+ v.isLinked = true;
+ }
});
- return v;
+ return lst;
}
v = new List();
record();
@@ -1446,6 +1451,7 @@ StageMorph.prototype.toXML = function (serializer) {
'lines="@" ' +
'codify="@" ' +
'inheritance="@" ' +
+ 'sublistIDs="@" ' +
'scheduled="@" ~>' +
'$' +
'%' +
@@ -1474,6 +1480,7 @@ StageMorph.prototype.toXML = function (serializer) {
SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round',
this.enableCodeMapping,
this.enableInheritance,
+ this.enableSublistIDs,
StageMorph.prototype.frameRate !== 0,
this.trailsCanvas.toDataURL('image/png'),
serializer.store(this.costumes, this.name + '_cst'),
@@ -1587,7 +1594,12 @@ VariableFrame.prototype.toXML = function (serializer) {
return Object.keys(this.vars).reduce(function (vars, v) {
var val = myself.vars[v].value,
dta;
- if (val === undefined || val === null) {
+ if (myself.vars[v].isTransient) {
+ dta = serializer.format(
+ '',
+ v)
+ ;
+ } else if (val === undefined || val === null) {
dta = serializer.format('', v);
} else {
dta = serializer.format(
@@ -1875,19 +1887,46 @@ ColorSlotMorph.prototype.toXML = function (serializer) {
List.prototype.toXML = function (serializer, mediaContext) {
// mediaContext is an optional name-stub
// when collecting media into a separate module
- var xml, item;
+ var xml, value, item;
if (this.isLinked) {
xml = '';
+ if (StageMorph.prototype.enableSublistIDs) {
+ // recursively nest tails:
+ value = this.first;
+ if (!isNil(value)) {
+ xml += serializer.format(
+ '- %
',
+ typeof value === 'object' ?
+ serializer.store(value, mediaContext)
+ : typeof value === 'boolean' ?
+ serializer.format('$', value)
+ : serializer.format('$', value)
+ );
+ }
+ if (!isNil(this.rest)) {
+ xml += serializer.store(this.rest, mediaContext);
+ }
+ return xml + '
';
+ }
+ // else sequentially serialize tails:
item = this;
do {
- xml += serializer.format(
- '- %
',
- serializer.store(item.first)
- );
+ value = item.first;
+ if (!isNil(value)) {
+ xml += serializer.format(
+ '- %
',
+ typeof value === 'object' ?
+ serializer.store(value, mediaContext)
+ : typeof value === 'boolean' ?
+ serializer.format('$', value)
+ : serializer.format('$', value)
+ );
+ }
item = item.rest;
- } while (item !== undefined && (item !== null));
+ } while (!isNil(item));
return xml + '';
}
+ // dynamic array:
return serializer.format(
'%
',
this.contents.reduce(function (xml, item) {
@@ -1903,7 +1942,6 @@ List.prototype.toXML = function (serializer, mediaContext) {
);
};
-
Context.prototype.toXML = function (serializer) {
if (this.isContinuation) { // continuations are transient in Snap!
return '';
diff --git a/threads.js b/threads.js
index ea2d9ccc..85124149 100644
--- a/threads.js
+++ b/threads.js
@@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph*/
-modules.threads = '2016-February-24';
+modules.threads = '2016-March-16';
var ThreadManager;
var Process;
@@ -3240,16 +3240,18 @@ Context.prototype.stackSize = function () {
// Variable /////////////////////////////////////////////////////////////////
-function Variable(value) {
+function Variable(value, isTransient) {
this.value = value;
+ this.isTransient = isTransient || false; // prevent value serialization
}
Variable.prototype.toString = function () {
- return 'a Variable [' + this.value + ']';
+ return 'a ' + this.isTransient ? 'transient ' : '' + 'Variable [' +
+ this.value + ']';
};
Variable.prototype.copy = function () {
- return new Variable(this.value);
+ return new Variable(this.value, this.isTransient);
};
// VariableFrame ///////////////////////////////////////////////////////