• Passer à la navigation principale
  • Passer au contenu principal

Jérémy Allard

Contrôlez votre entreprise sur le web

  • Ressources gratuites
  • Solutions Payantes
  • Ils témoignent
  • Show Search
  •  
Hide Search
Accueil/Référencement/Création d’une extension Chrome – Partie 3

Création d’une extension Chrome – Partie 3

Sommaire

  • 1 Récapitulatif:
  • 2 Jquery, le plugin « Positionchecker »
  • 3 webDB, la gestion de la base de donnée:
  • 4 Voilà, maintenant, l’extension elle-même

Récapitulatif:

  • Partie 1 – Introduction
  • Partie 2 – Faire Baver un peu

Allez hop, on y retourne. Si tu te souviens bien la dernière fois, j’avais parlé de faire une extension sur le positionnement des pages Web sur certains mots clés. Oui, j’ai horreur des truc du style « Hello World » et en me lancant la dessus, je me suis dis autant faire quelque chose de cool !

Alors que va t-il nous falloir pour faire joujou ?
– Tu as déjà en principe tes dossiers et tes fichiers prêts à recevoir du code, si ce n’est pas le cas, relis les deux premières parties.

– On va ajouter dans le dossier js/ un sous dossier /libs pour organiser les fichiers externes qui vont nous servir ( Jquery, etc… )

– Je ne me souviens pas en avoir parler mais un petit fichier helpers.js dans une extension chrome est toujours utile, je le mets au même niveau que les fichiers background.js etc…

– Un plugin Jquery pour aller chercher les positions de tes pages sur tes mots clés.

– Un fichier WebDB.js qui se chargera d’enregistrer les infos en base de donnée sqlite ( limitée à 5Mo)

Jquery, le plugin « Positionchecker »

On y va, on créé dans libs/ le fichier jquery.positionchecker.js avec le code suivant:

(function($) {
/**
   PLUGIN POSITION CHECKER
**/
$.fn.serpposition = function(options) {
  var opts = $.extend({},$.serpposition.defaults, options);
  //CODE
    //1. on a une url et des mots clés
    //2. on split les mots clé et pour chacun on check un moteur
        		var serpUrl = opts.serp.url;
                var serpQuery =  opts.serp.query;
                var serpName =  opts.serp.name;
                var linkSelector = opts.serp.linkSelector;
    // check position
    var $$ = $(this);
    console.log($$);
    var _url = $$.attr('href')|| $$;
    //verifier la présence du lien sur la page
        		var isOnPage = false;
                var serpPosition = 0;
                var keyword = opts.keywords;
                    //console.log(k);
                    //console.log(v);
                    console.log('On va checker la position de: '+_url+' sur le mot: '+$.trim(keyword));
                    console.log(serpUrl+'?'+serpQuery+$.trim(keyword)+'&'+opts.serp.extra);
                    var keywordToCheck =  $.trim(keyword);
                    $.ajax({
                        type:'GET',
                        url:serpUrl+'?'+serpQuery+keywordToCheck+'&'+opts.serp.extra,
                        dataType:'text',
                        async:false,
                        crossDomain:true,
                        statusCode: {
                            404: function() {
                              console.log (opts.errorMessages['404']);
                            },
                            301: function() {
                              console.log (opts.errorMessages['301']);
                            },
                        },
                        success: function (d, textStatus, jqXHR) {
                            isOnPage = ($("a[href^='"+_url+"']", d).size() === 0)? false : true ;
                            console.log(_url+' is on page: '+isOnPage);
                            var htmlReponse='';
                            if (isOnPage){
                            //position ?
                                $.each($(linkSelector,d),function(k,v){
                                    urlTocheck = $(v).attr('href');
                                    if (urlTocheck.match(_url)) {
                                        serpPosition = k+1;
                                    }
                                });
                            }else{
                                serpPosition = 'n/a';
                            }
                        },
                        error: function () {
                            serpPosition = 'Error Check';
                        }
                    });
                return serpPosition;
};
$.serpposition = {
  defaults : {
      addResOn: '#res',
      keywords : 'seotons',
      serp:{
        name: 'Google',
        url:'http://www.google.fr/search',
        query:'q=',
        extra:'num=100',
        linkSelector : 'h3.r > a.l'
      },
      sendToServeur:false,
      serveur:{
        url:''
      },
      errorMessages: {
        '404': 'Dead',
        '301': 'Redirection 301',
        '':''
      },
      }
};
})(jQuery);

