Archive for the 'Haladó szint' Category

Üzenetsablonok használata

Korábban bemutattuk, hogy az OpenSocial üzenet sablonok hogyan használhatóak csoportosított hírfolyam elemek küldéséhez, de nem ejtettünk szót arról, hogy milyen egyéb felhasználási lehetőségeik vannak: lehetőség van az alkalmazások többnyelvűvé tételére, illetve ezt a lehetőséget használhatjuk az alkalmazáson belül megjelenített szövegekhez akkor is, ha nem célünk a többnyelvűség.

Alkalmazáson belüli felhasználás

Ha az alkalmazáson belül egy üzenetet, szöveget szeretnénk valahol megjeleníteni, és szeretnénk betartani az MVC mintát, akkor jól jöhetnek az üzenet sablonok. A sablonok tartalma (definiálásukat lásd a korábbi bejegyzésünknél) egyszerűen lekérdezhető a következő JavaScript kódrészlettel:

var prefs = new gadgets.Prefs();
var text = prefs.getMsg("hello_world");

A “text” változóban a “hello_world” name paraméterű üzenet szövegét fogjuk megkapni. Az OpenSocial nem kínál olyan függvényt, mely segítségével sablon változók feloldhatóak lennének, de egy ilyet könnyen írhatunk saját magunk is:

