208 lines
6.8 KiB
JavaScript
208 lines
6.8 KiB
JavaScript
goog.loadJs('common', () => {
|
|
|
|
goog.require('path');
|
|
goog.require('Blockly');
|
|
goog.require('Mixly.Env');
|
|
goog.require('Mixly.XML');
|
|
goog.require('Mixly.Msg');
|
|
goog.require('Mixly.HTMLTemplate');
|
|
goog.require('Mixly.Debug');
|
|
goog.provide('Mixly.ToolboxSearcher');
|
|
|
|
const {
|
|
Env,
|
|
XML,
|
|
Msg,
|
|
HTMLTemplate,
|
|
Debug
|
|
} = Mixly;
|
|
|
|
class ToolboxSearcher {
|
|
static {
|
|
this.searchHtmlTemplate = new HTMLTemplate(
|
|
goog.readFileSync(path.join(Env.templatePath, 'html/search-div.html'))
|
|
);
|
|
}
|
|
|
|
constructor(mainWorkspace) {
|
|
this.mainWorkspace = mainWorkspace;
|
|
this.searchWorkspace = new Blockly.Workspace(new Blockly.Options({
|
|
toolbox: null
|
|
}));
|
|
this.mainToolbox = this.mainWorkspace.getToolbox();
|
|
this.$search = $(ToolboxSearcher.searchHtmlTemplate.render({
|
|
search: Msg.Lang['toolboxSearcher.search']
|
|
}));
|
|
this.$i = this.$search.find('i');
|
|
this.$input = this.$search.find('input');
|
|
this.prevText = '';
|
|
$(this.mainToolbox.HtmlDiv).append(this.$search);
|
|
this.addEventsListener();
|
|
}
|
|
|
|
addEventsListener() {
|
|
this.$input.change(() => this.startSearch());
|
|
this.$input.bind('input propertychange', (event) => {
|
|
const searchCategory = this.mainToolbox.getToolboxItemById('catSearch');
|
|
const keyText = event.target.value;
|
|
if (!keyText.replaceAll(' ', '')) {
|
|
searchCategory.hide();
|
|
this.$i.addClass('disabled');
|
|
return;
|
|
} else {
|
|
searchCategory.show();
|
|
}
|
|
this.scrollTop();
|
|
if (keyText === this.prevText) {
|
|
this.$i.addClass('disabled');
|
|
} else {
|
|
this.$i.removeClass('disabled');
|
|
}
|
|
});
|
|
}
|
|
|
|
scrollTop() {
|
|
const { HtmlDiv } = this.mainToolbox;
|
|
$(HtmlDiv).scrollTop(HtmlDiv.scrollHeight);
|
|
}
|
|
|
|
checkBlock(blockxml, keys) {
|
|
this.searchWorkspace.clear();
|
|
try {
|
|
Blockly.Xml.domToBlock(blockxml, this.searchWorkspace);
|
|
} catch (error) {
|
|
Debug.error(error);
|
|
return false;
|
|
}
|
|
const blocks = this.searchWorkspace.getAllBlocks(true);
|
|
let select = false;
|
|
for (let block of blocks) {
|
|
const { inputList } = block;
|
|
for (let input of inputList) {
|
|
const { fieldRow } = input;
|
|
for (let field of fieldRow) {
|
|
const fieldText = field.getText().toLowerCase();
|
|
let times = 0;
|
|
for (let key = 0; key < keys.length; key++) {
|
|
if (fieldText.indexOf(keys[key]) === -1) {
|
|
continue;
|
|
}
|
|
times++;
|
|
}
|
|
if (keys.length === times) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
searchBlocks(keys) {
|
|
return new Promise((resolve, reject) => {
|
|
const searchCategory = this.mainToolbox.getToolboxItemById('catSearch');
|
|
let outputXML = [];
|
|
let selectedBlocksLen = 0;
|
|
const categories = this.mainToolbox.getToolboxItems();
|
|
for (let j = 0; categories[j]; j++) {
|
|
const category = categories[j];
|
|
if (category.id_ === 'catSearch') continue;
|
|
if (typeof category.getContents !== 'function') continue;
|
|
const blocksList = category.getContents();
|
|
let addLabel = true;
|
|
for (let blockDef of blocksList) {
|
|
const { type, kind, blockxml } = blockDef;
|
|
if (kind !== 'BLOCK') {
|
|
continue;
|
|
}
|
|
if (!this.checkBlock(blockxml, keys)) {
|
|
continue;
|
|
}
|
|
if (addLabel) {
|
|
const categoryPath = this.getCategoryPath(category);
|
|
outputXML.push({
|
|
kind: 'LABEL',
|
|
text: categoryPath
|
|
});
|
|
addLabel = false;
|
|
}
|
|
outputXML.push(blockDef);
|
|
selectedBlocksLen++;
|
|
if (selectedBlocksLen > 30) {
|
|
break;
|
|
}
|
|
}
|
|
if (selectedBlocksLen > 30) {
|
|
outputXML.unshift({
|
|
kind: 'LABEL',
|
|
text: Msg.Lang['toolboxSearcher.tooManyResultsInfo']
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
this.searchWorkspace.clear();
|
|
searchCategory.updateFlyoutContents(
|
|
outputXML.length ?
|
|
outputXML : [{
|
|
kind: 'LABEL',
|
|
text: Msg.Lang['toolboxSearcher.empty']
|
|
}]
|
|
);
|
|
this.mainToolbox.refreshSelection();
|
|
this.mainToolbox.setSelectedItem(searchCategory);
|
|
const { selectedItem_ } = this.mainToolbox;
|
|
if (selectedItem_ && selectedItem_.isCollapsible()) {
|
|
selectedItem_.setExpanded(true);
|
|
}
|
|
this.scrollTop();
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
getCategoryPath(category) {
|
|
let categoryPath = '';
|
|
for (; category; category = category.getParent()) {
|
|
categoryPath = category.toolboxItemDef_.name + (categoryPath && (' > ' + categoryPath));
|
|
}
|
|
return categoryPath;
|
|
}
|
|
|
|
startSearch() {
|
|
if (this.$i.hasClass('disabled')) {
|
|
return
|
|
};
|
|
let text = this.$input.val();
|
|
this.prevText = text;
|
|
try {
|
|
if (!text.replaceAll(' ', '')) {
|
|
return;
|
|
}
|
|
} catch(error) {
|
|
Debug.error(error);
|
|
}
|
|
this.$input.attr('disabled', true);
|
|
this.$i.removeClass('codicon-search-fuzzy');
|
|
this.$i.addClass('codicon-loading layui-anim-rotate layui-anim-loop');
|
|
setTimeout(() => {
|
|
let keys = text.toLowerCase().split(' ');
|
|
this.searchBlocks(keys)
|
|
.catch(Debug.error)
|
|
.finally(() => {
|
|
this.$i.removeClass('codicon-loading layui-anim-rotate layui-anim-loop');
|
|
this.$i.addClass('codicon-search-fuzzy disabled');
|
|
this.$input.removeAttr('disabled');
|
|
});
|
|
}, 100);
|
|
}
|
|
|
|
restart() {
|
|
this.prevText = '';
|
|
const searchCategory = this.mainToolbox.getToolboxItemById('catSearch');
|
|
this.$input.val('');
|
|
searchCategory.hide();
|
|
}
|
|
}
|
|
|
|
Mixly.ToolboxSearcher = ToolboxSearcher;
|
|
|
|
}); |