@@ -75,26 +75,28 @@ <h3>AngularJS</h3>
7575 < li class ='red '>
7676 Many concepts make training difficult
7777 < div class ='subtle '>
78- (scope inheritance, isolation, dependency injection, digest cycle...)
78+ (scope inheritance, isolation, dependency injection, dot rule, digest cycle...)
7979 </ div >
8080 </ li >
8181 < li class ='red '> Angular 1 is EOL, leaving us in an awkward situation.</ li >
8282 < li class ='red '> We don't know how we're going to build SPAs in 2016+.</ li >
8383 </ ul >
8484 </ section >
85+ < section >
86+ < div class ='s '>
87+ < pre > < code class ='javascript '> angular.module('app', []).directive('myPane', ['$http', function($http) {
 return {
 require: ['^^myTabs', 'ngModel'],
 restrict: 'AEC',
 transclude: true,
 scope: {
 title: '@',
 info: '='
 },
 link: function(scope, element, attrs, controllers) {
 ...
 },
 };
});

</ code > </ pre >
88+ </ div >
89+ </ section >
8590 < section >
8691 < h3 > Half-assed AngularJS</ h3 >
8792 < ul >
8893 < li > AMC frontend, REALCUBE</ li >
8994 < li >
90- Uses Angular directives to run JS on matching HTML elements
91- < div class ='subtle '>
92- (like an < code > $.unobtrusive</ code > replacement):
93- </ div >
95+ Uses Angular directives to run JS on matching HTML elements:
9496 < pre class ='xs '> < code class ='javascript ' data-noescape > app.directive('foo', function() {
 return {
 link: function(scope, $element) {
 // do something with an $element that has class "foo"
 };
 }
});
</ code > </ pre >
9597 </ li >
9698 < li >
97- Use local scopes to toggle UI states:
99+ Uses local scopes to toggle UI states:
98100 < pre class ='xs '> < code class ='html ' data-noescape > <div ng-init="more = false">
 <span ng-click="more = true">Show more</a>
 <div ng-if="more">More information</div>
</div>
</ code > </ pre >
99101 </ li >
100102 </ ul >
108110 Issues
109111 </ div >
110112 </ h3 >
111- < ul >
113+ < ul class =' red ' >
112114 < li > Crawlable content must always be rendered on the server,< br /> so we can't really use this for important state changes</ li >
113115 < li > No routing, so no real URLs for changed state</ li >
114116 < li > Compile time is an issue on large pages</ li >
@@ -125,7 +127,7 @@ <h3>Random.js</h3>
125127 < ul >
126128 < li > Copy & paste of untested (and flawed!) code snippets from cards and old projects</ li >
127129 < li > Anything non-trivial is implemented with a wall of jQuery</ li >
128- < li > Initialized randomly (on load, < code > $.unobtrusive</ code > , < code > <script></ code > tags...)</ li >
130+ < li > Initialized randomly (on load, < code > $.unobtrusive</ code > , < code > <script></ code > tags, by library internals ...)</ li >
129131 </ ul >
130132 </ li >
131133 < li class ='red '>
@@ -187,6 +189,9 @@ <h3>A shitty decision for our clients</h3>
187189 </ table >
188190 </ section >
189191 < section >
192+ < p >
193+ We just spent three years learning how Javascript works.
194+ </ p >
190195 < p >
191196 Can we bring learnings from AngularJS into the server-side paradigm?
192197 </ p >
230235 </ ol >
231236 </ section >
232237 < section >
238+ < h2 > Unpoly</ h2 >
233239 < table >
234240 < tr >
235241 < th > </ th >
@@ -325,14 +331,14 @@ <h2>
325331 </ section >
326332 < section >
327333 < p >
328- Gleicher serverseitiger Code :
334+ Same code on the server :
329335 </ p >
330336 < ul >
331337 < li >
332- < a href ='http://demo.upjs.io/sessions/CSARbQ/cards/6463?up_enabled=false '> ohne Unpoly</ a >
338+ < a href ='http://demo.upjs.io/sessions/CSARbQ/cards/6463?up_enabled=false '> No Unpoly</ a >
333339 </ li >
334340 < li >
335- < a href ='http://demo.upjs.io/sessions/CSARbQ/cards/6463?up_enabled=true '> mit Unpoly</ a >
341+ < a href ='http://demo.upjs.io/sessions/CSARbQ/cards/6463?up_enabled=true '> With Unpoly</ a >
336342 </ li >
337343 </ ul >
338344 </ section >
605611 </ ul >
606612 </ section >
607613 < section >
608- < h3 > Freeing our time budget</ h3 >
614+ < h3 > Freeing up time budget</ h3 >
609615 < div class ='s '>
610616 < ul >
611617 < li >
@@ -712,18 +718,18 @@ <h3>
712718 < div class ='line '> Invent your own UJS syntax</ div >
713719 </ h3 >
714720 < h4 class ='subtle '> HTML</ h4 >
715- < pre > < code class ='html ' data-noescape > <a class="menu-link" href="/details">Show more</span>
</ code > </ pre >
721+ < pre class =' l ' > < code class ='html ' data-noescape > <a class="menu-link" href="/details">Show more</span>
</ code > </ pre >
716722 < h4 class ='subtle '> Javascript</ h4 >
717- < pre > < code class ='javascript '> up.compiler('.menu-link', function($link) {
 up.popup.attach($link, {
 target: '.menu',
 position: 'bottom-left',
 animation: 'roll-down'
 });
});
</ code > </ pre >
723+ < pre class =' l ' > < code class ='javascript '> up.compiler('.menu-link', function($link) {
 $link.on('click', function(event) {
 event.preventDefault();
 up.popup.attach($link, {
 target: '.menu',
 position: 'bottom-left',
 animation: 'roll-down'
 }); 
 });
});
</ code > </ pre >
718724 </ section >
719725 < section >
720726 < h3 >
721- < div class ='line '> Invent your own UJS syntax</ div >
727+ < div class ='line '> Repurpose existing UJS syntax</ div >
722728 </ h3 >
723729 < h4 class ='subtle '> HTML</ h4 >
724- < pre > < code class ='html ' data-noescape > <a class="menu-link" href="/details">Show more</span>
</ code > </ pre >
730+ < pre class =' l ' > < code class ='html ' data-noescape > <a class="menu-link" href="/details">Show more</span>
</ code > </ pre >
725731 < h4 class ='subtle '> Javascript</ h4 >
726- < pre > < code class ='javascript '> up.macro('.menu-link', function($link) {
 $link.attr(
 'up-target': '.menu',
 'up-position': 'bottom-left',
 'up-animation': 'roll-down'
 });
});
</ code > </ pre >
732+ < pre class =' l ' > < code class ='javascript '> up.macro('.menu-link', function($link) {
 $link.attr(
 'up-target': '.menu',
 'up-position': 'bottom-left',
 'up-animation': 'roll-down'
 });
});
 
 
  ;
</ code > </ pre >
727733 </ section >
728734 < section >
729735 < h3 >
@@ -763,6 +769,20 @@ <h3>Bootstrap integration</h3>
763769 </ li >
764770 </ ul >
765771 </ section >
772+ < section >
773+ < h3 > Rails integration</ h3 >
774+ < p >
775+ Include < a href ="http://www.rubydoc.info/gems/unpoly-rails/ "> unpoly-rails</ a > In your < code > Gemfile</ code > :
776+ </ p >
777+ < pre class ='xs '> < code class ='ruby '> gem 'unpoly-rails'
</ code > </ pre >
778+ < p >
779+ In your controllers, views and helpers:
780+ </ p >
781+ < pre class ='xs '> < code class ='ruby '> up? # request.headers['X-Up-Target'].present?
up.target # request.headers['X-Up-Target']
up.title = 'Title from server' # response.headers['X-Up-Title'] = 'Title ...'
up.validate? # request.headers['X-Up-Validate'].present?
</ code > </ pre >
782+ < p >
783+ The gem also provides the JS and CSS assets for the latest Unpoly.
784+ </ p >
785+ </ section >
766786 < section >
767787 < h3 > Legacy browsers</ h3 >
768788 < p >
@@ -790,20 +810,6 @@ <h3>Legacy browsers</h3>
790810 </ tr >
791811 </ table >
792812 </ section >
793- < section >
794- < h3 > Rails integration</ h3 >
795- < p >
796- Include < a href ="http://www.rubydoc.info/gems/unpoly-rails/ "> unpoly-rails</ a > In your < code > Gemfile</ code > :
797- </ p >
798- < pre class ='xs '> < code class ='ruby '> gem 'unpoly-rails'
</ code > </ pre >
799- < p >
800- In your controllers, views and helpers:
801- </ p >
802- < pre class ='xs '> < code class ='ruby '> up? # request.headers['X-Up-Target'].present?
up.target # request.headers['X-Up-Target']
up.title = 'Title from server' # response.headers['X-Up-Title'] = 'Title ...'
up.validate? # request.headers['X-Up-Validate'].present?
</ code > </ pre >
803- < p >
804- The gem also provides the JS and CSS assets for the latest Unpoly.
805- </ p >
806- </ section >
807813 < section >
808814 < h2 > Forms</ h2 >
809815 < p >
@@ -857,8 +863,44 @@ <h3>Updating dependent fields</h3>
857863 < pre class ='xs '> < code class ='html ' data-noescape > <form action="/contracts">
 <select name="department" < mark > up-validate="[name=employee]"</ mark > >...</select>
 <select name="employee">...</select>
</form>
</ code > </ pre >
858864 </ section >
859865 < section >
860- < h3 > Keep elements</ h3 >
861- < pre > < code class ='html ' data-noescape > <div class="story">

 <video < mark > up-keep</ mark > src="movie.mp4"></video>

 <p>Story summary</p>

 <a href="full.html" up-target=".story">
 Read full story
 </a>

</div>
</ code > </ pre >
866+ < h3 > Persisting elements</ h3 >
867+ < pre class ='l '> < code class ='html ' data-noescape > <div class="story">

 <video < mark > up-keep</ mark > src="movie.mp4"></video>

 <p>Story summary</p>

 <a href="full.html" up-target=".story">
 Read full story
 </a>

</div>

</ code > </ pre >
868+ </ section >
869+ < section >
870+ < pre > < code class ='html ' data-noescape > <div class="map" up-data="[
 { lat: 48.36, lng: 10.99 },
 { lat: 48.75, lng: 11.45 }
]"></div>

<form method="post" action="/pins">
 Lat: <input name="lat">
 Lng: <input name="lng">
 <button>Add pin</button>
</form>
</ code > </ pre >
871+ < pre > < code class ='javascript ' data-noescape > up.compiler('.map', function($element, pins) {
 var map = new google.maps.Map($element);
 pins.forEach(function(pin) {
 var position = new google.maps.LatLng(pin.lat, pin.lng);
 new google.maps.Marker({
 position: position,
 map: map
 });
});
</ code > </ pre >
872+ </ section >
873+ < section >
874+ < pre > < code class ='html ' data-noescape > <div class="map" up-data="<%= @pins.to_json %>"></div>
 
 
 
 
 
 
 
 
 
</ code > </ pre >
875+ < pre > < code class ='javascript ' data-noescape > up.compiler('.map', function($element, pins) {
 var map = new google.maps.Map($element);
 pins.forEach(function(pin) {
 var position = new google.maps.LatLng(pin.lat, pin.lng);
 new google.maps.Marker({
 position: position,
 map: map
 });
});
</ code > </ pre >
876+ </ section >
877+ < section >
878+ < pre > < code class ='html ' data-noescape > <div class="map" up-data="<%= @pins.to_json %>"></div>

<%= form_for Pin.new do |form| %>
 Lat: <%= form.text_field :lat %>
 Lng: <%= form.text_field :lng %>
 <%= form.submit 'Add pin' %>
</form>
 
 
 
</ code > </ pre >
879+ < pre > < code class ='javascript ' data-noescape > up.compiler('.map', function($element, pins) {
 var map = new google.maps.Map($element);
 pins.forEach(function(pin) {
 var position = new google.maps.LatLng(pin.lat, pin.lng);
 new google.maps.Marker({
 position: position,
 map: map
 });
});
</ code > </ pre >
880+ </ section >
881+ < section >
882+ < pre > < code class ='html ' data-noescape > <div class="map" up-data="<%= @pins.to_json %>"></div>

<%= form_for Pin.new do |form| %>
 Lat: <%= form.text_field :lat %>
 Lng: <%= form.text_field :lng %>
 <%= form.submit 'Add pin' %>
</form>
 
 
 
</ code > </ pre >
883+ < pre > < code class ='javascript ' data-noescape > up.compiler('.map', function($element, initialPins) {
 var map = new google.maps.Map($element);
 function renderPins(pins) { ... }
 renderPins(initialPins);
});
 
 
 
 
</ code > </ pre >
884+ </ section >
885+ < section >
886+ < pre > < code class ='html ' data-noescape > <div class="map" up-data="<%= @pins.to_json %>" < mark > up-keep</ mark > ></div>

<%= form_for Pin.new do |form| %>
 Lat: <%= form.text_field :lat %>
 Lng: <%= form.text_field :lng %>
 <%= form.submit 'Add pin' %>
</form>
 
 
 
</ code > </ pre >
887+ < pre > < code class ='javascript ' data-noescape > up.compiler('.map', function($element, initialPins) {
 var map = new google.maps.Map($element);
 function renderPins(pins) { ... }
 renderPins(initialPins);
 < mark > $element.on('up:fragment:keep', function(event) {</ mark > 
 < mark > renderPins(event.newData); </ mark > 
 < mark > }); </ mark > 
});
 
</ code > </ pre >
888+ </ section >
889+ < section >
890+ < h3 > Find-as-you-type search</ h3 >
891+ < pre > < code class ='html ' data-noescape > <form action="/users" up-target=".list" < mark > up-observe="up.submit(this)"</ mark > >
 <input type="search" name="query" />
</form>

<div class="list">
 <% @users.each do |user| %>
 = link_to user.email, user
 <% end %>
</div>
</ code > </ pre >
892+ < p >
893+ < code > up-observe</ code > reacts faster than our vintage < code > observeField</ code > helper
894+ and has no concurrency issues.
895+ </ p >
896+ </ section >
897+ < section >
898+ < h3 > Find-as-you-type search</ h3 >
899+ < pre > < code class ='html ' data-noescape > <form action="/users" up-target=".list" < mark > up-autosubmit</ mark > >
 <input type="search" name="query" />
</form>

<div class="list">
 <% @users.each do |user| %>
 = link_to user.email, user
 <% end %>
</div>
</ code > </ pre >
900+ < p >
901+ < code > up-observe</ code > reacts faster than our vintage < code > observeField</ code > helper
902+ and has no concurrency issues.
903+ </ p >
862904 </ section >
863905 < section >
864906 < h3 > Getting started</ h3 >
@@ -905,19 +947,16 @@ <h3>Easier integration testing</h3>
905947 </ p >
906948 </ section >
907949 < section >
908- < h2 > Project state </ h2 >
950+ < h2 > Should I use this for my project? </ h2 >
909951 < ul >
910952 < li > In development since October 2014</ li >
911- < li > Has seen some real world pain</ li >
912953 < li > ~ 500 specs</ li >
954+ < li > Has seen some real world pain, but we're still learning new things</ li >
955+ < li > < a href ="http://unpoly.com/changelog "> Changelog</ a > lists breaking changes and compatible changes separately</ li >
913956 < li >
914- Release policy
915- < ul >
916- < li > < a href ="http://unpoly.com/changelog "> Changelog</ a > lists breaking changes and compatible changes separately</ li >
917- < li > < a href ="http://unpoly.com/search/ "> API</ a > marks features as either < i > stable</ i > or < i > experimental</ i > </ li >
918- < li > There will be breaking changes, but always a simple upgrade path</ li >
919- </ ul >
957+ < a href ="http://unpoly.com/search/ "> API</ a > marks features as either < i > stable</ i > or < i > experimental</ i > .
920958 </ li >
959+ < li > There will be breaking changes, but always a simple upgrade path</ li >
921960 </ ul >
922961 </ section >
923962 < section >
0 commit comments