if (!iWiW) iWiW = {};
iWiW.getMsg = function(name, parameters) {
  var prefs = new gadgets.Prefs();
  var template = prefs.getMsg(name);
  if (parameters) for (var p in parameters) {
    template = template.replace('${' + p + '}', parameters[p];
  }
  return template;
}

Ha a “szorzas” nevű sablonunk szövege “Az ${a}*${b} szorzás eredménye ${c}”, akkor a függvény az iWiW.getMsg(”szorzas”, { ‘a’: 2, ‘b’: 2, ‘c’: 5 }); formában hívható meg.

Az sablonok szövege azonban nem csak JavaScriptből kérdezhető le, az alkalmazás XML-jében bárhol tudunk hivatkozni rá, és az OpenSocial előfeldolgozó lecseréli a hivatkozást a megfelelő szövegre. Avagy a fent elsőként bemutatott “bonyolult” kódrészlet helyett írhatjuk ezt is:

var text = '__MSG_hello_world__';

A “__MSG_azonosító__” (az egyértelműség kedvéért: az idézőjelet nem kell köréírni) szerepelhet bárhol az alkalmazás XML-jében, tehát a HTML vagy a CSS részekben is. Amire figyelni kell, hogy a fenti példa nem működik jól, ha az üzenet szövegében aposztróf is szerepel, hiszen ekkor nincsen megfelelően escape-elve az aposztróf karakter, s JavaScript hibát fogunk kapni (JavaScript kódrészbe az előbb ismertetett módon célszerű használni a sablonokat).

Többnyelvű alkalmazások

Bár az iWiW kapcsán jellemzően csak magyar nyelvű alkalmazások készülnek, de a sablonok jól használhatóak többnyelvű alkalmazások készítéséhez is (ráadásul eredetileg ebből a célból lett implementálva a funkció). Ha más OpenSocialt támogató oldallal is szeretnénk kompatibilissé tenni alkalmazásunkat, akkor mindenképpen célszerű a sablonok használatát választanunk.

A sablonok definiálásakor kell megadnunk a nyelvet:

<ModulePrefs>
  <Locale messages="http://example.hu/messages_HU.xml"/>
  <Locale messages="http://example.hu/messages_EN.xml" lang="EN"/>
</ModulePrefs>

Ebben a példában a magyar nyelvű üzenet definíciókhoz nem adtunk meg nyelvet - ezt választottuk alapértelmezettnek -, az angol nyelvű üzeneteknél a “lang” paramétert használtuk az nyelv megadásához. Ha az alkalmazást angol nyelvű környezetben töltik be, akkor a “messages_EN.xml” lép érvénybe, minden más esetben pedig a magyar nyelvű szövegek.

A témakörről itt bővebben is lehet olvasni.

Hírfolyam az iWiW nyitóoldalon: csoportosítás

Zárva a bejegyzés sorozatunkat a címlapon megjelenő hírfolyam elemek kapcsán, bemutatjuk a második opciót, melyet használhattok a hírek kiküldésekor: a csoportosítást. Ennek kapcsán az OpenSocial activity két további lehetőségét vezettük be az iWiW-en a hírfolyam elemeknél: a sablonok támogatását, és a hírfolyam elemek csoportosítását. A bejegyzésben bemutatjuk a sablonok használatát, illetve hogy hogyan készíthetőek olyan sablonok, melyek csoportosításra is alkalmasak.

Sablonok

Hírfolyam sablonokat kétféleképpen lehet hozzáadni alkalmazásunkhoz: vagy az alkalmazás XML-jébe ágyazva, vagy külső fájlként meghivatkozva (szintén XML formátum). Mindkét esetben a ModulePrefs részbe kerülnek információk. Az XML-ben elhelyezés a következőképpen néz ki (természetesen ahogy eddig is, a ModulePrefs további tulajdonságai, gyermek elemei megadandóak):

<ModulePrefs>
  <Locale>
    <msg name="uzenet_cime">
      Hello Világ!
    </msg>
    <msg name="uzenet_szovege">
      Ez itt egy szimpla Hello Világ üzenet.
    </msg>
  </Locale>
</ModulePrefs>

A példában ugyan két üzenet szerepel csak, de bármennyit definiálhatunk. Az üzenetek címét és szövegtörzsét két külön sablonnal kell definiálni. Külső XML-re hivatkozni pedig így lehet:

<ModulePrefs>
  <Locale messages="http://example.hu/my-activity-messages.xml"/>
</ModulePrefs>

A hivatkozott XML felépítése:

<?xml version="1.0" encoding="UTF-8"?>
<messagebundle>
  <msg name="uzenet_cime">
    Hello Világ!
  </msg>
  <msg name="uzenet_szovege">
    Ez itt egy szimpla Hello Világ üzenet.
  </msg>
</messagebundle>

Egy ilyen üzenet sablonra a “name” tulajdonságával lehet hivatkozni hírfolyam elem létrehozásakor:

var options = {};
options[opensocial.Activity.Field.TITLE_ID] = "uzenet_cime";
options[opensocial.Activity.Field.BODY_ID] = "uzenet_szovege";
opensocial.requestCreateActivity(opensocial.newActivity(options));

Egy sablonban változókat is használhatunk:

<msg name="osszeadas">
  Az ${a} + ${b} művelet eredménye: ${vegeredmeny}.
</msg>

A paramétereket a következőképpen adhatjuk át:

var options = {};
options[opensocial.Activity.Field.TEMPLATE_PARAMS] = { a: "12", b: "13", vegeredmeny: "42" };
options[opensocial.Activity.Field.TITLE_ID] = "uzenet_cime";
options[opensocial.Activity.Field.BODY_ID] = "osszeadas";
opensocial.requestCreateActivity(opensocial.newActivity(options));

Egy speciális változó is rendelkezésünkre áll, “Subject” névvel, és az aktuális felhasználó adataival. Ezt a következőképpen használhatjuk:

<msg name="osszeadas">
  ${Subject.DisplayName} most ütötte meg a főnyereményt.
</msg>

Ezt a paramétert átadnunk sem kell, a példa a felhasználó nevét - belinkelve a profil oldalára - fogja behelyettesíteni.

Tudnivalók az iWiW-en:

  • Minden, a hivatkozott sablonokban szereplő változóhoz értéket kell rendelnünk a TEMPLATE_PARAMS segítségével.
  • Csak string adható át paraméterként, objektum, vagy például egy OpenSocial Person átadása nem támogatott.
  • Sablon használata esetén a rendszer nem teszi automatikusan a hírfolyam elejére a felhasználó nevét, ezt magunknak kell megtennünk. A hírfolyam nevesítése, ahogyan az értesítéseknél is, kötelező.

Csoportosított hírfolyam elemek

A hírfolyam elemek csoportosítása a sablonok segítségével történik. A “sima” hírfolyam elemen felül definiálni kell azok csoportosított változatát is. Csoportosítás a sablon bármely változó eleme alapján történhet. Például egy alap üzenet:

Példa Béla lájkolt egyet.
Madonna zenésztől Like a Virgin szám a kedvence.

Itt változó paraméter lehet a felhasználó neve, az album neve és magának a számnak a neve. Ez sablonnal így nézhet ki:

<msg name="title">${Subject} lájkolt egyet.</msg>
<msg name="body">${artist} zenésztől ${song} szám a kedvence.</msg>

További sablonok segítségével csoportosíthatóvá tehetjük a hírfolyam elemet, például ha (az aktuális felhasználó ismerősei közül) több felhasználó (vagy egy felhasználó, de többször) is ugyanazt az előadót lájkolja, akkor:

<msg name="title:artist">${Subject.Count} ismerősöd ${artist} ${artist.Count} db számát lájkolta.</msg>
<msg name="body:artist">${Subject.List} kedvenc dalai: ${song.List}.</msg>

A sablon neve után kettősponttal kell jeleznünk, hogy melyik változó szerint kívánunk csoportosítani. Ha a hírfolyamban több hír is megjelenne úgy, hogy az adott változó értéke megegyezik, akkor a rendszer csoportosítani fogja azt a csoportosítást lehetővé tevő sablonokat felhasználva. Ebben a példában egyből láthatóak speciális értékek, a .List felsorolásként jeleníti meg az adott sablon paraméter értékeket, a .Count pedig a darabszámot helyettesíti be.

Lehet csoportosítani felhasználó szerint is, avagy ha az adott felhasználó több számot lájkol egymás után, akkor ahhoz így kell sablont rendelni:

<msg name="title:Subject">${Subject} ${song.Count} dalt lájkolt.</msg>
<msg name="body:Subject">Kedvenc dalai: ${song.List}. Kedvenc zenészei: ${artist.List}</msg>

Ha nincs alapértelmezett (nem csoportosított) sablon, akkor a rendszer a nem-csoportosított esetben a sorrendben legelső sablont használja megjelenítésre. A címlapra kikerüléshez kötelező legalább egy jellemző paraméter szerint csoportosítani mindegyik üzenettípust az alkalmazáson belül (az alap üzenet definiálásán kívül).

Végül, de nem utolsó sorban fogadjátok szeretettel példa alkalmazásunkat, a Rádió Aktivitást.

Hírfolyam az iWiW nyitóoldalon: megerősítés

Ahogy korábbi bejegyzésünkben írtuk, az alkalmazások híreinek címlapra kerüléséhez az egyik lehetőség, hogy az alkalmazásnak megerősítést kell kérnie a felhasználótól a hír elküldéséhez. Bár a konkrét megjelenésnek nincsenek részünkről design követelményei, úgy gondoltuk hogy hasznos lehet ha mutatunk egy példát arra, hogy hogyan valósítható meg ez a funkció.

A megerősítés kapcsán fontos tartalmi követelmények, melyeket a megerősítést kérő üzenetnek tartalmaznia kell:

  • tájékoztatás arról, hogy az alkalmazás hírfolyam elemet szeretne kiküldeni, s ehhez hozzájárulást kér
  • a kiküldendő hír pontos szövegének megjelenítése
  • két megegyező méretű, és ugyanolyan jól látható gomb az elfogadásról és az elutasításról
  • opcionálisan egy be nem jelölt checkbox, mely lehetőséget kínál arra, hogy a jövőben ne kelljen elfogadni a hírelem kiküldését

A példa alkalmazásunkban az iWiW fejlesztők között is népszerű jQuery függvénykönyvtárat, illetve az ahhoz készített Boxy kiegészítőt használtuk a megerősítő “popup” megjelenítéséhez. A példakód nincsen túlzottan kipolírozva, de a működés, illetve egy lehetséges megjelenés jól látható belőle:

activity-confirm

Hírfolyam megerősítés

Hírfolyam az iWiW nyitóoldalon: alapok

Az elmúlt napokban a hírfolyamokat illetően több jelentős változás is történt: a hírfolyam elemek köre kibővült számos iWiW-es “core” eseménnyel, több lehetőséget biztosító moderációs lehetőséget adtunk a felhasználók kezébe, továbbá az iWiW nyitóoldalon is megjelennek immáron ezek az információk. A hírfolyam ebben a formában jóval hangsúlyosabb megoldást, egyben az alkalmazások sikeres terjedéséhez jóval hatékonyabb eszközt jelent a korábbi aloldali megjelenéshez képest. Ebben a bejegyzésben összefoglaljuk a változásokat, és leírjuk, hogy milyen feltételekkel lehet megjelenni az alkalmazások activityjével az iWiW nyitóoldalon, a következő két bejegyzésben pedig példakódokkal illusztráljuk az opciókat.

Egy alkalmazás vagy core funkció által küldött hírfolyam elemnek három állapota lehet a megjelenés helyét illetően:

  • sehol sem jelenik meg (felhasználó letiltotta)
  • csak a hírfolyam aloldalon (iwiw.hu/pages/activity/activities.jsp) jelenik meg (ez az alapértelmezés, vagy a felhasználó így rendelkezett)
  • mind a nyitóoldalon, mind a hírfolyam aloldalon megjelenik (ez az alapértelmezés, vagy a felhasználó így rendelkezett)

Az egyes felhasználók szabadon felülbírálva az alapértelmezést letilthatják az adott forrásból származó hírelemeket, vagy a blokkolt alkalmazások oldalról visszaállíthatják, esetleg csak a hírfolyam aloldalra korlátozhatják azokat.

Az iWiW-es funkciók alapértelmezése, hogy a nyitólapon és a hírfolyam aloldalon is megjelennek.

Az API-hoz csatlakozó, általatok fejlesztett alkalmazások tekintetében két opció közül legalább egyet teljesítenetek kell, hogy az adott alkalmazáshoz központilag bekapcsoljuk a nyitólapi megjelenést is. (Az iWiW nyitólapra engedését minden esetben egyedileg fogjuk elbírálni, elképzelhető, hogy a kiengedéshez kérni fogjuk, hogy mindkét kritériumnak feleljen meg az alkalmazás.)

A két opció a következő:

  • Az alkalmazásból kiküldött hírek kapcsán a felhasználótól egy (div-vel megvalósított) “popup” segítségével a felhasználó hozzájárulását kell kérnetek a hírelem kiküldéséhez, tájékoztatva a felhasználót a hírelem pontos tartalmáról, és a kiküldés tényéről.
  • A kiküldött híreknél meg kell valósítanotok a hírelemek csoportosíthatóságát, vagyis hogy a címlapon az adott alkalmazás felől érkező híreket összefoglalva tudja megjeleníteni az iWiW.

A “popup” elkészítését és megjelenését rátok bízzuk, de egy jQuery-re és Boxy-ra épülő megoldást a következő bejegyzésben bemutatunk példaként. Itt a lényeg a fentebb is leírt adattartalom, és hozzájárulás.

A hírelemek csoportosításához üzenet sablonokat kell majd készítenetek, és ezeket használni a kiküldéskor, ezek használatáról, és a pontos technikai részletekről szintén egy külön bejegyzésben fogunk részletesebben is írni.

Medián WebAudit mérőkódok az alkalmazásokban

Az alkalmazások üzleti szempontból egyik legérdekesebb és legfontosabb mérőszáma a látogatottságuk, és a felhasználók különböző demográfiai paraméterei (életkor, nem, stb.). A jövőben minden alkalmazásban mérni fogjuk azok látogatottságát, ehhez partnerünk, a WebAudit biztosít számunkra mérőkódokat. A mérőkódokat az alkalmazás logikája szerint a fejlesztőknek kell elhelyezniük az alkalmazásokban.

A mérőkódok a dinamikus “oldalletöltéseket” mérik. A kódok központi beillesztése az alkalmazásokba pont ezért nem lehetséges, mert az, hogy mi számít oldalletöltésnek, az mindig alkalmazásspecifikus, így függ az alkalmazás logikájától, és az oldalak megjelenítésének technológiájától is.

A mérési eredményekhez és statisztikákhoz nem csak az Origo, de a fejlesztő is hozzáfér majd, ezzel olyan információkhoz jut, melyet jellemzően más statisztika alkalmazások nem tudnak nyújtani, illetve amelyek nyomán lehetőségetek nyílik tovább optimalizálni az alkalmazást a célcsoportotokra is.

Csak és kizárólag az alkalmazás canvas nézete mérendő, oda kell betenni az alábbi kódrészleteket. Két mérésről van szó, egyrészt az iWiW (iwiw.hu) saját mérésébe is be fog számítani egy kód, másrészt pedig az alkalmazás külön is mérve lesz. Ezért minden “oldalbetöltődéskor” két külön kód meghívása szükséges, egy iWiW-es, és egy az alkalmazáshoz tartozó.

A saját mérésetekhez minden alkalmazásnak egy főoldali és 5 aloldal méréséhez vannak kódjaink, míg a másodiknak meghívandó iWiW-es kód az minden oldalbetöltéshez ugyanaz (de alkalmazásonként az is különböző).

A canvas nézet fejlécébe ennek megfelelően be kell húzni a következő JavaScriptet:

<script type="text/javascript" src="http://static.iwiw.net/common/javascript/median.js"></script>

Az oldalak betöltődése után egyrészt az iWiW-es kóddal, másrészt pedig az adott oldal kódjával kell meghívni a WebAudit.measure() függvényt. Az iWiW-es kód mindig ugyanaz, az alkalmazás saját kódja változik.

A WebAudit.measure JavaScript függvényt kell meghívnotok oldalbetöltődéskor, például a főoldal betöltésekor:

WebAudit.measure(...iWiW-es kód...);
WebAudit.measure(...főoldal kód...);

Első aloldal betöltődésekor:

WebAudit.measure(...iWiW-es kód...);
WebAudit.measure(...aloldal1 kód...);

Hogy az adott alkalmazásban mi számít főoldalnak, aloldalnak, azt az iWiW Fejlesztői support-tal (dev kukac iwiw hu) tudjátok egyeztetni azután, hogy e-mailben megkaptátok az alkalmazáshoz tartozó kódokat. A struktúrára első körben várunk tőletek egy javaslatot. Értelemszerűen nem feltétlenül szükséges az összes kódot felhasználni - ha az alkalmazásnak nincs annyi különböző aloldala, akkor nem kell több aloldalt mérni.

A kódok kiosztásával kapcsolatban szeptember első napjaiban folyamatosan felkeressük az élesített alkalmazások tulajdonosait.

Az új, elbírálásra beérkező és jóváhagyásra váró alkalmazások fejlesztőinek az élesítési folyamat során adunk majd kódokat.

Módosul az iWiW Fejlesztői ÁSZF

2009. szeptember 10-i hatállyal módosul az iWiW Fejlesztői ÁSZF (Az iWiW Alkalmazások Általános Szerződési Feltételei Fejlesztők részére).

Az új ÁSZF-et itt olvashatjátok.

A legfontosabb változások röviden:

8.7 - az alkalmazásokba kötelező lesz Medián WebAudit mérőkódokat beépíteni, erre vonatkozóan egy külön részletes blogbejegyzést teszünk közzé a napokban.

17 - az alkalmazásokban megjelenő hirdetésekre csak jogi személyekkel tudunk szerződni.

Alkalmazások élesítése az iwiw.hu alatt

Zajlik a jóváhagyási folyamat, és napokon belül kiküldjük visszajelzéseinket a beküldött alkalmazásokkal kapcsolatosan. Sok alkalmazásnál csak kisebb formai vagy technikai problémák vannak csak, ezek gyors kijavítására számítunk. Az egyes feladatokról e-mailt küldünk.

A következő lépés innen már az alkalmazás élesbe állása, az iwiw.hu alatti megjelenése lesz, az ezirányú teendőiteket gyűjtöttük össze.

Az alkalmazás jóváhagyásáról egy emailt fog kiküldeni a rendszer, de ez nem jelenti az alkalmazás élesbe állását is - ezt a fejlesztő tudja megtenni az alkalmazás Aktív állapotba állításával. Ezt a Fejlesztői Portálon az alkalmazás Vezérlőpult menüpontja alatt éritek majd el.

Amint megkaptátok a formális értesítést a jóváhagyásól, kérjük ellenőrizzétek a következőket:

  • az alkalmazás tesztadatai, a Homokozóban felvitt információk törölve vannak
  • ha az alkalmazás igényli, fel van töltve kezdeti adatokkal, információkkal (pl. a cserebogarak különböző fajtáit bemutató alkalmazás legalább két-három cserebogarat bemutat)
  • az alkalmazás külön kezeli a Homokozót és az éles rendszert, elkülöníti az adatokat. A Homokozó és az éles rendszer mind a JavaScript kódban, mind a szerver oldalon elkülöníthetőek egymástól. JavaScriptből az opensocial.getEnvironment().getDomain() függvényhívás adja vissza az éppen aktuális domaint, míg szerver oldalon a signed requestek segítségével, a kérés során átadott oauth_consumer_key paraméter ellenőrzésével dönthető el, hogy honnan érkezett a kérés.
  • a nem élesbe szánt fejlesztéseket egy külön kódon végzitek, ugyanis amint lejár a cache ideje, vagy amikor frissítitek az alkalmazást a Homokozón, a legfrissebb kód fog megjelenni élesben is

A visszajelzésünk kiküldése után nem lesz sok időd, hamarosan indulunk! Várhatóan április 22-én, szerda reggel állnak élesbe az alkalmazások.

Linkek a történésekben, értesítésekben

Több helyen is leírtuk már, de nem részleteztük: a történésekben és az értesítésekben használhattok linkeket is. Megkötés, hogy ezek csak az iWiWen belülre mutathatnak, külső oldalra nem. A linkek előállítása nem feltétlenül triviális feladat, főként ha ki szeretnétek használni azt a lehetőséget, hogy az alkalmazásoknak paraméterek is átadhatók. Az alábbiakban egy példakódot is közzéteszünk, mely segítségével helyes linkek állíthatóak elő könnyedén.

Ha az iWiWen belülre szeretnénk linkelni, akkor célszerű relatív URL-eket használni. A rendszer ezeket, továbbá a http://iwiw.hu/ és http://sandbox.iwiw.hu/ címmel kezdődő linkeket engedi át. Ez utóbbi abszolút URL-ek használatát nem javasoljuk, mivel egy tévesen meghatározott domainből csak problémák lehetnek.

Leszámítva a profil oldalakra történő linkelést, egy történésben, értesítésben főként magára az alkalmazásra szeretnénk linkelni: ez egy /app/12345678 kinézetű URL-t jelent. A link egyébként /app/{appId}{-prefix|/|userId}{-prefix|?view-params=|viewParams} formátumú, amiből talán a legérdekesebb számotokra a viewParams paraméter. Ennek értéke JSON formátumban adható át, segítségével paraméterezhetjük az alkalmazást. Bár egy linket ennek ismeretében könnyedén előállíhatunk már, hogy még egyszerűbb legyen, egy függvényt is közzéteszünk:

if (typeof IWIW == 'undefined') { var IWIW = {}; }
IWIW.getApplicationLink = function(parameters) {
 return gadgets.views.bind(gadgets.config.get('views')['canvas'].urlTemplate, {
   appId: document.location.host.match(/(\d+)\./)[1],
   viewParams: gadgets.json.stringify(parameters)
 });
}

A függvény nem csinál mást, mint veszi a fentebb is bemutatott URL sablont, s behelyettesíti az alkalmazás azonosítóját (mely a Homokozóban és az éles iWiW-en ugyanaz lesz) és az átadandó paramétereket a gadgets.views.bind függvény segítségével. Az alkalmazás azonosítóját az aktuális URL-ből veszi, a sablont pedig egy OpenSocial konfigurációs változóból olvassa ki.

A használata elég egyszerű:

alert(IWIW.getApplicationLink({'aaa':'bbb'}));

A függvény persze okosítható, és átadható hogy a canvas vagy profil nézethez szeretnénk URL-t, vagy hogy melyik felhasználónak a nézetére szeretnénk linkelni, innen már talán nem nehéz ezeket implementálni, ha szükség van rá.

Ahogy korábban is írtunk már róla a requestNavigateTo bemutatása kapcsán, az átadott paramétereket a következőképpen olvashatjuk ki az alkalmazásban:

var params = gadgets.views.getParams();

Értesítés küldésnél például az alábbi formában használható a linkelés az üzenet BODY-jában, amennyiben egy adott tartalomra szeretnénk linkelni az alkalmazáson belül:

// felhasználó objektum, pl. ismerős lekérdezésből (newFetchPeopleRequest)
var user = ...;
// felhasználó keresztneve
var userName = user.getField(opensocial.Person.Field.NAME).getField(opensocial.Name.Field.GIVEN_NAME);
// felhasználó (pl. ismerős) lekérdezéséből jövő profil URL
var userProfile = user.getField(opensocial.Person.Field.PROFILE_URL);
// link az alkalmazásra, példaként egy contentId paraméterrel
var appLink = IWIW.getApplicationLink({'contentID': 87654321});
// az adott tartalom címe
var contentTitle = 'Boys Don\'t Cry';
// üzenet BODY összeállítása
var messageBody =
  '<a href="' + gadgets.utils.escapeString(userLink)+'">' +
  gadgets.utils.escapeString(userName) + '</a> ajánlja kedvencét: ' +
  '<a href="' + gadgets.utils.escapeString(appLink)+'">' +
  gadgets.utils.escapeString(contentTitle) + '</a>. Neked hogy tetszik?';

Figyeljünk rá, hogy csakis valid XHTML tartalmat lehet az üzenetben elküldeni. Tekintettel arra, hogy a felhasználó nevében szerepelhet HTML-nek nézhető tartalom (kisebb/nagyobb jelek, & karakter), illetve ez igaz lehet a linkekre, a linkelt tartalom címére is, ezért ezeket mindenképpen megfelelően kódolni kell!

Tippek és trükkök

Összejött pár apró tipp és trükk, melyek önmagukban nem töltenek ki egy blogbejegyzést, de adott esetben fontos lehet tudni ezekről a megoldásokról.

A következőkről lesz szó:

  • Flash beágyazása az oldalba
  • Szabványbarát doctype használata (IE6 quirks mode mellőzése)
  • Reklámok kirakása (külső scriptek kimenetének kezelése)
  • Térképek (Google/Yahoo/Live Maps) megjelenítése
  • Profil nézetből Canvas nézetre navigálás

Flash beágyazása

Ha Flash-t szeretnénk betenni az oldalunkba, a legjobb megoldás a gadgets.flash.embedFlash használata lehet. A függvénynek meg kell adni annak a HTML elemnek az id-ját, ahova a Flash-t szánjuk, illetve kell egy <Require feature=”flash” /> is a fejlécbe.

Ha JavaScript-Flash kommunikációt szeretnénk, vagy egyéb Flash lehetőséget, akkor figyeljünk az átadott paraméterekre. Fontos még az is, hogy az embedFlash függvényt init után hívjuk meg.

A beágyazás tehát valahogy így fog működni:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="iWiW Flash" author="DevBlogger" author_email="dev@iwiw.hu" height="600">
<Require feature="opensocial-0.8" />
<Require feature="flash" />
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript">
function init() {
  gadgets.flash.embedFlash('http://videa.hu/flvplayer.swf?v=F0cKU2XjFGTy6VMX', 'videa', 8,
    { 'width': 750, 'height': 600, 'allowFullScreen': true, 'allowscriptaccess': 'always' });
}
gadgets.util.registerOnLoadHandler(init);
</script>
<div id="videa"></div>
]]></Content>
</Module>

