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