|
#include <vector>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
#include <Wt/WText>
|
|
#include <Wt/WLineEdit>
|
|
#include <Wt/WApplication>
|
|
#include <Wt/WSuggestionPopup>
|
|
#include <Wt/WContainerWidget>
|
|
#include <Wt/WAbstractItemModel>
|
|
|
|
#include <boost/thread.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
using namespace std;
|
|
using namespace Wt;
|
|
|
|
|
|
#define INLINE_JAVASCRIPT(...) #__VA_ARGS__
|
|
|
|
|
|
class FilterModel : public WAbstractItemModel
|
|
{
|
|
//FilterModel: minimal class to provide server filtered suggestions for a
|
|
// WSuggestionPopup. Uses a limited set of nuclides (ex. Ba133, U235, etc) as
|
|
// suggestions.
|
|
protected:
|
|
std::vector<std::string> m_possibilities;
|
|
|
|
public:
|
|
FilterModel( WObject *parent )
|
|
: WAbstractItemModel( parent )
|
|
{ }
|
|
|
|
virtual ~FilterModel()
|
|
{ }
|
|
|
|
virtual WModelIndex index( int row, int column,
|
|
const WModelIndex &parent = WModelIndex() ) const
|
|
{
|
|
const int nrow = static_cast<int>( m_possibilities.size() );
|
|
if( parent.isValid() || row < 0 || column != 0 || row >= nrow )
|
|
return WModelIndex();
|
|
return createIndex( row, column, (void *)0 );
|
|
}
|
|
|
|
virtual WModelIndex parent( const WModelIndex &index ) const
|
|
{
|
|
return WModelIndex();
|
|
}
|
|
|
|
virtual int rowCount( const WModelIndex &parent = WModelIndex() ) const
|
|
{
|
|
if( parent.isValid() )
|
|
return 0;
|
|
return static_cast<int>( m_possibilities.size() );
|
|
}
|
|
|
|
virtual int columnCount( const WModelIndex & parent = WModelIndex() ) const
|
|
{
|
|
return parent.isValid() ? 0 : 1;
|
|
}
|
|
|
|
virtual boost::any data( const WModelIndex &index, int role = DisplayRole ) const
|
|
{
|
|
const int row = index.row();
|
|
const int nrow = static_cast<int>( m_possibilities.size() );
|
|
if( !index.isValid() || row < 0 || index.column() != 0 || row >= nrow )
|
|
return boost::any();
|
|
return boost::any( WString(m_possibilities[row]) );
|
|
}
|
|
|
|
virtual void filter( const WString &text )
|
|
{
|
|
static const string nuclides[] =
|
|
{ "Ba125", "Ba126", "Ba127", "Ba128", "Ba129", "Ba131", "Ba133", "B10",
|
|
"B12", "B14", "B185", "Bi187", "Co60", "U235", "Ir192", "Eu154",
|
|
"Na22", "Pu238"
|
|
};
|
|
const size_t num_nuclides = sizeof(nuclides)/sizeof(nuclides[0]);
|
|
|
|
const int ninitialrow = rowCount();
|
|
if( ninitialrow > 0 )
|
|
{
|
|
beginRemoveRows( WModelIndex(), 0, ninitialrow-1 );
|
|
m_possibilities.clear();
|
|
endRemoveRows();
|
|
}
|
|
|
|
std::string simpletxt = text.narrow();
|
|
boost::algorithm::to_lower( simpletxt );
|
|
|
|
vector<string> newpossiblities;
|
|
for( size_t i = 0; i < num_nuclides; ++i )
|
|
if( boost::algorithm::icontains( nuclides[i], simpletxt ) )
|
|
newpossiblities.push_back( nuclides[i] );
|
|
|
|
const int nrow = static_cast<int>( newpossiblities.size() );
|
|
beginInsertRows( WModelIndex(), 0, nrow -1 );
|
|
m_possibilities.swap( newpossiblities );
|
|
endInsertRows();
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class MinimalWtApp : public WApplication
|
|
{
|
|
public:
|
|
MinimalWtApp(const WEnvironment& env)
|
|
: WApplication(env)
|
|
{
|
|
setTitle("MinimalWtApp");
|
|
|
|
WText *label = new WText( "Type in server side filtered suggestions of nuclides (ex. Ba133, U235, Co60):", root() );
|
|
label->setInline( false );
|
|
|
|
WLineEdit *edit = new WLineEdit( root() );
|
|
|
|
WSuggestionPopup::Options opts;
|
|
|
|
opts.highlightBeginTag = "<b>";
|
|
opts.highlightEndTag = "</b>";
|
|
opts.listSeparator = ',';
|
|
opts.whitespace = " \\n";
|
|
opts.wordSeparators = " ";
|
|
|
|
WSuggestionPopup *suggest = new WSuggestionPopup( opts, root() );
|
|
suggest->setMaximumSize( WLength::Auto, WLength(15, WLength::FontEm) );
|
|
|
|
FilterModel *filterModel = new FilterModel( root() );
|
|
filterModel->filter( "" );
|
|
suggest->setFilterLength( -1 );
|
|
suggest->setModel( filterModel );
|
|
suggest->filterModel().connect( filterModel, &FilterModel::filter );
|
|
suggest->forEdit( edit, WSuggestionPopup::Editing ); // | WSuggestionPopup::DropDownIcon
|
|
|
|
/*
|
|
//Hack to catch exception JS caused by WSuggestionPopup refilter, so this
|
|
// way the whole (client side) app doesnt crash.
|
|
//If you define your own matcher javascript, you have to check to make sure
|
|
// the edit passed into your function is valid to.
|
|
string js = INLINE_JAVASCRIPT(
|
|
var addTryCatch = function( elid )
|
|
{
|
|
var dofix = function(elid){
|
|
var el = Wt.WT.getElement(elid);
|
|
var self = el ? jQuery.data(el, 'obj') : null;
|
|
if( !self ){
|
|
//Apparently not immediately available even though suggest should be
|
|
// in the DOM by the time this JS gets executed, not quit sure...
|
|
// but this works.
|
|
setTimeout( function(){dofix(elid);}, 100 );
|
|
return;
|
|
}
|
|
|
|
var oldfcn = self.refilter;
|
|
self.refilter = function(value){ try{ oldfcn(value); }catch(e){ console.log('My refilter caught: ' + e ); } };
|
|
};
|
|
dofix(elid);
|
|
}; );
|
|
|
|
suggest->doJavaScript( js + " addTryCatch('" + suggest->id() + "');" );
|
|
*/
|
|
|
|
label = new WText( "<br />If you type in a nuclide (ex Ba133) and quickly hit"
|
|
" enter, you will (sometimes) get a JS exception saying "
|
|
"\"Cannot read property 'value' of null\"", root() );
|
|
label->setInline( false );
|
|
}//MinimalWtApp constructor
|
|
|
|
virtual ~MinimalWtApp()
|
|
{
|
|
}
|
|
|
|
protected:
|
|
};//class MinimalWtApp
|
|
|
|
|
|
WApplication *createApplication(const WEnvironment& env)
|
|
{
|
|
return new MinimalWtApp(env);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
cout << "WT_VERSION=" << std::hex << WT_VERSION << endl;
|
|
return WRun(argc, argv, &createApplication);
|
|
}
|
|
|