V tomto článku vytvoříme serverový ovládací prvek, který použijeme pro pohodlné vytváření odkazu na obrázek. Takový odkaz potom přístupnou formou zobrazí obrázek v novém přizpůsobeném okně, aniž bychom museli do aplikace zvlášť dopisovat speciální klientský skript.

V řadě aplikací (fotogalerie, katalogy zboží) nabízíme uživatelům prohlédnutí velkého obrázku kliknutím na odkaz. Náš ovládací prvek vybaví běžný odkaz klientským skriptem, který se pokusí ohleduplným způsobem otevřít nové okno a do tohoto okna dynamicky vygenerovat kód dokumentu pro zobrazení obrázku. Po načtení obrázku bude velikost okna přizpůsobena velikosti obrázku. V libovolné aplikaci pak pro odkazy na velký obrázek jednoduše místo odkazu (realizovaného prvkem) použijeme náš nový prvek ImageViewLink. Pokud klient nebude podporovat otvírání nových oken nebo klientské skriptování, prvek se zachová jako vestavěný prvek HyperLink, ze kterého bude ImageViewLink dědit. Prohlédněte si ukázku (zdrojový kód), která využívá obrázky ze seriálu Reklama, webdesign a inspirace.

V tuto chvíli chci poukázat na fakt, že uvedený ovládací prvek má být pouze doplňkem, který usnadní tvorbu aplikací a současně nám stránka zůstane přístupná, nebude narušena validita ani sémantika dokumentu – obrázek bude možné prohlédnout i bez podpory klientského skriptu. Klientským skriptem budeme generovat vlastní dokument s obrázkem v novém okně – tento dokument je však pouze doplňkový, není určen pro vyhledávače ani pro různá alternativní zařízení. Proto jsem v jeho kódu upřednostnil správnou funkci v nejpoužívanějších prohlížečích před sémantikou a dalšími dobrými zásadami.

Základem prvku je klientský skript, který se pokusí otevřít nové okno a vypsat do něj kód dokumentu zobrazujícího obrázek. Kód skriptu, který tvoří jediná funkce, vypadá takto:

