2011. augusztus havi bejegyzések

Twitter HTTPS-en

Egy ideje nagyon komolyan vesszük, hogy a weboldalaink ne csak a bejelentkezéshez, hanem a bejelentkezés után folyamatosan HTTPS-t használjanak. Nincs kifogás, authentication cookie-t nem küldünk át HTTP-n. Persze ez mindig okoz váratlan meglepetéseket, főleg külső könyvtárak használatakor. Az egyik készülő projektünkben például az Internet Explorer az alábbi üzenettel fogadott bejelentkezés után (én mondom, élmény ezzel a böngészővel tesztelni):

IE: Only secure content is displayed.

Nem kellett sokáig keresni (elég csak rányomni a Show all content gombra), hogy kiderüljön, az oldalra helyezett Twitter widget a bűnös. Derítsük ki miért!

Elsőre egyszerűnek tűnt a megoldás, hiszen a widget kódja a http://widgets.twimg.com oldalról töltődött le. Nosza írjunk elé HTTPS-t (mint a Facebook esetén) és kész is. Hát nem, akkor ugyanis egyáltalán nem töltődik be a script az oldalon, ez tisztán látszik az IE DevTools Network fülén és Firebugban is. Annak ellenére, hogy azon a szerveren van SSL. Hm, akkor mi lehet a gond? Nézzük meg a tanúsítványt:

cloudfront-cert

Bizony, itt van az eb elhantolva! A widgets.twimg.com szerveren lévő tanúsítvány valójában a *.cloudfront.net címre szól, azaz a fájlok az Amazon CDN-jéről töltődnének le, ha tudnának. Ha ráhibáznánk a * értékére, meg is lenne oldva a probléma. Tudja-e ezt valaki?

Szerencsére van egy másik domain, ahol rendben van a tanúsítvány:

https://twitter-widgets.s3.amazonaws.com/j/2/widget.js

Itt már nem panaszkodik a böngésző.

 

Technorati-címkék: ,
Reklámok

Image overlay készítése CSS-sel

Az egyik projektünkben egy weboldalon olyan képeket kell megjelenítenünk, amiket a felhasználók töltenek fel. Ez még önmagában nem is nagy durranás, csakhogy a dizájner ráálmodott egy-egy Metros nyíl ikont is ezekre a képekre, overlay formájában:

A végeredmény

A feladat nyilván sokféleképpen megoldható, mi a CSS-t választottuk, dolgozzon csak a böngésző. Ehhez kellett először is az eredeti kép:

Az eredeti kép

Továbbá az overlay, ami ugyanakkora, mint az eredeti kép, majdnem teljesen átlátszó és csak a nyíl van rajta:

Az overlay

A kód pedig nagyon egyszerű, csak fordítva kell gondolkodni: az overlayt jelenítjük meg és a kép lesz a háttér:

<img style="background:url(kep.jpg)" src="overlay.png" />

 

Technorati-címkék:

Globalizálás és lokalizálás JavaScriptben

Ahogy a webalkalmazásaink logikájának egyre jelentősebb része költözik a kliens oldalra, úgy egyre gyakrabban merül fel az igény, hogy lokalizáljunk és globalizáljunk JavaScriptben. Például egy Ajax hívás nyers JSON adatokat ad vissza, de persze az átküldött Date objektumot már a felhasználó nyelvi beállításainak megfelelően kellene sztringgé alakítanunk megjelenítés előtt. Vagy éppen egy alert ablakot kell feldobnunk, természetesen olyan nyelven, amelyen ért a felhasználó.

A problémára több megoldás létezik, nekem a Microsoft által tavaly bejelentett jQuery Globalization Plugin tűnik legszimpatikusabbnak, mégpedig azért, mert nagyon közel áll a szerver oldalon megszokott CultureInfo képességekhez. Sajnos a plugin elsőre elég barátságtalannak tűnik, több ok miatt:

