123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /**
- * @license Licensed under the Apache License, Version 2.0 (the "License"):
- * http://www.apache.org/licenses/LICENSE-2.0
- */
- /**
- * @fileoverview Instances input field.
- */
- 'use strict';
- goog.provide('Blockly.FieldInstance');
- goog.require('Blockly.FieldDropdown');
- goog.require('Blockly.Instances');
- goog.require('Blockly.Msg');
- goog.require('Blockly.utils');
- goog.require('goog.string');
- /**
- * Class for a specific type of instances' dropdown field.
- * @param {?string} instanceName The default name for the instance. If null,
- * a unique instance name will be generated.
- * @param {!string} instanceType The type of instances for the dropdown.
- * @param {boolean} uniqueName
- * @param {boolean=} opt_lockNew Indicates a special case in which this
- * dropdown can only rename the current name and each new block will always
- * have a unique name.
- * @param {boolean=} opt_lockRename
- * @param {Function=} opt_validator A function that is executed when a new
- * option is selected. Its sole argument is the new option value.
- * @extends {Blockly.FieldDropdown}
- * @constructor
- */
- Blockly.FieldInstance = function(
- instanceType, instanceName, uniqueName, opt_lockNew, opt_lockRename,
- opt_editDropdownData, opt_validator) {
- Blockly.FieldInstance.superClass_.constructor.call(this,
- this.dropdownCreate, opt_validator);
- this.instanceType_ = instanceType;
- this.setValue(instanceName);
- this.uniqueName_ = (uniqueName === true);
- this.lockNew_ = (opt_lockNew === true);
- this.lockRename_ = (opt_lockRename === true);
- this.editDropdownData = (opt_editDropdownData instanceof Function) ?
- opt_editDropdownData : null;
- };
- goog.inherits(Blockly.FieldInstance, Blockly.FieldDropdown);
- /**
- * Sets a new change handler for instance field.
- * @param {Function} handler New change handler, or null.
- */
- Blockly.FieldInstance.prototype.setValidator = function(handler) {
- var wrappedHandler;
- if (handler) {
- // Wrap the user's change handler together with the instance rename handler.
- wrappedHandler = function(value) {
- var v1 = handler.call(this, value);
- if (v1 === null) {
- var v2 = v1;
- } else {
- if (v1 === undefined) {
- v1 = value;
- }
- var v2 = Blockly.FieldInstance.dropdownChange.call(this, v1);
- if (v2 === undefined) {
- v2 = v1;
- }
- }
- return v2 === value ? undefined : v2;
- };
- } else {
- wrappedHandler = Blockly.FieldInstance.dropdownChange;
- }
- Blockly.FieldInstance.superClass_.setValidator.call(this, wrappedHandler);
- };
- /**
- * Install this dropdown on a block.
- */
- Blockly.FieldInstance.prototype.init = function() {
- // Nothing to do if the dropdown has already been initialised once.
- if (this.fieldGroup_) return;
- Blockly.FieldInstance.superClass_.init.call(this);
- var workspace = this.sourceBlock_.isInFlyout ?
- this.sourceBlock_.workspace.targetWorkspace : this.sourceBlock_.workspace;
- if (!this.getValue()) {
- // Instances without names get uniquely named for this workspace.
- this.setValue(Blockly.Instances.generateUniqueName(workspace));
- } else {
- if (this.uniqueName_) {
- // Ensure the given name is unique in the workspace, but not in flyout
- if (!this.sourceBlock_.isInFlyout) {
- this.setValue(
- Blockly.Instances.convertToUniqueNameBlock(
- this.getValue(), this.sourceBlock_));
- }
- } else {
- // Pick an existing name from the workspace if any exists
- var existingName =
- Blockly.Instances.getAnyInstanceOf(this.instanceType_ , workspace);
- if (existingName) this.setValue(existingName);
- }
- }
- };
- /**
- * Get the instance's name (use a variableDB to convert into a real name).
- * Unlike a regular dropdown, instances are literal and have no neutral value.
- * @return {string} Current text.
- */
- Blockly.FieldInstance.prototype.getValue = function() {
- return this.getText();
- };
- Blockly.FieldInstance.prototype.getInstanceTypeValue = function(instanceType) {
- return (instanceType === this.instanceType_) ? this.getText() : undefined;
- };
- /**
- * Set the instance name.
- * @param {string} newValue New text.
- */
- Blockly.FieldInstance.prototype.setValue = function(newValue) {
- if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
- Blockly.Events.fire(new Blockly.Events.Change(
- this.sourceBlock_, 'field', this.name, this.value_, newValue));
- }
- this.value_ = newValue;
- this.setText(newValue);
- };
- /**
- * Return a sorted list of instance names for instance dropdown menus.
- * If editDropdownData has been defined it passes this list to the
- * @return {!Array.<string>} Array of instance names.
- */
- Blockly.FieldInstance.prototype.dropdownCreate = function() {
- if (this.sourceBlock_ && this.sourceBlock_.workspace) {
- var instanceList =
- Blockly.Instances.allInstancesOf(this.instanceType_,
- this.sourceBlock_.workspace);
- } else {
- var instanceList = [];
- }
- // Ensure that the currently selected instance is an option.
- var name = this.getText();
- if (name && instanceList.indexOf(name) == -1) {
- instanceList.push(name);
- }
- instanceList.sort(goog.string.caseInsensitiveCompare);
- if (!this.lockRename_) {
- instanceList.push(Blockly.Msg.RENAME_INSTANCE);
- }
- if (!this.lockNew_) {
- instanceList.push(Blockly.Msg.NEW_INSTANCE);
- }
- // If configured, pass data to external handler for additional processing
- var options = this.editDropdownData ? this.editDropdownData(options) : [];
- // Instances are not language specific, so use for display and internal name
- for (var i = 0; i < instanceList.length; i++) {
- options[i] = [instanceList[i], instanceList[i]];
- }
- return options;
- };
- /**
- * Event handler for a change in instance name.
- * Special case the 'New instance...' and 'Rename instance...' options.
- * In both of these special cases, prompt the user for a new name.
- * @param {string} text The selected dropdown menu option.
- * @return {null|undefined|string} An acceptable new instance name, or null if
- * change is to be either aborted (cancel button) or has been already
- * handled (rename), or undefined if an existing instance was chosen.
- * @this {!Blockly.FieldInstance}
- */
- Blockly.FieldInstance.dropdownChange = function(text) {
- function promptName(promptText, defaultText, callback) {
- Blockly.hideChaff();
- var newVar = Blockly.prompt(promptText, defaultText, function(newVar) {
- // Merge runs of whitespace. Strip leading and trailing whitespace.
- // Beyond this, all names are legal.
- if (newVar) {
- newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
- if (newVar == Blockly.Msg.RENAME_INSTANCE ||
- newVar == Blockly.Msg.NEW_INSTANCE) {
- newVar = null; // Ok, not ALL names are legal...
- }
- }
- callback(newVar);
- });
- }
- var workspace = this.sourceBlock_.workspace;
- if (text == Blockly.Msg.RENAME_INSTANCE) {
- var oldInstance = this.getText();
- var thisFieldInstance = this;
- var callbackRename = function(text) {
- if (text) {
- Blockly.Instances.renameInstance(
- oldInstance, text, thisFieldInstance.instanceType_, workspace);
- }
- };
- promptName(Blockly.Msg.RENAME_INSTANCE_TITLE.replace('%1', oldInstance),
- oldInstance, callbackRename);
- return null;
- } else if (text == Blockly.Msg.NEW_INSTANCE) {
- //TODO: this return needs to be replaced with an asynchronous callback
- return Blockly.Instances.generateUniqueName(workspace);
- }
- return undefined;
- };
|