Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

Page type tracking

edited June 2013 in Miscellaneous

Is there a way to track/check if a page in the navigation is a custom page or a page generated from an app?

also, I think it would be very useful to have a per page/app choice of a page target (_blank, _self and the like) for the navigation app.


  • The navigation tree doesn't store where a page came from, but it's pretty easy to check if a page ID matches an app name, and it's pretty easy to make a custom menu too :)

    The easiest way is to copy from one of the existing menus. For example, if I copied apps/navigation/handlers/top.php into a new file (apps/mynav/handlers/top.php), then I could modify the new handler to add a class="app" to links that point to apps, like this:

     *** Based on apps/navigation/handlers/top.php ***
     * Displays the top-level navigation as a bulleted list,
     * with `class="current"` added to the current page's
     * `<li>` element for custom styling.
     * Adds class="app" to links that point to apps.
    $n = Link::nav ();
    echo '<ul>';
    foreach ($n->tree as $item) {
        $link = Link::single ($item->attr->id, $item->data);
        // Add class="app" to links that point to apps
        if (file_exists ('apps/' . $item->attr->id)) {
            if (strpos ($link, 'class="')) {
                                // has existing class attribute
                $link = str_replace ('class="', 'class="app ', $link);
            } else {
                                // add a new class attribute
                $link = str_replace ('<li>', '<li class="app">', $link);
        echo $link;
    echo '</ul>';

    Then you just have to update your layout template to point to {! mynav/top !} instead of {! navigation/top !} so it knows to uses your new handler instead.

    And for changing the target, I can see an icon over the pages in the Tools > Navigation tree that pops up a target select box for each link, and the icon could even change to denote the current target value. Hmm... :)

  • edited June 2013

    Thank you! That handler helped a lot.

    Now I have a question about the slideshow handler. I want to pass a sting along with each img. But for easy access I want to store those strings in an ini file and list the text in there. I've tried a number of different setups with a copy of the handler, but I haven't been able to get it to render correctly through the view.

    Handler Snippit

    $files = glob ('files/' . $path . '/*.{jpg,jpeg,gif,png,JPG,JPEG,GIF,PNG}', GLOB_BRACE);
    $files = is_array ($files) ? $files : array ();
    $ini = parse_ini_file('files/'.$path.'/captions.ini');
    foreach ($files as $k => $file) {
      $y = explode('/',$file);
      $z = explode('.',$y[2]);
      $captions[] = $ini[$z[0]];
    $page->add_script ('/apps/filemanager/js/jquery.cycle.all.min.js');
    echo $tpl->render ('filemanager/slideshowcopy', array ('files' => $files, 'captions' => $captions, 'name' => $name));

    View Snippit

    <div id="slideshow-{{name}}">
    {% foreach files %}
     <div {% if loop_index > 0 %}style="display: none"{% end %}>
        <img src="/{{ loop_value }}" alt=""></img>
      <div id="caption">{{ captions->loop_index }}</div>
    {% end %}
    <div id="slideshow-{{name}}-nav"></div>
    <br style="clear: both" />
  • You're looping through the $files array in the view, so the easiest thing to do would probably be to add the captions to the $files array instead of using a separate array, for example:

    foreach ($files as $k => $file) {
        $y = explode ('/', $file);
        $z = explode ('.', $y[2]);
        $files[$k] = array ('file' => $file, 'caption' => $ini[$z[0]]);

    Then in the view, you would say:

    {% foreach files as file %}
        <img src="/{{file['file']}}">
        <div class="caption">{{file['caption']}}</div>
    {% end %}

    Another option is to use FileManager::prop() to fetch the captions, like the filemanager/gallery handler uses here. That lets you manage the caption for each file in the GUI under Tools > Files by clicking on the Properties link for that file.

    Here's how that would look in your handler:

    $descriptions = FileManager::prop ($files, 'desc');
    foreach ($files as $k => $file) {
        $files[$k] = array ('file' => $file, 'caption' => $descriptions[$file]);

    And the view would be the same as the above. Let me know how that goes! :)

  • edited June 2013

    Ok, so I tried both methods and got the ini file to work, but not the property one. I would like to be able to add links (via < a >) to the captions and the ini file screws up with the = unless I have the text quoted, but then it displays the full html text as part of the quote. I tried str_replace to remove the single quotes, but to no avail. I would like to get the property one to work, for both links (hopefully) and being able to edit through descriptions via browsers, but it doesn't seem to be getting the properties correctly...


    $files = glob ('files/' . $path . '/*.{jpg,jpeg,gif,png,JPG,JPEG,GIF,PNG}', GLOB_BRACE);
    $files = is_array ($files) ? $files : array ();
    $desc = FileManager::prop ($files, 'desc');
    echo print_r($desc,true);
    foreach ($files as $k => $file) {
      $files[$k] = array ('file' => $file, 'caption' => $desc[$file]);
    $page->add_script ('/apps/filemanager/js/jquery.cycle.all.min.js');
    echo $tpl->render ('filemanager/slideshow', array ('files' => $files, 'name' => $name));

    the view is the same as the one you listed (which it works with the ini version just fine).

    atm I have 4 photos and I have made sure that each has a description in the properties popup. when it renders, the print_r echos out just an empty Array ( ) and I get an empty caption div.

  • Looking at the paths in the elefant_filemanager_prop table, it looks like it's stripping the files/ prefix from the paths to store only what's needed, which means I gave you incomplete code :P

    What's missing is the section from filemanager/gallery just before the one I referenced before, which makes a list of the files without the files/ prefix:

    Here's a test that seems to be working for me. It should output the list of files and their captions:

    $path = 'homepage';
    $files = glob ('files/' . $path . '/*.{jpg,jpeg,gif,png,JPG,JPEG,GIF,PNG}', GLOB_BRACE);
    $files = is_array ($files) ? $files : array ();
    $list = array ();
    foreach ($files as $k => $file) {
        $list[preg_replace ('/^files\//', '', $file)] = array (
            'file' => $file,
            'caption' => ''
    $desc = FileManager::prop (array_keys ($list), 'desc');
    foreach ($list as $k => $file) {
      $list[$k]['caption'] = $desc[$k];
    info ($list);

    Hope that helps get it going for you!

  • edited June 2013

    Yes that works perfectly. Thank you! It broke the {% if loop_index > 0 %} condition in the view, but I added a self increasing index to the array to track it. That solved the issue.

    Is there a way to get the descriptions to interpret HTML tags instead of just treat them like text? I don't mind the text limit, but I would like for HTML tags to work.

  • You can disable the output filtering on a template tag like this:


    The |none is a special filter that returns the output as-is instead of escaping it.

  • OH! Dang I completely forgot about that. Thank you very much for your help! It has sped up my work significantly. =)

  • Glad to hear :)

  • edited June 2013

    Ok, I'm looking to add another text field to the properties menu of the filemanager. This may not be completely correct, but here's what I've tried adding so far.


    $out = array (
      'title' => __ ('Properties'),
      'body' => $tpl->render (
          array (
            'file' => $file,
            'link' => FileManager::prop ($file, 'link'),
            'desc' => FileManager::prop ($file, 'desc')


        {"Link"}:<br />
        <input type="text" id="link" size="70" placeholder="http://">{{link}}</input><br />
        {"Description"}:<br />
            <textarea id="desc" rows="4" cols="70">{{desc}}</textarea>


    $.filemanager_prop = function (form) {
        var file = form.elements.file.value,
            link =,
            desc = form.elements.desc.value;
        $.get ('/filemanager/api/prop/' + file + '?prop=link&value=' + encodeURIComponent (link));
        $.get ('/filemanager/api/prop/' + file + '?prop=desc&value=' + encodeURIComponent (desc), function (res) {
            $.close_dialog ();
            $.add_notification (;
        return false;

    That code displays the input field on the properties menu, but it doesn't seem to save it... my hunch says that i'm missing something on the index.html that has to do with this code:

    <script type="text/x-jquery-tmpl" id="tpl_edit_txt">
        <textarea cols="70" rows="20" id="tpl-edit-txt">\{{html txt}}</textarea>
  • At a quick glance, your input field syntax should be this:

    <input type="text" id="link" size="70" placeholder="http://" value="{{link|quotes}}" /><br />

    And the line in jquery.filemanager.js should be:

    $.get ('/filemanager/api/prop/' + file + '?prop=link&value=' + encodeURIComponent (link), function (res) {
        $.close_dialog ();
        $.add_notification (

    Really, the API method should be modified to send both at once, but that should work at least. Let me know if that helps.

  • edited July 2013

    Scratch that... I figured out what the issue was. For additional properites to be added to the file, it has to be reuploaded. That, plus your <input type="text" id="link" size="70" placeholder="http://" value="{{link|quotes}}"></input> fixed my issues. It works now. =)

    Edit: Not quite i guess... after some mucking around with it, I figured out that the DB only allows for one property to be stored. once I set either the link, or the desc for a file, it sets that as the singular property for that object in the DB. That is probably why most of the stuff I just tried wouldn't save...

    Edit2: I'm putting together a gist with edits for multiple property controls and a properties manager (for adding and removing properties). I'll link it here for feedback when I get it finished.

  • Ah yes, it looks like the DB schema is wrong for the file properties. I can get on fixing that right away, unless you have a fix already you can share.

  • edited July 2013

    I'm almost done with a possible fix for it, I just have a couple questions...

    1) Is it possible to do a switch statment in the View render?

    2) What is the array format that would result from DB:fetch ('select * from #prefix#table') look like if there was, say, 3 collumns with 2 things each in them?

    3) (off topic) Is avairy an img editor?

  • 1) Not directly, but you can approximate with ifs and elseifs:

    {% if foo == 'one' %}
    {% elseif foo == 'two' %}
    {% elseif foo == 'three' %}
    {% else %}
    {% end %}

    2) DB::fetch() simply returns each row as an object. So if your table has id, title, and link, then you would loop via:

    $res = DB::fetch ('select * from #prefix#table');
    foreach ($res as $row) {
        printf (
            '%d. <a href="%s">%s</a><br />',

    If a column contains multiple values, say in a string, then you'd have to split them up yourself. I believe even MySQL's SET column type returns a comma-separated string.

    3) Yep, i's an online image editor :)

  • edited July 2013

    So, after doing a bit of digging, I have a quick question... Does the DB abstraction layer treat all $args as text? What I'm after is to be able to send an SQL object through an $arg. Maybe if the DB layer would interpret ? as text and add ! for object arguments, that would fix my problems i'm having with the property manager and make databases able to be more dynamic.

    Example snippet similar to part of the fix i'm working on:

    $file = 'homepage/photo1.jpg';
    $prop = 'desc';
    $value = 'Default';
    DB::execute ( 
      'update #prefix#filemanager_prop set ! = ?, where file = ?', 

    Currently when the $prop is sent through, it throws an SQL error. I tried it manually in PHPadmin and it gave the exact same error. I tried it again with the correct object syntax, and it worked after that.

    If that's a bit confusing, let me know and I'll try and clarify.

  • If $prop is always set by the script and not coming from an input parameter, you can just concatenate it into the string. If it's coming from elsewhere (for example, a select box the user chooses, or an array passed via AJAX), you would probably be better to filter the $prop value first like this:

    if (! preg_match ('/^[a-zA-Z0-9_]+$/', $prop)) {
        // invalid value, return an error

    From there, it should be safe to concatenate into the string.

  • edited July 2013

    -_- I feel silly for forgetting about that. Thank you anyway.

    I just finished all the files and the property manager works! I'll link the gist when I finish putting it together.

    Edit: Here it is -

  • Cool! I'm going to be away til next Tuesday (camping at the Winnipeg Folk Festival), but I'll try it out once I'm back.

  • edited July 2013

    Any issues on the Property Manager?

  • Sorry, been taking forever to get back into things. Is it possible for you to create a pull request on Github with your changes? That way I can more easily review the changes and test everything out.

  • edited July 2013

    Sure. I'll go muck around with that and send one your way.

    Edit: Ok, I'm pretty sure I just sent a pull request with my edits. (first time with a pull request)

  • Thanks for putting that together. I just added my comments on the Github page.

Sign In or Register to comment.