目次
- 【Salesforce自動操作 第0回】はじめに【vba, chrome拡張機能】
- 【Salesforce自動操作 第1回】右クリックメニューの追加【vba, chrome拡張機能】
- 【Salesforce自動操作 第2回】プルダウン選択の自動化【vba, chrome拡張機能】
- 【Salesforce自動操作 第3回】テキスト入力の自動化【vba, chrome拡張機能】
- 【Salesforce自動操作 第4回】CDPによるキー操作【vba, chrome拡張機能】
- 【Salesforce自動操作 第5回】検索項目の自動化【vba, chrome拡張機能】
- 【Salesforce自動操作 第6回】ページ読込完了時に処理を開始【vba, chrome拡張機能】
前回のおさらい
Chrome拡張機能からケース作成画面のDOMを取得することができるようになりました。
今回やること
プルダウン項目の値を設定していきます。優先度を初期値「Medium」から「High」に切り替えます。
ソースコード 全体
/**
* プルダウンを選択する
* @param {string} target_label_name 画面上の表示ラベル名
* @param {string} option_value 設定値
*/
async function selectPulldown(target_label_name, option_value) {
const container = document.querySelector('.actionBody');
const items = container.querySelectorAll('button[role="combobox"]');
// 該当プルダウンを検索する。
for (let i = 0; i < items.length; i++) {
const item = items[i];
const aria_label = item.getAttribute('aria-label');
if (!aria_label) {
continue;
}
// ラベル名を取得する。
const label_name = aria_label.split(',')[0];
// 該当プルダウンをクリック
if (label_name == target_label_name) {
// 0.01秒待機
item.click();
await sleep(10);
// 値の一致するオプションをクリックする。
const options = item.parentNode.parentNode.parentNode.querySelectorAll('lightning-base-combobox-item');
for (let j = 0; j < options.length; j++) {
const option = options[j];
const val = option.getAttribute('data-value');
if (val == option_value) {
option.click();
}
}
}
}
}
/** * 指定時間待機する
* @param {integer} ms
*/
async function sleep(ms) { await new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function main() {
await selectPulldown('優先度', 'High');
}
main();
解説
ノード階層
まず、Salesforceのhtmlは必要な箇所のみ抜粋すると以下のような階層をしています。
<!-- ルート -->
<div class="actionBody">
<!-- オブジェクト -->
<records-record-layout-item field-label="優先度">
<lightning-combobox>
<!-- ラベル -->
<label class="slds-form-element__label">
優先度
</label>
<!-- プルダウン -->
<div lightning-combobox_combobox>
<div lightning-basecombobox_basecombobox class="slds-dropdown-trigger_click">
<div lightning-basecombobox_basecombobox>
<button role="combobox" data-value="Medium" aria-label="優先度, Medium">
</button>
</div>
</div>
</div>
</lightning-combobox>
</records-record-layout-item>
</div>
actionBody
は全入力項目を包括するページ全体に位置するタグです。records-record-layout-item
はテキストやプルダウンなどのオブジェクトごとのルートタグです。
値を変更したいプルダウンを特定するためにはラベル名を取得する必要があります。
ラベル名はbutton
タグのaria-label
に設定されているので、まずはそれを取得します。
ラベルの取得
const container = document.querySelector('.actionBody');
const items = container.querySelectorAll('button[role="combobox"]'); // (1)
// 該当プルダウンを検索する。
for (let i = 0; i < items.length; i++) {
const item = items[i];
const aria_label = item.getAttribute('aria-label');
if (!aria_label) { // (2)
continue;
}
// ラベル名を取得する。
const label_name = aria_label.split(',')[0]; // (3)
button[role="combobox"]
で全てのプルダウンを列挙しています。- 入力項目でないボタンの場合、
aria_label
が設定されていません。
そのままラベルを取得しようとするとエラーになってしまうので、属性有無を判定しています。 - 文字列「
優先度, Medium
」からラベル名「優先度
」のみを取り出します。
選択肢の表示
// 該当プルダウンをクリック
if (label_name == target_label_name) {
// 0.01秒待機
item.click(); // (1)
await sleep(10); // (2)
// (中略)
}
/**
* 指定時間待機する
* @param {integer} ms
*/
async function sleep(ms) {
await new Promise(resolve => {
setTimeout(resolve, ms);
});
}
- 変更対象のラベルとラベル名が一致したら、ボタンをクリックし、選択肢を画面上に表示させます。
- ボタンをクリックしてから選択肢が表示されるまで一瞬だけ時間がかかることがあります。
そのまま処理を進めると、ノードの取得に失敗することがあるので、少しだけ待機します。
また、ボタンのクリックによってHTMLに選択肢候補のノードが追加されます。
<div class="actionBody">
<records-record-layout-item field-label="優先度">
<lightning-combobox>
<label class="slds-form-element__label">
優先度
</label>
<div lightning-combobox_combobox>
<div lightning-basecombobox_basecombobox class="slds-dropdown-trigger_click">
<div lightning-basecombobox_basecombobox>
<button role="combobox" data-value="Medium" aria-label="優先度, Medium">
</button>
</div>
<!-- ここから -->
<div lightning-basecombobox_basecombobox>
<lightning-base-combobox-item data-value></lightning-base-combobox-item>
<lightning-base-combobox-item data-value="High"></lightning-base-combobox-item>
<lightning-base-combobox-item data-value="Medius"></lightning-base-combobox-item>
<lightning-base-combobox-item data-value="Low"></lightning-base-combobox-item>
</div>
<!-- ここまでノードが追加される -->
</div>
</div>
</lightning-combobox>
</records-record-layout-item>
</div>
選択肢の決定
// 値の一致するオプションをクリックする。
const options = item.parentNode.parentNode.parentNode.querySelectorAll('lightning-base-combobox-item'); // (1)
for (let j = 0; j < options.length; j++) {
const option = options[j];
const val = option.getAttribute('data-value');
if (val == option_value) {
option.click();
}
}
- 変数
item
はbuttonノードです。そこからlightning-base-combobox-item
ノードを取得するためには、それよりも上位のノード(class="slds-dropdown-trigger_click"
のノード)まで.parentNodeをたどる必要があります。 - あとはdata-valueが一致するノードを選んでクリックをするだけです。
呼び出し処理
async function main() {
await selectPulldown('優先度', 'High');
}
ラベル名と設定したい値を渡しています。
実行結果
右クリック後、値がHighに、背景が黄色に切り替わることを確認しましょう。
はまりやすいポイント
async-await
非同期処理が発生する場合は、メソッドの宣言にasync
を、呼び出し側にawait
を忘れずにつけます。await
だけ書き忘れてsleepが効かないとハマることがよくあります。
salesforceにおけるノード参照
const container = document.querySelector('.actionBody');
const items = container.querySelectorAll('button[role="combobox"]');
今回、.actionBody
を持つノードを経由して2回に分けてプルダウンのノードを取得しています。本来であれば、下の行だけでノードが取得できるはずですが、経由有無によって以下のようにノードの取得結果が変わることを確認しています。
コンソールログから実行していますが、.actionBody
を経由していない方だけ要素が取得できていません。
根本原因は分かっていませんが、.actionBody
を経由することで解決はするので、良しとしましょう。