00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef Web_Page_Menu_Hpp
00011 #define Web_Page_Menu_Hpp
00012
00013
00014 #include "cgiTemplates.h"
00015 #include "read_base.hpp"
00016 #include <vector>
00017 #include <map>
00018 #include <stack>
00019 #include "pg_handlers.hpp"
00020
00021
00022
00023 using namespace std;
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 class menu_item
00034 {
00035 protected:
00036
00037 long long m_id;
00038 long long m_site_id;
00039 long long m_menu_id;
00040 long long m_link_id;
00041 string m_template_tag;
00042 string m_locate_tag;
00043 string m_target_tag;
00044 string m_label_tag;
00045 long m_place_order;
00046 long m_place_level;
00047
00048 string m_name;
00049 string m_url;
00050 string m_target;
00051
00052
00053 public:
00054
00055 menu_item()
00056 :m_id(0),m_site_id(0),m_menu_id(0),m_link_id(0)
00057 ,m_place_order(0),m_place_level(0)
00058 {
00059 ;
00060 }
00061 virtual ~menu_item()
00062 {
00063 ;
00064 }
00065 menu_item & operator = ( const menu_item & in )
00066 {
00067 id(in.id());
00068 site_id(in.site_id());
00069 menu_id(in.menu_id());
00070 link_id(in.link_id());
00071 template_tag(in.template_tag());
00072 locate_tag(in.locate_tag());
00073 target_tag(in.target_tag());
00074 label_tag(in.label_tag());
00075 place_order(in.place_order());
00076 place_level(in.place_level());
00077 name(in.name());
00078 url(in.url());
00079 target(in.target());
00080 return *this;
00081 }
00082
00083
00084
00085
00086 long long id(void)const{return m_id;}
00087 long long site_id(void)const{return m_site_id;}
00088 long long menu_id(void)const{return m_menu_id;}
00089 long long link_id(void)const{return m_link_id;}
00090 string template_tag(void)const{return m_template_tag;}
00091 string locate_tag(void)const{return m_locate_tag;}
00092 string target_tag(void)const{return m_target_tag;}
00093 string label_tag(void)const{return m_label_tag;}
00094 long place_order(void)const{return m_place_order;}
00095 long place_level(void)const{return m_place_level;}
00096 string name(void)const{return m_name;}
00097 string url(void)const{return m_url;}
00098 string target(void)const{return m_target;}
00099
00100
00101 void id(long long in){m_id=in;}
00102 void site_id(long long in){m_site_id=in;}
00103 void menu_id(long long in){m_menu_id=in;}
00104 void link_id(long long in){m_link_id=in;}
00105 void template_tag(string in){m_template_tag=in;}
00106 void locate_tag(string in){m_locate_tag=in;}
00107 void target_tag(string in){m_target_tag=in;}
00108 void label_tag(string in){m_label_tag=in;}
00109 void place_order(long in){m_place_order=in;}
00110 void place_level(long in){m_place_level=in;}
00111 void name(string in){m_name=in;}
00112 void url(string in){m_url=in;}
00113 void target(string in){m_target=in;}
00114
00115 };
00116
00117
00118 typedef vector< menu_item> menu_items;
00119
00120
00121 typedef map< long, long> node_walk;
00122
00123 class page_menu
00124 {
00125 private:
00126
00127 protected:
00128
00129
00130 long long m_id;
00131 long long m_site_id;
00132 long long m_page_menu_id;
00133 long long m_page_id;
00134 string m_name;
00135 string m_template_open_tag;
00136 string m_template_close_tag;
00137 long m_place_order;
00138 bool m_collapsible;
00139 menu_items m_links;
00140
00141 public:
00142
00143
00144 page_menu ()
00145 :m_id(0),m_site_id(0)
00146 ,m_page_menu_id(0),m_page_id(0)
00147 ,m_place_order(0),m_collapsible(false){;}
00148 ~page_menu(){;}
00149 page_menu & operator = (const page_menu & in)
00150 {
00151 m_id = in.id();
00152 m_site_id = in.site_id();
00153 m_page_menu_id = in.page_menu_id();
00154 m_page_id = in.page_id();
00155 m_name = in.name();
00156 m_template_open_tag = in.template_open_tag();
00157 m_template_close_tag = in.template_close_tag();
00158 m_place_order = in.place_order();
00159 m_collapsible = in.collapsible();
00160 m_links = in.m_links;
00161 return *this;
00162 }
00163
00164
00165
00166 long long id(void)const{return m_id;}
00167 long long site_id(void)const{return m_site_id;}
00168 long long page_menu_id(void)const{return m_page_menu_id;}
00169 long long page_id(void)const{return m_page_id;}
00170 string name(void)const{return m_name;}
00171 string template_open_tag(void)const{return m_template_open_tag;}
00172 string template_close_tag(void)const{return m_template_close_tag;}
00173 long place_order(void)const{return m_place_order;}
00174 bool collapsible(void)const{return m_collapsible;}
00175
00176
00177 menu_items & links(void){return m_links;}
00178
00179
00180 void id(long long in) {m_id=in;}
00181 void site_id(long long in) {m_site_id=in;}
00182 void page_menu_id(long long in) {m_page_menu_id=in;}
00183 void page_id(long long in) {m_page_id=in;}
00184 void name(string in) {m_name=in;}
00185 void template_open_tag(string in) {m_template_open_tag=in;}
00186 void template_close_tag(string in) {m_template_close_tag=in;}
00187 void place_order(long in) {m_place_order=in;}
00188 void collapsible(bool in) {m_collapsible=in;}
00189 };
00190
00191 typedef vector<page_menu> page_menu_vector;
00192
00193 class page_menus : public page_menu_vector, protected read_base
00194 {
00195 int iMenu;
00196
00197 menu_item sel_item;
00198
00199 bool isSelected;
00200
00201 string m_boundStart;
00202 string m_boundEnd;
00203 public:
00204 pgHandlerMap handlers;
00205 string handlerKey;
00206
00207 page_menus()
00208 :page_menu_vector(),read_base(),iMenu(0),isSelected(false)
00209 {
00210 ;
00211 }
00212 virtual ~page_menus()
00213 {
00214 cleanHandlerMap(handlers);
00215 }
00216
00217 string menuSql( long long pgid )
00218 {
00219 ocString sql = "select m.id,m.site_id,pm.id, "
00220 "pm.page_id,m.name,m.template_open_tag, "
00221 "m.template_close_tag,pm.place_order, "
00222 "pm.collapsible from metasite.menus m "
00223 "inner join metasite.page_menus pm on "
00224 "pm.menu_id = m.id where pm.page_id = ";
00225 sql.append(pgid);
00226 sql += " order by pm.place_order ";
00227 return sql;
00228 }
00229
00230 string linkQ1( long long menu_id, string pathInfo )
00231 {
00232 ocString sql =
00233 "select l.name, l.url, "
00234 "mi.id, mi.place_order, mi.place_level "
00235 "from metasite.links l "
00236 "inner join metasite.menu_items mi on mi.link_id = l.id "
00237 "where mi.menu_id = ";
00238 sql.append(menu_id);
00239 sql += " and ( l.url = '";
00240 sql += baseUrl;
00241 sql += pathInfo;
00242 sql +="' or l.url like '%";
00243 sql += getenv("SERVER_NAME");
00244 sql += getenv("SCRIPT_NAME");
00245 sql += pathInfo;
00246 sql +="')";
00247
00248 return sql;
00249 }
00250 void setSelectItem(menu_item & mi)
00251 {
00252 mi.name(rs.getField(0).format());
00253 mi.url(rs.getField(1).format());
00254 mi.id(atoll(rs.getField(2).format().c_str()));
00255 mi.place_order(atol(rs.getField(3).format().c_str()));
00256 mi.place_level(atol(rs.getField(4).format().c_str()));
00257 }
00258
00259 string linkQ2( long long menu_id, long place_order, long place_level )
00260 {
00261 ocString sql = "select max(mi.place_order), mi.place_level "
00262 " from metasite.links l "
00263 " inner join metasite.menu_items mi on mi.link_id = l.id "
00264 " where mi.menu_id = ";
00265 sql.append(menu_id);
00266 sql += " and mi.place_order <= ";
00267 sql.append(place_order);
00268 sql += " and mi.place_level <= ";
00269 sql.append(place_level);
00270 sql += " group by mi.place_level "
00271 " order by mi.place_order";
00272
00273 return sql;
00274 }
00275
00276 node_walk walk;
00277 bool findNodesToWalk( page_menu & pm, string & pathInfo )
00278 {
00279 bool bret=true;
00280 long currentLevel = 1, lastParentPos = 0;
00281
00282 if( isSelected && pm.collapsible() )
00283 {
00284
00285 for( bool bopen = rs.open( linkQ2( pm.id(),
00286 sel_item.place_order(),
00287 sel_item.place_level() ) );
00288 bopen;
00289 bopen=rs.next() )
00290 {
00291 long place_order = atol(rs.getField(0).format().c_str());
00292 long place_level = atol(rs.getField(1).format().c_str());
00293 walk.insert( make_pair(place_order,place_level) );
00294 }
00295 rs.close();
00296 }
00297
00298 return bret;
00299 }
00300
00301 string linkQ3( long long menu_id )
00302 {
00303 ocString sql = "select l.id, l.name, l.url, l.target,"
00304 " mi.id, mi.template_tag, mi.locate_tag, mi.target_tag, "
00305 "mi.label_tag, mi.place_order, mi.place_level "
00306 " from metasite.links l "
00307 " inner join metasite.menu_items mi on mi.link_id = l.id"
00308 " where mi.menu_id = ";
00309 sql.append(menu_id);
00310 sql += " order by mi.place_order";
00311
00312 return sql;
00313 }
00314 void setMenuItem(menu_item & mi)
00315 {
00316 mi.link_id(atoll(rs.getField(0).format().c_str()));
00317 mi.name(rs.getField(1).format());
00318 mi.url(rs.getField(2).format());
00319 mi.target(rs.getField(3).format());
00320 mi.id(atoll(rs.getField(4).format().c_str()));
00321 mi.template_tag(rs.getField(5).format());
00322 mi.locate_tag(rs.getField(6).format());
00323 mi.target_tag(rs.getField(7).format());
00324 mi.label_tag(rs.getField(8).format());
00325 mi.place_order(atol(rs.getField(9).format().c_str()));
00326 mi.place_level(atol(rs.getField(10).format().c_str()));
00327 }
00328 void pageMenuPropSet( page_menu & pm )
00329 {
00330 pm.id(atoll(rs.getField(0).format().c_str()));
00331 pm.site_id(atoll(rs.getField(1).format().c_str()));
00332 pm.page_menu_id(atoll(rs.getField(2).format().c_str()));
00333 pm.page_id(atoll(rs.getField(3).format().c_str()));
00334 pm.name(rs.getField(4).format());
00335 pm.template_open_tag(rs.getField(5).format());
00336 pm.template_close_tag(rs.getField(6).format());
00337 pm.place_order(atol(rs.getField(7).format().c_str()));
00338 pm.collapsible(atol(rs.getField(8).format().c_str())!=0);
00339 }
00340 bool load( long long page_id )
00341 {
00342 bool bopen;
00343
00344 for( bopen=rs.open(menuSql(page_id));
00345 bopen;
00346 bopen=rs.next() )
00347 {
00348
00349 page_menu pm;
00350
00351 pageMenuPropSet(pm);
00352
00353 push_back(pm);
00354 }
00355
00356 rs.close();
00357 iMenu=0;
00358
00359 return true;
00360 }
00361
00362
00363
00364 bool emitMenuBoundary( paragraphMap & paras,
00365 string & Tag,
00366 ostream & toBrowser )
00367 {
00368 bool breturn=false;
00369 paragraphMap::iterator pos = static_cast<paragraphMap &>(paras).find(Tag);
00370 if( pos != paras.end() )
00371 {
00372 ocString bndry = pos->second;
00373 ocString menuItemId;
00374 menuItemId.append(sel_item.id());
00375 if(isSelected)
00376 toBrowser << bndry.replace("$selected$",menuItemId.c_str());
00377 else
00378 toBrowser << bndry;
00379 }
00380 else
00381 {
00382 toBrowser << "<!-- Can't find menu tag "
00383 << Tag
00384 << endl
00385 << "Check that the data matches the file template. -->"
00386 << endl;
00387 }
00388 return breturn;
00389 }
00390
00391 bool emitItem( paragraphMap & paras,
00392 page_menu & pm,
00393 menu_item & mi,
00394 ostream & toBrowser,
00395 bool defaultPage )
00396 {
00397 bool breturn=false;
00398 paragraphMap::iterator pos = paras.find(mi.template_tag());
00399 if( pos != paras.end() )
00400 {
00401 breturn = true;
00402 string base = baseUrl;
00403 if( base.length() ) base += "/";
00404 ocString url = mi.url();
00405 ocString item = pos->second;
00406 ocString uniqueId = "menu_item_";
00407 uniqueId.append(mi.id());
00408
00409 ocString place_level;
00410 place_level.append(mi.place_level());
00411
00412
00413 if( !defaultPage )
00414 {
00415
00416 if ( url.find( ":") == string::npos )
00417 {
00418
00419 if( url.find(base.c_str()) != string::npos )
00420 {
00421 url = url.replace( base.c_str(),"");
00422 }
00423
00424 else
00425 {
00426 string temp = "../";
00427 temp += url;
00428 url = temp;
00429 }
00430 }
00431 }
00432 toBrowser << item.replaceAll("$id",uniqueId.c_str() )
00433 .replaceAll("$level",place_level.c_str() )
00434 .replaceAll(mi.locate_tag().c_str(),
00435 url.c_str() )
00436 .replace(mi.target_tag().c_str(),mi.target().c_str())
00437 .replaceAll(mi.label_tag().c_str(),mi.name().c_str());
00438 }
00439 else
00440 {
00441 toBrowser << "<!-- Can't find menu item tag "
00442 << mi.template_tag()
00443 << endl
00444 << "Check that the data matches the file template. -->"
00445 << endl;
00446 }
00447 return breturn;
00448 }
00449
00450 bool getSelected(string & pathInfo)
00451 {
00452 if( iMenu < size() )
00453 {
00454 page_menu & pm = operator [] (iMenu);
00455 isSelected=false;
00456
00457
00458
00459 if( rs.open( linkQ1( pm.id(), pathInfo ) ) )
00460 {
00461
00462 isSelected=true;
00463
00464
00465 setSelectItem(sel_item);
00466 rs.close();
00467 }
00468 }
00469 return isSelected;
00470 }
00471
00472 bool nodeToWalkDetected( menu_item & mi )
00473 {
00474 bool bFound = false;
00475 node_walk::iterator pos = walk.find( mi.place_order() );
00476 if( pos != walk.end() && pos->second == mi.place_level() )
00477 {
00478 bFound = true;
00479 }
00480 return bFound;
00481 }
00482 void childMenuHandler( void )
00483 {
00484 if( handlerKey.length() )
00485 {
00486 pgHandlerMap::iterator pos = handlers.find(handlerKey);
00487 if( pos != handlers.end() )
00488 {
00489 (*(pos->second))();
00490 }
00491 }
00492 }
00493 void emitBoundary(ostream & toBrowser, paragraphMap & paras, string name, long long id, long level )
00494 {
00495 if( name.length() )
00496 {
00497 paragraphMap::iterator pos = paras.find(name);
00498 if( pos != paras.end() )
00499 {
00500 ocString strId = "";
00501 ocString strLvl = "";
00502 strId.append(id);
00503 strLvl.append(level);
00504 ocString templt = pos->second;
00505 toBrowser << templt.replaceAll("$id",strId).replaceAll("$level",strLvl);
00506 }
00507 }
00508 }
00509 bool emitRecursor( int currentLevel,
00510 paragraphMap & paras,
00511 page_menu & pm,
00512 ostream & toBrowser,
00513 bool defaultPage )
00514 {
00515 bool bret=true;
00516 bool seeChildren = false;
00517 bool sawChildren = false;
00518 bool previousSelected = false;
00519 long long last_id = 0;
00520 long last_level = currentLevel;
00521 do
00522 {
00523 menu_item mi;
00524 setMenuItem(mi);
00525 previousSelected = isSelected && sel_item.id() == mi.id();
00526 if( pm.collapsible() )
00527 {
00528
00529 if( mi.place_level() == currentLevel )
00530 {
00531 emitItem( paras, pm, mi, toBrowser, defaultPage);
00532 seeChildren = nodeToWalkDetected( mi );
00533 }
00534 else if( mi.place_level() > currentLevel )
00535 {
00536 if( seeChildren == true &&
00537 sawChildren == false )
00538 {
00539
00540 if( pm.collapsible() )
00541 {
00542 sawChildren = emitRecursor( mi.place_level(),
00543 paras,
00544 pm,
00545 toBrowser,
00546 defaultPage );
00547 }
00548 }
00549 }
00550 else
00551 {
00552
00553 emitItem( paras, pm, mi, toBrowser, defaultPage);
00554 break;
00555 }
00556 }
00557 else
00558 {
00559 int bndryCount = mi.place_level() - last_level;
00560
00561 for( int i=0; i<bndryCount; i++ ) emitBoundary(toBrowser,paras, m_boundStart, last_id, last_level);
00562 for( int i=bndryCount; i<0; i++ ) emitBoundary(toBrowser,paras, m_boundEnd, last_id, last_level );
00563 emitItem( paras, pm, mi, toBrowser, defaultPage);
00564
00565 }
00566
00567 if( previousSelected )
00568 {
00569 childMenuHandler();
00570 }
00571
00572 last_id = mi.id();
00573 last_level = mi.place_level();
00574 }
00575 while( rs.isOpen() && rs.next() );
00576 return bret;
00577 }
00578
00579
00580
00581 bool emitItems( paragraphMap & paras,
00582 page_menu & pm,
00583 ostream & toBrowser,
00584 string & pathInfo,
00585 bool defaultPage)
00586 {
00587 bool breturn=false, bopen=false;
00588
00589 findNodesToWalk( pm, pathInfo );
00590
00591 if( rs.open( linkQ3( pm.id() ) ) )
00592 {
00593 return emitRecursor( 1,
00594 paras,
00595 pm,
00596 toBrowser,
00597 defaultPage );
00598 rs.close();
00599 }
00600 }
00601
00602
00603 bool emit( paragraphMap & paras,
00604 ostream & toBrowser,
00605 string pathInfo,
00606 bool defaultPage,
00607 string startTag,
00608 string endTag,
00609 string boundStart = "", string boundEnd="")
00610 {
00611 bool breturn=false;
00612 m_boundStart = boundStart;
00613 m_boundEnd = boundEnd;
00614
00615 getSelected(pathInfo);
00616
00617
00618 emitMenuBoundary( paras, startTag, toBrowser );
00619
00620 if( iMenu < size() )
00621 {
00622 page_menu & pm = operator [] (iMenu);
00623 emitItems(paras,pm,toBrowser,pathInfo,defaultPage);
00624 iMenu++;
00625 breturn=true;
00626 }
00627
00628 emitMenuBoundary( paras, endTag, toBrowser );
00629
00630 return breturn;
00631 }
00632
00633
00634 menu_item & get_sel_item()
00635 {
00636 return sel_item;
00637 }
00638 };
00639
00640 #endif
00641