Este tutorial estará divido en 3 apartados: Un primer apartado donde explicaremos varios conceptos referentes a las extensiones en Chrome, su estructura y la creación básica de una extensión. En el segundo apartado, nos enfocaremos en la creación de extensiones para este grandioso navegador como lo es Google Chrome, realizando varios ejemplos prácticos. Finalmente, en el tercer apartado explicaremos opciones avanzadas al momento de crear extensiones y cómo realizar su publicación en la webstore de Google Chrome para que esté disponible para el público en general.
Las extensiones tienen poca o ninguna interfaz de usuario. Por ejemplo, la imagen a continuación muestra un ícono de un candado que al hacer clic en ella se abre una pequeña interfaz.
Esta extensión en particular se utiliza para encriptar y desencriptar con llave PGP tus correos. Las extensiones son archivos que se encuentran empaquetados en uno solo, los cuales el usuario descarga e instala. Este empaquetado a diferencia de las aplicaciones web normales, no necesita depender de contenido web.
Tal como fue expuesto anteriormente, las extensiones permiten añadir funcionalidad a Chrome sin sumergirse profundamente en código nativo. Se pueden crear nuevas extensiones con tecnologías básicas con las que mayormente trabajamos los programadores en desarrollo web: HTML, CSS y Javascript.
1. Cómo crear y programar extensión de Chrome
Para comenzar, realizaremos una simple extensión que recupera una imagen de Google mediante la URL de la página actual como un termino de búsqueda. Esto lo haremos mediante la implementación de un elemento de interfaz de usuario que llamamos chrome.browserAction, lo que nos permite colocar un ícono justo al lado del menú de chrome, al cual podrá darle clic para un acceso rápido. Al hacer clic en ese ícono, se abrirá una ventana emergente la cual contendrá una imagen obtenida de la página actual, que se verá así:
Para comenzar nuestra práctica, crearemos un directorio llamado Visor_Imagen, dentro de este incluiremos todos los archivos con los que vamos a trabajar. Como editor de desarrollo pueden usar el de su preferencia, en mi caso usare Chrome Dev Editor, el cual pueden descargar en la siguiente dirección:
Lo primero que vamos a necesitar es crear un archivo de manifiesto llamado manifest.json. Este manifiesto no es más que un archivo de metadatos en formato JSON que contiene propiedades como el nombre, descripción, número de versión de su extensión y así sucesivamente. En un nivel avanzado, lo vamos a utilizar para declarar a Chrome lo que la ampliación va hacer y los permisos que se requiere con el fin de hacer determinadas cosas.
El formato del archivo manifiesto es el siguiente:
{ // Requerido "manifest_version": 2, "name": "Mi Extension", "version": "versionString", // Recommendado "default_locale": "es", "description": "A plain text description", "icons": {...}, // Seleccione uno (o ninguno) "browser_action": {...}, "page_action": {...}, // Opcional "author": ..., "automation": ..., "background": { // Recommended "persistent": false }, "background_page": ..., "chrome_settings_overrides": {...}, "chrome_ui_overrides": { "bookmarks_ui": { "remove_bookmark_shortcut": true, "remove_button": true } }, "chrome_url_overrides": {...}, "commands": {...}, "content_capabilities": ..., "content_scripts": [{...}], "content_security_policy": "policyString", "converted_from_user_script": ..., "copresence": ..., "current_locale": ..., "devtools_page": "devtools.html", "event_rules": [{...}], "externally_connectable": { "matches": ["*://*.example.com/*"] }, "file_browser_handlers": [...], "file_system_provider_capabilities": { "configurable": true, "multiple_mounts": true, "source": "network" }, "homepage_url": "http://path/to/homepage", "import": [{"id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}], "incognito": "spanning or split", "input_components": ..., "key": "publicKey", "minimum_chrome_version": "versionString", "nacl_modules": [...], "oauth2": ..., "offline_enabled": true, "omnibox": { "keyword": "aString" }, "optional_permissions": ["tabs"], "options_page": "options.html", "options_ui": { "chrome_style": true, "page": "options.html" }, "permissions": ["tabs"], "platforms": ..., "plugins": [...], "requirements": {...}, "sandbox": [...], "short_name": "Short Name", "signature": ..., "spellcheck": ..., "storage": { "managed_schema": "schema.json" }, "system_indicator": ..., "tts_engine": {...}, "update_url": "http://path/to/updateInfo.xml", "version_name": "aString", "web_accessible_resources": [...] }A continuación describiré la función que cumple las etiquetas más importantes:
En requerido:
- manifest_version: Es la versión de manifiesto, se representa por un número entero que especifica la versión del formato de archivo. A partir de Chrome 18, los desarrolladores deben especificar el número 2.
- name: Es el nombre que tendrá tu extensión. Este debe estar comprendido por un máximo de 45 caracteres, name es el principal elemento de definición de la extensión y es un campo obligatorio. Se muestra en los siguiente lugares:
a) En la cuadro de instalación.
b) En la interfaz de usuario donde se administra la extensión.
c) En la tienda virtual de Chrome.
- version: Debe estar comprendida de uno a cuatro números enteros separados por puntos que identifican la versión de la extensión. Estos son algunos de los ejemplos de las versiones válidas:
"version 1"
"Version": "1.0"
"Version": "2.10.2"
"Version": "3.1.2.4567"
Recomendados:
- default_locale: Especifica el subdirectorio de _locales (idiomas) que contiene las cadenas por defecto para esta extensión. Debes colocar todas las cadenas visibles para el usuario dentro de un archivo llamado messages.json. Cada vez que incluyas un nuevo idioma, debes agregar un nuevo archivo messages.json bajo el directorio _locales/localecode donde localecode es el código del idioma, tal como en es inglés y es para el idioma español.
Un ejemplo de una extensión internacionalizada con soporte para Inglés (en), español (es) y Korean (ko), sería la siguiente:
- description: Comprende una cadena en texto plano (Sin formato HTML u otro) con un máximo de 132 caracteres que describe la funcionalidad de la extensión.
- Icons: Permite agregar uno o más íconos que representen a la extensión. Siempre se debe proporcionar un ícono de 128x128px. Este se usará durante la instalación y en la Chrome Web Store. Las extensiones también deben proporcionar un ícono de 48x48, que se utiliza en la página de administración de extensiones de Chrome (chrome://extensions).También puede especificar un ícono de 16x16 para ser utilizado como el favicon para las páginas de una extensión.
Los íconos deben estar generalmente en formato PNG, porque tiene el mejor soporte para la transparencia. Sin embargo, pueden estar en cualquier formato compatible con WebKit, incluyendo BMP, GIF, ICO, y JPEG. Aquí está un ejemplo de la especificación de los iconos:
"iconos" : { "16" : "icon16.png" , "48" : "icon48.png" , "128" : "icon128.png" },Ejemplo
Selecciona uno (o ninguno):
- browser_action: Use browser_action para poner iconos en la barra de herramientas principal que se encuentra en la parte superior del navegador Google Chrome, a la derecha de la barra de direcciones. Adicionalmente podrás agregar tooltip(mensaje flotante), badge(texto flotante sobre el icono) y popup(Ventana flotante).
Ejemplo de uso browser_action:
{ "name": "Mi extension", ... "browser_action": { "default_icon": { // opcional "19": "images/icon19.png", // opcional "38": "images/icon38.png" // opcional }, "default_title": "Google Mail", // opcional; muestra un tooltip "default_popup": "popup.html" // opcional }, ... }
- page_action: Utiliza este API para colocar tu ícono dentro de la barra de direcciones.
Ejemplo de uso:
{ "name" : "Mi extension" , ... "page_action" : { "default_icon" : { // opcional "19" : "images/icon19.png" , // opcional "38" : "images/icon38. png " // opcional }, "default_title": " Google mail ", // opcional; muestra en la descripción "default_popup": "popup.html" // opcional } , ... }Ej
Opcional:
- Background: Una necesidad común en las extensiones es tener una página única para la ejecución de secuencias largas para gestionar alguna tarea o estado. Esta es una página HTML que se ejecuta en conjunto con la extensión. Se inicia al comenzar la ejecución de la extensión y activa solo una instancia de ella a la vez. Lo recomendable en vez de usar Background es usar una página de eventos.
En una extensión típica con una página en Background, la interfaz del usuario por ejemplo, el browser_action o page_action y algunas opciones de la página actúan como la vista de la extensión. Cuando la vista necesita conocer algún estado (cerró la ventana, actualizó la página…), esta hace la petición del estado a la página que se encuentra como Background. Cuando la página Background notifica que hubo un cambio en el estado, esta le informa a la vista para que sea actualizada o ejecute alguna acción.
Su formato es el siguiente:
{ "name": "Mi extension", ... "background": { "scripts": ["background.js"] }, ... }Formato
- Páginas de Eventos: Antes de definir el siguiente atributo, es necesario explicar de qué trata las Páginas de Eventos. Una necesidad común de aplicaciones y extensiones es tener una única secuencia de comandos de larga ejecución para gestionar alguna tarea o estado. Este es el objetivo de las páginas de eventos. Las páginas de eventos se cargan solo cuando se necesitan. Cuando la misma no está haciendo algo activamente, esta se descarga del cache, liberando memoria y otros recursos del sistema.
Las ventajas de rendimiento son significativas, especialmente en dispositivos de baja potencia. Es por esto que se recomienda usar más páginas de eventos que Background.
La declaración de una página de eventos en el archivo de manifiesto seria la siguiente:
{ "name": "Mi extension" , ... "background": { "scripts": [ "eventPage.js" ], "persistent": false }, ... }Como pueden ver la diferencia que tiene con Background es el atributo persistent, el cual tendrá como estatus falso.
- chrome_settings_overrides: Se utiliza para sobrescribir alguna configuración seleccionada en el Chrome. Esta API solo está disponible para Windows.
Alguna de esas configuraciones pueden ser el Homepage (Página de inicio del navegador, Search Provider (el proveedor de búsqueda), etc.
Ejemplo de configuración:
{ "name": "Mi extension", ... "chrome_settings_overrides": { "homepage": "http://www.homepage.com", "search_provider": { "name": "name.__MSG_url_domain__", "keyword": "keyword.__MSG_url_domain__", "search_url": "http://www.foo.__MSG_url_domain__/s?q={searchTerms}", "favicon_url": "http://www.foo.__MSG_url_domain__/favicon.ico", "suggest_url": "http://www.foo.__MSG_url_domain__/suggest?q={searchTerms}", "instant_url": "http://www.foo.__MSG_url_domain__/instant?q={searchTerms}", "image_url": "http://www.foo.__MSG_url_domain__/image?q={searchTerms}", "search_url_post_params": "search_lang=__MSG_url_domain__", "suggest_url_post_params": "suggest_lang=__MSG_url_domain__", "instant_url_post_params": "instant_lang=__MSG_url_domain__", "image_url_post_params": "image_lang=__MSG_url_domain__", "alternate_urls": [ "http://www.moo.__MSG_url_domain__/s?q={searchTerms}", "http://www.noo.__MSG_url_domain__/s?q={searchTerms}" ], "encoding": "UTF-8", "is_default": true }, "startup_pages": ["http://www.startup.com"] }, "default_locale": "de", ... }
- chrome_ui_overrides: esta propiedad de la extensión se utiliza para sobrescribir alguna configuración de la interfaz de usuario del Chrome. Como por ejemplo los marcadores. Su configuración es la siguiente:
{ "name" : "Mi extension" , ... "chrome_ui_overrides" : { "bookmarks_ui" : { "remove_button" : "true" , "remove_bookmark_shortcut" : "true" } } , ... }En este caso se estaría eliminando la estrella que tiene el navegador para los favoritos.
- chrome_url_overrides: Esta es una forma de sustituir el archivo HTML desde la extensión para una página que normalmente el navegador Google Chrome provee. Adicionalmente, también puedes sobrescribir su CSS y su código JavaScript.
Una extensión con esta configuración puede reemplazar una de las siguientes páginas del Chrome:
- Administrador de Marcadores (bookmarks): Es la página que aparece cuando el usuario elige la opción del menú administrador de marcadores en el menú de Chrome o para Mac, el elemento Administrador de marcadores en el menú de Marcadores.
- Historial (history): Es la página que aparece cuando el usuario elige el historial desde el menú de Chrome o, en Mac el elemento mostrar historial completo desde el menú que se encuentra en la opción historial.
- Nueva pestaña (newtab): Es la página que aparece cuando el usuario crea una nueva pestaña o ventana desde el navegador. También puedes acceder a esta página colocando en la barra de direcciones la siguiente dirección: chrome://newtab
{ "name": "Mi extension", ... "chrome_url_overrides" : { " newtab": "mipagina.html" // la opciones son newtab, history, bookmarks }, ... }
- commands: Este API de comandos se utiliza para agregar los atajos del teclado que desencadenen una acción en tu extensión. Por ejemplo, una acción para abrir la acción del navegador o enviar un comando a la extensión.
{ "name": "Mi extension", ... "commands": { "toggle-feature-foo": { "suggested_key": { "default": "Ctrl+Shift+Y", "mac": "Command+Shift+Y" }, "description": "Toggle feature foo" }, "_execute_browser_action": { "suggested_key": { "windows": "Ctrl+Shift+Y", "mac": "Command+Shift+Y", "chromeos": "Ctrl+Shift+U", "linux": "Ctrl+Shift+J" } }, "_execute_page_action": { "suggested_key": { "default": "Ctrl+Shift+E", "windows": "Alt+Shift+P", "mac": "Alt+Shift+P" } } }, ... }En tu página de fondo (Background), puedes enlazar un controlador para cada uno de los comandos definidos en el manifest.js (a excepción de '_execute_browser_action' y '_execute_page_action') vía onCommand.addListener.
Por ejemplo:
chrome.commands.onCommand.addListener(function(command) { console.log('Commando presionado:', command); });
- content_scripts: Son archivos javascript que se ejecutan en el contexto de las páginas web. Mediante el uso de la norma Document Object Model (DOM), que pueden leer los detalles de las páginas web de las visitas del navegador o realizar cambios en ellos.
{ "name": "Mi extension", ... "content_scripts": [ { "matches": ["http://www.google.com/*"], "css": ["mystyles.css"], "js": ["jquery.js", "myscript.js"] } ], ... }
- content_scripts: Con el fin de hacer más segura nuestras extensiones y evitar posibles problemas de cross-site scripting, el sistema de extensión de Chrome ha incorporado el concepto general de Política de Seguridad de Contenidos (CSP). Esto introduce unas políticas muy estrictas que harán que las extensiones sean más seguras por defecto. En general, CSP funciona como un mecanismo de listas blancas y negras para los recursos cargados o ejecutados por sus extensiones.
{ ..., "content_security_policy": " script-src 'self' https://example.com; object-src 'self'" ... }Estos fueron algunos de los atributos más importantes. Para nuestra práctica inicial definiremos nuestro archivo manifest.json de la siguiente forma:
{ "manifest_version": 2, "name": "Ejemplo de inicio", "description": "Esta extensión muestra una imagen de google images de la página actual", "version": "1.0", "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "permissions": [ "activeTab", " https://www.googleapis.com/" ] }Como pueden ver en nuestro manifiesto de ejemplo, declaramos un browser_action, el permiso activeTab para ver la dirección URL de la pestaña actual, y se le dió el permiso al host, de esta forma se podrá acceder a la API de Google para realizar la búsqueda de imágenes externas.
A su vez, se encuentran 2 archivos de recursos al definir browser_action: icon.png y popup.html. Ambos recursos deben existir dentro del paquete de extensión, por lo que vamos a crearlos ahora:
- icon.png se mostrará al lado de cuadro multifunción, esperando por la interacción del usuario. Es solo un archivo PNG de 19px x 19px.
- popup.html será mostrado en la ventana emergente que se crea en respuesta al clic del usuario sobre el ícono. Es un archivo HTML estándar y su contenido es el siguiente:
<html> <head> <title>Getting Started Extension's Popup</title> <style> body { font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif; font-size: 100%; } #status { /* avoid an excessively wide status text */ white-space: pre; text-overflow: ellipsis; overflow: hidden; max-width: 400px; } </style> <!-- - JavaScript and HTML must be in separate files: see our Content Security - Policy documentation[1] for details and explanation. - [1]: https://developer.chrome.com/extensions/contentSecurityPolicy --> <script src="popup.js"></script> </head> <body> <div id="status"></div> <img id="image-result" hidden> </body> </html>La lógica real de construir el contenido de la ventana emergente es implementado por popup.js . Su contenido será el siguiente:
/** * Obtener la actual URL. * @param {function(string)} callback - es llamado cuando la URL de la pestaña actual es encontrado */ function getCurrentTabUrl(callback) { // Consulta filtro que será pasado a chrome.tabs.query - ver: // https://developer.chrome.com/extensions/tabs#method-query var queryInfo = { active: true, currentWindow: true }; chrome.tabs.query(queryInfo, function(tabs) { // chrome.tabs.query invoca el callback con una lista de pestañas que encuentra // la consulta. Cuando el popup es abierto, alli ciertamente es una ventana y al menos // una pestaña, asi nosotros podemos seguramente asumir que esa pestaña |tabs| no es un arreglo vacio. // Una ventana solo puede tener activa una pestaña a la vez, asi que el arreglo es // exactamento una pestaña. var tab = tabs[0]; // Un tab es un objeto plano que provee información sobre la pestaña. // Ver https://developer.chrome.com/extensions/tabs#type-Tab var url = tab.url; console.assert(typeof url == 'string', 'tab.url should be a string'); callback(url); }); // La mayoría de los métodos del Chrome extension API son asíncronos. Eso significa que // no puedes hacer algo como esto: // // var url; // chrome.tabs.query(queryInfo, function(tabs) { // url = tabs[0].url; // }); // alert(url); // Mostrará "undefined", porque chrome.tabs.query es asíncrono. } /** * @param {string} searchTerm – Buscar termino para Google Image search. * @param {function(string,number,number)} callback – Llamada cuando una imagen fue encontrada. El callback obtiene la URL, el ancho y alto de la imagen. * @param {function(string)} errorCallback – Llamada cuando la imagen no es encontrada. * El callback obtiene una cadena con las razones del porque fallo. */ function getImageUrl(searchTerm, callback, errorCallback) { var searchUrl = ' 'https://www.googleapis.com/customsearch/v1?cx=017923793791201738471%3A4nh2tpzikma&imgColorType=color&imgSize=medium&num=1&searchType=image&start=1&key=AIzaSyDcNC3g_HDSY8rHhBLFuqXbqqslQyjSgW4&q=' + encodeURIComponent(searchTerm); var x = new XMLHttpRequest(); x.open('GET', searchUrl); x.responseType = 'json'; x.onload = function() { var response = x.response; if (!response || !response.items || response.items.length === 0){ errorCallback('No response from Google Image search!'); return; } var firstResult = response.items[0].image; var imageUrl = firstResult.thumbnailLink; var width = parseInt(firstResult.thumbnailWidth); var height = parseInt(firstResult.thumbnailHeight); console.assert( typeof imageUrl == 'string' && !isNaN(width) && !isNaN(height), 'Unexpected respose from the Google Image Search API!'); callback(imageUrl, width, height); }; x.onerror = function() { errorCallback('Network error.'); }; x.send(); } function renderStatus(statusText) { document.getElementById('status').textContent = statusText; } document.addEventListener('DOMContentLoaded', function() { getCurrentTabUrl(function(url) { // Pone la imagen de la URL en Google search. renderStatus('Performing Google Image search for ' + url); getImageUrl(url, function(imageUrl, width, height) { renderStatus('Search term: ' + url + '\n' + 'Google image search result: ' + imageUrl); var imageResult = document.getElementById('image-result'); imageResult.width = width; imageResult.height = height; imageResult.src = imageUrl; imageResult.hidden = false; }, function(errorMessage) { renderStatus('Cannot display image. ' + errorMessage); }); }); });Ahora deberían tener 4 archivos en el directorio de trabajo: Icon.png, manifest.json, popup.html y popup.js. El siguiente paso es cargar los archivos en Chrome.
Las extensiones que se descargan de la Chrome Web Store se empaquetan como archivos .crx. Lo cual es perfecto para su distribución, mas no para el desarrollo. Reconociendo esto, Chrome te da una forma rápida de cargar tu directorio de trabajo para la prueba. Esto se hace de la siguiente manera:
1. Visita chrome://extensions en tu navegador o abre el menú de Chrome haciendo clic en el icono situado a la derecha de la Omnibox: El icono del menú es de tres barras horizontales. Y seleccione Extensiones en la opción Mis Herramientas para llegar al mismo lugar.
2. Asegúrese de que la casilla de verificación modo de desarrollador en la esquina superior derecha está marcada.
3. Haga clic en Cargar extensión descomprimida (sin empaquetar) para que aparezca un cuadro de diálogo de selección de archivos.
4. Navega hasta el directorio en el que se encuentran tus archivos de extensión, y selecciónelo.
Alternativamente puedes arrastrar el directorio que contiene tu proyecto y soltarlo sobre la ventana de extensiones de Chrome. De esta forma se cargara la extensión en tu navegador.
De esta forma habremos realizado una sencilla extensión para google Chrome. En nuestra próxima entrega profundizaremos en la construcción de extensiones en conjunto con frameworks de desarrollo como jquery y Bootstrap, los cuales nos permitirán agilizar nuestro desarrollo.
2. Ejemplo de extensiones para Chrome
En este apartado realizaremos varios ejemplos lo cual nos permitirá comprender ampliamente muchas de las funcionalidades que existen al momento de construir una extensión para google Chrome.
En este ejemplo vamos realizar una sencilla extensión donde aprenderemos como podemos modificar el contenido de las páginas que cargamos en nuestro navegador. En este caso modificaremos el color de fondo de la página cargada y lo cambiaremos por el color azul.
Como explique en la primera parte de este tutorial pueden usar cualquier IDE de desarrollo, en mi caso usaré Chrome Dev Editor.
Para empezar, crearemos un nuevo directorio con el nombre FondoAzul y crearemos un proyecto con el mismo nombre.
Dentro crearemos nuestro primer archivo manifest.json el cual contendrá las definiciones de nuestra extensión.
Nuestro archivo manifest.json deberá contener el siguiente código:
{ "manifest_version": 2, "name": "Fondo Azul", "description": "Esta extensión cambio el color de fondo de la página actual", "version": "1.0", "browser_action": { "default_icon": "icon.png", "default_title": "Haz esta página Azul" }, "permissions": [ "activeTab" ], "background": { "scripts": ["background.js"], "persistent": false } }Debido a que nuestra extensión es simple, solo contendrá un icono que al ser presionado ejecutará una acción. Como pueden ver en el archivo manifest.json definimos un nombre y su descripción, en el browser_action definimos el icono que se mostrará en la barra de nuestro navegador Google Chrome y un título el cual se mostrará al posicionar el puntero del ratón sobre dicho icono. Con respecto a los permisos definiremos que se hará solo en la pestaña activa. El archivo que se ejecutará de fondo será nuestro archivo background.js el cual no será persistente, ya que se ejecutará solo cuando hagamos clic sobre la extensión.
Creamos nuestro icono y lo guardamos dentro del directorio del proyecto como está definido en manifest.json. En este caso en la raíz del proyecto.
Luego creamos un archivo JavaScript llamado background.js dentro del mismo directorio con el siguiente código:
// llamada cuando el usuario hace clic sobre la extensión chrome.browserAction.onClicked.addListener(function(tab) { console.log('Cambiando ' + tab.url + ' a azul!'); chrome.tabs.executeScript({ code: 'document.body.style.backgroundColor="blue"' }); });Quedando todo el proyecto de la siguiente manera:
Para ejecutar nuestra extensión bastara con pulsar el botón de play que se encuentra en la barra superior del Chrome Dev Editor.
Al presionarlo la extensión será cargada automáticamente en el navegador Google Chrome.
Veamos nuestra extensión en acción, al hacer clic sobre el icono que hice (fondo azul con la letra A en blanco), la página que tengo cargada en la pestaña actual, en mi caso mi cuenta de usuario en Solvetic (http://www.solvetic....berth-ramncgev/) cambiara su fondo al color azul. Cabe resaltar que solo cambiara el color del elemento BODY, y no los DIV que sobre el contenga, ya que de esta forma fue que lo definí en mi background.js.
Para este ejemplo mostrare como agilizar nuestro trabajo desde el IDE de desarrollo y desde el código. En el Chrome Dev Editor, hacemos clic en el botón de +, para crear un nuevo proyecto, esta vez cambiaremos el tipo de proyecto, seleccionando la opción JavaScript Chrome App.
Como pueden ver automáticamente nos genera toda la estructura de nuestro proyecto. Con nuestro archivo manifest.json con las definiciones más comunes.
A este archivo le agregaremos una descripción corta en la etiqueta description colocando el texto que ustedes deseen, en mi caso “Extensión que permite cambiar el color de fondo”. Para este proyecto crearemos 2 iconos, uno de 16x16 pixeles y otro de 128x128 pixeles, como pueden ver en la estructura estos serán guardados dentro del directorio assets.
Agregaremos el siguiente código bajo la etiqueta minimum_chrome_version:
"permissions": [ "tabs", "http://*/*", "https://*/*" ], "browser_action": { "default_title": "Cambia la página a múltiples colores.", "default_popup": "popup.html" },Como pueden ver estamos definiendo un popup o vista el cual contendrá todo el html que visualizará el usuario al hacer clic sobre nuestra extensión. Luego agregaremos el siguiente código:
"content_scripts": [ { "matches": ["<all_urls>"], "css": ["assets/bootstrap/css/bootstrap.min.css"], "js": ["assets/jquery.min.js", "main.js"], "run_at": "document_start" } ]content_scripts: contiene los archivos JavaScript (js) y hojas de estilos (css) que se ejecutarán en el contexto de la página web. Esta puede contener las siguientes propiedades:
- matches: Obligatorio. Específica a que página se le inyectara el script.
- exclude_matches: Opcional. Páginas que serán excluida para que el script no sea inyectado.
- match_about_blank: Opcional. Este valor es booleano, e indica si el script será insertado en la página en blanco (about:blank y about:srcdoc).
- css: Opcional. Es un arreglo que indica la lista de archivos css que serán insertados en la página que se solicite en el navegador.
- js: Opcional. Es un arreglo con la lista de archivos JavaScript que serán insertados en la página que se solicite en el navegador.
- run_at: Opcional. Es una cadena de texto que controla en que momento los archivos js serán cargados. Su valor puede ser:
- document_start: Los archivos se inyectan después de cualquier archivo css , pero antes de que cualquier DOM se construya o cualquier otro script se ejecute.
- document_end: Se inyectan los archivos inmediatamente después de que el DOM se complete, pero antes de que algún recurso como imágenes y frames sean cargados.
- document_idle: El navegador elige el tiempo para inyectar secuencias de comandos entre document_end, e inmediatamente después de que el window.onload desencadene el evento.Esta opción es la que se encuentra configurada por defecto.
Al finalizar nuestro archivo manifest.json debe de quedar de la siguiente manera:
Como pueden ver, hemos agregados un par de cosas nuevas, en la propiedad css hemos definido el framework Bootstrap lo cual no hará más fácil el desarrollo a nivel de estilo. Seguido en la propiedad js definimos la librería JavaScript JQUERY lo que no permitirá trabajar de una manera más rápida y sencilla todo lo que tenga que ver con JavaScript. Nuestro archivo index.html deberá quedar de la siguiente manera:
<!doctype html> <html> <head> <title>Popup MultipleColor</title> <style> body{ overflow: hidden; margin: 0px; padding: 0px; background: white; } div:first-child { margin-top: 0px; } div{ cursor: pointer; text-align: center; font-size:1em; width: 100px; margin-top: 1px; background: #cccccc; color:#fff; } #rojo{ background-color:red; } #azul{ background-color:blue; } #verde{ background-color:green; } #amarillo{ background-color:yellow; color: #000; } </style> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <script src="assets/jquery.min.js"></script> <script src="main.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12" id="rojo">Rojo</div> </div> <div class="row"> <div class="col-md-12" id="azul">Azul</div> </div> <div class="row"> <div class="col-md-12" id="verde">Verde</div> </div> <div class="row"> <div class="col-md-12" id="amarillo">Amarillo</div> </div> </div> </body> </html>En el archivo index.html simplemente hacemos las referencias a nuestros archivos Bootstrap, Jquery y main.js. En el cuerpo definimos un contenedor bootstrap con sus divs los cuales servirán como botones para las diferentes opciones de colores.
Para el archivo main.js utilizaremos el evento clic el cual será ejecutado al momento de presionar el botón del ratón sobre cada clase “col-md-12” tomando el color de fondo del elemento que fue seleccionado y asignándolo al cuerpo de la página que ha sido abierta. Seguidamente se ejecutara el evento window.close(); el cual cerrar la ventana de nuestra extensión. El código definido para main.js es el siguiente:
$(document).ready(function(){ $(".col-md-12").click(function(){ var color = $( this ).css( "background-color" ); chrome.tabs.executeScript(null, { code: "$('body').css( 'background-color','"+color+"' )" }); window.close(); }); });El resultado al ejecutar nuestra extensión podremos visualizar en la barra superior el icono que hemos creado para la misma.
Al hacer clic sobre nuestra extensión se mostrará el siguiente popup:
Y al seleccionar una de las opciones el resultado será el siguiente:
En este ejemplo aplicaremos todo lo visto anteriormente, crearemos una extensión que al hacer clic sobre ella nos mostrará un popup con el listado de las páginas más visitadas desde nuestro navegador, dando un acceso directo a dichas páginas. Lo único diferente en este ejemplo es que solicitaremos permiso a una de los apis de Chrome para acceder a las páginas más vistas desde Chrome. El nombre de este api es chrome.topSites.
Para comenzar nos vamos a Chrome Dev Editor y creamos nuestro proyecto con el nombre TopHistorial y en tipo de proyecto seleccionamos la opción JavaScript Chrome App.
Luego nuestro archivo manifest.json deberá quedar de la siguiente manera:
{ "manifest_version": 2, "name": "TopHistorial", "short_name": "TopHistorial", "description": "Mostrar listado de páginas más vistas en nuestro navegador", "version": "0.0.1", "minimum_chrome_version": "38", "permissions": ["topSites"], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "content_scripts": [ { "matches": ["<all_urls>"], "css": ["assets/bootstrap/css/bootstrap.min.css"], "js": ["assets/jquery.min.js", "main.js"], "run_at": "document_start" } ] }Como pueden ver agregamos una nueva atributo al manifiesto para poder obtener permiso sobre el api de Chrome: Declarar Permisos, se utiliza en la mayoría de las API de Chrome en tu extensión, previamente debes declararla colocando el campo permissions en tu manifiesto. Cada permiso puede ser una cadena de texto perteneciente a la siguiente lista (Dividido en 3 imágenes):
Con respecto a nuestro archivo popup.html deberá de quedar de la siguiente manera:
<!doctype html> <html> <head> <title>Popup MultipleColor</title> <link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css"> <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'> <script src="assets/jquery.min.js"></script> <script src="main.js"></script> <style> body{ overflow: hidden; margin: 0px; padding: 0px; background:#000; color:#fff; font-family: 'Lato', sans-serif; } .container{ width:400px; background-color:#000; color:#fff; line-height: 25px; } .container a{ color:#fff; } .container a:hover{ color:yellow; text-decoration: overline underline; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"><h1>Mas vistas:</h1></div> <div class="col-md-12"> <ol id="lista_top"></ol> </div> </div> </div> </body> </html>Nuestro archivo main.js que contendrá la consulta del api y el manejo del evento clic, se representara de la siguiente manera:
$(document).ready(function(){ function abrirpagina() { chrome.tabs.create({ url: $(this).attr("href") }); } function buildPopupDom(mostVisitedURLs) { for (var i = 0; i < mostVisitedURLs.length; i++) { $("#lista_top").append('<li><a class="enlaces" href="'+mostVisitedURLs[i].url+'">'+mostVisitedURLs[i].title+'</a></li>'); } $(".enlaces").bind("click", abrirpagina); } chrome.topSites.get(buildPopupDom); });A nivel de estructura nuestro proyecto debió de quedar de la siguiente manera:
Al ejecutar nuestra extensión podremos ver un icono en la parte superior del navegador, que en mi caso lo diseñe de color azul, al hacer clic sobre él, me abre un popup con el listado de las paginas a la que más he accedido desde mi navegador ordenados por el número de visitas que he hecho.