Adding custom page and list it in the NavMenu

A place for users and developers of the Xataface to discuss and receive support.

Adding custom page and list it in the NavMenu

Postby SilverCorvus » Mon Feb 07, 2011 8:03 pm

At first I want to say, that Xataface is a great framework. 4 lines of php-code and listing the tables in the conf.ini file and the back-end is finished. Also the configuring is nice, to rename the labels ect.
It would be nice, if it somehow could inherit the relationships of the database to the config, but this is a nice-to-have (but a very nice one ^^).

------- My approach and stuff I found out -------

I'm writing this in that form, so you can follow the thoughts of a newbie in Xataface. Maybe it helps to develop or enhance tutorials for Xataface users.

After playing a bit with Xataface and its instantly generated back-end I thought, "Ok, back-end: nice, but how to make the front-end for the user?"
It started with the small question how to add a new page, with no direct link to a table. That's because I need very customized composition of various data of the DB.
One short attempt was to create a table in the conf.ini file and somehow to override the functionality by a delegate class, to create a very own content. But it failed because of the Xataface structure, because somewhere deep within it wants to query the table which doesn't exist ...

One way is using actions. I added an action and it worked, but there was no button to this site/this action. And because it's an "stand-alone" action - unlike edit, list or delete - it must be at the level of the Navigation Menu. I found the solution using the Dataface_Application_Menu.html to create a custom menu. But I don't like it, because it's separated from the NavMenu and has by default no style. Furthermore I want to use my custom pages in combination with the NavMenu, so they have to be together.

So the search for adding elements to the NavMenu began. Somewhere I read to add a action to the NavMenu you have to override the Dataface_NavMenu.html template. But I thought "Smarty templates? Then I must find the place where the vars/context are assigned to the template and found NavMenu.php. I tried to add values to $_tables, but nothing changed. I added an echo to look if it is even called, but nothing was shown. I placed an exit on the beginning of each function and the NavMenu was still showed. I deleted the half of the file so it should produce an error, but it didn't happen.
I even called the Dataface_NavMenu.html template directly with df_display() in my action, with the array("asdf" => "asdf", "fdsa" => "fdsa") as context and still the normal NavMenu with all tables showed up.
Very strange ...

So I traced the df_display() over the dataface-public-api.php to the function display() in SkinTool.php. I wanted to know what there the $context really contains and printed it. But there wasn't the tables listed ... But I saw also the $ENV in the file which fits the {foreach from=$ENV.APPLICATION._tables item=label key=table} stuff. So I printed $this->ENV and there were the tables listed, along with tons of other stuff. ^^
I added a value to $this->ENV['APPLICATION']['_tables'] and jackpot! The NavMenu had one entry more.

But how to add my action now? In the SkinTool.php for sure not. Then a brilliant idea came up - write it in the config file! It will be sure read into the $ENV stuff, I thought.

Code: Select all
[_actions_add_to_navmenu]
actionname = "Shown Name in the NavMenu"

After checking, I was right. So I can access it in the Template, only with a new entry in the config file.

I copied the foreach loop and modified it and it worked, but there was one little problem:
The first table was always marked as selected, because of the default table setting. So I had to change the if-part
{if $ENV.table==$table}class="selected"{/if}>

Oh, while writing this I found a better (and cleaner) method to solve this. :D

Code: Select all
pseudo code:
{action_selected = false} -- in smarty assign new var
foreach(_actions_add_to_navmenu )
{if $ENV.action == run_action} class="selected" {action_selected = true} {/if} -- if action in the ENV (= current action) == current shown action -> show as selected and save it to the var

{if !$action_selected && $ENV.table == $table} -- when action is shown selected, don't show any table as selected

Hurray, it works!
Drawbacks:
-- The actions are always listed before the tables.
-- The automatism when the horizontal menu is shown is only affected by the count of the tables, but via [_prefs] horizontal_tables_menu = 0 or 1 this shouldn't be a too big problem.

Code: Select all
see Application.php line 364:
if ( count($this->_tables) <= 10 ){
   $this->prefs['horizontal_tables_menu'] = 1;
}


What do you think about my solution? Is it clean enough? Could I improve some parts?


------- Installing Instructions -------

