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.
 
 
 
 
 
 

1562 lines
28 KiB

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