Chrome Extensions

From NoskeWiki
Jump to: navigation, search
Extension in action

About

NOTE: This page is a daughter page of: Chrome


Chrome extensions are pretty powerful. In Aug 2018 I decide to create my own and I found it was pretty easy, following the instructions at: developer.chrome.com. Below I have a complete example I made which populates a message into the first available `textarea` on a webpage. This specific example is designed to work with Tinder, but you could modify to anything else. Note that the text I have inserted is really not good material for any dating app - it just demonstrates the use of storage saved from the Extension "Options" area.


Options window

Note that Extension programming is all JavaScript and it is (by necessity) all asynchronous... so get used to this:

Instead of this (which assumes sync and won't work):

var result = chrome.moduleOne.doSomething(1);
chrome.moduleTwo.doSomethingElse(result.value);
// Do more things.

Do this (async):

chrome.moduleOne.doSomething(1, function(result) {
  chrome.moduleTwo.doSomethingElse(result.value, function(otherResult) {
    // Do more things.
  });
});


Chrome Extension Example: Tinder Message Writer

These instructions are based off the example at: developer.chrome's Get Started Tutorial.

Instructions

  1. Create all the files below in a single directory on your machine.
  2. Open the Extension Management page by navigating to chrome://extensions.
    1. NOTE: The Extension Management page can also be opened by clicking on the Chrome menu, hovering over More Tools then selecting Extensions.
  3. Enable Developer Mode by clicking the toggle switch next to Developer mode.
  4. Click the LOAD UNPACKED button and select the extension directory.
    1. NOTE: As you make changes you may have to click the refresh icon underneath.

Files

manifest.json (required)

/**
 * @fileoverview This file tells Chrome the files to
 * load for the extension.
 */
{
  "name": "Message Writer for Tinder",
  "version": "1.0",
  "description": "Will write your message in Tinder (tinder.com desktop app) for you.",
  "permissions": ["activeTab", "declarativeContent", "storage"],
  "background": {
    "scripts": ["background.js"],  // Is run in the background.
    "persistent": false
  },
  "page_action": {
    "default_popup": "popup.html",  // When you click the extension button.
    "default_icon": {
      "16": "images/get_started16.png",
      "32": "images/get_started32.png",
      "48": "images/get_started48.png",
      "128": "images/get_started128.png"
    }
  },
  "icons": {
    "16": "images/get_started16.png",
    "32": "images/get_started32.png",
    "48": "images/get_started48.png",
    "128": "images/get_started128.png"
  },
  "options_page": "options.html",  // When you go to extension's options.
  "manifest_version": 2
}


background.js

/**
 * @fileoverview Runs in the background even before you open the extension.
 */
 
'use strict';
 
chrome.runtime.onInstalled.addListener(function() {
  // Set a default myname value to storage:
  chrome.storage.sync.set({myname: 'Andrew'}, function() {
    console.log('Easy Tinder Loaded.');
  });
  // Only enable extension on these websites:
  chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
    chrome.declarativeContent.onPageChanged.addRules([{
      conditions: [
        new chrome.declarativeContent.PageStateMatcher({
        pageUrl: {hostEquals: 'messages.android.com'},}),
        new chrome.declarativeContent.PageStateMatcher({
        pageUrl: {hostEquals: 'tinder.com'},}),
      ],
          actions: [new chrome.declarativeContent.ShowPageAction()]
    }]);
  });
});


popup.html

<!DOCTYPE html>
<!-- @fileoverview > Rendered when you click the Extension button in Chrome toolbar. -->
<html>
  <head>
    <style>
      button {
        height: 30px;
        width: 200px;
        outline: none;
      }
    </style>
  </head>
  <body>
    Write tinder messages:
    <button id="btn-msg-hello" title="Add hello message">Hello</button>
    <button id="btn-msg-goodbye" title="Add goodbye message">Goodbye</button>
    <script src="popup.js"></script>
  </body>
</html>


popup.js

/**
 * @fileoverview This script is attached to `popup.html`
 * and creates event listeners for the buttons there.
 */
 
'use strict';
 
let btnMsgHello = document.getElementById('btn-msg-hello');
let btnMsgGoodbye = document.getElementById('btn-msg-goodbye');
 
chrome.storage.sync.get('myname', function(data) {
  console.log('Extension Initiated');
 
  btnMsgHello.onclick = function(element) {
    chrome.tabs.query({active: true, currentWindow: true}, 
    function(tabs) {
      chrome.tabs.executeScript(tabs[0].id, {
          code: 'var messageIdx = 0; var myName = "' + data.myname + '";'},
        function() {
          chrome.tabs.executeScript(tabs[0].id, {
            file: 'contentScript.js'});
        }
      );
    });
  };
 
  btnMsgGoodbye.onclick = function(element) {
    chrome.tabs.query({active: true, currentWindow: true}, 
    function(tabs) {
      chrome.tabs.executeScript(tabs[0].id, {
          code: 'var messageIdx = 1; var myName = "' + data.myname + '";'},
        function() {
          chrome.tabs.executeScript(tabs[0].id, {
            file: 'contentScript.js'});
        }
      );
    });
  };
});


