<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Dobrý kód</title>
	
	<link>http://www.dobrykod.com</link>
	<description>Pretože ostatné weby pre vývojárov sajú</description>
	<lastBuildDate>Thu, 07 May 2009 07:54:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/DobryKod" /><feedburner:info uri="dobrykod" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Asociativní hledání</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/odid8-LTAus/</link>
		<comments>http://www.dobrykod.com/archiv/asociativni-hledani/#comments</comments>
		<pubDate>Wed, 06 May 2009 08:00:41 +0000</pubDate>
		<dc:creator>Honza Štěrba</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[find]]></category>
		<category><![CDATA[has_many]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=260</guid>
		<description><![CDATA[Statické metody has_one, has_many, belongs_to, habtm a has_many :through z ActiveRecord::Associations jsou kromě validací základními stavebními kameny ActiveRecordu. Metody které tito pomocníci generují umí mnohem víc než najít všechny objekty platné pro danou asociaci. Toto se týká se především násobných asociací jako je například has_many. Dejme tomu, že mám modely firma a zaměstnananec ve vztahu [...]]]></description>
			<content:encoded><![CDATA[<p>Statické metody has_one, has_many, belongs_to, <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001792">habtm</a> a <em>has_many :through</em> z <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html ">ActiveRecord::Associations</a> jsou kromě validací základními stavebními kameny ActiveRecordu. Metody které tito pomocníci generují umí mnohem víc než najít všechny objekty platné pro danou asociaci.</p>
<p><span id="more-260"></span></p>
<p>Toto se týká se především násobných asociací jako je například <em>has_many</em>. Dejme tomu, že mám modely firma a zaměstnananec ve vztahu (1:N).</p>
<pre name="code" class="ruby">
class Employee < ActiveRecord::Base
   belongs_to :company
end
class Company < ActiveRecord::Base
   has_many :employees
end
</pre>
<p>Když potřebuji najít všechny zaměstnance s platem vyšším než 10 korun stačí napsat jednoduchý dotaz pomocí metody find:</p>
</pre>
<pre name="code" class="ruby">
Employee.find(:all, :conditions => ["salary > ?", 10])
</pre>
<p>Nicméně tento příklad moc realitu příliš nepostihuje. Většinou mě zajímají jenom zaměstnanci určité firmy:</p>
<pre name="code" class="ruby">
Employee.find(
   :all,
   :conditions => [ "company_id = ? AND salary > ?",
         my_company.id, 10]
   )
</pre>
<p>Tady je taky vše v pořádku. Kód funguje a dělá přesně to, co po něm chci. Problém je v tom, že princip <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY</a> (neopakujmež se!) dostává ránu pálkou do rozkroku. Na filtrování zaměstnanců naší firmy přece máme metodu _employees_ ve třídě Company:</p>
<pre name="code" class="ruby">
my_company.employees.each do |employee|
  # something clever
end
</pre>
<p>Na první pohled se zdá, že <em>company.employees</em> nevrací nic jiného než pole. <em>Company#employees</em> přitom vrací cosi, co se chová jako pole (nebo taky seznam, prostě <a href="http://www.ruby-doc.org/core/classes/Enumerable.html">Enumerable</a>), ale je to objekt mnohem chytřejší (je to Asociace). Dobře placené zaměstnance naší firmy najdu zkráceně takto:</p>
<pre name="code" class="ruby">
my_company.employees.find(:all,
   :conditions => ["salary > ?", 10])
</pre>
<p>Asi stojí za vysvětlení, že prosté volání <em>my_company.employees</em> nikdy nezpůsobí vykonání SQL dotazu. Dotaz do databáze se provede až ve chvíli kdy je jisté, co skutečně potřebuji (např. při zavolání each nebo find).</p>

<p><a href="http://feedads.g.doubleclick.net/~a/bYACpbNGRiM4G8FxMWVKMxYyRkg/0/da"><img src="http://feedads.g.doubleclick.net/~a/bYACpbNGRiM4G8FxMWVKMxYyRkg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/bYACpbNGRiM4G8FxMWVKMxYyRkg/1/da"><img src="http://feedads.g.doubleclick.net/~a/bYACpbNGRiM4G8FxMWVKMxYyRkg/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/DobryKod?a=odid8-LTAus:SiFqXbjBYFE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/DobryKod?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/DobryKod?a=odid8-LTAus:SiFqXbjBYFE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/DobryKod?i=odid8-LTAus:SiFqXbjBYFE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/DobryKod?a=odid8-LTAus:SiFqXbjBYFE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/DobryKod?i=odid8-LTAus:SiFqXbjBYFE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/DobryKod?a=odid8-LTAus:SiFqXbjBYFE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/DobryKod?i=odid8-LTAus:SiFqXbjBYFE:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/odid8-LTAus" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/asociativni-hledani/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/asociativni-hledani/</feedburner:origLink></item>
		<item>
		<title>Jednoduchý Drag &amp; Drop</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/gkd77iJ358Q/</link>
		<comments>http://www.dobrykod.com/archiv/jednoduchy-drag-and-drop/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 08:00:43 +0000</pubDate>
		<dc:creator>Honza Štěrba</dc:creator>
				<category><![CDATA[JavaFX]]></category>
		<category><![CDATA[drag&drop]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=179</guid>
		<description><![CDATA[Přetahování elemetů mezi dvěma seznamy patří většinou do příjemných rozšíření aplikací a přináší zpětnou vazbu a jednoduchost do jinak těžce realizovatelných funkcí. Začněme definováním jednoduchého grafického seznamu elementů. Nejdříve nadefinuji třídu Container, která se bude starat o seznam elementů, zobrazí k nim pozadí a bude je udržovat zarovnané pod sebou. class Container extends CustomNode { [...]]]></description>
			<content:encoded><![CDATA[<p>Přetahování elemetů mezi dvěma seznamy patří většinou do příjemných rozšíření aplikací a přináší zpětnou vazbu a jednoduchost do jinak těžce realizovatelných funkcí.</p>
<p><span id="more-179"></span></p>
<p>Začněme definováním jednoduchého grafického seznamu elementů. Nejdříve nadefinuji třídu <em>Container</em>, která se bude starat o seznam elementů, zobrazí k nim pozadí a bude je udržovat zarovnané pod sebou.</p>
<pre name="code" class="java">
class Container extends CustomNode {
	var list: Group = Group {}
	var nodes: Node[] on replace {
		var t = 0;
		for (node in nodes) {
			node.translateY = t;
			t += node.layoutBounds.height + 10;
		}
		list.content = nodes;
	}
	override function create() {
		Group {
			content: [
				Rectangle {
					x: bind list.boundsInParent.minX - 5
					y: bind list.boundsInParent.minY - 5
					width: bind list.boundsInParent.width + 10
					height: bind list.boundsInParent.height + 10
					fill: Color.YELLOW
				},
				list
			]
		}
	}
}
</pre>
<p>Jako elementy pro jednoduchost použiju obyčejné obdélníky vyplněné náhodnými barvami, kterými následně vyplním <em>Container</em>. </p>
<pre name="code" class="java">
class Draggable extends CustomNode {
	var container : Container;
	var rect = Rectangle {
			width: 80
			height: 30
			fill: randomColor()
	}
	override function create() {
		rect
	}
	function randomColor() : Color {
		Color.rgb(r.nextInt(255), r.nextInt(255), r.nextInt(255))
	}
}

var container1 = Container {
	translateX: 10
	translateY: 50
}
container1.nodes = [
	Draggable { container: container1 },
	Draggable { container: container1 },
	Draggable { container: container1 },
	Draggable { container: container1 }
];
</pre>
<p>Stejným způsobem pak vytvořím <em>container2</em> a oba vložím spolu s jednoduchým nadpisem do scény.</p>
<pre name="code" class="java">
Stage {
	title: TITLE
	scene: Scene {
		width: 240
		height: 320
		content: [
			header,
			container1,
			container2
		]
	}
}
</pre>
<p>Pro funkčnost drag&#038;drop je třeba, aby každý z vytvořených obdélníků reagoval na <em>onMouseDragged</em>.</p>
<pre name="code" class="java">
Rectangle {
	width: 80
	height: 30
	fill: randomColor()
	onMouseDragged: function(e) {
		this.translateX = e.dragX;
		this.translateY = e.dragY;
	}
}
</pre>
<p>Tato úprava sice způsobí, že se element stane táhnuteným, bohužel ale rozbije všechno ostatní. Při táhnutí je potřeba obdélník ze seznamu vyjmout a vložit do scény samostatně. Nejdříve přidám proměnou pro aktuálně tažený elment a zajistím aby se zobrazil ve scéně.</p>
<pre name="code" class="java">
// aktuálně tažený element
var dragged: Draggable;
Stage {
	scene: Scene {
		content: [
			header,
			container1,
			container2,
			Group {
				// zobrazuje aktuálně tažený element
				content: bind [dragged]
			}
		]
	}
}
</pre>
<p>Následně vložím kód zpracovávající reakci na <em>drag</em> a <em>release</em>. Funkce přidávám přímo do třídy Draggable pro větší přehlednost:</p>
<pre name="code" class="java">
class Draggable extends CustomNode {
	override var onMouseDragged = function(e) {
		if (not drag) {
			drag = true;
			delete this from container.nodes;
			dragged = this;
			// napozicovat element "pod myš"
			rect.x = e.sceneX - e.x;
			rect.y = e.sceneY - e.y;
		}
		// posunout element o relativní posun myši
		translateX = e.dragX;
		translateY = e.dragY;
	}
	override var onMouseReleased = function (e) {
		if (drag) {
			drag = false;
			// všechno se vrátí do původního stavu
			translateX = 0;
			translateY = 0;
			rect.x = 0;
			rect.y = 0;
			dragged = null;
			insert this into container.nodes;
		}
	}
}
</pre>
<p>Teď už se táhnutelné elemety chovají tak jak mají &#8211; pohybují se spolu s myší a při upuštění se vrátí zpět do původního seznamu. Aby se element při upuštění zařadil do správného seznamu, musí každý <em>Container</em> reagovat na <em>onMouseEntered</em> a <em>onMouseExited</em>. Je tedy třeba říct táhnutému elementu, kam má upadnout. A dále je potřeba zajistit, aby se element upuštěný jenom tak v prostoru vrátil na původní místo.</p>
<pre name="code" class="java">
class Draggable extends CustomNode {
	var startingContainer: Container;
	var container : Container on replace {
		if (container == null and startingContainer != null) {
			container = startingContainer;
		}
	};
}

class Container extends CustomNode {
	override var onMouseEntered = function(e) {
		// já jsem teď tvůj nový container
		dragged.container = this;
	}
	override var onMouseExited = function(e) {
		// zapomeň na mě, vrať se odkud si přišel
		dragged.container = null;
	}
}
</pre>
<p>Teď už mám plně funkční kód a zbývá jenom přidat trochu vizuální odezvy. Přidáním jedné řádky se táhnuté elementy stanou lehce průhlednými a aktivní seznamy se rozsvítí po najetí myši.</p>
<pre name="code" class="java">
class Draggable extends CustomNode {
	override var opacity = bind if (drag) 0.6 else 1
}

class Container extends CustomNode {
	override function create() {
		Group {
			content: [
				Rectangle {
					fill: bind if (hover and dragged != null) Color.GREEN else Color.YELLOW
				},
				list
			]
		}
	}
}
</pre>
<p>Jak to celé funguje si můžeš prohlédnout tu:</p>
<p><script src="http://dl.javafx.com/1.1/dtfx.js"></script></p>
<p><script>
    javafx(
        {
              archive: "http://www.dobrykod.com/wp-content/uploads/2009/02/simpledragdrop.jar",
              width: 240,
              height: 320,
              code: "simpledragdrop.Main",
              name: "SimpleDragDrop"
        }
    );
</script></p>
<p>Zdrojové kódy jsou k dispozici na githubu: <a href="http://github.com/honzasterba/dobrykod/tree/master/simple-drag-drop">simple-drag-drop</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/J9dFaD0mF8rpDABheM2PLiordxw/0/da"><img src="http://feedads.g.doubleclick.net/~a/J9dFaD0mF8rpDABheM2PLiordxw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/J9dFaD0mF8rpDABheM2PLiordxw/1/da"><img src="http://feedads.g.doubleclick.net/~a/J9dFaD0mF8rpDABheM2PLiordxw/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=Pi8mq3Ul"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=zYQkWaye"><img src="http://feeds.feedburner.com/~f/DobryKod?i=zYQkWaye" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=KJFBXDEE"><img src="http://feeds.feedburner.com/~f/DobryKod?i=KJFBXDEE" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=mLlHAOwD"><img src="http://feeds.feedburner.com/~f/DobryKod?i=mLlHAOwD" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/gkd77iJ358Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/jednoduchy-drag-and-drop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/jednoduchy-drag-and-drop/</feedburner:origLink></item>
		<item>
		<title>Přizpůsobivé pozadí</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/9Z6XV2SYwpI/</link>
		<comments>http://www.dobrykod.com/archiv/prizpusobive-pozadi/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 08:00:58 +0000</pubDate>
		<dc:creator>Honza Štěrba</dc:creator>
				<category><![CDATA[JavaFX]]></category>
		<category><![CDATA[bounds]]></category>
		<category><![CDATA[grafika]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=197</guid>
		<description><![CDATA[Grafické API v JavaFX obsahuje atributy pro zjišťování hranic (bounds) jednotlivých elementů ve scéně. Toto API je na první pohled docela jednoduché, ale při intenzivnějším používání se objevují mnohé záludnosti. Jedním vhodným použitím hranic elementu je vytvoření přizůsobivého pozadí. Jinými slovy jde o element, který svojí plochou pokrývá plochu jiného elementu a vykresluje se pod [...]]]></description>
			<content:encoded><![CDATA[<p>Grafické API v JavaFX obsahuje atributy pro zjišťování hranic (bounds) jednotlivých elementů ve scéně. Toto API je na první pohled docela jednoduché, ale při intenzivnějším používání se objevují mnohé záludnosti. Jedním vhodným použitím hranic elementu je vytvoření <em>přizůsobivého pozadí</em>. Jinými slovy jde o element, který svojí plochou pokrývá plochu jiného elementu a vykresluje se pod ním.</p>
<p><span id="more-197"></span></p>
<p>Začněme jednoduchým kódem, který obsahuje VBox (stará se o vertikální zarovnání elementů pod sebe), do kterého je možné přídávat a odebírat prvky.</p>
<pre name="code" class="java">
var nodes: Node[] = [];
var box: VBox;

Stage {
    title: "Background Fill"
    scene: Scene {
        width: 240
        height: 320
        content: [
            box = VBox {
                content: bind nodes
                spacing: 10
                onKeyPressed: function(e) {
                    if (e.code == KeyCode.VK_UP) {
                        insert
                        Rectangle {
                            width: 50
                            height: 50
                            fill: Color.GREEN
                        } into nodes;
                    }
                    if (e.code == KeyCode.VK_DOWN) {
                        if (sizeof(nodes) > 0) {
                            delete nodes[0] from nodes;
                        }
                    }
                }
            }
        ]
    }
}
</pre>
<p>Jediným správným místem kam pozadí umístit je na stejnou úroveň jako je <em>vbox</em> s elementy. Tím, že se element pro pozadí umístí do obsahu před <em>vbox</em> se zajistí, že se bude vykreslovat pod ním.</p>
<pre name="code" class="java">
        content: [
            Rectangle {
                x: 0
                y: 0
                width: 240
                height: 320
                fill: Color.YELLOW
            },
            box = VBox {
                   // beze změny
            }
        ]
</pre>
<p>Takto se ale vytvoří pouze obdélník, který zakrývá pevně danou plochu 240&#215;320. Aby kopíroval rozměry vboxu, kterému má být pozadím, je třeba jeho rozměry provázat s hranicemi vboxu. K tomu poslouží <strong>bind</strong> a <strong>boundsInParent</strong>.</p>
<pre name="code" class="java">
            Rectangle {
                x: 0
                y: 0
                width: bind box.boundsInParent.width
                height: bind box.boundsInParent.height
                fill: Color.RED
            }
</pre>
<p>Takhle kód funguje dobře a dělá přesně to, co se po něm chce. Vzhledově to ale moc dobře nevypadá, je dobré například přidat nějaké okraje:</p>
<pre name="code" class="java">
var nodes: Node[] = [];
var box: VBox;
def MARGIN = 5;

Stage {
    title: "Background Fill"
    scene: Scene {
        width: 240
        height: 320
        content: [
            Rectangle {
                x: bind box.boundsInParent.minX - MARGIN
                y: bind box.boundsInParent.minY - MARGIN
                width: bind box.boundsInParent.width + MARGIN*2
                height: bind box.boundsInParent.height + MARGIN*2
                fill: Color.RED
            },
            box = VBox {
                content: bind nodes
                spacing: 2*MARGIN
                translateX: MARGIN // Odsazení od kraje
                translateY: MARGIN // Odsazení od kraje
                onKeyPressed: function(e) {
                    if (e.code == KeyCode.VK_UP) {
                        insert
                        Rectangle {
                            width: 50
                            height: 50
                            fill: Color.GREEN
                        } into nodes;
                    }
                    if (e.code == KeyCode.VK_DOWN) {
                        if (sizeof(nodes) > 0) {
                            delete nodes[0] from nodes;
                        }
                    }
                }
            }
        ]
    }
}

box.requestFocus();
</pre>
<p>Výsledná aplikace pak vypadá takto:<br />
<script src="http://dl.javafx.com/1.1/dtfx.js"></script><br />
<script>
    javafx(
        {
              archive: "http://www.dobrykod.com/wp-content/uploads/2009/02/backgroudfill.jar",
              draggable: true,
              width: 240,
              height: 320,
              code: "backgroudfill.Main",
              name: "BackgroudFill"
        }
    );
</script></p>
<p>Kód je k dispozici na githubu: <a href="http://github.com/honzasterba/dobrykod/tree/master/prizpusobive-pozadi/">prizpusobive-pozadi</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/MxdTidHFIiX5PLdnoS4E4P5Olzk/0/da"><img src="http://feedads.g.doubleclick.net/~a/MxdTidHFIiX5PLdnoS4E4P5Olzk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/MxdTidHFIiX5PLdnoS4E4P5Olzk/1/da"><img src="http://feedads.g.doubleclick.net/~a/MxdTidHFIiX5PLdnoS4E4P5Olzk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=MxaBfj6X"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=er8nITbe"><img src="http://feeds.feedburner.com/~f/DobryKod?i=er8nITbe" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=fsY8XOgD"><img src="http://feeds.feedburner.com/~f/DobryKod?i=fsY8XOgD" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=m37qYPTN"><img src="http://feeds.feedburner.com/~f/DobryKod?i=m37qYPTN" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/9Z6XV2SYwpI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/prizpusobive-pozadi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/prizpusobive-pozadi/</feedburner:origLink></item>
		<item>
		<title>Refaktoring iterátoru</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/FD--VJp9U08/</link>
		<comments>http://www.dobrykod.com/archiv/refaktoring-iteratoru/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 10:48:25 +0000</pubDate>
		<dc:creator>Honza Štěrba</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[iterátor]]></category>
		<category><![CDATA[refaktoring]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=183</guid>
		<description><![CDATA[Iterátory v Ruby jsou ve spojení s uzávěry (closures) velmi silným nástrojem. Každá třída, která reprezentuje nějakou kolekci, totiž obsahuje Enumerable modul. Ten s sebou přináší několik iterátorů. Jednoduchá iterace přes položky pole vypadá takto: an_array.each do &#124;item&#124; # udelej neco s item end Mějme nějaká dvourozměrná data, která nejsou polem. Například objekt obsahující souřadnice [...]]]></description>
			<content:encoded><![CDATA[<p>Iterátory v Ruby jsou ve spojení s uzávěry (closures) velmi silným nástrojem. Každá třída, která reprezentuje nějakou kolekci, totiž obsahuje Enumerable modul. Ten s sebou přináší několik iterátorů. Jednoduchá iterace přes položky pole vypadá takto:</p>
<pre name="code" class="ruby">an_array.each do |item|
  # udelej neco s item
end</pre>
<p><span id="more-183"></span></p>
<p>Mějme nějaká dvourozměrná data, která nejsou polem. Například objekt obsahující souřadnice mezních bodů polygonu (pravý horní, levý horní, pravý dolní a levý dolní).</p>
<pre name="code" class="ruby"># polygon0.rb
class Polygon
  attr_accessor :ur_x, :ur_y, :ul_x, :ul_y, :lr_x, :lr_y, :ll_x, :ll_y
end</pre>
<p>Takto vypadá jednoduchá metoda, která hodnoty všech polí vypíše do konzole:</p>
<pre name="code" class="ruby"># polygon0.rb
  def print_corners
    puts ur_x, ur_y, ul_x, ul_y, lr_x, lr_y, ll_x, ll_y
  end
</pre>
<p>Stačilo zkopírovat seznam polí a odstranit dvojtečky. Kopírování kódu ale zavání problémem, takže je lepší se hned vrhnout do refaktoringu a seznam rohů si uložit do konstanty a upravit související kód.</p>
<pre name="code" class="ruby"># polygon1.rb
class Polygon

  CORNERS = [:ur_x, :ur_y, :ul_x, :ul_y, :lr_x, :lr_y, :ll_x, :ll_y]

  CORNERS.each do |corner|
    attr_accessor corner
  end

  def print_corners
    CORNERS.each do |corner|
      puts send(corner)
    end
  end
end</pre>
<p>Volání <em>send(corner)</em> je dynamickým voláním metody, tady snad není nutné další vysvětlení. Takto přepsaná třída dělá to samé, co předchozí verze, ale je daleko rozšiřitelnější.</p>
<p>Aby se dalo přes data iterovat skutečně dvourozměrně, musíme konstanty ještě trošku poupravit.</p>
<pre name="code" class="ruby"># polygon2.rb
class Polygon

  CORNERS = ["ur", "ul", "lr", "ll"]
  PARTS = ["x", "y"]

  CORNERS.each do |corner|
    PARTS.each do |part|
      attr_accessor "#{corner}_#{part}".to_sym
    end
  end

  def print_corners
    CORNERS.each do |corner|
      PARTS.each do |part|
        puts send("#{corner}_#{part}".to_sym)
      end
    end
  end

end</pre>
<p>To na jednu stranu přidává ohromnou flexibilitu při práci s jednotlivými souřadnicemi, na druhou stranu přináší nutnost pro každou operaci kopírovat dva vnořené iterátory. Pro příklad přidám metodu, která zkontroluje, zda jsou všechna pole nulová a pokud ano, nastaví je na <em>nil</em>.</p>
<pre name="code" class="ruby"># polygon2.rb
  def fix_zero_to_nil
    all_zero = true
    CORNERS.each do |corner|
      PARTS.each do |part|
        val = send("#{corner}_#{part}".to_sym)
        all_zero &#038;&#038;= val.nil? || val == 0
      end
    end
    return unless all_zero
    CORNERS.each do |corner|
      PARTS.each do |part|
        send("#{corner}_#{part}=".to_sym, nil)
      end
    end
  end
</pre>
<p>Na tomto kódu je krásně vidět, jak metoda díky nutnosti pokaždé iterovat přes dvě pole nabobtnala. Je třeba znova refaktorovat a udělat si vlastní iterátory. Jeden pro případ, že nás skutečně zajímá iterátor pro každou úroveň. Druhý pro případ, že nás zajímají jenom spojené položky.</p>
<pre name="code" class="ruby"># polygon3.rb
  def Polygon.each_corner_and_part
    CORNERS.each do |corner|
      PARTS.each do |part|
        yield(corner, part)
      end
    end
  end

  def Polygon.each_coordinate
    each_corner_adn_part do |corner, part|
      yield("#{corner}_#{part}")
    end
  end
</pre>
<p>Tyto iterátory přijdou vhod ve všech metodách třídy:</p>
<pre name="code" class="ruby"># polygon3.rb
class Polygon

  CORNERS = ["ur", "ul", "lr", "ll"]
  PARTS = ["x", "y"]

  def Polygon.each_corner_and_part
    CORNERS.each do |corner|
      PARTS.each do |part|
        yield(corner, part)
      end
    end
  end

  def Polygon.each_coordinate
    each_corner_and_part do |corner, part|
      yield("#{corner}_#{part}")
    end
  end

  each_coordinate do |coord|
    attr_accessor coord.to_sym
  end

  def print_corners
    Polygon.each_coordinate do |coord|
      puts send(coord.to_sym)
    end
  end

  def fix_zero_to_nil
    all_zero = true
    Polygon.each_coordinate do |coord|
      val = send(coord.to_sym)
      all_zero &#038;&#038;= val.nil? || val == 0
    end
    return unless all_zero
    Polygon.each_coordinate do |coord|
      send("#{coord}=".to_sym, nil)
    end
  end

end
</pre>
<p>Zdorjové kódy jsou k dispozici na githubu: <a href="http://github.com/honzasterba/dobrykod/tree/master/refaktoring-iteratoru">refaktoring-iteratoru</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/VgErP1KVL1rveLT8vZsJ-0EJrjg/0/da"><img src="http://feedads.g.doubleclick.net/~a/VgErP1KVL1rveLT8vZsJ-0EJrjg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/VgErP1KVL1rveLT8vZsJ-0EJrjg/1/da"><img src="http://feedads.g.doubleclick.net/~a/VgErP1KVL1rveLT8vZsJ-0EJrjg/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=17yOoroQ"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=rVW0dAqw"><img src="http://feeds.feedburner.com/~f/DobryKod?i=rVW0dAqw" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=VsIFtHC6"><img src="http://feeds.feedburner.com/~f/DobryKod?i=VsIFtHC6" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=Li7vkfye"><img src="http://feeds.feedburner.com/~f/DobryKod?i=Li7vkfye" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/FD--VJp9U08" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/refaktoring-iteratoru/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/refaktoring-iteratoru/</feedburner:origLink></item>
		<item>
		<title>Filtrovanie obsahu dokumentu bez použitia Ajaxu</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/uLdUb6az0w0/</link>
		<comments>http://www.dobrykod.com/archiv/filtrovanie-obsahu-dokumentu-bez-pouzitia-ajaxu/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 11:20:26 +0000</pubDate>
		<dc:creator>Riki Fridrich</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[string]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=164</guid>
		<description><![CDATA[Prefiltrovanie nejakého dlhého zoznamu. Šlo by to urobiť Ajaxom. Ale načo zaťažovať server v prípade, že je už aj tak celý zoznam zobrazený na stránke? Stačí na to jednoduchý objekt a dokonca je to rýchlejšie než séria ajaxových dotazov. Čo to má robiť? Otvor praktickú ukážku V základnej verzii to vezme zoznam položiek (napríklad odrážkový [...]]]></description>
			<content:encoded><![CDATA[<p>Prefiltrovanie nejakého dlhého zoznamu. Šlo by to urobiť Ajaxom. Ale načo zaťažovať server v prípade, že je už aj tak celý zoznam zobrazený na stránke? Stačí na to jednoduchý objekt a dokonca je to rýchlejšie než séria ajaxových dotazov.</p>
<p><span id="more-164"></span></p>
<h2>Čo to má robiť?</h2>
<p><a href="http://www.dobrykod.com/wp-content/uploads/2009/01/content-filter.html">Otvor praktickú ukážku</a></p>
<p>V základnej verzii to vezme zoznam položiek (napríklad odrážkový zoznam UL) a nejaké textové políčko. Pri písaní do textového políčka to prejde celý zoznam a schová všetky položky, ktoré neobsahujú text v políčku. Na schovávanie položiek sa použije nejaká jednoduchá CSS trieda, ktorá bude obsahovať akurát <code>display:none</code>.</p>
<p>Aby to bolo trochu univerzálnejšie, malo by to mať pár konfigurovateľných parametrov:</p>
<ul>
<li>Názov triedy na schovávanie elementov.</li>
<li>CSS selector pre výber elementov. Nie vždy to totiž musí byť odrážkový zoznam (t.j. LI). Môže sa to použiť trebárs na riadky tabuľky, alebo rovno na celé bloky s nejakou triedou.</li>
<li>Umožnenie definície oblasti v rámci elementu (čiže opäť CSS selector), v ktorom sa má vyhľadávať. To pre prípad, že by som napríklad mal zoznam článkov s titulkami a náhľadmi, pričom filtrovať by som chcel iba podľa titulkov, ale skrývať by som chcel celé bloky.</li>
</ul>
<p>Čerešnička na torte by bola jednoduchá možnosť prefiltrovať položky manuálne (t.j. zavolaním nejakej metódy a nie písaním do textového políčka).</p>
<h2>Kostra objektu</h2>
<p>Z požiadavkov na skript sa pekne vylúpne základná kostra:</p>
<pre name="code" class="js">var ContentFilter = Class.create({

	initialize : function ( element, input, options ) {
		this.element = $( element );
		this.input = $( input );
		this.options = Object.extend( {
			// defaultne hodnoty
		}, options || {} );

		// filter sa spusti pri kazdom stlaceni klavesy v policku,
		// alebo pri zmene jeho hodnoty (napr. pri copy/paste)
		this.input.observe( 'keyup', this.filter.bind( this ) );
		this.input.observe( 'change', this.filter.bind( this ) );
	},

	// pomocna funkcia, ktora sa spusti pri zmene obsahu policka
	filter : function () {
		this.filterBy( this.input.value );
	},

	// tuto funkciu je mozne volat aj manualne
	filterBy : function ( search ) {
		// mechanizmus filtrovania
	}

});</pre>
<p>Teraz už stačí len dopísať pár detailov a samotnú funkčnosť.</p>
<h2>Konfigurovateľné položky (options)</h2>
<ul>
<li><strong>hiddenClass</strong> &#8211; Názov triedy, ktorá sa pridá všetkým elementom, ktoré neobsahujú hľadaný text. Defaultná hodnota bude &#8220;hidden&#8221;. Niekde v CSS bude treba zadefinovať <code>.hidden { display: none; }</code></li>
<li><strong>itemSelector</strong> &#8211; CSS selector, ktorý reprezentuje položky v zozname. Predpokladám že defaultne sa bude skript používať na odrážkové zoznamy, takže tento selector bude <code>LI</code>.</li>
<li><strong>searchArea</strong> &#8211; Opäť CSS selector. Ak bude zadefinovaný, umožní rozlíšiť medzi elementom ktorý sa má zobrazovať/skrývať a medzi elementom, v ktorom sa má hľadať text. Defaultne bude prázdny.</li>
</ul>
<pre name="code" class="js">this.options = Object.extend( {
	hiddenClass : 'hidden', // defaultna trieda schovaneho elementu
	itemSelector : 'li', // defaultny CSS selector pre hladanie elementov
	searchArea : false // umozni specifikovat oblast v ramci elementu, kde sa ma hladat
}, options || {} );</pre>
<h2>Samotné vyhľadávanie</h2>
<p>Na vyhľadanie elementov sa použije metóda <a href="http://prototypejs.org/api/element/select">Element.select()</a>. Tá vráti zbierku elementov, ktoré bude treba prejsť a skontrolovať, či obsahujú daný text.</p>
<p>Na kontrolu sa použije jednoduchý regulárny výraz metódou <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/RegExp/Test">RegExp.test()</a>. Pozor! Pri generovaní regulárneho výrazu si treba dať pozor, aby to nehádzalo chyby kvôli nevalidnému reťazcu.</p>
<p>Samotný textový obsah elementu sa jednoducho získa odstránením tagov z jeho innerHTML pomocou <a href="http://prototypejs.org/api/string/stripTags">String.stripTags()</a>.</p>
<pre name="code" class="js">filterBy : function ( search ) {

	// osetrenie pripadu, kedy uzivatel vlozi do inputu string ktory rozhodi regexp
	try { var re = new RegExp( search, 'i' ); }
	catch ( err ) { var re = new RegExp(); }

	var items = this.element.select( this.options.itemSelector );

	for ( var i = 0, totalItems = items.length; i < totalItems; i++ ) {
		var item = items[i];
		if ( re.test( item.innerHTML.stripTags() ) ) {
			item.removeClassName( this.options.hiddenClass );
		} else {
			item.addClassName( this.options.hiddenClass );
		}
	}
}</pre>
<h2>Priestor pre optimalizáciu výkonu</h2>
<p>V skripte sú teraz dve miesta v hodné k optimalizácii.</p>
<p>V prvom rade je tu situácia, kedy bude <strong>hľadaný výraz prázdny</strong> (napr. keď vo filtrovacom políčku nič nebude). V takom prípade je jasné, že ani jeden element nemá mať <code>hiddenClass</code> a teda nemá zmysel ich po jednom prechádzať a kontrolovať regulárnym výrazom. Stačí zavolať:</p>
</pre>
<pre name="code" class="js">items.invoke( 'removeClassName', this.options.hiddenClass );</pre>
<p>V druhom rade je tu neustále <strong>zisťovanie zoznamu elementov</strong> (<code>items</code>) pri každom novom cykle. To je nutné robiť v prípade, že ten zoznam je dynamický a jeho obsah sa môže meniť. Ak sa však s takou situáciou nepočíta, výkonu by rozhodne pomohlo, keby skript tento zoznam získal už pri inicializácii a zapamätal si ho napríklad v premennej <code>this.items</code>.</p>
<h2>searchArea</h2>
<p>Ostáva doplniť poslednú drobnosť. Ak je zadefinovaná searchArea, treba text hľadať v nej a nie v celom elemente. Záležitosť jednej jednoduchej podmienky:</p>
<pre name="code" class="js">// ak nie je specifikovana searchArea, pouzije sa cely element
var searchArea = ( this.options.searchArea ) ? item.down( this.options.searchArea ) : item;

if ( re.test( searchArea.innerHTML.stripTags() ) ) {
	item.removeClassName( this.options.hiddenClass );
} else {
	item.addClassName( this.options.hiddenClass );
}</pre>
<h2>Výsledný skript</h2>
<p>Celý objekt bude vyzerať asi takto:</p>
<pre name="code" class="js">var ContentFilter = Class.create({

	initialize : function ( element, input, options ) {
		this.element = $( element );
		this.input = $( input );
		this.options = Object.extend( {
			hiddenClass : 'hidden', // defaultna trieda schovaneho elementu
			itemSelector : 'li', // defaultny CSS selector pre hladanie elementov
			searchArea : false // umozni specifikovat oblast v ramci elementu, kde sa ma hladat
		}, options || {} );

		// filter sa spusti pri kazdom stlaceni klavesy v policku,
		// alebo pri zmene jeho hodnoty (napr. pri copy/paste)
		this.input.observe( 'keyup', this.filter.bind( this ) );
		this.input.observe( 'change', this.filter.bind( this ) );
	},

	// pomocna funkcia, ktora sa spusti pri zmene obsahu policka
	filter : function () {
		this.filterBy( this.input.value );
	},

	// tuto funkciu je mozne volat aj manualne
	filterBy : function ( search ) {

		// ak sa nepredpoklada ze by sa obsah zoznamu dynamicky menil, je mozne kvoli optimalizacii
		// vykonu zoznam elementov ziskat uz pri inicializacii namiesto kontroly pri kazdom volani filtru
		var items = this.element.select( this.options.itemSelector );

		if ( search ) {

			// osetrenie pripadu, kedy uzivatel vlozi do inputu string ktory rozhodi regexp
			try { var re = new RegExp( search, 'i' ); }
			catch ( err ) { var re = new RegExp(); }

			// prejde textovy obsah vsetkych elementov a zisti ci obsahuju hladany vyraz
			// na zaklade toho prida alebo odoberie triedu
			for ( var i = 0, totalItems = items.length; i < totalItems; i++ ) {

				var item = items[i];

				// ak nie je specifikovana searchArea, pouzije sa cely element
				var searchArea = ( this.options.searchArea ) ? item.down( this.options.searchArea ) : item;

				if ( re.test( searchArea.innerHTML.stripTags() ) ) {
					item.removeClassName( this.options.hiddenClass );
				} else {
					item.addClassName( this.options.hiddenClass );
				}
			}
		} else {

			// optimalizacia vykonu: ak je hladany vyraz prazdny, je jasne ze vyhovuju vsetky elementy
			items.invoke( 'removeClassName', this.options.hiddenClass );

		}
	}

});</pre>
<h2>Použitie a praktická ukážka</h2>
<p><a href="http://www.dobrykod.com/wp-content/uploads/2009/01/content-filter.html">Otvor praktickú ukážku</a></p>
<p>V základnej verzii stačí obejektu poslať ID zoznamu a ID vyhľadávacieho políčka:</p>
</pre>
<pre name="code" class="js">new ContentFilter( 'idZoznamu', 'idPolicka' );</pre>
<p>Ak chceš objekt customizovať:</p>
<pre name="code" class="js">new ContentFilter( 'idZoznamu', 'idPolicka', {
	hiddenClass : 'alternativnaTrieda',
	itemSelector : 'div.polozka',
	searchArea : 'h2'
} );</pre>
<p>A v prípade, že chceš volať filtrovanie manuálne:</p>
<pre name="code" class="js">var mojFilter = new ContentFilter( 'idZoznamu', 'idPolicka' );
mojFilter.filterBy( 'nejaky text' );</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/nfrRztpJKgooLVpniRNtbjFkSQo/0/da"><img src="http://feedads.g.doubleclick.net/~a/nfrRztpJKgooLVpniRNtbjFkSQo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/nfrRztpJKgooLVpniRNtbjFkSQo/1/da"><img src="http://feedads.g.doubleclick.net/~a/nfrRztpJKgooLVpniRNtbjFkSQo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=boWkmqIa"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=HzdCxlLP"><img src="http://feeds.feedburner.com/~f/DobryKod?i=HzdCxlLP" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=loyREGcP"><img src="http://feeds.feedburner.com/~f/DobryKod?i=loyREGcP" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=jaZrGlXS"><img src="http://feeds.feedburner.com/~f/DobryKod?i=jaZrGlXS" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/uLdUb6az0w0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/filtrovanie-obsahu-dokumentu-bez-pouzitia-ajaxu/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/filtrovanie-obsahu-dokumentu-bez-pouzitia-ajaxu/</feedburner:origLink></item>
		<item>
		<title>Dynamicky generovaný iframe</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/7wTavhk2yEo/</link>
		<comments>http://www.dobrykod.com/archiv/dynamicky-generovany-iframe/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 12:29:39 +0000</pubDate>
		<dc:creator>Riki Fridrich</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[element]]></category>
		<category><![CDATA[frameborder]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[replace]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=156</guid>
		<description><![CDATA[V súčasnosti sa element IFRAME opäť začína celkom často používať. Aj keď sa obvykle používa na niečo trochu iné, než k čomu bol pôvodne určený. Dynamicky generované iframy majú svoje úskalia, ktoré by ťa mohli stáť pekných pár hodín strávených zúfalým hľadaním podkladov a debugovaním. Stačí však o nich vedieť a dá sa im ľahko [...]]]></description>
			<content:encoded><![CDATA[<p>V súčasnosti sa element IFRAME opäť začína celkom často používať. Aj keď sa obvykle používa na niečo trochu iné, než k čomu bol pôvodne určený. Dynamicky generované iframy majú svoje úskalia, ktoré by ťa mohli stáť pekných pár hodín strávených zúfalým hľadaním podkladov a debugovaním. Stačí však o nich vedieť a dá sa im ľahko vyhnúť.<br />
<span id="more-156"></span></p>
<h2>frameborder versus frameBorder</h2>
<p>Defaultne má iframe okolo seba hnusný border. Ten sa dá odstrániť nastavením atribútu <code>frameborder</code>:</p>
<pre name="code" class="html">&lt;iframe src="/zdroj/iframu/" frameborder="0"&gt;&lt;/iframe&gt;</pre>
<p>Problém nastáva v momente, kedy je iframe generovaný dynamicky a atribút frameborder sa mu pridáva javascriptom:</p>
<pre name="code" class="js">var mojIframe = document.createElement( 'iframe' );
mojIframe.frameborder = '0';
document.body.appendChild( mojIframe );</pre>
<p>Napriek všetkým očakávaniam tam ten hnusný border furt bude. <a href="http://www.dobrykod.com/wp-content/uploads/2009/01/iframe-frameborder.html">Mrkni na ukážku.</a></p>
<p>Čo s tým? Zmanená to, že sa iframy musia vkladať pomocou innerHTML? Dá sa toho borderu nejako rozumne zbaviť? Áno, dá. Finta je v tom, že <strong>atribút <code>frameborder</code> je case-sensitive</strong> a keď sa dynamicky priraďuje javascriptom, musí sa písať camelCase. Čiže <code>frameBorder</code>.</p>
<p>Toto v pohode zafunguje:</p>
<pre name="code" class="js">var mojIframe = document.createElement( 'iframe' );
mojIframe.frameBorder = '0';
document.body.appendChild( mojIframe );</pre>
<h2>URL prázdneho iframu</h2>
<p>Dosť často sa IFRAME do dokumentu vkladá kvôli svojej zázračnej schopnosti prekryť elementy ako SELECT alebo embedované flashové video. U takého iframu je celkom jedno, čo sa v ňom zobrazí (ideálne nič).</p>
<p>Ak sa jeho atribút <code>src</code> nechá prázdny, bude to vo väčšine prípadov v pohode. Browser do iframu buď nič nenatiahne, alebo do neho vloží prázdnu stránku (v podstate about:blank). Problém však nastane v prípade, že stránka bude podliehať nejakým bezpečnostným kontrolám. Napríklad ak bude servírovaná protokolom HTTPS. V tom momente bude browser kričať, že sa snažíš vložiť nezabezpečený dokument do zabezpečenej stránky.</p>
<p>Sú teda dve možnosti:</p>
<ol>
<li>Vytvoriť prázdny dokument, ktorý bude publikovaný na rovnakej doméne (a protokole) ako rodičovský dokument. Tento prázdny dokument potom použiť ako obsah iframu.</li>
<li>Alebo jednoducho nastaviť <code>src</code> atribút iframu na <strong><code>javascript:false;</code></strong></li>
</ol>
<h2>Element.toIframe()</h2>
<p>Ešte malý bonus na záver: Malá a jednoduchá metóda pre Prototype, ktorá nahradí existujúci element iframom:</p>
<pre name="code" class="js">Element.addMethods({
  toIframe : function ( element, url, options ) {
    var element = $( element );
    var options = Object.extend( {
      src : url || 'javascript:false;', // ak nie je uvedena, pouzije sa prazdna stranka
      frameBorder : 0, // pozor na camelCase
      scrolling : 'no', // ak 'yes', tak ich IE zobrazi vzdy, aj ked ich nie je treba
      width : element.getWidth(),
      height : element.getHeight(),
      id : element.id
    }, options || {} );
    var iframe = new Element( 'iframe', options );
    element.replace( iframe );
    return iframe;
  }
});</pre>
<p>Snáď ju netreba komplikovane popisovať. <a href="http://www.dobrykod.com/wp-content/uploads/2009/01/element-toiframe.html">Pozri sa na praktickú ukážku.</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/AlpiLVXjOkqSiSmWfEL_Zili8zI/0/da"><img src="http://feedads.g.doubleclick.net/~a/AlpiLVXjOkqSiSmWfEL_Zili8zI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/AlpiLVXjOkqSiSmWfEL_Zili8zI/1/da"><img src="http://feedads.g.doubleclick.net/~a/AlpiLVXjOkqSiSmWfEL_Zili8zI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=uQBS4G1x"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=DWPDZKym"><img src="http://feeds.feedburner.com/~f/DobryKod?i=DWPDZKym" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=4uYCGQqT"><img src="http://feeds.feedburner.com/~f/DobryKod?i=4uYCGQqT" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=4WBXNiUY"><img src="http://feeds.feedburner.com/~f/DobryKod?i=4WBXNiUY" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/7wTavhk2yEo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/dynamicky-generovany-iframe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/dynamicky-generovany-iframe/</feedburner:origLink></item>
		<item>
		<title>Políčka s hintom</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/nbEtn9FMUzg/</link>
		<comments>http://www.dobrykod.com/archiv/policka-s-hintom/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 15:38:08 +0000</pubDate>
		<dc:creator>Riki Fridrich</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[default value]]></category>
		<category><![CDATA[field]]></category>
		<category><![CDATA[hint]]></category>
		<category><![CDATA[label]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=144</guid>
		<description><![CDATA[V niektorých prípadoch je užitočné ukázať užívateľovi nápovedu k formulárovému políčku priamo ako hodnotu políčka. Šetrí to priestor a pre užívateľov je to pohodlné a zrozumiteľné. Stačí na to pár riadkov JavaScriptu. Ale bacha, má to svoje drobné nástrahy. Zhodou okolností na túto tému nedávno písal Thomas Fuchs v článku Using input values as hints, [...]]]></description>
			<content:encoded><![CDATA[<p>V niektorých prípadoch je užitočné ukázať užívateľovi nápovedu k formulárovému políčku priamo ako hodnotu políčka. Šetrí to priestor a pre užívateľov je to pohodlné a zrozumiteľné. Stačí na to pár riadkov JavaScriptu. Ale bacha, má to svoje drobné nástrahy.</p>
<p><span id="more-144"></span>Zhodou okolností na túto tému nedávno písal Thomas Fuchs v článku <a href="http://mir.aculo.us/2009/1/7/using-input-values-as-hints-the-easy-way">Using input values as hints, the easy way</a>. Jeho riešenie je krásne a jednoduché. Ja osobne však v praxi používam niečo trošku komplikovanejšie.</p>
<h2>Čo má skript robiť?</h2>
<p>Skript by mal políčko asociovať s nejakou defaultnou hodnotou. Ak je políčko prázdne a neaktívne (nie je na ňom focus), defaultná hodnota by sa v ňom mala zobraziť zašednutá (alebo nejak inak vizuálne potlačená). Akonáhle užívateľ políčko vyplní alebo do neho chce niečo písať (políčko získa focus), malo by sa opäť správať štandardne.</p>
<p>Počas implementácie si hlavne treba dať pozor na jednu veci:</p>
<p>Pri submitnutí formulára treba skontrolovať, či užívateľ skutočne niečo do políčka vložil. Ak to neurobíš, budú sa ti na server posielať hinty z nevyplnených políčok. Samozrejme, môžeš si to ošetriť aj na stran servera. Je to na tebe.</p>
<h2>Základ</h2>
<p>Objekt ktorý sa mi o hint v políčku postará si nazvem FieldHint.</p>
<pre name="code" class="js">var FieldHint = Class.create({

	initialize : function ( field, hint ) {
		this.field = $( field );
		this.hint = hint;

		this.field.observe( 'focus', this.focus.bind( this ) );
		this.field.observe( 'blur', this.blur.bind( this ) );

		this.blur(); // inicializacne spustenie
	},

	focus : function () {
		if ( this.field.value == this.hint ) {
			this.field.value = '';
		}
	},

	blur : function () {
		if ( ( this.field.value == '' ) || ( this.field.value == this.hint ) ) {
			this.field.value = this.hint;
		}
	}

});</pre>
<h2>Ošetrenie submitu</h2>
<p>Pred odoslaním obsahu formuláru ešte treba zaistiť, aby sa neposlali aj hinty.</p>
<p>Toto síce vyzerá zložito, ale v skutočnosti na to už máš všetko čo potrebuješ (deje sa to v metóde <code>focus()</code>). Takže ju stačí pred submitom iba zavolať:</p>
<pre name="code" class="js">this.field.form.observe( 'submit', this.focus.bindAsEventListener( this ) );</pre>
<h2>Customizácia a formátovanie</h2>
<p>Chýba posledná vec: Formátovanie políčka keď obsahuje hint (napr. šedý text) a nejaká jednoduchá možnosť customizácie.</p>
<pre name="code" class="js">var FieldHint = Class.create({

	options : {
		hintClass : 'hint'
	},

	initialize : function ( field, hint, options) {
		this.field = $( field );
		this.hint = hint;
		Object.extend( this.options, options || {} );

		this.field.observe( 'focus', this.focus.bind( this ) );
		this.field.observe( 'blur', this.blur.bind( this ) );

		this.field.form.observe( 'submit', this.focus.bindAsEventListener( this ) );

		this.blur();
	},

	focus : function () {
		this.field.removeClassName( this.options.hintClass );
		if ( this.field.value == this.hint ) { this.field.value = ''; }
	},

	blur : function () {
		if ( ( this.field.value == '' ) || ( this.field.value == this.hint ) ) {
			this.field.addClassName( this.options.hintClass );
			this.field.value = this.hint;
		}
	}

});</pre>
<h2>Praktická ukážka</h2>
<p><a href="http://www.dobrykod.com/wp-content/uploads/2009/01/field-hint.html">Otvoriť praktickú ukážku</a></p>
<h2>Tip na ďalšie rozširovanie</h2>
<p>Hinty v políčkach sa často používajú ako náhrada za labely, obzvlášť ak designer potrebuje šetriť miestom. Labely by sa dali jednoducho skryť pomocou CSS a následne použiť pri automatickej inicializácii hintov. Asi takto:</p>
<h3>HTML</h3>
<pre name="code" class="html">&lt;label class=&quot;hint&quot; for=&quot;idPolicka&quot;&gt;label policka&lt;/label&gt;</pre>
<h3>CSS</h3>
<pre name="code" class="css">label.hint { display: none; }</pre>
<h3>JS</h3>
<pre name="code" class="js">document.observe( 'dom:loaded', function () {
	$$( 'label.hint' ).each( function ( elm ) {
		new FieldHint( elm.for, elm.innerHTML );
	} );
} )</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/6inlSXmUEHwV7diAaYh0RIAIeVY/0/da"><img src="http://feedads.g.doubleclick.net/~a/6inlSXmUEHwV7diAaYh0RIAIeVY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/6inlSXmUEHwV7diAaYh0RIAIeVY/1/da"><img src="http://feedads.g.doubleclick.net/~a/6inlSXmUEHwV7diAaYh0RIAIeVY/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=FJf1NYeL"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=2UZLHzsY"><img src="http://feeds.feedburner.com/~f/DobryKod?i=2UZLHzsY" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=q8itJOEO"><img src="http://feeds.feedburner.com/~f/DobryKod?i=q8itJOEO" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=Fv39TaID"><img src="http://feeds.feedburner.com/~f/DobryKod?i=Fv39TaID" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/nbEtn9FMUzg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/policka-s-hintom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/policka-s-hintom/</feedburner:origLink></item>
		<item>
		<title>document.getPageSize()</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/DKpReh5aKAU/</link>
		<comments>http://www.dobrykod.com/archiv/documentgetpagesize/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 10:21:33 +0000</pubDate>
		<dc:creator>Riki Fridrich</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[dimensions]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[viewport]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=138</guid>
		<description><![CDATA[Je viac spôsobov ako zistiť rozmery stránky. Podľa situácie ti môžu dať rôzne výsledky. Je dobré vedieť, čo ktorý znamená a ako sa za každej situácie dopracovať k tomu správnemu. Obzvlášť sa to hodí, keď niečím potrebuješ prekrývať celú stránku: napr. u javascriptových modálnych dialógov, galérií typu lightbox a pod. Základné pojmy Časť okna prehliadača, [...]]]></description>
			<content:encoded><![CDATA[<p>Je viac spôsobov ako zistiť rozmery stránky. Podľa situácie ti môžu dať rôzne výsledky. Je dobré vedieť, čo ktorý znamená a ako sa za každej situácie dopracovať k tomu správnemu. Obzvlášť sa to hodí, keď niečím potrebuješ prekrývať celú stránku: napr. u javascriptových modálnych dialógov, galérií typu lightbox a pod.</p>
<h2><span id="more-138"></span>Základné pojmy</h2>
<p>Časť okna prehliadača, v ktorej sa zobrazuje webová stránka je <strong>viewport</strong>. Súčasťou viewportu nie sú toolbary ani sidebary, dokonca ani scrollbary. Viewport je proste plocha v ktorej je zobrazená stránka a nič viac.</p>
<p><strong>Telo dokumentu</strong> (document.body) je plocha, ktorú zaberá obsah stránky. Jeho výška sa rovná pozícii spodného okraju najnižšie položeného elementu na stránke (obdobne je definovaná šírka).</p>
<p>Pár faktov, ktoré si treba pri zisťovaní veľkosti stránky uvedomiť:</p>
<ul>
<li>Ak je nejaký rozmer viewportu menší než rozmer tela dokumentu, bude stránka scrolovať.</li>
<li>Telo dokumentu sa automaticky nerozťahuje na rozmery viewportu. Ich šírka sa obvykle zhoduje (pretože blokové elementy majú defaultne šírku 100%). Ale výška je obvykle rôzna.</li>
</ul>
<h2>Možné problémy</h2>
<p><img class="size-full wp-image-140" title="viewport je menší než telo dokumentu" src="http://www.dobrykod.com/wp-content/uploads/2009/01/pagesize2.png" alt="viewport je menší než telo dokumentu" width="300" height="280" /></p>
<p>Ak je viewport menší než telo dokumentu, ty stránku prekryješ elementom s rozmermi viewportu a užívateľ odskroluje nižšie, uvidí neprekrytý obsah. Samozrejme, môžeš to ošetriť tak, že pri zobrazení prekrývajúceho elementu zakážeš skrolovanie. Akurát si to však skomplikuješ: Schovanie scrollbarov ti zmení veľkosť viewportu. A zakázanie skrolovania kolečkom rozhodne nie je triviálna záležitosť.</p>
<p><img class="size-full wp-image-139" title="Telo dokumentu je menšie než viewport" src="http://www.dobrykod.com/wp-content/uploads/2009/01/pagesize1.png" alt="Telo dokumentu je menšie než viewport. Scrollbar sa nezobrazí." width="300" height="280" /></p>
<p>Ak je telo dokumentu menšie než viewport a ty stránku prekryješ elementom s veľkosťou tela dokumentu, bude ti dole vyčuhovať neprekrytá plocha. Síce bude prázdna a nebude v nej žiadny klikací element, ale asi to nebude vyzerať úplne košer (hlavne ak je pozadie BODY iné než pozadie prekrývajúceho elementu.</p>
<h2>Čo s tým?</h2>
<p>Je to jednoduché. Treba hrať na istotu. Stačí si zistiť obidva údaje a použiť vždy tú vyššiu hodnotu. V <a href="http://prototypejs.org/">Prototype</a> sa to dá takto jednoducho (v ostatných knižniciach to bude obdobné):</p>
<pre name="code" class="js">document.getPageSize = function () {
	var viewportSize = document.viewport.getDimensions();
	var bodySize = $( document.body ).getDimensions();
	return {
		width : ( viewportSize.width &gt; bodySize.width ) ? viewportSize.width : bodySize.width,
		height : ( viewportSize.height &gt; bodySize.height ) ? viewportSize.height : bodySize.height
	};
}</pre>
<p>Použitie je jednoduché. Stačí sa opýtať na <code>document.getPageSize()</code>, ktorá vráti objekt s hodnotami width a height v pixeloch:</p>
<pre name="code" class="js">{ width : x, height: y }</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/O0VOLGjCzxCmXaQwB0xKAdmcmBg/0/da"><img src="http://feedads.g.doubleclick.net/~a/O0VOLGjCzxCmXaQwB0xKAdmcmBg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/O0VOLGjCzxCmXaQwB0xKAdmcmBg/1/da"><img src="http://feedads.g.doubleclick.net/~a/O0VOLGjCzxCmXaQwB0xKAdmcmBg/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=ehlV51bz"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=CQ66W4Sb"><img src="http://feeds.feedburner.com/~f/DobryKod?i=CQ66W4Sb" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=jREpzGH9"><img src="http://feeds.feedburner.com/~f/DobryKod?i=jREpzGH9" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=GFxp92J8"><img src="http://feeds.feedburner.com/~f/DobryKod?i=GFxp92J8" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/DKpReh5aKAU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/documentgetpagesize/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/documentgetpagesize/</feedburner:origLink></item>
		<item>
		<title>onResize event</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/ucL4wAuWSbs/</link>
		<comments>http://www.dobrykod.com/archiv/onresize-event/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 08:15:19 +0000</pubDate>
		<dc:creator>Riki Fridrich</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[document]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[resize]]></category>
		<category><![CDATA[window]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=129</guid>
		<description><![CDATA[Je to síce prasáreň, ale občas je to treba: Reagovať skriptom na zmenu veľkosti okna. Nič sa nedá robiť, treba sa s tým popasovať. document.onResize VS window.onResize Implementácia onResize eventu nie je v rôznych browseroch jednotná. Niektoré ju vešajú na dokument, niektoré na okno. A potom sú aj také (Opera), ktoré to alibisticky všajú všade: [...]]]></description>
			<content:encoded><![CDATA[<p>Je to síce prasáreň, ale občas je to treba: Reagovať skriptom na zmenu veľkosti okna. Nič sa nedá robiť, treba sa s tým popasovať.</p>
<p><span id="more-129"></span></p>
<h2>document.onResize VS window.onResize</h2>
<p>Implementácia onResize eventu nie je v rôznych browseroch jednotná. Niektoré ju vešajú na dokument, niektoré na okno. A potom sú aj také (Opera), ktoré to alibisticky všajú všade:</p>
<p><strong>document.onResize</strong></p>
<ul>
<li>Internet Explorer</li>
<li>Opera</li>
</ul>
<p><strong>window.onResize</strong></p>
<ul>
<li>Firefox</li>
<li>Opera</li>
<li>Safari</li>
</ul>
<h2>Správne volanie eventu</h2>
<p>Ako teda správne volať event onResize? Rozhodne by bola chyba detekovať browser. Vždy treba detekovať prítomnosť metódy. Kvôli obojpohlavnosti Opery by tiež bola chyba volať to aj nad dokumentom aj nad oknom &#8211; v Opere by sa to totiž spustilo dvakrát.</p>
<p>V Prototype sa teda tento event jednoducho zavesí takto:</p>
<pre name="code" class="js">Event.observe( document.onresize ? document : window, "resize", function() {
    // obsah resize eventu
} );</pre>
<p>Obdobné to bude vo všetkých ostatných knižniciach.</p>
<h2>Pár praktických informácií</h2>
<h3>Na čo onResize reaguje?</h3>
<p>onResize event reaguje na všetky zmeny veľkosti viewportu. To znamená:</p>
<ul>
<li>fyzická zmena okna (ťahaním za okraje a pod.)</li>
<li>zmena veľkosti okna skriptom (ak to browser umožňuje)</li>
<li>obnovenie z maxima (restore down&#8230; proste to stredné tlačítko medzi minimalizáciou a zatvorením) / maximalizácia okna</li>
<li>prepnutie do / z fullscreenu</li>
<li>zobrazenie / schovanie sidebarov, toolbarov a pod.</li>
<li>ak je okno prehliadača maximalizované, onResize zareaguje aj na zmenu rozlíšenia obrazovky!</li>
</ul>
<h3>Na čo onResize nereaguje?</h3>
<ul>
<li>minimalizácia okna</li>
<li>zmena pozície okna (preťahovaním myšou alebo skriptom)</li>
<li>skrolovanie</li>
<li>keď sa zmení veľkost BODY tak, že sa zobrazí alebo schová scrollbar, nepovažuje sa to za onResize</li>
</ul>
<h2>Praktická ukážka</h2>
<p><a href="http://www.dobrykod.com/wp-content/uploads/2009/01/onresize_event.html">Otvor praktickú ukážku</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/KNpXbELx4hCMKW08HozhS3j3uM8/0/da"><img src="http://feedads.g.doubleclick.net/~a/KNpXbELx4hCMKW08HozhS3j3uM8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KNpXbELx4hCMKW08HozhS3j3uM8/1/da"><img src="http://feedads.g.doubleclick.net/~a/KNpXbELx4hCMKW08HozhS3j3uM8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=FnoGaEwj"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=UFzGjMDI"><img src="http://feeds.feedburner.com/~f/DobryKod?i=UFzGjMDI" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=gPURMFvJ"><img src="http://feeds.feedburner.com/~f/DobryKod?i=gPURMFvJ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=CmLTIwZo"><img src="http://feeds.feedburner.com/~f/DobryKod?i=CmLTIwZo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/ucL4wAuWSbs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/onresize-event/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/onresize-event/</feedburner:origLink></item>
		<item>
		<title>Začínáme s Git</title>
		<link>http://feedproxy.google.com/~r/DobryKod/~3/Aql-GCGzYt8/</link>
		<comments>http://www.dobrykod.com/archiv/zaciname-s-git/#comments</comments>
		<pubDate>Fri, 02 Jan 2009 20:48:11 +0000</pubDate>
		<dc:creator>Honza Štěrba</dc:creator>
				<category><![CDATA[VSC]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[vcs]]></category>

		<guid isPermaLink="false">http://www.dobrykod.com/?p=116</guid>
		<description><![CDATA[Git je (podobně jako třeba mercurial) průkopníkem v novém přístupu ke správě verzí. Hlavním rysem distribuovaných systémů pro správu verzí (DVCS) je, že každá kopie repository je plnohodnotná a samostatná. To sice může být ze začátku složité na pochopení a občas to přidává práci, nicméně to s sebou přináší také nezanedbatelné výhody. Cílem tohoto článku [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://git-scm.com/">Git</a> je (podobně jako třeba <a href="http://www.selenic.com/mercurial/">mercurial</a>) průkopníkem v novém přístupu ke správě verzí. Hlavním rysem distribuovaných systémů pro správu verzí (<a href="http://en.wikipedia.org/wiki/Distributed_revision_control">DVCS</a>) je, že každá kopie repository je plnohodnotná a samostatná. To sice může být ze začátku složité na pochopení a občas to přidává práci, nicméně to s sebou přináší také nezanedbatelné výhody. Cílem tohoto článku je pomoci udělat první krůčky směrem ke Gitu a pochopit jak se s takovýmto systémem pracuje.</p>
<p><span id="more-116"></span>Když se řekne Git tak si asi každý vybaví <a href="http://github.com/">Github</a>. Github je zároveň poskytovatel hostingu pro Git a zároveň programátorská sociální síť. Jelikož nabízí hosting pro otevřené projekty zdarma, není lepšího místa, kde začít hrátky s Gitem.</p>
<h3>Checkout versus Clone</h3>
<p>Uživatelé Subversion jistě znají pojem checkout. U distribuovaných systémů má <em>checkout</em> trošku jiný význam a stažení repository ze serveru se nazývá <strong>clone</strong>. Pro moje testovací repository je <strong>clone</strong> úplně jednoduchý:</p>
<pre name="code" class="ruby">git clone git@github.com:honzasterba/gitest.git</pre>
<p>V případě, že sis zrovna vytvořil nové repository na Githubu toto ale fungovat nebude, protože je repository docela prázdné (není tam ani žádná větev) a je tedy třeba ho znicializovat.</p>
<pre name="code" class="ruby">cd gitest
git init # vytvoří prázdné lokální git repository
touch README
git add README # přidá lokální soubor do dalšího commitu
git commit -m 'first commit' # lokální commit souboru
git remote add origin git@github.com:honzasterba/gitest.git
git push origin master</pre>
<h3>Add, commit a push</h3>
<p>Poslední dva řádky víše jsem nechal bez komentáře záměrně, protože je třeba vysvětlit jednu základní odlišnost Gitu od například Subversion. <strong>Commit</strong> je lokální operace. Co to znamená? Jenom to, že když uděláš <strong>git commit</strong> tak se změny uloží jako revize do lokálního repository. K tomu, aby se změny dostaly na server, je třeba udělat <strong>push</strong>. V konečném důsledku to vypadá tak, že svoji práci můžeš postupně lokálně commitovat a následně udělat <strong>push</strong> a odeslat změny na server. Zjednodušený proces vypadá následovně:</p>
<ol>
<li>práce a změny v souborech</li>
<li><em>git add &lt;soubory které chci commitovat&gt;</em></li>
<li><em>git commit</em></li>
<li>návrat do bodu 1. nebo pokračování</li>
<li><em>git push origin master</em></li>
</ol>
<p>Celý <strong>push</strong> vypadá taky velmi komplikovaně, ale nic složitého na něm není. <em>Origin</em> je symbolické jméno, které jsme na začátku přiřadili našemu repository na serveru a může být ekvivalentně nahrazeno URL. <em>Master</em> je jméno větve do které se naše změny mají synchronizovat a jedná se taky o jmennou konvenci pro hlavní větev. Parametr s názvem větve je nepovinný (použije se aktuální větev), ale doporučovaný, aby se později předešlo omylům.</p>
<h3>Pull</h3>
<p>Opakem operace <strong>push</strong> je <strong>pull</strong>. <strong>Pull</strong> je dvoukroková operce, git nejdříve vytvoří lokální větev (branch) do které stáhne nové změny ze serveru a pak tuto větev (FETCH_HEAD) merguje do aktuální větve. Celý příkaz vypadá takto:</p>
<pre name="code" class="ruby">git pull origin master</pre>
<p>Opět je třeba předat název repository a větve. Oba parametry se dají vynechat pokud git nakonfiguruješ tak aby si <em>master</em> doplnil automaticky.</p>
<h3 name="code" class="ruby">Merge</h3>
<p>Každý kdo používal jakýkoli VCS systém zná nončí můru jménem merge. Drtivou většinu mergování zvádá git automaticky a děje se v podstatě kdesi za oponou. Co ale v případě, že od doby, kdy jsi udělal poslední pull, někdo jiný pushnul svoje změny a tobě teď push nefunguje? Celý pproblém je v tom, že před pushnutím je potřeba mít lokální repository akuální, což znamené udělat pull:</p>
<pre name="code" class="ruby">git pull origin master</pre>
<p>Občas ale dojde ke nofliktu dvou revizí. Někdo jiný pushne změny do douboru, který mám já u sebe lokálně změněný a je problém. V takovém případě se git pokusí udělat merge automaticky a když ani to neprojde tak je potřeba ho udělat ručně. Při konfliktu git nahlásí toto:</p>
<pre name="code" class="ruby">CONFLICT (content): Merge conflict in &lt;cesta k souboru&gt;
Automatic merge failed; fix conflicts and then commit the result.</pre>
<p>Soubor je nutné ručně upravit a výsledný merge pak commitnout:</p>
<pre name="code" class="ruby">git add &lt;cesta k souboru&gt;
git commit</pre>
<p>Při commitu pak git předvyplní <em>commit message</em> tak aby indikovala, že se něco mergovalo:</p>
<pre name="code" class="ruby">Merge branch 'master' of git@github.com:honzasterba/gitest</pre>
<p>Následně už nic nebrání tomu svoje změny včetně přimergovaných změn kolegů poslat na server.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/EN0aoUgTNvONyJeL_yM4WKD10lw/0/da"><img src="http://feedads.g.doubleclick.net/~a/EN0aoUgTNvONyJeL_yM4WKD10lw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/EN0aoUgTNvONyJeL_yM4WKD10lw/1/da"><img src="http://feedads.g.doubleclick.net/~a/EN0aoUgTNvONyJeL_yM4WKD10lw/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/DobryKod?a=Ax80HArR"><img src="http://feeds.feedburner.com/~f/DobryKod?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=RfDkTFGh"><img src="http://feeds.feedburner.com/~f/DobryKod?i=RfDkTFGh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=z9IaTqXT"><img src="http://feeds.feedburner.com/~f/DobryKod?i=z9IaTqXT" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/DobryKod?a=3F78z7JB"><img src="http://feeds.feedburner.com/~f/DobryKod?i=3F78z7JB" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DobryKod/~4/Aql-GCGzYt8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.dobrykod.com/archiv/zaciname-s-git/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.dobrykod.com/archiv/zaciname-s-git/</feedburner:origLink></item>
	</channel>
</rss>