function __imageViewLink(imgUrl,title,backColor,cssFile,reuseWindow)
{
  var sTarget = ‚_viewLink‘;
  if (reuseWindow !=null && !reuseWindow)
    sTarget = ‚_blank‘;
  var pWin = window.open(“, sTarget, ‚width=400, height=460, top=40, left=60, channelmode=0, directories=0, fullscreen=0, location=0, menubar=0, resizable=1, scrollbars=1, status=0, titlebar=0, toolbar=0‘);
  if (pWin)
  {
    pWin.focus();
    pWin.document.open();
    pWin.document.writeln(‚<html>‘);
    pWin.document.writeln(‚ <head>‘);
    pWin.document.writeln(‚ <meta http-equiv=“Page-Enter“ content=“RevealTrans(Duration=2,Transition=23)“ />‘);
    pWin.document.writeln(‚ <meta http-equiv=“Page-Exit“ content=“RevealTrans(Duration=1,Transition=12)“ />‘);
    pWin.document.writeln(‚ <meta http-equiv=“Imagetoolbar“ content=“no“ />‘);
    pWin.document.writeln(‚ <meta http-equiv=“MSThemeCompatible“ content=“no“ />‘);
    pWin.document.writeln(‚ <meta name=“MSSmartTagsPreventParsing“ content=“true“ />‘);
    pWin.document.writeln(‚ <meta name=“AutoSize“ content=“Off“ />‘);
    var sTitle = ‚Image View‘;
    if (title != null && title.length > 0)
      sTitle = title;
    pWin.document.writeln(‚ <title>’+sTitle+'<\/title>‘);
    var bodyStyle = “;
    var divStyle = “;
    var imgStyle = “;
    var sBackColor = ‚#333333‘;
    if (backColor != null && backColor.length > 2)
      sBackColor = backColor;
    if (cssFile != null && cssFile.length > 5)
    {
      pWin.document.writeln(‚ <link href=“‚ + cssFile + ‚“ rel=“StyleSheet“ type=“text/css“ media=“Screen“><\/link>‘);
      if (backColor != null && backColor.length > 2)
        bodyStyle = ‚ style=“background: ‚ + sBackColor + ‚;“‚;
    }
    else
    {
      bodyStyle = ‚ style=“background: ‚ + sBackColor + ‚; scrollbar-base-color:‘ + sBackColor + ‚;padding:4px; margin:0px;  overflow:auto; cursor:pointer;“‚;
      if (navigator.appName==’Microsoft Internet Explorer‘)
        bodyStyle += ‚ height:100%;‘;
      bodyStyle +='“‚;
      divStyle = ‚ style=“width:100%;text-align:center;“‚;
      imgStyle = ‚ style=“border:2px outset;“‚;
    }
    pWin.document.writeln(‚ <\/head>‘);
    pWin.document.writeln(‚ <body‘ + bodyStyle + ‚ onclick=“window.blur();“  onload=“window.resizeTo(document.getElementById(\’Image\‘).width+56,document.getElementById(\’Image\‘).height+78);“>‘);
pWin.document.writeln(‚ <div‘ +divStyle + ‚><img id=“Image“ src=“‚ + imgUrl + ‚“ alt=““ title=“&times;“‚ + imgStyle + ‚ /><\/div>‘);
    pWin.document.writeln(‚ <\/body>‘);
    pWin.document.write(‚<\/html>‘);
    pWin.document.close();
  }
  return pWin;
}

Smyslem článku není detailně zde probírat tento klientský skript, proto jen stručně. Skript se pokusí otevřít nové okno, pokud se mu to podaří, preventivně přenese okno do popředí a otevře dokument v okně pro zápis. Následně je zapisován kód dokumentu včetně různých vlastností, jak jsou předány při voláni funkce kliknutím na odkaz – například titulek okna, barva pozadí obrázku či odkaz na externí stylopis, rozměry obrázku a jiné. Tělo dokumentu je doplněno obsluhou události onclick – pokud uživatel na zobrazený obrázek klikne, okno s obrázkem se přesune do pozadí, uživatel se tak vrátí na stránku s odkazem na obrázek. Obsluha události onload zase zajistí přizpůsobení velikosti okna podle rozměrů obrázku, vidíme, že k rozměrům obrázku jsou připočteny konstanty, které byly stanoveny empiricky. Ošetřeno je také odlišné chování prohlížeče Internet Explorer, kdy je potřeba právě jen pro tento nastavit výšku elementu BODY na 100 %, aby ani tento prohlížeč nezobrazil v okně obrázku scrollbar.

Další části rozebereme dále v popisu implementace skriptu do serverového ovládacího prvku. V dokumentu jsou využity také takzvané přechody stránek, které fungují sice pouze v Internet Exploreru, ovšem pro jednoduchost použití snadno ozvláštníme okamžik, kdy se obrázek právě načítá. Vzhledem k tomu, že celý dokument je generován dynamicky skriptem u klienta, není potřeba se tu zvlášť starat o sémantiku či validitu – jde čistě o vylepšení, funkcionalita je zde na prvním místě, a proto, jak vidíte, je výsledný kód kombinací validního základu a částí funkčně ověřených v nejpoužívanějších prohlížečích.

Pro úplnost si ještě ukážeme kód ohleduplného odkazu, kterým se bude obrázek otvírat do nového okna – tento kód bude také zajišťovat náš prvek ImageViewLink:

<a onclick=“return !__imageViewLink(this.href,’Image View‘,’#3165CE‘,null,true);“ href=“cliobanner.gif“>Obrázek</a>

Pro pochopení, jaké schopnosti jsme dali do vínku našemu ovládacímu prvku, si probereme jeho veřejné vlastnosti. Nejprve pro ně deklarujeme privátní proměnné, kterým rovnou určíme výchozí hodnoty:

private Color _imageViewBackColor = Color.Empty;
private String _imageViewTitle = „Image View“;
private String _imageViewCssFile = null;
private Boolean _imageViewReuseWindow = true;

Dále si ukážeme zveřejnění vlastností, kde si pozornosti zaslouží práce s ViewState, takže náš prvek bude schopen dobře podržet svůj stav i mezi jednotlivými PostBacky stránky.

/// <summary>
/// Background color of the view image window
/// </summary>
public Color ImageViewBackColor
{
  get
  {
    object o = this.ViewState[„ImageViewBackColor“];
    if (o != null)
      return (Color) o;
    else
      return _imageViewBackColor;
  }
  set
  {
    this.ViewState[„ImageViewBackColor“] = value;
    _imageViewBackColor = value;
  }
}

Vlastnost ImageViewBackColor slouží pro rychlé nastavení barvy pozadí okna s obrázkem. Rychlé proto, že tato barva bude ve výsledném kódu okna použita ve formě inline stylu elementu body, hodí se ji proto využít v případě, že nemáme v úmyslu pro okno obrázku připravit zvláštní soubor stylopisu.

/// <summary>
/// Title text of the view image window, default is „Image View“
/// </summary>
public String ImageViewTitle
{
  get
  {
    object o = this.ViewState[„ImageViewTitle“];
    if (o != null)
      return (String) o;
    else
      return _imageViewTitle;
  }
  set
  {
    this.ViewState[„ImageViewTitle“] = value;
    _imageViewTitle = value;
  }
}

Vlastnost ImageViewTitle umožňuje nastavit titulek okna obrázku, pokud ji nenastavíme, má výchozí hodnotu Image View.

/// <summary>
/// Path (Url) to the view image window CSS file
/// </summary>
public String ImageViewCssFile
{
  get
  {
    object o = this.ViewState[„ImageViewCssFile“];
    if (o != null)
      return (String) o;
    else
      return _imageViewCssFile;
  }
  set
  {
    this.ViewState[„ImageViewCssFile“] = value;
    _imageViewCssFile = value;
  }
}

Pomocí ImageViewCssFile můžeme přiřadit oknu obrázku soubor vlastního stylopisu a ovlivnit jím tak vzhled okna s obrázkem. Ve většině případů si však vystačíme s nastavením barvy pozadí již dříve popsanou vlastností, prvek sám pro snadnost použití obsahuje kód inline stylu, a tak externí soubor zřejmě využijeme málokdy.

/// <summary>
/// How window will be handle – using the same window or open new window, default is true
/// </summary>
public Boolean ImageViewReuseWindow
{
  get
  {
    object o = this.ViewState[„ImageViewReuseWindow“];
    if (o != null)
      return (Boolean) o;
    else
      return _imageViewReuseWindow;
  }
  set
  {
    this.ViewState[„ImageViewReuseWindow“] = value;
    _imageViewReuseWindow = value;
  }
}

Velmi důležitá je vlastnost ImageViewReuseWindow, kterou říkáme, zda se má každým kliknutím na odkaz otvírající obrázek otevřít nové okno nebo se má stále používat jedno již dříve otevřené okno – v tom případě se okno pouze přenese do popředí provedením metody focus() a nahraje se do něj nový obsah. Výchozí hodnota je true.

Nyní již potřebujeme jen zajistit vypsání výše uvedené klientského skriptu a přidání potřebných atributů k elementu odkazu – toto pro nás provede přepsaná metoda Render().

protected override void Render (HtmlTextWriter writer)
{
  String ScriptKey = this.GetType().FullName;
  if (Page != null && Page.Request != null && !Page.IsClientScriptBlockRegistered(ScriptKey))
  {
    Page.RegisterClientScriptBlock(ScriptKey,String.Empty);
    writer.WriteBeginTag(„script“);
    writer.WriteAttribute(„type“,“text/javascript“);
    writer.WriteLine(HtmlTextWriter.TagRightChar);
    writer.WriteLine(„<!– <![CDATA[„);
    writer.WriteLine(„function __imageViewLink(imgUrl,title,backColor,cssFile,reuseWindow)“);
    writer.WriteLine(„{„);
    writer.WriteLine(“ var sTarget = ‚_viewLink‘;“);
    writer.WriteLine(“ if (reuseWindow !=null && !reuseWindow)“);
    writer.WriteLine(“ sTarget = ‚_blank‘;“);
    writer.WriteLine(“ var pWin =  window.open(“, sTarget, ‚width=400, height=460, top=40, left=60, channelmode=0, directories=0, fullscreen=0, location=0, menubar=0, resizable=1, scrollbars=1, status=0, titlebar=0, toolbar=0‘);“);
    writer.WriteLine(“ if (pWin)“);
    writer.WriteLine(“ {„);
    writer.WriteLine(“ pWin.focus();“);
    writer.WriteLine(“ pWin.document.open();“);
    writer.WriteLine(“ pWin.document.writeln(‚<html>‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <head>‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta http-equiv=\“Page-Enter\“ content=\“RevealTrans(Duration=2,Transition=23)\“ />‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta http-equiv=\“Page-Exit\“ content=\“RevealTrans(Duration=1,Transition=12)\“ />‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta http-equiv=\“Imagetoolbar\“ content=\“no\“ />‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta http-equiv=\“MSThemeCompatible\“ content=\“no\“ />‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta name=\“MSSmartTagsPreventParsing\“ content=\“true\“ />‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <meta name=\“AutoSize\“ content=\“Off\“ />‘);“);
    writer.WriteLine(“ var sTitle = ‚Image View‘;“);
    writer.WriteLine(“ if (title != null && title.length > 0)“);
    writer.WriteLine(“ sTitle = title;“);
    writer.WriteLine(“ pWin.document.writeln(‚ <title>’+sTitle+'<\\/title>‘);“);
    writer.WriteLine(“ var bodyStyle = “;“);
    writer.WriteLine(“ var divStyle = “;“);
    writer.WriteLine(“ var imgStyle = “;“);
    writer.WriteLine(“ var sBackColor = ‚#333333‘;“);
    writer.WriteLine(“ if (backColor != null && backColor.length > 2)“);
    writer.WriteLine(“ sBackColor = backColor;“);
    writer.WriteLine(“ if (cssFile != null && cssFile.length > 5)“);
    writer.WriteLine(“ {„);
    writer.WriteLine(“ pWin.document.writeln(‚ <link href=\“‚ + cssFile + ‚\“ rel=\“StyleSheet\“ type=\“text/css\“ media=\“Screen\“><\\/link>‘);“);
    writer.WriteLine(“ if (backColor != null && backColor.length > 2)“);
    writer.WriteLine(“ bodyStyle = ‚ style=\“background: ‚ + sBackColor + ‚;\“‚;“);
    writer.WriteLine(“ }“);
    writer.WriteLine(“ else“);
    writer.WriteLine(“ {„);
    writer.WriteLine(“ bodyStyle = ‚ style=\“background: ‚ + sBackColor + ‚; scrollbar-base-color:‘ + sBackColor + ‚;padding:4px; margin:0px; overflow:auto; cursor:pointer;\“‚;“);
    writer.WriteLine(“ if (navigator.appName==’Microsoft Internet Explorer‘)“);
    writer.WriteLine(“ bodyStyle += ‚ height:100%;‘;“);
    writer.WriteLine(“ bodyStyle +=’\“‚;“);
    writer.WriteLine(“ divStyle = ‚ style=\“width:100%;text-align:center;\“‚;“);
    writer.WriteLine(“ imgStyle = ‚ style=\“border:2px outset;\“‚;“);
    writer.WriteLine(“ }“);
    writer.WriteLine(“ pWin.document.writeln(‚ <\\/head>‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <body‘ + bodyStyle + ‚ onclick=\“window.blur();\“  onload=\“window.resizeTo(document.getElementById(\\’Image\\‘).width+56,document.getElementById(\\’Image\\‘).height+78);\“>‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <div‘ +divStyle + ‚><img id=\“Image\“ src=\“‚ + imgUrl + ‚\“ alt=\“\“ title=\“&times;\“‚ + imgStyle + ‚ /><\\/div>‘);“);
    writer.WriteLine(“ pWin.document.writeln(‚ <\\/body>‘);“);
    writer.WriteLine(“ pWin.document.write(‚<\\/html>‘);“);
    writer.WriteLine(“ pWin.document.close();“);
    writer.WriteLine(“ }“);
    writer.WriteLine(“ return pWin;“);
    writer.WriteLine(„}“);
    writer.WriteLine(„//]]> –>“);
    writer.WriteEndTag(„script“);
    writer.WriteLine();
  }
  System.Text.StringBuilder fncParameters = new System.Text.StringBuilder(„return !__imageViewLink(this.href,“);
  if (_imageViewTitle != null)
    fncParameters.Append(„‚“ + _imageViewTitle.Replace(„‚“,“\\'“) + „‚,“);
  else
    fncParameters.Append(„null,“);
  if (_imageViewBackColor != Color.Empty)
    fncParameters.Append(„‚“ + ColorTranslator.ToHtml(_imageViewBackColor) + „‚,“);
  else
    fncParameters.Append(„null,“);
  if (_imageViewCssFile != null)
    fncParameters.Append(„‚“ + _imageViewCssFile + „‚,“);
  else
    fncParameters.Append(„null,“);
  if (_imageViewReuseWindow)
    fncParameters.Append(„true“);
  else
    fncParameters.Append(„false“);
  fncParameters.Append(„);“);
    base.Attributes.Add(„onclick“,fncParameters.ToString());
  base.Render(writer);
}

Hned na začátku kódu metody provádíme malou fintu s renderováním klientského skriptu. Ten se samozřejmě může ve stránce objevit pouze jednou, i když náš ovládací prvek bude ve stránce vícekrát. Toto jediné vypsání by měla zajistit metoda Page.RegisterClientScriptBlock(), její použití má ovšem háček – klientský skript je vypsán jako součást formuláře. Náš prvek zděděný z běžného HyperLinku však budeme chtít použít nejen ve formuláři, proto je v kódu zaregistrován skript v podobě String.Empty a do stránky se tedy touto metodu nic nevypíše. Vypsání si zajistíme sami klasickým přidáním částí skriptu do výstupního writeru a to, že bude klientský skript vypsán pouze jednou, zajistíme otestováním vlastnosti IsClientScriptBlockRegistered(). Povšimněte si, jak je vytvářen klíč pro registraci skriptu – jednoduše převezmeme název typu (třídy) ovládacího prvku pomocí this.GetType().FullName. Celou tuto nestandardní šarádu tedy provádíme proto, aby náš prvek nebyl závislý na umístění uvnitř formuláře.

Po vyřešení výpisu obslužného skriptu si už připravíme jen StringBuilder, do kterého postupně naskládáme potřebné části funkce volané obsluhou události onclick. Připravený řetězec volání funkce pak pomocí Attributes.Add() přidáme do kolekce atributů prvku. Nakonec zavoláme původní (bázovou) metodu Render(), která zajistí kompletní vykreslení námi rozšířeného HyperLinku.

Prohlédněte si také možnosti použití:

<Ic:ImageViewLink NavigateUrl=“fwa.gif“ Text=“FWA – Favourite WebSite Awards“ RunAt=“Server“ />
<Ic:ImageViewLink ImageViewTitle=“Titulek 2. obrázku“ ImageViewBackColor=“#3165CE“ ImageViewReuseWindow=“False“ NavigateUrl=“goguard.jpg“ Text=“Druhý obrázek“ RunAt=“Server“ />
<Ic:ImageViewLink NavigateUrl=“cliobanner.gif“ RunAt=“Server“ />
<Ic:ImageViewLink ImageViewReuseWindow=“True“ NavigateUrl=“nissan.jpg“ ImageUrl=“nissan_small.gif“  RunAt=“Server“ />

Prvek můžeme samozřejmě ovládat i programově a také jej použít vnořeně v prvcích pro vykazování dat jako je Repeater či DataList. Připomínám, že odkaz nemusí být tvořen pouze textově, pomocí vlastnosti ImageUrl můžeme odkazu nastavit obrázek náhledu.

Závěrem chci dodat, že prvek jsem vytvořil již dříve pro ASP.NET 1.1, je tedy možné a vhodné vylepšit ho v souladu s novinkami v ASP.NET 2.0 – základní doporučení poskytne sám kompilátor při kompilaci do knihovny DLL.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět