some more work on web interface
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 3 Jan 2011 08:01:18 +0000 (08:01 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 3 Jan 2011 08:01:18 +0000 (08:01 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@704 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

15 files changed:
wob/classes/cart.wolf
wob/transact/cart.wolf
wob/transact/order.wolf
www/images/arrowdown.png [new file with mode: 0644]
www/inc/rendering/cart_listing.php
www/inc/wext/autoload.php
www/inc/wext/event.php
www/inc/wext/voucher.php
www/inc/wext/webcart.php
www/index.php
www/styles/style.css
www/template/en/cart.html
www/template/en/eventdetails.html
www/template/en/index.html
www/template/en/layout.html

index 25526c2..5b66c37 100644 (file)
@@ -49,6 +49,7 @@
        
        
        <Class name="CartVoucher">
+               <Abstract lang="php"/>
                <Doc>Encapsulates vouchers as they are stored in the cart. Used by the client to tell the server about new orders. Used by the Web UI to actually store its cart.</Doc>
                <Enum name="ValidationState">
                        <Value name="Ok">The voucher can be sold</Value>
index b30b7bd..6e394b9 100644 (file)
                <Call lang="php" method="WOWebCart::addTickets($this);"/>
                <Output/>
        </Transaction>
+       <Transaction name="WebCartRemoveTicket">
+               <Doc>Called from the Web UI only: removes tickets for a specific event from the cart</Doc>
+               <Input>
+                       <Var name="cartid" type="astring">The cart to add into</Var>
+                       <Var name="eventid" type="int">The event to buy tickets for</Var>
+                       <Var name="pricecategoryid" type="int">Price category of that event</Var>
+               </Input>
+               <Call lang="php" method="WOWebCart::removeTickets($this);"/>
+               <Output/>
+       </Transaction>
+       
+       <Transaction name="WebCartAddVoucher">
+               <Doc>Called from the Web UI only: adds vouchers</Doc>
+               <Input>
+                       <Var name="cartid" type="astring">The cart to add into</Var>
+                       <Var name="price" type="int">The price of the voucher</Var>
+               </Input>
+               <Call lang="php" method="WOWebCart::addVoucher($this);"/>
+               <Output/>
+       </Transaction>
+       <Transaction name="WebCartRemoveVoucher">
+               <Doc>Called from the Web UI only: removes vouchers</Doc>
+               <Input>
+                       <Var name="cartid" type="astring">The cart to add into</Var>
+                       <Var name="lineid" type="int">The voucher line to remove</Var>
+               </Input>
+               <Call lang="php" method="WOWebCart::removeVoucher($this);"/>
+               <Output/>
+       </Transaction>
 </Wolf>
\ No newline at end of file
index a820fb9..8387516 100644 (file)
        </Transaction>
        
        <Transaction name="GetValidVoucherPrices" updating="no">
-               <Call lang="php" method="$this->setprices(explode(' ',$GLOBALS['db']->getConfig('ValidVouchers')));"/>
+               <Call lang="php" method="$this->setprices(WOVoucher::validVoucherPrices());"/>
                <Output>
                        <Var name="prices" type="List:int"/>
                </Output>
        </Transaction>
        <Transaction name="GetEntranceEvents" updating="no">
                <Doc>This is a convenience transaction: it returns all events that are likely to be chosen at an entrance barcode scanner; this includes all events starting at max. within the next 24 hours that and that have not ended yet</Doc>
+               <Input>
+                       <Var name="maxbeforestart" type="int"/>
+                       <Var name="maxafterend" type="int"/>
+               </Input>
                <Call lang="php" method="WOEvent::getEntranceEvents($this);"/>
                <Output>
                        <Var name="events" type="List:Event"/>
diff --git a/www/images/arrowdown.png b/www/images/arrowdown.png
new file mode 100644 (file)
index 0000000..683c465
Binary files /dev/null and b/www/images/arrowdown.png differ
index 845bc8d..8bc9679 100644 (file)
@@ -16,7 +16,8 @@ const cartIdName = "smoke_cartid";
 const TicketAmountField = "amountTickets";
 
 /**called from index.php - add tickets to cart*/
-static public function addTickets(){
+static public function addTickets()
+{
        global $HTTPARGS;
        //get the cart
        $cartid=self::getOrCreateCart();
@@ -42,6 +43,50 @@ static public function addTickets(){
        redirectHome(array("mode"=>"cart","cartid"=>$cartid));
 }
 
+///called from index.php - adds a voucher to the cart
+static public function addVoucher()
+{
+       global $HTTPARGS,$basevars;
+       //get the cart
+       $cartid=self::getOrCreateCart();
+       //find event
+       echo "checking";
+       $vi=$basevars['inputnames']['voucher'];
+       if(!isset($HTTPARGS[$vi])){
+               redirectHome();
+               return;
+       }
+       //price
+       $prc=$HTTPARGS[$vi];
+       //add
+       echo "adding";
+       WTrWebCartAddVoucher::execute($cartid,$prc);
+       //go to the cart
+       redirectHome(array("mode"=>"cart","cartid"=>$cartid));
+}
+
+/**called from index.php - removes tickets/vouchers from cart*/
+static public function removeItem()
+{
+       global $HTTPARGS,$basevars;
+       $cartid=self::getOrCreateCart();
+       //find event
+       $ti=$basevars["inputnames"]["ticket"];
+       if(isset($HTTPARGS[$ti])){
+               $evid=WOEventPrice::getEventIdFromAmountIndex($HTTPARGS[$ti]);
+               $pcid=WOEventPrice::getCategoryIdFromAmountIndex($HTTPARGS[$ti]);
+               //remove
+               WTrWebCartRemoveTicket::execute($cartid,$evid,$pcid);
+       }
+       $vi=$basevars['inputnames']['voucher'];
+       if(isset($HTTPARGS[$vi])){
+               $vid=$HTTPARGS[$vi]+0;
+               //find and remove voucher
+               WTrWebCartRemoveVoucher::execute($cartid,$vid);
+       }
+       redirectHome(array("mode"=>"cart","cartid"=>$cartid));
+}
+
 /**returns the current cart ID, or an empty string if there is no cart, automatically updates its timeout*/
 static public function getCart(){
        global $CartTimeout;
@@ -133,6 +178,22 @@ The cart.html template is used to render the current cart of the customer.
 \param shipping and array of web objects of type <a href="../wob/class-Shipping.html">Shipping</a> (PHP: WOShipping) which represent all available shipping types that customers can chose from.
 \param forceshipping a boolean that contains whether customers must chose a shipping type.
 
+\subsection tpl_cartext Cart Extensions
+
+Some of the sub-objects of cart have extended attributes in addition to those generated by Wob:
+
+\param cart.isempty true if the cart is empty
+\param cart.totalsum the complete sum of all prices in the cart
+\param cart.tickets[...].eventprice.*:
+\param *.amountInputField name of the input field of a form that should contain the amount of tickets for ordering, see the example on how to use it
+\param *.categoryIdWeb part of the URL query that represents this category, used for removing tickets from the cart, see the example on how to use it
+
+\section tpl_voucher Voucher Variables
+
+The voucher.html template is used to render the voucher selection form.
+
+\param voucherprices contains an array of valid voucher prices.
+
 \section tpl_carterror Cart Error Variables
 
 The carterror.html template is used to when the cart expired or the customers browser lost the cookie.
@@ -181,6 +242,52 @@ static public function createCartOverview()
        return $p->render($list);
 }
 
+/** creates an overview of known good voucher types
+
+for templating info see \ref tpl_voucher Voucher Variables
+and \ref tpl_base Base Variables
+*/
+static public function createVoucherOverview()
+{
+       global $twig,$basevars;
+       //get voucher values
+       $list=$basevars;
+       $list['voucherprices']=WTrGetValidVoucherPrices::execute()->resultprices();
+       //display
+       $p=$twig->loadTemplate("vouchers.html");
+       return $p->render($list);
+}
+
+/** creates an overview of known good voucher types
+
+For templating info see \ref tpl_cart Cart Variables
+and \ref tpl_base Base Variables
+, however only the 'cart' variable itself is available from the Cart Variables.
+*/
+static public function orderLoginPage()
+{
+       global $twig,$basevars;
+       //get cart id and check it
+       $cartid=self::getCart();
+       if($cartid==""){
+               $p=$twig->loadTemplate("carterror.html");
+               return $p->render($basevars);
+       }
+       
+       //cart is ok, now get the object
+       $cart = WOWebCart::fromTablecart(WTcart::getFromDB($cartid));
+       if(!is_a($cart,"WOWebCart")){
+               //ooops. internal problem
+               $p=$twig->loadTemplate("carterror.html");
+               return $p->render($basevars);
+       }
+       $list=$basevars;
+       $list["cart"]=$cart;
+       //display
+       $p=$twig->loadTemplate("orderlogin.html");
+       return $p->render($list);
+}
+
 //end of WebCart
 };
 
index 121c7f1..1e010f2 100644 (file)
@@ -21,6 +21,7 @@ wob_autoclass("WOTemplate","inc/wext/template.php");
 wob_autoclass("WOTicket","inc/wext/ticket.php");
 wob_autoclass("WOVoucher","inc/wext/voucher.php");
 wob_autoclass("WOWebCart","inc/wext/webcart.php");
+wob_autoclass("WOCartVoucher","inc/wext/webcart.php");
 
 wob_autoclass("MSmokeTransaction","inc/wext/transaction.php");
 ?>
\ No newline at end of file
index 5a3b227..87799b9 100644 (file)
@@ -33,6 +33,13 @@ class WOEventPrice extends WOEventPriceAbstract
                return WebCart::TicketAmountField."[".$this->prop_pricecategoryid.":".$this->prop_eventid."]";
        }
        
+       /**helper for web UI: returns the value for HTML variables for this event price: an index indicating category and event IDs*/
+       public function getCategoryIdWeb()
+       {
+               global $basevars;
+               return $basevars["inputnames"]["ticket"]."=".$this->prop_pricecategoryid.":".$this->prop_eventid;
+       }
+       
        /**helper function for web UI: returns the event ID from an amount field index */
        static public function getEventIdFromAmountIndex($idx)
        {
@@ -240,8 +247,12 @@ class WOEvent extends WOEventAbstract
        /**called by the GetEntranceEvents transaction*/
        public static function getEntranceEvents($trans)
        {
-               $start=time()+(24*3600); //is running or starts within 24h
-               $end=time(); //has not ended yet
+               $ms=$trans->getmaxbeforestart();
+               if($ms===null || $ms<10000)$ms=24*3600;
+               $start=time()+$ms; //is running or starts within 24h
+               $ms=$trans->getmaxafterend();
+               if($ms===null || $ms<0)$ms=0;
+               $end=time()-$ms; //has not ended yet
                global $db;
                $trans->setevents(WOEvent::fromTableArrayevent(WTevent::selectFromDB("starttime<=".$db->escapeInt($start)." AND endtime>=".$db->escapeInt($end))));
        }
index da56d6f..4e189f8 100644 (file)
@@ -6,6 +6,7 @@
 
 class WOVoucher extends WOVoucherAbstract
 {
+       ///helper for audit table creation
        public static function getTransactionComment()
        {
                $inst=WobTransaction::getInstance();
@@ -15,6 +16,7 @@ class WOVoucher extends WOVoucherAbstract
                else return null;
        }
        
+       ///implements the GetVoucherAudit transaction
        public static function GetVoucherAuditTransaction($trans)
        {
                global $db;
@@ -22,6 +24,13 @@ class WOVoucher extends WOVoucherAbstract
                $arr=WOVoucherAudit::fromTableArrayvoucher_audit($tab);
                $trans->setvoucher($arr);
        }
+       
+       ///returns all valid voucher prices
+       static public function validVoucherPrices()
+       {
+               global $db;
+               return explode(' ',$db->getConfig('ValidVouchers'));
+       }
 };
 
 ?>
\ No newline at end of file
index 28dcc03..7850ed9 100644 (file)
@@ -48,9 +48,11 @@ class WOWebCart extends WOWebCartAbstract
                if(!is_a($event,"WTevent"))return;
                //ignore non-buy
                if($amount<1)return;
-               //find category, match with event
+               //find category, match with event, check for usability
                $pc=WTeventprice::getFromDB($evid,$pcid);
                if(!is_a($pc,"WTeventprice"))return;
+               $pco=WOEventPrice::fromTableeventprice($pc);
+               if(!$pco->getCanUse())return;
                //find whether cart contains this
                $itm=WTcartticket::getFromDB($cartid,$evid,$pcid);
                if(is_a($itm,"WTcartticket")){
@@ -70,6 +72,68 @@ class WOWebCart extends WOWebCartAbstract
                }
 //             die ("hallo");
        }
+
+       /**transaction to remove tickets from cart*/
+       static public function removeTickets($trans)
+       {
+               $cartid=$trans->getcartid();
+               $evid=$trans->geteventid();
+               $pcid=$trans->getpricecategoryid();
+               //get cart
+               $cart=WOWebCart::fromTablecart(WTcart::getFromDB($cartid));
+               if(!is_a($cart,"WOWebCart"))return;
+               //find whether cart contains this
+               $itm=WTcartticket::getFromDB($cartid,$evid,$pcid);
+               if(is_a($itm,"WTcartticket")){
+                       //yes: remove it
+//                     echo "add".$amount;
+                       $itm->deleteFromDb();
+               }
+       }
+       
+       ///transaction to add vouchers
+       static public function addVoucher($trans)
+       {
+               $cartid=$trans->getcartid();
+               $prc=$trans->getprice();
+               //get cart
+               $cart=WOWebCart::fromTablecart(WTcart::getFromDB($cartid));
+               if(!is_a($cart,"WOWebCart"))return;
+               //get valid prices
+               if(!in_array($prc,WOVoucher::validVoucherPrices()))return;
+               //add voucher
+               $cv=WTcartvoucher::newRow();
+               $cv->cartid=$cartid;
+               $cv->value=$prc;
+               $cv->insert();
+       }
+       
+       ///transaction to remove vouchers
+       static public function removeVoucher($trans)
+       {
+               $cartid=$trans->getcartid();
+               $lineid=$trans->getlineid();
+               //get cart
+               $cart=WOWebCart::fromTablecart(WTcart::getFromDB($cartid));
+               if(!is_a($cart,"WOWebCart"))return;
+               //get voucher
+               $cv=WTcartvoucher::getFromDB($lineid);
+               //checks
+               if(!is_a($cv,"WTcartvoucher"))return;
+               if($cv->cartid!=$cartid)return;
+               //delete
+               $cv->deleteFromDb();
+       }
+};
+
+class WOCartVoucher extends WOCartVoucherAbstract
+{
+       ///used for web: returns the URL part of this voucher for removal
+       public function getInCartIdWeb()
+       {
+               global $basevars;
+               return $basevars['inputnames']['voucher'].'='.$this->getcartlineid();
+       }
 };
 
 ?>
\ No newline at end of file
index 1e1d554..d6dde21 100644 (file)
@@ -51,7 +51,11 @@ There are some variables available for all templates.<p>
 <tr><td><tt>script.this</tt></td><td>the URL of the currently called script mode</td></tr>
 <tr><td><tt>script.index</tt></td><td>URL of the list index</td></tr>
 <tr><td><tt>script.eventDetails</tt></td><td>URL for event detail pages, append the event ID to it to complete it</td></tr>
-<tr><td><tt>script.eventOrder</tt></td><td>URL for ordering tickets for a specific event, arguments are expected as POST parameters</td></tr>
+<tr><td><tt>script.eventOrder</tt></td><td>URL for ordering tickets for a specific event, arguments are expected as POST or GET parameters</td></tr>
+<tr><td><tt>script.vouchers</tt></td><td>URL for listing vouchers</td></tr>
+<tr><td><tt>script.voucherOrder</tt></td><td>URL for ordering vouchers, arguments are expected as POST or GET parameters</td></tr>
+<tr><td><tt>script.removeItem</tt></td><td>URL for removing tickets/vouchers/items from the cart, arguments are expected as POST or GET parameters</td></tr>
+<tr><td><tt>script.shop</tt></td><td>URL for listing shop items</td></tr>
 <tr><td><tt>script.cart</tt></td><td>URL of the cart, the cart must exist when calling it, otherwise a cookie error will be displayed</td></tr>
 <tr><td><tt>script.mycart</tt></td><td>URL of the cart that transparently creates the cart if it does not exist yet</td></tr>
 <tr><td><tt>script.checkout</tt></td><td>URL to check out the cart</td></tr>
@@ -83,11 +87,16 @@ $basevars['script']['this']=$_SERVER['REQUEST_URI'];
 $basevars['script']['index']=$_SERVER['SCRIPT_NAME']."?mode=index";
 $basevars['script']['eventDetails']=$_SERVER['SCRIPT_NAME']."?mode=eventDetails&event=";
 $basevars['script']['eventOrder']=$_SERVER['SCRIPT_NAME']."?mode=eventOrder";
+$basevars['script']['vouchers']=$_SERVER['SCRIPT_NAME']."?mode=vouchers";
+$basevars['script']['voucherOrder']=$_SERVER['SCRIPT_NAME']."?mode=voucherOrder";
+$basevars['script']['shop']=$_SERVER['SCRIPT_NAME']."?mode=shop";
 $basevars['script']['cart']=$_SERVER['SCRIPT_NAME']."?mode=cart";
 $basevars['script']['mycart']=$_SERVER['SCRIPT_NAME']."?mode=mycart";
 $basevars['script']['checkout']=$_SERVER['SCRIPT_NAME']."?mode=checkout";
-//$basevars['script']['orderLogin']=$_SERVER['SCRIPT_NAME']."?mode=orderLogin";
-//$basevars['script']['customerRegistration']=$_SERVER['SCRIPT_NAME']."?mode=customerRegistration";
+$basevars['script']['removeItem']=$_SERVER['SCRIPT_NAME']."?mode=removeItem";
+$basevars['script']['orderLogin']=$_SERVER['SCRIPT_NAME']."?mode=orderLogin";
+$basevars['script']['customerLogin']=$_SERVER['SCRIPT_NAME']."?mode=customerLogin";
+$basevars['script']['customerRegistration']=$_SERVER['SCRIPT_NAME']."?mode=customerRegistration";
 //$basevars['script']['orderOverview']=$_SERVER['SCRIPT_NAME']."?mode=orderOverview";
 //$basevars['script']['editShippingAddress']=$_SERVER['SCRIPT_NAME']."?mode=editShippingAddress";
 //$basevars['script']['editOrderComments']=$_SERVER['SCRIPT_NAME']."?mode=editOrderComments";
@@ -95,7 +104,15 @@ $basevars['script']['setlanguage']=$_SERVER['SCRIPT_NAME']."?mode=setlanguage&la
 // form elements
 $basevars['inputnames']['amountTickets']="amountTickets";
 $basevars['inputnames']['event']="event";
+$basevars['inputnames']['ticket']="event";
+$basevars['inputnames']['voucher']="voucher";
 $basevars['inputnames']['mode']="mode";
+$basevars['inputnames']['login']['name']='customer_mail';
+$basevars['inputnames']['login']['passwd']='customer_passwd';
+$basevars['inputnames']['login']['passwdrepeat']='customer_passwd2';
+$basevars['inputnames']['login']['name']='customer_name';
+$basevars['inputnames']['login']['firstname']='customer_firstname';
+$basevars['inputnames']['login']['title']='customer_title';
 $basevars['inputnames']['cartid']=WebCart::cartIdName;
 $basevars['cartcookie']=WebCart::cartIdName;
 // other info
@@ -120,15 +137,32 @@ try{
                case "cart":
                        $page=WebCart::createCartOverview();
                        break;
-/*             case "orderLogin":
-                       checkOrderLogin();
-                       createOrderLogin();
+               case "removeItem":
+                       WebCart::removeItem();
+                       break;
+               case "vouchers":
+                       $page=WebCart::createVoucherOverview();
+                       break;
+               case "voucherOrder":
+                       WebCart::addVoucher();
+                       break;
+               case "shop":
+                       //TODO: implement
+                       redirectHome();
+                       break;
+               case "checkout":
+                       $page=WebCart::checkout();
+                       break;
+               case "orderLogin":
+                       $page=WebCart::orderLoginPage();
+                       break;
+               case "customerLogin":
+                       WebCart::checkOrderLogin();
                        break;
                case "customerRegistration":
-                       registerUser();
-                       createCustomerRegistration();
+                       WebCart::registerUser();
                        break;
-               case "orderOverview":
+/*             case "orderOverview":
                        orderTickets();
                        createOrderOverview();
                        break;
index 851ddc6..43eaec8 100644 (file)
 \r
 .ms_ButtonArea         {margin-top: 10px}\r
 \r
-.ms_ErrorArea          {color: red; margin-top: 10px;}
\ No newline at end of file
+.ms_ErrorArea          {color: red; margin-top: 10px;}\r
+\r
+div.titlediv {\r
+ display: none;\r
+ position: relative;\r
+ top: 100%;\r
+ left: 0;\r
+ z-index: 5;\r
+ /* width: 100%; */\r
+ background-color: #ccc;\r
+ border:1px solid #888;\r
+ float: none;\r
+}\r
index 1ee15f7..ed81349 100644 (file)
   {# go through tickets and render them #}
   {% for ticket in cart.tickets %}
     {% set pricesum=ticket.price * ticket.amount %}
-    <tr><td>Ticket: {{ticket.event.title}}</td>
+    <tr>
+    <td>Ticket: {{ticket.event.title}}</td>
     <td align="right">{{ticket.price|asMoney}}</td>
     <td align="right">{{ticket.amount}}</td>
-    <td align="right">{{pricesum|asMoney}}</td></tr>
+    <td align="right">{{pricesum|asMoney}}</td>
+    <td>
+     <a href="{{script.removeItem}}&{{ticket.eventprice.categoryidweb}}">remove</a>
+    </td>
+    </tr>
   {% endfor %}
   
   {# now go through vouchers #}
   {% for voucher in cart.vouchers %}
-  <tr><td>Voucher</td><td align="right">{{voucher.value}}</td><td align="right">1</td><td align="right">{{voucher.value}}</td></tr>
+  <tr>
+  <td>Voucher</td>
+  <td align="right">{{voucher.value|asMoney}}</td>
+  <td align="right">1</td>
+  <td align="right">{{voucher.value|asMoney}}</td>
+  <td><a href="{{script.removeItem}}&{{voucher.incartidweb}}">remove</a></td>
+  </tr>
   {% endfor %}
   
   {# TODO: go through product items #}
index 0d5a6bd..b0dfcc6 100644 (file)
@@ -12,8 +12,8 @@
   Artist: {{event.artist.name|e}}<br/>
   {{event.description}}<br/>
   
-  {# start the form that allows users to order for an event, the |safe filter tells the Twig parser that the URL should not be mangled #}
-  <form action="{{script.eventOrder|safe}}" method="POST">
+  {# start the form that allows users to order for an event, the |raw filter tells the Twig parser that the URL should not be mangled #}
+  <form action="{{script.eventOrder|raw}}" method="POST">
    <table>
    {# listing pricing options... #}
    <tr><td>Price:</td><td>Amount:</td></tr>
index 4ab49e5..1b32945 100644 (file)
       {% set olddate = newdate %}
       
       {# show basic data about the event #}
-      <h2>{{event.name}}</h2>
+      <h2>{{event.title}}</h2>
       {{event.start|asDateTime}}, {{event.room}}<br/>
       Artist: {{event.artist.name}}<br/>
+      {# uncomment to show the full description
       {{event.description}}<br/>
+      #}
       
       {# show pricing options #}
       Price: 
       {% for price in event.price %}
+       {% if price.canuse %}
         {% if loop.index > 1 %},{% endif %}
         {{price.price|asMoney}} ({{price.pricecategory.name}})
+       {% endif %}
       {% endfor %}<br/>
       
       {# is it sold out? #}
index bd38368..88693c9 100644 (file)
@@ -8,12 +8,14 @@
 <body>
 <!-- Begin Menu -->
 <p align="right">
-<a href="{{script.root}}">Ticket Shop</a> |
-<a href="{{script.mycart}}">My Shoping Cart</a>
+<a href="{{script.root|raw}}">Ticket Shop</a> |
+<a href="{{script.vouchers|raw}}">Voucher Shop</a> |
+<a href="{{script.shop|raw}}">Merchandising</a> |
+<a href="{{script.mycart|raw}}">My Shoping Cart</a>
 {% if lang.languages|length > 1 %}
 | Language:
 {% for lng in lang.languages %}
- <a href="{{script.setlanguage}}{{lng}}"><img src="images/{{lng}}.png" alt="{{lng}}"/></a>
+ <a href="{{script.setlanguage|raw}}{{lng|raw}}"><img src="images/{{lng|raw}}.png" alt="{{lng}}"/></a>
 {% endfor %}
 {% endif %}
 </p>
@@ -35,9 +37,7 @@ You can get the sources of MagicSmoke via Subversion:<br/>
 <!-- end of lines that must be preserved -->
 
 <p><b>Note to admins of MagicSmoke based Web-Sites:</b><br/>
-Some lines like the ones above must be visible in any web-page that is rendered by MagicSmoke or
-your modifications of it. If you modify MagicSmoke you must give the users the possibility to download
-your modifications (as well).<br/>
+Some lines like the ones above must be visible in any web-page that is rendered by MagicSmoke or your modifications of it. MagicSmoke's web interface is under the AGPL, which demands that you give users the ability to download the sources. If you modify MagicSmoke you must give the users the possibility to download your modifications (as well).<br/>
 See COPYING.AGPL for details.</p>
 
 </body>