Rien de bien terrible et le plugin peut bugger ( je lui ai retiré quelques fonctions en route que je garderais pour ma pomme :) )

Te voilà avec ton plugin jQuery qui va te servir à checker les positions sur Google ici, tu l’auras compris…en trifouillant un peu tu pourras aller bien plus loin.

Si tu utilises un plugin jQuery, il va de soi que l’on risque de retrouver dans ton dossier libs/  jquery.min.js … Allez hop on charge la bête ! Puis un petit plugin sympa qui va nous servir pour organiser les résultats sous forme de tableau par la suite ! [TELECHARGER]

Voilà ça c’est fait, tu as donc dans libs/ 4 fichiers dont webDB.js dont voici le code:

webDB, la gestion de la base de donnée:

(function ($) {
    //config
    $.DB = function () {
        return {
            db: null,
            open: function () {
                var dbSize = 5 * 1024 * 1024; // 5MB
                db = openDatabase('DB', '1.0', 'DB Manager', dbSize);
            },
            createTable: function () {
                db.transaction(function (tx) {
                    tx.executeSql('CREATE TABLE IF NOT EXISTS ' + 'DB(ID INTEGER PRIMARY KEY ASC, url TEXT, keyword TEXT, position TEXT, added_on DATETIME)', []);
                });
            },
            cleanTable: function () {
                db.transaction(function (tx) {
                    tx.executeSql('DELETE FROM "DB"', [], null,function (tx, error) {
                        console.log(error);
                    } );
                });
            },
            dropTable: function () {
                db.transaction(function (tx) {
                    tx.executeSql('DROP TABLE IF EXISTS "DB"', [], null,function (tx, error) {
                        console.log(error);
                    } );
                });
            },
            saveData: function (url, keyword, position) {
                //console.log('Verif avant add: '+url);
                db.transaction(function (tx) {
                    var addedOn = new Date().getTime();
                    tx.executeSql('SELECT * FROM DB WHERE url=? AND keyword=?',
                    [url,keyword],
                    function (tx,result) {
                  //      console.log('SELECT SQL ok');
                        var count = result.rows.length;
                    //    console.log('count: '+count);
                        if(count === 0){
                      //     console.log(url+' Absent donc on save');
                        $.DB.addData(url, keyword, position);
                        }else{console.log(url+' Duplicate in BDD');}
                    },
                    function (tx, error) {
                        console.log(error);
                    });
                });
            },
            addData: function (url, keyword, position) {
                //console.log('Verif avant add: '+url);
                db.transaction(function (tx) {
                    var addedOn = new Date().getTime();
                    tx.executeSql('INSERT INTO DB(url, keyword, position, added_on) VALUES (?,?,?,?)',
                    [url, keyword, position, addedOn],
                    function (tx,result) {
                        console.log('Datas Saved!');
                    }, function (tx, error) {
                        console.log(error);
                        console.log('Datas Error On Save');
                    });
                });
            },
            updateData: function (url,keyword,position) {
                //console.log('Verif avant add: '+url);
                db.transaction(function (tx) {
                    var addedOn = new Date().getTime();
                    tx.executeSql('UPDATE DB SET url=?,keyword=?,position=?,added_on=? WHERE url=? AND keyword=?',
                    [url,keyword,position,addedOn, url,keyword],
                    function (tx,result) {
                       console.log('Datas Updated!');
                    }, function (tx, error) {
                        console.log(error);
                        console.log('Datas Error On Save');
                    });
                });
            },
            getAllDatasItems: function (renderFunc) {
                db.transaction(function (tx) {
                    tx.executeSql('SELECT * FROM DB', [], renderFunc, this.onError);
                });
            },
            getAllDatasItemsByCat: function (renderFunc) {
                db.transaction(function (tx) {
                    tx.executeSql('SELECT * FROM DB ORDER BY position DESC', [], renderFunc, this.onError);
                });
            },
            deleteData: function (id) {
                db.transaction(function (tx) {
                    tx.executeSql('DELETE FROM DB WHERE ID=?', [id], null, this.onError);
                });
            }
        };
    }();
})(jQuery);