contentScript.js

/**
 * @fileoverview This script is executed by button clicks
 * in `popup.html` and requires you to first set
 * `messageIdx` and `myName`.
 */
 
// Preset messages.
var kFixedTinderMessages = [
  // 0:
  'Hello {NAME}, my name is {MYNAME}. Do you think Tinder is bad for society?',
  // 1:
  'Goodbye {NAME}. I have decided Tinder is empty and meaningless.'
];
 
/**
 * Trims the text of whitespace and strange characters.
 * @param {string} text The text to trim (eg: ' Fred, ').
 * @return {string} Trimmed string (eg: 'Fred').
 */
function trimAnswer(text) {
  text = text.replace('\n', '');
  text = text.replace(',', '');
  return text.trim();
}
 
/**
 * Gets all tinder profile text, separated by newlines.
 * @return {string} Tinder profile text.
 */
function getTinderProfileText() {
  var profileCards = document.querySelectorAll('div[class^="profileCard"]');
 
  if (profileCards == null || profileCards.length == 0) {
    window.alert('Could not find profile area');
    return '';
  }
 
  var allText = '';
  var profileCard = profileCards[0];
  for (var i = 0; i < profileCard.children.length; i++) {
    if (profileCard.children[i].textContent != null) {
      allText += profileCard.children[i].textContent;
      if (allText != '') { allText += '\n'; }
    }
  }
  return allText;
}
 
/**
 * Extracts a first name from Tinder profile text.
 * It assumes that the first name is the first part of the text.
 * @param {string} text Tinder profile text chunk.
 * @return {string} First name or empty if none found.
 */
function getFirstNameFromProfileText(text) {
  var lines = text.split('\n');
  if (lines.lengh == 0) { return ''; }
  var firstWord = lines[0].replace(/ .*/, '');
  return trimAnswer(firstWord);
}
 
/**
 * Adds text to all `textarea`.
 * @param {string} newText The text to add.
 */
function addTextToTextArea(newText) {
 
  // Replace any '{NAME}' with name:
  var profileText = getTinderProfileText();
  var firstName = getFirstNameFromProfileText(profileText);
  if (firstName) {
    newText = newText.replace(/{NAME}/, firstName);
  }
 
  // Replace any '{MYNAME}' with myname:
  if (myName) {
    newText = newText.replace(/{MYNAME}/, myName);
  }
 
  // Write newText into all 'textarea' divs: 
  var textAreas = document.getElementsByTagName('textarea');
  if (textAreas == null || textAreas.length == 0) {
    window.alert('Could not find text area');
  }
  for(i=0; i<textAreas.length; i++) {
    // window.alert(textAreas[i].value);
    textAreas[i].value = newText;
  }  
}
 
/**
 * Adds a message to Tinder message box.
 * @param {int} idxOfMessage The index of the message within
 *    kFixedTinderMessages.
 */
function addTinderTextMessage(idxOfMessage) {
  var newText = kFixedTinderMessages[idxOfMessage];
  addTextToTextArea(newText);
}
 
 
addTinderTextMessage(messageIdx);


options.html

<!DOCTYPE html>
<!-- @fileoverview > Rendered when you click Extension's Options. -->
<html>
  <head>
    <style>
      button {
        outline: none;
      }
    </style>
  </head>
  <body>
    First name: <input type="text" id="txt-name" value="Loading...">
    <br><br>
    <div id="div-save-options">
    </div>
  </body>
  <script src="options.js"></script>
</html>


options.js

/**
 * @fileoverview This script is attached to `options.html`
 * and lets the user record their name to persistance.
 */
 
'use strict';
 
function constructOptions() {
  console.log('constructOptions');
 
  let txtName = document.getElementById('txt-name');
  chrome.storage.sync.get('myname', function(data) {
    txtName.value = data.myname;
  });
 
  let divOptions = document.getElementById('div-save-options');
  let btnSave = document.createElement('button');
  btnSave.innerHTML = 'Save';
  btnSave.addEventListener('click', function() {
      chrome.storage.sync.set({myname: txtName.value}, function() {
        console.log('Name saved as: ' + txtName.value);
        window.alert('Your new preferences are saved ' + txtName.value);
      })
    });
 
  divOptions.appendChild(btnSave);
}
 
constructOptions();


images subdir (for logo)

Download: this zip file and unzip to an "images" subfolder in your directory (should contain 4 images - png icons).



Links