diff options
| -rw-r--r-- | blocks.js | 20 | ||||
| -rw-r--r-- | byob.js | 115 | ||||
| -rwxr-xr-x | history.txt | 10 | ||||
| -rw-r--r-- | store.js | 22 |
4 files changed, 106 insertions, 61 deletions
@@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2013-October-25'; +modules.blocks = '2013-November-12'; var SyntaxElementMorph; var BlockMorph; @@ -517,6 +517,12 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) { if (idx !== -1) { if (this instanceof BlockMorph) { deflt = this.labelPart(this.parseSpec(this.blockSpec)[idx]); + if (deflt instanceof InputSlotMorph && this.definition) { + deflt.choices = this.definition.dropDownMenuOfInputIdx( + this.inputs().indexOf(arg) + ); + deflt.fixLayout(); + } } else if (this instanceof MultiArgMorph) { deflt = this.labelPart(this.slotSpec); } else if (this instanceof ReporterSlotMorph) { @@ -1889,7 +1895,8 @@ BlockMorph.prototype.parseSpec = function (spec) { BlockMorph.prototype.setSpec = function (spec) { var myself = this, - part; + part, + inputIdx = -1; if (!spec) {return; } this.parts().forEach(function (part) { @@ -1899,6 +1906,9 @@ BlockMorph.prototype.setSpec = function (spec) { this.add(this.placeHolder()); } this.parseSpec(spec).forEach(function (word) { + if (word[0] === '%') { + inputIdx += 1; + } part = myself.labelPart(word); myself.add(part); if (!(part instanceof CommandSlotMorph)) { @@ -1917,6 +1927,10 @@ BlockMorph.prototype.setSpec = function (spec) { if (myself.isPrototype) { myself.add(myself.placeHolder()); } + if (part instanceof InputSlotMorph && myself.definition) { + part.choices = myself.definition.dropDownMenuOfInputIdx(inputIdx); + part.fixLayout(); // needed when de-serializing + } }); this.blockSpec = spec; this.fixLayout(); @@ -2325,7 +2339,7 @@ BlockMorph.prototype.mapToHeader = function () { } else { help = 'Enter code that corresponds to the block\'s definition. ' + 'Choose your own\nformal parameter names (ignoring the ones ' + - 'shown .'; + 'shown).'; } new DialogBoxMorph( this, @@ -102,11 +102,11 @@ ArrowMorph, PushButtonMorph, contains, InputSlotMorph, ShadowMorph, ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph, Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer, CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences, -SymbolMorph*/ +SymbolMorph, isNil*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2013-November-04'; +modules.byob = '2013-November-12'; // Declarations @@ -137,7 +137,7 @@ function CustomBlockDefinition(spec, receiver) { this.isGlobal = false; this.type = 'command'; this.spec = spec || ''; - this.declarations = {}; // {'inputName' : [type, default]} + this.declarations = {}; // {'inputName' : [type, default, options]} this.comment = null; this.codeMapping = null; // experimental, generate text code this.codeHeader = null; // experimental, generate text code @@ -192,6 +192,7 @@ CustomBlockDefinition.prototype.prototypeInstance = function () { if (slot) { part.fragment.type = slot[0]; part.fragment.defaultValue = slot[1]; + part.fragment.options = slot[2]; } } }); @@ -265,6 +266,23 @@ CustomBlockDefinition.prototype.defaultValueOfInputIdx = function (idx) { return this.defaultValueOf(inputName); }; +CustomBlockDefinition.prototype.dropDownMenuOfInputIdx = function (idx) { + var inputName = this.inputNames()[idx]; + return this.dropDownMenuOf(inputName); +}; + +CustomBlockDefinition.prototype.dropDownMenuOf = function (inputName) { + var dict = {}; + if (this.declarations[inputName] && this.declarations[inputName][2]) { + this.declarations[inputName][2].split('\n').forEach(function (line) { + var pair = line.split('='); + dict[pair[0]] = isNil(pair[1]) ? pair[0] : pair[1]; + }); + return dict; + } + return null; +}; + CustomBlockDefinition.prototype.inputNames = function () { var vNames = [], parts = this.parseSpec(this.spec); @@ -334,6 +352,13 @@ CustomCommandBlockMorph.prototype.refresh = function () { this.fixBlockColor(); this.fixLabelColor(); this.restoreInputs(oldInputs); + } else { // update all input slots' drop-downs + this.inputs().forEach(function (inp, i) { + if (inp instanceof InputSlotMorph) { + inp.choices = def.dropDownMenuOfInputIdx(i); + inp.fixLayout(); + } + }); } // find unnahmed upvars and label them @@ -383,48 +408,6 @@ CustomCommandBlockMorph.prototype.refreshDefaults = function () { }); }; -/* -custom drop down menus, still incomplete, commented out for now - -CustomCommandBlockMorph.prototype.refreshDefaults = function () { - // fill my editable slots with the defaults specified in my definition - var inputs = this.inputs(), idx = 0, myself = this, dflt; - - inputs.forEach(function (inp) { - if (inp instanceof InputSlotMorph) { - dflt = myself.parseDefault( - myself.definition.defaultValueOfInputIdx(idx) - ); - inp.choices = dflt.menu; - inp.setContents(dflt.value); - } - idx += 1; - }); -}; - -CustomCommandBlockMorph.prototype.parseDefault = function (str) { - // experimental shot at custom drop downs for input slots, - // answer an object of form: {value: 'bar', menu: {key: val, ...}} - var ans = {}, - menu = {}, - tokens; - if (str.indexOf('&') !== -1) { - tokens = str.split('&'); - ans.value = tokens[0]; - if (tokens[1]) { - tokens[1].split(',').forEach(function (entry) { - var pair = entry.split('='); - if (pair[0]) { - menu[pair[0]] = pair[1] || pair[0]; - } - }); - ans.menu = menu; - } - } - return ans; -}; -*/ - CustomCommandBlockMorph.prototype.refreshPrototype = function () { // create my label parts from my (edited) fragments only var hat, @@ -579,8 +562,11 @@ CustomCommandBlockMorph.prototype.declarationsFromFragments = function () { this.parts().forEach(function (part) { if (part instanceof BlockInputFragmentMorph) { - ans[part.fragment.labelString] = - [part.fragment.type, part.fragment.defaultValue]; + ans[part.fragment.labelString] = [ + part.fragment.type, + part.fragment.defaultValue, + part.fragment.options + ]; } }); return ans; @@ -1901,6 +1887,7 @@ function BlockLabelFragment(labelString) { this.labelString = labelString || ''; this.type = '%s'; // null for label, a spec for an input this.defaultValue = ''; + this.options = ''; this.isDeleted = false; } @@ -1950,6 +1937,7 @@ BlockLabelFragment.prototype.copy = function () { var ans = new BlockLabelFragment(this.labelString); ans.type = this.type; ans.defaultValue = this.defaultValue; + ans.options = this.options; return ans; }; @@ -2364,6 +2352,7 @@ InputSlotDialogMorph.prototype.init = function ( this.add(this.slots); this.createSlotTypeButtons(); this.fixSlotsLayout(); + this.addSlotsMenu(); this.createTypeButtons(); this.fixLayout(); }; @@ -2838,6 +2827,38 @@ InputSlotDialogMorph.prototype.fixSlotsLayout = function () { this.slots.changed(); }; +InputSlotDialogMorph.prototype.addSlotsMenu = function () { + var myself = this; + + this.slots.userMenu = function () { + if (contains(['%s', '%n', '%txt', '%anyUE'], myself.fragment.type)) { + var menu = new MenuMorph(myself); + menu.addItem('options...', 'editSlotOptions'); + return menu; + } + return Morph.prototype.userMenu.call(myself); + }; +}; + +InputSlotDialogMorph.prototype.editSlotOptions = function () { + var myself = this; + new DialogBoxMorph( + myself, + function (options) { + myself.fragment.options = options; + }, + myself + ).promptCode( + 'Input Slot Options', + myself.fragment.options, + myself.world(), + null, + 'Enter one option per line.' + + 'Optionally use "=" as key/value delimiter\n' + + 'e.g.\n the answer=42' + ); +}; + // InputSlotDialogMorph hiding and showing: /* diff --git a/history.txt b/history.txt index e24e7c3..8bc9b1c 100755 --- a/history.txt +++ b/history.txt @@ -1970,7 +1970,7 @@ ______ * Threads: fixed #213 - Empty else block breaks return to caller 131025 -——— +------ * Blocks: enable Costumes as Symbols and Symbols as custom block label parts * BYOB: Symbol selection menu for BlockLabelFragmentMorphs * Portuguese translation update @@ -1978,11 +1978,15 @@ ______ * BYOB: enable Symbols in InputSlotDialog Morph’s drop down menu 131104 -——— +------ * GUI: filter quotation marks from project names (for backend index) * BYOB: only show symbol menu for label fragments * BYOB: customizable drop-down menus for input slots (experimental, commented out) 131107 -——— +------ * GUI, Cloud: transmission integrity check + +131112 +------ +* Blocks, BYOB, Store: customizable drop-down menus for input slots @@ -49,7 +49,7 @@ */ -/*global modules, XML_Element, XML_Serializer, VariableFrame, StageMorph, +/*global modules, XML_Element, VariableFrame, StageMorph, SpriteMorph, WatcherMorph, Point, CustomBlockDefinition, Context, ReporterBlockMorph, CommandBlockMorph, HatBlockMorph, RingMorph, contains, detect, CustomCommandBlockMorph, CustomReporterBlockMorph, Color, List, @@ -61,7 +61,7 @@ SyntaxElementMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2013-September-17'; +modules.store = '2013-November-12'; // XML_Serializer /////////////////////////////////////////////////////// @@ -741,12 +741,16 @@ SnapSerializer.prototype.loadCustomBlocks = function ( if (inputs) { i = -1; inputs.children.forEach(function (child) { + var options = child.childNamed('options'); if (child.tag !== 'input') { return; } i += 1; - definition.declarations[names[i]] - = [child.attributes.type, child.contents]; + definition.declarations[names[i]] = [ + child.attributes.type, + child.contents, + options ? options.contents : undefined + ]; }); } @@ -1479,8 +1483,6 @@ VariableFrame.prototype.toXML = function (serializer) { }, ''); }; - - // Watchers WatcherMorph.prototype.toXML = function (serializer) { @@ -1661,9 +1663,13 @@ CustomBlockDefinition.prototype.toXML = function (serializer) { this.codeMapping || '', Object.keys(this.declarations).reduce(function (xml, decl) { return xml + serializer.format( - '<input type="@">$</input>', + '<input type="@">$%</input>', myself.declarations[decl][0], - myself.declarations[decl][1] + myself.declarations[decl][1], + myself.declarations[decl][2] ? + '<options>' + myself.declarations[decl][2] + + '</options>' + : '' ); }, ''), this.body ? serializer.store(this.body.expression) : '', |
