XAjax und Gears

Thopeto

Erfahrenes Mitglied
Hallo

Ich möchte in meinem CMS Google Gears unterstützen und zwar wie folgt:

Gears macht Webseiteninhalte offline verfügbar. Dies möchte ich nun nutzen. Vorher war es so, dass wenn Besucher auf ps3 geklickt hat, eine Seite geladen wurde, auf der ein Xml Request abgeschickt wurde, um die angeforderten News zu sortieren und zu bekommen. Die Ausgabe bestand dann darin, dass der Besucher alle RSS News über das Thema PS3 bekommen hat.

Nun möchte ich dies mit Gear schneller gestalten. gears gibt ja dem Webdesigner die Möglichkeit, Seiten im Hintergund zu aktualisieren. Das heißt, wenn der Besucher auf der Startseite ist, kann ja im Hintergrund schon die ps3 news aktualisiert werden. So dass er dann beim öffnen der PS3 News Seite die Daten local und somit schneller bekommt. Wie könnte ich das realisieren?

Im Body Tag wird die Xajax funktion geladen, die den Xml Request abschickt und auch ausgibt:
Code:
<body onLoad="xajax_getRSSFeeds(7');">
die Zahl 7 sagt mit dann das alle SQL Einträge mit der Kategorienummer 7 damit gemeint ist(PS3 News z.B.).

eine PHP Funktion führt dass dann aus und gibt den fertigen Html Code aus und zwar zum Element "resultContainer":

HTML:
<div id="resultContainer"></div>

Jetzt könnte ja der besucher, der gears hat, das ganze Prozedere überspringen und die Daten ja local laden. Wie müsste ich da den Ablauf ändern?

Meine Idee wäre, dass ich eine weitere Funktion erstelle, die überprüft, ob der Besucher Gears hat und wenn ja, eien locale Datei läd und wenn nicht, eben diesen Request vornimmt:

