Рефакторинг
This commit is contained in:
@@ -3,6 +3,124 @@ export default class DrawHelper {
|
|||||||
return `${size}px ${this.fontName}`;
|
return `${size}px ${this.fontName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fontByStyle(style) {
|
||||||
|
return `${style.italic ? 'italic' : this.fontStyle} ${style.bold ? 'bold' : this.fontWeight} ${this.fontSize}px ${this.fontName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
measureText(text, style) {// eslint-disable-line no-unused-vars
|
||||||
|
this.context.font = this.fontByStyle(style);
|
||||||
|
return this.context.measureText(text).width;
|
||||||
|
}
|
||||||
|
|
||||||
|
measureTextFont(text, font) {// eslint-disable-line no-unused-vars
|
||||||
|
this.context.font = font;
|
||||||
|
return this.context.measureText(text).width;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPage(lines) {
|
||||||
|
if (!this.lastBook || this.pageLineCount < 1 || !this.book || !lines || !this.parsed.textLength)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
const spaceWidth = this.measureText(' ', {});
|
||||||
|
|
||||||
|
let out = `<div class="layout" style="width: ${this.realWidth}px; height: ${this.realHeight}px;` +
|
||||||
|
` color: ${this.textColor}">`;
|
||||||
|
|
||||||
|
let len = lines.length;
|
||||||
|
len = (len > this.pageLineCount + 1 ? this.pageLineCount + 1 : len);
|
||||||
|
|
||||||
|
let y = this.fontSize*this.textShift;
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
const line = lines[i];
|
||||||
|
/* line:
|
||||||
|
{
|
||||||
|
begin: Number,
|
||||||
|
end: Number,
|
||||||
|
first: Boolean,
|
||||||
|
last: Boolean,
|
||||||
|
parts: array of {
|
||||||
|
style: {bold: Boolean, italic: Boolean, center: Boolean}
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
let indent = line.first ? this.p : 0;
|
||||||
|
|
||||||
|
let lineText = '';
|
||||||
|
let center = false;
|
||||||
|
let centerStyle = {};
|
||||||
|
for (const part of line.parts) {
|
||||||
|
lineText += part.text;
|
||||||
|
center = center || part.style.center;
|
||||||
|
if (part.style.center)
|
||||||
|
centerStyle = part.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
let filled = false;
|
||||||
|
// если выравнивание по ширине включено
|
||||||
|
if (this.textAlignJustify && !line.last && !center) {
|
||||||
|
const words = lineText.split(' ');
|
||||||
|
|
||||||
|
if (words.length > 1) {
|
||||||
|
const spaceCount = words.length - 1;
|
||||||
|
|
||||||
|
const space = (this.w - line.width + spaceWidth*spaceCount)/spaceCount;
|
||||||
|
|
||||||
|
let x = indent;
|
||||||
|
for (const part of line.parts) {
|
||||||
|
const font = this.fontByStyle(part.style);
|
||||||
|
let partWords = part.text.split(' ');
|
||||||
|
|
||||||
|
for (let j = 0; j < partWords.length; j++) {
|
||||||
|
let f = font;
|
||||||
|
let style = part.style;
|
||||||
|
let word = partWords[j];
|
||||||
|
if (i == 0 && this.searching && word.toLowerCase().indexOf(this.needle) >= 0) {
|
||||||
|
style = Object.assign({}, part.style, {bold: true});
|
||||||
|
f = this.fontByStyle(style);
|
||||||
|
}
|
||||||
|
out += this.fillText(word, x, y, f);
|
||||||
|
x += this.measureText(word, style) + (j < partWords.length - 1 ? space : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// просто выводим текст
|
||||||
|
if (!filled) {
|
||||||
|
let x = indent;
|
||||||
|
x = (center ? (this.w - this.measureText(lineText, centerStyle))/2 : x);
|
||||||
|
for (const part of line.parts) {
|
||||||
|
let font = this.fontByStyle(part.style);
|
||||||
|
|
||||||
|
if (i == 0 && this.searching) {//для поиска, разбивка по словам
|
||||||
|
let partWords = part.text.split(' ');
|
||||||
|
for (let j = 0; j < partWords.length; j++) {
|
||||||
|
let f = font;
|
||||||
|
let style = part.style;
|
||||||
|
let word = partWords[j];
|
||||||
|
if (word.toLowerCase().indexOf(this.needle) >= 0) {
|
||||||
|
style = Object.assign({}, part.style, {bold: true});
|
||||||
|
f = this.fontByStyle(style);
|
||||||
|
}
|
||||||
|
out += this.fillText(word, x, y, f);
|
||||||
|
x += this.measureText(word, style) + (j < partWords.length - 1 ? spaceWidth : 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out += this.fillText(part.text, x, y, font);
|
||||||
|
x += this.measureText(part.text, part.style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y += this.lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
out += '</div>';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
drawPercentBar(x, y, w, h, font, fontSize, bookPos, textLength) {
|
drawPercentBar(x, y, w, h, font, fontSize, bookPos, textLength) {
|
||||||
const pad = 3;
|
const pad = 3;
|
||||||
const fh = h - 2*pad;
|
const fh = h - 2*pad;
|
||||||
|
|||||||
@@ -112,9 +112,9 @@ class TextPage extends Vue {
|
|||||||
this.toggleLayout = !this.toggleLayout;
|
this.toggleLayout = !this.toggleLayout;
|
||||||
|
|
||||||
if (this.toggleLayout)
|
if (this.toggleLayout)
|
||||||
this.page1 = this.drawPage(lines);
|
this.page1 = this.drawHelper.drawPage(lines);
|
||||||
else
|
else
|
||||||
this.page2 = this.drawPage(lines);
|
this.page2 = this.drawHelper.drawPage(lines);
|
||||||
|
|
||||||
this.doPageTransition();
|
this.doPageTransition();
|
||||||
}, 10);
|
}, 10);
|
||||||
@@ -148,28 +148,7 @@ class TextPage extends Vue {
|
|||||||
this.lineHeight = this.fontSize + this.lineInterval;
|
this.lineHeight = this.fontSize + this.lineInterval;
|
||||||
this.pageLineCount = 1 + Math.floor((this.h - this.fontSize)/this.lineHeight);
|
this.pageLineCount = 1 + Math.floor((this.h - this.fontSize)/this.lineHeight);
|
||||||
|
|
||||||
if (this.parsed) {
|
|
||||||
this.parsed.p = this.p;
|
|
||||||
this.parsed.w = this.w;// px, ширина текста
|
|
||||||
this.parsed.font = this.font;
|
|
||||||
this.parsed.wordWrap = this.wordWrap;
|
|
||||||
let t = '';
|
|
||||||
while (this.measureText(t, {}) < this.w) t += 'Щ';
|
|
||||||
this.parsed.maxWordLength = t.length - 1;
|
|
||||||
this.parsed.measureText = this.measureText;
|
|
||||||
}
|
|
||||||
|
|
||||||
//сообщение "Загрузка шрифтов..."
|
|
||||||
const flText = 'Загрузка шрифта...';
|
|
||||||
this.$refs.fontsLoading.innerHTML = flText;
|
|
||||||
const fontsLoadingStyle = this.$refs.fontsLoading.style;
|
|
||||||
fontsLoadingStyle.position = 'absolute';
|
|
||||||
fontsLoadingStyle.fontSize = this.fontSize + 'px';
|
|
||||||
fontsLoadingStyle.top = (this.realHeight/2 - 2*this.fontSize) + 'px';
|
|
||||||
fontsLoadingStyle.left = (this.realWidth - this.measureText(flText, {}))/2 + 'px';
|
|
||||||
|
|
||||||
//stuff
|
//stuff
|
||||||
this.statusBarColor = this.hex2rgba(this.textColor || '#000000', this.statusBarColorAlpha);
|
|
||||||
this.currentTransition = '';
|
this.currentTransition = '';
|
||||||
this.pageChangeDirectionDown = true;
|
this.pageChangeDirectionDown = true;
|
||||||
this.fontShift = this.fontVertShift/100;
|
this.fontShift = this.fontVertShift/100;
|
||||||
@@ -178,17 +157,52 @@ class TextPage extends Vue {
|
|||||||
//drawHelper
|
//drawHelper
|
||||||
this.drawHelper.realWidth = this.realWidth;
|
this.drawHelper.realWidth = this.realWidth;
|
||||||
this.drawHelper.realHeight = this.realHeight;
|
this.drawHelper.realHeight = this.realHeight;
|
||||||
|
this.drawHelper.lastBook = this.lastBook;
|
||||||
|
this.drawHelper.book = this.book;
|
||||||
|
this.drawHelper.parsed = this.parsed;
|
||||||
|
this.drawHelper.pageLineCount = this.pageLineCount;
|
||||||
|
|
||||||
this.drawHelper.backgroundColor = this.backgroundColor;
|
this.drawHelper.backgroundColor = this.backgroundColor;
|
||||||
this.drawHelper.statusBarColor = this.statusBarColor;
|
this.drawHelper.statusBarColor = this.statusBarColor;
|
||||||
|
this.drawHelper.fontStyle = this.fontStyle;
|
||||||
|
this.drawHelper.fontWeight = this.fontWeight;
|
||||||
|
this.drawHelper.fontSize = this.fontSize;
|
||||||
this.drawHelper.fontName = this.fontName;
|
this.drawHelper.fontName = this.fontName;
|
||||||
this.drawHelper.fontShift = this.fontShift;
|
this.drawHelper.fontShift = this.fontShift;
|
||||||
this.drawHelper.measureText = this.measureText;
|
this.drawHelper.textColor = this.textColor;
|
||||||
this.drawHelper.measureTextFont = this.measureTextFont;
|
this.drawHelper.textShift = this.textShift;
|
||||||
|
this.drawHelper.p = this.p;
|
||||||
|
this.drawHelper.w = this.w;
|
||||||
|
this.drawHelper.textAlignJustify = this.textAlignJustify;
|
||||||
|
this.drawHelper.lineHeight = this.lineHeight;
|
||||||
|
this.drawHelper.context = this.context;
|
||||||
|
|
||||||
|
//сообщение "Загрузка шрифтов..."
|
||||||
|
const flText = 'Загрузка шрифта...';
|
||||||
|
this.$refs.fontsLoading.innerHTML = flText;
|
||||||
|
const fontsLoadingStyle = this.$refs.fontsLoading.style;
|
||||||
|
fontsLoadingStyle.position = 'absolute';
|
||||||
|
fontsLoadingStyle.fontSize = this.fontSize + 'px';
|
||||||
|
fontsLoadingStyle.top = (this.realHeight/2 - 2*this.fontSize) + 'px';
|
||||||
|
fontsLoadingStyle.left = (this.realWidth - this.drawHelper.measureText(flText, {}))/2 + 'px';
|
||||||
|
|
||||||
|
//parsed
|
||||||
|
if (this.parsed) {
|
||||||
|
this.parsed.p = this.p;
|
||||||
|
this.parsed.w = this.w;// px, ширина текста
|
||||||
|
this.parsed.font = this.font;
|
||||||
|
this.parsed.wordWrap = this.wordWrap;
|
||||||
|
let t = '';
|
||||||
|
while (this.drawHelper.measureText(t, {}) < this.w) t += 'Щ';
|
||||||
|
this.parsed.maxWordLength = t.length - 1;
|
||||||
|
this.parsed.measureText = this.drawHelper.measureText.bind(this.drawHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
//statusBar
|
||||||
this.$refs.statusBar.style.left = '0px';
|
this.$refs.statusBar.style.left = '0px';
|
||||||
this.$refs.statusBar.style.top = (this.statusBarTop ? 1 : this.realHeight - this.statusBarHeight) + 'px';
|
this.$refs.statusBar.style.top = (this.statusBarTop ? 1 : this.realHeight - this.statusBarHeight) + 'px';
|
||||||
|
|
||||||
|
this.statusBarColor = this.hex2rgba(this.textColor || '#000000', this.statusBarColorAlpha);
|
||||||
this.statusBarClickable = this.drawHelper.statusBarClickable(this.statusBarTop, this.statusBarHeight);
|
this.statusBarClickable = this.drawHelper.statusBarClickable(this.statusBarTop, this.statusBarHeight);
|
||||||
|
|
||||||
//scrolling page
|
//scrolling page
|
||||||
@@ -208,16 +222,6 @@ class TextPage extends Vue {
|
|||||||
page2.style.left = this.indentLR + 'px';
|
page2.style.left = this.indentLR + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
measureText(text, style) {// eslint-disable-line no-unused-vars
|
|
||||||
this.context.font = this.fontByStyle(style);
|
|
||||||
return this.context.measureText(text).width;
|
|
||||||
}
|
|
||||||
|
|
||||||
measureTextFont(text, font) {// eslint-disable-line no-unused-vars
|
|
||||||
this.context.font = font;
|
|
||||||
return this.context.measureText(text).width;
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkLoadedFonts() {
|
async checkLoadedFonts() {
|
||||||
let loaded = await Promise.all(this.fontList.map(font => document.fonts.check(font)));
|
let loaded = await Promise.all(this.fontList.map(font => document.fonts.check(font)));
|
||||||
if (loaded.some(r => !r)) {
|
if (loaded.some(r => !r)) {
|
||||||
@@ -323,7 +327,6 @@ class TextPage extends Vue {
|
|||||||
|
|
||||||
this.linesUp = null;
|
this.linesUp = null;
|
||||||
this.linesDown = null;
|
this.linesDown = null;
|
||||||
this.searching = false;
|
|
||||||
|
|
||||||
this.statusBarMessage = '';
|
this.statusBarMessage = '';
|
||||||
|
|
||||||
@@ -407,31 +410,27 @@ class TextPage extends Vue {
|
|||||||
return `${this.fontStyle} ${this.fontWeight} ${this.fontSize}px ${this.fontName}`;
|
return `${this.fontStyle} ${this.fontWeight} ${this.fontSize}px ${this.fontName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
fontByStyle(style) {
|
|
||||||
return `${style.italic ? 'italic' : this.fontStyle} ${style.bold ? 'bold' : this.fontWeight} ${this.fontSize}px ${this.fontName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
onScrollingTransitionEnd() {
|
onScrollingTransitionEnd() {
|
||||||
if (this.resolveTransitionFinish)
|
if (this.resolveTransitionFinish)
|
||||||
this.resolveTransitionFinish();
|
this.resolveTransitionFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
startSearch(needle) {
|
startSearch(needle) {
|
||||||
this.needle = '';
|
this.drawHelper.needle = '';
|
||||||
const words = needle.split(' ');
|
const words = needle.split(' ');
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
if (word != '') {
|
if (word != '') {
|
||||||
this.needle = word;
|
this.drawHelper.needle = word;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.searching = true;
|
this.drawHelper.searching = true;
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSearch() {
|
stopSearch() {
|
||||||
this.searching = false;
|
this.drawHelper.searching = false;
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,7 +507,7 @@ class TextPage extends Vue {
|
|||||||
const lines = this.getLines(this.bookPos);
|
const lines = this.getLines(this.bookPos);
|
||||||
this.linesDown = lines.linesDown;
|
this.linesDown = lines.linesDown;
|
||||||
this.linesUp = lines.linesUp;
|
this.linesUp = lines.linesUp;
|
||||||
this.page1 = this.drawPage(lines.linesDown);
|
this.page1 = this.drawHelper.drawPage(lines.linesDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
//caching next
|
//caching next
|
||||||
@@ -518,7 +517,7 @@ class TextPage extends Vue {
|
|||||||
if (this.linesDown && this.linesDown.length > this.pageLineCount && this.pageLineCount > 0) {
|
if (this.linesDown && this.linesDown.length > this.pageLineCount && this.pageLineCount > 0) {
|
||||||
this.cachedPos = this.linesDown[1].begin;
|
this.cachedPos = this.linesDown[1].begin;
|
||||||
this.linesCached = this.getLines(this.cachedPos);
|
this.linesCached = this.getLines(this.cachedPos);
|
||||||
this.pageCached = this.drawPage(this.linesCached.linesDown);
|
this.pageCached = this.drawHelper.drawPage(this.linesCached.linesDown);
|
||||||
}
|
}
|
||||||
this.cachedPageTimer = null;
|
this.cachedPageTimer = null;
|
||||||
}, 20);
|
}, 20);
|
||||||
@@ -549,12 +548,6 @@ class TextPage extends Vue {
|
|||||||
const lines = this.getLines(this.bookPos);
|
const lines = this.getLines(this.bookPos);
|
||||||
this.linesDown = lines.linesDown;
|
this.linesDown = lines.linesDown;
|
||||||
this.linesUp = lines.linesUp;
|
this.linesUp = lines.linesUp;
|
||||||
|
|
||||||
/*if (this.toggleLayout)
|
|
||||||
this.page1 = this.drawPage(lines.linesDown);
|
|
||||||
else
|
|
||||||
this.page2 = this.drawPage(lines.linesDown);*/
|
|
||||||
|
|
||||||
this.debouncedUpdatePage(lines.linesDown);
|
this.debouncedUpdatePage(lines.linesDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,110 +583,6 @@ class TextPage extends Vue {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
drawPage(lines) {
|
|
||||||
if (!this.lastBook || this.pageLineCount < 1 || !this.book || !lines || !this.parsed.textLength)
|
|
||||||
return '';
|
|
||||||
|
|
||||||
const spaceWidth = this.measureText(' ', {});
|
|
||||||
|
|
||||||
let out = `<div class="layout" style="width: ${this.realWidth}px; height: ${this.realHeight}px;` +
|
|
||||||
` color: ${this.textColor}">`;
|
|
||||||
|
|
||||||
let len = lines.length;
|
|
||||||
len = (len > this.pageLineCount + 1 ? this.pageLineCount + 1 : len);
|
|
||||||
|
|
||||||
let y = this.fontSize*this.textShift;
|
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
const line = lines[i];
|
|
||||||
/* line:
|
|
||||||
{
|
|
||||||
begin: Number,
|
|
||||||
end: Number,
|
|
||||||
first: Boolean,
|
|
||||||
last: Boolean,
|
|
||||||
parts: array of {
|
|
||||||
style: {bold: Boolean, italic: Boolean, center: Boolean}
|
|
||||||
text: String,
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let indent = line.first ? this.p : 0;
|
|
||||||
|
|
||||||
let lineText = '';
|
|
||||||
let center = false;
|
|
||||||
let centerStyle = {};
|
|
||||||
for (const part of line.parts) {
|
|
||||||
lineText += part.text;
|
|
||||||
center = center || part.style.center;
|
|
||||||
if (part.style.center)
|
|
||||||
centerStyle = part.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
let filled = false;
|
|
||||||
// если выравнивание по ширине включено
|
|
||||||
if (this.textAlignJustify && !line.last && !center) {
|
|
||||||
const words = lineText.split(' ');
|
|
||||||
|
|
||||||
if (words.length > 1) {
|
|
||||||
const spaceCount = words.length - 1;
|
|
||||||
|
|
||||||
const space = (this.w - line.width + spaceWidth*spaceCount)/spaceCount;
|
|
||||||
|
|
||||||
let x = indent;
|
|
||||||
for (const part of line.parts) {
|
|
||||||
const font = this.fontByStyle(part.style);
|
|
||||||
let partWords = part.text.split(' ');
|
|
||||||
|
|
||||||
for (let j = 0; j < partWords.length; j++) {
|
|
||||||
let f = font;
|
|
||||||
let style = part.style;
|
|
||||||
let word = partWords[j];
|
|
||||||
if (i == 0 && this.searching && word.toLowerCase().indexOf(this.needle) >= 0) {
|
|
||||||
style = Object.assign({}, part.style, {bold: true});
|
|
||||||
f = this.fontByStyle(style);
|
|
||||||
}
|
|
||||||
out += this.drawHelper.fillText(word, x, y, f);
|
|
||||||
x += this.measureText(word, style) + (j < partWords.length - 1 ? space : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// просто выводим текст
|
|
||||||
if (!filled) {
|
|
||||||
let x = indent;
|
|
||||||
x = (center ? (this.w - this.measureText(lineText, centerStyle))/2 : x);
|
|
||||||
for (const part of line.parts) {
|
|
||||||
let font = this.fontByStyle(part.style);
|
|
||||||
|
|
||||||
if (i == 0 && this.searching) {//для поиска, разбивка по словам
|
|
||||||
let partWords = part.text.split(' ');
|
|
||||||
for (let j = 0; j < partWords.length; j++) {
|
|
||||||
let f = font;
|
|
||||||
let style = part.style;
|
|
||||||
let word = partWords[j];
|
|
||||||
if (word.toLowerCase().indexOf(this.needle) >= 0) {
|
|
||||||
style = Object.assign({}, part.style, {bold: true});
|
|
||||||
f = this.fontByStyle(style);
|
|
||||||
}
|
|
||||||
out += this.drawHelper.fillText(word, x, y, f);
|
|
||||||
x += this.measureText(word, style) + (j < partWords.length - 1 ? spaceWidth : 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out += this.drawHelper.fillText(part.text, x, y, font);
|
|
||||||
x += this.measureText(part.text, part.style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y += this.lineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
out += '</div>';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
drawStatusBar(message) {
|
drawStatusBar(message) {
|
||||||
if (this.w < minLayoutWidth) {
|
if (this.w < minLayoutWidth) {
|
||||||
this.statusBar = null;
|
this.statusBar = null;
|
||||||
@@ -790,9 +679,9 @@ class TextPage extends Vue {
|
|||||||
this.linesUpNext = lines.linesUp;
|
this.linesUpNext = lines.linesUp;
|
||||||
|
|
||||||
if (this.toggleLayout)
|
if (this.toggleLayout)
|
||||||
this.page2 = this.drawPage(lines.linesDown);//наоборот
|
this.page2 = this.drawHelper.drawPage(lines.linesDown);//наоборот
|
||||||
else
|
else
|
||||||
this.page1 = this.drawPage(lines.linesDown);
|
this.page1 = this.drawHelper.drawPage(lines.linesDown);
|
||||||
|
|
||||||
this.pagePrepared = true;
|
this.pagePrepared = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user