### Instagram Navigation Steps Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Provides step-by-step instructions on how to navigate Instagram to access the follower list for use with the Sky Follower Bridge extension. ```APIDOC 1. Navigate to Instagram Visit any of Instagram's following tab: 1. Open profile page 2. Click 'following' text 3. Show dialog ``` -------------------------------- ### Keyboard Shortcut for Extension Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Describes the keyboard shortcut to launch the Sky Follower Bridge extension. It also provides a tip for Firefox users. ```APIDOC Usage: Launch Sky Follower Bridge Either press `Alt + B` or click the extension icon in your browser toolbar. TIP: For Firefox users, pressing `Alt + B` may not work. In that case, click the extension icon in the browser toolbar. See: https://support.mozilla.org/en-US/kb/extensions-button ``` -------------------------------- ### Scanning and Reviewing Results Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Explains how to initiate the search for matching Bluesky profiles and how to view the results found by the Sky Follower Bridge extension. ```APIDOC 4. Start the Search Click "Find Bluesky Users" to begin scanning. The extension will search for matching Bluesky profiles by checking the Bluesky API. 5. Review Results Click "View Results" to see potential matches found on Bluesky. This will open the options page showing all detected Bluesky users. ``` -------------------------------- ### Platform Detection Script Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Detects if the user is on a Mac or iOS device and adds a 'mac' class to the document element for platform-specific styling. ```javascript document.documentElement.classList.toggle('mac', /Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### VitePress Theme Appearance and Platform Detection Source: https://sky-follower-bridge.dev/get-started-for-threads.html Manages the website's theme appearance based on user preference or system settings, and detects the user's platform (e.g., Mac, iPhone) to apply platform-specific styling. ```javascript const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark"); document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### Theme Appearance and Platform Detection Source: https://sky-follower-bridge.dev/get-started-for-tiktok.html Manages the website's appearance settings based on user preferences stored in local storage and system's dark mode preference. It also detects the operating system to apply specific styling for macOS users. ```javascript (function(){const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})(); document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### Keyboard Shortcut for Extension Source: https://sky-follower-bridge.dev/get-started-for-facebook.html Instructions for users on how to activate the Sky Follower Bridge extension using a keyboard shortcut. It notes a potential issue for Firefox users and suggests an alternative. ```text Either press `Alt + B` or click the extension icon in your browser toolbar. For Firefox users, pressing `Alt + B` may not work. In that case, click the extension icon in the browser toolbar. ``` -------------------------------- ### Build and Package Extension (Option 1) Source: https://github.com/kawamataryo/sky-follower-bridge Instructions for cloning the repository, installing Node.js dependencies, creating a .env file to specify the Bluesky domain, and building/packaging the extension for Chrome and Firefox. ```shell git clone https://github.com/kawamataryo/sky-follower-bridge.git cd sky-follower-bridge npm install echo "PLASMO_PUBLIC_BSKY_DOMAIN=bsky.social" > .env # For Chrome npm run build npm run package # For Firefox npm run build:firefox npm run package:firefox ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/kawamataryo/sky-follower-bridge/blob/main/README Installs all necessary project dependencies using npm. This command should be run after cloning the repository and before building the extension. ```shell npm install ``` -------------------------------- ### Clone and Navigate Sky Follower Bridge Repository Source: https://github.com/kawamataryo/sky-follower-bridge/blob/main/README Steps to clone the Sky Follower Bridge project repository from GitHub and navigate into the project directory. This is the initial setup step for building the extension. ```shell git clone https://github.com/kawamataryo/sky-follower-bridge.git cd sky-follower-bridge ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/get-started-for-facebook.html Initializes Google Tag Manager (GTM) by asynchronously loading the GTM script. This snippet is typically found in website headers to enable tracking and analytics. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[],t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/get-started-for-threads.html Initializes Google Tag Manager by creating a dataLayer array and asynchronously loading the GTM script. This is used for website analytics and tracking. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[];t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/get-started-for-tiktok.html Initializes Google Tag Manager for website analytics and tracking. It dynamically creates a script tag to load the GTM container. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[],t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Bluesky Sign-in Credentials Source: https://sky-follower-bridge.dev/get-started-for-facebook.html Guidance on entering Bluesky credentials for the Sky Follower Bridge extension. It specifies the required inputs: Bluesky handle (or email) and an App password. ```text Enter your Bluesky handle (or email) and [App password](https://bsky.app/settings/app-passwords). ``` -------------------------------- ### VitePress Theme Appearance Script Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Handles the theme appearance (light/dark mode) based on user preference stored in localStorage or system settings. It adds a 'dark' class to the document element if dark mode is enabled. ```javascript (() => { const e = localStorage.getItem('vitepress-theme-appearance') || 'auto'; const a = window.matchMedia('(prefers-color-scheme: dark)').matches; (!e || e === 'auto' ? a : e === 'dark') && document.documentElement.classList.add('dark'); })(); ``` -------------------------------- ### Platform Detection Script Source: https://sky-follower-bridge.dev/get-started-for-facebook.html Detects the user's operating system platform (specifically checking for macOS-like environments) and adds a 'mac' class to the documentElement if detected. This is often used for platform-specific styling or behavior. ```javascript document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### Theme Appearance and Platform Detection Source: https://sky-follower-bridge.dev/get-started.html This JavaScript code snippet handles the theme appearance (light/dark mode) based on user preference or system settings and detects the user's platform (e.g., Mac, iPhone). ```javascript (function(){const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})(); document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### Bluesky Sign-in Credentials Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Details the information required to sign into Bluesky via the Sky Follower Bridge extension, including the handle and App Password. ```APIDOC 3. Sign in to Bluesky Enter your Bluesky handle (or email) and [App password](https://bsky.app/settings/app-passwords). TIP: If you encounter login errors, please refer to the [Troubleshooting Guide](/troubleshooting.html). ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/get-started-for-instagram.html Initializes Google Tag Manager (GTM) with the provided ID and configuration. This script is typically used for website analytics and tracking. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[],t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/get-started.html Initializes Google Tag Manager for tracking page views and events. This script is typically found in the `` section of a web page. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[],t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Theme Appearance Script Source: https://sky-follower-bridge.dev/get-started-for-facebook.html This script manages the website's theme appearance based on user preference stored in localStorage or system settings. It adds a 'dark' class to the documentElement if the theme is set to dark or auto-detects dark mode. ```javascript (()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})(); ``` -------------------------------- ### Modal Steps Plugin Initialization (Buy Commission) Source: https://ko-fi.com/kawamataryo Initializes the 'modalSteps' plugin for '#buyCommissionModal'. It configures button labels, validation logic in the 'completeCallback' (checking contact details and seller terms), and calls specific setup functions for steps. ```javascript $('#buyCommissionModal').modalSteps({ btnCancelHtml: "Cancel", btnPreviousHtml: "Back", btnNextHtml: "Next >", btnLastStepHtml: "Go to Payment", closeOnConfirm: false, disableNextButton: false, completeCallback: function (e) { if (($('#contactDetails').val() == "")) { swal("", "Please give your contact details."); e.preventDefault(); e.stopImmediatePropagation(); return false; } if (!($('#commissionsAgreeToSeller').is(":checked"))) { swal("", "Please accept the seller terms"); e.preventDefault(); e.stopImmediatePropagation(); return false; } else { $(".commissionRequestForm").submit(); showSpinner(); } }, callbacks: { '1': doFirstStepSetup, '2': doSecondStepSetup }, getTitleAndStep: function () {} }); function doFirstStepSetup() { $("#commsNextBtn").hide(); } function doSecondStepSetup() { $("#commsNextBtn").show(); } ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/kawamataryo/sky-follower-bridge Command to install all necessary Node.js dependencies for the Sky Follower Bridge project using npm. This step is crucial before running or building the project. ```shell npm install ``` -------------------------------- ### Bluesky Authentication and Rate Limit Guidance Source: https://sky-follower-bridge.dev/troubleshooting.html Provides guidance on common Bluesky API errors, including authentication issues like incorrect username format or password usage, and rate limit errors. It details the structure of app passwords and the point system for API usage. ```APIDOC Bluesky API Troubleshooting: Authentication Errors: - Login Issues: - Error Message: Error: Invalid identifier or password - Common Mistakes: - Username format: Must be `your-username.bsky.social`. Missing `.bsky.social` is a common error. - Password: Use an App Password (19 characters, e.g., `xxxx-xxxx-xxxx-xxxx`) instead of the regular password. - App Password Creation: 1. Navigate to App Passwords section: https://bsky.app/settings/app-passwords 2. Click "Add App Password" 3. Click "Create App Password" 4. Copy the generated 19-character password. Do not confuse it with the 'password name'. Rate Limit Errors: - Error Message: Error: Rate limit error - Bluesky API Limits (Official Documentation: https://docs.bsky.app/docs/advanced-guides/rate-limits): - Per Hour: Up to 5,000 points (approx. 1,666 new actions) - Per Day: Up to 35,000 points - Points per Action: - Create: 3 points - Update: 2 points - Delete: 1 point - Solution: - Wait for the limit to reset. - Click the "Restart" button to try again. - Recommendations: - Firefox version may frequently encounter rate limit errors; try Chrome. - Most users won't hit limits during normal usage, but be mindful of bulk actions (following many users, liking many posts quickly). ``` -------------------------------- ### Clone Repository and Navigate Source: https://github.com/kawamataryo/sky-follower-bridge Instructions to clone the Sky Follower Bridge repository from GitHub and navigate into the project directory. This is the first step for setting up the project locally. ```shell git clone https://github.com/kawamataryo/sky-follower-bridge.git cd sky-follower-bridge ``` -------------------------------- ### Initiate Onboarding Helper Source: https://ko-fi.com/kawamataryo A utility function to initialize an onboarding instance, setting the intent, payload, and pre-filled user details. It handles optional parameters for email and display name, returning the configured instance. ```javascript initiateOnboarding: function (intent, payload, prefilledEmail, prefilledDisplayName) { var instance = this.renderAsModal(); instance.intent = intent; if (payload != null) { instance.intentPayload = payload; } if (prefilledEmail != null) { instance.emailSignup.email = prefilledEmail; } if (prefilledDisplayName != null) { instance.emailSignup.displayName = prefilledDisplayName; } return instance; } ``` -------------------------------- ### Build and Package Sky Follower Bridge Extension Source: https://github.com/kawamataryo/sky-follower-bridge/blob/main/README Commands to build and package the extension for different browsers. Includes steps for Chrome and Firefox builds and packaging. ```shell # For Chrome npm run build npm run package # For Firefox npm run build:firefox npm run package:firefox ``` -------------------------------- ### Build and Package Extension (Option 2) Source: https://github.com/kawamataryo/sky-follower-bridge Demonstrates how to build and package the extension for Chrome and Firefox by directly passing the Bluesky domain as an environment variable during the build process, bypassing the need for a .env file. ```shell # For Chrome PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run build PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run package # For Firefox PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run build:firefox PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run package:firefox ``` -------------------------------- ### Instant Sign-Up Experience Management (JavaScript) Source: https://ko-fi.com/kawamataryo Manages the rendering and behavior of instant sign-up experiences, both inline and as modals. It handles instance management, dynamic content injection, and setting specific intents for onboarding flows. It uses JavaScript and interacts with DOM elements. ```javascript var instantSignUp = { instances: [], // Stores active instances renderInlineExperience: function (elementId, showHeaders) { var existingInstance = this.instances.find(function (i) { return i.elementId == elementId }); if (existingInstance != null) { existingInstance.instance.$destroy(); // Destroy previous instance if exists } if (showHeaders == null) showHeaders = true; var targetElement = document.getElementById(elementId); targetElement.innerHTML = ""; // Clear existing content var sourceElement = document.getElementById("instant-signup-wrapper").innerHTML; var uniqueId = (new Date()).getTime(); sourceElement = sourceElement.replace('%INSTANCE_ID%', uniqueId); targetElement.innerHTML = sourceElement; var instance = this.renderInstance("#instant-signup-experience-" + uniqueId, false, showHeaders); this.instances.push({ elementId: elementId, instance: instance }); return instance; }, renderAsModal: function () { var elementId = "instant-signup-modal"; var existingInstance = this.instances.find(function (i) { return i.elementId == elementId }); if (existingInstance != null) { existingInstance.instance.$destroy(); // Destroy previous instance if exists } var targetElement = document.getElementById(elementId); targetElement.innerHTML = ""; // Clear existing content var sourceElement = document.getElementById("instant-signup-wrapper").innerHTML; var uniqueId = (new Date()).getTime(); sourceElement = sourceElement.replace('%INSTANCE_ID%', uniqueId); targetElement.innerHTML = sourceElement; var instance = this.renderInstance("#instant-signup-experience-" + uniqueId, true, true); this.instances.push({ elementId: elementId, instance: instance }); return instance; }, onboardIntoCreatorFromGuestTransactionManagement: function (transactionId, prefilledEmail, prefilledDisplayName) { var instance = this.renderAsModal(); instance.intent = 'onboard_from_guest_management_screen'; instance.intentPayload = transactionId; instance.emailSignup.email = prefilledEmail; instance.emailSignup.displayName = prefilledDisplayName; }, onboardIntoCreatorFromCoffeeShop: function (transactionId, prefilledEmail, prefilledDisplayName) { var instance = this.renderAsModal(); instance.intent = 'onboard_from_coffeeshop'; instance.intentPayload = transactionId; instance.emailSignup.email = prefilledEmail; instance.emailSignup.displayName = prefilledDisplayName; }, onboardIntoDirectMessageFromCoffeeShop: function (transactionId, prefilledEmail, prefilledDisplayName) { var instance = this.renderAsModal(); instance.intent = 'onboard_into_direct_message_from_coffee'; instance.intentPayload = transactionId; instance.emailSignup.email = prefilledEmail; instance.emailSignup.displayName = prefilledDisplayName; } // Note: The provided text was truncated, so additional methods might exist. } ``` -------------------------------- ### Get Captcha Source: https://ko-fi.com/kawamataryo A placeholder function to retrieve a captcha. It logs the container ID and returns null, indicating it's a stub for captcha retrieval. ```javascript async function getCaptcha(containerId) { console.log("Dummy getCaptcha: " + containerId); return null; } ``` -------------------------------- ### Page Load Tracking Source: https://ko-fi.com/kawamataryo Sends an AJAX GET request to '/buttons/PageLoaded' with a specific pageId when the window has finished loading. This is likely for analytics or tracking page views. ```javascript $(window).load(function () { try { $.get("/buttons/PageLoaded?pageId=X8X315UWFN", function (data) { console.log("PL:1"); }); } catch (err) { console.log("PL:0"); } }); ``` -------------------------------- ### Onboarding Functions Source: https://ko-fi.com/kawamataryo Provides various functions to initiate user onboarding processes for different scenarios like connecting Discord, signing up after guest checkout, or engaging with polls. These functions prepare modal instances with specific intents and payloads. ```javascript onboardIntoDirectMessageFromProfilePage: function (pageId) { var instance = this.renderAsModal(); instance.intent = 'onboard_into_direct_message_from_profile_page'; instance.intentPayload = pageId; }, onboardIntoConnectDiscordFromCoffeeShop: function (transactionId, prefilledEmail, prefilledDisplayName) { var instance = this.renderAsModal(); instance.intent = 'onboard_into_connect_discord_from_coffeeshop'; instance.intentPayload = transactionId; instance.emailSignup.email = prefilledEmail; instance.emailSignup.displayName = prefilledDisplayName; }, onboardIntoCreatorAfterGuestCheckout: function (prefilledEmail, prefilledDisplayName) { var instance = this.initiateOnboarding('onboard_from_creator_page_after_geust_checkout', null, prefilledEmail, prefilledDisplayName); instance.subheader = 'Create an account to start a conversation, unlock supporter thank-yous and much more...'; }, onboardIntoDirectMessageFromBrowseCommission: function (target) { let shopCommissionItemId = target.getAttribute('data-shop-commission-item-id'); var instance = this.renderAsModal(); instance.subheader = "Send direct messages to " + "ryo kawamata"; instance.intent = 'onboard_into_direct_message_from_browse_commission'; instance.intentPayload = shopCommissionItemId; }, onboardIntoPoll: function (pollSlug) { var instance = this.renderAsModal(); instance.subheader = "Log in or sign up to vote on " + "ryo kawamata" + "'s poll."; instance.intent = 'onboard_into_poll'; instance.intentPayload = pollSlug; } ``` -------------------------------- ### Create .env File for Custom Configuration Source: https://github.com/kawamataryo/sky-follower-bridge Guidance on creating a '.env' file in the project's root directory to manage environment-specific configurations, such as custom Bluesky domains. ```shell touch .env ``` -------------------------------- ### Error Handling and Feedback Source: https://ko-fi.com/kawamataryo Provides examples of displaying error messages to the user using `swal` (SweetAlert) and `toastr` notifications, along with logging to the console. Also includes hiding loading spinners. ```javascript // Example of handling a successful response with potential errors // ... inside an AJAX success callback ... if (response.responseText) { // ... Stripe checkout logic ... } else { console.log(response.responseText); toastr.error(response.responseText); $(".loading-spinner-center").hide(); } // Example of handling an AJAX error // ... inside an AJAX error callback ... $(".loading-spinner-center").hide(); console.log(response.responseText); toastr.error(response.responseText); ``` -------------------------------- ### Social Sharing URL Generation Source: https://ko-fi.com/kawamataryo These are examples of URLs constructed for sharing content on social media platforms like Twitter and Facebook. They include parameters for the URL to share and associated text or quotes. ```javascript [ "http://twitter.com/intent/tweet?url=https%3a%2f%2fko-fi.com%2fkawamataryo%2fgoal%3fg%3d8&text=%f0%9f%9f%a9%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c+8%25+of+goal+on+Ko-fi!", "http://www.facebook.com/sharer.php?u=https%3a%2f%2fko-fi.com%2fkawamataryo%2fgoal%3fg%3d8"e=%f0%9f%9f%a9%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c%e2%ac%9c+8%25+of+goal+on+Ko-fi!" ] ``` -------------------------------- ### Google Tag Manager Initialization Source: https://sky-follower-bridge.dev/troubleshooting.html Initializes Google Tag Manager for website analytics and tracking. This script is typically found in the head of a webpage. ```javascript (function(t,n,r,e,m){t[e]=t[e]||[],t[e].push({"gtm.start":new Date().getTime(),event:"gtm.js"});var g=n.getElementsByTagName(r)[0],a=n.createElement(r),s=e!="dataLayer"?"&l="+e:"";a.async=!0,a.src="https://www.googletagmanager.com/gtm.js?id="+m+s,g.parentNode.insertBefore(a,g)})(window,document,"script","dataLayer","GTM-N9HZN4NL"); ``` -------------------------------- ### Platform Detection Script Source: https://sky-follower-bridge.dev/troubleshooting.html Detects if the user is on a Mac or iOS device and adds a 'mac' class to the document element for potential styling or behavioral adjustments. ```javascript document.documentElement.classList.toggle("mac", /Mac|iPhone|iPod|iPad/i.test(navigator.platform)); ``` -------------------------------- ### Initialize PayPal Marketplace and Billing Agreements Source: https://ko-fi.com/kawamataryo Initializes PayPal marketplace or billing agreement buttons. Includes logic for guest checkout email validation, enabling/disabling buttons, and handling payment approval or cancellation. ```JavaScript initializePayPalMarketplace: function () { var that = this; setTimeout(function () { var config = { style: { layout: 'vertical', color: 'gold' }, onClick: function (data, actions) { if (!that.validateIfGuestCheckoutInformationIsFilledInIfRequired('PAYPAL_MARKETPLACE_SPB', false, false)) { return actions.reject(); } that.paymentMethodsContext.fundingSource = data.fundingSource; return actions.resolve(); }, onInit: function (data, actions) { if (that.isGuestCheckout) { try { if ($('#GuestEmail-' + that.instanceId).val().indexOf('.') > -1) { console.log('autofilled'); actions.enable(); } else { actions.disable(); } } catch (err) { console.log(err); } document.querySelector('#GuestEmail-' + that.instanceId) .addEventListener('input', function (event) { if (that.validateIfGuestCheckoutInformationIsFilledInIfRequired('PAYPAL_MARKETPLACE_SPB', false, true)) { actions.enable(); } else { actions.disable(); } }); } }, onApprove: function (data, actions) { return that.performPayPalPaymentApproval(data, actions, 'PAYPAL_MARKETPLACE_SPB'); }, onCancel: function (data) { that.showPaymentInterrupted(); }, }; var flow = that.donationPanel.isMembershipOrSubscription ? 'PAYPAL_BILLING_AGREEMENT' : 'PAYPAL_MARKETPLACE_SPB'; var checkoutFunction = function (data, actions) { return that.initiateTransactionCheckout(flow).then(function (data) { return data != null ? data.id : null; }); }; if (!that.donationPanel.isMembershipOrSubscription) { config.createOrder = checkoutFunction; } else { config.createBillingAgreement = checkoutFunction; } paypal.Buttons(config).render(elementToMount + ' #paypal-button-container'); }, 50); } ``` -------------------------------- ### Modal Steps Plugin Initialization (Give Gold) Source: https://ko-fi.com/kawamataryo Initializes the 'modalSteps' plugin for the '#giveGoldModal'. It configures button labels and sets a 'completeCallback' function that submits the '.giveGoldForm' and shows a spinner. ```javascript $('#giveGoldModal').modalSteps({ btnCancelHtml: "Cancel", btnPreviousHtml: "Previous", btnNextHtml: "Next", btnLastStepHtml: "Buy Now", disableNextButton: false, completeCallback: function () { $(".giveGoldForm").submit(); showSpinner(); }, callbacks: {}, getTitleAndStep: function () {} }); ``` -------------------------------- ### Load More Feed Functionality Source: https://ko-fi.com/kawamataryo Fetches and appends more feed items to the page using an AJAX GET request. It handles query string parameters for 'useIframely' and appends loaded HTML content to a specific div, hiding a loading indicator. ```javascript function showMoreFeed(start) { var useIframelyQS = getQueryStringByName("useiframely"); var iframelyQS = useIframelyQS ? "?useiframely=" + useIframelyQS : ""; var data = { buttonId: 'X8X315UWFN', start: start }; $.ajax({ url: '/Buttons/LoadPageFeed' + iframelyQS, type: "GET", dataType: "html", data: data, //cache: false, success: function (data) { $("#feedContainerDiv").append(data); $('#feedLoading').hide(); }, error: function (xhr, status, error) { //toastr.error('Error loading page feed.'); $('#feedLoading').hide(); } }); } ``` -------------------------------- ### Email/Password Sign Up and Login (JavaScript) Source: https://ko-fi.com/kawamataryo Handles the process of signing up or logging in a user using email and password. It integrates with a CAPTCHA service (e.g., Turnstile) and makes an AJAX POST request to `/Onboarding/EmailPasswordSignUp`. It manages UI states like button text, spinner, and error messages, and handles redirection or email verification flow based on the API response. ```javascript signUpWithEmailAndPassword: function () { if (this.emailSignup.isNewUser) { $('#instant-sign-up-continue-button').val("Creating account..."); } else { $('#instant-sign-up-continue-button').val("Logging in..."); } document.getElementById('instant-sign-up-continue-button').disabled = true; showSpinner(); var that = this; getCaptcha('turnstile-instant-sign-up').then(that.doEmailPasswordSignUp) }, doEmailPasswordSignUp: function (token) { trackCustomEvent("instant_sign_in_clicked_email_method", "email"); this.emailSignup.errors = []; var that = this; $.ajax({ type: "POST", ajaxasync: true, cache: false, data: { //__RequestVerificationToken: $(".ds-c-email-form .token input").val(), Name: that.emailSignup.displayName, UserName: that.emailSignup.email, Password: that.emailSignup.password, AcceptTerms: that.emailSignup.termsAccepted, CaptchaToken: token }, url: "/Onboarding/EmailPasswordSignUp?intent=" + that.intent + "&intentPayload=" + that.intentPayload, success: function (response) { if (response.success == false) { hideSpinner(); that.emailSignup.errors.push(response.friendly_error_message); return; } that.redirect_url = response.redirect_url; if (response.redirect_url != null && response.redirect_url != '/') { window.location.href = response.redirect_url; return; } if (response.activation_email_sent == true) { hideSpinner(); that.onboarded = true; that.emailVerification.code = [null, null, null, null]; that.emailVerification.show = true; return; } if (response.success == true) { that.onboarded = true; that.handleModalClose(); } }, error: function () { // Handle AJAX error } }); } ``` -------------------------------- ### Build and Package Extension Source: https://github.com/kawamataryo/sky-follower-bridge Commands to build and package the extension for both Chrome and Firefox. It involves running npm scripts for building and creating distributable packages. ```shell # For Chrome npm run build npm run package # For Firefox npm run build:firefox npm run package:firefox ``` -------------------------------- ### Load Page Feed via AJAX Source: https://ko-fi.com/kawamataryo Fetches and displays the page feed using jQuery's AJAX GET method. It supports an optional 'useiframely' query parameter and handles the display of feed content, loading indicators, and embeds from Instagram. ```javascript function loadPageFeed() { var deferred = $.Deferred(); var useIframelyQS = getQueryStringByName("useiframely"); var iframelyQS = useIframelyQS ? "?useiframely=" + useIframelyQS : ""; var data = { buttonId: 'X8X315UWFN' }; $.ajax({ url: '/Buttons/LoadPageFeed' + iframelyQS, type: "GET", dataType: "html", data: data, /*cache: false,*/ success: function (data) { $("#feedContainerDiv").html(data); $('#feedLoading').hide(); if (window.instgrm) { window.instgrm.Embeds.process(); } deferred.resolve(); }, error: function (xhr, status, error) { //toastr.error('Error loading page feed.'); $('#feedLoading').hide(); deferred.resolve(); } }); return deferred.promise(); } ``` -------------------------------- ### Handle YouTube Embed Player Events Source: https://ko-fi.com/kawamataryo Attaches event listeners to YouTube embeds to manage player states. It supports pausing other videos when one starts playing and logging pause events. It uses a closure to manage callbacks and iframe IDs. ```javascript function assignYouTubeEmbedListeners() { return; var addYouTubeEventListener = (function () { var callbacks = []; var iframeId = 0; return function (iframe, callback) { if (iframeId === 0) { window.addEventListener("message", function (e) { if (e.origin !== "https://www.youtube.com" || e.data === undefined) return; try { var data = JSON.parse(e.data); if (data.event !== 'onStateChange') return; var callback = callbacks[data.id]; callback(data); } catch (e) { } }); } // store callback iframeId++; callbacks[iframeId] = callback; var currentFrameId = iframeId; // sendMessage to frame to start receiving messages iframe.addEventListener("load", function () { var message = JSON.stringify({ event: 'listening', id: currentFrameId, channel: 'widget' }); iframe.contentWindow.postMessage(message, 'https://www.youtube.com'); message = JSON.stringify({ event: "command", func: "addEventListener", args: ["onStateChange"], id: currentFrameId, channel: "widget" }); iframe.contentWindow.postMessage(message, 'https://www.youtube.com'); }); } })(); for (const embed of document.getElementsByClassName("youtube-embed")) { addYouTubeEventListener(embed, function (e) { switch (e.info) { case 0: break; case 1: var youTubeEmbeds = $('.youtube-embed'); for (let i = 0; i < youTubeEmbeds.length; i++) { if (i === e.id - 1) { continue; } youTubeEmbeds[i].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*'); } break; case 2: console.log('paused youtube'); break; } }); }; } ``` -------------------------------- ### Load Top Supporters via AJAX Source: https://ko-fi.com/kawamataryo Fetches and displays top supporters using jQuery's AJAX GET method. It sends specific data including a buttonId and handle, updating a designated container and hiding a loading indicator upon success. ```javascript function loadTopSupporters() { var data = { buttonId: 'X8X315UWFN', handle: 'kawamataryo' }; $.ajax({ url: '/Buttons/LoadTopSupporters', type: "GET", dataType: "html", data: data, cache: false, success: function (data) { $(".topsupporterscontainerdiv").html(data); $('.topSupportersLoading').hide(); }, error: function (xhr, status, error) { $('.topsupporterscontainerdiv').hide(); } }); } ``` -------------------------------- ### GitHub Codespaces Feature Description Source: https://github.com/kawamataryo/sky-follower-bridge Description of GitHub Codespaces, providing instant and fully configured development environments in the cloud. ```text Codespaces Instant dev environments ``` -------------------------------- ### Load Recent Posts via AJAX Source: https://ko-fi.com/kawamataryo Retrieves and displays recent posts using jQuery's AJAX GET method. It supports an optional 'useiframely' query parameter and updates two separate feed containers, also handling loading indicators. ```javascript function loadRecentPosts() { var useIframelyQS = getQueryStringByName("useiframely"); var iframelyQS = useIframelyQS ? "?useiframely=" + useIframelyQS : ""; var data = { buttonId: 'X8X315UWFN' }; $.ajax({ url: '/Buttons/LoadRecentPosts' + iframelyQS, type: "GET", dataType: "html", data: data, cache: false, success: function (data) { $("#recentPostsContainerDiv").html(data); $("#recentPostsContainerDiv2").html(data); $('#recentPostsLoading').hide(); $('#recentPostsLoading2').hide(); }, error: function (xhr, status, error) { //toastr.error('Error loading page feed.'); $('#recentPostsLoading').hide(); $('#recentPostsLoading2').hide(); } }); } ``` -------------------------------- ### Load Personal Feed with Pagination via AJAX Source: https://ko-fi.com/kawamataryo Fetches personal feed items with pagination support using jQuery's AJAX GET method. It manages loading states, end-of-feed detection, and integrates with Instagram embeds. Supports an optional 'useiframely' query parameter. ```javascript var isLoadingPosts = false; var endOfPostsFeed = false; function loadPagePosts(pageIndex) { var deferred = $.Deferred(); if (pageIndex == undefined) { postsPageIndex = 0; pageIndex = postsPageIndex; } if (!endOfPostsFeed) { $('#postsLoading').show(); } isLoadingPosts = true; var data = { pageIndex: pageIndex, pageId: 'X8X315UWFN' }; var useIframelyQS = getQueryStringByName("useiframely"); var iframelyQS = useIframelyQS ? "?useiframely=" + useIframelyQS : ""; $.ajax({ url: '/Feed/PersonalFeed' + iframelyQS, type: "GET", dataType: "html", data: data, timeout:60000, //cache: false, success: function (data) { isLoadingPosts = false; endOfPostsFeed = data != null && data.length == 0; if (pageIndex == 0) { $("#postsContainerDiv").html(data); } else { $("#postsContainerDiv").append(data); } $('#postsLoading').hide(); if (endOfPostsFeed) { $('#postsLoading').remove(); } if (window.instgrm) { window.instgrm.Embeds.process(); } deferred.resolve(); }, error: function (xhr, status, error) { isLoadingPosts = false; //toastr.error('Error loading page feed.'); $('#postsLoading').hide(); $('#postsLoading').remove(); deferred.resolve(); } }); return deferred.promise(); } ``` -------------------------------- ### VitePress Theme Appearance Script Source: https://sky-follower-bridge.dev/troubleshooting.html Manages the website's appearance settings, specifically enabling dark mode based on user preference or system settings. It checks local storage for theme preference and applies the 'dark' class to the document element if necessary. ```javascript (() => { const e = localStorage.getItem("vitepress-theme-appearance") || "auto"; const a = window.matchMedia("(prefers-color-scheme: dark)").matches; (!e || e === "auto" ? a : e === "dark") && document.documentElement.classList.add("dark"); })(); ``` -------------------------------- ### Social Login Initiation (JavaScript) Source: https://ko-fi.com/kawamataryo Initiates a social login process by setting the selected provider and submitting a form (`social-onboarding-form`). It tracks the login method and displays a spinner during the process. ```javascript startSocialLoginWith: function (provider) { try { trackCustomEvent("instant_sign_in_clicked_method", provider); } catch (err) { // Ignore tracking errors } showSpinner(); document.getElementsByName("provider")[0].value = provider; document.getElementById("social-onboarding-form").submit(); } ```