1. A bejelentés óta nem sokat írt róla sem a Microsoft, sem pedig a jQuery csapat, de szerencsére ez nem azt jelenti, hogy egy újabb ígéretes fejlesztés került a kukába, ugyanis a jQuery csapatnak komoly tervei vannak ezzel a komponenssel.

2. Nehéz megtalálni az aktuális verziót, mert időközben átnevezték a projektet. Már nem jQuery Globalization Pluginnek hívják, hanem egyszerűen csak jQuery Globalize és itt található: https://github.com/jquery/globalize. “Globalize certianly needs some polishing and bug fixing, but the API is now pretty stable, so you should give it a try.”

3. A nevében a “jQuery” félrevezető. Szerencsére már nem hívják “plugin”-nak, ugyanis nem plugin. Ez egy önálló JavaScript osztálykönyvtár hasznos függvényekkel, nem kell hozzá se $, se selector.

Mit tud?

  • Ismeri 350 kultúra paramétereit, méghozzá a .NET Framework CultureInfo adatai alapján, de persze a lista bővíthető. Számformátumok, dátum formátumok, naptár információk stb.
  • Számok és dátumok formázása a megadott kultúra szerint. A sok formázási lehetőséget legegyszerűbben a példák között található examples/browser/index.html fájl futtatásával lehet áttekinteni.
  • Lokalizált sztringek definiálása és felolvasása.
  • Egész számok, törtszámok és dátumok parszolása sztringből.

A rövid, de használható dokumentáció megtalálható itt: https://github.com/jquery/globalize/blob/master/README.md

Bár a jelenlegi verziószáma 0.1.0a1 (ez vajon mennyivel több, mint a 0.0?) és van néhány nyitott issue, a tapasztalataink alapján már jól működik, merjük is élesben használni.

Ti mit használtok kliens oldali globalizálásra és lokalizálásra?

 

ASP.NET-es képfeltöltő CLEditorhoz

Nagyon sok JavaScriptes WYSIWYG editor létezik, nekem az egyik kedvencem a CLEditor. Nem tud sokat, nem is tökéletes, de kicsi, egyszerű, pluginekkel bővíthető és jQuery alapú. Az egész editor 4 fájlból áll és mindössze 9kb, amiért ezt kapjuk:

cleditor-demo

Nem is beszélve arról, hogy gyakorlatilag ingyenesen használható a MIT és a GPLv2 licencek értelmében. Egy próbát mindenképp megér, ami a fájlok bemásolása után mindössze ennyi:

<head runat="server">
  <link href="Scripts/CLEditor/jquery.cleditor.css" rel="stylesheet" type="text/css" />
  <script src="Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
  <script src="Scripts/CLEditor/jquery.cleditor.js" type="text/javascript"></script>

  <script type="text/javascript">
    $(function () {
      $('#txtContent').cleditor();
    });
  </script>
</head>

<body>
  <form id="form1" runat="server">
    <div>
      <asp:TextBox ID="txtContent" runat="server" 
                   ClientIDMode="Static" TextMode="MultiLine" />
    </div>
  </form>
</body>

Mint sok más editor, sajnos alapból ez sem tud képfeltöltést, csak képbeszúrást, ami különösen nem is meglepő, hiszen a fájlfeltöltéshez szerver oldali komponens is kell. PHP-s megoldást találtam, de nekem természetesen ASP.NET-es kellett, hát csináltam egyet.

A pluginezés szerencsére nagyon egyszerű, gyakorlatilag egy új gombot kell regisztrálni:

$.cleditor.buttons.imageUpload = {
    name: "imageUpload",
    image: "imageUpload.png",
    title: "Upload and insert image",
    command: "inserthtml",
    buttonClick: onImageUploadButtonClick
};

Majd ezt a gombot beszúrni az eszköztárra, például a beépített képbeszúró gomb (“image”) elé:

$.cleditor.defaultOptions.controls = 
  $.cleditor.defaultOptions.controls.replace("image", "imageUpload image");

Máris van egy gombunk, és ha a felhasználó rákattint, meghívódik az onImageUploadButtonClick függvényünk. Itt egy jQueryUI-os dialog ablakot szeretnénk feldobni, amiben egy iframe jeleníti meg az ASP.NET-es feltöltő oldalt. Ezt így alapozhatjuk meg a markupban:

<div id="dialog" style="display: none;">
    <iframe src="ImageUploadPopup.aspx" frameborder="0"></iframe>
</div>

Ha ez megvan, akkor máris írhatjuk a JavaScript kódot a popup megjelenítésére:

  function onImageUploadButtonClick(e, data) {
    // Open a new popup dialog.
    $("#dialog").dialog({
        autoOpen: true,
        modal: true,
        width: '500',
        position: 'auto',
        title: 'Insert image',
        buttons:
        [
            {
                text: "Insert",
                click: function () {
                    $(this).dialog('close');
                    onImageUploadPopupClose(data);
                }
            },
            {
                text: "Cancel",
                click: function () {
                    $(this).dialog('close');
                }
            }
        ]
    });

    // Ez kell, hogy az IE az editorba szúrja be a képet,
    // ne kedve szerint valami meglepő helyre az oldalon.
    data.editor.focus();

    // A false azt jelzi, hogy a gomb funkcióját teljes egészében mi
    // valósítjuk meg, ne a gomb deklarációnál megadott command hajtódjon végre.
    return false;
  }

A végén lévő két sortól eltekintve ebben semmi extra nincs, klasszikus jQueryUI dialog. A felugró ablakba az ImageUploadPopup.aspx fog betöltődni, ami a példa kedvéért igen egyszerű:

<asp:FileUpload runat="server" ID="fupImage" />
<asp:Button ID="btnUpload" runat="server" 
            onclick="btnUpload_Click" Text="Upload" />
<asp:Label ID="lblResult" runat="server" />
<asp:HiddenField ID="hfSelectedImageUrl" runat="server" ClientIDMode="Static" />

A fájlt az Upload gomb megnyomására töltjük fel, majd a Labelben tájékoztatjuk a felhasználót az eredményről. A rejtett mezőt arra használjuk, hogy beleírjuk azt az URL-t, amit majd az editorba be kell szúrni. A gomb eseménykezelője:

protected void btnUpload_Click( object sender, EventArgs e )
{
  // Fájl mentése a diszkre.
  // VIGYÁZAT: demó kód, input validálás hiányzik!
  string folder = this.Server.MapPath( "~/Upload" );
  string target = Path.Combine( folder, this.fupImage.FileName );
  this.fupImage.SaveAs( target );

  // Felhasználó tájékoztatása.
  this.lblResult.Text = String.Format( CultureInfo.InvarianCulture, 
                                     "{0} feltöltve!", this.fupImage.FileName );

  // Beszúrandó URL mentése a rejtett mezőbe.
  this.hfSelectedImageUrl.Value = "Upload/" + this.fupImage.FileName;
}

Amikor a felhasználó az Insert gombra kattintva bezárja a dialógusablakot, akkor meg fog hívódni az onImageUploadPopupClose függvényünk. Itt kiolvassuk a rejtett mező tartalmát, gyártunk belőle egy img elemet és megkérjük az editort, hogy szúrja be a szövegbe:

  function onImageUploadPopupClose(data) 
  {
    var strSelectedImageUrl = 
      $("#dialog").find("iframe").contents().find("#hfSelectedImageUrl").val();

    var editor = data.editor;

    var html = "<img src='" + strSelectedImageUrl + "' />";
    editor.execCommand(data.command, html, null, data.button);

    editor.hidePopups();
    editor.focus();
  }

 

Leírni bonyolultabb, mint megcsinálni, de még egyszerűbb a teljes forráskódot letölteni innen.

 

Technorati-címkék: ,,,,

HTML 5 custom data attributes

A HTML 5 szabványba foglalt egyik legkedvesebb részem a custom data attribute lehetősége. Egyrészt azért tetszik, mert nagyon régóta fájó problémát old meg, másrészt mert nem kell megvárni hozzá a HTML 5 szabvány elkészültét, már ma is használható, a korábbi böngészők is elviselik.

