Posts tagged with javascript

How to use a context menu with FancyTree

Sep 14, 2016 in javascript, fancytree, nestor-qa | tutorials

There used to be several different ways, and even an almost official way to have a context menu in a FancyTree. But it has long been decommissioned, and now the recommendation is to use a global context menu, instead of having a context menu only for the FancyTree. That does make sense, since if your application is already using a context menu library, there may be some inconsistencies with another library provided by FancyTree. Good engineering decision.

Requirements

In Nestor QA, we are using Bower to manage some of the project dependencies. The now recommended library for context menus, that is compatible with the FancyTree library, is jquery-ui-contextmenu (by the same author). However, I could not find it via bower search. So the first step is to install it using a GitHub tag.

bower install --save ui-contextmenu=mar10/jquery-ui-contextmenu#84fb56c6760d1ebd8be3785cd6ff5b67c5c41453

Where 84fb56c6760d1ebd8be3785cd6ff5b67c5c41453 is the commit hash for the latest tag, v1.13.0.

Furthermore, as we also have RequireJS, we have to add the following entry under the paths entry.

paths: {
    'jquery-ui/menu': 'libs/jquery-ui/ui/widgets/menu'
},

packages: [
    {
        name: 'uicontextmenu',
        location: 'libs/ui-contextmenu/',
        main: 'jquery.ui-contextmenu.min'
    }
],

map: {
    'jquery-ui/menu': {
        'keycode': 'libs/jquery-ui/ui/keycode',
        'position': 'libs/jquery-ui/ui/position',
        'safe-active-element': 'libs/jquery-ui/ui/safe-active-element',
        'unique-id': 'libs/jquery-ui/ui/unique-id',
        'version': 'libs/jquery-ui/ui/version',
        'widget': 'libs/jquery-ui/ui/widget'
    }
}

You need to add a package as the ui-contextmenu requires jquery-ui/menu, and adding a path doesn’t seem to work correctly in this case. But you do need to add a path for the jquery-ui/menu dependency.

Finally, jquery-ui/menu requires several other dependencies, that you can just add a map entry for RequireJS, and that’s it.

Creating the navigation tree

We are using FancyTree for the navigation tree, so the code may look a bit more complex than necessary, but if you abstract the logic for the Nestor QA application, you can see that it consists only of a delegate property, which is the CSS filter for elements that trigger the context menu; the menu items, and a select function invoked when you - as you correctly deduced - select a menu item.

// context menu
el.contextmenu({
    delegate: ".editable",
    menu: [
        {
            title: "Edit", 
            cmd: "edit", 
            uiIcon: "ui-icon-pencil"
        },
        {
            title: "Delete",
            cmd: "delete",
            uiIcon: "ui-icon-trash"
        }
    ],
    select: function(event, ui) {
        var nodeId = ui.target[0].parentNode.parentNode.id;
        // fancy tree HTML elements have the key as ft_$KEY
        var underscoreIndex = nodeId.indexOf('_');
        if (underscoreIndex > 0) {
            var length = nodeId.length;
            var key = nodeId.substring(underscoreIndex+1, length);
            var node = el.fancytree('getNodeByKey', key);
            var href = node.data.href;
            if (ui.cmd == 'edit') {
                var editHref = href.substring(0, href.length - 5);
                Backbone.history.navigate(editHref, {
                    trigger: false
                });
            } else if (ui.cmd == 'delete') {
                var editHref = href.substring(0, href.length - 5);
                var deleteHref = editHref + '/confirmDelete';
                Backbone.history.navigate(deleteHref, {
                    trigger: false
                });
            } else {
                console.log('Command ' + ui.cmd + ' not recognized!');
            }
        }
    }
});

But nevertheless the el.fancytree('getNodeByKey', key); call may be useful for you as well! Read more about the ui-context menu API in their Wiki page.

Context menu in action
Context menu in action

Happy hacking!

Fixing "XMLHttpRequest Origin is not allowed by Access-Control-Allow-Origin" in PHP and CodeIgniter

Mar 16, 2013 in blog, csrf, javascript, php, speak-like-a-brazilian | blog

Since it has been released, Speak Like A Brazilian had a bug when users voted, but had accessed the site via speaklikeabrazilian.com, and not www.speaklikeabrazilian.com (the latter is the base_url in application/config/config.php).

Looking at the developer console in Chrome, you could see that XMLHttpRequest was having trouble by, what looked in principle, like a security bug. Maybe a cross-domain issue.

After searching the Internet, we’ve found what was causing this issue. Unfortunately I lost the link, but in a StackOverFlow discussion, one user said it had something to do with the CSRF check.

A quick test, where we disabled the CSRF token verification, showed that he was right. But we couldn’t simply disable CSRF everywhere. So if you are facing similar issue, here’s the trick: Create a hook that disables CSRF verification only for a certain URL.

It’s not a very nice approach, but as in Speak Like A Brazilian the votes are linked by IP, there’s no need to keep the CSRF token. Here’s the solution that worked for us.

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
* Security Class
*
* @package hooks
* @description Disables CSRF token for certain pages.
*/

class DisableCSRF
{

function disable_if_callback()
{
if(stripos($_SERVER["REQUEST_URI"],'/rating/expression') !== FALSE)
{
$CFG =& load_class('Config', 'core');
$CFG->set_item('csrf_protection', FALSE);
}
}

}

And as a side note, we are still in honey moon with CodeIgniter. We have just finished another project with it, and so far we haven’t been let down by this amazing framework. Hope it helps you, in case you have similar error.

Happy St. Patricks Day! And happy coding!