Ce fichier est en fait le fichier qui servira de lien entre la base de donnée Sqlite et ton extension … Je ne m’étale pas trop, je te laisse décortiquer le code…Mais en règle générale, ce sont des requêtes que l’on retrouve un peu partout dans les autres languages. Si tu joues avec PHP, tu devrais t’y retrouver assez rapidement !

Voila, on a fait le plus gros en fait…le moteur est prêt, il faut habiller le Bébé !

Je reviens donc a la base de mon dossier js/ j’ouvre helpers.js et je lui colle ceci:

/*========================= Ext Version =========================*/
chrome.extension.getVersion = function () {
if (!chrome.extension.version_) {
//console.log(chrome.extension);
var a = new XMLHttpRequest;
a.open("GET", chrome.extension.getURL("manifest.json"), false);
a.onreadystatechange = function () {
if (this.readyState == 4) {
var b = JSON.parse(this.responseText);
chrome.extension.version_ = b.version.toString();
}
};
a.send()
}
return chrome.extension.version_;
};
var ExtVersion =  chrome.extension.getVersion();
/*========================= Badges Color =========================*/
function blueBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [100, 149, 237, 255]
})
}
function redBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [227, 38, 54, 255]
})
}
function blackBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [0, 0, 0, 255]
})
}
function whiteBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [255, 255, 255, 255]
})
}
function greenBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [141, 182, 0, 255]
})
}
function greenLawBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [124, 252, 0, 255]
})
}
function purpleBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [102, 102, 255, 255]
})
}
function orangeBadge() {
chrome.browserAction.setBadgeBackgroundColor({
color: [255, 153, 0, 255]
})
}
function notify(title,url,time) {
var notification = webkitNotifications.createNotification(
'img/icon128.png',                                       // The image.
title, // The title.
url                                   // The body.
);
notification.show();
setTimeout(function(){
notification.cancel();
}, time);
}
function notifyHTML(url,link,anchor,time) {
var link = link;
var anchor = anchor;
var notification = webkitNotifications.createHTMLNotification(url);
notification.show();
setTimeout(function(){
notification.cancel();
}, time);
}
function date (format, timestamp) {
// http://kevin.vanzonneveld.net
//http://phpjs.org/functions/date:380
var that = this,
jsdate, f, formatChr = /\?([a-z])/gi,
formatChrCb,
// Keep this here (works, but for code commented-out
// below for file size reasons)
//, tal= [],
_pad = function (n, c) {
if ((n = n + '').length < c) {
return new Array((++c) - n.length).join('0') + n;
}
return n;
},
txt_words = ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"];
formatChrCb = function (t, s) {
return f[t] ? f[t]() : s;
};
f = {
// Day
d: function () { // Day of month w/leading 0; 01..31
return _pad(f.j(), 2);
},
D: function () { // Shorthand day name; Mon...Sun
return f.l().slice(0, 3);
},
j: function () { // Day of month; 1..31
return jsdate.getDate();
},
l: function () { // Full day name; Monday...Sunday
return txt_words[f.w()] + 'day';
},
N: function () { // ISO-8601 day of week; 1[Mon]..7[Sun]
return f.w() || 7;
},
S: function () { // Ordinal suffix for day of month; st, nd, rd, th
var j = f.j();
return j > 4 || j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th';
},
w: function () { // Day of week; 0[Sun]..6[Sat]
return jsdate.getDay();
},
z: function () { // Day of year; 0..365
var a = new Date(f.Y(), f.n() - 1, f.j()),
b = new Date(f.Y(), 0, 1);
return Math.round((a - b) / 864e5) + 1;
},
// Week
W: function () { // ISO-8601 week number
var a = new Date(f.Y(), f.n() - 1, f.j() - f.N() + 3),
b = new Date(a.getFullYear(), 0, 4);
return _pad(1 + Math.round((a - b) / 864e5 / 7), 2);
},
// Month
F: function () { // Full month name; January...December
return txt_words[6 + f.n()];
},
m: function () { // Month w/leading 0; 01...12
return _pad(f.n(), 2);
},
M: function () { // Shorthand month name; Jan...Dec
return f.F().slice(0, 3);
},
n: function () { // Month; 1...12
return jsdate.getMonth() + 1;
},
t: function () { // Days in month; 28...31
return (new Date(f.Y(), f.n(), 0)).getDate();
},
// Year
L: function () { // Is leap year?; 0 or 1
return new Date(f.Y(), 1, 29).getMonth() === 1 | 0;
},
o: function () { // ISO-8601 year
var n = f.n(),
W = f.W(),
Y = f.Y();
return Y + (n === 12 && W < 9 ? -1 : n === 1 && W > 9);
},
Y: function () { // Full year; e.g. 1980...2010
return jsdate.getFullYear();
},
y: function () { // Last two digits of year; 00...99
return (f.Y() + "").slice(-2);
},
// Time
a: function () { // am or pm
return jsdate.getHours() > 11 ? "pm" : "am";
},
A: function () { // AM or PM
return f.a().toUpperCase();
},
B: function () { // Swatch Internet time; 000..999
var H = jsdate.getUTCHours() * 36e2,
// Hours
i = jsdate.getUTCMinutes() * 60,
// Minutes
s = jsdate.getUTCSeconds(); // Seconds
return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3);
},
g: function () { // 12-Hours; 1..12
return f.G() % 12 || 12;
},
G: function () { // 24-Hours; 0..23
return jsdate.getHours();
},
h: function () { // 12-Hours w/leading 0; 01..12
return _pad(f.g(), 2);
},
H: function () { // 24-Hours w/leading 0; 00..23
return _pad(f.G(), 2);
},
i: function () { // Minutes w/leading 0; 00..59
return _pad(jsdate.getMinutes(), 2);
},
s: function () { // Seconds w/leading 0; 00..59
return _pad(jsdate.getSeconds(), 2);
},
u: function () { // Microseconds; 000000-999000
return _pad(jsdate.getMilliseconds() * 1000, 6);
},
// Timezone
e: function () {
throw 'Not supported (see source code of date() for timezone on how to add support)';
},
I: function () {
var a = new Date(f.Y(), 0),
// Jan 1
c = Date.UTC(f.Y(), 0),
// Jan 1 UTC
b = new Date(f.Y(), 6),
// Jul 1
d = Date.UTC(f.Y(), 6); // Jul 1 UTC
return 0 + ((a - c) !== (b - d));
},
O: function () { // Difference to GMT in hour format; e.g. +0200
var a = jsdate.getTimezoneOffset();
return (a > 0 ? "-" : "+") + _pad(Math.abs(a / 60 * 100), 4);
},
P: function () { // Difference to GMT w/colon; e.g. +02:00
var O = f.O();
return (O.substr(0, 3) + ":" + O.substr(3, 2));
},
T: function () {
return 'UTC';
},
Z: function () { // Timezone offset in seconds (-43200...50400)
return -jsdate.getTimezoneOffset() * 60;
},
// Full Date/Time
c: function () { // ISO-8601 date.
return 'Y-m-d\Th:i:sP'.replace(formatChr, formatChrCb);
},
r: function () { // RFC 2822
return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb);
},
U: function () { // Seconds since UNIX epoch
return jsdate.getTime() / 1000 | 0;
}
};
this.date = function (format, timestamp) {
that = this;
jsdate = ((typeof timestamp === 'undefined') ? new Date() : // Not provided
(timestamp instanceof Date) ? new Date(timestamp) : // JS Date()
new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
);
return format.replace(formatChr, formatChrCb);
};
return this.date(format, timestamp);
}
function formatTime(unixTimestamp) {
var dt = new Date(unixTimestamp * 1000);
var hours = dt.getHours();
var minutes = dt.getMinutes();
var seconds = dt.getSeconds();
if (hours < 10)
hours = '0' + hours;
if (minutes < 10)
minutes = '0' + minutes;
if (seconds < 10)
seconds = '0' + seconds;
return hours + ":" + minutes + ":" + seconds;
}

