-
-
Save towerofnix/2cee388117d378a81c3d4482b7c8e304 to your computer and use it in GitHub Desktop.
Scratch 3.0 "Text Tools" source code dump
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ArgumentType = require('../../extension-support/argument-type'); | |
const BlockType = require('../../extension-support/block-type'); | |
const Clone = require('../../util/clone'); | |
const Cast = require('../../util/cast'); | |
const formatMessage = require('format-message'); | |
const MathUtil = require('../../util/math-util'); | |
const Timer = require('../../util/timer'); | |
/** | |
* Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. | |
* @type {string} | |
*/ | |
// eslint-disable-next-line max-len | |
const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTc5MiIgd2lkdGg9IjE3OTIiPjxwYXRoIGQ9Ik0xMjE2IDEyOHEtMzIwIDAtMzIwIDIyNHY0MTZoMTI4djEyOEg4OTZ2NTQ0cTAgMjI0IDMyMCAyMjRoNjR2MTI4aC02NHEtMjcyIDAtMzg0LTE0Ni0xMTIgMTQ2LTM4NCAxNDZoLTY0di0xMjhoNjRxMzIwIDAgMzIwLTIyNFY4OTZINjQwVjc2OGgxMjhWMzUycTAtMjI0LTMyMC0yMjRoLTY0VjBoNjRxMjcyIDAgMzg0IDE0NlE5NDQgMCAxMjE2IDBoNjR2MTI4aC02NHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4='; | |
// https://www.iconfinder.com/icons/1608366/cursor_i_icon | |
/** | |
* Icon svg to be displayed in the category menu, encoded as a data URI. | |
* @type {string} | |
*/ | |
// eslint-disable-next-line max-len | |
const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE2LjA5IDEyLjkzN2MuMjI4IDEuMTQxLS44MzMgMi4wNjMtMi4zNzMgMi4wNjMtMS41MzUgMC0yLjk2Mi0uOTIyLTMuMTg2LTIuMDYzLS4yMy0xLjE0Mi44MzMtMi4wNjggMi4zNzItMi4wNjguMzIzIDAgLjY0MS4wNDIuOTQ1LjExN2EzLjUgMy41IDAgMCAxIC40NjguMTUxYy40MzUtLjAxLS4wNTItMS4xNDctLjkxNy02LjExNC0xLjA2Ny02LjE1MiAxLjUzLS45MzUgNC4zODQtMS4zNzcgMi44NTQtLjQ0Mi4wMzggMi40MS0xLjgyNSAxLjkyMi0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc3LjEzMiA3LjM3ek03LjQ2IDguNTYzYy0xLjg2Mi0uNDkzLTIuMzI1LTMuNTc2LjEzIDcuMzdDNy44MTYgMTcuMDczIDYuNzU0IDE4IDUuMjIgMThjLTEuNTM1IDAtMi45NjEtLjkyNi0zLjE5LTIuMDY4LS4yMjQtMS4xNDIuODM3LTIuMDY3IDIuMzc1LTIuMDY3LjUwMSAwIC45ODcuMDk4IDEuNDI3LjI3Mi40MTItLjAyOC0uMDc0LTEuMTg5LS45My02LjExNEMzLjgzNCAxLjg3IDYuNDMgNy4wODcgOS4yODIgNi42NDZjMi44NTQtLjQ0Ny4wMzggMi40MS0xLjgyMyAxLjkxN3oiIGZpbGw9IiM1NzVFNzUiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg=='; | |
/** | |
* Class for the "Text Tools" extension's blocks in Scratch 3.0 | |
* @param {Runtime} runtime - the runtime instantiating this block package. | |
* @constructor | |
*/ | |
class Scratch3TextToolsBlocks { | |
constructor (runtime) { | |
/** | |
* The runtime instantiating this block package. | |
* @type {Runtime} | |
*/ | |
this.runtime = runtime; | |
} | |
/** | |
* @returns {object} metadata for this extension and its blocks. | |
*/ | |
getInfo () { | |
return { | |
id: 'textTools', | |
name: formatMessage({ | |
id: 'textTools.categoryName', | |
default: 'Text Tools', | |
description: 'Label for the Text Tools extension category' | |
}), | |
menuIconURI: menuIconURI, | |
blockIconURI: blockIconURI, | |
blocks: [ | |
{ | |
opcode: 'replaceSubstring', | |
blockType: BlockType.REPORTER, | |
text: formatMessage({ | |
id: 'textTools.replaceSubstring', | |
default: 'replace [WHICH] [BEFORE] with [AFTER] in [STRING]', | |
description: 'replace text in a string' | |
}), | |
arguments: { | |
WHICH: { | |
type: ArgumentType.STRING, | |
menu: 'REPLACE_WHICH', | |
defaultValue: 'every' | |
}, | |
BEFORE: { | |
type: ArgumentType.STRING, | |
defaultValue: 'world' | |
}, | |
AFTER: { | |
type: ArgumentType.STRING, | |
defaultValue: 'friend' | |
}, | |
STRING: { | |
type: ArgumentType.STRING, | |
defaultValue: 'hello world' | |
} | |
} | |
}, | |
{ | |
opcode: 'getSubstring', | |
blockType: BlockType.REPORTER, | |
text: formatMessage({ | |
id: 'textTools.getSubstring', | |
default: 'letters [START] to [END] of [STRING]', | |
description: 'get letters from a range of a string' | |
}), | |
arguments: { | |
START: { | |
type: ArgumentType.NUMBER, | |
defaultValue: 1 | |
}, | |
END: { | |
type: ArgumentType.NUMBER, | |
defaultValue: 5 | |
}, | |
STRING: { | |
type: ArgumentType.STRING, | |
defaultValue: 'octopus' | |
} | |
} | |
}, | |
{ | |
opcode: 'locationOfSubstring', | |
blockType: BlockType.REPORTER, | |
text: formatMessage({ | |
id: 'textTools.locationOfSubstring', | |
default: 'location of [SUBSTRING] in [STRING]', | |
description: 'get location (index) of one string in another' | |
}), | |
arguments: { | |
SUBSTRING: { | |
type: ArgumentType.STRING, | |
defaultValue: 'eat' | |
}, | |
STRING: { | |
type: ArgumentType.STRING, | |
defaultValue: 'wheat' | |
} | |
} | |
}, | |
{ | |
opcode: 'caseSensitiveEqual', | |
blockType: BlockType.BOOLEAN, | |
text: formatMessage({ | |
id: 'textTools.caseSensitiveEqual', | |
default: '[A] = [B] and is the same case', | |
description: 'check if two strings are equal and capitalized the same way' | |
}), | |
arguments: { | |
A: { | |
type: ArgumentType.STRING, | |
defaultValue: 'library' | |
}, | |
B: { | |
type: ArgumentType.STRING, | |
defaultValue: 'liBRARY' | |
} | |
} | |
} | |
], | |
menus: { | |
REPLACE_WHICH: [ | |
{text: 'every', value: 'every'}, | |
{text: 'first', value: 'first'}, | |
{text: 'last', value: 'last'} | |
] | |
} | |
}; | |
} | |
replaceSubstring(args) { | |
const which = Cast.toString(args.WHICH); | |
const before = Cast.toString(args.BEFORE); | |
const after = Cast.toString(args.AFTER); | |
const string = Cast.toString(args.STRING); | |
const split = string.split(before); | |
if (split.length === 1) { | |
// The "before" string doesn't show up at all, so don't do anything. | |
return string; | |
} else if (which === 'every') { | |
return split.join(after); | |
} else if (which === 'first') { | |
return split[0] + after + split.slice(1).join(before); | |
} else if (which === 'last') { | |
return split.slice(0, -1).join(before) + after + split[split.length - 1]; | |
} else { | |
// We got passed an invalid menu option, so don't do anything to the string. | |
return string; | |
} | |
} | |
getSubstring(args) { | |
let start = Cast.toNumber(args.START); | |
let end = Cast.toNumber(args.END); | |
const string = Cast.toString(args.STRING); | |
// Slice expects 0-indexed, but Scratch is 1-indexed. So first we subtract 1 from start and end: | |
// * start = start - 1 | |
// * end = end - 1 | |
// Also, we want to return the range INCLUSIVE of both the start and the end (octopus [0 .. 5] = octop), but | |
// slice is only inclusive of the start. So we add one to the end: | |
// * start = start - 1 | |
// * end = end | |
// So we don't change end. | |
// Only decrement start if it is positive. Negative start already behaves like we want it to. | |
// ("start = -N" means 'starting from the Nth character from the end", where -1 = last character.) | |
if (start > 0) { | |
start = start - 1; | |
} | |
// If end is negative, we have to increment it so that slice is inclusive of the character at the end index. | |
// In this block, "end = -1" means "until and including the last character", but once we increment -1, we have | |
// 0, and "slice(N, 0)" means "until but not including the last character", so in that case we have to change | |
// end to be the (positive) length of the string. | |
if (end < 0) { | |
end = end + 1; | |
if (end === 0) { | |
end = string.length; | |
} | |
} | |
return string.slice(start, end); | |
} | |
locationOfSubstring(args) { | |
const substring = Cast.toString(args.SUBSTRING); | |
const string = Cast.toString(args.STRING); | |
return string.indexOf(substring) + 1; | |
} | |
caseSensitiveEqual(args) { | |
const a = Cast.toString(args.A); | |
const b = Cast.toString(args.B); | |
return a === b; | |
} | |
} | |
module.exports = Scratch3TextToolsBlocks; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment