Overview
This plugin duplicates the functionality found in Twitter’s mobile apps where an options menu is exposed after swiping over an item in a list. The plugin was created as an ‘I wonder if that’s possible’ type project and serves to prove once again that anything native apps can do Sencha Touch can do too.

The Plugin
The plugin is added to Ext.List components and requires only a few configuration options to get it up and running quickly, however it also offers quite a lot of control over its behaviour.
Configuration Options
| optionsSelector | Selector to use to get the dynamically created List Options Ext.Element (where the menu options are held)Once hidden the List Options element will be removedDefaults to ‘x-list-options‘ |
| menuOptions | An array of objects to be applied to the ‘listOptionsTpl‘ XTemplate to create the List Options menu |
| menuOptionSelector | Selector to use to get individual List Options within the created Ext.ElementThis is used when attaching event handlers to the menu optionsDefaults to ‘x-menu-option‘ |
| menuOptionsTpl | Ext.XTemplate to use to create the List Options view |
| menuOptionPressedClass | CSS Class that is applied to the tapped Menu Option while it is being touched. Defaults to ‘x-menu-option-pressed‘ |
| menuOptionDataFilter | Set to a function that takes in 2 arguments – your initial ‘menuOptions‘ config option and the current item’s Model instance. The function must return either the original ‘menuOptions’ variable or a revised one |
| revealAnimation | Animation used to reveal the List Options. Only works properly with ‘slide‘ animation right now.Defaults to:{ reverse: false, type: ‘slide’, duration: 500 } |
| revealDirection | The direction the List Item will slide to reveal the List Options Possible values: ‘left’, ‘right’ and ‘both’ Setting to ‘both’ means it will be decided by the direction of the User’s swipe if ‘triggerEvent‘ is set to ‘itemswipe‘ |
| swipeThreshold | Distance (in pixels) a User must swipe before triggering the List Options to be displayed.Set to -1 to disable threshold checks |
| swipeDirection | The direction the user must swipe to reveal the menuOnly applicable when ‘triggerEvent‘ is set to ‘itemswipe‘.Possible values: ‘left’, ‘right’ or ‘both’. Defaults to ‘both’ |
| triggerEvent | Ext.DataView event used to trigger the menu revealUsual values are ‘itemswipe‘, ‘itemtap‘, ‘itemdoubletap‘Notes: itemswipe: see configs ‘swipeThreshold‘ & ‘swipeDirection‘ |
| stopScrollOnShow | Stops the Ext.List from continuing its scrolling when a List Options menu is about to open.Accepts a boolean value. Defaults to true. |
| hideOnScroll | Decides whether the visible List Options menu is hidden when the List is scrolled. Accepts a boolean value |
| allowMultiple | Decides whether multiple List Options can be visible at once. Accepts a boolean value. Defaults to false |
| enableSoundEffects | Decides whether a sound effect will be played when the List Options menu opens and closes. Accepts a boolean value. Defaults to false |
| openSoundEffectURL | URL for the sound effect to play when the List Options menu opens (see enableSoundEffects). Set to blank string to prevent sound from playing. |
| closeSoundEffectURL | URL for the sound effect to play when the List Options menu closes (see enableSoundEffects). Set to blank string to prevent sound from playing. |
Events
The plugin adds 3 events to the parent Ext.List component.
| menuoptiontap | This event is fired when the User taps one of the List Options’ Menu Item – what Elements this event fires on is based on the ‘menuItemSelector‘.The event passes 2 parameters to its handler:menuItemData: this is the array item from the ‘menuOptions‘ array to allow you to perform different functionality based on what menu item was tappedactiveListRecord: the record associated with the List item that the List Options menu is showing for |
| beforelistoptionstap | Fired when a List Options menu item is tapped. Takes 2 parameters – the first is the object associated with the tapped menu item from the ‘menuOptions’ config. The second is the Model instance associated with the current menu’s List Item.This event must return true or false. A true return value will mean the tap will execute as normally (the pressed state will occur and the ‘menuoptiontap‘ event will fire. If false the tap will stop and no other actions will occur.This is a useful event to tailor menu option behaviour to the individual Model currently being dealt with. |
| listoptionsopen | Fired when the List Options menu is opened |
| listoptionsclose | Fired when the List Options menu is closed |
An Example
I’ll talk through a simple example that is based on the Ext.List demo in the Sencha Touch download package.
First I’ll quickly explain the Model, Store and plain List. I’ll assume you have a base index.html file with all the library files etc linked into it.
Defining the plugin
Ext.regModel('Contact', {
fields: ['firstName', 'lastName']
});
var store = new Ext.data.JsonStore({
model: 'Contact',
getGroupString: function(record){
return record.get('lastName')[0];
},
data: [{
firstName: 'Tommy',
lastName: 'Maintz'
}
...
{
firstName: 'Jay',
lastName: 'Robinson'
}]
});
var list = new Ext.List({
fullscreen: true,
itemTpl: '{firstName} {lastName}',
indexBar: true,
store: store,
disableSelection: true
});
list.show();
If you fire this inside your Ext.setup function and load the page you should see a list with some of Sencha’s employees in it.
Now, let’s add the plugin!
Firstly make sure you’ve added the Plugin’s source file and CSS file.
//Inside the Ext.List's config
...
plugins: [new Ext.ux.touch.ListOptions({
menuOptions: [{
id: 'Team Icon Tapped',
img: 'images/team1_small.png'
}, {
id: 'Favourite Icon Tapped',
img: 'images/favorites1_small.png'
}, {
id: 'Cart Icon Tapped',
img: 'images/shop2_small.png'
}, {
id: 'Share Icon Tapped',
img: 'images/share_small.png'
}]
})]
...
By taking the default values for all the other config options and adding some menuOptions we get the plugin up and running straight away. You can now play around with the various options to get the plugin working how you want!
If you have any problems with using the plugin, have questions about how it works or have suggestions about ways we can make it better then please leave us a comment or drop us an email!