kopia lustrzana https://github.com/backface/turtlestitch
customizable drop-down menus for input slots
rodzic
cc7a1558f1
commit
651f44ebdf
20
blocks.js
20
blocks.js
|
@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.blocks = '2013-October-25';
|
modules.blocks = '2013-November-12';
|
||||||
|
|
||||||
var SyntaxElementMorph;
|
var SyntaxElementMorph;
|
||||||
var BlockMorph;
|
var BlockMorph;
|
||||||
|
@ -517,6 +517,12 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
if (this instanceof BlockMorph) {
|
if (this instanceof BlockMorph) {
|
||||||
deflt = this.labelPart(this.parseSpec(this.blockSpec)[idx]);
|
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) {
|
} else if (this instanceof MultiArgMorph) {
|
||||||
deflt = this.labelPart(this.slotSpec);
|
deflt = this.labelPart(this.slotSpec);
|
||||||
} else if (this instanceof ReporterSlotMorph) {
|
} else if (this instanceof ReporterSlotMorph) {
|
||||||
|
@ -1889,7 +1895,8 @@ BlockMorph.prototype.parseSpec = function (spec) {
|
||||||
|
|
||||||
BlockMorph.prototype.setSpec = function (spec) {
|
BlockMorph.prototype.setSpec = function (spec) {
|
||||||
var myself = this,
|
var myself = this,
|
||||||
part;
|
part,
|
||||||
|
inputIdx = -1;
|
||||||
|
|
||||||
if (!spec) {return; }
|
if (!spec) {return; }
|
||||||
this.parts().forEach(function (part) {
|
this.parts().forEach(function (part) {
|
||||||
|
@ -1899,6 +1906,9 @@ BlockMorph.prototype.setSpec = function (spec) {
|
||||||
this.add(this.placeHolder());
|
this.add(this.placeHolder());
|
||||||
}
|
}
|
||||||
this.parseSpec(spec).forEach(function (word) {
|
this.parseSpec(spec).forEach(function (word) {
|
||||||
|
if (word[0] === '%') {
|
||||||
|
inputIdx += 1;
|
||||||
|
}
|
||||||
part = myself.labelPart(word);
|
part = myself.labelPart(word);
|
||||||
myself.add(part);
|
myself.add(part);
|
||||||
if (!(part instanceof CommandSlotMorph)) {
|
if (!(part instanceof CommandSlotMorph)) {
|
||||||
|
@ -1917,6 +1927,10 @@ BlockMorph.prototype.setSpec = function (spec) {
|
||||||
if (myself.isPrototype) {
|
if (myself.isPrototype) {
|
||||||
myself.add(myself.placeHolder());
|
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.blockSpec = spec;
|
||||||
this.fixLayout();
|
this.fixLayout();
|
||||||
|
@ -2325,7 +2339,7 @@ BlockMorph.prototype.mapToHeader = function () {
|
||||||
} else {
|
} else {
|
||||||
help = 'Enter code that corresponds to the block\'s definition. ' +
|
help = 'Enter code that corresponds to the block\'s definition. ' +
|
||||||
'Choose your own\nformal parameter names (ignoring the ones ' +
|
'Choose your own\nformal parameter names (ignoring the ones ' +
|
||||||
'shown .';
|
'shown).';
|
||||||
}
|
}
|
||||||
new DialogBoxMorph(
|
new DialogBoxMorph(
|
||||||
this,
|
this,
|
||||||
|
|
115
byob.js
115
byob.js
|
@ -102,11 +102,11 @@ ArrowMorph, PushButtonMorph, contains, InputSlotMorph, ShadowMorph,
|
||||||
ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph,
|
ToggleButtonMorph, IDE_Morph, MenuMorph, copy, ToggleElementMorph,
|
||||||
Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer,
|
Morph, fontHeight, StageMorph, SyntaxElementMorph, SnapSerializer,
|
||||||
CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences,
|
CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences,
|
||||||
SymbolMorph*/
|
SymbolMorph, isNil*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.byob = '2013-November-04';
|
modules.byob = '2013-November-12';
|
||||||
|
|
||||||
// Declarations
|
// Declarations
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ function CustomBlockDefinition(spec, receiver) {
|
||||||
this.isGlobal = false;
|
this.isGlobal = false;
|
||||||
this.type = 'command';
|
this.type = 'command';
|
||||||
this.spec = spec || '';
|
this.spec = spec || '';
|
||||||
this.declarations = {}; // {'inputName' : [type, default]}
|
this.declarations = {}; // {'inputName' : [type, default, options]}
|
||||||
this.comment = null;
|
this.comment = null;
|
||||||
this.codeMapping = null; // experimental, generate text code
|
this.codeMapping = null; // experimental, generate text code
|
||||||
this.codeHeader = null; // experimental, generate text code
|
this.codeHeader = null; // experimental, generate text code
|
||||||
|
@ -192,6 +192,7 @@ CustomBlockDefinition.prototype.prototypeInstance = function () {
|
||||||
if (slot) {
|
if (slot) {
|
||||||
part.fragment.type = slot[0];
|
part.fragment.type = slot[0];
|
||||||
part.fragment.defaultValue = slot[1];
|
part.fragment.defaultValue = slot[1];
|
||||||
|
part.fragment.options = slot[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -265,6 +266,23 @@ CustomBlockDefinition.prototype.defaultValueOfInputIdx = function (idx) {
|
||||||
return this.defaultValueOf(inputName);
|
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 () {
|
CustomBlockDefinition.prototype.inputNames = function () {
|
||||||
var vNames = [],
|
var vNames = [],
|
||||||
parts = this.parseSpec(this.spec);
|
parts = this.parseSpec(this.spec);
|
||||||
|
@ -334,6 +352,13 @@ CustomCommandBlockMorph.prototype.refresh = function () {
|
||||||
this.fixBlockColor();
|
this.fixBlockColor();
|
||||||
this.fixLabelColor();
|
this.fixLabelColor();
|
||||||
this.restoreInputs(oldInputs);
|
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
|
// 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 () {
|
CustomCommandBlockMorph.prototype.refreshPrototype = function () {
|
||||||
// create my label parts from my (edited) fragments only
|
// create my label parts from my (edited) fragments only
|
||||||
var hat,
|
var hat,
|
||||||
|
@ -579,8 +562,11 @@ CustomCommandBlockMorph.prototype.declarationsFromFragments = function () {
|
||||||
|
|
||||||
this.parts().forEach(function (part) {
|
this.parts().forEach(function (part) {
|
||||||
if (part instanceof BlockInputFragmentMorph) {
|
if (part instanceof BlockInputFragmentMorph) {
|
||||||
ans[part.fragment.labelString] =
|
ans[part.fragment.labelString] = [
|
||||||
[part.fragment.type, part.fragment.defaultValue];
|
part.fragment.type,
|
||||||
|
part.fragment.defaultValue,
|
||||||
|
part.fragment.options
|
||||||
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return ans;
|
return ans;
|
||||||
|
@ -1901,6 +1887,7 @@ function BlockLabelFragment(labelString) {
|
||||||
this.labelString = labelString || '';
|
this.labelString = labelString || '';
|
||||||
this.type = '%s'; // null for label, a spec for an input
|
this.type = '%s'; // null for label, a spec for an input
|
||||||
this.defaultValue = '';
|
this.defaultValue = '';
|
||||||
|
this.options = '';
|
||||||
this.isDeleted = false;
|
this.isDeleted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1950,6 +1937,7 @@ BlockLabelFragment.prototype.copy = function () {
|
||||||
var ans = new BlockLabelFragment(this.labelString);
|
var ans = new BlockLabelFragment(this.labelString);
|
||||||
ans.type = this.type;
|
ans.type = this.type;
|
||||||
ans.defaultValue = this.defaultValue;
|
ans.defaultValue = this.defaultValue;
|
||||||
|
ans.options = this.options;
|
||||||
return ans;
|
return ans;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2364,6 +2352,7 @@ InputSlotDialogMorph.prototype.init = function (
|
||||||
this.add(this.slots);
|
this.add(this.slots);
|
||||||
this.createSlotTypeButtons();
|
this.createSlotTypeButtons();
|
||||||
this.fixSlotsLayout();
|
this.fixSlotsLayout();
|
||||||
|
this.addSlotsMenu();
|
||||||
this.createTypeButtons();
|
this.createTypeButtons();
|
||||||
this.fixLayout();
|
this.fixLayout();
|
||||||
};
|
};
|
||||||
|
@ -2838,6 +2827,38 @@ InputSlotDialogMorph.prototype.fixSlotsLayout = function () {
|
||||||
this.slots.changed();
|
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:
|
// InputSlotDialogMorph hiding and showing:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
10
history.txt
10
history.txt
|
@ -1970,7 +1970,7 @@ ______
|
||||||
* Threads: fixed #213 - Empty else block breaks return to caller
|
* Threads: fixed #213 - Empty else block breaks return to caller
|
||||||
|
|
||||||
131025
|
131025
|
||||||
———
|
------
|
||||||
* Blocks: enable Costumes as Symbols and Symbols as custom block label parts
|
* Blocks: enable Costumes as Symbols and Symbols as custom block label parts
|
||||||
* BYOB: Symbol selection menu for BlockLabelFragmentMorphs
|
* BYOB: Symbol selection menu for BlockLabelFragmentMorphs
|
||||||
* Portuguese translation update
|
* Portuguese translation update
|
||||||
|
@ -1978,11 +1978,15 @@ ______
|
||||||
* BYOB: enable Symbols in InputSlotDialog Morph’s drop down menu
|
* BYOB: enable Symbols in InputSlotDialog Morph’s drop down menu
|
||||||
|
|
||||||
131104
|
131104
|
||||||
———
|
------
|
||||||
* GUI: filter quotation marks from project names (for backend index)
|
* GUI: filter quotation marks from project names (for backend index)
|
||||||
* BYOB: only show symbol menu for label fragments
|
* BYOB: only show symbol menu for label fragments
|
||||||
* BYOB: customizable drop-down menus for input slots (experimental, commented out)
|
* BYOB: customizable drop-down menus for input slots (experimental, commented out)
|
||||||
|
|
||||||
131107
|
131107
|
||||||
———
|
------
|
||||||
* GUI, Cloud: transmission integrity check
|
* GUI, Cloud: transmission integrity check
|
||||||
|
|
||||||
|
131112
|
||||||
|
------
|
||||||
|
* Blocks, BYOB, Store: customizable drop-down menus for input slots
|
||||||
|
|
22
store.js
22
store.js
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*global modules, XML_Element, XML_Serializer, VariableFrame, StageMorph,
|
/*global modules, XML_Element, VariableFrame, StageMorph,
|
||||||
SpriteMorph, WatcherMorph, Point, CustomBlockDefinition, Context,
|
SpriteMorph, WatcherMorph, Point, CustomBlockDefinition, Context,
|
||||||
ReporterBlockMorph, CommandBlockMorph, HatBlockMorph, RingMorph, contains,
|
ReporterBlockMorph, CommandBlockMorph, HatBlockMorph, RingMorph, contains,
|
||||||
detect, CustomCommandBlockMorph, CustomReporterBlockMorph, Color, List,
|
detect, CustomCommandBlockMorph, CustomReporterBlockMorph, Color, List,
|
||||||
|
@ -61,7 +61,7 @@ SyntaxElementMorph*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.store = '2013-September-17';
|
modules.store = '2013-November-12';
|
||||||
|
|
||||||
|
|
||||||
// XML_Serializer ///////////////////////////////////////////////////////
|
// XML_Serializer ///////////////////////////////////////////////////////
|
||||||
|
@ -741,12 +741,16 @@ SnapSerializer.prototype.loadCustomBlocks = function (
|
||||||
if (inputs) {
|
if (inputs) {
|
||||||
i = -1;
|
i = -1;
|
||||||
inputs.children.forEach(function (child) {
|
inputs.children.forEach(function (child) {
|
||||||
|
var options = child.childNamed('options');
|
||||||
if (child.tag !== 'input') {
|
if (child.tag !== 'input') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
definition.declarations[names[i]]
|
definition.declarations[names[i]] = [
|
||||||
= [child.attributes.type, child.contents];
|
child.attributes.type,
|
||||||
|
child.contents,
|
||||||
|
options ? options.contents : undefined
|
||||||
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1479,8 +1483,6 @@ VariableFrame.prototype.toXML = function (serializer) {
|
||||||
}, '');
|
}, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Watchers
|
// Watchers
|
||||||
|
|
||||||
WatcherMorph.prototype.toXML = function (serializer) {
|
WatcherMorph.prototype.toXML = function (serializer) {
|
||||||
|
@ -1661,9 +1663,13 @@ CustomBlockDefinition.prototype.toXML = function (serializer) {
|
||||||
this.codeMapping || '',
|
this.codeMapping || '',
|
||||||
Object.keys(this.declarations).reduce(function (xml, decl) {
|
Object.keys(this.declarations).reduce(function (xml, decl) {
|
||||||
return xml + serializer.format(
|
return xml + serializer.format(
|
||||||
'<input type="@">$</input>',
|
'<input type="@">$%</input>',
|
||||||
myself.declarations[decl][0],
|
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) : '',
|
this.body ? serializer.store(this.body.expression) : '',
|
||||||
|
|
Ładowanie…
Reference in New Issue