Added Scrollview.
This commit is contained in:
Vendored
+7557
-890
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
-890
@@ -1,893 +1,3 @@
|
||||
/*
|
||||
Syntax highlighting with language autodetection.
|
||||
https://highlightjs.org/
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
|
||||
// Find the global object for export to both the browser and web workers.
|
||||
var globalObject = typeof window === 'object' && window ||
|
||||
typeof self === 'object' && self;
|
||||
|
||||
// Setup highlight.js for different environments. First is Node.js or
|
||||
// CommonJS.
|
||||
if(typeof exports !== 'undefined') {
|
||||
factory(exports);
|
||||
} else if(globalObject) {
|
||||
// Export hljs globally even when using AMD for cases when this script
|
||||
// is loaded with others that may still expect a global hljs.
|
||||
globalObject.hljs = factory({});
|
||||
|
||||
// Finally register the global hljs with AMD.
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define([], function() {
|
||||
return globalObject.hljs;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}(function(hljs) {
|
||||
// Convenience variables for build-in objects
|
||||
var ArrayProto = [],
|
||||
objectKeys = Object.keys;
|
||||
|
||||
// Global internal variables used within the highlight.js library.
|
||||
var languages = {},
|
||||
aliases = {};
|
||||
|
||||
// Regular expressions used throughout the highlight.js library.
|
||||
var noHighlightRe = /^(no-?highlight|plain|text)$/i,
|
||||
languagePrefixRe = /\blang(?:uage)?-([\w-]+)\b/i,
|
||||
fixMarkupRe = /((^(<[^>]+>|\t|)+|(?:\n)))/gm;
|
||||
|
||||
// The object will be assigned by the build tool. It used to synchronize API
|
||||
// of external language files with minified version of the highlight.js library.
|
||||
var API_REPLACES;
|
||||
|
||||
var spanEndTag = '</span>';
|
||||
|
||||
// Global options used when within external APIs. This is modified when
|
||||
// calling the `hljs.configure` function.
|
||||
var options = {
|
||||
classPrefix: 'hljs-',
|
||||
tabReplace: null,
|
||||
useBR: false,
|
||||
languages: undefined
|
||||
};
|
||||
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
function escape(value) {
|
||||
return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
function tag(node) {
|
||||
return node.nodeName.toLowerCase();
|
||||
}
|
||||
|
||||
function testRe(re, lexeme) {
|
||||
var match = re && re.exec(lexeme);
|
||||
return match && match.index === 0;
|
||||
}
|
||||
|
||||
function isNotHighlighted(language) {
|
||||
return noHighlightRe.test(language);
|
||||
}
|
||||
|
||||
function blockLanguage(block) {
|
||||
var i, match, length, _class;
|
||||
var classes = block.className + ' ';
|
||||
|
||||
classes += block.parentNode ? block.parentNode.className : '';
|
||||
|
||||
// language-* takes precedence over non-prefixed class names.
|
||||
match = languagePrefixRe.exec(classes);
|
||||
if (match) {
|
||||
return getLanguage(match[1]) ? match[1] : 'no-highlight';
|
||||
}
|
||||
|
||||
classes = classes.split(/\s+/);
|
||||
|
||||
for (i = 0, length = classes.length; i < length; i++) {
|
||||
_class = classes[i];
|
||||
|
||||
if (isNotHighlighted(_class) || getLanguage(_class)) {
|
||||
return _class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function inherit(parent) { // inherit(parent, override_obj, override_obj, ...)
|
||||
var key;
|
||||
var result = {};
|
||||
var objects = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
for (key in parent)
|
||||
result[key] = parent[key];
|
||||
objects.forEach(function(obj) {
|
||||
for (key in obj)
|
||||
result[key] = obj[key];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Stream merging */
|
||||
|
||||
function nodeStream(node) {
|
||||
var result = [];
|
||||
(function _nodeStream(node, offset) {
|
||||
for (var child = node.firstChild; child; child = child.nextSibling) {
|
||||
if (child.nodeType === 3)
|
||||
offset += child.nodeValue.length;
|
||||
else if (child.nodeType === 1) {
|
||||
result.push({
|
||||
event: 'start',
|
||||
offset: offset,
|
||||
node: child
|
||||
});
|
||||
offset = _nodeStream(child, offset);
|
||||
// Prevent void elements from having an end tag that would actually
|
||||
// double them in the output. There are more void elements in HTML
|
||||
// but we list only those realistically expected in code display.
|
||||
if (!tag(child).match(/br|hr|img|input/)) {
|
||||
result.push({
|
||||
event: 'stop',
|
||||
offset: offset,
|
||||
node: child
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
})(node, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
function mergeStreams(original, highlighted, value) {
|
||||
var processed = 0;
|
||||
var result = '';
|
||||
var nodeStack = [];
|
||||
|
||||
function selectStream() {
|
||||
if (!original.length || !highlighted.length) {
|
||||
return original.length ? original : highlighted;
|
||||
}
|
||||
if (original[0].offset !== highlighted[0].offset) {
|
||||
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
|
||||
}
|
||||
|
||||
/*
|
||||
To avoid starting the stream just before it should stop the order is
|
||||
ensured that original always starts first and closes last:
|
||||
|
||||
if (event1 == 'start' && event2 == 'start')
|
||||
return original;
|
||||
if (event1 == 'start' && event2 == 'stop')
|
||||
return highlighted;
|
||||
if (event1 == 'stop' && event2 == 'start')
|
||||
return original;
|
||||
if (event1 == 'stop' && event2 == 'stop')
|
||||
return highlighted;
|
||||
|
||||
... which is collapsed to:
|
||||
*/
|
||||
return highlighted[0].event === 'start' ? original : highlighted;
|
||||
}
|
||||
|
||||
function open(node) {
|
||||
function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value).replace('"', '"') + '"';}
|
||||
result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>';
|
||||
}
|
||||
|
||||
function close(node) {
|
||||
result += '</' + tag(node) + '>';
|
||||
}
|
||||
|
||||
function render(event) {
|
||||
(event.event === 'start' ? open : close)(event.node);
|
||||
}
|
||||
|
||||
while (original.length || highlighted.length) {
|
||||
var stream = selectStream();
|
||||
result += escape(value.substring(processed, stream[0].offset));
|
||||
processed = stream[0].offset;
|
||||
if (stream === original) {
|
||||
/*
|
||||
On any opening or closing tag of the original markup we first close
|
||||
the entire highlighted node stack, then render the original tag along
|
||||
with all the following original tags at the same offset and then
|
||||
reopen all the tags on the highlighted stack.
|
||||
*/
|
||||
nodeStack.reverse().forEach(close);
|
||||
do {
|
||||
render(stream.splice(0, 1)[0]);
|
||||
stream = selectStream();
|
||||
} while (stream === original && stream.length && stream[0].offset === processed);
|
||||
nodeStack.reverse().forEach(open);
|
||||
} else {
|
||||
if (stream[0].event === 'start') {
|
||||
nodeStack.push(stream[0].node);
|
||||
} else {
|
||||
nodeStack.pop();
|
||||
}
|
||||
render(stream.splice(0, 1)[0]);
|
||||
}
|
||||
}
|
||||
return result + escape(value.substr(processed));
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
||||
function expand_mode(mode) {
|
||||
if (mode.variants && !mode.cached_variants) {
|
||||
mode.cached_variants = mode.variants.map(function(variant) {
|
||||
return inherit(mode, {variants: null}, variant);
|
||||
});
|
||||
}
|
||||
return mode.cached_variants || (mode.endsWithParent && [inherit(mode)]) || [mode];
|
||||
}
|
||||
|
||||
function restoreLanguageApi(obj) {
|
||||
if(API_REPLACES && !obj.langApiRestored) {
|
||||
obj.langApiRestored = true;
|
||||
for(var key in API_REPLACES)
|
||||
obj[key] && (obj[API_REPLACES[key]] = obj[key]);
|
||||
(obj.contains || []).concat(obj.variants || []).forEach(restoreLanguageApi);
|
||||
}
|
||||
}
|
||||
|
||||
function compileLanguage(language) {
|
||||
|
||||
function reStr(re) {
|
||||
return (re && re.source) || re;
|
||||
}
|
||||
|
||||
function langRe(value, global) {
|
||||
return new RegExp(
|
||||
reStr(value),
|
||||
'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
|
||||
);
|
||||
}
|
||||
|
||||
// joinRe logically computes regexps.join(separator), but fixes the
|
||||
// backreferences so they continue to match.
|
||||
function joinRe(regexps, separator) {
|
||||
// backreferenceRe matches an open parenthesis or backreference. To avoid
|
||||
// an incorrect parse, it additionally matches the following:
|
||||
// - [...] elements, where the meaning of parentheses and escapes change
|
||||
// - other escape sequences, so we do not misparse escape sequences as
|
||||
// interesting elements
|
||||
// - non-matching or lookahead parentheses, which do not capture. These
|
||||
// follow the '(' with a '?'.
|
||||
var backreferenceRe = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
||||
var numCaptures = 0;
|
||||
var ret = '';
|
||||
for (var i = 0; i < regexps.length; i++) {
|
||||
var offset = numCaptures;
|
||||
var re = reStr(regexps[i]);
|
||||
if (i > 0) {
|
||||
ret += separator;
|
||||
}
|
||||
while (re.length > 0) {
|
||||
var match = backreferenceRe.exec(re);
|
||||
if (match == null) {
|
||||
ret += re;
|
||||
break;
|
||||
}
|
||||
ret += re.substring(0, match.index);
|
||||
re = re.substring(match.index + match[0].length);
|
||||
if (match[0][0] == '\\' && match[1]) {
|
||||
// Adjust the backreference.
|
||||
ret += '\\' + String(Number(match[1]) + offset);
|
||||
} else {
|
||||
ret += match[0];
|
||||
if (match[0] == '(') {
|
||||
numCaptures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function compileMode(mode, parent) {
|
||||
if (mode.compiled)
|
||||
return;
|
||||
mode.compiled = true;
|
||||
|
||||
mode.keywords = mode.keywords || mode.beginKeywords;
|
||||
if (mode.keywords) {
|
||||
var compiled_keywords = {};
|
||||
|
||||
var flatten = function(className, str) {
|
||||
if (language.case_insensitive) {
|
||||
str = str.toLowerCase();
|
||||
}
|
||||
str.split(' ').forEach(function(kw) {
|
||||
var pair = kw.split('|');
|
||||
compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1];
|
||||
});
|
||||
};
|
||||
|
||||
if (typeof mode.keywords === 'string') { // string
|
||||
flatten('keyword', mode.keywords);
|
||||
} else {
|
||||
objectKeys(mode.keywords).forEach(function (className) {
|
||||
flatten(className, mode.keywords[className]);
|
||||
});
|
||||
}
|
||||
mode.keywords = compiled_keywords;
|
||||
}
|
||||
mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);
|
||||
|
||||
if (parent) {
|
||||
if (mode.beginKeywords) {
|
||||
mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b';
|
||||
}
|
||||
if (!mode.begin)
|
||||
mode.begin = /\B|\b/;
|
||||
mode.beginRe = langRe(mode.begin);
|
||||
if (mode.endSameAsBegin)
|
||||
mode.end = mode.begin;
|
||||
if (!mode.end && !mode.endsWithParent)
|
||||
mode.end = /\B|\b/;
|
||||
if (mode.end)
|
||||
mode.endRe = langRe(mode.end);
|
||||
mode.terminator_end = reStr(mode.end) || '';
|
||||
if (mode.endsWithParent && parent.terminator_end)
|
||||
mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end;
|
||||
}
|
||||
if (mode.illegal)
|
||||
mode.illegalRe = langRe(mode.illegal);
|
||||
if (mode.relevance == null)
|
||||
mode.relevance = 1;
|
||||
if (!mode.contains) {
|
||||
mode.contains = [];
|
||||
}
|
||||
mode.contains = Array.prototype.concat.apply([], mode.contains.map(function(c) {
|
||||
return expand_mode(c === 'self' ? mode : c);
|
||||
}));
|
||||
mode.contains.forEach(function(c) {compileMode(c, mode);});
|
||||
|
||||
if (mode.starts) {
|
||||
compileMode(mode.starts, parent);
|
||||
}
|
||||
|
||||
var terminators =
|
||||
mode.contains.map(function(c) {
|
||||
return c.beginKeywords ? '\\.?(?:' + c.begin + ')\\.?' : c.begin;
|
||||
})
|
||||
.concat([mode.terminator_end, mode.illegal])
|
||||
.map(reStr)
|
||||
.filter(Boolean);
|
||||
mode.terminators = terminators.length ? langRe(joinRe(terminators, '|'), true) : {exec: function(/*s*/) {return null;}};
|
||||
}
|
||||
|
||||
compileMode(language);
|
||||
}
|
||||
|
||||
/*
|
||||
Core highlighting function. Accepts a language name, or an alias, and a
|
||||
string with the code to highlight. Returns an object with the following
|
||||
properties:
|
||||
|
||||
- relevance (int)
|
||||
- value (an HTML string with highlighting markup)
|
||||
|
||||
*/
|
||||
function highlight(name, value, ignore_illegals, continuation) {
|
||||
|
||||
function escapeRe(value) {
|
||||
return new RegExp(value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
|
||||
}
|
||||
|
||||
function subMode(lexeme, mode) {
|
||||
var i, length;
|
||||
|
||||
for (i = 0, length = mode.contains.length; i < length; i++) {
|
||||
if (testRe(mode.contains[i].beginRe, lexeme)) {
|
||||
if (mode.contains[i].endSameAsBegin) {
|
||||
mode.contains[i].endRe = escapeRe( mode.contains[i].beginRe.exec(lexeme)[0] );
|
||||
}
|
||||
return mode.contains[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function endOfMode(mode, lexeme) {
|
||||
if (testRe(mode.endRe, lexeme)) {
|
||||
while (mode.endsParent && mode.parent) {
|
||||
mode = mode.parent;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
if (mode.endsWithParent) {
|
||||
return endOfMode(mode.parent, lexeme);
|
||||
}
|
||||
}
|
||||
|
||||
function isIllegal(lexeme, mode) {
|
||||
return !ignore_illegals && testRe(mode.illegalRe, lexeme);
|
||||
}
|
||||
|
||||
function keywordMatch(mode, match) {
|
||||
var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0];
|
||||
return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str];
|
||||
}
|
||||
|
||||
function buildSpan(classname, insideSpan, leaveOpen, noPrefix) {
|
||||
var classPrefix = noPrefix ? '' : options.classPrefix,
|
||||
openSpan = '<span class="' + classPrefix,
|
||||
closeSpan = leaveOpen ? '' : spanEndTag;
|
||||
|
||||
openSpan += classname + '">';
|
||||
|
||||
return openSpan + insideSpan + closeSpan;
|
||||
}
|
||||
|
||||
function processKeywords() {
|
||||
var keyword_match, last_index, match, result;
|
||||
|
||||
if (!top.keywords)
|
||||
return escape(mode_buffer);
|
||||
|
||||
result = '';
|
||||
last_index = 0;
|
||||
top.lexemesRe.lastIndex = 0;
|
||||
match = top.lexemesRe.exec(mode_buffer);
|
||||
|
||||
while (match) {
|
||||
result += escape(mode_buffer.substring(last_index, match.index));
|
||||
keyword_match = keywordMatch(top, match);
|
||||
if (keyword_match) {
|
||||
relevance += keyword_match[1];
|
||||
result += buildSpan(keyword_match[0], escape(match[0]));
|
||||
} else {
|
||||
result += escape(match[0]);
|
||||
}
|
||||
last_index = top.lexemesRe.lastIndex;
|
||||
match = top.lexemesRe.exec(mode_buffer);
|
||||
}
|
||||
return result + escape(mode_buffer.substr(last_index));
|
||||
}
|
||||
|
||||
function processSubLanguage() {
|
||||
var explicit = typeof top.subLanguage === 'string';
|
||||
if (explicit && !languages[top.subLanguage]) {
|
||||
return escape(mode_buffer);
|
||||
}
|
||||
|
||||
var result = explicit ?
|
||||
highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) :
|
||||
highlightAuto(mode_buffer, top.subLanguage.length ? top.subLanguage : undefined);
|
||||
|
||||
// Counting embedded language score towards the host language may be disabled
|
||||
// with zeroing the containing mode relevance. Usecase in point is Markdown that
|
||||
// allows XML everywhere and makes every XML snippet to have a much larger Markdown
|
||||
// score.
|
||||
if (top.relevance > 0) {
|
||||
relevance += result.relevance;
|
||||
}
|
||||
if (explicit) {
|
||||
continuations[top.subLanguage] = result.top;
|
||||
}
|
||||
return buildSpan(result.language, result.value, false, true);
|
||||
}
|
||||
|
||||
function processBuffer() {
|
||||
result += (top.subLanguage != null ? processSubLanguage() : processKeywords());
|
||||
mode_buffer = '';
|
||||
}
|
||||
|
||||
function startNewMode(mode) {
|
||||
result += mode.className? buildSpan(mode.className, '', true): '';
|
||||
top = Object.create(mode, {parent: {value: top}});
|
||||
}
|
||||
|
||||
function processLexeme(buffer, lexeme) {
|
||||
|
||||
mode_buffer += buffer;
|
||||
|
||||
if (lexeme == null) {
|
||||
processBuffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var new_mode = subMode(lexeme, top);
|
||||
if (new_mode) {
|
||||
if (new_mode.skip) {
|
||||
mode_buffer += lexeme;
|
||||
} else {
|
||||
if (new_mode.excludeBegin) {
|
||||
mode_buffer += lexeme;
|
||||
}
|
||||
processBuffer();
|
||||
if (!new_mode.returnBegin && !new_mode.excludeBegin) {
|
||||
mode_buffer = lexeme;
|
||||
}
|
||||
}
|
||||
startNewMode(new_mode, lexeme);
|
||||
return new_mode.returnBegin ? 0 : lexeme.length;
|
||||
}
|
||||
|
||||
var end_mode = endOfMode(top, lexeme);
|
||||
if (end_mode) {
|
||||
var origin = top;
|
||||
if (origin.skip) {
|
||||
mode_buffer += lexeme;
|
||||
} else {
|
||||
if (!(origin.returnEnd || origin.excludeEnd)) {
|
||||
mode_buffer += lexeme;
|
||||
}
|
||||
processBuffer();
|
||||
if (origin.excludeEnd) {
|
||||
mode_buffer = lexeme;
|
||||
}
|
||||
}
|
||||
do {
|
||||
if (top.className) {
|
||||
result += spanEndTag;
|
||||
}
|
||||
if (!top.skip && !top.subLanguage) {
|
||||
relevance += top.relevance;
|
||||
}
|
||||
top = top.parent;
|
||||
} while (top !== end_mode.parent);
|
||||
if (end_mode.starts) {
|
||||
if (end_mode.endSameAsBegin) {
|
||||
end_mode.starts.endRe = end_mode.endRe;
|
||||
}
|
||||
startNewMode(end_mode.starts, '');
|
||||
}
|
||||
return origin.returnEnd ? 0 : lexeme.length;
|
||||
}
|
||||
|
||||
if (isIllegal(lexeme, top))
|
||||
throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '<unnamed>') + '"');
|
||||
|
||||
/*
|
||||
Parser should not reach this point as all types of lexemes should be caught
|
||||
earlier, but if it does due to some bug make sure it advances at least one
|
||||
character forward to prevent infinite looping.
|
||||
*/
|
||||
mode_buffer += lexeme;
|
||||
return lexeme.length || 1;
|
||||
}
|
||||
|
||||
var language = getLanguage(name);
|
||||
if (!language) {
|
||||
throw new Error('Unknown language: "' + name + '"');
|
||||
}
|
||||
|
||||
compileLanguage(language);
|
||||
var top = continuation || language;
|
||||
var continuations = {}; // keep continuations for sub-languages
|
||||
var result = '', current;
|
||||
for(current = top; current !== language; current = current.parent) {
|
||||
if (current.className) {
|
||||
result = buildSpan(current.className, '', true) + result;
|
||||
}
|
||||
}
|
||||
var mode_buffer = '';
|
||||
var relevance = 0;
|
||||
try {
|
||||
var match, count, index = 0;
|
||||
while (true) {
|
||||
top.terminators.lastIndex = index;
|
||||
match = top.terminators.exec(value);
|
||||
if (!match)
|
||||
break;
|
||||
count = processLexeme(value.substring(index, match.index), match[0]);
|
||||
index = match.index + count;
|
||||
}
|
||||
processLexeme(value.substr(index));
|
||||
for(current = top; current.parent; current = current.parent) { // close dangling modes
|
||||
if (current.className) {
|
||||
result += spanEndTag;
|
||||
}
|
||||
}
|
||||
return {
|
||||
relevance: relevance,
|
||||
value: result,
|
||||
language: name,
|
||||
top: top
|
||||
};
|
||||
} catch (e) {
|
||||
if (e.message && e.message.indexOf('Illegal') !== -1) {
|
||||
return {
|
||||
relevance: 0,
|
||||
value: escape(value)
|
||||
};
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Highlighting with language detection. Accepts a string with the code to
|
||||
highlight. Returns an object with the following properties:
|
||||
|
||||
- language (detected language)
|
||||
- relevance (int)
|
||||
- value (an HTML string with highlighting markup)
|
||||
- second_best (object with the same structure for second-best heuristically
|
||||
detected language, may be absent)
|
||||
|
||||
*/
|
||||
function highlightAuto(text, languageSubset) {
|
||||
languageSubset = languageSubset || options.languages || objectKeys(languages);
|
||||
var result = {
|
||||
relevance: 0,
|
||||
value: escape(text)
|
||||
};
|
||||
var second_best = result;
|
||||
languageSubset.filter(getLanguage).filter(autoDetection).forEach(function(name) {
|
||||
var current = highlight(name, text, false);
|
||||
current.language = name;
|
||||
if (current.relevance > second_best.relevance) {
|
||||
second_best = current;
|
||||
}
|
||||
if (current.relevance > result.relevance) {
|
||||
second_best = result;
|
||||
result = current;
|
||||
}
|
||||
});
|
||||
if (second_best.language) {
|
||||
result.second_best = second_best;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Post-processing of the highlighted markup:
|
||||
|
||||
- replace TABs with something more useful
|
||||
- replace real line-breaks with '<br>' for non-pre containers
|
||||
|
||||
*/
|
||||
function fixMarkup(value) {
|
||||
return !(options.tabReplace || options.useBR)
|
||||
? value
|
||||
: value.replace(fixMarkupRe, function(match, p1) {
|
||||
if (options.useBR && match === '\n') {
|
||||
return '<br>';
|
||||
} else if (options.tabReplace) {
|
||||
return p1.replace(/\t/g, options.tabReplace);
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
function buildClassName(prevClassName, currentLang, resultLang) {
|
||||
var language = currentLang ? aliases[currentLang] : resultLang,
|
||||
result = [prevClassName.trim()];
|
||||
|
||||
if (!prevClassName.match(/\bhljs\b/)) {
|
||||
result.push('hljs');
|
||||
}
|
||||
|
||||
if (prevClassName.indexOf(language) === -1) {
|
||||
result.push(language);
|
||||
}
|
||||
|
||||
return result.join(' ').trim();
|
||||
}
|
||||
|
||||
/*
|
||||
Applies highlighting to a DOM node containing code. Accepts a DOM node and
|
||||
two optional parameters for fixMarkup.
|
||||
*/
|
||||
function highlightBlock(block) {
|
||||
var node, originalStream, result, resultNode, text;
|
||||
var language = blockLanguage(block);
|
||||
|
||||
if (isNotHighlighted(language))
|
||||
return;
|
||||
|
||||
if (options.useBR) {
|
||||
node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(/<br[ \/]*>/g, '\n');
|
||||
} else {
|
||||
node = block;
|
||||
}
|
||||
text = node.textContent;
|
||||
result = language ? highlight(language, text, true) : highlightAuto(text);
|
||||
|
||||
originalStream = nodeStream(node);
|
||||
if (originalStream.length) {
|
||||
resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
resultNode.innerHTML = result.value;
|
||||
result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
|
||||
}
|
||||
result.value = fixMarkup(result.value);
|
||||
|
||||
block.innerHTML = result.value;
|
||||
block.className = buildClassName(block.className, language, result.language);
|
||||
block.result = {
|
||||
language: result.language,
|
||||
re: result.relevance
|
||||
};
|
||||
if (result.second_best) {
|
||||
block.second_best = {
|
||||
language: result.second_best.language,
|
||||
re: result.second_best.relevance
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Updates highlight.js global options with values passed in the form of an object.
|
||||
*/
|
||||
function configure(user_options) {
|
||||
options = inherit(options, user_options);
|
||||
}
|
||||
|
||||
/*
|
||||
Applies highlighting to all <pre><code>..</code></pre> blocks on a page.
|
||||
*/
|
||||
function initHighlighting() {
|
||||
if (initHighlighting.called)
|
||||
return;
|
||||
initHighlighting.called = true;
|
||||
|
||||
var blocks = document.querySelectorAll('pre code');
|
||||
ArrayProto.forEach.call(blocks, highlightBlock);
|
||||
}
|
||||
|
||||
/*
|
||||
Attaches highlighting to the page load event.
|
||||
*/
|
||||
function initHighlightingOnLoad() {
|
||||
addEventListener('DOMContentLoaded', initHighlighting, false);
|
||||
addEventListener('load', initHighlighting, false);
|
||||
}
|
||||
|
||||
function registerLanguage(name, language) {
|
||||
var lang = languages[name] = language(hljs);
|
||||
restoreLanguageApi(lang);
|
||||
if (lang.aliases) {
|
||||
lang.aliases.forEach(function(alias) {aliases[alias] = name;});
|
||||
}
|
||||
}
|
||||
|
||||
function listLanguages() {
|
||||
return objectKeys(languages);
|
||||
}
|
||||
|
||||
function getLanguage(name) {
|
||||
name = (name || '').toLowerCase();
|
||||
return languages[name] || languages[aliases[name]];
|
||||
}
|
||||
|
||||
function autoDetection(name) {
|
||||
var lang = getLanguage(name);
|
||||
return lang && !lang.disableAutodetect;
|
||||
}
|
||||
|
||||
/* Interface definition */
|
||||
|
||||
hljs.highlight = highlight;
|
||||
hljs.highlightAuto = highlightAuto;
|
||||
hljs.fixMarkup = fixMarkup;
|
||||
hljs.highlightBlock = highlightBlock;
|
||||
hljs.configure = configure;
|
||||
hljs.initHighlighting = initHighlighting;
|
||||
hljs.initHighlightingOnLoad = initHighlightingOnLoad;
|
||||
hljs.registerLanguage = registerLanguage;
|
||||
hljs.listLanguages = listLanguages;
|
||||
hljs.getLanguage = getLanguage;
|
||||
hljs.autoDetection = autoDetection;
|
||||
hljs.inherit = inherit;
|
||||
|
||||
// Common regexps
|
||||
hljs.IDENT_RE = '[a-zA-Z]\\w*';
|
||||
hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
|
||||
hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
|
||||
hljs.C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float
|
||||
hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
|
||||
hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
|
||||
|
||||
// Common modes
|
||||
hljs.BACKSLASH_ESCAPE = {
|
||||
begin: '\\\\[\\s\\S]', relevance: 0
|
||||
};
|
||||
hljs.APOS_STRING_MODE = {
|
||||
className: 'string',
|
||||
begin: '\'', end: '\'',
|
||||
illegal: '\\n',
|
||||
contains: [hljs.BACKSLASH_ESCAPE]
|
||||
};
|
||||
hljs.QUOTE_STRING_MODE = {
|
||||
className: 'string',
|
||||
begin: '"', end: '"',
|
||||
illegal: '\\n',
|
||||
contains: [hljs.BACKSLASH_ESCAPE]
|
||||
};
|
||||
hljs.PHRASAL_WORDS_MODE = {
|
||||
begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
|
||||
};
|
||||
hljs.COMMENT = function (begin, end, inherits) {
|
||||
var mode = hljs.inherit(
|
||||
{
|
||||
className: 'comment',
|
||||
begin: begin, end: end,
|
||||
contains: []
|
||||
},
|
||||
inherits || {}
|
||||
);
|
||||
mode.contains.push(hljs.PHRASAL_WORDS_MODE);
|
||||
mode.contains.push({
|
||||
className: 'doctag',
|
||||
begin: '(?:TODO|FIXME|NOTE|BUG|XXX):',
|
||||
relevance: 0
|
||||
});
|
||||
return mode;
|
||||
};
|
||||
hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$');
|
||||
hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/');
|
||||
hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$');
|
||||
hljs.NUMBER_MODE = {
|
||||
className: 'number',
|
||||
begin: hljs.NUMBER_RE,
|
||||
relevance: 0
|
||||
};
|
||||
hljs.C_NUMBER_MODE = {
|
||||
className: 'number',
|
||||
begin: hljs.C_NUMBER_RE,
|
||||
relevance: 0
|
||||
};
|
||||
hljs.BINARY_NUMBER_MODE = {
|
||||
className: 'number',
|
||||
begin: hljs.BINARY_NUMBER_RE,
|
||||
relevance: 0
|
||||
};
|
||||
hljs.CSS_NUMBER_MODE = {
|
||||
className: 'number',
|
||||
begin: hljs.NUMBER_RE + '(' +
|
||||
'%|em|ex|ch|rem' +
|
||||
'|vw|vh|vmin|vmax' +
|
||||
'|cm|mm|in|pt|pc|px' +
|
||||
'|deg|grad|rad|turn' +
|
||||
'|s|ms' +
|
||||
'|Hz|kHz' +
|
||||
'|dpi|dpcm|dppx' +
|
||||
')?',
|
||||
relevance: 0
|
||||
};
|
||||
hljs.REGEXP_MODE = {
|
||||
className: 'regexp',
|
||||
begin: /\//, end: /\/[gimuy]*/,
|
||||
illegal: /\n/,
|
||||
contains: [
|
||||
hljs.BACKSLASH_ESCAPE,
|
||||
{
|
||||
begin: /\[/, end: /\]/,
|
||||
relevance: 0,
|
||||
contains: [hljs.BACKSLASH_ESCAPE]
|
||||
}
|
||||
]
|
||||
};
|
||||
hljs.TITLE_MODE = {
|
||||
className: 'title',
|
||||
begin: hljs.IDENT_RE,
|
||||
relevance: 0
|
||||
};
|
||||
hljs.UNDERSCORE_TITLE_MODE = {
|
||||
className: 'title',
|
||||
begin: hljs.UNDERSCORE_IDENT_RE,
|
||||
relevance: 0
|
||||
};
|
||||
hljs.METHOD_GUARD = {
|
||||
// excludes method names from keyword processing
|
||||
begin: '\\.\\s*' + hljs.UNDERSCORE_IDENT_RE,
|
||||
relevance: 0
|
||||
};
|
||||
|
||||
return hljs;
|
||||
}));
|
||||
|
||||
/*!
|
||||
* VERSION: 2.1.2
|
||||
* DATE: 2019-03-01
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+689
-2
@@ -11972,7 +11972,7 @@
|
||||
class Timeline extends BitmapLabeledGraphics {
|
||||
|
||||
constructor(width, height, { ticks = null,
|
||||
baseLine = 0.5, showRange = true } = {}) {
|
||||
baseLine = 0.5, showRange = true, throwDamping = 0.95 } = {}) {
|
||||
super();
|
||||
this.wantedWidth = width;
|
||||
this.wantedHeight = height;
|
||||
@@ -12003,6 +12003,7 @@
|
||||
this.selection = null;
|
||||
this.autoScroll = false;
|
||||
this.direction = -1;
|
||||
this.throwDamping = throwDamping;
|
||||
this.timeticks = ticks || new TimeTicks(new DecadeTicks(),
|
||||
new YearTicks(),
|
||||
new MonthTicks(),
|
||||
@@ -12380,7 +12381,7 @@
|
||||
return
|
||||
}
|
||||
this.scroll += delta;
|
||||
delta *= 0.985;
|
||||
delta *= this.throwDamping;
|
||||
this.redraw();
|
||||
if (Math.abs(delta) > 1 && this.autoScroll) {
|
||||
setTimeout(() => this.keepInBounds(delta, anchor), 1000 / 100);
|
||||
@@ -12410,6 +12411,691 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pixi.js scrollbox: a masked content box that can scroll vertically or horizontally with scrollbars
|
||||
*/
|
||||
class Scrollbox extends PIXI.Container {
|
||||
/**
|
||||
* create a scrollbox
|
||||
* @param {object} options
|
||||
* @param {boolean} [options.dragScroll=true] user may drag the content area to scroll content
|
||||
* @param {string} [options.overflowX=auto] (none, scroll, hidden, auto) this changes whether the scrollbar is shown
|
||||
* @param {string} [options.overflowY=auto] (none, scroll, hidden, auto) this changes whether the scrollbar is shown
|
||||
* @param {string} [options.overflow] (none, scroll, hidden, auto) sets overflowX and overflowY to this value
|
||||
* @param {number} [options.boxWidth=100] width of scrollbox including scrollbar (in pixels)
|
||||
* @param {number} [options.boxHeight=100] height of scrollbox including scrollbar (in pixels)
|
||||
* @param {number} [options.scrollbarSize=10] size of scrollbar (in pixels)
|
||||
* @param {number} [options.scrollbarOffsetHorizontal=0] offset of horizontal scrollbar (in pixels)
|
||||
* @param {number} [options.scrollbarOffsetVertical=0] offset of vertical scrollbar (in pixels)
|
||||
* @param {boolean} [options.stopPropagation=true] call stopPropagation on any events that impact scrollbox
|
||||
* @param {number} [options.scrollbarBackground=0xdddddd] background color of scrollbar
|
||||
* @param {number} [options.scrollbarBackgroundAlpha=1] alpha of background of scrollbar
|
||||
* @param {number} [options.scrollbarForeground=0x888888] foreground color of scrollbar
|
||||
* @param {number} [options.scrollbarForegroundAlpha=1] alpha of foreground of scrollbar
|
||||
* @param {string} [options.underflow=top-left] what to do when content underflows the scrollbox size: none: do nothing; (left/right/center AND top/bottom/center); OR center (e.g., 'top-left', 'center', 'none', 'bottomright')
|
||||
* @param {(boolean|number)} [options.fade] fade the scrollbar when not in use (true = 1000ms)
|
||||
* @param {number} [options.fadeWait=3000] time to wait before fading the scrollbar if options.fade is set
|
||||
* @param {(string|function)} [options.fadeEase=easeInOutSine] easing function to use for fading
|
||||
*/
|
||||
constructor(options)
|
||||
{
|
||||
super();
|
||||
this.options = Object.assign({}, {
|
||||
"boxWidth": 100,
|
||||
"boxHeight": 100,
|
||||
"scrollbarSize": 10,
|
||||
"scrollbarBackground": 14540253,
|
||||
"scrollbarBackgroundAlpha": 1,
|
||||
"scrollbarForeground": 8947848,
|
||||
"scrollbarForegroundAlpha": 1,
|
||||
"dragScroll": true,
|
||||
"stopPropagation": true,
|
||||
"scrollbarOffsetHorizontal": 0,
|
||||
"scrollbarOffsetVertical": 0,
|
||||
"underflow": "top-left",
|
||||
"fadeScrollbar": false,
|
||||
"fadeWait": 3000,
|
||||
"fadeEase": "easeInOutSine"
|
||||
}, options);
|
||||
this.ease = new PIXI.extras.Ease.list();
|
||||
|
||||
/**
|
||||
* content in placed in here
|
||||
* you can use any function from pixi-viewport on content to manually move the content (see https://davidfig.github.io/pixi-viewport/jsdoc/)
|
||||
* @type {PIXI.extras.Viewport}
|
||||
*/
|
||||
this.content = this.addChild(new PIXI.extras.Viewport({ passiveWheel: this.options.stopPropagation, stopPropagation: this.options.stopPropagation, screenWidth: this.options.boxWidth, screenHeight: this.options.boxHeight }));
|
||||
this.content
|
||||
.decelerate()
|
||||
.on('moved', () => this._drawScrollbars());
|
||||
|
||||
/**
|
||||
* graphics element for drawing the scrollbars
|
||||
* @type {PIXI.Graphics}
|
||||
*/
|
||||
this.scrollbar = this.addChild(new PIXI.Graphics());
|
||||
this.scrollbar.interactive = true;
|
||||
this.scrollbar.on('pointerdown', this.scrollbarDown, this);
|
||||
this.interactive = true;
|
||||
this.on('pointermove', this.scrollbarMove, this);
|
||||
this.on('pointerup', this.scrollbarUp, this);
|
||||
this.on('pointercancel', this.scrollbarUp, this);
|
||||
this.on('pointerupoutside', this.scrollbarUp, this);
|
||||
this._maskContent = this.addChild(new PIXI.Graphics());
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* offset of horizontal scrollbar (in pixels)
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollbarOffsetHorizontal()
|
||||
{
|
||||
return this.options.scrollbarOffsetHorizontal
|
||||
}
|
||||
set scrollbarOffsetHorizontal(value)
|
||||
{
|
||||
this.options.scrollbarOffsetHorizontal = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* offset of vertical scrollbar (in pixels)
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollbarOffsetVertical()
|
||||
{
|
||||
return this.options.scrollbarOffsetVertical
|
||||
}
|
||||
set scrollbarOffsetVertical(value)
|
||||
{
|
||||
this.options.scrollbarOffsetVertical = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* disable the scrollbox (if set to true this will also remove the mask)
|
||||
* @type {boolean}
|
||||
*/
|
||||
get disable()
|
||||
{
|
||||
return this._disabled
|
||||
}
|
||||
set disable(value)
|
||||
{
|
||||
if (this._disabled !== value)
|
||||
{
|
||||
this._disabled = value;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call stopPropagation on any events that impact scrollbox
|
||||
* @type {boolean}
|
||||
*/
|
||||
get stopPropagation()
|
||||
{
|
||||
return this.options.stopPropagation
|
||||
}
|
||||
set stopPropagation(value)
|
||||
{
|
||||
this.options.stopPropagation = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* user may drag the content area to scroll content
|
||||
* @type {boolean}
|
||||
*/
|
||||
get dragScroll()
|
||||
{
|
||||
return this.options.dragScroll
|
||||
}
|
||||
set dragScroll(value)
|
||||
{
|
||||
this.options.dragScroll = value;
|
||||
if (value)
|
||||
{
|
||||
this.content.drag();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.content.removePlugin('drag');
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* width of scrollbox including the scrollbar (if visible)- this changes the size and not the scale of the box
|
||||
* @type {number}
|
||||
*/
|
||||
get boxWidth()
|
||||
{
|
||||
return this.options.boxWidth
|
||||
}
|
||||
set boxWidth(value)
|
||||
{
|
||||
this.options.boxWidth = value;
|
||||
this.content.screenWidth = value;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets overflowX and overflowY to (scroll, hidden, auto) changing whether the scrollbar is shown
|
||||
* scroll = always show scrollbar
|
||||
* hidden = hide overflow and do not show scrollbar
|
||||
* auto = if content is larger than box size, then show scrollbar
|
||||
* @type {string}
|
||||
*/
|
||||
get overflow()
|
||||
{
|
||||
return this.options.overflow
|
||||
}
|
||||
set overflow(value)
|
||||
{
|
||||
this.options.overflow = value;
|
||||
this.options.overflowX = value;
|
||||
this.options.overflowY = value;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets overflowX to (scroll, hidden, auto) changing whether the scrollbar is shown
|
||||
* scroll = always show scrollbar
|
||||
* hidden = hide overflow and do not show scrollbar
|
||||
* auto = if content is larger than box size, then show scrollbar
|
||||
* @type {string}
|
||||
*/
|
||||
get overflowX()
|
||||
{
|
||||
return this.options.overflowX
|
||||
}
|
||||
set overflowX(value)
|
||||
{
|
||||
this.options.overflowX = value;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets overflowY to (scroll, hidden, auto) changing whether the scrollbar is shown
|
||||
* scroll = always show scrollbar
|
||||
* hidden = hide overflow and do not show scrollbar
|
||||
* auto = if content is larger than box size, then show scrollbar
|
||||
* @type {string}
|
||||
*/
|
||||
get overflowY()
|
||||
{
|
||||
return this.options.overflowY
|
||||
}
|
||||
set overflowY(value)
|
||||
{
|
||||
this.options.overflowY = value;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* height of scrollbox including the scrollbar (if visible) - this changes the size and not the scale of the box
|
||||
* @type {number}
|
||||
*/
|
||||
get boxHeight()
|
||||
{
|
||||
return this.options.boxHeight
|
||||
}
|
||||
set boxHeight(value)
|
||||
{
|
||||
this.options.boxHeight = value;
|
||||
this.content.screenHeight = value;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* scrollbar size in pixels
|
||||
* @type {number}
|
||||
*/
|
||||
get scrollbarSize()
|
||||
{
|
||||
return this.options.scrollbarSize
|
||||
}
|
||||
set scrollbarSize(value)
|
||||
{
|
||||
this.options.scrollbarSize = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* width of scrollbox less the scrollbar (if visible)
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
get contentWidth()
|
||||
{
|
||||
return this.options.boxWidth - (this.isScrollbarVertical ? this.options.scrollbarSize : 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* height of scrollbox less the scrollbar (if visible)
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
get contentHeight()
|
||||
{
|
||||
return this.options.boxHeight - (this.isScrollbarHorizontal ? this.options.scrollbarSize : 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* is the vertical scrollbar visible
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isScrollbarVertical()
|
||||
{
|
||||
return this._isScrollbarVertical
|
||||
}
|
||||
|
||||
/**
|
||||
* is the horizontal scrollbar visible
|
||||
* @type {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isScrollbarHorizontal()
|
||||
{
|
||||
return this._isScrollbarHorizontal
|
||||
}
|
||||
|
||||
/**
|
||||
* top coordinate of scrollbar
|
||||
*/
|
||||
get scrollTop()
|
||||
{
|
||||
return this.content.top
|
||||
}
|
||||
|
||||
/**
|
||||
* left coordinate of scrollbar
|
||||
*/
|
||||
get scrollLeft()
|
||||
{
|
||||
return this.content.left
|
||||
}
|
||||
|
||||
/**
|
||||
* width of content area
|
||||
* if not set then it uses content.width to calculate width
|
||||
*/
|
||||
get scrollWidth()
|
||||
{
|
||||
return this._scrollWidth || this.content.width
|
||||
}
|
||||
set scrollWidth(value)
|
||||
{
|
||||
this._scrollWidth = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* height of content area
|
||||
* if not set then it uses content.height to calculate height
|
||||
*/
|
||||
get scrollHeight()
|
||||
{
|
||||
return this._scrollHeight || this.content.height
|
||||
}
|
||||
set scrollHeight(value)
|
||||
{
|
||||
this._scrollHeight = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* draws scrollbars
|
||||
* @private
|
||||
*/
|
||||
_drawScrollbars()
|
||||
{
|
||||
this._isScrollbarHorizontal = this.overflowX === 'scroll' ? true : ['hidden', 'none'].indexOf(this.overflowX) !== -1 ? false : this.scrollWidth > this.options.boxWidth;
|
||||
this._isScrollbarVertical = this.overflowY === 'scroll' ? true : ['hidden', 'none'].indexOf(this.overflowY) !== -1 ? false : this.scrollHeight > this.options.boxHeight;
|
||||
this.scrollbar.clear();
|
||||
let options = {};
|
||||
options.left = 0;
|
||||
options.right = this.scrollWidth + (this._isScrollbarVertical ? this.options.scrollbarSize : 0);
|
||||
options.top = 0;
|
||||
options.bottom = this.scrollHeight + (this.isScrollbarHorizontal ? this.options.scrollbarSize : 0);
|
||||
const width = this.scrollWidth + (this.isScrollbarVertical ? this.options.scrollbarSize : 0);
|
||||
const height = this.scrollHeight + (this.isScrollbarHorizontal ? this.options.scrollbarSize : 0);
|
||||
this.scrollbarTop = (this.content.top / height) * this.boxHeight;
|
||||
this.scrollbarTop = this.scrollbarTop < 0 ? 0 : this.scrollbarTop;
|
||||
this.scrollbarHeight = (this.boxHeight / height) * this.boxHeight;
|
||||
this.scrollbarHeight = this.scrollbarTop + this.scrollbarHeight > this.boxHeight ? this.boxHeight - this.scrollbarTop : this.scrollbarHeight;
|
||||
this.scrollbarLeft = (this.content.left / width) * this.boxWidth;
|
||||
this.scrollbarLeft = this.scrollbarLeft < 0 ? 0 : this.scrollbarLeft;
|
||||
this.scrollbarWidth = (this.boxWidth / width) * this.boxWidth;
|
||||
this.scrollbarWidth = this.scrollbarWidth + this.scrollbarLeft > this.boxWidth ? this.boxWidth - this.scrollbarLeft : this.scrollbarWidth;
|
||||
if (this.isScrollbarVertical)
|
||||
{
|
||||
this.scrollbar
|
||||
.beginFill(this.options.scrollbarBackground, this.options.scrollbarBackgroundAlpha)
|
||||
.drawRect(this.boxWidth - this.scrollbarSize + this.options.scrollbarOffsetVertical, 0, this.scrollbarSize, this.boxHeight)
|
||||
.endFill();
|
||||
}
|
||||
if (this.isScrollbarHorizontal)
|
||||
{
|
||||
this.scrollbar
|
||||
.beginFill(this.options.scrollbarBackground, this.options.scrollbarBackgroundAlpha)
|
||||
.drawRect(0, this.boxHeight - this.scrollbarSize + this.options.scrollbarOffsetHorizontal, this.boxWidth, this.scrollbarSize)
|
||||
.endFill();
|
||||
}
|
||||
if (this.isScrollbarVertical)
|
||||
{
|
||||
this.scrollbar
|
||||
.beginFill(this.options.scrollbarForeground, this.options.scrollbarForegroundAlpha)
|
||||
.drawRect(this.boxWidth - this.scrollbarSize + this.options.scrollbarOffsetVertical, this.scrollbarTop, this.scrollbarSize, this.scrollbarHeight)
|
||||
.endFill();
|
||||
}
|
||||
if (this.isScrollbarHorizontal)
|
||||
{
|
||||
this.scrollbar
|
||||
.beginFill(this.options.scrollbarForeground, this.options.scrollbarForegroundAlpha)
|
||||
.drawRect(this.scrollbarLeft, this.boxHeight - this.scrollbarSize + this.options.scrollbarOffsetHorizontal, this.scrollbarWidth, this.scrollbarSize)
|
||||
.endFill();
|
||||
}
|
||||
// this.content.forceHitArea = new PIXI.Rectangle(0, 0 , this.boxWidth, this.boxHeight)
|
||||
this.activateFade();
|
||||
}
|
||||
|
||||
/**
|
||||
* draws mask layer
|
||||
* @private
|
||||
*/
|
||||
_drawMask()
|
||||
{
|
||||
this._maskContent
|
||||
.beginFill(0)
|
||||
.drawRect(0, 0, this.boxWidth, this.boxHeight)
|
||||
.endFill();
|
||||
this.content.mask = this._maskContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* call when scrollbox content changes
|
||||
*/
|
||||
update()
|
||||
{
|
||||
this.content.mask = null;
|
||||
this._maskContent.clear();
|
||||
if (!this._disabled)
|
||||
{
|
||||
this._drawScrollbars();
|
||||
this._drawMask();
|
||||
if (this.options.dragScroll)
|
||||
{
|
||||
const direction = this.isScrollbarHorizontal && this.isScrollbarVertical ? 'all' : this.isScrollbarHorizontal ? 'x' : 'y';
|
||||
if (direction !== null)
|
||||
{
|
||||
this.content
|
||||
.drag({ clampWheel: true, direction })
|
||||
.clamp({ direction, underflow: this.options.underflow });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show the scrollbar and restart the timer for fade if options.fade is set
|
||||
*/
|
||||
activateFade()
|
||||
{
|
||||
if (this.options.fade)
|
||||
{
|
||||
if (this.fade)
|
||||
{
|
||||
this.ease.remove(this.fade);
|
||||
}
|
||||
this.scrollbar.alpha = 1;
|
||||
const time = this.options.fade === true ? 1000 : this.options.fade;
|
||||
this.fade = this.ease.to(this.scrollbar, { alpha: 0 }, time, { wait: this.options.fadeWait, ease: this.options.fadeEase });
|
||||
this.fade.on('each', () => this.content.dirty = true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle pointer down on scrollbar
|
||||
* @param {PIXI.interaction.InteractionEvent} e
|
||||
* @private
|
||||
*/
|
||||
scrollbarDown(e)
|
||||
{
|
||||
const local = this.toLocal(e.data.global);
|
||||
if (this.isScrollbarHorizontal)
|
||||
{
|
||||
if (local.y > this.boxHeight - this.scrollbarSize)
|
||||
{
|
||||
if (local.x >= this.scrollbarLeft && local.x <= this.scrollbarLeft + this.scrollbarWidth)
|
||||
{
|
||||
this.pointerDown = { type: 'horizontal', last: local };
|
||||
}
|
||||
else
|
||||
{
|
||||
if (local.x > this.scrollbarLeft)
|
||||
{
|
||||
this.content.left += this.content.worldScreenWidth;
|
||||
this.update();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.content.left -= this.content.worldScreenWidth;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
if (this.options.stopPropagation)
|
||||
{
|
||||
e.stopPropagation();
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (this.isScrollbarVertical)
|
||||
{
|
||||
if (local.x > this.boxWidth - this.scrollbarSize)
|
||||
{
|
||||
if (local.y >= this.scrollbarTop && local.y <= this.scrollbarTop + this.scrollbarWidth)
|
||||
{
|
||||
this.pointerDown = { type: 'vertical', last: local };
|
||||
}
|
||||
else
|
||||
{
|
||||
if (local.y > this.scrollbarTop)
|
||||
{
|
||||
this.content.top += this.content.worldScreenHeight;
|
||||
this.update();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.content.top -= this.content.worldScreenHeight;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
if (this.options.stopPropagation)
|
||||
{
|
||||
e.stopPropagation();
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle pointer move on scrollbar
|
||||
* @param {PIXI.interaction.InteractionEvent} e
|
||||
* @private
|
||||
*/
|
||||
scrollbarMove(e)
|
||||
{
|
||||
if (this.pointerDown)
|
||||
{
|
||||
if (this.pointerDown.type === 'horizontal')
|
||||
{
|
||||
const local = this.toLocal(e.data.global);
|
||||
this.content.left += local.x - this.pointerDown.last.x;
|
||||
this.pointerDown.last = local;
|
||||
this.update();
|
||||
}
|
||||
else if (this.pointerDown.type === 'vertical')
|
||||
{
|
||||
const local = this.toLocal(e.data.global);
|
||||
this.content.top += local.y - this.pointerDown.last.y;
|
||||
this.pointerDown.last = local;
|
||||
this.update();
|
||||
}
|
||||
if (this.options.stopPropagation)
|
||||
{
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle pointer down on scrollbar
|
||||
* @private
|
||||
*/
|
||||
scrollbarUp()
|
||||
{
|
||||
this.pointerDown = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* resize the mask for the container
|
||||
* @param {object} options
|
||||
* @param {number} [options.boxWidth] width of scrollbox including scrollbar (in pixels)
|
||||
* @param {number} [options.boxHeight] height of scrollbox including scrollbar (in pixels)
|
||||
* @param {number} [options.scrollWidth] set the width of the inside of the scrollbox (leave null to use content.width)
|
||||
* @param {number} [options.scrollHeight] set the height of the inside of the scrollbox (leave null to use content.height)
|
||||
*/
|
||||
resize(options)
|
||||
{
|
||||
this.options.boxWidth = typeof options.boxWidth !== 'undefined' ? options.boxWidth : this.options.boxWidth;
|
||||
this.options.boxHeight = typeof options.boxHeight !== 'undefined' ? options.boxHeight : this.options.boxHeight;
|
||||
if (options.scrollWidth)
|
||||
{
|
||||
this.scrollWidth = options.scrollWidth;
|
||||
}
|
||||
if (options.scrollHeight)
|
||||
{
|
||||
this.scrollHeight = options.scrollHeight;
|
||||
}
|
||||
this.content.resize(this.options.boxWidth, this.options.boxHeight, this.scrollWidth, this.scrollHeight);
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* ensure that the bounding box is visible
|
||||
* @param {number} x - relative to content's coordinate system
|
||||
* @param {number} y
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
*/
|
||||
ensureVisible(x, y, width, height)
|
||||
{
|
||||
this.content.ensureVisible(x, y, width, height);
|
||||
this._drawScrollbars();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the switch action.
|
||||
*
|
||||
* @callback actionCallback
|
||||
* @param {object} event - The event object.
|
||||
* @param {Switch} switch - A reference to the switch (also this refers to the switch).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback for the switch action.
|
||||
*
|
||||
* @callback actionActiveCallback
|
||||
* @param {object} event - The event object.
|
||||
* @param {Switch} switch - A reference to the switch (also this refers to the switch).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback for the switch beforeAction.
|
||||
*
|
||||
* @callback beforeActionCallback
|
||||
* @param {object} event - The event object.
|
||||
* @param {Switch} switch - A reference to the switch (also this refers to the switch).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback for the switch afterAction.
|
||||
*
|
||||
* @callback afterActionCallback
|
||||
* @param {object} event - The event object.
|
||||
* @param {Switch} switch - A reference to the switch (also this refers to the switch).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents a PixiJS Switch.
|
||||
*
|
||||
* @example
|
||||
* // Create the app
|
||||
* const app = new PIXIApp({
|
||||
* view: canvas,
|
||||
* width: 900,
|
||||
* height: 250
|
||||
* }).setup().run()
|
||||
*
|
||||
* // Create the switch
|
||||
* const switch1 = new Switch({
|
||||
* x: 10,
|
||||
* y: 20
|
||||
* })
|
||||
*
|
||||
* // Add the switch to a DisplayObject
|
||||
* app.scene.addChild(switch1)
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.extras.Scrollbox
|
||||
* @see {@link https://davidfig.github.io/pixi-scrollbox/jsdoc/Scrollbox.html|Scrollbox}
|
||||
* @see {@link https://davidfig.github.io/pixi-viewport/jsdoc/Viewport.html|Viewport}
|
||||
*/
|
||||
class Scrollview extends Scrollbox {
|
||||
|
||||
/**
|
||||
* Creates an instance of a Switch.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
constructor(opts = {}) {
|
||||
|
||||
super(opts);
|
||||
|
||||
this.opts = opts;
|
||||
|
||||
// setup
|
||||
//-----------------
|
||||
this.setup();
|
||||
|
||||
// layout
|
||||
//-----------------
|
||||
this.layout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates children and instantiates everything.
|
||||
*
|
||||
* @private
|
||||
* @return {Scrollview} A reference to the Scrollview for chaining.
|
||||
*/
|
||||
setup() {
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called to refresh the layout of the Scrollview. Can be used after resizing.
|
||||
*
|
||||
* @return {Scrollview} A reference to the Scrollview for chaining.
|
||||
*/
|
||||
layout() {
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the slider action onStart.
|
||||
*
|
||||
@@ -14055,6 +14741,7 @@
|
||||
window.Theme = Theme;
|
||||
window.Button = Button;
|
||||
window.ButtonGroup = ButtonGroup;
|
||||
window.Scrollview = Scrollview;
|
||||
window.Slider = Slider;
|
||||
window.Switch = Switch;
|
||||
window.Popup = Popup;
|
||||
|
||||
Reference in New Issue
Block a user