Code:
<script src="gears_init.js"></script>
<script>
  if (!window.google || !google.gears) {
    xajax_getRSSFeeds(7');">
  } else {
    // lade die Datei
  }
</script>

Meint ihr das haut so hin?

Gruß
Thorsten

Ps: Um zu sehen, was ich meine PetriPlay.de
 
dsa mach ich ja mir hasPermission dann. ich lade das aber in die Datenbank statt in extra Dateien. da diese operation von gears nicht wirklich unterstützt wird :(
 
Ich habe es geschafft. Zwei Tage lang habe ich mich durch die Doku von Gears gelesen und mich bei google wundgesucht. Aber am Ende habe ich es geschafft. Hier einmal ein paar erklärungen für die, die gears auch in ihr CMS integrieren wollen.

Es geht darum, die langen Sortieroperationen, die jedesmal auf ein neues durchgeführt werden, zu cachen, da sich der Inhalt allerhöchstens einmal in einer Stunde ändert.

Als allererstes wird überprüft, ob der Besucher überhaupt Gears bei sich aktiviert hat:
Code:
<script type="text/javascript">
          function drawGameResults(plattform,time) {
            if(!ppGears.gearsLoad(plattform,time))
              xajax_showGameResults(plattform);
        }
        </script>
wenn er Gears nicht hat, wird die normale xajax funktion aufgerufen. ansonsten soll nun Gears unterstützen werden.

Code:
  gearsLoad : function(plattform,time) {
    // Gears initialisieren
    if(!this.gearsInit())
      return false;
    
    // Die URL, woher ich meine Daten dann bekomme
    var urlOfPlattform = 'plattform_' + escape(plattform) + '.htm';
         
    // Da wir in die Datenbank des Besuchers schreiben,
    // brauchen wir eine Erlaubnis.     
    if(!google.gears.factory.hasPermission) 
      if(!google.gears.factory.getPermission('PetriPlay'))
        return false;
    
    var db = google.gears.factory.create('beta.database');
                
    // Datenbank exisitiert?
    db.open('dbDeineDatenbank');
    db.execute('CREATE TABLE IF NOT EXISTS table (' +
                       'tableField1 INT AUTO_INCREMENT ,' +
                       'tableField2 VARCHAR( 255 ) ,' +
                       'PRIMARY KEY ( plattformNr )' +
                       ')');
       
    // haben wir Eintr&auml;ge von dieser Plattform in der DB?
    var rs = db.execute('SELECT * FROM table WHERE tableField2 = ? ORDER BY tableField1 DESC',[plattform]);        
    
    // Wenn es Einträge gibt dann überprüfe auf Inhalt
    if(rs.isValidRow()) {
      if(rs.fieldByName('plattformValue') != '') {
        // Gib den Eintrag dem Benutzer aus
        this.gearsPrint(this.divGameResults,rs.fieldByName('tableField2'));
        rs.close();
      } else {
        // Leerer Eintrag ersetzen
        rs.close();
        db.execute('DELETE FROM table WHERE tableField1 = ?',[plattform]);
        db.close();
                  
        this.gearsOpenFile(urlOfPlattform,plattform,time);
      }
    } else {
      // Keine Eintr&auml;ge vorhanden
      // Neue Daten holen
      db.execute('DELETE FROM ppPlattform WHERE plattformKat = ?',[plattform]);
      db.close();
                
      this.gearsOpenFile(urlOfPlattform,plattform,time);
    }
    return true;
  }
Ich habe den MySQL Code natürlich aus sicherheitsgründen etwas abgeändert. Aber so funktioniert es bei mir. Eigentlich wollte ich das ganze ohne Datenbank lösen und auf Dateien zurückgreifen, aber das funktioniert leider nicht so, wie ich es haben wollte. Gears hat da nicht wirklich eine unterstützung.

Doch was bringt das ganze:

Vorteil::
- weniger Datentransfer
- schnelleres Anzeigen der Daten
- weniger Prozesse für den Server
- spart Resourcen

Nachteil:
- bleibt nur Besuchern vorenthalten, die Gears haben
- aktualisierung nur nach eine gewissen Zeit(bei mir 1 stunde)

Ansonsten bin ich sehr zufrieden. Es ist schon beeindruckend, wieviel Gears ausmachen kann. Die Daten sind sofort verfügbar. Einfach klasse!

Wenn jmd noch Ideen oder Fragen oder Kritik hat, der kann es gerne hier reinschreiben.

gruß
Thorsten

PS: ich baue heute abend workerPool ein. Damit im hintergund der Abgleich der Daten stattfinden kann, so dass der Besucher davon nichts bemerkt und somit nicht gestört wird.
 
Zuletzt bearbeitet:
Moin,

find ich Klasse, dass du deine Ergebnisse zur Verfügung stellst, ich glaube Gears ist eine Sache mit grossem Zukunftspotential :)
 
Vielen dank. Ich empfehle auch jedem, der auf seiner Webseite große Prozesse am laufen hat, sich Gears anzuschauen.

Die ganze Api ist Google typisch geschrieben. D.h. sehr sauber und ohne große Irritationen.
Wenn Ihr bisher dazu noch Fragen habt, dann stellt sie, ich hab dass momentan noch gut im Gedächtnis :D

Ich baue heute abend noch den WorkerPool ein. Das wird ebenfalls sehr interessant und ist eins der effektivsten Module von Gears, da er aufwendige Prozesse im Hintergund startet und den Besucher trotzdem das surfen ohne irgendwelchen Einschränkungen ermöglicht.

gruß
Thorsten


PS: Die gearsInit() funktion sieht so aus:

Code:
  gearsInit : function() {
    if(!window.google || !google.gears)
      return false;
    else
      return true;
  },
 
also das mit dem WorkerPool lass ich jetzt mal. Da tauchen fehler auf, wo keine seien sollten. Das mein Worker 1 kein message handling habe, was haber nicht stimmen konnte. Naja, who care. integriere Gears weiter in mein CMS. Es folgen also noch weitere Beiträge :-D
 
hi leute, hier mal die Klasse, welche in meinem CMS die Artikel offline verfügbar macht. Sie ist in PHP geschrieben und sehr unordentlich und buggy:

PHP:
<?php 

define(GEARS_UPLOAD_PATH, "my/path/");

class tpGears {
  var $sql;
  var $user;
  var $table;
  
  var $path;
  var $tplPath;
  
  var $manifestContent;
  var $entries;
  
  function tpGears($sql,$user,$path,$tplPath) {
    $this->sql = $sql;
    $this->user = $user;
    $this->table = 'gearsTable';
    
    $this->path = $path;
    $this->tplPath = $tplPath;
    
    $this->manifestContent = "";
    $this->entries = "";
  }

  function createTable() {
    $sqlQuery = 'CREATE TABLE gearsTable (';
    $sqlQuery .= 'gearsURL VARCHAR( 255 ) NOT NULL ,';
    $sqlQuery .= 'gearsUser INT NOT NULL ,';
    $sqlQuery .= 'PRIMARY KEY ( gearsURL )';
    $sqlQuery .= ') TYPE = MYISAM ;';
    
    $this->sql->tpExecute($sqlQuery);
    return 'Table created';
  }

  function getTable() {
    return $this->table;
  }

  function add($url) {
    if($this->urlAlreadyListed($url))
      return 'Seite wurde bereits hinzugef&uuml;gt';
      
    $sqlQuery = "INSERT INTO ".$this->getTable()." (gearsURL,gearsUser) VALUES ('".addslashes($url)."',".$this->user.")";
    
    $this->sql->tpExecute($sqlQuery);
    return 'Seite hinzugef&uuml;gt';
  }

  function urlAlreadyListed($url) {
    $result = $this->sql->tpExecute("SELECT * FROM ".$this->getTable()." WHERE gearsURL = '".addslashes($url)."' AND gearsUser = ".$this->user);
    if($result->tpNumRows() > 0) {
      $result->freeMySQL();
      return true;
    } else {
      $result->freeMySQL();
      return false;
    }
  }

  function delete($url) {
    $sqlQuery = "DELETE FROM ".$this->getTable()." WHERE gearsURL = '".addslashes($url)."' AND gearsUser = ".$this->user;
    
    $this->sql->tpExecute($sqlQuery);
    return 'Seite gel&ouml;scht';
  }

  function clear() {
    $sqlQuery = "DELETE FROM ".$this->getTable()." WHERE gearsUser = ".$this->user;
    
    $this->sql->tpExecute($sqlQuery);
    
    
    return 'Liste geleert';
  }

  function createDesktopIcon() {
  }

  function buildManifest() {
    $version = 'pp_ver_'.time();
    
    $workAround = '../..';

    $this->manifestContent = "{\r\n";
    $this->manifestContent .= "\t\"betaManifestVersion\": 1,\r\n";
    $this->manifestContent .= "\t\"version\": \"".$version."\",\r\n";
    $this->manifestContent .= "\t\"entries\": [\r\n";
    
    $result = $this->sql->tpExecute("SELECT * FROM ".$this->getTable()." WHERE gearsUser = ".$this->user);
    while($result->tpFetchAssoc()) {
      $this->addManifestEntry(stripslashes($workAround.$result->tpGetValue('gearsURL')));
    }
    $result->freeMySQL();

    $this->addManifestEntry($workAround."/index.htm",true);
    
    $this->manifestContent .= $this->entries;
    $this->manifestContent .= "\t]\r\n";
    $this->manifestContent .= "}";
    
    $fp = fopen($this->path.$this->getManifestName(), "w+");
    fwrite($fp, $this->manifestContent);
    fclose($fp);
    
    return "Liste wurde zusammengestellt. PetriPlay aktualisiert die Daten - Bitte warten...";
  }

  function addManifestEntry($url,$end = false) {
    if(!$end)
      $this->entries .= "\t{ \"url\": \"".$url."\"},\r\n";
    else
      $this->entries .= "\t{ \"url\": \"".$url."\"}\r\n";
  }

  function render($path) {
    loadApi("tpTemplate");
    $tpl = new tpTemplate();
    $tpl->tpLoad($this->tplPath."api/gears_download.tpl");
    
    $tpl->tpDefineBlock("gearsList");
    $result = $this->sql->tpExecute("SELECT * FROM ".$this->getTable()." WHERE gearsUser = ".$this->user);
    while($result->tpFetchAssoc()) {
      $tpl->tpReplaceBlock("item.url",stripslashes($result->tpGetValue('gearsURL')));
      $tpl->tpEndBlockLoop();
    }
    $result->freeMySQL();
    $tpl->tpParseBlock();
    
    return $tpl->tpGetContent();
  }

  function getManifestName() {
    return "pp_".$this->user."_gmanifest.json";
  }
}

?>

und nun die jscript funktion:
Code:
gearsCreateManifest : function(fileManifest,resultID,progressMsg,completeMsg) {
    if(!ppGears.gearsInit())
      return false;
    		    
    if(!ppGears.gearsPermission())
      return false;
      
    var divID = resultID;
      
    var localServer = google.gears.factory.create('beta.localserver');
    var store = localServer.createManagedStore('petriplay-store');
    store.manifestUrl = fileManifest;
    
    store.onerror = function () {
      var divHandle = document.getElementById(divID);
      divHandle.innerHTML = store.lastErrorMessage;
    };
    
    store.onprogress = function () {
      var divHandle = document.getElementById(divID);
      divHandle.innerHTML = progressMsg;
    };
    
    store.oncomplete = function () {
      var divHandle = document.getElementById(divID);
      divHandle.innerHTML = completeMsg;
    };
  
    store.checkForUpdate();
  },

Wie das ganze dann fertig aussieht, könnt ihr auf petriplay.de anschauen, wenn ihr auf einen artikel klickt. unter diesem Artikel sind dann Buttons. Einer davon hat einen Pfeil nach unten gerichtet drauf. Den müsst ihr anklicken.

Das sieht wirklich gut aus und ich muss zugeben, echt gelungen.:rolleyes:

Tutorial wird schwer, da es extrem in mein cms eingebunden wurde. aber wenn jmd fragen hat, helf ich gerne.

gruß
Thorsten
 
Zurück