Can you copy one number that doesn't work here (edit it a bit for privacy), maybe it uses some special character that is not matched?
One of the numbers that doesn't work is shown in the example
7 917 809β97β58β¬
I see. That seems to contain an invisible unicode character 0x202c at the end (you will notice when trying to select or delete only the 8).
You could modify the script to remove that character:
let phoneNumber = clipboardContentString.replace(/[\s\-\(\)\u200B-\u200D\u202C\uFEFF]/g, "");
Nice spot Andreas!
@T-N-T Here is the full updated script. You'll notice that I added:
// set to true to show dialog, set to false to not show the dialog
let debug = true;
at the beginning of the script.
If you want to turn off the dialog to display the summary of the script, set debug
to false
.
I hope this helps!
async (clipboardContentString) => {
// set to true to show dialog, set to false to not show the dialog
let debug = true;
// Function to display dialog with input, escaping any double quotes
function displayDialog(message) {
let safeMessage = message.replace(/"/g, '\\"'); // Escape double quotes
let debugScript = `
display dialog "${safeMessage}"
`;
runAppleScript(debugScript);
}
// Error handling block
try {
// Remove whitespace, dashes, parentheses, and invisible unicode characters
let phoneNumber = clipboardContentString.replace(/[\s\-\(\)\u200B-\u200D\u202C\uFEFF]/g, "");
// Regex check for valid phone number format (example: international format)
let isValidPhoneNumber = /^\+?[1-9]\d{1,14}$/.test(phoneNumber);
// Stop execution if phone number is not valid
if (!isValidPhoneNumber) {
displayDialog(`Invalid phone number format: ${phoneNumber}. Execution stopped.`);
return phoneNumber;
}
// Escape any special characters to prevent command injection
let escapedPhoneNumber = phoneNumber.replace(/[^a-zA-Z0-9+]/g, '');
// Construct the shell command with the escaped phone number
let script = `/usr/bin/open whatsapp://send\?phone=${escapedPhoneNumber}`;
if (debug == true) {
// Use AppleScript with better readability and extra new lines between key-value pairs
let appleScript = `
set dialogText to "Clipboard Content:\n" & "${clipboardContentString}" & "\n\n" & \
"\nFormatted Phone Number:\n" & "${phoneNumber}" & "\n\n" & \
"\nIs Valid Phone Number:\n" & "${isValidPhoneNumber}" & "\n\n" & \
"\nShell Script:\n" & "${script}"
display dialog dialogText
`;
// Execute the AppleScript
runAppleScript(appleScript);
};
// Execute the shell command
runShellScript({ script });
return phoneNumber;
} catch (error) {
// Display dialog with the last variable that caused an error
displayDialog(`Error encountered: ${error.message}`);
throw error; // Re-throw the error for any higher-level handling
}
};
Guys, would it be too much trouble for you to send me the entire script so I can paste it into the program?
I'm not very good with programming at all...
I copied what you sent above, pasted it into the program, and now it crashes )
@T-N-T Here's a new and improved version of the script that should work:
async (clipboardContentString) => {
// Set to true to show dialog, set to false to not show the dialog
let debug = false;
// Function to display dialog with input, escaping any double quotes
function displayDialog(message) {
let safeMessage = message.replace(/"/g, '\\"'); // Escape double quotes
let debugScript = `
display dialog "${safeMessage}"
`;
runAppleScript(debugScript);
}
// Error handling block
try {
// Remove all characters except '+' and digits
let phoneNumber = clipboardContentString.replace(/[^+\d]/g, "");
// Regex check for valid phone number format (E.164 international format)
let isValidPhoneNumber = /^\+?[1-9]\d{1,14}$/.test(phoneNumber);
// Stop execution if phone number is not valid
if (!isValidPhoneNumber) {
displayDialog(`Invalid phone number format: ${phoneNumber}. Execution stopped.`);
return phoneNumber;
}
// Construct the shell command with the cleaned phone number
let script = `/usr/bin/open whatsapp://send?phone=${phoneNumber}`;
if (debug) {
// Use AppleScript with better readability and extra new lines between key-value pairs
let appleScript = `
set dialogText to "Clipboard Content:\n" & "${clipboardContentString}" & "\n\n" & \
"Formatted Phone Number:\n" & "${phoneNumber}" & "\n\n" & \
"Is Valid Phone Number:\n" & "${isValidPhoneNumber}" & "\n\n" & \
"Shell Script:\n" & "${script}"
display dialog dialogText
`;
// Execute the AppleScript
runAppleScript(appleScript);
}
// Execute the shell command
runShellScript({ script });
return phoneNumber;
} catch (error) {
// Display dialog with the error message
displayDialog(`Error encountered: ${error.message}`);
throw error; // Re-throw the error for any higher-level handling
}
};
This one works
And in Google Sheets and everywhere, thank you very much
Guys, tell me, is it difficult to add to this script the ability to perform an action also from the selected text?
That is, everything is the same, only not from the clipboard, but from the selected text.
Previously (before WhatsApp was updated) both options worked.
When I used the "%@" function
Are you using the "Transform & Copy Selection With Java Script" action like described here Paste from clipboard with a specific variable - #2 by Andreas_Hegenberg ?
That should work with the selected text
You are right! There was an option, not like in your example.
Now everything works and with selection!
You are very cool guys! Thank you very much
This saves me a lot of time and nerves )))
Found where the script doesn't work.
Let's say we right-click on the phone number from this site:
https://bamper.by/zapchast_dvigatel/50315-B462580995/
And select "copy phone number" (FireFox browser)
Run the script and get: ο»Ώο»Ώο»Ώο»ΏInvalid phone number format: . Execution stopped.
At the same time, if after "copy phone number" we paste this text into some editor, then from there this number will work according to the script.
It's probably easier to shoot a video, but is it possible to post it somewhere here?
And another thing.
Previously, I could drop something into the clipboard, then select the phone number, run the script and paste the text from the clipboard into the opened WhatsApp chat.
Now, if I copy some text into the clipboard, then select the phone number, run the script, then the phone number is pasted into the clipboard.
@T-N-T I updated the script to make it works like this:
If there is text selected, check if it's a valid phone number. If yes, then open it in WhatsApp. If no, then check if the clipboard content is a valid phone number. If yes, then open it in WhatsApp. If no, then display an error.
To make this script work, the Action type must be:
Run Real JavaScript
It will not work if the Action type is:
Transform & Copy Selection With Java Script
, or;
Transform Clipboard Contents with JavaScript
(async function () {
// Enable or disable debug mode (set to false to disable debug dialogs)
const DEBUG = true;
/**
* Function to display a dialog box using AppleScript.
* This is used to show messages to the user.
* @param {string} title - The title of the dialog box.
* @param {string} message - The message content to display.
*/
async function showDialog(title, message) {
// Prepare the AppleScript command to display a dialog
const appleScript = `display dialog ${JSON.stringify(
message
)} with title ${JSON.stringify(
title
)} buttons {"OK"} default button "OK"`;
// Execute the AppleScript command to show the dialog
await runAppleScript(appleScript);
}
/**
* Function to validate a phone number against the E.164 international format.
* E.164 is an international standard for phone numbers.
* @param {string} phoneNumber - The phone number to validate.
* @returns {boolean} - Returns true if the phone number is valid, false otherwise.
*/
function isValidE164(phoneNumber) {
// Regular expression to match E.164 phone numbers
return /^\+?[1-9]\d{1,14}$/.test(phoneNumber);
}
/**
* Function to extract a valid phone number from input text.
* It sanitizes the input by removing unwanted characters and checks if it's a valid phone number.
* @param {string} input - The input text that may contain a phone number.
* @returns {string|null} - Returns the sanitized phone number if valid, or null if invalid.
*/
function extractValidPhoneNumber(input) {
// If input is null or empty, return null
if (!input) return null;
// Remove all characters except '+' and digits
const sanitized = input.replace(/[^+\d]/g, "");
// Check if the sanitized number is a valid E.164 phone number
return isValidE164(sanitized) ? sanitized : null;
}
/**
* Function to get a valid phone number from content.
* @param {string} content - The content to extract the phone number from.
* @param {string} sourceLabel - A label indicating the source ("Selection" or "Clipboard").
* @returns {{phoneNumber: string, source: string, content: string} | null} - Returns an object with the phone number, source, and content, or null if not found.
*/
function getPhoneNumberFromContent(content, sourceLabel) {
// Attempt to extract a valid phone number from the content
const phoneNumber = extractValidPhoneNumber(content);
if (phoneNumber) {
// Return the phone number, source label, and the original content
return { phoneNumber, source: sourceLabel, content: content };
} else {
// Return null if no valid phone number is found
return null;
}
}
try {
// Step 1: Retrieve the clipboard content first
// This ensures that BTT updates any internal states related to the clipboard and selection
const clipboardContent = await callBTT("get_clipboard_content", {});
// Step 2: Retrieve the selected text from BTT's variables
const selectionContent = await get_string_variable({
variable_name: "selected_text",
});
// Step 3: Attempt to get the phone number from the selection
const selectionResult = getPhoneNumberFromContent(
selectionContent,
"Selection"
);
// Step 4: If not found in selection, attempt to get from clipboard
const finalResult =
selectionResult ||
getPhoneNumberFromContent(clipboardContent, "Clipboard");
// Step 5: If no valid phone number is found, show an error dialog
if (!finalResult) {
await showDialog(
"Invalid Input",
`No valid phone number found.
Selection Content:
${selectionContent || "[No Selection]"}
Clipboard Content:
${clipboardContent || "[Clipboard is Empty]"}`
);
// Exit the script since there's no valid phone number to proceed with
return;
}
// Step 6: If debug mode is enabled, show debug information to the user
if (DEBUG) {
await showDialog(
"Debug Information",
`Source: ${finalResult.source}
Phone Number: ${finalResult.phoneNumber}`
);
}
// Step 7: Open WhatsApp with the valid phone number
// This constructs a shell command to open WhatsApp using the 'whatsapp://' URL scheme
const shellScriptOpenWhatsApp = `/usr/bin/open "whatsapp://send?phone=${finalResult.phoneNumber}"`;
// Execute the shell command to open WhatsApp
await runShellScript({ script: shellScriptOpenWhatsApp });
// Step 8: Return the valid phone number to BTT (optional)
// This can be used if you need to pass the phone number back to BTT for further actions
returnToBTT(finalResult.phoneNumber);
} catch (error) {
// If any error occurs during the execution of the script, show an error dialog to the user
await showDialog("Script Error", `An error occurred: ${error.message}`);
}
})();
ΠΡΠΎΠ΄Π΅ Π±Ρ ΠΏΠΎΠΊΠ° ΡΠ°Π±ΠΎΡΠ°Π΅Ρ, Π½ΡΠΆΠ½ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ.
ΠΠΎΠ΄ΡΠΊΠ°ΠΆΠΈΡΠ΅, ΠΊΠ°ΠΊ ΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ±ΡΠ°ΡΡ ΡΡΠΎ ΠΎΠΊΠ½ΠΎ?
English reply
I made some further modifications to the code to simplify it. I hope you'll be able to understand how it works.
π Click to see updated code (English version):
/**
* Script to Open WhatsApp with a Selected or Copied Phone Number
*
* **Description:**
* This script extracts a phone number from either the selected text or the clipboard,
* validates it according to the E.164 international format, and then opens WhatsApp
* to send a message to that number.
*
* **How to Use:**
* - Set up this script in BetterTouchTool (BTT) as a **"Run Real JavaScript"** action.
* - **Important:** This script will **not** work with other action types like
* "Transform & Copy Selection With JavaScript" or "Transform Clipboard Contents with JavaScript".
* - To use the script:
* 1. Select a phone number in any application, or copy it to the clipboard.
* 2. Trigger the BTT action that runs this script.
*
* **Turning Debug Mode On/Off:**
* - The `DEBUG` variable controls whether debug dialogs are shown.
* - Set `DEBUG = true` to enable debug mode (shows additional dialogs with information).
* - Set `DEBUG = false` to disable debug mode (no debug dialogs will appear).
*
* **Requirements:**
* - BetterTouchTool (BTT) version **4.867** or later.
* - WhatsApp MacOS app.
*
* **Author:** https://community.folivora.ai/u/fortred2
* **Date:** 2024-11-14
*/
(async function () {
// Enable or disable debug mode.
// Set to 'true' to show debug dialogs, or 'false' to hide them.
const DEBUG = false;
/**
* Displays a dialog box using AppleScript to show messages to the user.
* @param {string} title - The title of the dialog box.
* @param {string} message - The message content to display.
*/
async function showDialog(title, message) {
// Prepare the AppleScript command to display a dialog
const appleScript = `display dialog ${JSON.stringify(
message
)} with title ${JSON.stringify(
title
)} buttons {"OK"} default button "OK"`;
// Execute the AppleScript command to show the dialog
await runAppleScript(appleScript);
}
/**
* Validates a phone number against the E.164 international format.
* @param {string} phoneNumber - The phone number to validate.
* @returns {boolean} True if the phone number is valid, false otherwise.
*/
function isValidE164(phoneNumber) {
// Regular expression to match E.164 phone numbers
return /^\+?[1-9]\d{1,14}$/.test(phoneNumber);
}
/**
* Extracts a valid phone number from input text.
* Removes unwanted characters and checks if the number is valid.
* @param {string} input - The input text that may contain a phone number.
* @returns {string|null} The sanitized phone number if valid, or null if not.
*/
function extractValidPhoneNumber(input) {
// If input is null or empty, return null
if (!input) return null;
// Remove all characters except '+' and digits
const sanitized = input.replace(/[^+\d]/g, "");
// Check if the sanitized number is valid according to E.164 format
return isValidE164(sanitized) ? sanitized : null;
}
/**
* Attempts to extract a valid phone number from the provided content.
* @param {string} content - The content to extract the phone number from.
* @param {string} sourceLabel - Indicates the source ("Selection" or "Clipboard").
* @returns {Object|null} An object with the phone number, source, and content, or null if not found.
*/
function getPhoneNumberFromContent(content, sourceLabel) {
// Attempt to extract a valid phone number from the content
const phoneNumber = extractValidPhoneNumber(content);
if (phoneNumber) {
// Return the phone number, source label, and the original content
return { phoneNumber, source: sourceLabel, content: content };
} else {
// Return null if no valid phone number is found
return null;
}
}
try {
// Note: The following functions are provided by the BetterTouchTool (BTT) JavaScript environment:
// - callBTT
// - get_string_variable
// - runAppleScript
// - runShellScript
// - returnToBTT
// Step 1: Retrieve the clipboard content BEFORE getting 'selected_text'
const clipboardContent = await callBTT("get_clipboard_content", {});
// Step 2: Retrieve the selected text from BTT's variables
const selectionContent = await get_string_variable({
variable_name: "selected_text",
});
// Step 3: Attempt to get the phone number from the selection
const selectionResult = getPhoneNumberFromContent(
selectionContent,
"Selection"
);
// Step 4: If not found in selection, attempt to get from clipboard
const finalResult =
selectionResult ||
getPhoneNumberFromContent(clipboardContent, "Clipboard");
// Step 5: If no valid phone number is found, show an error dialog
if (!finalResult) {
await showDialog(
"Invalid Input",
`No valid phone number found.
Selection Content:
${selectionContent || "[No Selection]"}
Clipboard Content:
${clipboardContent || "[Clipboard is Empty]"}`
);
// Exit the script since there's no valid phone number to proceed with
return;
}
// Step 6: If debug mode is enabled, show debug information to the user
if (DEBUG) {
await showDialog(
"Debug Information",
`Source: ${finalResult.source}
Phone Number: ${finalResult.phoneNumber}`
);
}
// Step 7: Open WhatsApp with the valid phone number
// Constructs a shell command to open WhatsApp using the 'whatsapp://' URL scheme
const shellScriptOpenWhatsApp = `/usr/bin/open "whatsapp://send?phone=${finalResult.phoneNumber}"`;
// Execute the shell command to open WhatsApp
await runShellScript({ script: shellScriptOpenWhatsApp });
// Step 8: Return the valid phone number to BTT
// This is required for BTT to receive the phone number for further actions
returnToBTT(finalResult.phoneNumber);
} catch (error) {
// If any error occurs during execution, show an error dialog to the user
await showDialog("Script Error", `An error occurred: ${error.message}`);
}
})();
Let me know if you encounter any issues or bugs with the JavaScript. If you encounter an issue or bug, it would help me a lot if you shared a screen recordings. This makes identifying the cause a lot easier for me.
You can remove the debug window by setting DEBUG
to false
instead of true
in the script, like this:
const DEBUG = false;
ChatGPT helped me translate the message and the JavaScript into Russian. I hope this helps you understand the code. Please see below the Russian version of the JavaScript. I did some testing with both English and Russian versions and they appear to be working correctly.
Russian translation
Π― Π²Π½Π΅Ρ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΠΊΠΎΠ΄, ΡΡΠΎΠ±Ρ ΡΠΏΡΠΎΡΡΠΈΡΡ Π΅Π³ΠΎ. ΠΠ°Π΄Π΅ΡΡΡ, Π²Ρ ΡΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΠΎΠ½ΡΡΡ, ΠΊΠ°ΠΊ ΠΎΠ½ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ.
π Click to see updated code (Russian version):
/**
* Π‘ΠΊΡΠΈΠΏΡ Π΄Π»Ρ ΠΎΡΠΊΡΡΡΠΈΡ WhatsApp Ρ Π²ΡΠ±ΡΠ°Π½Π½ΡΠΌ ΠΈΠ»ΠΈ ΡΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½Π½ΡΠΌ Π½ΠΎΠΌΠ΅ΡΠΎΠΌ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°
*
* **ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅:**
* ΠΡΠΎΡ ΡΠΊΡΠΈΠΏΡ ΠΈΠ·Π²Π»Π΅ΠΊΠ°Π΅Ρ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° ΠΈΠ· Π²ΡΠ΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° ΠΈΠ»ΠΈ Π±ΡΡΠ΅ΡΠ° ΠΎΠ±ΠΌΠ΅Π½Π°,
* ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ Π΅Π³ΠΎ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄ΡΠ½Π°ΡΠΎΠ΄Π½ΠΎΠΌΡ ΡΠΎΡΠΌΠ°ΡΡ E.164, Π° Π·Π°ΡΠ΅ΠΌ ΠΎΡΠΊΡΡΠ²Π°Π΅Ρ WhatsApp
* Π΄Π»Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π½Π° ΡΡΠΎΡ Π½ΠΎΠΌΠ΅Ρ.
*
* **ΠΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ:**
* - ΠΠ°ΡΡΡΠΎΠΉΡΠ΅ ΡΡΠΎΡ ΡΠΊΡΠΈΠΏΡ Π² BetterTouchTool (BTT) ΠΊΠ°ΠΊ Π΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ **"Run Real JavaScript"**.
* - **ΠΠ°ΠΆΠ½ΠΎ:** ΠΡΠΎΡ ΡΠΊΡΠΈΠΏΡ **Π½Π΅** Π±ΡΠ΄Π΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ Π΄ΡΡΠ³ΠΈΠΌΠΈ ΡΠΈΠΏΠ°ΠΌΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΠΉ, ΡΠ°ΠΊΠΈΠΌΠΈ ΠΊΠ°ΠΊ
* "Transform & Copy Selection With JavaScript" ΠΈΠ»ΠΈ "Transform Clipboard Contents with JavaScript".
* - Π§ΡΠΎΠ±Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΊΡΠΈΠΏΡ:
* 1. ΠΡΠ΄Π΅Π»ΠΈΡΠ΅ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π² Π»ΡΠ±ΠΎΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ ΠΈΠ»ΠΈ ΡΠΊΠΎΠΏΠΈΡΡΠΉΡΠ΅ Π΅Π³ΠΎ Π² Π±ΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°.
* 2. ΠΠ°ΠΏΡΡΡΠΈΡΠ΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ BTT, ΠΊΠΎΡΠΎΡΠΎΠ΅ Π²ΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΡΡΠΎΡ ΡΠΊΡΠΈΠΏΡ.
*
* **ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΈ ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅ΠΆΠΈΠΌΠ° ΠΎΡΠ»Π°Π΄ΠΊΠΈ:**
* - ΠΠ΅ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ `DEBUG` ΠΊΠΎΠ½ΡΡΠΎΠ»ΠΈΡΡΠ΅Ρ, ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡΡΡ Π»ΠΈ ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΡΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΈ.
* - Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ `DEBUG = true`, ΡΡΠΎΠ±Ρ Π²ΠΊΠ»ΡΡΠΈΡΡ ΡΠ΅ΠΆΠΈΠΌ ΠΎΡΠ»Π°Π΄ΠΊΠΈ (ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°Π΅Ρ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΈ Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ).
* - Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ `DEBUG = false`, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ ΡΠ΅ΠΆΠΈΠΌ ΠΎΡΠ»Π°Π΄ΠΊΠΈ (ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΡΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΈ Π½Π΅ Π±ΡΠ΄ΡΡ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡΡΡ).
*
* **Π’ΡΠ΅Π±ΠΎΠ²Π°Π½ΠΈΡ:**
* - BetterTouchTool (BTT) Π²Π΅ΡΡΠΈΠΈ **4.867** ΠΈΠ»ΠΈ Π²ΡΡΠ΅.
* - WhatsApp Π΄Π»Ρ macOS.
*
* **ΠΠ²ΡΠΎΡ:** https://community.folivora.ai/u/fortred2
* **ΠΠ°ΡΠ°:** 2024-11-14
*/
(async function () {
// ΠΠΊΠ»ΡΡΠΈΡΡ ΠΈΠ»ΠΈ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ ΡΠ΅ΠΆΠΈΠΌ ΠΎΡΠ»Π°Π΄ΠΊΠΈ.
// Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ 'true', ΡΡΠΎΠ±Ρ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΡΠ΅ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΈ, ΠΈΠ»ΠΈ 'false', ΡΡΠΎΠ±Ρ ΡΠΊΡΡΡΡ ΠΈΡ
.
const DEBUG = false;
/**
* ΠΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅Ρ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΎΠ²ΠΎΠ΅ ΠΎΠΊΠ½ΠΎ Ρ ΠΏΠΎΠΌΠΎΡΡΡ AppleScript, ΡΡΠΎΠ±Ρ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ.
* @param {string} title - ΠΠ°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠΊΠ½Π°.
* @param {string} message - Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ.
*/
async function showDialog(title, message) {
// ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΈΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ AppleScript Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π΄ΠΈΠ°Π»ΠΎΠ³Π°
const appleScript = `display dialog ${JSON.stringify(
message
)} with title ${JSON.stringify(
title
)} buttons {"OK"} default button "OK"`;
// ΠΡΠΏΠΎΠ»Π½ΠΈΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ AppleScript Π΄Π»Ρ ΠΏΠΎΠΊΠ°Π·Π° Π΄ΠΈΠ°Π»ΠΎΠ³Π°
await runAppleScript(appleScript);
}
/**
* ΠΡΠΎΠ²Π΅ΡΡΠ΅Ρ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π½Π° ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄ΡΠ½Π°ΡΠΎΠ΄Π½ΠΎΠΌΡ ΡΠΎΡΠΌΠ°ΡΡ E.164.
* @param {string} phoneNumber - ΠΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π΄Π»Ρ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ.
* @returns {boolean} True, Π΅ΡΠ»ΠΈ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»Π΅Π½, ΠΈΠ½Π°ΡΠ΅ false.
*/
function isValidE164(phoneNumber) {
// Π Π΅Π³ΡΠ»ΡΡΠ½ΠΎΠ΅ Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΡ Π½ΠΎΠΌΠ΅ΡΠ°ΠΌ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π² ΡΠΎΡΠΌΠ°ΡΠ΅ E.164
return /^\+?[1-9]\d{1,14}$/.test(phoneNumber);
}
/**
* ΠΠ·Π²Π»Π΅ΠΊΠ°Π΅Ρ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° ΠΈΠ· Π²Ρ
ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ°.
* Π£Π΄Π°Π»ΡΠ΅Ρ Π½Π΅Π½ΡΠΆΠ½ΡΠ΅ ΡΠΈΠΌΠ²ΠΎΠ»Ρ ΠΈ ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ, ΡΠ²Π»ΡΠ΅ΡΡΡ Π»ΠΈ Π½ΠΎΠΌΠ΅Ρ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΌ.
* @param {string} input - ΠΡ
ΠΎΠ΄Π½ΠΎΠΉ ΡΠ΅ΠΊΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΠΎΠΆΠ΅Ρ ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΡ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°.
* @returns {string|null} ΠΡΠΈΡΠ΅Π½Π½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°, Π΅ΡΠ»ΠΈ ΠΎΠ½ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»Π΅Π½, ΠΈΠ»ΠΈ null, Π΅ΡΠ»ΠΈ Π½Π΅Ρ.
*/
function extractValidPhoneNumber(input) {
// ΠΡΠ»ΠΈ Π²Ρ
ΠΎΠ΄Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ ΠΏΡΡΡΡ ΠΈΠ»ΠΈ ΡΠ°Π²Π½Ρ null, Π²Π΅ΡΠ½ΡΡΡ null
if (!input) return null;
// Π£Π΄Π°Π»ΠΈΡΡ Π²ΡΠ΅ ΡΠΈΠΌΠ²ΠΎΠ»Ρ, ΠΊΡΠΎΠΌΠ΅ '+' ΠΈ ΡΠΈΡΡ
const sanitized = input.replace(/[^+\d]/g, "");
// ΠΡΠΎΠ²Π΅ΡΠΈΡΡ, ΡΠ²Π»ΡΠ΅ΡΡΡ Π»ΠΈ ΠΎΡΠΈΡΠ΅Π½Π½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΌ ΠΏΠΎ ΡΠΎΡΠΌΠ°ΡΡ E.164
return isValidE164(sanitized) ? sanitized : null;
}
/**
* ΠΡΡΠ°Π΅ΡΡΡ ΠΈΠ·Π²Π»Π΅ΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° ΠΈΠ· ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ³ΠΎ.
* @param {string} content - Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ Π΄Π»Ρ ΠΈΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΡ Π½ΠΎΠΌΠ΅ΡΠ° ΡΠ΅Π»Π΅ΡΠΎΠ½Π°.
* @param {string} sourceLabel - Π£ΠΊΠ°Π·ΡΠ²Π°Π΅Ρ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ ("ΠΡΠ΄Π΅Π»Π΅Π½ΠΈΠ΅" ΠΈΠ»ΠΈ "ΠΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°").
* @returns {Object|null} ΠΠ±ΡΠ΅ΠΊΡ Ρ Π½ΠΎΠΌΠ΅ΡΠΎΠΌ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°, ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΎΠΌ ΠΈ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΡΠΌ, ΠΈΠ»ΠΈ null, Π΅ΡΠ»ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ.
*/
function getPhoneNumberFromContent(content, sourceLabel) {
// ΠΠΎΠΏΡΡΠ°ΡΡΡΡ ΠΈΠ·Π²Π»Π΅ΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° ΠΈΠ· ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ³ΠΎ
const phoneNumber = extractValidPhoneNumber(content);
if (phoneNumber) {
// ΠΠ΅ΡΠ½ΡΡΡ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°, ΠΌΠ΅ΡΠΊΡ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠ° ΠΈ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅
return { phoneNumber, source: sourceLabel, content: content };
} else {
// ΠΠ΅ΡΠ½ΡΡΡ null, Π΅ΡΠ»ΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½
return null;
}
}
try {
// ΠΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΠ΅: Π‘Π»Π΅Π΄ΡΡΡΠΈΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡΡΡ ΡΡΠ΅Π΄ΠΎΠΉ JavaScript BetterTouchTool (BTT):
// - callBTT
// - get_string_variable
// - runAppleScript
// - runShellScript
// - returnToBTT
// Π¨Π°Π³ 1: ΠΠΎΠ»ΡΡΠΈΡΡ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ Π±ΡΡΠ΅ΡΠ° ΠΎΠ±ΠΌΠ΅Π½Π° ΠΠΠ ΠΠ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ΠΌ 'selected_text'
const clipboardContent = await callBTT("get_clipboard_content", {});
// Π¨Π°Π³ 2: ΠΠΎΠ»ΡΡΠΈΡΡ Π²ΡΠ΄Π΅Π»Π΅Π½Π½ΡΠΉ ΡΠ΅ΠΊΡΡ ΠΈΠ· ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ
BTT
const selectionContent = await get_string_variable({
variable_name: "selected_text",
});
// Π¨Π°Π³ 3: ΠΠΎΠΏΡΡΠ°ΡΡΡΡ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° ΠΈΠ· Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΡ
const selectionResult = getPhoneNumberFromContent(
selectionContent,
"ΠΡΠ΄Π΅Π»Π΅Π½ΠΈΠ΅"
);
// Π¨Π°Π³ 4: ΠΡΠ»ΠΈ Π² Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ, ΠΏΠΎΠΏΡΡΠ°ΡΡΡΡ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΈΠ· Π±ΡΡΠ΅ΡΠ° ΠΎΠ±ΠΌΠ΅Π½Π°
const finalResult =
selectionResult ||
getPhoneNumberFromContent(clipboardContent, "ΠΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π°");
// Π¨Π°Π³ 5: ΠΡΠ»ΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½, ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅
if (!finalResult) {
await showDialog(
"ΠΠ΅Π²Π΅ΡΠ½ΡΠΉ Π²Π²ΠΎΠ΄",
`ΠΠ΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½.
Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΡ:
${selectionContent || "[ΠΠ΅Ρ Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΡ]"}
Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ Π±ΡΡΠ΅ΡΠ° ΠΎΠ±ΠΌΠ΅Π½Π°:
${clipboardContent || "[ΠΡΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½Π° ΠΏΡΡΡ]"}`
);
// ΠΡΠΉΡΠΈ ΠΈΠ· ΡΠΊΡΠΈΠΏΡΠ°, ΡΠ°ΠΊ ΠΊΠ°ΠΊ Π½Π΅Ρ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ³ΠΎ Π½ΠΎΠΌΠ΅ΡΠ° ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π΄Π»Ρ ΠΏΡΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΈΡ
return;
}
// Π¨Π°Π³ 6: ΠΡΠ»ΠΈ ΡΠ΅ΠΆΠΈΠΌ ΠΎΡΠ»Π°Π΄ΠΊΠΈ Π²ΠΊΠ»ΡΡΠ΅Π½, ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΠΎΡΠ»Π°Π΄ΠΎΡΠ½ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ
if (DEBUG) {
await showDialog(
"ΠΡΠ»Π°Π΄ΠΎΡΠ½Π°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ",
`ΠΡΡΠΎΡΠ½ΠΈΠΊ: ${finalResult.source}
ΠΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°: ${finalResult.phoneNumber}`
);
}
// Π¨Π°Π³ 7: ΠΡΠΊΡΡΡΡ WhatsApp Ρ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΌ Π½ΠΎΠΌΠ΅ΡΠΎΠΌ ΡΠ΅Π»Π΅ΡΠΎΠ½Π°
// Π‘ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΊΠΎΠΌΠ°Π½Π΄Ρ shell Π΄Π»Ρ ΠΎΡΠΊΡΡΡΠΈΡ WhatsApp Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΡΡ
Π΅ΠΌΡ URL 'whatsapp://'
const shellScriptOpenWhatsApp = `/usr/bin/open "whatsapp://send?phone=${finalResult.phoneNumber}"`;
// ΠΡΠΏΠΎΠ»Π½ΠΈΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ shell Π΄Π»Ρ ΠΎΡΠΊΡΡΡΠΈΡ WhatsApp
await runShellScript({ script: shellScriptOpenWhatsApp });
// Π¨Π°Π³ 8: ΠΠ΅ΡΠ½ΡΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π² BTT
// ΠΡΠΎ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ, ΡΡΠΎΠ±Ρ BTT ΠΏΠΎΠ»ΡΡΠΈΠ» Π½ΠΎΠΌΠ΅Ρ ΡΠ΅Π»Π΅ΡΠΎΠ½Π° Π΄Π»Ρ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠΈΡ
Π΄Π΅ΠΉΡΡΠ²ΠΈΠΉ
returnToBTT(finalResult.phoneNumber);
} catch (error) {
// ΠΡΠ»ΠΈ Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡ ΠΎΡΠΈΠ±ΠΊΠ°, ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π΄ΠΈΠ°Π»ΠΎΠ³ΠΎΠ²ΠΎΠ΅ ΠΎΠΊΠ½ΠΎ Ρ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ
await showDialog("ΠΡΠΈΠ±ΠΊΠ° ΡΠΊΡΠΈΠΏΡΠ°", `ΠΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΎΡΠΈΠ±ΠΊΠ°: ${error.message}`);
}
})();
Π‘ΠΎΠΎΠ±ΡΠΈΡΠ΅ ΠΌΠ½Π΅, Π΅ΡΠ»ΠΈ Π²Ρ ΡΡΠΎΠ»ΠΊΠ½Π΅ΡΠ΅ΡΡ Ρ ΠΊΠ°ΠΊΠΈΠΌΠΈ-Π»ΠΈΠ±ΠΎ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠ°ΠΌΠΈ ΠΈΠ»ΠΈ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ Π² JavaScript. ΠΡΠ»ΠΈ Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠ° ΠΈΠ»ΠΈ ΠΎΡΠΈΠ±ΠΊΠ°, ΠΌΠ½Π΅ ΠΎΡΠ΅Π½Ρ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ, Π΅ΡΠ»ΠΈ Π²Ρ ΠΏΠΎΠ΄Π΅Π»ΠΈΡΠ΅ΡΡ Π·Π°ΠΏΠΈΡΡΠΌΠΈ ΡΠΊΡΠ°Π½Π°. ΠΡΠΎ Π·Π½Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΎΠ±Π»Π΅Π³ΡΠΈΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΈΡΠΈΠ½Ρ.
ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΡΠ±ΡΠ°ΡΡ ΠΎΠΊΠ½ΠΎ ΠΎΡΠ»Π°Π΄ΠΊΠΈ, ΡΡΡΠ°Π½ΠΎΠ²ΠΈΠ² DEBUG
Π² Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ false
Π²ΠΌΠ΅ΡΡΠΎ true
Π² ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ:
const DEBUG = false;
Π― Π²Π½Π΅Ρ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΠΊΠΎΠ΄, ΡΡΠΎΠ±Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΡΡΠΎ ΠΏΡΠΎΡΠ΅. ΠΠ°Π΄Π΅ΡΡΡ, Π²Ρ ΠΏΠΎΠΉΠΌΠ΅ΡΠ΅, ΠΊΠ°ΠΊ ΠΎΠ½ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ.
ChatGPT ΠΏΠΎΠΌΠΎΠ³ ΠΌΠ½Π΅ ΠΏΠ΅ΡΠ΅Π²Π΅ΡΡΠΈ ΡΡΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΈ JavaScript Π½Π° ΡΡΡΡΠΊΠΈΠΉ ΡΠ·ΡΠΊ. ΠΠ°Π΄Π΅ΡΡΡ, ΡΡΠΎ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ Π²Π°ΠΌ ΠΏΠΎΠ½ΡΡΡ ΠΊΠΎΠ΄.
Π― ΠΏΡΠΎΠ²Π΅Π» Π½Π΅ΠΊΠΎΡΠΎΡΠΎΠ΅ ΠΎΠ±ΡΡΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΊΠ°ΠΊ Ρ Π°Π½Π³Π»ΠΈΠΉΡΠΊΠΎΠΉ, ΡΠ°ΠΊ ΠΈ Ρ ΡΡΡΡΠΊΠΎΠΉ Π²Π΅ΡΡΠΈΠ΅ΠΉ JavaScript, ΠΈ ΠΎΠ½ΠΈ, ΠΊΠ°ΠΆΠ΅ΡΡΡ, ΡΠ°Π±ΠΎΡΠ°ΡΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ.
Thank you very much.
My first impression is that everything works.
I will test it and give you feedback