DocType módosítás

A hivatalos OpenSocial szabvány szerint az iframe-en belüli HTML kód DOCTYPE nélkül töltődik be, vagyis úgynevezett quirks módban jelenik meg. Ezzel egy nagy gond van: IE6 alatt a doboz modell jelentősen eltér a szabványostól, ami megnehezíti egy minden böngészőben jól működő layout kivitelezését.

A megoldás egy a szabványon túllépő kiegészítés (ha minden igaz, az OpenSocial 0.9 valahogy megoldja ezt a kérdést, de szerettünk volna addig is valamilyen megoldást kínálni), miszerint hogyha a Content elemen belül teljes HTML írunk, akkor nem csak a BODY elemen belüli részt befolyásolhatjuk, hanem a teljes oldal kódját.

Vagyis ha át szeretnénk billenteni szabványos módba az IE6 alatt is a dobozmodellt, akkor a következőképpen kell eljárnunk:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="DocType teszt" author="DevBlogger" author_email="dev@iwiw.hu">
  <Require feature="opensocial-0.8" />
</ModulePrefs>
<Content type="html" view="canvas, profile"><![CDATA[
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
Hello IE6 standards mode!
</body>
</html>
]]></Content>
</Module>

Térképek

Térképek beszúrását igazán csak a Google nehezítette meg, mivel külön fejlesztői kulcsot kell kérnünk domainenként, de jöjjön egy példa a három legnagyobb térkép szolgáltatást illetően. További infókat az egyes szolgáltatások doksijaiban lehet találni.

