Доброго дня!
Хочу зробити новий контрол, як в прикладі:
На контрол хочу додати кастомну логіку:
- Як можна опрацьовувати подію input на полі (https://www.w3schools.com/jsref/event_oninput.asp)? При введені кожного символу хочу робити моментальну валідацію введеного тексту.
- Як в клас контролу додати додаткові надписи поряд з полем, в яких відображати кількість введених символів та введений текст (червоним виділяти не коректні символи). Як в прикладі на скріні.
Нравится
Степане, зверніть увагу на текстове поле, яке використовується для введення внутрішніх коментарів. Там при введенні «@» і перших літер прізвища показується панель-список зі знайденими користувачами:
Логіка цього поля реалізована в схемі ESNHtmlEditModule, що успадковується від ExtendedHtmlEditModule. Наприклад, при натисканні клавіш-літер спрацьовує:
/** * @inheritdoc Terrasoft.ExtendedHtmlEdit#onKeyPress * @overridden */ onKeyPress: function(e) { if (!this.enabled || this.readonly) { return; } var charCode = e.getCharCode(); this.lastKeySymbol = String.fromCharCode(charCode); if (!e.isNavKeyPress()) { if (this.isTrackingStartChar(this.lastKeySymbol)) { this.stopTracking(); this.startTracking(); } } },
А його застосування реалізовано у ESNFeedConfig:
{ className: "Terrasoft.ESNHtmlEdit", keydown: {bindTo: "onKeyDown"}, value: {bindTo: "commentMessage"}, placeholder: resources.localizableStrings.WriteComment, classes: { htmlEditClass: ["inlineTable", "wide", "editedCommentMessage", "placeholderOpacity"] }, focus: {bindTo: "onNewCommentContainerFocus"}, blur: {bindTo: "onNewCommentContainerBlur"}, markerValue: "commentToEditESNHtmlEdit", height: "47px", prepareList: {bindTo: "prepareEntitiesExpandableList"}, list: {bindTo: "entitiesList"}, listViewItemRender: {bindTo: "onEntitiesListViewItemRender"}, autoGrow: true, autoGrowMinHeight: 47 },
Функція prepareEntitiesExpandableList із підключенням серверного сервісу ESNFeedModuleService, що повертає за запитом імена, знаходиться у SocialMentionUtilities.
Зверев Александр, дякую, за відповідь. Але поки чекав відповіді, знайшов як можна реалізувати контрол і щоб він спрацьовував на EVENT INPUT.
В результаті наслідувався від контрола Terrasoft.controls.MemoEdit, в якого вже реалізований метод onInput.
Для використання контрола потрібно в картку додати:
{
"operation": "insert",
"name": "STRINGca49c1a2-6ab9-441e-bc09-46de5d822d60",
"parentName": "Header",
"propertyName": "items",
"values": {
"itemType": Terrasoft.ViewItemType.COMPONENT,
"className": "Terrasoft.UsrSMSMemoEdit",
"value": { "bindTo": "UsrSMSTemplate" },
"maxLimit": 160,
"caption": "Текст SMS",
"layout": {
"colSpan": 24,
"rowSpan": 2,
"column": 0,
"row": 0,
}
}
},
Підкріпляю реалізацію з коментарями:
define("UsrSMSMemoEdit", ["css!UsrSMSMemoEditCSS"], function () {
Ext.define("Terrasoft.controls.UsrSMSMemoEdit", {
extend: "Terrasoft.controls.MemoEdit",
alternateClassName: "Terrasoft.UsrSMSMemoEdit",
caption: null,
maxLimit: 1000,
textCount: 0,
errorText: "",
errorVisbility: "hidden",
isErrorTextDataset: "0",
//визначення HTML шаблону
tpl: [
"<div id=\"{id}-wrap\" data-resize=\"{resize}\" style=\"{wrapStyle}\">",
"<div id=\"{id}-error-block\" class=\"{rightPartClass}\" style=\"visibility:{errorVisbility}\">",
"<div class=\"{titleCounterClass}\">Помилка:</div>",
"<div class=\"{errorMarcerCopyClass}\"><div id=\"{id}-error-text\" >{errorText}</div></div>",
"</div>",
"<div class=\"{leftPartClass}\">",
"<div id=\"{id}-title\" class=\"{titleCounterClass}\">",
"{captionCounter} (<span id=\"{id}-title-counter\">{textCount}</span>/{maxLimit})",
"</div>",
"<div class=\"{wrapClass}\">",
"<div id=\"{id}-scroll\" class=\"{scrollClass}\">",
"<textarea id=\"{id}-virtual\" class=\"{textareaClasses} virtual\" style=\"{inputStyle}\">"
+"{value}</textarea>",
"<textarea id=\"{id}-el\" class=\"{textareaClasses}\" data-is-error-text=\"{isErrorTextDataset}\"",
"style=\"{inputStyle}\" tabindex=\"{tabIndex}\" ",
"placeholder=\"{placeholder}\" {spellcheck} {disabled} {readonly}>{value}</textarea>",
"<div id=\"{id}-disabled-el-icon\" class=\"{disabledElIconClass}\"></div>",
"</div></div>",
"<span id=\"{id}-validation\" class=\"{validationClass}\" style=\"{validationStyle}\">"
+"{validationText}</span>",
"</div>",
"</div>"
],
//після рендеренгу картки, в якій використовується шаблон та вставлення карткою даних в контрол
//виконувати перевизначення характеристик контрола та виклик методів,
//які виконують валідацію та заповнюють HTML шаблон
setValue: function (value) {
this.callParent(arguments);
if(value!==null && value!==undefined ) {
this.updateControl(value);
}
},
/**/
//при винекнення подій input та blur
//виконувати перевизначення характеристик контрола та виклик методів,
//які виконують валідацію та заповнюють HTML шаблон
onInput: function () {
this.callParent(arguments);
this.updateControl();
},
onBlur: function () {
this.callParent(arguments);
this.updateControl();
},
/**/
// перевизначення даних які будуть використовуватись в HTML шаблоні
getTplData: function () {
var tplData = this.callParent(arguments);
return Ext.apply(tplData, {
maxLimit: this.maxLimit,
captionCounter: this.caption,
textCount: this.textCount,
errorText: this.errorText,
errorVisbility: this.errorVisbility,
isErrorTextDataset: this.isErrorTextDataset,
});
},
//перевизначення css селекторів, які будуть використовуатись в HTML шаблоні
combineClasses: function () {
var classes = this.callParent(arguments);
return Ext.apply(classes, {
titleCounterClass: ["title-counter"],
leftPartClass: ["left-part"],
rightPartClass: ["right-part"],
errorMarcerCopyClass: ["error-marcer-copy"]
});
},
//перевизначення селекторів елементів HTML шаблону,
//в які будуть апдецйтитись дані
combineSelectors: function () {
var selectors = this.callParent(arguments);
return Ext.apply(selectors, {
titleCounterEl: "#" + this.id + "-title-counter",
errorTextEl: "#" + this.id + "-error-text",
errorBlocEl: "#" + this.id + "-error-block",
});
},
// Перевизначення характеристик контрола та виклик методів,
//які виконують валідацію та заповнюють HTML шаблон
updateControl: function(value) {
var text = this.getText(value);
var length = text.length;
this.textCount = length;
var err = this.getSMSTextError(text, this.maxLimit);
var errorVisbility = err==="" ? "hidden" : "visible";
this.errorText=err;
this.errorVisbility=errorVisbility;
this.isErrorTextDataset = (err === undefined || err === "") ? "0" : "1";
this.setDataInControlEl();
this.makeValidationEl(err);
},
// додавання даних в HTML шаблон
setDataInControlEl: function () {
if(!this.errorBlocEl){return;}
this.errorBlocEl.dom.style.visibility = this.errorVisbility;
this.titleCounterEl.update(this.textCount.toString());
var textarea = this.getEl().dom;
if (this.errorText || this.errorText === "") {
this.errorTextEl.dom.innerHTML = this.errorText;
}
textarea.dataset.isErrorText = this.isErrorTextDataset;
},
// отримання ввеленого тексту
getText: function(value) {
if(value!==null && value!==undefined ){
return value;
}
var textarea = this.getEl();
var v = textarea.dom.value;
var tv = this.getTypedValue();
var result = v.length > tv.length ? v : tv;
return result;
},
// валідація
makeValidationEl: function (err) {
var msg = err!=="" ? "Не коректний текст SMS" : "";
this.validationInfo.invalidMessage =msg;
this.validationInfo.isValid = err!=="" ? false : true;
this.setMarkOut();
},
getSMSTextError: function (str, countLimit) {
// форматування str додавання тегів в строку
//....
return result;
}
});
});
Додатково стилізував контрол
div.title-counter {
font-size: 1.5em;
color: #4e7bd8;
height: 2em;
padding-top: 0.1em;
}
div.left-part{
width:50%;
float: left;
}
div.right-part{
width:50%;
float: right;
}
.error-marcer-copy {
border:inherit;
position: relative;
display: inline-block;
clear: both;
padding-right: 20px;
padding-left: 20px;
width: 100%;
border: inherit;
vertical-align: top;
min-height: 28px;
box-sizing: border-box;
}
.error-marcer-copy > div {
width: 100%;
display: inline-block;
outline: none;
border: 0px;
font-size: 1.4em;
padding: 0;
box-sizing: border-box;
height: 100%;
overflow-y: hidden;
overflow-wrap: break-word;
}
.right-part > div.title-counter{
padding-left: 20px;
}
.error-marcer-copy > div > span{
background-color: red;
}