Röviden a custom data attributes arra jó, hogy tetszőleges, nem látható információt ágyazzunk be kulturált módon a HTML markupba. Ehhez nem kell más tennünk, mint egy data- kezdetű attribútumot biggyesztenünk a kiszemelt HTML elemhez. Például így:

  <span data-rendezo="Michael Bay">Transformers</span>

Ha erre az adatra később szükségünk van JavaScriptben, akkor akár az element.dataset tulajdonságon keresztül, akár jQuery-vel a data() metóduson keresztül elérhetjük:

  alert( $('span').data('rendezo') );    // --> Michael Bay

Persze a jQuery támogatja az értékek írását, törlését és hozzáadását is. Sőt, akár összetett objektumokat is tehetünk ide, természetesen JSON formában (a tulajdonságok neveit idézőjelbe kell tenni):

  <span id="tr"
    data-film='{ "rendezo": "Michael Bay", "ev": 2007, "moziban": true }'>
    Transformers
  </span>

Kiolvasni nagyon egyszerű:

  var f = $("#tr").data('film');

És ahogy Firebugban is látszik, egy összetett objektumot kapunk vissza, méghozzá nem csak stringekkel, hanem ha lehet, típusokkal (Boolean, Number):

dataAttribute-Firebug

Sokkal jobb, mint JavaScriptbe írni a szerver oldalon előálló adatokat vagy hidden fieldeket generálni, nem?

Ez az a pont, ahol az ember úgy érzi, hogy ennél egyszerűbb és jobb dolog nincs a világon. Csakhogy a specifikáció nagyon pontosan definiálja, hogy hogyan kell kezelni a nagybetűs és a kötőjeles attribútumokat, ami nagyon érdekes hibákat tud eredményezni. Vegyük például ezt:

  <p data-productId="22">...</p>

Talán meglepő, de ez bizony undefined a javából:

  alert( $("p").data("productId") );

Helyesen:

  alert( $("p").data("productid") );

Ez nem bug, főként nem a szerver oldali keretrendszer hibája, hanem feature: úgy működik, ahogy a specifikáció előírja.

A jQuery próbál segíteni a programozói bénaságokon és gyakran többféleképpen is elérhetővé teszi ugyanazt az adatot. Például íme a markup:

  <p data-Id="22">...</p>

Ebből az Id két módon is elérhető:

  $("p").data("id")
  $("p").data("Id")

A Studio is tudja, mi a helyes, mert a Format Document vagy Format Selection parancs kiadásakor kisbetűsre alakítja ezeket az attribútumokat.

Mindenképp érdemes elolvasni azt a pár mondatot a specifikációban, ami erről szól (3.2.3.8 fejezet) és csak akkor használni ezt a lehetőséget, ha értjük is.

Keresztkérdés! Íme a markup:

  <p data-egy="1" 
     data-Ketto="2" 
     data-haromHarom="3" 
     data-Negy-negy="4" 
     data-ot-ot="5" 
     data-hat-Hat="6">...</p>

Milyen tulajdonságai lesznek az alábbi sor után az adat objektumnak?

  var adat = $("p").data();

Íme a megoldás (a szürke kosz egy mini kép, kattints rá a teljes mérethez): Kattints ide a megoldás megtekintéséhez!

 

Technorati-címkék: ,,

OData sorozat 4: JSONP támogatás

A sorozat előző epizódjában láttuk, hogyan érhetjük el az OData szolgáltatásunkat JQuery-ből. Sajnos ez a módszer nem működik, ha a szolgáltatás és a kliens más tartományban van, mert a böngésző Same Origin Policy-je nem fogja engedni, hogy a böngésző a háttérben másik tartományban lévő kiszolgálóval kommunikáljon.

A mai epizódban elmondom röviden, hogy a JSONP hogyan segít megoldani ezt a problémát és hogy hogyan bővíthetjük ki a szolgáltatásunkat JSONP támogatással:

720p, teljes képernyő ajánlott

Nem is olyan vészes, igaz?

 

Technorati-címkék: ,,,,,