A Google Maps-hez két kulcsra lesz szükségünk. Mindenekelőtt ezeket szerezzük be a Google Maps API oldalán. Ehhez az alkalmazásunk azonosítójára lesz szükség, ami egy többjegyű szám, pl: 123456789 (a sandboxban megnézhetjük) — a http://123456789.app.sandbox.iwiw.hu és a http://123456789.app.iwiw.hu domainekre kell kérnünk egy-egy kulcsot. Ha ezzel megvagyunk, a következő kód segítségünkre lehet (a kódba írjuk a kulcsokat bele a megfelelő helyre!):

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Google Maps" author="DevBlogger" author_email="dev@iwiw.hu" height="400">
  <Require feature="opensocial-0.8" />
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript">
// kulcsok
var GMapKeys = {
  "sandbox.iwiw.hu": "...fejlesztői.kulcs...",
  "iwiw.hu": "...fejlesztői.kulcs..."
}
 
// az aktuális kulcs kiválasztása
var GMapKey = GMapKeys[opensocial.getEnvironment().getDomain()];
 
// egy új <script> elem létrehozása és felparaméterezése
document.write('<scri'+'pt type="text/javascript" src="http://maps.google.com/maps?file=api&v=2&key=' + GMapKey + '"></sc'+'ript>');
</script>
 
