Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Ekstensibilitas dengan JS SDK versi 2.0 dan yang lebih tinggi
Sebelum Anda memulai
PENTING: Versi 2.0 dan yang lebih besar dari JS SDK menggunakan dekorator TypeScript. Dekorator masih merupakan fitur eksperimental dan harus diaktifkan secara eksplisit dalam file Anda
tsconfig.js:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Versi 2.0 dari JS SDK memperkenalkan perubahan mencolok dalam cara elemen dan tindakan kustom diimplementasikan dan didaftarkan. Untuk contoh tentang cara mengimplementasikan dan mendaftarkan elemen atau tindakan menggunakan versi SDK sebelumnya, lihat Ekstensibilitas dengan JS SDK sebelum versi 2.0.
Elemen kustom
Langkah-langkah untuk membuat jenis elemen Kartu Adaptif kustom adalah:
- Membuat kelas baru yang berasal dari
CardElement - Buat skemanya dengan mendeklarasikan definisi properti statis
getJsonTypeNameMenerapkan metode , daninternalRender- Daftarkan di registri elemen global, atau gunakan registri kustom berdasarkan per kartu
Mari kita ambil contoh dan terapkan elemen Progress Bar sederhana:
export class ProgressBar extends AC.CardElement {
static readonly JsonTypeName = "ProgressBar";
//#region Schema
static readonly titleProperty = new AC.StringProperty(AC.Versions.v1_0, "title", true);
static readonly valueProperty = new AC.NumProperty(AC.Versions.v1_0, "value");
@AC.property(ProgressBar.titleProperty)
get title(): string | undefined {
return this.getValue(ProgressBar.titleProperty);
}
set title(value: string) {
if (this.title !== value) {
this.setValue(ProgressBar.titleProperty, value);
this.updateLayout();
}
}
@AC.property(ProgressBar.valueProperty)
get value(): number {
return this.getValue(ProgressBar.valueProperty);
}
set value(value: number) {
let adjustedValue = value;
if (adjustedValue < 0) {
adjustedValue = 0;
}
else if (adjustedValue > 100) {
adjustedValue = 100;
}
if (this.value !== adjustedValue) {
this.setValue(ProgressBar.valueProperty, adjustedValue);
this.updateLayout();
}
}
//#endregion
private _titleElement: HTMLElement;
private _leftBarElement: HTMLElement;
private _rightBarElement: HTMLElement;
protected internalRender(): HTMLElement {
let element = document.createElement("div");
let textBlock = new AC.TextBlock();
textBlock.setParent(this);
textBlock.text = this.title;
textBlock.wrap = true;
this._titleElement = textBlock.render();
this._titleElement.style.marginBottom = "6px";
let progressBarElement = document.createElement("div");
progressBarElement.style.display = "flex";
this._leftBarElement = document.createElement("div");
this._leftBarElement.style.height = "6px";
this._leftBarElement.style.backgroundColor = AC.stringToCssColor(this.hostConfig.containerStyles.emphasis.foregroundColors.accent.default);
this._rightBarElement = document.createElement("div");
this._rightBarElement.style.height = "6px";
this._rightBarElement.style.backgroundColor = AC.stringToCssColor(this.hostConfig.containerStyles.emphasis.backgroundColor);
progressBarElement.append(this._leftBarElement, this._rightBarElement);
element.append(this._titleElement, progressBarElement);
return element;
}
getJsonTypeName(): string {
return ProgressBar.JsonTypeName;
}
updateLayout(processChildren: boolean = true) {
super.updateLayout(processChildren);
if (this.renderedElement) {
if (this.title) {
this._titleElement.style.display = "none";
}
else {
this._titleElement.style.removeProperty("display");
}
this._leftBarElement.style.flex = "1 1 " + this.value + "%";
this._rightBarElement.style.flex = "1 1 " + (100 - this.value) + "%";
}
}
}
Itu saja. Elemen ProgressBar sekarang perlu didaftarkan agar dapat dikenali oleh SDK. Anda dapat mendaftarkannya secara global:
AC.GlobalRegistry.elements.register(ProgressBar.JsonTypeName, ProgressBar);
Atau Anda dapat menggunakan registri per kartu, yang memungkinkan penggunaan registri yang berbeda untuk kartu yang berbeda dalam aplikasi Anda:
// Create a custom registry for elements
let elementRegistry = new AC.CardObjectRegistry<AC.CardElement>();
// Populate it with the default set of elements
AC.GlobalRegistry.populateWithDefaultElements(elementRegistry);
// Register the custom ProgressBar element
elementRegistry.register(ProgressBar.JsonTypeName, ProgressBar);
// Parse a card payload using the custom registry
let serializationContext = new AC.SerializationContext();
serializationContext.setElementRegistry(elementRegistry);
let card = new AC.AdaptiveCard();
card.parse(
{
type: "AdaptiveCard",
version: "1.0",
body: [
{
type: "ProgressBar",
title: "This is a progress bar",
value: 45
}
]
},
serializationContext
);
Input kustom
Input adalah jenis elemen khusus yang didedikasikan untuk mengumpulkan data yang dimasukkan oleh pengguna akhir yang kemudian dapat diteruskan sebagai parameter ke tindakan.
Versi 2.x dari Kartu Adaptif JS SDK memperkenalkan dua perubahan penting dalam hal input:
- Validasi input: sekarang ada mekanisme validasi input bawaan yang secara otomatis menangani kesalahan validasi termasuk petunjuk visual
- Peningkatan aksesibilitas: input bawaan memiliki dukungan yang lebih baik untuk fitur aksesibilitas
Karena itu, menerapkan input kustom membutuhkan sedikit lebih banyak logika daripada menerapkan elemen sederhana. Tabel di bawah ini mencantumkan semua metode yang harus diterapkan implementasi input kustom untuk mempartiosipasi dalam mekanisme validasi input dan dapat diakses:
| Metode | Deskripsi |
|---|---|
protected updateInputControlAriaLabelledBy() |
Metode ini dipanggil selama urutan validasi input. Ketika input gagal validasi, pesan kesalahan terkait ditampilkan dan atribut kontrol aria-labelledby input yang mendasar perlu diperbarui agar input mematuhi persyaratan aksesibilitas. Input kustom HARUS mengambil updateInputControlAriaLabelledBy alih untuk menerapkan atribut yang sesuai aria-labelledby ke kontrol input yang mendasar. Metode getAllLabelIds(): string[] ini dapat digunakan untuk mengambil Id dari semua label yang harus ditentukan dalam aria-labelledby atribut . |
protected internalRender(): HTMLElement |
Sama seperti untuk elemen kustom Kartu Adaptif lainnya, internalRender HARUS ditimpa untuk merender input Anda sesuai keinginan. Di sinilah Anda ingin membuat kontrol input dasar yang sebenarnya. |
protected get isNullable(): boolean |
Menunjukkan apakah input mendukung nilai yang tidak terdefinisi (misalnya, Input.Text tidak, sedangkan Input.Toggle tidak.) Input kustom HARUS mengambil alih pengalih properti ini untuk menunjukkan apakah mereka mendukung nilai yang tidak terdefinisi. Implementasi dasar mengembalikan true. |
public focus() |
Ketika kesalahan validasi ditemui, fokus secara otomatis ditempatkan pada input pertama yang gagal validasi. Implementasi dasar akan focus dalam beberapa kasus hanya berfungsi untuk input kustom. Ketika itu tidak terjadi, kontrol input kustom HARUS mengambil alih focus untuk secara eksplisit menempatkan fokus pada kontrol input yang mendasar. |
public abstract isSet(): boolean |
Menunjukkan apakah nilai input telah ditetapkan oleh pengguna. Metode ini dipanggil selama urutan validasi input untuk menentukan apakah input lolos atau gagal validasi. Input kustom HARUS mengambil alih isSet untuk berpartisipasi dalam mekanisme validasi input. |
public isValid(): boolean |
Menunjukkan apakah nilai input valid. Metode ini dipanggil selama urutan validasi input untuk menentukan apakah input lolos atau gagal validasi. Input kustom HARUS mengambil isValid alih untuk berpartisipasi dalam mekanisme validasi input. Implementasi dasar mengembalikan true. |
public abstract get value(): any |
Mengembalikan nilai input. Input kustom HARUS mengambil alih ini sehingga nilai input diambil dari kontrol input yang mendasar. |
Tindakan kustom
Langkah-langkah untuk menerapkan tindakan kustom sama dengan langkah-langkah untuk elemen. Satu-satunya perbedaan adalah bahwa tindakan terdaftar dalam registri tindakan, dan bukan di registri elemen.
export class AlertAction extends AC.Action {
static readonly JsonTypeName = "Action.Alert";
//#region Schema
static readonly textProperty = new AC.StringProperty(AC.Versions.v1_0, "text", true);
@AC.property(AlertAction.textProperty)
text?: string;
//#endregion
getJsonTypeName(): string {
return AlertAction.JsonTypeName;
}
execute() {
alert(this.text);
}
}
Daftarkan tindakan baru secara global:
AC.GlobalRegistry.actions.register(AlertAction.JsonTypeName, AlertAction);
Atau gunakan registri per kartu:
// Create a custom registry for actions
let actionRegistry = new AC.CardObjectRegistry<AC.Action>();
// Populate it with the default set of actions
AC.GlobalRegistry.populateWithDefaultActions(actionRegistry);
// Register the custom AlertAction type
actionRegistry.register(AlertAction.JsonTypeName, AlertAction);
// Parse a card payload using the custom registry
let serializationContext = new AC.SerializationContext();
serializationContext.setActionRegistry(actionRegistry);
let card = new AC.AdaptiveCard();
card.parse(
{
type: "AdaptiveCard",
version: "1.0",
body: [
{
type: "TextBlock",
text: "This demonstrates the AlertAction action."
}
],
actions: [
{
type: "Action.Alert",
title: "Click me!",
text: "Hello World"
}
]
},
serializationContext
);
Ekstensibilitas dengan JavaScript SDK sebelum versi 2.0
Elemen kustom
Sebelum Anda memulai
PENTING: Versi 2.0 dan yang lebih besar dari JS SDK menggunakan dekorator TypeScript. Dekorator masih merupakan fitur eksperimental dan harus diaktifkan secara eksplisit dalam file Anda
tsconfig.js:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Versi 2.0 dari JS SDK memperkenalkan perubahan mencolok dalam cara elemen dan tindakan kustom diimplementasikan dan didaftarkan. Untuk contoh tentang cara mengimplementasikan dan mendaftarkan elemen atau tindakan menggunakan versi SDK sebelumnya, lihat Ekstensibilitas dengan JS SDK sebelum versi 2.0.
Elemen kustom
Langkah-langkah untuk membuat jenis elemen Kartu Adaptif kustom adalah:
- Membuat kelas baru yang berasal dari
CardElement - Buat skemanya dengan mendeklarasikan definisi properti statis
getJsonTypeNameMenerapkan metode , daninternalRender- Daftarkan di registri elemen global, atau gunakan registri kustom berdasarkan per kartu
Mari kita ambil contoh dan terapkan elemen Progress Bar sederhana:
export class ProgressBar extends AC.CardElement {
static readonly JsonTypeName = "ProgressBar";
//#region Schema
static readonly titleProperty = new AC.StringProperty(AC.Versions.v1_0, "title", true);
static readonly valueProperty = new AC.NumProperty(AC.Versions.v1_0, "value");
@AC.property(ProgressBar.titleProperty)
get title(): string | undefined {
return this.getValue(ProgressBar.titleProperty);
}
set title(value: string) {
if (this.title !== value) {
this.setValue(ProgressBar.titleProperty, value);
this.updateLayout();
}
}
@AC.property(ProgressBar.valueProperty)
get value(): number {
return this.getValue(ProgressBar.valueProperty);
}
set value(value: number) {
let adjustedValue = value;
if (adjustedValue < 0) {
adjustedValue = 0;
}
else if (adjustedValue > 100) {
adjustedValue = 100;
}
if (this.value !== adjustedValue) {
this.setValue(ProgressBar.valueProperty, adjustedValue);
this.updateLayout();
}
}
//#endregion
private _titleElement: HTMLElement;
private _leftBarElement: HTMLElement;
private _rightBarElement: HTMLElement;
protected internalRender(): HTMLElement {
let element = document.createElement("div");
let textBlock = new AC.TextBlock();
textBlock.setParent(this);
textBlock.text = this.title;
textBlock.wrap = true;
this._titleElement = textBlock.render();
this._titleElement.style.marginBottom = "6px";
let progressBarElement = document.createElement("div");
progressBarElement.style.display = "flex";
this._leftBarElement = document.createElement("div");
this._leftBarElement.style.height = "6px";
this._leftBarElement.style.backgroundColor = AC.stringToCssColor(this.hostConfig.containerStyles.emphasis.foregroundColors.accent.default);
this._rightBarElement = document.createElement("div");
this._rightBarElement.style.height = "6px";
this._rightBarElement.style.backgroundColor = AC.stringToCssColor(this.hostConfig.containerStyles.emphasis.backgroundColor);
progressBarElement.append(this._leftBarElement, this._rightBarElement);
element.append(this._titleElement, progressBarElement);
return element;
}
getJsonTypeName(): string {
return ProgressBar.JsonTypeName;
}
updateLayout(processChildren: boolean = true) {
super.updateLayout(processChildren);
if (this.renderedElement) {
if (this.title) {
this._titleElement.style.display = "none";
}
else {
this._titleElement.style.removeProperty("display");
}
this._leftBarElement.style.flex = "1 1 " + this.value + "%";
this._rightBarElement.style.flex = "1 1 " + (100 - this.value) + "%";
}
}
}
Itu saja. Elemen ProgressBar sekarang perlu didaftarkan agar dapat dikenali oleh SDK. Anda dapat mendaftarkannya secara global:
AC.GlobalRegistry.elements.register(ProgressBar.JsonTypeName, ProgressBar);
Atau Anda dapat menggunakan registri per kartu, yang memungkinkan penggunaan registri yang berbeda untuk kartu yang berbeda dalam aplikasi Anda:
// Create a custom registry for elements
let elementRegistry = new AC.CardObjectRegistry<AC.CardElement>();
// Populate it with the default set of elements
AC.GlobalRegistry.populateWithDefaultElements(elementRegistry);
// Register the custom ProgressBar element
elementRegistry.register(ProgressBar.JsonTypeName, ProgressBar);
// Parse a card payload using the custom registry
let serializationContext = new AC.SerializationContext();
serializationContext.setElementRegistry(elementRegistry);
let card = new AC.AdaptiveCard();
card.parse(
{
type: "AdaptiveCard",
version: "1.0",
body: [
{
type: "ProgressBar",
title: "This is a progress bar",
value: 45
}
]
},
serializationContext
);
Tindakan kustom
Langkah-langkah untuk menerapkan tindakan kustom sama dengan langkah-langkah untuk elemen. Satu-satunya perbedaan adalah bahwa tindakan terdaftar dalam registri tindakan, dan bukan di registri elemen.
export class AlertAction extends AC.Action {
static readonly JsonTypeName = "Action.Alert";
//#region Schema
static readonly textProperty = new AC.StringProperty(AC.Versions.v1_0, "text", true);
@AC.property(AlertAction.textProperty)
text?: string;
//#endregion
getJsonTypeName(): string {
return AlertAction.JsonTypeName;
}
execute() {
alert(this.text);
}
}
Daftarkan tindakan baru secara global:
AC.GlobalRegistry.actions.register(AlertAction.JsonTypeName, AlertAction);
Atau gunakan registri per kartu:
// Create a custom registry for actions
let actionRegistry = new AC.CardObjectRegistry<AC.Action>();
// Populate it with the default set of actions
AC.GlobalRegistry.populateWithDefaultActions(actionRegistry);
// Register the custom AlertAction type
actionRegistry.register(AlertAction.JsonTypeName, AlertAction);
// Parse a card payload using the custom registry
let serializationContext = new AC.SerializationContext();
serializationContext.setActionRegistry(actionRegistry);
let card = new AC.AdaptiveCard();
card.parse(
{
type: "AdaptiveCard",
version: "1.0",
body: [
{
type: "TextBlock",
text: "This demonstrates the AlertAction action."
}
],
actions: [
{
type: "Action.Alert",
title: "Click me!",
text: "Hello World"
}
]
},
serializationContext
);
Ekstensibilitas dengan JS SDK sebelum versi 2.0
Elemen kustom
Langkah-langkah untuk membuat jenis elemen Kartu Adaptif kustom adalah:
- Membuat kelas baru yang berasal dari
CardElement getJsonTypeNameMenerapkan metode ,parse,toJSON,internalRenderdanrenderSpeech- Daftarkan dengan menambahkannya ke registri elemen perender
Mari kita ambil contoh dan terapkan elemen Progress Bar sederhana:
import * as Adaptive from "adaptivecards";
export class ProgressBar extends Adaptive.CardElement {
private _title: string;
private _value: number = 0;
private _titleElement: HTMLElement;
private _leftBarElement: HTMLElement;
private _rightBarElement: HTMLElement;
protected internalRender(): HTMLElement {
let element = document.createElement("div");
let textBlock = new Adaptive.TextBlock();
textBlock.setParent(this);
textBlock.text = this.title;
textBlock.wrap = true;
this._titleElement = textBlock.render();
this._titleElement.style.marginBottom = "6px";
let progressBarElement = document.createElement("div");
progressBarElement.style.display = "flex";
this._leftBarElement = document.createElement("div");
this._leftBarElement.style.height = "6px";
this._leftBarElement.style.backgroundColor = Adaptive.stringToCssColor(this.hostConfig.containerStyles.emphasis.foregroundColors.accent.default);
this._rightBarElement = document.createElement("div");
this._rightBarElement.style.height = "6px";
this._rightBarElement.style.backgroundColor = Adaptive.stringToCssColor(this.hostConfig.containerStyles.emphasis.backgroundColor);
progressBarElement.append(this._leftBarElement, this._rightBarElement);
element.append(this._titleElement, progressBarElement);
return element;
}
getJsonTypeName(): string {
return "ProgressBar";
}
toJSON(): any {
let result = super.toJSON();
Adaptive.setProperty(result, "title", this.title);
Adaptive.setProperty(result, "value", this.value);
return result;
}
parse(json: any, errors?: Array<Adaptive.IValidationError>) {
super.parse(json, errors);
this.title = Adaptive.getStringValueOrDefault(json["title"], undefined);
this.value = Adaptive.getValueOrDefault(json["value"], this._value);
}
updateLayout(processChildren: boolean = true) {
super.updateLayout(processChildren);
if (this.renderedElement) {
if (Adaptive.isNullOrEmpty(this.title)) {
this._titleElement.style.display = "none";
}
else {
this._titleElement.style.removeProperty("display");
}
this._leftBarElement.style.flex = "1 1 " + this.value + "%";
this._rightBarElement.style.flex = "1 1 " + (100 - this.value) + "%";
}
}
renderSpeech(): string {
return (Adaptive.isNullOrEmpty(this.title) ? "Progress" : this.title) + " " + Math.ceil(this.value) + "%";
}
get title(): string {
return this._title;
}
set title(value: string) {
if (this._title !== value) {
this._title = value;
this.updateLayout();
}
}
get value(): number {
return this._value;
}
set value(value: number) {
let adjustedValue = value;
if (adjustedValue < 0) {
adjustedValue = 0;
}
else if (adjustedValue > 100) {
adjustedValue = 100;
}
if (this._value !== adjustedValue) {
this._value = adjustedValue;
this.updateLayout();
}
}
}
Itu saja. Sekarang cukup daftarkan kelas Bilah Kemajuan dengan perender:
Adaptive.AdaptiveCard.elementTypeRegistry.registerType("ProgressBar", () => { return new ProgressBar(); });
Tindakan kustom
Langkah-langkah untuk membuat tindakan Kartu Adaptif kustom pada dasarnya sama dengan yang untuk elemen kustom. Berikut adalah contoh sederhana Tindakan Pemberitahuan yang hanya menampilkan kotak pesan dengan teks yang dapat dikonfigurasi:
import * as Adaptive from "adaptivecards";
export class AlertAction extends Adaptive.Action {
text: string;
getJsonTypeName(): string {
return "Action.ALert";
}
execute() {
alert(this.text);
}
parse(json: any) {
super.parse(json);
this.text = Adaptive.getStringValueOrDefault(json["text"], "Alert!");
}
toJSON() {
let result = super.toJSON();
Adaptive.setProperty(result, "text", this.text);
return result;
}
}
Sekarang daftarkan tindakan baru:
Adaptive.AdaptiveCard.actionTypeRegistry.registerType("Action.Alert", () => { return new AlertAction(); });
Contoh
Berikut adalah kartu sampel yang menggunakan elemen ProgressBar dan tindakan AlertAction:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "Custom ProgressBar element"
},
{
"type": "ProgressBar",
"title": "Please wait...",
"value": 10
}
],
"actions": [
{
"type": "Action.Alert",
"title": "Click me",
"text": "Hello world!"
}
]
}
Dan inilah caranya merender: 