Put the modified Dataface_NavMenu.html Template into yourapplicationpath/templates (see the whole file at the end of this post)
That overrides the template of Xataface.

Add to conf.ini
Code: Select all
[_actions_add_to_navmenu]
actionname1 = "Shown Name1 in the NavMenu"
actionname2 = "Shown Name2 in the NavMenu"


------- Dataface_NavMenu.html - the whole file -------

Code: Select all
{*-------------------------------------------------------------------------------
* Dataface Web Application Framework
* Copyright (C) 2005-2006  Steve Hannah (shannah@sfu.ca)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
* Modified by SilverCorvus 2011
* Description of the modification:
* You can add actions like the tables in the conf.ini to the
* new section [_actions_add_to_navmenu] and those actions will be listed in this
* NavMenu before the tables.
*-------------------------------------------------------------------------------
*}
{if $ENV.prefs.horizontal_tables_menu}

<ul id="table_selection_tabs">
   {assign var=action_selected value=false}
   {block name="tables_menu_head"}
   {define_slot name="tables_menu_options"}
   
   {foreach from=$ENV.APPLICATION._actions_add_to_navmenu item=label key=action}
   <li {if $ENV.action==$action}{assign var=action_selected value=true}class="selected"{/if}><a href="{$ENV.DATAFACE_SITE_HREF}?-action={$action}"
                           accesskey="accesskeys-navigation"
                           class="action-selection-tab {if $ENV.action==$action}selected{/if}"
                           title="{$label}"
                           id="TableLink_{$action}">
                           
                           
                                  {$label}
                           
                        </a></li>
   {/foreach}
   
   {foreach from=$ENV.APPLICATION._tables item=label key=table}
   <li {if !$action_selected && $ENV.table == $table}class="selected"{/if}><a href="{$ENV.DATAFACE_SITE_HREF}?-table={$table}"
                           accesskey="accesskeys-navigation"
                           class="table-selection-tab {if !$action_selected && $ENV.table == $table}selected{/if}"
                           title="{$label}"
                           id="TableLink_{$table}">
                           
                           
                                  {$label}
                           
                        </a></li>
   {/foreach}
   
   {/define_slot}
   {block name="tables_menu_tail"}
</ul>

{else}
<div class="portlet" id="portlet-navigation-tree">
    <div>
        <h5>Navigation</h5>
        <div class="portletBody">
      {assign var=action_selected value=false}
        {block name="tables_menu_head"}
      {foreach from=$ENV.APPLICATION._actions_add_to_navmenu item=label key=action}
       
           {define_slot name="tables_menu_options"}
            <div class="portletContent">
             <a href="{$ENV.DATAFACE_SITE_HREF}?-action={$action}"
                           accesskey="accesskeys-navigation"
                           class="navItem {if $ENV.action==$action}{assign var=action_selected value=true}currentNavItem{/if}"
                           title="{$label}"
                           id="ActionLink_{$action}">
                            <img
    src="{$ENV.DATAFACE_URL}/images/folder_icon.gif" alt="" class="navIconRoot" title="Plone Site" />
                            <span class="navItemText">
                                  {$label}
                            </span>
                        </a>
           </div>
           {/define_slot}
       {/foreach}
      
        {foreach from=$ENV.APPLICATION._tables item=label key=table}
       
           {define_slot name="tables_menu_options"}
            <div class="portletContent">
             <a href="{$ENV.DATAFACE_SITE_HREF}?-table={$table}"
                           accesskey="accesskeys-navigation"
                           class="navItem {if !$action_selected && $ENV.table == $table}currentNavItem{/if}"
                           title="{$label}"
                           id="TableLink_{$table}">
                            <img
    src="{$ENV.DATAFACE_URL}/images/folder_icon.gif" alt="" class="navIconRoot" title="Plone Site" />
                            <span class="navItemText">
                                  {$label}
                            </span>
                        </a>
           </div>
           {/define_slot}
       {/foreach}
       {block name="tables_menu_tail"}
       </div>
   </div>
</div>
{/if}


PS: Please excuse me if there are grammar failures or strange expressions, but English isn't my mother tongue. ^^
SilverCorvus
 
Posts: 8
Joined: Mon Feb 07, 2011 5:07 pm
Location: Europe

Re: Adding custom page and list it in the NavMenu