Pas bien difficile à comprendre, la première fonction lit le fichier manifest.json pour truver la version du plugin ( la flemme de modifier un fichier html de plus pour changer un numéro de version ? cette fonction va t’être utile ;) ) => un simple document.write(ExtVersion); et hop ! Tu n’auras plus qu’a changer dans le fichier manifest et c’est tout !

Les fonction suivantes permettent de faire des badges de couleurs différentes, les badges sont des petits carrés qui apparaissent sur les icône de certaines extensions avec des chiffres bien souvent car un ne peut pas trop en mettre, mais pour afficher le pagerank d’une page par exemple c’est tout de même sympas…Et comme j’ai une extension qui peut afficher plusieurs type de Badge, et bien voici les fonctions toutes faites ;)

Et enfin, quelques fonctions de date pour formater ce que l’on va ressortir de la base de donnée. Et deux fonctions de notifications  ( les notifications sont des petites fenêtres qui apparaissent lorsque l’extension le demande…généralement en bas à droite de l’écran ( on va les utiliser dans notre extension )

Voilà, maintenant, l’extension elle-même

Tu vas commencer par le popup et le manifest.json, comme tu pourras déjà afficher ton plugin tout beau tout neuf :)

Dans le fichier popup.html, il nous faut un lien pour aller voir notre tableau de posisition, et un formulaire pour ajouter une url et un mot clé ! Allez hop !

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Démo Checker</title>
<link rel="stylesheet" type="text/css" href="css/popup.css" />
<script type="text/javascript" src="js/libs/jquery.min.js"></script>
<script type="text/javascript" src="js/libs/webDB.js"></script>
</head>
<body>
<a href="#" onclick="loadOptionsPage();return false;">Mes positions</a>
<h2>Ajouter une url</h2>
<form id="form">
<input type="text" name="url" id="url" value="Votre Url" />
<input type="text" name="keyword" id="keyword" value="Votre Mot Clé" />
<input type="submit" id="submit" value="enregistrer" />
</form>
<script type="text/javascript">
$.DB.open();
$.DB.createTable();
$('#form').submit(function(){
var url = $('#url').val()|| '';
var keyword = $('#keyword').val()|| '';
//save DB
$.DB.saveData(url,keyword,'N/A');
$('#submit').val(url+' est enregistré');
return false; 
});
function loadOptionsPage(){
chrome.tabs.create({ url: chrome.extension.getURL('options.html')});
}
</script>
</body>
</html>

