Initial commit of 001code-html Scratch frontend project.
Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
666
scratch-blocks/blocks_vertical/data.js
Normal file
666
scratch-blocks/blocks_vertical/data.js
Normal file
@@ -0,0 +1,666 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2016 Massachusetts Institute of Technology
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.data');
|
||||
goog.provide('Blockly.Constants.Data');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.Colours');
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.ScratchBlocks.VerticalExtensions');
|
||||
|
||||
|
||||
Blockly.Blocks['data_variable'] = {
|
||||
/**
|
||||
* Block of Variables
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "%1",
|
||||
"lastDummyAlign0": "CENTRE",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable_getter",
|
||||
"text": "",
|
||||
"name": "VARIABLE",
|
||||
"variableType": ""
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.data,
|
||||
"checkboxInFlyout": true,
|
||||
"extensions": ["contextMenu_getVariableBlock", "colours_data", "output_string"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_setvariableto'] = {
|
||||
/**
|
||||
* Block to set variable to a certain value
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_SETVARIABLETO,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VARIABLE"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE"
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_data", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_changevariableby'] = {
|
||||
/**
|
||||
* Block to change variable by a certain value
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_CHANGEVARIABLEBY,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VARIABLE"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE"
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_data", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_showvariable'] = {
|
||||
/**
|
||||
* Block to show a variable
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_SHOWVARIABLE,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VARIABLE"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_data"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_hidevariable'] = {
|
||||
/**
|
||||
* Block to hide a variable
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_HIDEVARIABLE,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VARIABLE"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_data"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_listcontents'] = {
|
||||
/**
|
||||
* List reporter.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable_getter",
|
||||
"text": "",
|
||||
"name": "LIST",
|
||||
"variableType": Blockly.LIST_VARIABLE_TYPE
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["contextMenu_getListBlock", "colours_data_lists", "output_string"],
|
||||
"checkboxInFlyout": true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_listindexall'] = {
|
||||
/**
|
||||
* List index menu, with all option.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_numberdropdown",
|
||||
"name": "INDEX",
|
||||
"value": "1",
|
||||
"min": 1,
|
||||
"precision": 1,
|
||||
"options": [
|
||||
["1", "1"],
|
||||
[Blockly.Msg.DATA_INDEX_LAST, "last"],
|
||||
[Blockly.Msg.DATA_INDEX_ALL, "all"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_textfield", "output_string"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_listindexrandom'] = {
|
||||
/**
|
||||
* List index menu, with random option.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_numberdropdown",
|
||||
"name": "INDEX",
|
||||
"value": "1",
|
||||
"min": 1,
|
||||
"precision": 1,
|
||||
"options": [
|
||||
["1", "1"],
|
||||
[Blockly.Msg.DATA_INDEX_LAST, "last"],
|
||||
[Blockly.Msg.DATA_INDEX_RANDOM, "random"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.data,
|
||||
"extensions": ["colours_textfield", "output_string"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_addtolist'] = {
|
||||
/**
|
||||
* Block to add item to list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_ADDTOLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_deleteoflist'] = {
|
||||
/**
|
||||
* Block to delete item from list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_DELETEOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "INDEX"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_deletealloflist'] = {
|
||||
/**
|
||||
* Block to delete all items from list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_DELETEALLOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_insertatlist'] = {
|
||||
/**
|
||||
* Block to insert item to list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_INSERTATLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "INDEX"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_replaceitemoflist'] = {
|
||||
/**
|
||||
* Block to insert item to list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_REPLACEITEMOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "INDEX"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_itemoflist'] = {
|
||||
/**
|
||||
* Block for reporting item of list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_ITEMOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "INDEX"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"output": null,
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists"],
|
||||
"outputShape": Blockly.OUTPUT_SHAPE_ROUND
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_itemnumoflist'] = {
|
||||
/**
|
||||
* Block for reporting the item # of a string in a list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_ITEMNUMOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
},
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"output": null,
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists"],
|
||||
"outputShape": Blockly.OUTPUT_SHAPE_ROUND
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_lengthoflist'] = {
|
||||
/**
|
||||
* Block for reporting length of list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_LENGTHOFLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "output_number"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_listcontainsitem'] = {
|
||||
/**
|
||||
* Block to report whether list contains item.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_LISTCONTAINSITEM,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "output_boolean"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_showlist'] = {
|
||||
/**
|
||||
* Block to show a list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_SHOWLIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['data_hidelist'] = {
|
||||
/**
|
||||
* Block to hide a list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.DATA_HIDELIST,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "LIST",
|
||||
"variableTypes": [Blockly.LIST_VARIABLE_TYPE]
|
||||
}
|
||||
],
|
||||
"category": Blockly.Categories.dataLists,
|
||||
"extensions": ["colours_data_lists", "shape_statement"]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin to add a context menu for a data_variable block. It adds one item for
|
||||
* each variable defined on the workspace.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Data.CUSTOM_CONTEXT_MENU_GET_VARIABLE_MIXIN = {
|
||||
/**
|
||||
* Add context menu option to change the selected variable.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
var fieldName = 'VARIABLE';
|
||||
if (this.isCollapsed()) {
|
||||
return;
|
||||
}
|
||||
var currentVarName = this.getField(fieldName).text_;
|
||||
if (!this.isInFlyout) {
|
||||
var variablesList = this.workspace.getVariablesOfType('');
|
||||
variablesList.sort(function(a, b) {
|
||||
return Blockly.scratchBlocksUtils.compareStrings(a.name, b.name);
|
||||
});
|
||||
for (var i = 0; i < variablesList.length; i++) {
|
||||
var varName = variablesList[i].name;
|
||||
if (varName == currentVarName) continue;
|
||||
|
||||
var option = {enabled: true};
|
||||
option.text = varName;
|
||||
|
||||
option.callback =
|
||||
Blockly.Constants.Data.VARIABLE_OPTION_CALLBACK_FACTORY(this,
|
||||
variablesList[i].getId(), fieldName);
|
||||
options.push(option);
|
||||
}
|
||||
} else {
|
||||
var renameOption = {
|
||||
text: Blockly.Msg.RENAME_VARIABLE,
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Data.RENAME_OPTION_CALLBACK_FACTORY(this,
|
||||
fieldName)
|
||||
};
|
||||
var deleteOption = {
|
||||
text: Blockly.Msg.DELETE_VARIABLE.replace('%1', currentVarName),
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Data.DELETE_OPTION_CALLBACK_FACTORY(this,
|
||||
fieldName)
|
||||
};
|
||||
options.push(renameOption);
|
||||
options.push(deleteOption);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_getVariableBlock',
|
||||
Blockly.Constants.Data.CUSTOM_CONTEXT_MENU_GET_VARIABLE_MIXIN);
|
||||
|
||||
/**
|
||||
* Mixin to add a context menu for a data_listcontents block. It adds one item for
|
||||
* each list defined on the workspace.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Data.CUSTOM_CONTEXT_MENU_GET_LIST_MIXIN = {
|
||||
/**
|
||||
* Add context menu option to change the selected list.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
var fieldName = 'LIST';
|
||||
if (this.isCollapsed()) {
|
||||
return;
|
||||
}
|
||||
var currentVarName = this.getField(fieldName).text_;
|
||||
if (!this.isInFlyout) {
|
||||
var variablesList = this.workspace.getVariablesOfType('list');
|
||||
variablesList.sort(function(a, b) {
|
||||
return Blockly.scratchBlocksUtils.compareStrings(a.name, b.name);
|
||||
});
|
||||
for (var i = 0; i < variablesList.length; i++) {
|
||||
var varName = variablesList[i].name;
|
||||
if (varName == currentVarName) continue;
|
||||
|
||||
var option = {enabled: true};
|
||||
option.text = varName;
|
||||
|
||||
option.callback =
|
||||
Blockly.Constants.Data.VARIABLE_OPTION_CALLBACK_FACTORY(this,
|
||||
variablesList[i].getId(), fieldName);
|
||||
options.push(option);
|
||||
}
|
||||
} else {
|
||||
var renameOption = {
|
||||
text: Blockly.Msg.RENAME_LIST,
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Data.RENAME_OPTION_CALLBACK_FACTORY(this,
|
||||
fieldName)
|
||||
};
|
||||
var deleteOption = {
|
||||
text: Blockly.Msg.DELETE_LIST.replace('%1', currentVarName),
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Data.DELETE_OPTION_CALLBACK_FACTORY(this,
|
||||
fieldName)
|
||||
};
|
||||
options.push(renameOption);
|
||||
options.push(deleteOption);
|
||||
}
|
||||
}
|
||||
};
|
||||
Blockly.Extensions.registerMixin('contextMenu_getListBlock',
|
||||
Blockly.Constants.Data.CUSTOM_CONTEXT_MENU_GET_LIST_MIXIN);
|
||||
|
||||
/**
|
||||
* Callback factory for dropdown menu options associated with a variable getter
|
||||
* block. Each variable on the workspace gets its own item in the dropdown
|
||||
* menu, and clicking on that item changes the text of the field on the source
|
||||
* block.
|
||||
* @param {!Blockly.Block} block The block to update.
|
||||
* @param {string} id The id of the variable to set on this block.
|
||||
* @param {string} fieldName The name of the field to update on the block.
|
||||
* @return {!function()} A function that updates the block with the new name.
|
||||
*/
|
||||
Blockly.Constants.Data.VARIABLE_OPTION_CALLBACK_FACTORY = function(block,
|
||||
id, fieldName) {
|
||||
return function() {
|
||||
var variableField = block.getField(fieldName);
|
||||
if (!variableField) {
|
||||
console.log("Tried to get a variable field on the wrong type of block.");
|
||||
}
|
||||
variableField.setValue(id);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for rename variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to rename.
|
||||
* @param {string} fieldName The name of the field to inspect on the block.
|
||||
* @return {!function()} A function that renames the variable.
|
||||
*/
|
||||
Blockly.Constants.Data.RENAME_OPTION_CALLBACK_FACTORY = function(block,
|
||||
fieldName) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField(fieldName).getVariable();
|
||||
Blockly.Variables.renameVariable(workspace, variable);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for delete variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to delete.
|
||||
* @param {string} fieldName The name of the field to inspect on the block.
|
||||
* @return {!function()} A function that deletes the variable.
|
||||
*/
|
||||
Blockly.Constants.Data.DELETE_OPTION_CALLBACK_FACTORY = function(block,
|
||||
fieldName) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField(fieldName).getVariable();
|
||||
workspace.deleteVariableById(variable.getId());
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user