<script type="text/javascript">
 
function init() {
  if (typeof GBrowserIsCompatible == 'function' && GBrowserIsCompatible()) {
    var map = new GMap2(document.getElementById("map"));
    map.setCenter(new GLatLng(37.4419, -122.1419), 13);
  }
}
 
// beindítjuk az alkalmazást
gadgets.util.registerOnLoadHandler(init);
 
</script>
<div id="map" style="height: 400px;"></div>
]]></Content>
</Module>

Yahoo! Maps esetén szintén kell kulcsot kérnünk, ám ez nem domainhez, hanem alkalmazáshoz kötött, így nem kell két külön kulcs a Homokozóhoz és az éles rendszerbe. Fejlesztéshez, kipróbáláshoz használhatjuk a YD-eQRpTl0_JX2E95l_xAFs5UwZUlNQhhn7lj1H kulcsot, de élesbe ezzel nem mehet az alkalmazásunk (mert letiltja a Yahoo! a térképet). A kulcsot a SCRIPT elem végére kell beírnunk:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Yahoo! Maps" author="DevBlogger" author_email="dev@iwiw.hu" height="400">
  <Require feature="opensocial-0.8" />
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=...fejlesztői.kulcs..."></script>
<script type="text/javascript">
 
function init() {
  var map = new YMap(document.getElementById('map'));
  map.addTypeControl();
  map.setMapType(YAHOO_MAP_REG);
  map.drawZoomAndCenter("Budapest", 3);
}
 