On appele donc bien jQuery et le fichier webDB pour enregistrer nos données…On a notre formulaire d’enregistrement qui réponds lors de la soumission par un enregistrement en base de donnée. Puis tu as ton lien qui va charger la page option.html de ton extension ou nous allons placer ton tableau !

Alors attention ici, Chrome empêche de mettre des liens cliquables dans le popup … Au lieu de celà, il faut lui faire créer une fenêtre avec la page en question… d’où la fonction loadOptionsPage() appelé dans le lien par onclick= »loadOptionsPage();return false; »

Voilà pour ta page popup … qui se déclenchera lorsque tu cliquera sur l’icone de ton extension sous chrome !

On y va pour le fichier manifest.json, qui va nous permettre de lancer tout ça correctement :

{
"description": "Demo d'une creation d'extension !",
"name": "Demo Creation Extension",
"version": "1.0",
"browser_action": {
"default_icon": "img/icon.png",
"default_title": "Demo Extension",
"popup": "popup.html"
},
"background_page": "background.html",
"options_page": "options.html",
"content_scripts": [ {
"css": [ "css/content_script.css" ],
"js": [ "js/libs/jquery.min.js","js/content_script.js" ],
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ],
"icons": {
"128": "img/icon128.png",
"48": "img/icon48.png"
},
"permissions": [ "http://*/*", "https://*/*", "tabs", "notifications" ],
"update_url": "http://www.site.com/updates.xml"
}

Voilà ça c’est bon…Pour à présent lancer ton application, il va te falloir trois images ( icon.png de 19*19, icon128.png de 128*128 et icon48.png de 48*48 ) rien de bien sorcier, le tout placé dans img/ normalement en racine de ton extension… ou imgs/ il m’arrive de changer entre 2 :)

