Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dfd3948a9 | ||
|
|
b3ebab438b | ||
|
|
0070ad353a | ||
|
|
39ce13e9b3 | ||
|
|
6ed8e9d788 | ||
|
|
9eb86c14b4 | ||
|
|
c7a4196413 | ||
|
|
4decc08e53 | ||
|
|
76a30ace67 |
5
build.sh
Normal file
5
build.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
grunt build:npm-react
|
||||
cd build/packages/react
|
||||
deps link
|
||||
npm install
|
||||
cd ../../..
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
2
docs/js/es5-sham.min.js
vendored
2
docs/js/es5-sham.min.js
vendored
File diff suppressed because one or more lines are too long
2
docs/js/es5-shim.min.js
vendored
2
docs/js/es5-shim.min.js
vendored
File diff suppressed because one or more lines are too long
8
docs/js/html5shiv.min.js
vendored
8
docs/js/html5shiv.min.js
vendored
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
|
||||
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
|
||||
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
|
||||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
|
||||
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
|
||||
@@ -1,746 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
|
||||
"await": C, "async": kw("async")
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "variable-3"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("class"),
|
||||
"implements": C,
|
||||
"namespace": C,
|
||||
"module": kw("module"),
|
||||
"enum": kw("module"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("modifier"),
|
||||
"private": kw("modifier"),
|
||||
"protected": kw("modifier"),
|
||||
"abstract": kw("modifier"),
|
||||
|
||||
// operators
|
||||
"as": operator,
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "boolean": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/o/i)) {
|
||||
stream.eatWhile(/[0-7]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/b/i)) {
|
||||
stream.eatWhile(/[01]/i);
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
ret("variable", "variable", word);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) break;
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (/["'\/]/.test(ch)) {
|
||||
return;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), expression, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
|
||||
if (type == "async") return cont(statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "modifier") {
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression);
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type, value) {
|
||||
if (type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(what, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
if (type == end || value == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type) {
|
||||
if (isTS && type == ":") return cont(typeexpr);
|
||||
}
|
||||
function maybedefault(_, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function typeexpr(type) {
|
||||
if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(commasep(typeexpr, ">"), afterType)
|
||||
if (type == "[") return cont(expect("]"), afterType)
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "modifier") return cont(pattern)
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype, maybedefault);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "extends") return cont(expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
if (value == "static") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
|
||||
return cont(functiondef, classBody);
|
||||
}
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
}
|
||||
function classGetterSetter(type) {
|
||||
if (type != "variable") return pass();
|
||||
cx.marked = "property";
|
||||
return cont();
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
return pass(statement);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(expressionNoComma, maybeArrayComprehension);
|
||||
}
|
||||
function maybeArrayComprehension(type) {
|
||||
if (type == "for") return pass(comprehension, expect("]"));
|
||||
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function comprehension(type) {
|
||||
if (type == "for") return cont(forspec, comprehension);
|
||||
if (type == "if") return cont(expression, comprehension);
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
skipExpression: function(state) {
|
||||
var top = state.cc[state.cc.length - 1]
|
||||
if (top == expression || top == expressionNoComma) state.cc.pop()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
(function() {
|
||||
var tag = document.querySelector(
|
||||
'script[type="application/javascript;version=1.7"]'
|
||||
);
|
||||
if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) {
|
||||
alert('Bad JSFiddle configuration, please fork the original React JSFiddle');
|
||||
}
|
||||
tag.setAttribute('type', 'text/babel');
|
||||
tag.textContent = tag.textContent.replace(/^\/\/<!\[CDATA\[/, '');
|
||||
})();
|
||||
147
docs/js/jsx.js
147
docs/js/jsx.js
@@ -1,147 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"))
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript"], mod)
|
||||
else // Plain browser env
|
||||
mod(CodeMirror)
|
||||
})(function(CodeMirror) {
|
||||
"use strict"
|
||||
|
||||
// Depth means the amount of open braces in JS context, in XML
|
||||
// context 0 means not in tag, 1 means in tag, and 2 means in tag
|
||||
// and js block comment.
|
||||
function Context(state, mode, depth, prev) {
|
||||
this.state = state; this.mode = mode; this.depth = depth; this.prev = prev
|
||||
}
|
||||
|
||||
function copyContext(context) {
|
||||
return new Context(CodeMirror.copyState(context.mode, context.state),
|
||||
context.mode,
|
||||
context.depth,
|
||||
context.prev && copyContext(context.prev))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("jsx", function(config, modeConfig) {
|
||||
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
|
||||
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
|
||||
|
||||
function flatXMLIndent(state) {
|
||||
var tagName = state.tagName
|
||||
state.tagName = null
|
||||
var result = xmlMode.indent(state, "")
|
||||
state.tagName = tagName
|
||||
return result
|
||||
}
|
||||
|
||||
function token(stream, state) {
|
||||
if (state.context.mode == xmlMode)
|
||||
return xmlToken(stream, state, state.context)
|
||||
else
|
||||
return jsToken(stream, state, state.context)
|
||||
}
|
||||
|
||||
function xmlToken(stream, state, cx) {
|
||||
if (cx.depth == 2) { // Inside a JS /* */ comment
|
||||
if (stream.match(/^.*?\*\//)) cx.depth = 1
|
||||
else stream.skipToEnd()
|
||||
return "comment"
|
||||
}
|
||||
|
||||
if (stream.peek() == "{") {
|
||||
xmlMode.skipAttribute(cx.state)
|
||||
|
||||
var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context
|
||||
// If JS starts on same line as tag
|
||||
if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) {
|
||||
while (xmlContext.prev && !xmlContext.startOfLine)
|
||||
xmlContext = xmlContext.prev
|
||||
// If tag starts the line, use XML indentation level
|
||||
if (xmlContext.startOfLine) indent -= config.indentUnit
|
||||
// Else use JS indentation level
|
||||
else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented
|
||||
// Else if inside of tag
|
||||
} else if (cx.depth == 1) {
|
||||
indent += config.indentUnit
|
||||
}
|
||||
|
||||
state.context = new Context(CodeMirror.startState(jsMode, indent),
|
||||
jsMode, 0, state.context)
|
||||
return null
|
||||
}
|
||||
|
||||
if (cx.depth == 1) { // Inside of tag
|
||||
if (stream.peek() == "<") { // Tag inside of tag
|
||||
xmlMode.skipAttribute(cx.state)
|
||||
state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)),
|
||||
xmlMode, 0, state.context)
|
||||
return null
|
||||
} else if (stream.match("//")) {
|
||||
stream.skipToEnd()
|
||||
return "comment"
|
||||
} else if (stream.match("/*")) {
|
||||
cx.depth = 2
|
||||
return token(stream, state)
|
||||
}
|
||||
}
|
||||
|
||||
var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop
|
||||
if (/\btag\b/.test(style)) {
|
||||
if (/>$/.test(cur)) {
|
||||
if (cx.state.context) cx.depth = 0
|
||||
else state.context = state.context.prev
|
||||
} else if (/^</.test(cur)) {
|
||||
cx.depth = 1
|
||||
}
|
||||
} else if (!style && (stop = cur.indexOf("{")) > -1) {
|
||||
stream.backUp(cur.length - stop)
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
function jsToken(stream, state, cx) {
|
||||
if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) {
|
||||
jsMode.skipExpression(cx.state)
|
||||
state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")),
|
||||
xmlMode, 0, state.context)
|
||||
return null
|
||||
}
|
||||
|
||||
var style = jsMode.token(stream, cx.state)
|
||||
if (!style && cx.depth != null) {
|
||||
var cur = stream.current()
|
||||
if (cur == "{") {
|
||||
cx.depth++
|
||||
} else if (cur == "}") {
|
||||
if (--cx.depth == 0) state.context = state.context.prev
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {context: new Context(CodeMirror.startState(jsMode), jsMode)}
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
return {context: copyContext(state.context)}
|
||||
},
|
||||
|
||||
token: token,
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
return state.context.mode.indent(state.context.state, textAfter, fullLine)
|
||||
},
|
||||
|
||||
innerMode: function(state) {
|
||||
return state.context
|
||||
}
|
||||
}
|
||||
}, "xml", "javascript")
|
||||
|
||||
CodeMirror.defineMIME("text/jsx", "jsx")
|
||||
});
|
||||
42
docs/js/react-dom.js
vendored
42
docs/js/react-dom.js
vendored
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* ReactDOM v15.3.1
|
||||
*
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
|
||||
;(function(f) {
|
||||
// CommonJS
|
||||
if (typeof exports === "object" && typeof module !== "undefined") {
|
||||
module.exports = f(require('react'));
|
||||
|
||||
// RequireJS
|
||||
} else if (typeof define === "function" && define.amd) {
|
||||
define(['react'], f);
|
||||
|
||||
// <script>
|
||||
} else {
|
||||
var g;
|
||||
if (typeof window !== "undefined") {
|
||||
g = window;
|
||||
} else if (typeof global !== "undefined") {
|
||||
g = global;
|
||||
} else if (typeof self !== "undefined") {
|
||||
g = self;
|
||||
} else {
|
||||
// works providing we're not in "use strict";
|
||||
// needed for Java 8 Nashorn
|
||||
// see https://github.com/facebook/react/issues/3037
|
||||
g = this;
|
||||
}
|
||||
g.ReactDOM = f(g.React);
|
||||
}
|
||||
|
||||
})(function(React) {
|
||||
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
||||
});
|
||||
20600
docs/js/react.js
vendored
20600
docs/js/react.js
vendored
File diff suppressed because it is too large
Load Diff
4
docs/js/remarkable.min.js
vendored
4
docs/js/remarkable.min.js
vendored
File diff suppressed because one or more lines are too long
394
docs/js/xml.js
394
docs/js/xml.js
@@ -1,394 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var htmlConfig = {
|
||||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
|
||||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
|
||||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
|
||||
'track': true, 'wbr': true, 'menuitem': true},
|
||||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
|
||||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
|
||||
'th': true, 'tr': true},
|
||||
contextGrabbers: {
|
||||
'dd': {'dd': true, 'dt': true},
|
||||
'dt': {'dd': true, 'dt': true},
|
||||
'li': {'li': true},
|
||||
'option': {'option': true, 'optgroup': true},
|
||||
'optgroup': {'optgroup': true},
|
||||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
|
||||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
|
||||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
|
||||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
|
||||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
|
||||
'rp': {'rp': true, 'rt': true},
|
||||
'rt': {'rp': true, 'rt': true},
|
||||
'tbody': {'tbody': true, 'tfoot': true},
|
||||
'td': {'td': true, 'th': true},
|
||||
'tfoot': {'tbody': true},
|
||||
'th': {'td': true, 'th': true},
|
||||
'thead': {'tbody': true, 'tfoot': true},
|
||||
'tr': {'tr': true}
|
||||
},
|
||||
doNotIndent: {"pre": true},
|
||||
allowUnquoted: true,
|
||||
allowMissing: true,
|
||||
caseFold: true
|
||||
}
|
||||
|
||||
var xmlConfig = {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false,
|
||||
caseFold: false
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("xml", function(editorConf, config_) {
|
||||
var indentUnit = editorConf.indentUnit
|
||||
var config = {}
|
||||
var defaults = config_.htmlMode ? htmlConfig : xmlConfig
|
||||
for (var prop in defaults) config[prop] = defaults[prop]
|
||||
for (var prop in config_) config[prop] = config_[prop]
|
||||
|
||||
// Return variables for tokenizers
|
||||
var type, setStyle;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
|
||||
else return null;
|
||||
} else if (stream.match("--")) {
|
||||
return chain(inBlock("comment", "-->"));
|
||||
} else if (stream.match("DOCTYPE", true, true)) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(doctype(1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("meta", "?>");
|
||||
return "meta";
|
||||
} else {
|
||||
type = stream.eat("/") ? "closeTag" : "openTag";
|
||||
state.tokenize = inTag;
|
||||
return "tag bracket";
|
||||
}
|
||||
} else if (ch == "&") {
|
||||
var ok;
|
||||
if (stream.eat("#")) {
|
||||
if (stream.eat("x")) {
|
||||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
|
||||
}
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
|
||||
}
|
||||
return ok ? "atom" : "error";
|
||||
} else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
inText.isInText = true;
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "tag bracket";
|
||||
} else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
} else if (ch == "<") {
|
||||
state.tokenize = inText;
|
||||
state.state = baseState;
|
||||
state.tagName = state.tagStart = null;
|
||||
var next = state.tokenize(stream, state);
|
||||
return next ? next + " tag error" : "tag error";
|
||||
} else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
state.stringStartCol = stream.column();
|
||||
return state.tokenize(stream, state);
|
||||
} else {
|
||||
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
|
||||
return "word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
var closure = function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
closure.isInAttribute = true;
|
||||
return closure;
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
function doctype(depth) {
|
||||
return function(stream, state) {
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "<") {
|
||||
state.tokenize = doctype(depth + 1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ">") {
|
||||
if (depth == 1) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
} else {
|
||||
state.tokenize = doctype(depth - 1);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
};
|
||||
}
|
||||
|
||||
function Context(state, tagName, startOfLine) {
|
||||
this.prev = state.context;
|
||||
this.tagName = tagName;
|
||||
this.indent = state.indented;
|
||||
this.startOfLine = startOfLine;
|
||||
if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
|
||||
this.noIndent = true;
|
||||
}
|
||||
function popContext(state) {
|
||||
if (state.context) state.context = state.context.prev;
|
||||
}
|
||||
function maybePopContext(state, nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!state.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = state.context.tagName;
|
||||
if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext(state);
|
||||
}
|
||||
}
|
||||
|
||||
function baseState(type, stream, state) {
|
||||
if (type == "openTag") {
|
||||
state.tagStart = stream.column();
|
||||
return tagNameState;
|
||||
} else if (type == "closeTag") {
|
||||
return closeTagNameState;
|
||||
} else {
|
||||
return baseState;
|
||||
}
|
||||
}
|
||||
function tagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
state.tagName = stream.current();
|
||||
setStyle = "tag";
|
||||
return attrState;
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return tagNameState;
|
||||
}
|
||||
}
|
||||
function closeTagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
var tagName = stream.current();
|
||||
if (state.context && state.context.tagName != tagName &&
|
||||
config.implicitlyClosed.hasOwnProperty(state.context.tagName))
|
||||
popContext(state);
|
||||
if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
|
||||
setStyle = "tag";
|
||||
return closeState;
|
||||
} else {
|
||||
setStyle = "tag error";
|
||||
return closeStateErr;
|
||||
}
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return closeStateErr;
|
||||
}
|
||||
}
|
||||
|
||||
function closeState(type, _stream, state) {
|
||||
if (type != "endTag") {
|
||||
setStyle = "error";
|
||||
return closeState;
|
||||
}
|
||||
popContext(state);
|
||||
return baseState;
|
||||
}
|
||||
function closeStateErr(type, stream, state) {
|
||||
setStyle = "error";
|
||||
return closeState(type, stream, state);
|
||||
}
|
||||
|
||||
function attrState(type, _stream, state) {
|
||||
if (type == "word") {
|
||||
setStyle = "attribute";
|
||||
return attrEqState;
|
||||
} else if (type == "endTag" || type == "selfcloseTag") {
|
||||
var tagName = state.tagName, tagStart = state.tagStart;
|
||||
state.tagName = state.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
config.autoSelfClosers.hasOwnProperty(tagName)) {
|
||||
maybePopContext(state, tagName);
|
||||
} else {
|
||||
maybePopContext(state, tagName);
|
||||
state.context = new Context(state, tagName, tagStart == state.indented);
|
||||
}
|
||||
return baseState;
|
||||
}
|
||||
setStyle = "error";
|
||||
return attrState;
|
||||
}
|
||||
function attrEqState(type, stream, state) {
|
||||
if (type == "equals") return attrValueState;
|
||||
if (!config.allowMissing) setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
|
||||
setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrContinuedState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function(baseIndent) {
|
||||
var state = {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: baseIndent || 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null}
|
||||
if (baseIndent != null) state.baseIndent = baseIndent
|
||||
return state
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol())
|
||||
state.indented = stream.indentation();
|
||||
|
||||
if (stream.eatSpace()) return null;
|
||||
type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if ((style || type) && style != "comment") {
|
||||
setStyle = null;
|
||||
state.state = state.state(type || style, stream, state);
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
var context = state.context;
|
||||
// Indent multi-line strings (e.g. css).
|
||||
if (state.tokenize.isInAttribute) {
|
||||
if (state.tagStart == state.indented)
|
||||
return state.stringStartCol + 1;
|
||||
else
|
||||
return state.indented + indentUnit;
|
||||
}
|
||||
if (context && context.noIndent) return CodeMirror.Pass;
|
||||
if (state.tokenize != inTag && state.tokenize != inText)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
// Indent the starts of attribute names.
|
||||
if (state.tagName) {
|
||||
if (config.multilineTagIndentPastTag !== false)
|
||||
return state.tagStart + state.tagName.length + 2;
|
||||
else
|
||||
return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
|
||||
}
|
||||
if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
|
||||
if (tagAfter && tagAfter[1]) { // Closing tag spotted
|
||||
while (context) {
|
||||
if (context.tagName == tagAfter[2]) {
|
||||
context = context.prev;
|
||||
break;
|
||||
} else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
|
||||
context = context.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagAfter) { // Opening tag spotted
|
||||
while (context) {
|
||||
var grabbers = config.contextGrabbers[context.tagName];
|
||||
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
|
||||
context = context.prev;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (context && context.prev && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return state.baseIndent || 0;
|
||||
},
|
||||
|
||||
electricInput: /<\/[\s\w:]+>$/,
|
||||
blockCommentStart: "<!--",
|
||||
blockCommentEnd: "-->",
|
||||
|
||||
configuration: config.htmlMode ? "html" : "xml",
|
||||
helperType: config.htmlMode ? "html" : "xml",
|
||||
|
||||
skipAttribute: function(state) {
|
||||
if (state.state == attrValueState)
|
||||
state.state = attrState
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
|
||||
});
|
||||
@@ -31,5 +31,10 @@
|
||||
"transform": [
|
||||
"loose-envify"
|
||||
]
|
||||
},
|
||||
"node-haste" {
|
||||
"roots": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
module.exports = function autoImporter(babel) {
|
||||
const t = babel.types;
|
||||
|
||||
function getAssignIdent(path, file, state) {
|
||||
function isObjectAssign(file) {
|
||||
var filename = file.opts.filename;
|
||||
return filename.indexOf('object-assign') >= 0;
|
||||
}
|
||||
|
||||
function getAssignIdent(path, state) {
|
||||
if (!state.id) {
|
||||
state.id = path.scope.generateUidIdentifier('assign');
|
||||
path.scope.getProgramParent().push({
|
||||
@@ -33,17 +38,19 @@ module.exports = function autoImporter(babel) {
|
||||
},
|
||||
|
||||
visitor: {
|
||||
CallExpression: function(path, file) {
|
||||
CallExpression: function(path, state) {
|
||||
if (isObjectAssign(state.file)) { return }
|
||||
if (path.get('callee').matchesPattern('Object.assign')) {
|
||||
// generate identifier and require if it hasn't been already
|
||||
var id = getAssignIdent(path, file, this);
|
||||
var id = getAssignIdent(path, state);
|
||||
path.node.callee = id;
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression: function(path, file) {
|
||||
MemberExpression: function(path, state) {
|
||||
if (isObjectAssign(state.file)) { return }
|
||||
if (path.matchesPattern('Object.assign')) {
|
||||
var id = getAssignIdent(path, file, this);
|
||||
var id = getAssignIdent(path, state);
|
||||
path.replaceWith(id);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -191,33 +191,17 @@ var ReactNativeEventEmitter = {
|
||||
removeTouchesAtIndices(touches, changedIndices) :
|
||||
touchSubsequence(touches, changedIndices);
|
||||
|
||||
for (var jj = 0; jj < changedTouches.length; jj++) {
|
||||
var touch = changedTouches[jj];
|
||||
// Touch objects can fulfill the role of `DOM` `Event` objects if we set
|
||||
// the `changedTouches`/`touches`. This saves allocations.
|
||||
touch.changedTouches = changedTouches;
|
||||
touch.touches = touches;
|
||||
var nativeEvent = touch;
|
||||
var rootNodeID = null;
|
||||
var target = nativeEvent.target;
|
||||
if (target !== null && target !== undefined) {
|
||||
if (target < ReactNativeTagHandles.tagsStartAt) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'A view is reporting that a touch occured on tag zero.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rootNodeID = target;
|
||||
}
|
||||
}
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
rootNodeID,
|
||||
eventTopLevelType,
|
||||
nativeEvent
|
||||
);
|
||||
}
|
||||
var nativeEvent = {
|
||||
target: changedTouches[0].target,
|
||||
touches,
|
||||
changedTouches,
|
||||
};
|
||||
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
nativeEvent.target,
|
||||
eventTopLevelType,
|
||||
nativeEvent
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -14,13 +14,11 @@ var UIManager = require('UIManager');
|
||||
|
||||
var ReactNativeGlobalResponderHandler = {
|
||||
onChange: function(from, to, blockNativeResponder) {
|
||||
if (from !== null) {
|
||||
UIManager.clearJSResponder(from._rootNodeID);
|
||||
}
|
||||
if (to !== null) {
|
||||
UIManager.setJSResponder(
|
||||
to._rootNodeID,
|
||||
blockNativeResponder
|
||||
);
|
||||
} else {
|
||||
UIManager.clearJSResponder();
|
||||
UIManager.setJSResponder(to._rootNodeID, blockNativeResponder);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
154
src/renderers/shared/stack/event/eventPlugins/GestureCache.js
Normal file
154
src/renderers/shared/stack/event/eventPlugins/GestureCache.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule GestureCache
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {Touch, TouchEvent} from 'TouchHistory';
|
||||
|
||||
const EventPluginUtils = require('EventPluginUtils');
|
||||
const ResponderCache = require('ResponderCache');
|
||||
const TouchHistory = require('TouchHistory');
|
||||
|
||||
export type Gesture = {
|
||||
target: number,
|
||||
touchMap: {[key:number]: Touch},
|
||||
changedTouches: Array<Touch>,
|
||||
touchHistory: TouchHistory,
|
||||
};
|
||||
|
||||
const activeGestures = [];
|
||||
const gesturesByTouch = {};
|
||||
const gesturesByTarget = {};
|
||||
|
||||
exports.targetChanged = function(topLevelType: string, oldTarget: any, newTarget: any): void {
|
||||
|
||||
const oldTag = EventPluginUtils.getNodeFromInstance(oldTarget);
|
||||
const oldGesture = gesturesByTarget[oldTag];
|
||||
if (!oldGesture) {
|
||||
return console.warn(`Invalid target has no gesture: ${oldTag}`);
|
||||
}
|
||||
|
||||
const newTag = EventPluginUtils.getNodeFromInstance(newTarget);
|
||||
const newGesture = gesturesByTarget[newTag];
|
||||
|
||||
// Move touch data from `oldGesture` to `newGesture`.
|
||||
if (newGesture) {
|
||||
newGesture.touchHistory.recordTouchEvent(
|
||||
topLevelType, oldGesture.changedTouches
|
||||
);
|
||||
oldGesture.changedTouches.forEach(touch => {
|
||||
newGesture.changedTouches.push(touch);
|
||||
});
|
||||
for (let identifier in oldGesture.touchMap) {
|
||||
gesturesByTouch[identifier] = newGesture;
|
||||
newGesture.touchMap[identifier] = oldGesture.touchMap[identifier];
|
||||
}
|
||||
removeGesture(oldGesture);
|
||||
} else {
|
||||
oldGesture.target = newTag;
|
||||
gesturesByTarget[newTag] = oldGesture;
|
||||
delete gesturesByTarget[oldTag];
|
||||
}
|
||||
};
|
||||
|
||||
exports.touchesChanged = function(topLevelType: string, nativeEvent: TouchEvent): Array<Gesture> {
|
||||
|
||||
const isStartish = EventPluginUtils.isStartish(topLevelType);
|
||||
const isEndish = EventPluginUtils.isEndish(topLevelType);
|
||||
|
||||
activeGestures.forEach(gesture => {
|
||||
gesture.changedTouches.length = 0;
|
||||
});
|
||||
|
||||
nativeEvent.changedTouches.forEach(touch => {
|
||||
const gesture = isStartish ?
|
||||
attachGesture(touch) :
|
||||
gesturesByTouch[touch.identifier];
|
||||
|
||||
gesture.changedTouches.push(touch);
|
||||
|
||||
if (!isEndish) {
|
||||
// Changed touches are entirely new objects.
|
||||
gesture.touchMap[touch.identifier] = touch;
|
||||
}
|
||||
});
|
||||
|
||||
// Detach ended touches from their gestures.
|
||||
if (isEndish) {
|
||||
nativeEvent.changedTouches.forEach(touch => {
|
||||
const {identifier} = touch;
|
||||
const gesture = gesturesByTouch[identifier];
|
||||
|
||||
// Remove the touch from the gesture, but *not* vice versa.
|
||||
delete gesture.touchMap[identifier];
|
||||
delete gesturesByTouch[identifier];
|
||||
});
|
||||
}
|
||||
|
||||
// Gather all gestures with at least one changed touch.
|
||||
// Ended gestures are removed from `activeGestures` while
|
||||
// looping, causing a shift in `activeGestures.length`.
|
||||
// Thus, we must start from the end of `activeGestures`.
|
||||
const changedGestures = [];
|
||||
for (let i = activeGestures.length - 1; i >= 0; i--) {
|
||||
let gesture = activeGestures[i];
|
||||
if (!gesture.changedTouches.length) {
|
||||
continue;
|
||||
}
|
||||
changedGestures.push(gesture);
|
||||
|
||||
// Update the touch history of every gesture with changed touches.
|
||||
gesture.touchHistory.recordTouchEvent(
|
||||
topLevelType, gesture.changedTouches
|
||||
);
|
||||
|
||||
// When a gesture has no touches, remove it from the cache.
|
||||
if (isEndish && gesture.touchHistory.numberActiveTouches === 0) {
|
||||
removeGesture(gesture);
|
||||
}
|
||||
}
|
||||
return changedGestures;
|
||||
};
|
||||
|
||||
// Attach a gesture to a touch. Create a gesture if necessary.
|
||||
function attachGesture(touch: Touch): Gesture {
|
||||
|
||||
// Using `findAncestor` means child responders cannot start
|
||||
// new gestures while a parent has an active gesture.
|
||||
const responderInst = ResponderCache.findAncestor(touch.target);
|
||||
const target = responderInst ?
|
||||
EventPluginUtils.getNodeFromInstance(responderInst) :
|
||||
touch.target;
|
||||
|
||||
// Use the same gesture between touches with the same target.
|
||||
let gesture = gesturesByTarget[target];
|
||||
if (!gesture) {
|
||||
gesture = {
|
||||
target,
|
||||
touchMap: {},
|
||||
changedTouches: [],
|
||||
touchHistory: new TouchHistory(),
|
||||
};
|
||||
activeGestures.push(gesture);
|
||||
gesturesByTarget[target] = gesture;
|
||||
}
|
||||
|
||||
gesturesByTouch[touch.identifier] = gesture;
|
||||
return gesture;
|
||||
}
|
||||
|
||||
// Remove a gesture from the global cache.
|
||||
function removeGesture(gesture: Gesture): void {
|
||||
const index = activeGestures.indexOf(gesture);
|
||||
activeGestures.splice(index, 1);
|
||||
delete gesturesByTarget[gesture.target];
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ResponderCache
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const EventPluginUtils = require('EventPluginUtils');
|
||||
|
||||
const emptyFunction = require('emptyFunction');
|
||||
|
||||
// Each active responder (by its react tag).
|
||||
const activeResponders = Object.create(null);
|
||||
|
||||
// Set this to handle responder grant/release/terminate events.
|
||||
exports.globalHandler = {onChange: emptyFunction};
|
||||
|
||||
exports.hasResponder = function(responderInst) {
|
||||
const nodeTag = EventPluginUtils.getNodeFromInstance(responderInst);
|
||||
return activeResponders[nodeTag] != null;
|
||||
};
|
||||
|
||||
exports.onResponderGrant = function(responderInst, blockHostResponder) {
|
||||
const nodeTag = EventPluginUtils.getNodeFromInstance(responderInst);
|
||||
activeResponders[nodeTag] = responderInst;
|
||||
this.globalHandler.onChange(null, responderInst, blockHostResponder);
|
||||
};
|
||||
|
||||
exports.onResponderEnd = function(responderInst) {
|
||||
const nodeTag = EventPluginUtils.getNodeFromInstance(responderInst);
|
||||
delete activeResponders[nodeTag];
|
||||
this.globalHandler.onChange(responderInst, null);
|
||||
};
|
||||
|
||||
exports.findAncestor = function(targetInst) {
|
||||
let parentInst = typeof targetInst === 'number' ?
|
||||
EventPluginUtils.getInstanceFromNode(targetInst) :
|
||||
targetInst;
|
||||
|
||||
while (parentInst != null) {
|
||||
let parentTag = EventPluginUtils.getNodeFromInstance(parentInst);
|
||||
if (activeResponders[parentTag]) {
|
||||
return activeResponders[parentTag];
|
||||
}
|
||||
parentInst = EventPluginUtils.getParentInstance(parentInst);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -14,8 +14,9 @@
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPluginUtils = require('EventPluginUtils');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var GestureCache = require('GestureCache');
|
||||
var ResponderCache = require('ResponderCache');
|
||||
var ResponderSyntheticEvent = require('ResponderSyntheticEvent');
|
||||
var ResponderTouchHistoryStore = require('ResponderTouchHistoryStore');
|
||||
|
||||
var accumulate = require('accumulate');
|
||||
var keyOf = require('keyOf');
|
||||
@@ -28,12 +29,6 @@ var hasDispatches = EventPluginUtils.hasDispatches;
|
||||
var executeDispatchesInOrderStopAtTrue =
|
||||
EventPluginUtils.executeDispatchesInOrderStopAtTrue;
|
||||
|
||||
/**
|
||||
* Instance of element that should respond to touch/move types of interactions,
|
||||
* as indicated explicitly by relevant callbacks.
|
||||
*/
|
||||
var responderInst = null;
|
||||
|
||||
/**
|
||||
* Count of current touches. A textInput should become responder iff the
|
||||
* selection changes while there is a touch on the screen.
|
||||
@@ -45,18 +40,6 @@ var trackedTouchCount = 0;
|
||||
*/
|
||||
var previousActiveTouches = 0;
|
||||
|
||||
var changeResponder = function(nextResponderInst, blockHostResponder) {
|
||||
var oldResponderInst = responderInst;
|
||||
responderInst = nextResponderInst;
|
||||
if (ResponderEventPlugin.GlobalResponderHandler !== null) {
|
||||
ResponderEventPlugin.GlobalResponderHandler.onChange(
|
||||
oldResponderInst,
|
||||
nextResponderInst,
|
||||
blockHostResponder
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var eventTypes = {
|
||||
/**
|
||||
* On a `touchStart`/`mouseDown`, is it desired that this element become the
|
||||
@@ -330,6 +313,16 @@ function setResponderAndExtractTransfer(
|
||||
eventTypes.selectionChangeShouldSetResponder :
|
||||
eventTypes.scrollShouldSetResponder;
|
||||
|
||||
// Active responders automatically capture touches inside descendants.
|
||||
var responderInst = ResponderCache.findAncestor(targetInst);
|
||||
if (responderInst && responderInst !== targetInst) {
|
||||
GestureCache.targetChanged(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
responderInst
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: stop one short of the current responder.
|
||||
var bubbleShouldSetFrom = !responderInst ?
|
||||
targetInst :
|
||||
@@ -346,7 +339,7 @@ function setResponderAndExtractTransfer(
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
shouldSetEvent.touchHistory = nativeEvent.touchHistory;
|
||||
if (skipOverBubbleShouldSetFrom) {
|
||||
EventPropagators.accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
|
||||
} else {
|
||||
@@ -361,25 +354,15 @@ function setResponderAndExtractTransfer(
|
||||
return null;
|
||||
}
|
||||
var extracted;
|
||||
var grantEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderGrant,
|
||||
wantsResponderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
|
||||
EventPropagators.accumulateDirectDispatches(grantEvent);
|
||||
var blockHostResponder = executeDirectDispatch(grantEvent) === true;
|
||||
if (responderInst) {
|
||||
|
||||
var terminationRequestEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderTerminationRequest,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
terminationRequestEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
|
||||
var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
|
||||
executeDirectDispatch(terminationRequestEvent);
|
||||
@@ -387,32 +370,56 @@ function setResponderAndExtractTransfer(
|
||||
terminationRequestEvent.constructor.release(terminationRequestEvent);
|
||||
}
|
||||
|
||||
if (shouldSwitch) {
|
||||
var terminateEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderTerminate,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(terminateEvent);
|
||||
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
|
||||
changeResponder(wantsResponderInst, blockHostResponder);
|
||||
} else {
|
||||
if (!shouldSwitch) {
|
||||
var rejectEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderReject,
|
||||
wantsResponderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
rejectEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(rejectEvent);
|
||||
extracted = accumulate(extracted, rejectEvent);
|
||||
return accumulate(extracted, rejectEvent);
|
||||
}
|
||||
|
||||
var terminateEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderTerminate,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
terminateEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(terminateEvent);
|
||||
extracted = accumulate(extracted, terminateEvent);
|
||||
|
||||
// Always dispatch 'terminateEvent' before 'grantEvent'.
|
||||
if (hasDispatches(terminateEvent)) {
|
||||
executeDirectDispatch(terminateEvent);
|
||||
}
|
||||
} else {
|
||||
extracted = accumulate(extracted, grantEvent);
|
||||
changeResponder(wantsResponderInst, blockHostResponder);
|
||||
}
|
||||
|
||||
// Transfer gesture to next responder.
|
||||
if (responderInst || targetInst !== wantsResponderInst) {
|
||||
GestureCache.targetChanged(
|
||||
topLevelType,
|
||||
responderInst || targetInst,
|
||||
wantsResponderInst
|
||||
);
|
||||
}
|
||||
|
||||
var grantEvent = ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderGrant,
|
||||
wantsResponderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
grantEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(grantEvent);
|
||||
extracted = accumulate(extracted, grantEvent);
|
||||
|
||||
var blockHostResponder = executeDirectDispatch(grantEvent) === true;
|
||||
responderInst && ResponderCache.onResponderEnd(responderInst);
|
||||
ResponderCache.onResponderGrant(wantsResponderInst, blockHostResponder);
|
||||
return extracted;
|
||||
}
|
||||
|
||||
@@ -438,32 +445,105 @@ function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this touch end event makes it such that there are no
|
||||
* longer any touches that started inside of the current `responderInst`.
|
||||
*
|
||||
* @param {NativeEvent} nativeEvent Native touch end event.
|
||||
* @return {boolean} Whether or not this touch end event ends the responder.
|
||||
*/
|
||||
function noResponderTouches(nativeEvent) {
|
||||
var touches = nativeEvent.touches;
|
||||
if (!touches || touches.length === 0) {
|
||||
return true;
|
||||
}
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var activeTouch = touches[i];
|
||||
var target = activeTouch.target;
|
||||
if (target !== null && target !== undefined && target !== 0) {
|
||||
// Is the original touch location inside of the current responder?
|
||||
var targetInst = EventPluginUtils.getInstanceFromNode(target);
|
||||
if (EventPluginUtils.isAncestor(responderInst, targetInst)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function extractTouchEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
var extracted;
|
||||
|
||||
if (canTriggerTransfer(topLevelType, targetInst, nativeEvent)) {
|
||||
extracted = setResponderAndExtractTransfer(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
}
|
||||
|
||||
// Find the first ancestor that is currently responding.
|
||||
var responderInst = ResponderCache.findAncestor(targetInst);
|
||||
if (responderInst) {
|
||||
nativeEventTarget =
|
||||
EventPluginUtils.getNodeFromInstance(responderInst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responder may or may not have transferred on a new touch start/move.
|
||||
* Regardless, whoever is the responder after any potential transfer, we
|
||||
* direct all touch start/move/ends to them in the form of
|
||||
* `onResponderMove/Start/End`. These will be called for *every* additional
|
||||
* finger that move/start/end, dispatched directly to whoever is the
|
||||
* current responder at that moment, until the responder is "released".
|
||||
*
|
||||
* These multiple individual change touch events are are always bookended
|
||||
* by `onResponderGrant`, and one of
|
||||
* (`onResponderRelease/onResponderTerminate`).
|
||||
*/
|
||||
var isResponderTouchStart = responderInst && isStartish(topLevelType);
|
||||
var isResponderTouchMove = responderInst && isMoveish(topLevelType);
|
||||
var isResponderTouchEnd = responderInst && isEndish(topLevelType);
|
||||
var incrementalTouch =
|
||||
isResponderTouchStart ? eventTypes.responderStart :
|
||||
isResponderTouchMove ? eventTypes.responderMove :
|
||||
isResponderTouchEnd ? eventTypes.responderEnd :
|
||||
null;
|
||||
|
||||
var touchHandler = ResponderEventPlugin.GlobalTouchHandler;
|
||||
if (touchHandler && isEndish(topLevelType)) {
|
||||
var endishEvent =
|
||||
ResponderSyntheticEvent.getPooled(
|
||||
eventTypes.responderEnd,
|
||||
responderInst || targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
endishEvent.touchHistory = nativeEvent.touchHistory;
|
||||
touchHandler.onTouchEnd(endishEvent);
|
||||
}
|
||||
|
||||
if (incrementalTouch) {
|
||||
var touchEvent =
|
||||
ResponderSyntheticEvent.getPooled(
|
||||
incrementalTouch,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
touchEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(touchEvent);
|
||||
extracted = accumulate(extracted, touchEvent);
|
||||
}
|
||||
|
||||
var isResponderTerminate =
|
||||
responderInst &&
|
||||
topLevelType === EventConstants.topLevelTypes.topTouchCancel;
|
||||
var isResponderRelease =
|
||||
responderInst &&
|
||||
!isResponderTerminate &&
|
||||
isEndish(topLevelType) &&
|
||||
nativeEvent.touchHistory.numberActiveTouches === 0;
|
||||
var finalTouch =
|
||||
isResponderTerminate ? eventTypes.responderTerminate :
|
||||
isResponderRelease ? eventTypes.responderRelease :
|
||||
null;
|
||||
if (finalTouch) {
|
||||
ResponderCache.onResponderEnd(responderInst);
|
||||
var finalEvent =
|
||||
ResponderSyntheticEvent.getPooled(
|
||||
finalTouch,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
finalEvent.touchHistory = nativeEvent.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(finalEvent);
|
||||
extracted = accumulate(extracted, finalEvent);
|
||||
}
|
||||
|
||||
return extracted;
|
||||
}
|
||||
|
||||
var ResponderEventPlugin = {
|
||||
|
||||
@@ -485,12 +565,15 @@ var ResponderEventPlugin = {
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
if (!nativeEvent.touches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isStartish(topLevelType)) {
|
||||
trackedTouchCount += 1;
|
||||
trackedTouchCount += nativeEvent.changedTouches.length;
|
||||
} else if (isEndish(topLevelType)) {
|
||||
if (trackedTouchCount >= 0) {
|
||||
trackedTouchCount -= 1;
|
||||
} else {
|
||||
trackedTouchCount -= nativeEvent.changedTouches.length;
|
||||
if (trackedTouchCount < 0) {
|
||||
console.error(
|
||||
'Ended a touch event which was not counted in `trackedTouchCount`.'
|
||||
);
|
||||
@@ -498,93 +581,52 @@ var ResponderEventPlugin = {
|
||||
}
|
||||
}
|
||||
|
||||
ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent);
|
||||
// Touches are grouped by active target.
|
||||
var changedGestures = GestureCache.touchesChanged(topLevelType, nativeEvent);
|
||||
|
||||
var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) ?
|
||||
setResponderAndExtractTransfer(
|
||||
var extracted;
|
||||
changedGestures.forEach(gesture => {
|
||||
gesture.touches = Object.values(gesture.touchMap);
|
||||
var targetInst = EventPluginUtils.getInstanceFromNode(gesture.target);
|
||||
var touchEvents = extractTouchEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget) :
|
||||
null;
|
||||
// Responder may or may not have transferred on a new touch start/move.
|
||||
// Regardless, whoever is the responder after any potential transfer, we
|
||||
// direct all touch start/move/ends to them in the form of
|
||||
// `onResponderMove/Start/End`. These will be called for *every* additional
|
||||
// finger that move/start/end, dispatched directly to whoever is the
|
||||
// current responder at that moment, until the responder is "released".
|
||||
//
|
||||
// These multiple individual change touch events are are always bookended
|
||||
// by `onResponderGrant`, and one of
|
||||
// (`onResponderRelease/onResponderTerminate`).
|
||||
var isResponderTouchStart = responderInst && isStartish(topLevelType);
|
||||
var isResponderTouchMove = responderInst && isMoveish(topLevelType);
|
||||
var isResponderTouchEnd = responderInst && isEndish(topLevelType);
|
||||
var incrementalTouch =
|
||||
isResponderTouchStart ? eventTypes.responderStart :
|
||||
isResponderTouchMove ? eventTypes.responderMove :
|
||||
isResponderTouchEnd ? eventTypes.responderEnd :
|
||||
null;
|
||||
|
||||
if (incrementalTouch) {
|
||||
var gesture =
|
||||
ResponderSyntheticEvent.getPooled(
|
||||
incrementalTouch,
|
||||
responderInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
);
|
||||
gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(gesture);
|
||||
extracted = accumulate(extracted, gesture);
|
||||
}
|
||||
|
||||
var isResponderTerminate =
|
||||
responderInst &&
|
||||
topLevelType === EventConstants.topLevelTypes.topTouchCancel;
|
||||
var isResponderRelease =
|
||||
responderInst &&
|
||||
!isResponderTerminate &&
|
||||
isEndish(topLevelType) &&
|
||||
noResponderTouches(nativeEvent);
|
||||
var finalTouch =
|
||||
isResponderTerminate ? eventTypes.responderTerminate :
|
||||
isResponderRelease ? eventTypes.responderRelease :
|
||||
null;
|
||||
if (finalTouch) {
|
||||
var finalEvent = ResponderSyntheticEvent.getPooled(
|
||||
finalTouch, responderInst, nativeEvent, nativeEventTarget
|
||||
gesture,
|
||||
gesture.target
|
||||
);
|
||||
finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(finalEvent);
|
||||
extracted = accumulate(extracted, finalEvent);
|
||||
changeResponder(null);
|
||||
}
|
||||
if (touchEvents) {
|
||||
extracted = accumulate(extracted, touchEvents);
|
||||
}
|
||||
});
|
||||
|
||||
var numberActiveTouches =
|
||||
ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
|
||||
if (ResponderEventPlugin.GlobalInteractionHandler &&
|
||||
numberActiveTouches !== previousActiveTouches) {
|
||||
ResponderEventPlugin.GlobalInteractionHandler.onChange(
|
||||
numberActiveTouches
|
||||
);
|
||||
var interactionHandler = ResponderEventPlugin.GlobalInteractionHandler;
|
||||
if (interactionHandler && trackedTouchCount !== previousActiveTouches) {
|
||||
interactionHandler.onChange(trackedTouchCount);
|
||||
}
|
||||
previousActiveTouches = numberActiveTouches;
|
||||
previousActiveTouches = trackedTouchCount;
|
||||
|
||||
return extracted;
|
||||
},
|
||||
|
||||
GlobalResponderHandler: null,
|
||||
GlobalTouchHandler: null,
|
||||
GlobalInteractionHandler: null,
|
||||
|
||||
injection: {
|
||||
/**
|
||||
* @param {onTouchEnd: (TouchEvent) => void} GlobalTouchHandler
|
||||
* Object that handles all touch events.
|
||||
*/
|
||||
injectGlobalTouchHandler:function(GlobalTouchHandler) {
|
||||
ResponderEventPlugin.GlobalTouchHandler = GlobalTouchHandler;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler
|
||||
* Object that handles any change in responder. Use this to inject
|
||||
* integration with an existing touch handling system etc.
|
||||
*/
|
||||
injectGlobalResponderHandler: function(GlobalResponderHandler) {
|
||||
ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
|
||||
ResponderCache.globalHandler = GlobalResponderHandler;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
228
src/renderers/shared/stack/event/eventPlugins/TouchHistory.js
Normal file
228
src/renderers/shared/stack/event/eventPlugins/TouchHistory.js
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule TouchHistory
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const EventPluginUtils = require('EventPluginUtils');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const warning = require('warning');
|
||||
|
||||
const {
|
||||
isEndish,
|
||||
isMoveish,
|
||||
isStartish,
|
||||
} = EventPluginUtils;
|
||||
|
||||
export type Touch = {
|
||||
identifier: ?number,
|
||||
pageX: number,
|
||||
pageY: number,
|
||||
timestamp: number,
|
||||
};
|
||||
|
||||
export type TouchEvent = {
|
||||
changedTouches: Array<Touch>,
|
||||
touches: Array<Touch>,
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracks the position and time of each active touch by `touch.identifier`. We
|
||||
* should typically only see IDs in the range of 1-20 because IDs get recycled
|
||||
* when touches end and start again.
|
||||
*/
|
||||
type TouchRecord = {
|
||||
touchActive: boolean,
|
||||
startPageX: number,
|
||||
startPageY: number,
|
||||
startTimeStamp: number,
|
||||
currentPageX: number,
|
||||
currentPageY: number,
|
||||
currentTimeStamp: number,
|
||||
previousPageX: number,
|
||||
previousPageY: number,
|
||||
previousTimeStamp: number,
|
||||
};
|
||||
|
||||
type TouchBank = Array<TouchRecord>;
|
||||
|
||||
const MAX_TOUCH_BANK = 20;
|
||||
|
||||
class TouchHistory {
|
||||
constructor() {
|
||||
this.touchBank = [];
|
||||
this.numberActiveTouches = 0;
|
||||
// If there is only one active touch, we remember its location. This prevents
|
||||
// us having to loop through all of the touches all the time in the most
|
||||
// common case.
|
||||
this.indexOfSingleActiveTouch = -1;
|
||||
this.mostRecentTimeStamp = 0;
|
||||
}
|
||||
|
||||
recordTouchEvent(topLevelType: string, changedTouches: Array<Touch>): void {
|
||||
if (isMoveish(topLevelType)) {
|
||||
changedTouches.forEach(touch => this._recordTouchMove(touch));
|
||||
} else if (isStartish(topLevelType)) {
|
||||
changedTouches.forEach(touch => this._recordTouchStart(touch));
|
||||
if (this.numberActiveTouches === 1) {
|
||||
this.indexOfSingleActiveTouch =
|
||||
changedTouches[0].identifier;
|
||||
}
|
||||
} else if (isEndish(topLevelType)) {
|
||||
changedTouches.forEach(touch => this._recordTouchEnd(touch));
|
||||
if (this.numberActiveTouches === 1) {
|
||||
for (let i = 0; i < this.touchBank.length; i++) {
|
||||
const touchTrackToCheck = this.touchBank[i];
|
||||
if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
|
||||
this.indexOfSingleActiveTouch = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
const activeRecord = this.touchBank[this.indexOfSingleActiveTouch];
|
||||
warning(
|
||||
activeRecord != null &&
|
||||
activeRecord.touchActive,
|
||||
'Cannot find single active touch.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_recordTouchStart(touch: Touch): void {
|
||||
const identifier = getTouchIdentifier(touch);
|
||||
const touchRecord = this.touchBank[identifier];
|
||||
if (touchRecord) {
|
||||
resetTouchRecord(touchRecord, touch);
|
||||
} else {
|
||||
this.touchBank[identifier] = createTouchRecord(touch);
|
||||
}
|
||||
this.mostRecentTimeStamp = timestampForTouch(touch);
|
||||
this.numberActiveTouches += 1;
|
||||
}
|
||||
|
||||
_recordTouchMove(touch: Touch): void {
|
||||
const touchRecord = this.touchBank[getTouchIdentifier(touch)];
|
||||
if (touchRecord) {
|
||||
touchRecord.touchActive = true;
|
||||
touchRecord.previousPageX = touchRecord.currentPageX;
|
||||
touchRecord.previousPageY = touchRecord.currentPageY;
|
||||
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
|
||||
touchRecord.currentPageX = touch.pageX;
|
||||
touchRecord.currentPageY = touch.pageY;
|
||||
touchRecord.currentTimeStamp = timestampForTouch(touch);
|
||||
this.mostRecentTimeStamp = timestampForTouch(touch);
|
||||
} else {
|
||||
console.error(
|
||||
'Cannot record touch move without a touch start.\n' +
|
||||
'Touch Move: %s\n',
|
||||
'Touch Bank: %s',
|
||||
printTouch(touch),
|
||||
printTouchBank(this.touchBank)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_recordTouchEnd(touch: Touch): void {
|
||||
const touchRecord = this.touchBank[getTouchIdentifier(touch)];
|
||||
if (touchRecord) {
|
||||
this.numberActiveTouches -= 1;
|
||||
touchRecord.touchActive = false;
|
||||
touchRecord.previousPageX = touchRecord.currentPageX;
|
||||
touchRecord.previousPageY = touchRecord.currentPageY;
|
||||
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
|
||||
touchRecord.currentPageX = touch.pageX;
|
||||
touchRecord.currentPageY = touch.pageY;
|
||||
touchRecord.currentTimeStamp = timestampForTouch(touch);
|
||||
this.mostRecentTimeStamp = timestampForTouch(touch);
|
||||
} else {
|
||||
console.error(
|
||||
'Cannot record touch end without a touch start.\n' +
|
||||
'Touch End: %s\n',
|
||||
'Touch Bank: %s',
|
||||
printTouch(touch),
|
||||
printTouchBank(this.touchBank)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TouchHistory;
|
||||
|
||||
function timestampForTouch(touch: Touch): number {
|
||||
// The legacy internal implementation provides "timeStamp", which has been
|
||||
// renamed to "timestamp". Let both work for now while we iron it out
|
||||
// TODO (evv): rename timeStamp to timestamp in internal code
|
||||
return (touch: any).timeStamp || touch.timestamp;
|
||||
}
|
||||
|
||||
function getTouchIdentifier({identifier}: Touch): number {
|
||||
invariant(identifier != null, 'Touch object is missing identifier.');
|
||||
warning(
|
||||
identifier <= MAX_TOUCH_BANK,
|
||||
'Touch identifier %s is greater than maximum supported %s which causes ' +
|
||||
'performance issues backfilling array locations for all of the indices.',
|
||||
identifier,
|
||||
MAX_TOUCH_BANK
|
||||
);
|
||||
return identifier;
|
||||
}
|
||||
|
||||
function printTouch(touch: Touch): string {
|
||||
return JSON.stringify({
|
||||
identifier: touch.identifier,
|
||||
pageX: touch.pageX,
|
||||
pageY: touch.pageY,
|
||||
timestamp: timestampForTouch(touch),
|
||||
});
|
||||
}
|
||||
|
||||
function printTouchBank(touchBank: TouchBank): string {
|
||||
let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
|
||||
if (touchBank.length > MAX_TOUCH_BANK) {
|
||||
printed += ' (original size: ' + touchBank.length + ')';
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Instead of making gestures recompute filtered velocity, we could
|
||||
* include a built in velocity computation that can be reused globally.
|
||||
*/
|
||||
function createTouchRecord(touch: Touch): TouchRecord {
|
||||
return {
|
||||
touchActive: true,
|
||||
startPageX: touch.pageX,
|
||||
startPageY: touch.pageY,
|
||||
startTimeStamp: timestampForTouch(touch),
|
||||
currentPageX: touch.pageX,
|
||||
currentPageY: touch.pageY,
|
||||
currentTimeStamp: timestampForTouch(touch),
|
||||
previousPageX: touch.pageX,
|
||||
previousPageY: touch.pageY,
|
||||
previousTimeStamp: timestampForTouch(touch),
|
||||
};
|
||||
}
|
||||
|
||||
function resetTouchRecord(touchRecord: TouchRecord, touch: Touch): void {
|
||||
touchRecord.touchActive = true;
|
||||
touchRecord.startPageX = touch.pageX;
|
||||
touchRecord.startPageY = touch.pageY;
|
||||
touchRecord.startTimeStamp = timestampForTouch(touch);
|
||||
touchRecord.currentPageX = touch.pageX;
|
||||
touchRecord.currentPageY = touch.pageY;
|
||||
touchRecord.currentTimeStamp = timestampForTouch(touch);
|
||||
touchRecord.previousPageX = touch.pageX;
|
||||
touchRecord.previousPageY = touch.pageY;
|
||||
touchRecord.previousTimeStamp = timestampForTouch(touch);
|
||||
}
|
||||
@@ -730,8 +730,8 @@ describe('ResponderEventPlugin', function() {
|
||||
|
||||
// Parent is responder, and responder is transferred by a second touch start
|
||||
config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: true};
|
||||
config.responderGrant.grandParent = {order: 1};
|
||||
config.responderTerminationRequest.parent = {order: 2, returnVal: true};
|
||||
config.responderTerminationRequest.parent = {order: 1, returnVal: true};
|
||||
config.responderGrant.grandParent = {order: 2};
|
||||
config.responderTerminate.parent = {order: 3};
|
||||
config.responderStart.grandParent = {order: 4};
|
||||
run(config, three, startConfig(three.child, [three.child, three.child], [1]));
|
||||
@@ -899,11 +899,10 @@ describe('ResponderEventPlugin', function() {
|
||||
config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
|
||||
config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
|
||||
config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
|
||||
config.responderGrant.parent = {order: 3};
|
||||
config.responderTerminationRequest.child = {order: 4, returnVal: false};
|
||||
config.responderReject.parent = {order: 5};
|
||||
config.responderTerminationRequest.child = {order: 3, returnVal: false};
|
||||
config.responderReject.parent = {order: 4};
|
||||
// The start/move should occur on the original responder if new one is rejected
|
||||
config.responderMove.child = {order: 6};
|
||||
config.responderMove.child = {order: 5};
|
||||
|
||||
var touchConfig =
|
||||
moveConfig(three.child, [three.child], [0]);
|
||||
@@ -914,11 +913,10 @@ describe('ResponderEventPlugin', function() {
|
||||
config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
|
||||
config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
|
||||
config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
|
||||
config.responderGrant.parent = {order: 3};
|
||||
config.responderTerminationRequest.child = {order: 4, returnVal: false};
|
||||
config.responderReject.parent = {order: 5};
|
||||
config.responderTerminationRequest.child = {order: 3, returnVal: false};
|
||||
config.responderReject.parent = {order: 4};
|
||||
// The start/move should occur on the original responder if new one is rejected
|
||||
config.responderStart.child = {order: 6};
|
||||
config.responderStart.child = {order: 5};
|
||||
|
||||
touchConfig =
|
||||
startConfig(three.child, [three.child, three.child], [1]);
|
||||
@@ -948,9 +946,8 @@ describe('ResponderEventPlugin', function() {
|
||||
config.scrollShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
|
||||
config.scrollShouldSetResponder.captured.parent = {order: 1, returnVal: false};
|
||||
config.scrollShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
|
||||
config.responderGrant.parent = {order: 3};
|
||||
config.responderTerminationRequest.child = {order: 4, returnVal: false};
|
||||
config.responderReject.parent = {order: 5};
|
||||
config.responderTerminationRequest.child = {order: 3, returnVal: false};
|
||||
config.responderReject.parent = {order: 4};
|
||||
|
||||
run(config, three, {
|
||||
topLevelType: topLevelTypes.topScroll,
|
||||
@@ -965,8 +962,8 @@ describe('ResponderEventPlugin', function() {
|
||||
config.scrollShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
|
||||
config.scrollShouldSetResponder.captured.parent = {order: 1, returnVal: false};
|
||||
config.scrollShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
|
||||
config.responderGrant.parent = {order: 3};
|
||||
config.responderTerminationRequest.child = {order: 4, returnVal: true};
|
||||
config.responderTerminationRequest.child = {order: 3, returnVal: true};
|
||||
config.responderGrant.parent = {order: 4};
|
||||
config.responderTerminate.child = {order: 5};
|
||||
|
||||
run(config, three, {
|
||||
|
||||
Reference in New Issue
Block a user