mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-08-22 22:28:58 +00:00
Converted text entry to a bigger area, allowing multi-line entry. Added rudimentary spell checking (it's not perfect at the momenent)
This commit is contained in:
parent
a4e87954a3
commit
8a88a147f2
@ -17,6 +17,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -41,6 +42,9 @@ import org.badvision.outlaweditor.data.xml.Scope;
|
|||||||
import org.badvision.outlaweditor.data.xml.Script;
|
import org.badvision.outlaweditor.data.xml.Script;
|
||||||
import org.badvision.outlaweditor.data.xml.UserType;
|
import org.badvision.outlaweditor.data.xml.UserType;
|
||||||
import org.badvision.outlaweditor.data.xml.Variable;
|
import org.badvision.outlaweditor.data.xml.Variable;
|
||||||
|
import org.badvision.outlaweditor.spelling.SpellChecker;
|
||||||
|
import org.badvision.outlaweditor.spelling.SpellResponse;
|
||||||
|
import org.badvision.outlaweditor.spelling.Suggestion;
|
||||||
import org.badvision.outlaweditor.ui.ApplicationUIController;
|
import org.badvision.outlaweditor.ui.ApplicationUIController;
|
||||||
import org.badvision.outlaweditor.ui.MythosScriptEditorController;
|
import org.badvision.outlaweditor.ui.MythosScriptEditorController;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -58,10 +62,12 @@ public class MythosEditor {
|
|||||||
Stage primaryStage;
|
Stage primaryStage;
|
||||||
MythosScriptEditorController controller;
|
MythosScriptEditorController controller;
|
||||||
public static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
public static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||||
|
SpellChecker spellChecker;
|
||||||
|
|
||||||
public MythosEditor(Script theScript, Scope theScope) {
|
public MythosEditor(Script theScript, Scope theScope) {
|
||||||
script = theScript;
|
script = theScript;
|
||||||
scope = theScope;
|
scope = theScope;
|
||||||
|
spellChecker = new SpellChecker();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show() {
|
public void show() {
|
||||||
@ -146,7 +152,6 @@ public class MythosEditor {
|
|||||||
// Called when the name of the root block is changed in the JS editor
|
// Called when the name of the root block is changed in the JS editor
|
||||||
public void setFunctionName(String name) {
|
public void setFunctionName(String name) {
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
System.out.println("How can the script be null?? wanted to set script name to " + name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
script.setName(name);
|
script.setName(name);
|
||||||
@ -165,9 +170,11 @@ public class MythosEditor {
|
|||||||
public List<Script> getGlobalFunctions() {
|
public List<Script> getGlobalFunctions() {
|
||||||
return getFunctions(getGlobalScope());
|
return getFunctions(getGlobalScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Script> getLocalFunctions() {
|
public List<Script> getLocalFunctions() {
|
||||||
return getFunctions(scope);
|
return getFunctions(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Script> getFunctions(Scope scriptScope) {
|
private List<Script> getFunctions(Scope scriptScope) {
|
||||||
if (scriptScope.getScripts() == null) {
|
if (scriptScope.getScripts() == null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
@ -191,17 +198,17 @@ public class MythosEditor {
|
|||||||
private boolean isGlobalScope() {
|
private boolean isGlobalScope() {
|
||||||
return scope.equals(getGlobalScope());
|
return scope.equals(getGlobalScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Variable> getLocalVariables() {
|
public List<Variable> getLocalVariables() {
|
||||||
return getVariables(scope);
|
return getVariables(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Variable> getVariables(Scope scriptScope) {
|
private List<Variable> getVariables(Scope scriptScope) {
|
||||||
if (scriptScope.getVariables() == null) {
|
if (scriptScope.getVariables() == null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
} else {
|
} else {
|
||||||
return scriptScope.getVariables().getVariable();
|
return scriptScope.getVariables().getVariable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Variable> getVariablesByType(String type) {
|
public List<Variable> getVariablesByType(String type) {
|
||||||
@ -219,18 +226,36 @@ public class MythosEditor {
|
|||||||
public List<String> getParametersForScript(Script script) {
|
public List<String> getParametersForScript(Script script) {
|
||||||
List<String> allArgs = new ArrayList();
|
List<String> allArgs = new ArrayList();
|
||||||
if (script.getBlock() != null && script.getBlock().getFieldOrMutationOrStatement() != null) {
|
if (script.getBlock() != null && script.getBlock().getFieldOrMutationOrStatement() != null) {
|
||||||
script.getBlock().getFieldOrMutationOrStatement()
|
script.getBlock().getFieldOrMutationOrStatement()
|
||||||
.stream().filter((o) -> (o instanceof Mutation))
|
.stream().filter((o) -> (o instanceof Mutation))
|
||||||
.map((o) -> (Mutation) o).findFirst().ifPresent((m) -> {
|
.map((o) -> (Mutation) o).findFirst().ifPresent((m) -> {
|
||||||
m.getArg().stream().forEach((a) -> {
|
m.getArg().stream().forEach((a) -> {
|
||||||
allArgs.add(a.getName());
|
allArgs.add(a.getName());
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return allArgs;
|
return allArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String checkSpelling(String value) {
|
||||||
|
SpellResponse result = spellChecker.check(value);
|
||||||
|
if (result.getErrors() == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
StringBuilder message = new StringBuilder();
|
||||||
|
result.getCorrections().forEach((SpellResponse.Source source, Set<Suggestion> suggestions) -> {
|
||||||
|
message
|
||||||
|
.append(source.word)
|
||||||
|
.append(" : ")
|
||||||
|
.append(suggestions.stream().map(Suggestion::getWord).collect(Collectors.joining(", ")))
|
||||||
|
.append("\n");
|
||||||
|
});
|
||||||
|
return message.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void log(String message) {
|
public void log(String message) {
|
||||||
|
Logger.getLogger(getClass().getName()).warning(message);
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
package org.badvision.outlaweditor.data;
|
package org.badvision.outlaweditor.data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.badvision.outlaweditor.Application;
|
import org.badvision.outlaweditor.Application;
|
||||||
import org.badvision.outlaweditor.data.xml.Field;
|
import org.badvision.outlaweditor.data.xml.Field;
|
||||||
@ -20,6 +24,8 @@ import org.badvision.outlaweditor.data.xml.Scope;
|
|||||||
import org.badvision.outlaweditor.data.xml.Script;
|
import org.badvision.outlaweditor.data.xml.Script;
|
||||||
|
|
||||||
public class DataUtilities {
|
public class DataUtilities {
|
||||||
|
private DataUtilities() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void ensureGlobalExists() {
|
public static void ensureGlobalExists() {
|
||||||
if (Application.gameData.getGlobal() == null) {
|
if (Application.gameData.getGlobal() == null) {
|
||||||
@ -98,4 +104,130 @@ public class DataUtilities {
|
|||||||
cleanupScriptNames(Application.gameData.getGlobal());
|
cleanupScriptNames(Application.gameData.getGlobal());
|
||||||
Application.gameData.getMap().forEach(DataUtilities::cleanupScriptNames);
|
Application.gameData.getMap().forEach(DataUtilities::cleanupScriptNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------ String comparators
|
||||||
|
/**
|
||||||
|
* Rank two strings similarity in terms of distance The lower the number,
|
||||||
|
* the more similar these strings are to each other See:
|
||||||
|
* http://en.wikipedia.org/wiki/Levenshtein_distance#Computing_Levenshtein_distance
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* @param t
|
||||||
|
* @return Distance (higher is better)
|
||||||
|
*/
|
||||||
|
public static int levenshteinDistance(String s, String t) {
|
||||||
|
if (s == null || t == null || s.length() == 0 || t.length() == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s.toLowerCase().replaceAll("[^a-zA-Z0-9\\s]", "");
|
||||||
|
t = t.toLowerCase().replaceAll("[^a-zA-Z0-9\\s]", "");
|
||||||
|
int m = s.length();
|
||||||
|
int n = t.length();
|
||||||
|
int[][] dist = new int[m + 1][n + 1];
|
||||||
|
for (int i = 1; i <= m; i++) {
|
||||||
|
dist[i][0] = i;
|
||||||
|
}
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
dist[0][i] = i;
|
||||||
|
}
|
||||||
|
for (int j = 1; j <= n; j++) {
|
||||||
|
for (int i = 1; i <= m; i++) {
|
||||||
|
if (s.charAt(i - 1) == t.charAt(j - 1)) {
|
||||||
|
dist[i][j] = dist[i - 1][j - 1];
|
||||||
|
} else {
|
||||||
|
int del = dist[i - 1][j] + 1;
|
||||||
|
int insert = dist[i][j - 1] + 1;
|
||||||
|
int sub = dist[i - 1][j - 1] + 1;
|
||||||
|
dist[i][j] = Math.min(Math.min(del, insert), sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(m, n) - dist[m][n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare strings based on a tally of similar patterns found, using a fixed
|
||||||
|
* search window The resulting score is heavily penalized if the strings
|
||||||
|
* differ greatly in length This is not as efficient as levenshtein, so it's
|
||||||
|
* only used as a tie-breaker.
|
||||||
|
*
|
||||||
|
* @param c1
|
||||||
|
* @param c2
|
||||||
|
* @param width Search window size
|
||||||
|
* @return Overall similarity score (higher is beter)
|
||||||
|
*/
|
||||||
|
public static double rankMatch(String c1, String c2, int width) {
|
||||||
|
double score = 0;
|
||||||
|
String s1 = c1.toLowerCase();
|
||||||
|
String s2 = c2.toLowerCase();
|
||||||
|
for (int i = 0; i < s1.length() + 1 - width; i++) {
|
||||||
|
String m = s1.substring(i, i + width);
|
||||||
|
int j = 0;
|
||||||
|
while ((j = s2.indexOf(m, j)) > -1) {
|
||||||
|
score += width;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double l1 = s1.length();
|
||||||
|
double l2 = s2.length();
|
||||||
|
// If the two strings are equivilent in length, the score is higher
|
||||||
|
// If the two strings are different in length, the score is adjusted lower depending on how large the difference is
|
||||||
|
// This is offset just a hair for tuning purposes
|
||||||
|
double adjustment = (Math.min(l1, l2) / Math.max(l1, l2)) + 0.1;
|
||||||
|
return score * adjustment * adjustment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RankingComparator implements Comparator<String> {
|
||||||
|
|
||||||
|
String match;
|
||||||
|
|
||||||
|
public RankingComparator(String match) {
|
||||||
|
// Adding a space helps respect word boundaries as part of the match
|
||||||
|
// In the case of very close matches this is another tie-breaker
|
||||||
|
// Especially for very small search terms
|
||||||
|
this.match = match + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(String o1, String o2) {
|
||||||
|
double s1 = levenshteinDistance(match, o1);
|
||||||
|
double s2 = levenshteinDistance(match, o2);
|
||||||
|
if (s2 == s1) {
|
||||||
|
s1 = rankMatch(o1, match, 3) + rankMatch(o1, match, 2);
|
||||||
|
s2 = rankMatch(o2, match, 3) + rankMatch(o2, match, 2);
|
||||||
|
if (s2 == s1) {
|
||||||
|
return (o1.compareTo(o2));
|
||||||
|
} else {
|
||||||
|
// Normalize result to -1, 0 or 1 so there is no rounding issues!
|
||||||
|
return (int) Math.signum(s2 - s1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (int) (s2 - s1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a desired search string and a search space of recognized
|
||||||
|
* selections, identify the best match in the list
|
||||||
|
*
|
||||||
|
* @param match String to search for
|
||||||
|
* @param search Space of all valid results
|
||||||
|
* @return Best match found, or null if there was nothing close to a match
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
public static String findBestMatch(String match, Collection<String> search) {
|
||||||
|
if (search == null || search.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
RankingComparator r = new RankingComparator(match);
|
||||||
|
List<String> candidates = new ArrayList<>(search);
|
||||||
|
Collections.sort(candidates, r);
|
||||||
|
double score = levenshteinDistance(match, candidates.get(0));
|
||||||
|
if (score > 1) {
|
||||||
|
return candidates.get(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
||||||
|
* (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-1.1>.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package org.badvision.outlaweditor.spelling;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.badvision.outlaweditor.data.DataUtilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author blurry
|
||||||
|
*/
|
||||||
|
public class SpellChecker {
|
||||||
|
private static HashMap<Character, Set<String>> dictionary;
|
||||||
|
private final double SIMILARITY_THRESHOLD = 0.5;
|
||||||
|
|
||||||
|
public SpellChecker() {
|
||||||
|
loadDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellResponse check(String value) {
|
||||||
|
SpellResponse response = new SpellResponse();
|
||||||
|
String[] words = value.split("[^A-Za-z]");
|
||||||
|
int pos = 0;
|
||||||
|
for (String word : words) {
|
||||||
|
Set<Suggestion> suggestions = getSuggestions(word);
|
||||||
|
if (suggestions != null && !suggestions.isEmpty()) {
|
||||||
|
Suggestion first = suggestions.stream().findFirst().get();
|
||||||
|
if (first.similarity == 1.0) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
SpellResponse.Source source = new SpellResponse.Source();
|
||||||
|
source.start = pos;
|
||||||
|
source.word = word;
|
||||||
|
response.corrections.put(source, suggestions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += word.length() + 1;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadDictionary() {
|
||||||
|
if (dictionary == null) {
|
||||||
|
URL dictionaryPath = SpellChecker.class.getResource("/mythos/dictionary.txt");
|
||||||
|
try {
|
||||||
|
BufferedReader content = new BufferedReader(new InputStreamReader((InputStream) dictionaryPath.getContent()));
|
||||||
|
dictionary = new HashMap<>();
|
||||||
|
content.lines().forEach((String word)-> {
|
||||||
|
String lower = word.toLowerCase();
|
||||||
|
Set<String> words = dictionary.get(lower.charAt(0));
|
||||||
|
if (words == null) {
|
||||||
|
words = new LinkedHashSet<>();
|
||||||
|
dictionary.put(lower.charAt(0), words);
|
||||||
|
}
|
||||||
|
words.add(word);
|
||||||
|
});
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(SpellChecker.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Suggestion> getSuggestions(String word) {
|
||||||
|
TreeSet<Suggestion> suggestions = new TreeSet<>();
|
||||||
|
if (word == null || word.isEmpty()) {
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
String lower = word.toLowerCase();
|
||||||
|
Character first = lower.charAt(0);
|
||||||
|
Set<String> words = dictionary.get(first);
|
||||||
|
if (words != null) {
|
||||||
|
if (words.contains(lower)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
words.parallelStream().forEach((String dictWord) -> {
|
||||||
|
int distance = DataUtilities.levenshteinDistance(lower, dictWord);
|
||||||
|
double similarity = distance / ((double) Math.max(lower.length(), dictWord.length()));
|
||||||
|
if (similarity >= SIMILARITY_THRESHOLD) {
|
||||||
|
Suggestion suggestion = new Suggestion();
|
||||||
|
suggestion.similarity = similarity;
|
||||||
|
suggestion.word = dictWord;
|
||||||
|
suggestions.add(suggestion);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
||||||
|
* (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-1.1>.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package org.badvision.outlaweditor.spelling;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class SpellResponse {
|
||||||
|
public static class Source {
|
||||||
|
public int start;
|
||||||
|
public String word;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Source, Set<Suggestion>> corrections = new LinkedHashMap<>();
|
||||||
|
public int getErrors() {
|
||||||
|
return corrections.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Source, Set<Suggestion>> getCorrections() {
|
||||||
|
return corrections;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
||||||
|
* (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-1.1>.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package org.badvision.outlaweditor.spelling;
|
||||||
|
|
||||||
|
public class Suggestion implements Comparable<Suggestion> {
|
||||||
|
public String word;
|
||||||
|
public double similarity;
|
||||||
|
public String getWord() {
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
public double getSimilarity() {
|
||||||
|
return similarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Suggestion o) {
|
||||||
|
return (int) Math.signum(o.similarity - similarity);
|
||||||
|
}
|
||||||
|
}
|
274927
OutlawEditor/src/main/resources/mythos/dictionary.txt
Normal file
274927
OutlawEditor/src/main/resources/mythos/dictionary.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,10 +8,10 @@
|
|||||||
* governing permissions and limitations under the License.
|
* governing permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global Blockly */
|
/* global Blockly, goog */
|
||||||
|
|
||||||
if (typeof Mythos === "undefined") {
|
if (typeof Mythos === "undefined") {
|
||||||
// Hook up the rename function to notify the java editor when changes occur
|
// Hook up the rename function to notify the java editor when changes occur
|
||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
window = {};
|
window = {};
|
||||||
}
|
}
|
||||||
@ -20,7 +20,6 @@ if (typeof Mythos === "undefined") {
|
|||||||
Mythos.editor.setFunctionName(name);
|
Mythos.editor.setFunctionName(name);
|
||||||
return Blockly.Procedures.rename_old.call(this, name);
|
return Blockly.Procedures.rename_old.call(this, name);
|
||||||
};
|
};
|
||||||
|
|
||||||
Mythos = {
|
Mythos = {
|
||||||
setScriptXml: function (xml) {
|
setScriptXml: function (xml) {
|
||||||
Blockly.mainWorkspace.clear();
|
Blockly.mainWorkspace.clear();
|
||||||
@ -89,8 +88,7 @@ if (typeof Mythos === "undefined") {
|
|||||||
typeConstructor.appendValueInput(attribute.getName())
|
typeConstructor.appendValueInput(attribute.getName())
|
||||||
.setAlign(Blockly.ALIGN_RIGHT)
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
.setCheck(attribute.getType())
|
.setCheck(attribute.getType())
|
||||||
.appendField(attribute.getName())
|
.appendField(attribute.getName());
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Mythos.editor.log(error);
|
Mythos.editor.log(error);
|
||||||
@ -484,6 +482,63 @@ if (typeof Mythos === "undefined") {
|
|||||||
this.setTooltip('Scrolls text window up one line');
|
this.setTooltip('Scrolls text window up one line');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Blockly.Blocks['text_area'] = {
|
||||||
|
init: function () {
|
||||||
|
var field = new Blockly.FieldTextArea('', this.checkSpelling);
|
||||||
|
field.block_ = this;
|
||||||
|
this.setHelpUrl(Blockly.Msg.TEXT_TEXT_HELPURL);
|
||||||
|
this.setColour(Blockly.Blocks.texts.HUE);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField("Big")
|
||||||
|
.appendField(this.newQuote_(true))
|
||||||
|
.appendField(field, 'TEXT')
|
||||||
|
.appendField(this.newQuote_(false));
|
||||||
|
this.setOutput(true, 'String');
|
||||||
|
this.setTooltip(Blockly.Msg.TEXT_TEXT_TOOLTIP);
|
||||||
|
// this.setMutator(new Blockly.Mutator(['text']));
|
||||||
|
},
|
||||||
|
newQuote_: function (open) {
|
||||||
|
var file;
|
||||||
|
if (open === this.RTL) {
|
||||||
|
file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==';
|
||||||
|
} else {
|
||||||
|
file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC';
|
||||||
|
}
|
||||||
|
return new Blockly.FieldImage(file, 12, 12, '"');
|
||||||
|
},
|
||||||
|
checkSpelling: function(value) {
|
||||||
|
this.block_.setCommentText(Mythos.editor.checkSpelling(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Blockly.Blocks['text'] = {
|
||||||
|
init: function () {
|
||||||
|
var field = new Blockly.FieldTextInput('', this.checkSpelling);
|
||||||
|
field.block_ = this;
|
||||||
|
this.setHelpUrl(Blockly.Msg.TEXT_TEXT_HELPURL);
|
||||||
|
this.setColour(Blockly.Blocks.texts.HUE);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField(this.newQuote_(true))
|
||||||
|
.appendField(field, 'TEXT')
|
||||||
|
.appendField(this.newQuote_(false));
|
||||||
|
this.setOutput(true, 'String');
|
||||||
|
this.setTooltip(Blockly.Msg.TEXT_TEXT_TOOLTIP);
|
||||||
|
// this.setMutator(new Blockly.Mutator(['text_area']));
|
||||||
|
},
|
||||||
|
newQuote_: function (open) {
|
||||||
|
var file;
|
||||||
|
if (open === this.RTL) {
|
||||||
|
file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==';
|
||||||
|
} else {
|
||||||
|
file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC';
|
||||||
|
}
|
||||||
|
return new Blockly.FieldImage(file, 12, 12, '"');
|
||||||
|
},
|
||||||
|
checkSpelling: function(value) {
|
||||||
|
this.block_.setCommentText(Mythos.editor.checkSpelling(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
Blockly.Blocks['text_getstring'] = {
|
Blockly.Blocks['text_getstring'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
this.setHelpUrl(Mythos.helpUrl);
|
this.setHelpUrl(Mythos.helpUrl);
|
||||||
@ -553,3 +608,138 @@ if (typeof Mythos === "undefined") {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
//------
|
||||||
|
goog.provide('Blockly.FieldTextArea');
|
||||||
|
goog.require('Blockly.Field');
|
||||||
|
goog.require('Blockly.Msg');
|
||||||
|
goog.require('goog.asserts');
|
||||||
|
goog.require('goog.userAgent');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for an editable text field.
|
||||||
|
* @param {string} text The initial content of the field.
|
||||||
|
* @param {Function} opt_changeHandler An optional function that is called
|
||||||
|
* to validate any constraints on what the user entered. Takes the new
|
||||||
|
* text as an argument and returns either the accepted text, a replacement
|
||||||
|
* text, or null to abort the change.FFF
|
||||||
|
* @extends {Blockly.Field}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
Blockly.FieldTextArea = function (text, opt_changeHandler) {
|
||||||
|
Blockly.FieldTextInput.superClass_.constructor.call(this, text);
|
||||||
|
this.changeHandler_ = opt_changeHandler;
|
||||||
|
};
|
||||||
|
goog.inherits(Blockly.FieldTextArea, Blockly.FieldTextInput);
|
||||||
|
/**
|
||||||
|
* Clone this FieldTextArea.
|
||||||
|
* @return {!Blockly.FieldTextArea} The result of calling the constructor again
|
||||||
|
* with the current values of the arguments used during construction.
|
||||||
|
*/
|
||||||
|
Blockly.FieldTextArea.prototype.clone = function () {
|
||||||
|
return new Blockly.FieldTextArea(this.getText(), this.changeHandler_);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Show the inline free-text editor on top of the text.
|
||||||
|
* @param {boolean=} opt_quietInput True if editor should be created without
|
||||||
|
* focus. Defaults to false.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Blockly.FieldTextInput.prototype.showEditor_ = function (opt_quietInput) {
|
||||||
|
var quietInput = opt_quietInput || false;
|
||||||
|
if (!quietInput && (goog.userAgent.MOBILE || goog.userAgent.ANDROID ||
|
||||||
|
goog.userAgent.IPAD)) {
|
||||||
|
// Mobile browsers have issues with in-line textareas (focus & keyboards).
|
||||||
|
var newValue = window.prompt(Blockly.Msg.CHANGE_VALUE_TITLE, this.text_);
|
||||||
|
if (this.sourceBlock_ && this.changeHandler_) {
|
||||||
|
var override = this.changeHandler_(newValue);
|
||||||
|
if (override !== undefined) {
|
||||||
|
newValue = override;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newValue !== null) {
|
||||||
|
this.setText(newValue);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_());
|
||||||
|
var div = Blockly.WidgetDiv.DIV;
|
||||||
|
// Create the input.
|
||||||
|
var htmlInput = goog.dom.createDom('textarea', 'blocklyHtmlInput');
|
||||||
|
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||||
|
htmlInput.setAttribute('cols', 80);
|
||||||
|
htmlInput.setAttribute('rows', 7);
|
||||||
|
var fontSize = (Blockly.FieldTextInput.FONTSIZE *
|
||||||
|
this.sourceBlock_.workspace.scale) + 'pt';
|
||||||
|
div.style.fontSize = fontSize;
|
||||||
|
div.style.width = "30em";
|
||||||
|
htmlInput.style.width = "30em";
|
||||||
|
htmlInput.style.fontSize = fontSize;
|
||||||
|
htmlInput.style.backgroundColor = "#eee";
|
||||||
|
/** @type {!HTMLTextArea} */
|
||||||
|
Blockly.FieldTextInput.htmlInput_ = htmlInput;
|
||||||
|
div.appendChild(htmlInput);
|
||||||
|
|
||||||
|
htmlInput.value = htmlInput.defaultValue = this.text_;
|
||||||
|
htmlInput.oldValue_ = null;
|
||||||
|
this.validate_();
|
||||||
|
this.resizeEditor_();
|
||||||
|
if (!quietInput) {
|
||||||
|
htmlInput.focus();
|
||||||
|
htmlInput.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind to keydown -- trap Enter without IME and Esc to hide.
|
||||||
|
htmlInput.onKeyDownWrapper_ =
|
||||||
|
Blockly.bindEvent_(htmlInput, 'keydown', this, this.onHtmlInputKeyDown_);
|
||||||
|
// Bind to keyup -- trap Enter; resize after every keystroke.
|
||||||
|
htmlInput.onKeyUpWrapper_ =
|
||||||
|
Blockly.bindEvent_(htmlInput, 'keyup', this, this.onHtmlInputChange_);
|
||||||
|
// Bind to keyPress -- repeatedly resize when holding down a key.
|
||||||
|
htmlInput.onKeyPressWrapper_ =
|
||||||
|
Blockly.bindEvent_(htmlInput, 'keypress', this, this.onHtmlInputChange_);
|
||||||
|
var workspaceSvg = this.sourceBlock_.workspace.getCanvas();
|
||||||
|
htmlInput.onWorkspaceChangeWrapper_ =
|
||||||
|
Blockly.bindEvent_(workspaceSvg, 'blocklyWorkspaceChange', this,
|
||||||
|
this.resizeEditor_);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle key down to the editor.
|
||||||
|
* @param {!Event} e Keyboard event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function (e) {
|
||||||
|
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||||
|
var escKey = 27;
|
||||||
|
if (e.keyCode === escKey) {
|
||||||
|
this.setText(htmlInput.defaultValue);
|
||||||
|
Blockly.WidgetDiv.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Handle a change to the editor.
|
||||||
|
* @param {!Event} e Keyboard event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Blockly.FieldTextArea.prototype.onHtmlInputChange_ = function (e) {
|
||||||
|
var htmlInput = Blockly.FieldTextArea.htmlInput_;
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
// Esc
|
||||||
|
this.setText(htmlInput.defaultValue);
|
||||||
|
Blockly.WidgetDiv.hide();
|
||||||
|
} else {
|
||||||
|
// Update source block.
|
||||||
|
var text = htmlInput.value;
|
||||||
|
if (text !== htmlInput.oldValue_) {
|
||||||
|
htmlInput.oldValue_ = text;
|
||||||
|
this.setText(text);
|
||||||
|
this.validate_();
|
||||||
|
} else if (goog.userAgent.WEBKIT) {
|
||||||
|
// Cursor key. Render the source block to show the caret moving.
|
||||||
|
// Chrome only (version 26, OS X).
|
||||||
|
this.sourceBlock_.render();
|
||||||
|
}
|
||||||
|
this.resizeEditor_();
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user