Sans tes images, ton extension va charger le fichier manifest et vérifier si tout ce que tu y dis est disponible donc les images, les fichiers CSS, les fichier JS et HTML également. Donc attention a ne pas faire de faute…Si l’extension ne charge pas de toute façon, tu sauras que c’est ici que tu dois regarder en premier

Donc comme on voit un content_script.css, il est judicieux de créer de suite le fichier css/content_script.css même s’il reste vide pour le moment ! Idem pour js/content_script.js

Et enfin nos permissions … qui sont essentielles pour faire tout ce que l’on souhaite ! Ici accès possible a toute protocol http https ( l’extension n’a pas de limite…on va pouvoir chercher nos positions sur Google.fr ), tabs pour permettre la création de nouvelle fenetres ( l’appel à la page d’option par exemple ), et enfin les notifications car dans les mises à jour on va afficher un pti truc du style: « Site: toto.com » position sur le mot: toto => 2ème

Voilà…on vérifie que tous les fichiers par défaut soit faits ( CSS, HTML, JS ) … Tu vas ensuite dans ton repertoire extension sur chrome ( clé à molette => outils => extensions ), tu cliques sur « Mode Développeur » en haut a droite et tu clic sur « Charger l’extension non empaquetée« .

Là tu cherche le repertoire de ton extension ( par exemple /ma-premiere-extension/ ) et tu charges…Si tout va bien, ton icône 19*19 va apparaitre dans ta barre de plugin en haut a droite du navigateur… et dans le gestionnaire des extensions, tu verras un paragraphe en plus sur ta magnifique extension ( icone128 je crois et les infos importantes ).

Si tu ne vois rien … Et bien pas de bol, direction le manifest.json et on vérifie que tout est clean … parfois un S manquant comme j’ai souvent le tour avec mes dossiers img/ V.S. imgs/

Sur ce, hein, je ne sais pas pour toi mais j’ai faim…Alors je te dis à la prochaine pour continuer tout ça…encore deux ou trois articles je pense ! Mais aujourd’hui, tu as déjà de quoi faire.

La prochaine fois, on se fait le background.js, un pti peu de css si tu ne t’ai pas encore amusé avec … on verra comment ressortir nos données de la table Sqlite pour faire un tableau avec petite option de + – ou = lors des mises à jours qui te permettra de savoir si ta position a changé en bien ou en mal ;)

Allez, laisse moi un pti commentaire…ça va me motiver à rédiger plus vite loustic va ! Et pense à moi si tu trouves des fautes hein, je tape vite et je zappe des choses parfois ;)

(638 lectures)

Vous utilisez ces astuces ?

Tous les jours dans votre boite mail, une astuce pour réussir en ligne...
cher lecteur

A votre avis serait-il intéressant pour moi de vendre votre adresse mail 5€ alors que l'abonné moyen à cette newsletter me rapporte plus de 15€ ? Comme les 7000+ abonnés là avant vous, vous n'avez pas grand chose à craindre.

[personnalize var="fn"]

Footer

Copyright © 2009–2021 | Contactez-moi | Mentions Légales | Plan de site | Témoignages | Devenir Riche A Paris

  • Support
  • Affiliation
  • Blog
  • Forum de discussion