// beindítjuk az alkalmazást
gadgets.util.registerOnLoadHandler(init);
 
</script>
<div id="map" style="height: 400px;"></div>
]]></Content>
</Module>

Végül nézzük a Microsoft Virtual Earth / Live Maps megoldást, aholis nincs szükségünk kulcsra:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Live Maps" author="DevBlogger" author_email="dev@iwiw.hu" height="400">
  <Require feature="opensocial-0.8" />
</ModulePrefs>
<Content type="html"><![CDATA[
<script charset="UTF-8" type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"></script>
<script type="text/javascript">
 
function init() {
  var map = new VEMap('map');
  map.LoadMap();
}
 
// beindítjuk az alkalmazást
gadgets.util.registerOnLoadHandler(init);
 
</script>
<div id="map" style="height: 400px;"></div>
]]></Content>
</Module>

Reklámok beszúrása

Egy reklám blokkot (bannert) nem nehéz beszúrni, egy SCRIPT/NOSCRIPT párost lehet kapni az Origotól, amit a megfelelő HTML pozícióba betehetünk. Problémát okozhat viszont, hogy ha olyan oldalrészbe szeretnénk a reklámot megjeleníteni, ami induláskor még nem létezik, mert az alkalmazás futása során generáljuk, hozzuk létre. Ekkor az egyik lehetséges trükk az, hogy a generált HTML részbe bemásoljuk egy olyan helyről, amit induláskor hoztunk létre. Az alábbi kód ezt csinálja (egy egyszerű SCRIPT elemmel, nem konkrét bannerkóddal):

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Hello iWiW" author="DevBlogger" author_email="dev@iwiw.hu">
  <Require feature="opensocial-0.8" />
  <Require feature="views" />
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
 
