Fixed hyphenate bug
This commit is contained in:
parent
3856e59093
commit
68e46e81c1
12191
dist/iwmlib.3rdparty.js
vendored
12191
dist/iwmlib.3rdparty.js
vendored
File diff suppressed because it is too large
Load Diff
16
dist/iwmlib.3rdparty.min.js
vendored
16
dist/iwmlib.3rdparty.min.js
vendored
File diff suppressed because one or more lines are too long
150
lib/3rdparty/jquery.hypher.js
vendored
150
lib/3rdparty/jquery.hypher.js
vendored
@ -1,58 +1,60 @@
|
|||||||
(function () {
|
;(function () {
|
||||||
|
var module = {
|
||||||
var module = {
|
exports: null,
|
||||||
exports: null
|
}
|
||||||
};
|
/**
|
||||||
/**
|
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {!{patterns: !Object, leftmin: !number, rightmin: !number}} language The language pattern file. Compatible with Hyphenator.js.
|
* @param {!{patterns: !Object, leftmin: !number, rightmin: !number}} language The language pattern file. Compatible with Hyphenator.js.
|
||||||
*/
|
*/
|
||||||
function Hypher(language) {
|
function Hypher(language) {
|
||||||
var exceptions = [],
|
var exceptions = [],
|
||||||
i = 0;
|
i = 0
|
||||||
/**
|
/**
|
||||||
* @type {!Hypher.TrieNode}
|
* @type {!Hypher.TrieNode}
|
||||||
*/
|
*/
|
||||||
this.trie = this.createTrie(language['patterns']);
|
this.trie = this.createTrie(language['patterns'])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {!number}
|
* @type {!number}
|
||||||
* @const
|
* @const
|
||||||
*/
|
*/
|
||||||
this.leftMin = language['leftmin'];
|
this.leftMin = language['leftmin']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {!number}
|
* @type {!number}
|
||||||
* @const
|
* @const
|
||||||
*/
|
*/
|
||||||
this.rightMin = language['rightmin'];
|
this.rightMin = language['rightmin']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {!Object.<string, !Array.<string>>}
|
* @type {!Object.<string, !Array.<string>>}
|
||||||
*/
|
*/
|
||||||
this.exceptions = {};
|
this.exceptions = {}
|
||||||
|
|
||||||
if (language['exceptions']) {
|
if (language['exceptions']) {
|
||||||
exceptions = language['exceptions'].split(/,\s?/g);
|
exceptions = language['exceptions'].split(/,\s?/g)
|
||||||
|
|
||||||
for (; i < exceptions.length; i += 1) {
|
for (; i < exceptions.length; i += 1) {
|
||||||
this.exceptions[exceptions[i].replace(/\u2027/g, '').toLowerCase()] = new RegExp('(' + exceptions[i].split('\u2027').join(')(') + ')', 'i');
|
this.exceptions[exceptions[i].replace(/\u2027/g, '').toLowerCase()] = new RegExp(
|
||||||
|
'(' + exceptions[i].split('\u2027').join(')(') + ')',
|
||||||
|
'i'
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{_points: !Array.<number>}}
|
* @typedef {{_points: !Array.<number>}}
|
||||||
*/
|
*/
|
||||||
Hypher.TrieNode;
|
Hypher.TrieNode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a trie from a language pattern.
|
* Creates a trie from a language pattern.
|
||||||
* @private
|
* @private
|
||||||
* @param {!Object} patternObject An object with language patterns.
|
* @param {!Object} patternObject An object with language patterns.
|
||||||
* @return {!Hypher.TrieNode} An object trie.
|
* @return {!Hypher.TrieNode} An object trie.
|
||||||
*/
|
*/
|
||||||
Hypher.prototype.createTrie = function (patternObject) {
|
Hypher.prototype.createTrie = function (patternObject) {
|
||||||
var size = 0,
|
var size = 0,
|
||||||
i = 0,
|
i = 0,
|
||||||
c = 0,
|
c = 0,
|
||||||
@ -62,76 +64,78 @@ Hypher.prototype.createTrie = function (patternObject) {
|
|||||||
codePoint = null,
|
codePoint = null,
|
||||||
t = null,
|
t = null,
|
||||||
tree = {
|
tree = {
|
||||||
_points: []
|
_points: [],
|
||||||
},
|
},
|
||||||
patterns;
|
patterns
|
||||||
|
|
||||||
for (size in patternObject) {
|
for (size in patternObject) {
|
||||||
if (patternObject.hasOwnProperty(size)) {
|
if (patternObject.hasOwnProperty(size)) {
|
||||||
patterns = patternObject[size].match(new RegExp('.{1,' + (+size) + '}', 'g'));
|
patterns = patternObject[size].match(new RegExp('.{1,' + +size + '}', 'g'))
|
||||||
|
|
||||||
for (i = 0; i < patterns.length; i += 1) {
|
for (i = 0; i < patterns.length; i += 1) {
|
||||||
chars = patterns[i].replace(/[0-9]/g, '').split('');
|
chars = patterns[i].replace(/[0-9]/g, '').split('')
|
||||||
points = patterns[i].split(/\D/);
|
points = patterns[i].split(/\D/)
|
||||||
t = tree;
|
t = tree
|
||||||
|
|
||||||
for (c = 0; c < chars.length; c += 1) {
|
for (c = 0; c < chars.length; c += 1) {
|
||||||
codePoint = chars[c].charCodeAt(0);
|
codePoint = chars[c].charCodeAt(0)
|
||||||
|
|
||||||
if (!t[codePoint]) {
|
if (!t[codePoint]) {
|
||||||
t[codePoint] = {};
|
t[codePoint] = {}
|
||||||
}
|
}
|
||||||
t = t[codePoint];
|
t = t[codePoint]
|
||||||
}
|
}
|
||||||
|
|
||||||
t._points = [];
|
t._points = []
|
||||||
|
|
||||||
for (p = 0; p < points.length; p += 1) {
|
for (p = 0; p < points.length; p += 1) {
|
||||||
t._points[p] = points[p] || 0;
|
t._points[p] = points[p] || 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tree;
|
return tree
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hyphenates a text.
|
* Hyphenates a text.
|
||||||
*
|
*
|
||||||
* @param {!string} str The text to hyphenate.
|
* @param {!string} str The text to hyphenate.
|
||||||
* @return {!string} The same text with soft hyphens inserted in the right positions.
|
* @return {!string} The same text with soft hyphens inserted in the right positions.
|
||||||
*/
|
*/
|
||||||
Hypher.prototype.hyphenateText = function (str, minLength) {
|
Hypher.prototype.hyphenateText = function (str, minLength) {
|
||||||
minLength = minLength || 4;
|
minLength = minLength || 4
|
||||||
|
|
||||||
// Regexp("\b", "g") splits on word boundaries,
|
// Regexp("\b", "g") splits on word boundaries,
|
||||||
// compound separators and ZWNJ so we don't need
|
// compound separators and ZWNJ so we don't need
|
||||||
// any special cases for those characters. Unfortunately
|
// any special cases for those characters. Unfortunately
|
||||||
// it does not support unicode word boundaries, so
|
// it does not support unicode word boundaries, so
|
||||||
// we implement it manually.
|
// we implement it manually.
|
||||||
var words = str.split(/([a-zA-Z0-9_\u0027\u00DF-\u00EA\u00EC-\u00EF\u00F1-\u00F6\u00F8-\u00FD\u0101\u0103\u0105\u0107\u0109\u010D\u010F\u0111\u0113\u0117\u0119\u011B\u011D\u011F\u0123\u0125\u012B\u012F\u0131\u0135\u0137\u013C\u013E\u0142\u0144\u0146\u0148\u0151\u0153\u0155\u0159\u015B\u015D\u015F\u0161\u0165\u016B\u016D\u016F\u0171\u0173\u017A\u017C\u017E\u017F\u0219\u021B\u02BC\u0390\u03AC-\u03CE\u03F2\u0401\u0410-\u044F\u0451\u0454\u0456\u0457\u045E\u0491\u0531-\u0556\u0561-\u0587\u0902\u0903\u0905-\u090B\u090E-\u0910\u0912\u0914-\u0928\u092A-\u0939\u093E-\u0943\u0946-\u0948\u094A-\u094D\u0982\u0983\u0985-\u098B\u098F\u0990\u0994-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BE-\u09C3\u09C7\u09C8\u09CB-\u09CD\u09D7\u0A02\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A14-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A82\u0A83\u0A85-\u0A8B\u0A8F\u0A90\u0A94-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABE-\u0AC3\u0AC7\u0AC8\u0ACB-\u0ACD\u0B02\u0B03\u0B05-\u0B0B\u0B0F\u0B10\u0B14-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B57\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C02\u0C03\u0C05-\u0C0B\u0C0E-\u0C10\u0C12\u0C14-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C43\u0C46-\u0C48\u0C4A-\u0C4D\u0C82\u0C83\u0C85-\u0C8B\u0C8E-\u0C90\u0C92\u0C94-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBE-\u0CC3\u0CC6-\u0CC8\u0CCA-\u0CCD\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60\u0D61\u0D7A-\u0D7F\u1F00-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB2-\u1FB4\u1FB6\u1FB7\u1FBD\u1FBF\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD2\u1FD3\u1FD6\u1FD7\u1FE2-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u200D\u2019]+)/g);
|
var words = str.split(
|
||||||
|
/([a-zA-Z0-9_\u0027\u00DF-\u00EA\u00EC-\u00EF\u00F1-\u00F6\u00F8-\u00FD\u0101\u0103\u0105\u0107\u0109\u010D\u010F\u0111\u0113\u0117\u0119\u011B\u011D\u011F\u0123\u0125\u012B\u012F\u0131\u0135\u0137\u013C\u013E\u0142\u0144\u0146\u0148\u0151\u0153\u0155\u0159\u015B\u015D\u015F\u0161\u0165\u016B\u016D\u016F\u0171\u0173\u017A\u017C\u017E\u017F\u0219\u021B\u02BC\u0390\u03AC-\u03CE\u03F2\u0401\u0410-\u044F\u0451\u0454\u0456\u0457\u045E\u0491\u0531-\u0556\u0561-\u0587\u0902\u0903\u0905-\u090B\u090E-\u0910\u0912\u0914-\u0928\u092A-\u0939\u093E-\u0943\u0946-\u0948\u094A-\u094D\u0982\u0983\u0985-\u098B\u098F\u0990\u0994-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BE-\u09C3\u09C7\u09C8\u09CB-\u09CD\u09D7\u0A02\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A14-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A82\u0A83\u0A85-\u0A8B\u0A8F\u0A90\u0A94-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABE-\u0AC3\u0AC7\u0AC8\u0ACB-\u0ACD\u0B02\u0B03\u0B05-\u0B0B\u0B0F\u0B10\u0B14-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B57\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C02\u0C03\u0C05-\u0C0B\u0C0E-\u0C10\u0C12\u0C14-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C43\u0C46-\u0C48\u0C4A-\u0C4D\u0C82\u0C83\u0C85-\u0C8B\u0C8E-\u0C90\u0C92\u0C94-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBE-\u0CC3\u0CC6-\u0CC8\u0CCA-\u0CCD\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60\u0D61\u0D7A-\u0D7F\u1F00-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB2-\u1FB4\u1FB6\u1FB7\u1FBD\u1FBF\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD2\u1FD3\u1FD6\u1FD7\u1FE2-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u200D\u2019]+)/g
|
||||||
|
)
|
||||||
|
|
||||||
for (var i = 0; i < words.length; i += 1) {
|
for (var i = 0; i < words.length; i += 1) {
|
||||||
if (words[i].indexOf('/') !== -1) {
|
if (words[i].indexOf('/') !== -1) {
|
||||||
// Don't insert a zero width space if the slash is at the beginning or end
|
// Don't insert a zero width space if the slash is at the beginning or end
|
||||||
// of the text, or right after or before a space.
|
// of the text, or right after or before a space.
|
||||||
if (i !== 0 && i !== words.length - 1 && !(/\s+\/|\/\s+/.test(words[i]))) {
|
if (i !== 0 && i !== words.length - 1 && !/\s+\/|\/\s+/.test(words[i])) {
|
||||||
words[i] += '\u200B';
|
words[i] += '\u200B'
|
||||||
}
|
}
|
||||||
} else if (words[i].length > minLength) {
|
} else if (words[i].length > minLength) {
|
||||||
words[i] = this.hyphenate(words[i]).join('\u00AD');
|
words[i] = this.hyphenate(words[i]).join('\u00AD')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return words.join('');
|
return words.join('')
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hyphenates a word.
|
* Hyphenates a word.
|
||||||
*
|
*
|
||||||
* @param {!string} word The word to hyphenate
|
* @param {!string} word The word to hyphenate
|
||||||
* @return {!Array.<!string>} An array of word fragments indicating valid hyphenation points.
|
* @return {!Array.<!string>} An array of word fragments indicating valid hyphenation points.
|
||||||
*/
|
*/
|
||||||
Hypher.prototype.hyphenate = function (word) {
|
Hypher.prototype.hyphenate = function (word) {
|
||||||
var characters,
|
var characters,
|
||||||
characterPoints = [],
|
characterPoints = [],
|
||||||
originalCharacters,
|
originalCharacters,
|
||||||
@ -146,71 +150,75 @@ Hypher.prototype.hyphenate = function (word) {
|
|||||||
nodePointsLength,
|
nodePointsLength,
|
||||||
m = Math.max,
|
m = Math.max,
|
||||||
trie = this.trie,
|
trie = this.trie,
|
||||||
result = [''];
|
result = ['']
|
||||||
|
|
||||||
if (this.exceptions.hasOwnProperty(lowerCaseWord)) {
|
if (this.exceptions.hasOwnProperty(lowerCaseWord)) {
|
||||||
return word.match(this.exceptions[lowerCaseWord]).slice(1);
|
return word.match(this.exceptions[lowerCaseWord]).slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (word.indexOf('\u00AD') !== -1) {
|
if (word.indexOf('\u00AD') !== -1) {
|
||||||
return [word];
|
return [word]
|
||||||
}
|
}
|
||||||
|
|
||||||
word = '_' + word + '_';
|
word = '_' + word + '_'
|
||||||
|
|
||||||
characters = word.toLowerCase().split('');
|
characters = word.toLowerCase().split('')
|
||||||
originalCharacters = word.split('');
|
originalCharacters = word.split('')
|
||||||
wordLength = characters.length;
|
wordLength = characters.length
|
||||||
|
|
||||||
for (i = 0; i < wordLength; i += 1) {
|
for (i = 0; i < wordLength; i += 1) {
|
||||||
points[i] = 0;
|
points[i] = 0
|
||||||
characterPoints[i] = characters[i].charCodeAt(0);
|
characterPoints[i] = characters[i].charCodeAt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < wordLength; i += 1) {
|
for (i = 0; i < wordLength; i += 1) {
|
||||||
node = trie;
|
node = trie
|
||||||
for (j = i; j < wordLength; j += 1) {
|
for (j = i; j < wordLength; j += 1) {
|
||||||
node = node[characterPoints[j]];
|
node = node[characterPoints[j]]
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
nodePoints = node._points;
|
nodePoints = node._points
|
||||||
if (nodePoints) {
|
if (nodePoints) {
|
||||||
for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
|
for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
|
||||||
points[i + k] = m(points[i + k], nodePoints[k]);
|
points[i + k] = m(points[i + k], nodePoints[k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 1; i < wordLength - 1; i += 1) {
|
for (i = 1; i < wordLength - 1; i += 1) {
|
||||||
if (i > this.leftMin && i < (wordLength - this.rightMin) && points[i] % 2) {
|
if (i > this.leftMin && i < wordLength - this.rightMin && points[i] % 2) {
|
||||||
result.push(originalCharacters[i]);
|
result.push(originalCharacters[i])
|
||||||
} else {
|
} else {
|
||||||
result[result.length - 1] += originalCharacters[i];
|
result[result.length - 1] += originalCharacters[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = Hypher;
|
module.exports = Hypher
|
||||||
window['Hypher'] = module.exports;
|
window['Hypher'] = module.exports
|
||||||
|
|
||||||
window['Hypher']['languages'] = {};
|
window['Hypher']['languages'] = {}
|
||||||
}());(function ($) {
|
})()
|
||||||
|
;(function ($) {
|
||||||
$.fn.hyphenate = function (language) {
|
$.fn.hyphenate = function (language) {
|
||||||
if (window['Hypher']['languages'][language]) {
|
if (window['Hypher']['languages'][language]) {
|
||||||
return this.each(function () {
|
return this.each(function () {
|
||||||
var i = 0, len = this.childNodes.length;
|
var i = 0,
|
||||||
|
len = this.childNodes.length
|
||||||
for (; i < len; i += 1) {
|
for (; i < len; i += 1) {
|
||||||
if (this.childNodes[i].nodeType === 3) {
|
if (this.childNodes[i].nodeType === 3) {
|
||||||
this.childNodes[i].nodeValue = window['Hypher']['languages'][language].hyphenateText(this.childNodes[i].nodeValue);
|
this.childNodes[i].nodeValue = window['Hypher']['languages'][language].hyphenateText(
|
||||||
|
this.childNodes[i].nodeValue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}(jQuery));
|
})(jQuery)
|
||||||
|
4619
lib/3rdparty/pixi-ease.js
vendored
4619
lib/3rdparty/pixi-ease.js
vendored
File diff suppressed because it is too large
Load Diff
8701
lib/3rdparty/pixi-viewport.js
vendored
8701
lib/3rdparty/pixi-viewport.js
vendored
File diff suppressed because it is too large
Load Diff
@ -1385,7 +1385,7 @@ export default class Card {
|
|||||||
|
|
||||||
//jquery hyphenate below
|
//jquery hyphenate below
|
||||||
if (this._isJQueryPresent()) {
|
if (this._isJQueryPresent()) {
|
||||||
//$('.column').not('.overview').children('p').hyphenate('de')
|
$('.column').not('.overview').children('p').hyphenate('de')
|
||||||
}
|
}
|
||||||
|
|
||||||
//logging
|
//logging
|
||||||
@ -1936,7 +1936,7 @@ export default class Card {
|
|||||||
|
|
||||||
if (this._isJQueryPresent()) {
|
if (this._isJQueryPresent()) {
|
||||||
//jquery hyphenate below
|
//jquery hyphenate below
|
||||||
//console.log('hyphenated popup:', $('span').hyphenate('de'))
|
console.log('hyphenated popup:', $('span').hyphenate('de'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "iwmlib",
|
"name": "iwmlib",
|
||||||
"version": "2.0.0-beta.0",
|
"version": "2.0.0-beta.1",
|
||||||
"description": "An Open Source library for multi-touch, WebGL powered applications.",
|
"description": "An Open Source library for multi-touch, WebGL powered applications.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user