ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1345 lines
25 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Lesser General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. #define CPPCMS_SOURCE
  20. #include "form.h"
  21. #include "config.h"
  22. #include "encoding.h"
  23. #include "regex.h"
  24. #include "filters.h"
  25. #include "cppcms_error.h"
  26. #include <stack>
  27. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  28. # include <boost/format.hpp>
  29. #else // Internal Boost
  30. # include <cppcms_boost/format.hpp>
  31. namespace boost = cppcms_boost;
  32. #endif
  33. namespace cppcms {
  34. struct form_context::data {};
  35. form_context::form_context() :
  36. html_type_(as_html),
  37. html_list_type_(as_p),
  38. widget_part_type_(first_part),
  39. output_(0)
  40. {
  41. }
  42. form_context::form_context(std::ostream &out,form_context::html_type t,form_context::html_list_type hlt) :
  43. html_type_(t),
  44. html_list_type_(hlt),
  45. widget_part_type_(first_part),
  46. output_(&out)
  47. {
  48. }
  49. void form_context::html(html_type t)
  50. {
  51. html_type_=t;
  52. }
  53. void form_context::html_list(html_list_type t)
  54. {
  55. html_list_type_ = t;
  56. }
  57. void form_context::widget_part(widget_part_type t)
  58. {
  59. widget_part_type_ = t;
  60. }
  61. void form_context::out(std::ostream &out)
  62. {
  63. output_ = &out;
  64. }
  65. std::ostream &form_context::out() const
  66. {
  67. if(!output_)
  68. throw cppcms_error("Can't use form context without assigned output");
  69. return *output_;
  70. }
  71. form_flags::html_type form_context::html() const
  72. {
  73. return static_cast<html_type>(html_type_);
  74. }
  75. form_flags::html_list_type form_context::html_list() const
  76. {
  77. return static_cast<html_list_type>(html_list_type_);
  78. }
  79. form_flags::widget_part_type form_context::widget_part() const
  80. {
  81. return static_cast<widget_part_type>(widget_part_type_);
  82. }
  83. form_context::~form_context()
  84. {
  85. }
  86. base_form::base_form()
  87. {
  88. }
  89. base_form::~base_form()
  90. {
  91. }
  92. // Meanwhile -- empty
  93. struct form::data {
  94. // TOADD
  95. };
  96. form::form() : parent_(0)
  97. {
  98. }
  99. form::~form()
  100. {
  101. for(unsigned i=0;i<elements_.size();i++) {
  102. if(elements_[i].second)
  103. delete elements_[i].first;
  104. }
  105. }
  106. void form::parent(base_form *parent)
  107. {
  108. parent_=&dynamic_cast<form &>(*parent);
  109. }
  110. form *form::parent()
  111. {
  112. return parent_;
  113. }
  114. void form::render(form_context &context)
  115. {
  116. for(unsigned int i=0;i<elements_.size();i++) {
  117. elements_[i].first->render(context);
  118. }
  119. }
  120. void form::load(http::context &cont)
  121. {
  122. for(unsigned int i=0;i<elements_.size();i++) {
  123. elements_[i].first->load(cont);
  124. }
  125. }
  126. bool form::validate()
  127. {
  128. bool result=true;
  129. for(unsigned int i=0;i<elements_.size();i++) {
  130. result = elements_[i].first->validate() & result;
  131. }
  132. return result;
  133. }
  134. void form::clear()
  135. {
  136. for(unsigned int i=0;i<elements_.size();i++) {
  137. elements_[i].first->clear();
  138. }
  139. }
  140. void form::add(widgets::base_widget &form)
  141. {
  142. elements_.push_back(widget_type(&form,false));
  143. form.parent(this);
  144. }
  145. void form::add(form &subform)
  146. {
  147. elements_.push_back(widget_type(&subform,false));
  148. subform.parent(this);
  149. }
  150. void form::attach(form *subform)
  151. {
  152. elements_.push_back(widget_type(subform,true));
  153. subform->parent(this);
  154. }
  155. void form::attach(widgets::base_widget *subform)
  156. {
  157. elements_.push_back(widget_type(subform,true));
  158. subform->parent(this);
  159. }
  160. struct form::iterator::data {};
  161. form::iterator::iterator() : current_(0), offset_(0)
  162. {
  163. }
  164. form::iterator::iterator(form &f) : current_(&f), offset_(0)
  165. {
  166. next();
  167. }
  168. form::iterator::~iterator()
  169. {
  170. }
  171. form::iterator::iterator(form::iterator const &other) :
  172. return_positions_(other.return_positions_),
  173. current_(other.current_),
  174. offset_(other.offset_),
  175. d(other.d)
  176. {
  177. }
  178. form::iterator const &form::iterator::operator=(form::iterator const &other)
  179. {
  180. if(this != &other) {
  181. return_positions_ = other.return_positions_;
  182. current_ = other.current_;
  183. offset_=other.offset_;
  184. d=other.d;
  185. }
  186. return *this;
  187. }
  188. bool form::iterator::equal(form::iterator const &other) const
  189. {
  190. return current_ == other.current_
  191. && offset_ == other.offset_
  192. && return_positions_ == other.return_positions_;
  193. }
  194. void form::iterator::zero()
  195. {
  196. current_ = 0;
  197. offset_ = 0;
  198. }
  199. void form::iterator::next()
  200. {
  201. for(;;) {
  202. if(!current_)
  203. return;
  204. if(offset_ >=current_->elements_.size()) {
  205. if(return_positions_.empty()) {
  206. zero();
  207. return;
  208. }
  209. offset_ = return_positions_.top();
  210. return_positions_.pop();
  211. current_ = current_->parent();
  212. }
  213. else if(dynamic_cast<widgets::base_widget *>(current_->elements_[offset_].first)!=0) {
  214. offset_++;
  215. return;
  216. }
  217. else {
  218. // Elements can be only base_widget or form... so it should be safe
  219. current_ = static_cast<form *>(current_->elements_[offset_].first);
  220. return_positions_.push(offset_+1);
  221. offset_=0;
  222. }
  223. }
  224. }
  225. widgets::base_widget *form::iterator::get() const
  226. {
  227. return static_cast<widgets::base_widget *>(current_->elements_[offset_ - 1].first);
  228. }
  229. form::iterator form::begin()
  230. {
  231. return form::iterator(*this);
  232. }
  233. form::iterator form::end()
  234. {
  235. return form::iterator();
  236. }
  237. namespace widgets {
  238. ////////////////////////////////
  239. // widgets::base_widget
  240. ////////////////////////////////
  241. struct base_widget::data {};
  242. base_widget::base_widget() :
  243. parent_(0),
  244. is_valid_(1),
  245. is_set_(0),
  246. is_disabled_(0),
  247. is_generation_done_(0),
  248. has_message_(0),
  249. has_error_(0),
  250. has_help_(0)
  251. {
  252. }
  253. base_widget::~base_widget()
  254. {
  255. }
  256. bool base_widget::has_message()
  257. {
  258. return has_message_;
  259. }
  260. bool base_widget::has_help()
  261. {
  262. return has_help_;
  263. }
  264. bool base_widget::has_error_message()
  265. {
  266. return has_error_;
  267. }
  268. void base_widget::parent(base_form *parent)
  269. {
  270. parent_=&dynamic_cast<form &>(*parent);
  271. }
  272. form *base_widget::parent()
  273. {
  274. return parent_;
  275. }
  276. bool base_widget::set()
  277. {
  278. return is_set_;
  279. }
  280. bool base_widget::valid()
  281. {
  282. return is_valid_;
  283. }
  284. std::string base_widget::id()
  285. {
  286. return id_;
  287. }
  288. std::string base_widget::name()
  289. {
  290. return name_;
  291. }
  292. locale::message base_widget::message()
  293. {
  294. return message_;
  295. }
  296. locale::message base_widget::error_message()
  297. {
  298. return error_message_;
  299. }
  300. locale::message base_widget::help()
  301. {
  302. return help_;
  303. }
  304. void base_widget::set(bool v)
  305. {
  306. is_set_=v;
  307. }
  308. void base_widget::valid(bool v)
  309. {
  310. is_valid_=v;
  311. }
  312. void base_widget::id(std::string v)
  313. {
  314. id_=v;
  315. }
  316. void base_widget::name(std::string v)
  317. {
  318. name_=v;
  319. }
  320. void base_widget::message(locale::message const &v)
  321. {
  322. has_message_ = 1;
  323. message_=v;
  324. }
  325. void base_widget::error_message(locale::message const &v)
  326. {
  327. has_error_ = 1;
  328. error_message_=v;
  329. }
  330. void base_widget::help(locale::message const &v)
  331. {
  332. has_help_ = 1;
  333. help_=v;
  334. }
  335. void base_widget::message(std::string v)
  336. {
  337. has_message_ = 1;
  338. message_=locale::message("#NOTRANS#" + v);
  339. }
  340. void base_widget::error_message(std::string v)
  341. {
  342. has_error_ = 1;
  343. error_message_=locale::message("#NOTRANS#" + v);
  344. }
  345. void base_widget::help(std::string v)
  346. {
  347. has_help_ = 1;
  348. help_=locale::message("#NOTRANS#" + v);
  349. }
  350. void base_widget::attributes_string(std::string v)
  351. {
  352. attr_=v;
  353. }
  354. bool base_widget::disabled()
  355. {
  356. return is_disabled_;
  357. }
  358. void base_widget::disabled(bool v)
  359. {
  360. is_disabled_=v;
  361. }
  362. std::string base_widget::attributes_string()
  363. {
  364. return attr_;
  365. }
  366. void base_widget::generate(int position,form_context *context)
  367. {
  368. if(is_generation_done_)
  369. return;
  370. if(name_.empty()) {
  371. name_ = (boost::format("_%1%",std::locale::classic()) % position).str();
  372. }
  373. is_generation_done_ = 1;
  374. }
  375. void base_widget::auto_generate(form_context *context)
  376. {
  377. if(is_generation_done_)
  378. return;
  379. if(parent() == 0) {
  380. generate(1,context);
  381. return;
  382. }
  383. form *top;
  384. for(top = parent();top->parent();top=top->parent())
  385. ;
  386. int i=1;
  387. form::iterator p=top->begin(),e=top->end();
  388. while(p!=e) {
  389. p->generate(i,context);
  390. ++p;
  391. ++i;
  392. }
  393. }
  394. void base_widget::render(form_context &context)
  395. {
  396. auto_generate(&context);
  397. std::ostream &output = context.out();
  398. switch(context.html_list()) {
  399. case as_p: output<<"<p>"; break;
  400. case as_table: output<<"<tr><th>"; break;
  401. case as_ul: output<<"<li>"; break;
  402. case as_dl: output<<"<dt>"; break;
  403. default: ;
  404. }
  405. if(has_message()) {
  406. if(id_.empty())
  407. output << filters::escape(message());
  408. else
  409. output<<"<label for=\"" << id() << "\">" << filters::escape(message()) <<":</label> ";
  410. }
  411. else {
  412. output<<"&nbsp;";
  413. }
  414. switch(context.html_list()) {
  415. case as_table: output<<"</th><td>"; break;
  416. case as_dl: output<<"</dt><dd>"; break;
  417. default: ;
  418. }
  419. if(!valid()) {
  420. output<<"<span class=\"cppcms_form_error\">";
  421. if(has_error_message())
  422. output<<filters::escape(error_message());
  423. else
  424. output<<"*";
  425. output<<"</span> ";
  426. }
  427. else {
  428. output<<"&nbsp;";
  429. }
  430. output<<"<span class=\"cppcms_form_input\">";
  431. context.widget_part(first_part);
  432. render_input(context);
  433. output<<attr_;
  434. context.widget_part(second_part);
  435. render_input(context);
  436. output<<"</span>";
  437. if(has_help()) {
  438. output<<"<span class=\"cppcms_form_help\">"<<filters::escape(help())<<"</span>";
  439. }
  440. switch(context.html_list()) {
  441. case as_p: output<<"</p>\n"; break;
  442. case as_table: output<<"</td><tr>\n"; break;
  443. case as_ul: output<<"</li>\n"; break;
  444. case as_dl: output<<"</dd>\n"; break;
  445. case as_space:
  446. if(context.html() == as_xhtml)
  447. output<<"<br />\n";
  448. else
  449. output<<"<br>\n";
  450. break;
  451. default: ;
  452. }
  453. }
  454. void base_widget::render_attributes(form_context &context)
  455. {
  456. auto_generate(&context);
  457. std::ostream &output = context.out();
  458. if(!id_.empty()) output << "id=\"" << id_ << "\" ";
  459. if(!name_.empty()) output << "name=\"" << name_ << "\" ";
  460. if(disabled()) {
  461. if(context.html() == as_xhtml)
  462. output << "disabled=\"disabled\" ";
  463. else
  464. output << "disabled ";
  465. }
  466. }
  467. void base_widget::clear()
  468. {
  469. set(false);
  470. }
  471. bool base_widget::validate()
  472. {
  473. valid(true);
  474. return true;
  475. }
  476. ////////////////////////////////
  477. // widgets::base_text
  478. ////////////////////////////////
  479. struct base_text::data {};
  480. base_text::base_text() : low_(0),high_(-1),validate_charset_(true)
  481. {
  482. }
  483. base_text::~base_text()
  484. {
  485. }
  486. std::string base_text::value()
  487. {
  488. if(!set())
  489. throw cppcms_error("Value was not loaded");
  490. return value_;
  491. }
  492. void base_text::value(std::string v)
  493. {
  494. set(true);
  495. value_=v;
  496. }
  497. void base_text::non_empty()
  498. {
  499. limits(1,-1);
  500. }
  501. void base_text::limits(int min,int max)
  502. {
  503. low_=min;
  504. high_=max;
  505. }
  506. std::pair<int,int> base_text::limits()
  507. {
  508. return std::make_pair(low_,high_);
  509. }
  510. void base_text::validate_charset(bool v)
  511. {
  512. validate_charset_=v;
  513. }
  514. bool base_text::validate_charset()
  515. {
  516. return validate_charset_;
  517. }
  518. void base_text::load(http::context &context)
  519. {
  520. auto_generate();
  521. value_.clear();
  522. code_points_ = 0;
  523. set(false);
  524. valid(true);
  525. if(name().empty()) {
  526. return;
  527. }
  528. http::request::form_type::const_iterator p;
  529. p=context.request().post_or_get().find(name());
  530. if(p==context.request().post_or_get().end()) {
  531. return;
  532. }
  533. value_=p->second;
  534. set(true);
  535. if(validate_charset_) {
  536. code_points_ = 0;
  537. if(!encoding::valid(context.locale(),value_.data(),value_.data()+value_.size(),code_points_))
  538. valid(false);
  539. }
  540. else {
  541. code_points_=value_.size();
  542. }
  543. }
  544. bool base_text::validate()
  545. {
  546. if(!valid())
  547. return false;
  548. if(!set() && low_==0 && high_==-1) {
  549. valid(true);
  550. return true;
  551. }
  552. if(code_points_ < size_t(low_) || (high_ >=0 && code_points_ > size_t(high_))) {
  553. valid(false);
  554. return false;
  555. }
  556. return true;
  557. }
  558. //////////////////////////////////////////////
  559. /// widgets::text
  560. /////////////////////////////////////////////
  561. struct text::data {};
  562. text::~text() {}
  563. text::text(): base_html_input("text"), size_(-1) {}
  564. text::text(std::string const &type): base_html_input(type), size_(-1) {}
  565. void text::render_value(form_context &context)
  566. {
  567. if(set()) {
  568. context.out() << " value=\"" << util::escape(value()) << "\"";
  569. }
  570. }
  571. void text::render_attributes(form_context &context)
  572. {
  573. base_widget::render_attributes(context);
  574. std::ostream &output = context.out();
  575. if(size_ >= 0)
  576. output << boost::format("size=\"%1%\" ",std::locale::classic()) % size_;
  577. std::pair<int,int> lm=limits();
  578. if(lm.second >= 0 && validate_charset()) {
  579. output << boost::format("maxlength=\"%1%\" ",std::locale::classic()) % lm.second;
  580. }
  581. }
  582. struct base_html_input::data{};
  583. base_html_input::base_html_input(std::string const &type) : type_(type) {}
  584. base_html_input::~base_html_input() {}
  585. void base_html_input::render_input(form_context &context)
  586. {
  587. auto_generate(&context);
  588. std::ostream &output=context.out();
  589. if(context.widget_part() == first_part) {
  590. output<<"<input type=\""<<type_<<"\" ";
  591. render_attributes(context);
  592. render_value(context);
  593. }
  594. else {
  595. if(context.html() == as_xhtml)
  596. output<<" />";
  597. else
  598. output<<" >";
  599. }
  600. }
  601. //////////////////////////////////////////////
  602. /// widgets::textarea
  603. /////////////////////////////////////////////
  604. struct textarea::data {};
  605. textarea::textarea() : rows_(-1), cols_(-1) {}
  606. textarea::~textarea() {}
  607. int textarea::rows() { return rows_; }
  608. int textarea::cols() { return cols_; }
  609. void textarea::rows(int n) { rows_ = n; }
  610. void textarea::cols(int n) { cols_ = n; }
  611. void textarea::render_input(form_context &context)
  612. {
  613. std::ostream &output = context.out();
  614. if(context.widget_part() == first_part)
  615. {
  616. output<<"<textarea ";
  617. render_attributes(context);
  618. if(rows_ >= 0) {
  619. output<<boost::format("rows=\"%1%\"",std::locale::classic()) % rows_;
  620. }
  621. if(cols_ >= 0) {
  622. output<<boost::format("cols=\"%1%\"",std::locale::classic()) % cols_;
  623. }
  624. }
  625. else {
  626. if(set()) {
  627. output << ">"<<util::escape(value())<<"</textarea>";
  628. }
  629. else {
  630. output << "></textarea>";
  631. }
  632. }
  633. }
  634. ////////////////////////
  635. /// Password widget ///
  636. ////////////////////////
  637. struct password::data {};
  638. password::password() : text("password"), password_to_check_(0)
  639. {
  640. }
  641. password::~password()
  642. {
  643. }
  644. void password::check_equal(password &p2)
  645. {
  646. password_to_check_ = &p2;
  647. }
  648. bool password::validate()
  649. {
  650. if(!text::validate()) {
  651. value("");
  652. return false;
  653. }
  654. if(password_to_check_) {
  655. if(!password_to_check_->set() || !set() || password_to_check_->value()!=value()) {
  656. valid(false);
  657. value("");
  658. password_to_check_->value("");
  659. return false;
  660. }
  661. }
  662. return true;
  663. }
  664. struct regex_field::data {};
  665. regex_field::regex_field() : expression_(0) {}
  666. regex_field::regex_field(util::regex const &e) : expression_(&e) {}
  667. regex_field::~regex_field() {}
  668. void regex_field::regex(util::regex const &e)
  669. {
  670. expression_ = &e;
  671. }
  672. bool regex_field::validate()
  673. {
  674. if(!text::validate())
  675. return false;
  676. valid(set() && expression_->match(value()));
  677. return valid();
  678. }
  679. struct email::data {};
  680. namespace {
  681. util::regex email_regex("^[^@]+@[^@]+$");
  682. }
  683. email::email() : regex_field(email_regex) {}
  684. email::~email() {}
  685. struct checkbox::data {};
  686. checkbox::checkbox(std::string const &type) :
  687. base_html_input(type),
  688. identification_("y"),
  689. value_(false)
  690. {
  691. set(true);
  692. }
  693. checkbox::checkbox() :
  694. base_html_input("checkbox"),
  695. identification_("y"),
  696. value_(false)
  697. {
  698. set(true);
  699. }
  700. checkbox::~checkbox()
  701. {
  702. }
  703. bool checkbox::value()
  704. {
  705. return value_;
  706. }
  707. void checkbox::value(bool v)
  708. {
  709. value_=v;
  710. }
  711. void checkbox::identification(std::string const &id)
  712. {
  713. identification_=id;
  714. }
  715. std::string checkbox::identification()
  716. {
  717. return identification_;
  718. }
  719. void checkbox::render_value(form_context &context)
  720. {
  721. if(value()) {
  722. if(context.html() == as_xhtml)
  723. context.out() << " checked=\"checked\" ";
  724. else
  725. context.out() << " checked ";
  726. }
  727. context.out() << "value=\""<<util::escape(identification_)<<"\" ";
  728. }
  729. void checkbox::load(http::context &context)
  730. {
  731. auto_generate();
  732. std::pair<http::request::form_type::const_iterator,http::request::form_type::const_iterator>
  733. range=context.request().post_or_get().equal_range(name());
  734. value(false);
  735. while(range.first != range.second) {
  736. if(range.first->second == identification_) {
  737. value(true);
  738. break;
  739. }
  740. ++range.first;
  741. }
  742. }
  743. struct select_multiple::data{};
  744. select_multiple::element::element():
  745. selected(0),
  746. need_translation(0),
  747. original_select(0)
  748. {
  749. }
  750. select_multiple::element::element(std::string const &val,locale::message const &msg,bool sel) :
  751. selected(sel),
  752. need_translation(1),
  753. original_select(sel),
  754. id(val),
  755. tr_option(msg)
  756. {
  757. }
  758. select_multiple::element::element(std::string const &val,std::string const &msg,bool sel) :
  759. selected(sel),
  760. need_translation(0),
  761. original_select(sel),
  762. id(val),
  763. str_option(msg)
  764. {
  765. }
  766. select_multiple::select_multiple() :
  767. low_(0),
  768. high_(std::numeric_limits<unsigned>::max()),
  769. rows_(0)
  770. {
  771. }
  772. select_multiple::~select_multiple()
  773. {
  774. }
  775. void select_multiple::add(std::string const &opt,std::string const &id,bool selected)
  776. {
  777. elements_.push_back(element(id,opt,selected));
  778. }
  779. void select_multiple::add(locale::message const &opt,std::string const &id,bool selected)
  780. {
  781. elements_.push_back(element(id,opt,selected));
  782. }
  783. void select_multiple::add(std::string const &opt,bool selected)
  784. {
  785. std::string id=(boost::format("%1%",std::locale::classic()) % elements_.size()).str();
  786. elements_.push_back(element(id,opt,selected));
  787. }
  788. void select_multiple::add(locale::message const &opt,bool selected)
  789. {
  790. std::string id=(boost::format("%1%",std::locale::classic()) % elements_.size()).str();
  791. elements_.push_back(element(id,opt,selected));
  792. }
  793. std::vector<bool> select_multiple::selected_map()
  794. {
  795. std::vector<bool> flags(elements_.size(),false);
  796. for(unsigned i=0;i<elements_.size();i++)
  797. flags[i]=elements_[i].selected;
  798. return flags;
  799. }
  800. std::set<std::string> select_multiple::selected_ids()
  801. {
  802. std::set<std::string> ids;
  803. for(unsigned i=0;i<elements_.size();i++)
  804. if(elements_[i].selected)
  805. ids.insert(elements_[i].id);
  806. return ids;
  807. }
  808. void select_multiple::clear()
  809. {
  810. for(unsigned i=0;i<elements_.size();i++){
  811. elements_[i].selected=elements_[i].original_select;
  812. }
  813. }
  814. void select_multiple::load(http::context &context)
  815. {
  816. auto_generate();
  817. std::pair<http::request::form_type::const_iterator,http::request::form_type::const_iterator>
  818. range=context.request().post_or_get().equal_range(name());
  819. std::set<std::string> keys;
  820. for(http::request::form_type::const_iterator p=range.first;p!=range.second;++p)
  821. keys.insert(p->second);
  822. for(unsigned i=0;i<elements_.size();i++) {
  823. elements_[i].selected= keys.find(elements_[i].id) != keys.end();
  824. }
  825. }
  826. bool select_multiple::validate()
  827. {
  828. unsigned count=0;
  829. for(unsigned i=0;i<elements_.size();i++)
  830. count += elements_[i].selected;
  831. if(low_ <= count && count <= high_) {
  832. valid(true);
  833. return true;
  834. }
  835. else {
  836. valid(false);
  837. return false;
  838. }
  839. }
  840. void select_multiple::render_input(form_context &context)
  841. {
  842. auto_generate(&context);
  843. std::ostream &out=context.out();
  844. if(context.widget_part() == first_part) {
  845. if(context.html() == as_xhtml)
  846. out<<"<select multiple=\"multiple\" ";
  847. else
  848. out<<"<select multiple ";
  849. if(rows_ > 0)
  850. out << boost::format(" size=\"%1%\" ",std::locale::classic()) % rows_;
  851. render_attributes(context);
  852. }
  853. else {
  854. out<<" >\n";
  855. for(unsigned i=0;i<elements_.size();i++) {
  856. element &el=elements_[i];
  857. out << "<option value=\"" << util::escape(el.id) <<"\" ";
  858. if(el.selected) {
  859. if(context.html() == as_xhtml)
  860. out << "selected=\"selected\" ";
  861. else
  862. out << "selected ";
  863. }
  864. out << ">";
  865. if(el.need_translation)
  866. out << filters::escape(el.tr_option);
  867. else
  868. out << util::escape(el.str_option);
  869. out << "</option>\n";
  870. }
  871. out << "</select>";
  872. }
  873. }
  874. void select_multiple::non_empty()
  875. {
  876. at_least(1);
  877. }
  878. void select_multiple::at_least(unsigned l)
  879. {
  880. low_ = l;
  881. }
  882. void select_multiple::at_most(unsigned h)
  883. {
  884. high_ = h;
  885. }
  886. unsigned select_multiple::at_least()
  887. {
  888. return low_;
  889. }
  890. unsigned select_multiple::at_most()
  891. {
  892. return high_;
  893. }
  894. unsigned select_multiple::rows()
  895. {
  896. return rows_;
  897. }
  898. void select_multiple::rows(unsigned v)
  899. {
  900. rows_=v;
  901. }
  902. ////////////////////
  903. // Select base
  904. ///////////////////
  905. struct select_base::data {};
  906. struct select_base::element::data {};
  907. select_base::element::element() : need_translation(0)
  908. {
  909. }
  910. select_base::element::element(std::string const &v,std::string const &msg) :
  911. need_translation(0),
  912. id(v),
  913. str_option(msg)
  914. {
  915. }
  916. select_base::element::element(std::string const &v,locale::message const &msg) :
  917. need_translation(1),
  918. id(v),
  919. tr_option(msg)
  920. {
  921. }
  922. select_base::select_base() : selected_(-1), default_selected_(-1), non_empty_(0)
  923. {
  924. }
  925. select_base::~select_base()
  926. {
  927. }
  928. void select_base::add(std::string const &str,std::string const &id)
  929. {
  930. elements_.push_back(element(id,str));
  931. }
  932. void select_base::add(locale::message const &str,std::string const &id)
  933. {
  934. elements_.push_back(element(id,str));
  935. }
  936. void select_base::add(std::string const &str)
  937. {
  938. std::string id=(boost::format("%1%",std::locale::classic()) % elements_.size()).str();
  939. elements_.push_back(element(id,str));
  940. }
  941. void select_base::add(locale::message const &str)
  942. {
  943. std::string id=(boost::format("%1%",std::locale::classic()) % elements_.size()).str();
  944. elements_.push_back(element(id,str));
  945. }
  946. void select_base::selected(int no)
  947. {
  948. if(no >= int(elements_.size()))
  949. throw cppcms_error("select_base::invalid index");
  950. else if(no < 0) no = -1;
  951. selected_ = no;
  952. default_selected_ = no;
  953. }
  954. void select_base::selected_id(std::string id)
  955. {
  956. if(id.empty()) {
  957. selected_ = -1;
  958. default_selected_ = -1;
  959. return;
  960. }
  961. for(unsigned i=0;i<elements_.size();i++) {
  962. if(id==elements_[i].id) {
  963. selected_ = i;
  964. default_selected_ = i;
  965. return;
  966. }
  967. }
  968. throw cppcms_error("Select base::invalid index: " + id);
  969. }
  970. void select_base::clear()
  971. {
  972. selected_ = default_selected_;
  973. }
  974. void select_base::non_empty()
  975. {
  976. non_empty_ = 1;
  977. }
  978. int select_base::selected()
  979. {
  980. return selected_;
  981. }
  982. std::string select_base::selected_id()
  983. {
  984. if(selected_ < 0 || selected_ >= int(elements_.size()))
  985. return "";
  986. return elements_[selected_].id;
  987. }
  988. bool select_base::validate()
  989. {
  990. if(non_empty_ && selected_ == -1)
  991. valid(false);
  992. else
  993. valid(true);
  994. return valid();
  995. }
  996. void select_base::load(http::context &context)
  997. {
  998. auto_generate();
  999. std::pair<http::request::form_type::const_iterator,http::request::form_type::const_iterator>
  1000. range=context.request().post_or_get().equal_range(name());
  1001. selected_ = -1;
  1002. http::request::form_type::const_iterator p=range.first;
  1003. // If empty or more then one
  1004. if(range.first == range.second || (++range.first)!=range.second )
  1005. return;
  1006. std::string key = p->second;
  1007. for(unsigned i=0;i<elements_.size();i++) {
  1008. if(elements_[i].id == key) {
  1009. selected_ = i;
  1010. break;
  1011. }
  1012. }
  1013. }
  1014. ////////////////
  1015. /// select
  1016. ///////////////////
  1017. struct select::data {};
  1018. select::select() {}
  1019. select::~select() {}
  1020. void select::render_input(form_context &context)
  1021. {
  1022. auto_generate(&context);
  1023. std::ostream &out=context.out();
  1024. if(context.widget_part() == first_part) {
  1025. out<<"<select ";
  1026. render_attributes(context);
  1027. }
  1028. else {
  1029. out<<" >\n";
  1030. for(unsigned i=0;i<elements_.size();i++) {
  1031. element &el=elements_[i];
  1032. out << "<option value=\"" << util::escape(el.id) <<"\" ";
  1033. if(int(i) == selected()) {
  1034. if(context.html() == as_xhtml)
  1035. out << "selected=\"selected\" ";
  1036. else
  1037. out << "selected ";
  1038. }
  1039. out << ">";
  1040. if(el.need_translation)
  1041. out << filters::escape(el.tr_option);
  1042. else
  1043. out << util::escape(el.str_option);
  1044. out << "</option>\n";
  1045. }
  1046. out << "</select>";
  1047. }
  1048. }
  1049. ///////////////////////////
  1050. /// Radio
  1051. /////////////////////////
  1052. struct radio::data {};
  1053. radio::radio() : vertical_(1)
  1054. {
  1055. }
  1056. radio::~radio() {}
  1057. void radio::vertical(bool v)
  1058. {
  1059. vertical_ = v;
  1060. }
  1061. bool radio::vertical()
  1062. {
  1063. return vertical_;
  1064. }
  1065. void radio::render_input(form_context &context)
  1066. {
  1067. auto_generate(&context);
  1068. std::ostream &out=context.out();
  1069. if(context.widget_part() == first_part) {
  1070. out<<"<div class=\"cppcms_radio\" ";
  1071. if(!id().empty()) out << "id=\"" << id() << "\" ";
  1072. }
  1073. else {
  1074. out<<" >\n";
  1075. for(unsigned i=0;i<elements_.size();i++) {
  1076. element &el=elements_[i];
  1077. out << "<input type=\"radio\" value=\""
  1078. << util::escape(el.id) <<"\" ";
  1079. if(!name().empty()) {
  1080. out<< "name=\"" << name() << "\" ";
  1081. }
  1082. if(int(i) == selected()) {
  1083. if(context.html() == as_xhtml)
  1084. out << "checked=\"checked\" ";
  1085. else
  1086. out << "checked ";
  1087. }
  1088. if(disabled()) {
  1089. if(context.html() == as_xhtml)
  1090. out << "disabled=\"disabled\" ";
  1091. else
  1092. out << "disabled ";
  1093. }
  1094. if(context.html() == as_xhtml)
  1095. out << "/> ";
  1096. else
  1097. out << "> ";
  1098. if(el.need_translation)
  1099. out << filters::escape(el.tr_option);
  1100. else
  1101. out << util::escape(el.str_option);
  1102. if(vertical_)
  1103. if(context.html() == as_xhtml)
  1104. out << "<br/>\n";
  1105. else
  1106. out << "<br>\n";
  1107. else
  1108. out << "\n";
  1109. }
  1110. out << "</div>";
  1111. }
  1112. }
  1113. //////////////
  1114. // Submit
  1115. ////////////////
  1116. struct submit::data {};
  1117. submit::submit() :
  1118. base_html_input("submit"),
  1119. pressed_(false)
  1120. {
  1121. set(true);
  1122. }
  1123. submit::~submit()
  1124. {
  1125. }
  1126. void submit::value(std::string val)
  1127. {
  1128. value_=locale::message("#NOTRANS#" + val);
  1129. }
  1130. void submit::value(locale::message const &msg)
  1131. {
  1132. value_=msg;
  1133. }
  1134. void submit::render_value(form_context &context)
  1135. {
  1136. context.out() << "value=\"" << filters::escape(value_) << "\" ";
  1137. }
  1138. void submit::load(http::context &context)
  1139. {
  1140. auto_generate();
  1141. pressed_ = context.request().post_or_get().find(name()) != context.request().post_or_get().end();
  1142. }
  1143. bool submit::value()
  1144. {
  1145. return pressed_;
  1146. }
  1147. } // widgets
  1148. } // cppcms