Postby shannah » Mon Feb 07, 2011 11:05 pm

This looks like a fine solution to the problem at hand. The solution that I often use for this problem is no better than yours but I'll post it here in case it offers insight. I often use the tables_menu_head and tables_menu_tail blocks to add HTML content directly to the beginning or end of the tables menu. Or the tables_menu_options to completely override the menu... or a combination of both.

Here is a snippet from the ApplicationDelegate class from one of my xataface applications:
Code: Select all
function block__tables_menu_head(){
      $app =& Dataface_Application::getInstance();
      $q =& $app->getQuery();
      if ( getUser() ){
         $actions = array(
            array(
               'dashboard',
               '-table=dashboard&-action=view',
               df_translate('Dashboard', "Dashboard")),
            array(
               'webpage_sites',
               "-table=webpage_sites&-action=list&site_id=".(getSiteRoles()?implode('+OR+',array_keys(getSiteRoles())):'='),
               df_translate('tables.webpage_sites.label', "Websites")),
            array(
               'webpage_status',
               "-table=webpage_status&-action=list&site_id=".(getSiteRoles()?implode('+OR+',array_keys(getSiteRoles())):'='),
               df_translate('tables.webpage_status.label', "Webpages")),
            array(
               'proof_jobs',
               "-table=proof_jobs&-action=list&posted_by=".urlencode(getUsername()),
               df_translate('tables.proof_jobs.label', "Jobs")));
               
         $aff = df_get_record('affiliate_accounts', array('user_id'=>getUser()->val('user_id')));
         if ( $aff ){
            $actions[] = array(
               'affiliate_accounts',
               '-table=affiliate_accounts&-action=view&user_id='.getUser()->val("user_id"),
               df_translate('affiliate account', "Affiliate Account"));
            
         }
         
         $aff = df_get_record('translator_accounts', array('user_id'=>getUser()->val('user_id')));
         if ( $aff ){
            $actions[] = array(
               'translator_accounts',
               '-table=translator_accounts&-action=view&user_id='.getUser()->val("user_id"),
               df_translate('translator account', "Translator Account"));
            
         }
      } else {
      
         $actions = array(
            array(
               'home',
               '-action=home',
               df_translate('Home','Home')
            )
         );
      }

      foreach($actions as $action){
         list($table, $params, $label) = $action;
         echo "<li".(($q['-table'] == $table) ? ' class="selected" ':'')."><a href='".DATAFACE_SITE_HREF."?${params}'>${label}</a></li>";
      }
         
      //if ( isClient() ){
      //   echo '<li '.(($q['-table'] == 'webpage_sites' and $q['-action'] == 'list')?' class="selected" ':'').' ><a href="'.DATAFACE_SITE_HREF.'?-action=list&-table=webpage_sites&owner='.urlencode('='.getUser()->val('username')).'">My Websites</a></li>';
      //}   
   }
   
   function block__tables_menu_options(){
      if ( isAdmin() ){
         return PEAR::raiseError("Not handled", DATAFACE_E_REQUEST_NOT_HANDLED);
      }
   }


This snippet makes use of 2 functions getUser() and isAdmin() that are not part of Xataface but were defined for that application (and do exactly what it sounds like they do). What this snippet does:

1. The block__tables_menu_options method outputs nothing (blank), which effectively hides the tables menu options from showing up at all. The only exception to this is for administrators. In which case a DATAFACE_E_REQUEST_NOT_HANDLED error is returned to tell xataface that this method decided not to override the content (so it should operate as though that method was never implemented).

2. The block__tables_menu_head adds some extra options to the beginning of the tables menu for any logged in users.


I'm sure you can see how your strategy could be used to improve upon this solution and make it more parametrized.


--

The ideal solution would be to incorporate this menu into the Action tool like all of the other tab and action sets are. That way it would allow you to add an action to the tables menu by simply setting it to a particular category. That will be added to a future version, but it's not really high priority right now. In the mean time your solution looks like a good one.

-Steve
shannah
 
Posts: 4457
Joined: Wed Dec 31, 1969 5:00 pm


Return to Xataface Users

Who is online

Users browsing this forum: No registered users and 17 guests

cron
Powered by Dataface
© 2005-2007 Steve Hannah All rights reserved