var App = {
 
  // ezt a függvényt hívjuk meg az alkalmazás betöltődésekor
  init: function() {
    var ad = document.getElementById("ad");
    var contentAd = document.getElementById("content-ad");
    contentAd.innerHTML = ad.innerHTML;
  }
 
};
 
// az alkalmazás betöltődésekor meghívandó függvényt adjuk át, hasonlít a
// weblapok onload függvényéhez
gadgets.util.registerOnLoadHandler(App.init);
 
</script>
<div id="ad-container" style="display: none;">
    <div id="ad">
	<!-- a banner kódja -->
	<script>document.write("ad");</script>
	<!-- a banner kódja -->
    </div>
</div>
 
<div id="content">
    <p>Ez lenne a generált tartalom.</p>
    <div id="content-ad">ide jön a reklám</div>
    <p>Itt a vége, fuss el véle.</p>
</div>
 
]]></Content>
</Module>

Canvas nézetre navigálás

Ha át szeretnénk navigálni a Canvas nézetre, akkor ehhez be kell töltenünk a views kiegészítést a fejlécben (<Require feature=”views” />), illetve a következő függvényt kell meghívni:

gadgets.views.requestNavigateTo(gadgets.views.getSupportedViews()["canvas"], {});

A kapcsos zárójelek között átadhatunk paramétereket is, melyeket a következő módon olvashatunk ki a Canvas nézetben:

var params = gadgets.views.getParams()

A profil oldali megjelenést célszerű úgy kialakítani, hogy a legfontosabb információkat gyűjtse össze, és kvázi a canvas nézet reklámjaként, funkcionális bannerként működjön - ehhez nyújthat segítséget az átnavigálás lehetősége.

Az összes ismerős lekérdezése

UPDATE: Fontos változás az ismerősök lekérdezésénél.

Az iWiW alkalmazások lekérdezhetik az alkalmazás tulajdonosának, illetve az alkalmazás nézőjének ismerőseit (erről már volt korábban szó: Mit tehet egy alkalmazás?), ám ezt illetően vannak kötöttségek, például egy lekérdezés után alapértelmezetten csak 20 ismerőst kapunk vissza, s bár ezt meg lehet növelni, de a limit 50 ismerős - vagyis lapozni kell. Az alábbiakban egy megoldást teszek közzé, mely felhasználóbarát módon teszi lehetővé az összes ismerős elérését.

A megoldás kulcsához nézzük át, hogy a newFetchPeopleRequest kérés milyen módon paraméterezhető:

  • FILTER: Szűrhetjük az ismerősök listáját, például szűkíthetjük az ismerősök listáját azokra, akiknek a jelen alkalmazás már fel van telepítve. Jelenleg csak ezt a szűrési módot támogatja az iWiW.
  • FILTER_OPTIONS: Egyes filterekhez lehet(ne) megadni további paramétereket segítségével.
  • FIRST: Ezzel határozhatjuk meg, hogy hányadik ismerőstől kérjük a listát.
  • MAX: Ezzel pedig azt, hogy maximum mennyi elemet kérünk (50-nél többet nem kérhetünk az iWiW-en).
  • PROFILE_DETAILS: Milyen profil tulajdonságokat szeretnénk lekérni - jelenleg felesleges használni, de a jövőben amikor további profil információkhoz is hozzá lehet majd férni, akkor igen hasznos lesz.
  • SORT_ORDER: Milyen sorrendben szeretnénk az ismerőseinket visszakapni. Jelenleg csak a névsort támogatja az iWiW, vagy ha nem adunk meg sorrendet, akkor valamilyen “véletlen” (belső azonosítóra épülő), de nem változó listát kapunk.

A trükkre az eddig írtakból rá lehet jönni: a FIRST és MAX paraméterek állításával fogjuk lekérdezni az összes ismerőst. Van még két trükk azonban: az egyik, hogy a kéréseket összecsomagolva csökkenthetjük a szerver felé indított kérések számát, illetve hogy először csak egy csomagot (50 ismerőst) kérünk le, s a válaszban benne levő teljes ismerősök száma tulajdonságot használjuk fel ahhoz hogy meghatározzuk, mennyi további csomagot fogunk lekérni (300 ismerősnél első kérésben 50-et, második kérésben 5 csomagban 5×50-et, avagy 250-et fogunk lekérni).

Ennek a felállásnak az is előnye, hogy az első válasz után már meg tudjuk jeleníteni a felhasználók felé az első adagot, s míg jön a többi, ő már elkezdhet tevékenykedni.

Ezekkel a funkciókkal, lehetőségekkel összeállítottam egy kész függvényt, mely ezeket a feladatokat megcsinálja mind helyettünk:

var IWIW = {};
IWIW.loadFriends = function(options) {
  // az objektumot később is fogjuk még használni, amikor a "this" más értékkel fog
  // bírni, ezért letároljuk az "obj" változóba
  var obj = this;
  // az ismerősök száma
  obj.totalSize = 0;
  // a params paraméterrel átadhatunk paramétereket a newFetchPeopleRequest hívásnak
  obj.params = options.params || {};
  // az ismerősök lekérdezését a legelején kezdjük
  obj.params[opensocial.DataRequest.PeopleRequestFields.FIRST] = 0;
  // és 50-et kérünk le (iWiW-en az egy csomagban lekérhető maximum)
  obj.params[opensocial.DataRequest.PeopleRequestFields.MAX] = 50;
  // a userId paraméter segítségével megmondhatjuk, hogy az OWNER vagy VIEWER
  // ismerőseire vagyunk-e kíváncsiak
  var userId = options.userId;
  // az onFirstFriends egy függvény, mely akkor hívódik meg, amikor az első ismerős
  // csomag megérkezik
  var onFirstFriends = options.onFirstFriends || function(){};
  // az onAllFriends egy függvény, mely akkor hívódik meg, amikor az összes ismerős
  // csomag megérkezett
  var onAllFriends = options.onAllFriends || function(){};
  // egy adatlekérés objektumot hozunk létre
  var request = opensocial.newDataRequest();
  // egy csoportot definiálunk: az alkalmazás nézőjének vagy tulajdonosának (userId) az ismerőseit
  obj.usergroup = opensocial.newIdSpec({"userId": userId, "groupId": "FRIENDS"});
  // a kéréshez hozzáadjuk az előbb definiált csoport lekérdezését, a választ
  // "friends0" néven fogjuk visszakapni
  request.add(request.newFetchPeopleRequest(obj.usergroup, obj.params), "friends0");
  // a függvény, mely az első adatlekérés után fut le
  var firstReady = function(response) {
    // itt a this értéke különbözik az eredeti objektumunktól,
    // ezért is használjuk az obj változót.
    // az obj.friends egy tömb lesz, melybe a válasz csomagokat pakoljuk
    obj.friends = [response.get("friends0").getData()];
    // a válaszban benne van az az információ, hogy összesen mennyi ismerős van, letároljuk
    obj.totalSize = obj.friends[0].getTotalSize();
    // a size értéke a jelen csomagban érkezett ismerősök száma (jellemzően 50, hacsak nincs
    // 50-nél kevesebb ismerőse a felhasználónak)
    var size = obj.friends[0].size();
    // a pozíció, ahol az ismerősök listájával járunk (0, 50, 100, stb. lesz)
    var pos = 0;
    // ha nem jött meg az összes ismerős, akkor...
    if (size < obj.totalSize) {
      // meghívjuk az első ismerősök megérkezésekor lefutó függvényt
      onFirstFriends(obj);
      // egy adatlekérés objektumot hozunk létre
      var request = opensocial.newDataRequest();
      // amíg nem érjük el az ismerősök számát...
      while (pos + size < obj.totalSize) {
        // következő csomag ott kezdődik, ahol az előző abbamaradt
        pos += size;
        // beállítjuk, hogy honnantól kezdje letölteni az ismerősöket, mi legyen az első elem
        obj.params[opensocial.DataRequest.PeopleRequestFields.FIRST] = pos;
        // a kéréshez hozzáadjuk a korábban már definiált csoport lekérdezését, a választ
        // "friendsXXX" néven fogjuk visszakapni, ahol az XXX a pozíció
        request.add(request.newFetchPeopleRequest(obj.usergroup, obj.params), "friends"+pos);
      }
      // elküldjük a több csomagot is tartalmazó kérést (második kérés)
      request.send(allReady);
    } else {
      // ha az első kérés során megjött az összes ismerős, akkor csak az onAllFriends kerül
      // meghívásra, mert már most tartalmazza az összes ismerőst.
      onAllFriends(obj);
    }
  }
  // a függvény, melyet a második lekérdezés válaszának megérkezésekor hívunk meg
  var allReady = function(response) {
    // csomag változó
    var package;
    // az első csomag végéről indulunk
    var pos = obj.friends[0].size();
    // ha nem értünk a végére, akkor...
    while (pos < obj.totalSize) {
      // a csomagot kivesszük a válaszból
      var package = response.get("friends"+pos).getData();
      // és betesszük az obj.friends tömbbe
      obj.friends.push(package);
      // növelkjük a pozíciót
      pos += package.size();
    }
    // meghívjuk az onAllFriends függvényt az összes ismerőssel
    onAllFriends(obj);
  }
  // elküldjük a lekérdezést, a függvény paramétere egy másik függvény,
  // ami akkor kerül meghívásra, amikor a szervertől megérkezik a válasz
  request.send(firstReady);
  // visszatérünk az IWIW.loadFriends objektumunkkal, ez egyelőre elég üres
  // de már beindítottuk az első lekérdezést, melyre hamarosan megjön a válasz
  return this;
};

A függvényt igyekeztem elég jól dokumentálni sok-sok megjegyzéssel, a kódban benne van tehát a magyarázat - emiatt nem írnám le még egyszer hogy pontosan hogyan működik. Összefoglalva: egy vagy két kérést indítunk a szerver felé, második kérést csak akkor, ha az első 50 elembe nem fért bele az összes ismerős. A második kérésben annyi csomagban kérjük le az ismerősöket, hogy immár a teljes ismerősi kör beleférjen. Paraméterként két függvényt adhatunk át, az első az első kérés után fut le (ha nem jött meg az összes ismerős), míg a második akkor, ha megjött az összes. A megkapott objektum friends tömbjében lesznek benne a szervertől visszakapott válaszok.

A függvény használatára egy példa, így valószínűleg még érthetőbb lesz:

// új kérés
new IWIW.loadFriends({
  // a tulajdonos ismerőseit fogjuk lekérdezni
  userId: "OWNER",
  // ha megjött az első adag ismerős
  onFirstFriends: function(response) {
    // az objektum friends tulajdonsága a fentebb emlegetett tömb
    var friends = response.friends;
    // a friends tömbnek még csak egy eleme van
    friends[0].each(function(person){
      // person.getDisplayName() használható, például
    })
  },
  // ha megjött az összes ismerős
  onAllFriends: function(response) {
    // az objektum friends tulajdonsága a fentebb emlegetett tömb
    var friends = response.friends;
    // végigmegyünk a tömb elemein, a csomagokon
    for(var i=0; i<friends.length; i++) {
      // minden csomagból kiolvassuk a benne levő személyeket
      friends[i].each(function(person){
        // person.getDisplayName() használható, például
      })
    }
  }
});