summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorxue <>2006-06-02 18:27:02 +0000
committerxue <>2006-06-02 18:27:02 +0000
commit0f3a577bed4d828472469675e90fcab032e33f44 (patch)
tree3ca817247b8006563900d5fb8995d6a6f0627a2b /framework
parent067ab51fbd9b2f18f63fc80895476e5b0e2f9bfb (diff)
merge from 3.0 branch till 1133.
Diffstat (limited to 'framework')
-rw-r--r--framework/3rdParty/Markdown/License.text34
-rw-r--r--framework/3rdParty/Markdown/MarkdownParser.php1257
-rw-r--r--framework/3rdParty/readme.html10
-rw-r--r--framework/I18N/TTranslate.php78
-rw-r--r--framework/Web/Javascripts/datepicker/datepicker.js34
-rw-r--r--framework/Web/Javascripts/js/datepicker.js14
-rw-r--r--framework/Web/Javascripts/js/prado.js2
-rw-r--r--framework/Web/Javascripts/prototype/event.js1
-rw-r--r--framework/Web/UI/TTemplateManager.php34
-rw-r--r--framework/Web/UI/WebControls/TDataBoundControl.php2
-rw-r--r--framework/Web/UI/WebControls/TMarkdown.php113
-rw-r--r--framework/Web/UI/WebControls/TRepeater.php3
-rw-r--r--framework/Web/UI/WebControls/TValidationSummary.php17
-rw-r--r--framework/Web/UI/WebControls/TWizard.php6
14 files changed, 1565 insertions, 40 deletions
diff --git a/framework/3rdParty/Markdown/License.text b/framework/3rdParty/Markdown/License.text
new file mode 100644
index 00000000..ea6a6a1a
--- /dev/null
+++ b/framework/3rdParty/Markdown/License.text
@@ -0,0 +1,34 @@
+Copyright (c) 2004-2005, John Gruber
+<http://daringfireball.net/>
+All rights reserved.
+
+Copyright (c) 2004-2005, Michel Fortin
+<http://www.michelf.com/>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name "Markdown" nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as
+is" and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed. In no event shall the copyright owner
+or contributors be liable for any direct, indirect, incidental, special,
+exemplary, or consequential damages (including, but not limited to,
+procurement of substitute goods or services; loss of use, data, or
+profits; or business interruption) however caused and on any theory of
+liability, whether in contract, strict liability, or tort (including
+negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
diff --git a/framework/3rdParty/Markdown/MarkdownParser.php b/framework/3rdParty/Markdown/MarkdownParser.php
new file mode 100644
index 00000000..c0d2becf
--- /dev/null
+++ b/framework/3rdParty/Markdown/MarkdownParser.php
@@ -0,0 +1,1257 @@
+<?php
+
+#
+# Markdown - A text-to-HTML conversion tool for web writers
+#
+# Copyright (c) 2004-2005 John Gruber
+# <http://daringfireball.net/projects/markdown/>
+#
+# Copyright (c) 2004-2005 Michel Fortin - PHP Port
+# <http://www.michelf.com/projects/php-markdown/>
+#
+
+/**
+ * PHP5 version of the markdown parser.
+ * Usage:
+ * <code>
+ * $markdown = new MarkdownParser;
+ * echo $markdown->parse($text);
+ * </code>
+ */
+class MarkdownParser
+{
+ private static $md_nested_brackets;
+ private static $md_escape_table = array();
+ private static $md_backslash_escape_table = array();
+ private static $md_nested_brackets_depth = 6;
+
+ protected $md_empty_element_suffix = " />"; # Change to ">" for HTML output
+ protected $md_tab_width = 4;
+
+ private $md_list_level = 0;
+ private $md_urls = array();
+ private $md_titles = array();
+ private $md_html_blocks = array();
+
+ public function __construct()
+ {
+ if(is_null(self::$md_nested_brackets))
+ $this->initialize();
+ }
+
+ private function initialize()
+ {
+ self::$md_nested_brackets =
+ str_repeat('(?>[^\[\]]+|\[', self::$md_nested_brackets_depth).
+ str_repeat('\])*', self::$md_nested_brackets_depth);
+
+ self::$md_escape_table = array(
+ "\\" => md5("\\"),
+ "`" => md5("`"),
+ "*" => md5("*"),
+ "_" => md5("_"),
+ "{" => md5("{"),
+ "}" => md5("}"),
+ "[" => md5("["),
+ "]" => md5("]"),
+ "(" => md5("("),
+ ")" => md5(")"),
+ ">" => md5(">"),
+ "#" => md5("#"),
+ "+" => md5("+"),
+ "-" => md5("-"),
+ "." => md5("."),
+ "!" => md5("!")
+ );
+
+ # Table of hash values for escaped characters:
+ # Create an identical table but for escaped characters.
+ foreach (self::$md_escape_table as $key => $char)
+ self::$md_backslash_escape_table["\\$key"] = $char;
+ }
+
+ public function parse($text)
+ {
+ #
+ # Main function. The order in which other subs are called here is
+ # essential. Link and image substitutions need to happen before
+ # _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
+ # and <img> tags get encoded.
+ #
+ # Clear the hashes. If we don't clear these, you get conflicts
+ # from other articles when generating a page which contains more than
+ # one article (e.g. an index page that shows the N most recent
+ # articles):
+ $this->md_urls = array();
+ $this->md_titles = array();
+ $this->md_html_blocks = array();
+
+ # Standardize line endings:
+ # DOS to Unix and Mac to Unix
+ $text = str_replace(array("\r\n", "\r"), "\n", $text);
+
+ # Make sure $text ends with a couple of newlines:
+ $text .= "\n\n";
+
+ # Convert all tabs to spaces.
+ $text = $this->_Detab($text);
+
+ # Strip any lines consisting only of spaces and tabs.
+ # This makes subsequent regexen easier to write, because we can
+ # match consecutive blank lines with /\n+/ instead of something
+ # contorted like /[ \t]*\n+/ .
+ $text = preg_replace('/^[ \t]+$/m', '', $text);
+
+ # Turn block-level HTML blocks into hash entries
+ $text = $this->_HashHTMLBlocks($text);
+
+ # Strip link definitions, store in hashes.
+ $text = $this->_StripLinkDefinitions($text);
+
+ $text = $this->_RunBlockGamut($text);
+
+ $text = $this->_UnescapeSpecialChars($text);
+
+ return $text . "\n";
+ }
+
+
+ private function _StripLinkDefinitions($text) {
+ #
+ # Strips link definitions from text, stores the URLs and titles in
+ # hash references.
+ #
+ $less_than_tab = $this->md_tab_width - 1;
+
+ # Link defs are in the form: ^[id]: url "optional title"
+ $text = preg_replace_callback('{
+ ^[ ]{0,'.$less_than_tab.'}\[(.+)\]: # id = $1
+ [ \t]*
+ \n? # maybe *one* newline
+ [ \t]*
+ <?(\S+?)>? # url = $2
+ [ \t]*
+ \n? # maybe one newline
+ [ \t]*
+ (?:
+ (?<=\s) # lookbehind for whitespace
+ ["(]
+ (.+?) # title = $3
+ [")]
+ [ \t]*
+ )? # title is optional
+ (?:\n+|\Z)
+ }xm',
+ array($this,'_StripLinkDefinitions_callback'),
+ $text);
+ return $text;
+ }
+
+ private function _StripLinkDefinitions_callback($matches) {
+ $link_id = strtolower($matches[1]);
+ $this->md_urls[$link_id] = $this->_EncodeAmpsAndAngles($matches[2]);
+ if (isset($matches[3]))
+ $this->md_titles[$link_id] = str_replace('"', '&quot;', $matches[3]);
+ return ''; # String that will replace the block
+ }
+
+
+ private function _HashHTMLBlocks($text) {
+ $less_than_tab = $this->md_tab_width - 1;
+
+ # Hashify HTML blocks:
+ # We only want to do this for block-level HTML tags, such as headers,
+ # lists, and tables. That's because we still want to wrap <p>s around
+ # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ # phrase emphasis, and spans. The list of tags we're looking for is
+ # hard-coded:
+ $block_tags_a = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
+ 'script|noscript|form|fieldset|iframe|math|ins|del';
+ $block_tags_b = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
+ 'script|noscript|form|fieldset|iframe|math';
+
+ # First, look for nested blocks, e.g.:
+ # <div>
+ # <div>
+ # tags for inner block must be indented.
+ # </div>
+ # </div>
+ #
+ # The outermost tags must start at the left margin for this to match, and
+ # the inner nested divs must be indented.
+ # We need to do this before the next, more liberal match, because the next
+ # match will start at the first `<div>` and stop at the first `</div>`.
+ $text = preg_replace_callback("{
+ ( # save in $1
+ ^ # start of line (with /m)
+ <($block_tags_a) # start tag = $2
+ \\b # word break
+ (.*\\n)*? # any number of lines, minimally matching
+ </\\2> # the matching end tag
+ [ \\t]* # trailing spaces/tabs
+ (?=\\n+|\\Z) # followed by a newline or end of document
+ )
+ }xm",
+ array($this,'_HashHTMLBlocks_callback'),
+ $text);
+
+ #
+ # Now match more liberally, simply from `\n<tag>` to `</tag>\n`
+ #
+ $text = preg_replace_callback("{
+ ( # save in $1
+ ^ # start of line (with /m)
+ <($block_tags_b) # start tag = $2
+ \\b # word break
+ (.*\\n)*? # any number of lines, minimally matching
+ .*</\\2> # the matching end tag
+ [ \\t]* # trailing spaces/tabs
+ (?=\\n+|\\Z) # followed by a newline or end of document
+ )
+ }xm",
+ array($this,'_HashHTMLBlocks_callback'),
+ $text);
+
+ # Special case just for <hr />. It was easier to make a special case than
+ # to make the other regex more complicated.
+ $text = preg_replace_callback('{
+ (?:
+ (?<=\n\n) # Starting after a blank line
+ | # or
+ \A\n? # the beginning of the doc
+ )
+ ( # save in $1
+ [ ]{0,'.$less_than_tab.'}
+ <(hr) # start tag = $2
+ \b # word break
+ ([^<>])*? #
+ /?> # the matching end tag
+ [ \t]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+ )
+ }x',
+ array($this,'_HashHTMLBlocks_callback'),
+ $text);
+
+ # Special case for standalone HTML comments:
+ $text = preg_replace_callback('{
+ (?:
+ (?<=\n\n) # Starting after a blank line
+ | # or
+ \A\n? # the beginning of the doc
+ )
+ ( # save in $1
+ [ ]{0,'.$less_than_tab.'}
+ (?s:
+ <!
+ (--.*?--\s*)+
+ >
+ )
+ [ \t]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+ )
+ }x',
+ array($this,'_HashHTMLBlocks_callback'),
+ $text);
+
+ return $text;
+ }
+ private function _HashHTMLBlocks_callback($matches) {
+ $text = $matches[1];
+ $key = md5($text);
+ $this->md_html_blocks[$key] = $text;
+ return "\n\n$key\n\n"; # String that will replace the block
+ }
+
+
+ private function _RunBlockGamut($text) {
+ #
+ # These are all the transformations that form block-level
+ # tags like paragraphs, headers, and list items.
+ #
+ $text = $this->_DoHeaders($text);
+
+ # Do Horizontal Rules:
+ $text = preg_replace(
+ array('{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}mx',
+ '{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}mx',
+ '{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}mx'),
+ "\n<hr{$this->md_empty_element_suffix}\n",
+ $text);
+
+ $text = $this->_DoLists($text);
+ $text = $this->_DoCodeBlocks($text);
+ $text = $this->_DoBlockQuotes($text);
+
+ # We already ran _HashHTMLBlocks() before, in Markdown(), but that
+ # was to escape raw HTML in the original Markdown source. This time,
+ # we're escaping the markup we've just created, so that we don't wrap
+ # <p> tags around block-level tags.
+ $text = $this->_HashHTMLBlocks($text);
+ $text = $this->_FormParagraphs($text);
+
+ return $text;
+ }
+
+
+ private function _RunSpanGamut($text) {
+ #
+ # These are all the transformations that occur *within* block-level
+ # tags like paragraphs, headers, and list items.
+ #
+
+ $text = $this->_DoCodeSpans($text);
+
+ $text = $this->_EscapeSpecialChars($text);
+
+ # Process anchor and image tags. Images must come first,
+ # because ![foo][f] looks like an anchor.
+ $text = $this->_DoImages($text);
+ $text = $this->_DoAnchors($text);
+
+ # Make links out of things like `<http://example.com/>`
+ # Must come after _DoAnchors(), because you can use < and >
+ # delimiters in inline links like [this](<url>).
+ $text = $this->_DoAutoLinks($text);
+ $text = $this->_EncodeAmpsAndAngles($text);
+ $text = $this->_DoItalicsAndBold($text);
+
+ # Do hard breaks:
+ $text = preg_replace('/ {2,}\n/', "<br{$this->md_empty_element_suffix}\n", $text);
+
+ return $text;
+ }
+
+
+ private function _EscapeSpecialChars($text) {
+ $tokens = $this->_TokenizeHTML($text);
+
+ $text = ''; # rebuild $text from the tokens
+ # $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags.
+ # $tags_to_skip = "!<(/?)(?:pre|code|kbd|script|math)[\s>]!";
+
+ foreach ($tokens as $cur_token) {
+ if ($cur_token[0] == 'tag') {
+ # Within tags, encode * and _ so they don't conflict
+ # with their use in Markdown for italics and strong.
+ # We're replacing each such character with its
+ # corresponding MD5 checksum value; this is likely
+ # overkill, but it should prevent us from colliding
+ # with the escape values by accident.
+ $cur_token[1] = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $cur_token[1]);
+ $text .= $cur_token[1];
+ } else {
+ $t = $cur_token[1];
+ $t = $this->_EncodeBackslashEscapes($t);
+ $text .= $t;
+ }
+ }
+ return $text;
+ }
+
+
+ private function _DoAnchors($text) {
+ #
+ # Turn Markdown link shortcuts into XHTML <a> tags.
+ #
+ #
+ # First, handle reference-style links: [link text] [id]
+ #
+ $bracket = self::$md_nested_brackets;
+ $text = preg_replace_callback("{
+ ( # wrap whole match in $1
+ \\[
+ ({$bracket}) # link text = $2
+ \\]
+
+ [ ]? # one optional space
+ (?:\\n[ ]*)? # one optional newline followed by spaces
+
+ \\[
+ (.*?) # id = $3
+ \\]
+ )
+ }xs",
+ array($this,'_DoAnchors_reference_callback'), $text);
+
+ #
+ # Next, inline-style links: [link text](url "optional title")
+ #
+ $text = preg_replace_callback("{
+ ( # wrap whole match in $1
+ \\[
+ ({$bracket}) # link text = $2
+ \\]
+ \\( # literal paren
+ [ \\t]*
+ <?(.*?)>? # href = $3
+ [ \\t]*
+ ( # $4
+ (['\"]) # quote char = $5
+ (.*?) # Title = $6
+ \\5 # matching quote
+ )? # title is optional
+ \\)
+ )
+ }xs",
+ array($this,'_DoAnchors_inline_callback'), $text);
+
+ return $text;
+ }
+ private function _DoAnchors_reference_callback($matches) {
+ $whole_match = $matches[1];
+ $link_text = $matches[2];
+ $link_id = strtolower($matches[3]);
+
+ if ($link_id == "") {
+ $link_id = strtolower($link_text); # for shortcut links like [this][].
+ }
+
+ if (isset($this->md_urls[$link_id])) {
+ $url = $this->md_urls[$link_id];
+ # We've got to encode these to avoid conflicting with italics/bold.
+ $url = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $url);
+ $result = "<a href=\"$url\"";
+ if ( isset( $this->md_titles[$link_id] ) ) {
+ $title = $this->md_titles[$link_id];
+ $title = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'],
+ self::$md_escape_table['_']), $title);
+ $result .= " title=\"$title\"";
+ }
+ $result .= ">$link_text</a>";
+ }
+ else {
+ $result = $whole_match;
+ }
+ return $result;
+ }
+ private function _DoAnchors_inline_callback($matches) {
+ $whole_match = $matches[1];
+ $link_text = $matches[2];
+ $url = $matches[3];
+ $title =& $matches[6];
+
+ # We've got to encode these to avoid conflicting with italics/bold.
+ $url = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $url);
+ $result = "<a href=\"$url\"";
+ if (isset($title)) {
+ $title = str_replace('"', '&quot;', $title);
+ $title = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $title);
+ $result .= " title=\"$title\"";
+ }
+
+ $result .= ">$link_text</a>";
+
+ return $result;
+ }
+
+
+ private function _DoImages($text) {
+ #
+ # Turn Markdown image shortcuts into <img> tags.
+ #
+ #
+ # First, handle reference-style labeled images: ![alt text][id]
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ !\[
+ ('.self::$md_nested_brackets.') # alt text = $2
+ \]
+
+ [ ]? # one optional space
+ (?:\n[ ]*)? # one optional newline followed by spaces
+
+ \[
+ (.*?) # id = $3
+ \]
+
+ )
+ }xs',
+ array($this,'_DoImages_reference_callback'), $text);
+
+ #
+ # Next, handle inline images: ![alt text](url "optional title")
+ # Don't forget: encode * and _
+
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ !\[
+ ('.self::$md_nested_brackets.') # alt text = $2
+ \]
+ \( # literal paren
+ [ \t]*
+ <?(\S+?)>? # src url = $3
+ [ \t]*
+ ( # $4
+ ([\'"]) # quote char = $5
+ (.*?) # title = $6
+ \5 # matching quote
+ [ \t]*
+ )? # title is optional
+ \)
+ )
+ }xs',
+ array($this,'_DoImages_inline_callback'), $text);
+
+ return $text;
+ }
+ private function _DoImages_reference_callback($matches) {
+ $whole_match = $matches[1];
+ $alt_text = $matches[2];
+ $link_id = strtolower($matches[3]);
+
+ if ($link_id == "") {
+ $link_id = strtolower($alt_text); # for shortcut links like ![this][].
+ }
+
+ $alt_text = str_replace('"', '&quot;', $alt_text);
+ if (isset($this->md_urls[$link_id])) {
+ $url = $this->md_urls[$link_id];
+ # We've got to encode these to avoid conflicting with italics/bold.
+ $url = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $url);
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
+ if (isset($this->md_titles[$link_id])) {
+ $title = $this->md_titles[$link_id];
+ $title = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'],
+ self::$md_escape_table['_']), $title);
+ $result .= " title=\"$title\"";
+ }
+ $result .= $this->md_empty_element_suffix;
+ }
+ else {
+ # If there's no such link ID, leave intact:
+ $result = $whole_match;
+ }
+
+ return $result;
+ }
+ private function _DoImages_inline_callback($matches) {
+ $whole_match = $matches[1];
+ $alt_text = $matches[2];
+ $url = $matches[3];
+ $title = '';
+ if (isset($matches[6])) {
+ $title = $matches[6];
+ }
+
+ $alt_text = str_replace('"', '&quot;', $alt_text);
+ $title = str_replace('"', '&quot;', $title);
+ # We've got to encode these to avoid conflicting with italics/bold.
+ $url = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $url);
+ $result = "<img src=\"$url\" alt=\"$alt_text\"";
+ if (isset($title)) {
+ $title = str_replace(array('*', '_'),
+ array(self::$md_escape_table['*'], self::$md_escape_table['_']),
+ $title);
+ $result .= " title=\"$title\""; # $title already quoted
+ }
+ $result .= $this->md_empty_element_suffix;
+
+ return $result;
+ }
+
+
+ private function _DoHeaders($text) {
+ # Setext-style headers:
+ # Header 1
+ # ========
+ #
+ # Header 2
+ # --------
+ #
+ $text = preg_replace(
+ array('{ ^(.+)[ \t]*\n=+[ \t]*\n+ }emx',
+ '{ ^(.+)[ \t]*\n-+[ \t]*\n+ }emx'),
+ array("'<h1>'.\$this->_RunSpanGamut(\$this->_UnslashQuotes('\\1')).'</h1>\n\n'",
+ "'<h2>'.\$this->_RunSpanGamut(\$this->_UnslashQuotes('\\1')).'</h2>\n\n'"),
+ $text);
+
+ # atx-style headers:
+ # # Header 1
+ # ## Header 2
+ # ## Header 2 with closing hashes ##
+ # ...
+ # ###### Header 6
+ #
+ $text = preg_replace("{
+ ^(\\#{1,6}) # $1 = string of #'s
+ [ \\t]*
+ (.+?) # $2 = Header text
+ [ \\t]*
+ \\#* # optional closing #'s (not counted)
+ \\n+
+ }xme",
+ "'<h'.strlen('\\1').'>'.\$this->_RunSpanGamut(\$this->_UnslashQuotes('\\2')).'</h'.strlen('\\1').'>\n\n'",
+ $text);
+
+ return $text;
+ }
+
+
+ private function _DoLists($text) {
+ #
+ # Form HTML ordered (numbered) and unordered (bulleted) lists.
+ #
+ $less_than_tab = $this->md_tab_width - 1;
+
+ # Re-usable patterns to match list item bullets and number markers:
+ $marker_ul = '[*+-]';
+ $marker_ol = '\d+[.]';
+ $marker_any = "(?:$marker_ul|$marker_ol)";
+
+ $markers = array($marker_ul, $marker_ol);
+
+ foreach ($markers as $marker) {
+ # Re-usable pattern to match any entirel ul or ol list:
+ $whole_list = '
+ ( # $1 = whole list
+ ( # $2
+ [ ]{0,'.$less_than_tab.'}
+ ('.$marker.') # $3 = first list item marker
+ [ \t]+
+ )
+ (?s:.+?)
+ ( # $4
+ \z
+ |
+ \n{2,}
+ (?=\S)
+ (?! # Negative lookahead for another list item marker
+ [ \t]*
+ '.$marker.'[ \t]+
+ )
+ )
+ )
+ '; // mx
+
+ # We use a different prefix before nested lists than top-level lists.
+ # See extended comment in _ProcessListItems().
+
+ if ($this->md_list_level) {
+ $text = preg_replace_callback('{
+ ^
+ '.$whole_list.'
+ }mx',
+ array($this,'_DoLists_callback_top'), $text);
+ }
+ else {
+ $text = preg_replace_callback('{
+ (?:(?<=\n\n)|\A\n?)
+ '.$whole_list.'
+ }mx',
+ array($this,'_DoLists_callback_nested'), $text);
+ }
+ }
+
+ return $text;
+ }
+ private function _DoLists_callback_top($matches) {
+ # Re-usable patterns to match list item bullets and number markers:
+ $marker_ul = '[*+-]';
+ $marker_ol = '\d+[.]';
+ $marker_any = "(?:$marker_ul|$marker_ol)";
+
+ $list = $matches[1];
+ $list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol";
+
+ $marker_any = ( $list_type == "ul" ? $marker_ul : $marker_ol );
+
+ # Turn double returns into triple returns, so that we can make a
+ # paragraph for the last item in a list, if necessary:
+ $list = preg_replace("/\n{2,}/", "\n\n\n", $list);
+ $result = $this->_ProcessListItems($list, $marker_any);
+
+ # Trim any trailing whitespace, to put the closing `</$list_type>`
+ # up on the preceding line, to get it past the current stupid
+ # HTML block parser. This is a hack to work around the terrible
+ # hack that is the HTML block parser.
+ $result = rtrim($result);
+ $result = "<$list_type>" . $result . "</$list_type>\n";
+ return $result;
+ }
+ private function _DoLists_callback_nested($matches) {
+ # Re-usable patterns to match list item bullets and number markers:
+ $marker_ul = '[*+-]';
+ $marker_ol = '\d+[.]';
+ $marker_any = "(?:$marker_ul|$marker_ol)";
+
+ $list = $matches[1];
+ $list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol";
+
+ $marker_any = ( $list_type == "ul" ? $marker_ul : $marker_ol );
+
+ # Turn double returns into triple returns, so that we can make a
+ # paragraph for the last item in a list, if necessary:
+ $list = preg_replace("/\n{2,}/", "\n\n\n", $list);
+ $result = $this->_ProcessListItems($list, $marker_any);
+ $result = "<$list_type>\n" . $result . "</$list_type>\n";
+ return $result;
+ }
+
+
+ private function _ProcessListItems($list_str, $marker_any) {
+ #
+ # Process the contents of a single ordered or unordered list, splitting it
+ # into individual list items.
+ #
+
+ # The $md_list_level keeps track of when we're inside a list.
+ # Each time we enter a list, we increment it; when we leave a list,
+ # we decrement. If it's zero, we're not in a list anymore.
+ #
+ # We do this because when we're not inside a list, we want to treat
+ # something like this:
+ #
+ # I recommend upgrading to version
+ # 8. Oops, now this line is treated
+ # as a sub-list.
+ #
+ # As a single paragraph, despite the fact that the second line starts
+ # with a digit-period-space sequence.
+ #
+ # Whereas when we're inside a list (or sub-list), that line will be
+ # treated as the start of a sub-list. What a kludge, huh? This is
+ # an aspect of Markdown's syntax that's hard to parse perfectly
+ # without resorting to mind-reading. Perhaps the solution is to
+ # change the syntax rules such that sub-lists must start with a
+ # starting cardinal number; e.g. "1." or "a.".
+
+ $this->md_list_level++;
+
+ # trim trailing blank lines:
+ $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
+
+ $list_str = preg_replace_callback('{
+ (\n)? # leading line = $1
+ (^[ \t]*) # leading whitespace = $2
+ ('.$marker_any.') [ \t]+ # list marker = $3
+ ((?s:.+?) # list item text = $4
+ (\n{1,2}))
+ (?= \n* (\z | \2 ('.$marker_any.') [ \t]+))
+ }xm',
+ array($this,'_ProcessListItems_callback'), $list_str);
+
+ $this->md_list_level--;
+ return $list_str;
+ }
+ private function _ProcessListItems_callback($matches) {
+ $item = $matches[4];
+ $leading_line =& $matches[1];
+ $leading_space =& $matches[2];
+
+ if ($leading_line || preg_match('/\n{2,}/', $item)) {
+ $item = $this->_RunBlockGamut($this->_Outdent($item));
+ }
+ else {
+ # Recursion for sub-lists:
+ $item = $this->_DoLists($this->_Outdent($item));
+ $item = preg_replace('/\n+$/', '', $item);
+ $item = $this->_RunSpanGamut($item);
+ }
+
+ return "<li>" . $item . "</li>\n";
+ }
+
+
+ private function _DoCodeBlocks($text) {
+ #
+ # Process Markdown `<pre><code>` blocks.
+ #
+ $text = preg_replace_callback('{
+ (?:\n\n|\A)
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
+ (?:
+ (?:[ ]{'.$this->md_tab_width.'} | \t) # Lines must start with a tab or a tab-width of spaces
+ .*\n+
+ )+
+ )
+ ((?=^[ ]{0,'.$this->md_tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
+ }xm',
+ array($this,'_DoCodeBlocks_callback'), $text);
+
+ return $text;
+ }
+ private function _DoCodeBlocks_callback($matches) {
+ $codeblock = $matches[1];
+
+ $codeblock = $this->_EncodeCode($this->_Outdent($codeblock));
+ // $codeblock = _Detab($codeblock);
+ # trim leading newlines and trailing whitespace
+ $codeblock = preg_replace(array('/\A\n+/', '/\s+\z/'), '', $codeblock);
+
+ $result = "\n\n<pre><code>" . $codeblock . "\n</code></pre>\n\n";
+
+ return $result;
+ }
+
+
+ private function _DoCodeSpans($text) {
+ #
+ # * Backtick quotes are used for <code></code> spans.
+ #
+ # * You can use multiple backticks as the delimiters if you want to
+ # include literal backticks in the code span. So, this input:
+ #
+ # Just type ``foo `bar` baz`` at the prompt.
+ #
+ # Will translate to:
+ #
+ # <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
+ #
+ # There's no arbitrary limit to the number of backticks you
+ # can use as delimters. If you need three consecutive backticks
+ # in your code, use four for delimiters, etc.
+ #
+ # * You can use spaces to get literal backticks at the edges:
+ #
+ # ... type `` `bar` `` ...
+ #
+ # Turns to:
+ #
+ # ... type <code>`bar`</code> ...
+ #
+ $text = preg_replace_callback('@
+ (?<!\\\) # Character before opening ` can\'t be a backslash
+ (`+) # $1 = Opening run of `
+ (.+?) # $2 = The code block
+ (?<!`)
+ \1 # Matching closer
+ (?!`)
+ @xs',
+ array($this,'_DoCodeSpans_callback'), $text);
+
+ return $text;
+ }
+ private function _DoCodeSpans_callback($matches) {
+ $c = $matches[2];
+ $c = preg_replace('/^[ \t]*/', '', $c); # leading whitespace
+ $c = preg_replace('/[ \t]*$/', '', $c); # trailing whitespace
+ $c = $this->_EncodeCode($c);
+ return "<code>$c</code>";
+ }
+
+
+ private function _EncodeCode($_) {
+ #
+ # Encode/escape certain characters inside Markdown code runs.
+ # The point is that in code, these characters are literals,
+ # and lose their special Markdown meanings.
+ #
+ # Encode all ampersands; HTML entities are not
+ # entities within a Markdown code span.
+ $_ = str_replace('&', '&amp;', $_);
+
+ # Do the angle bracket song and dance:
+ $_ = str_replace(array('<', '>'),
+ array('&lt;', '&gt;'), $_);
+
+ # Now, escape characters that are magic in Markdown:
+ $_ = str_replace(array_keys(self::$md_escape_table),
+ array_values(self::$md_escape_table), $_);
+
+ return $_;
+ }
+
+
+ private function _DoItalicsAndBold($text) {
+ # <strong> must go first:
+ $text = preg_replace('{
+ ( # $1: Marker
+ (?<!\*\*) \*\* | # (not preceded by two chars of
+ (?<!__) __ # the same marker)
+ )
+ (?=\S) # Not followed by whitespace
+ (?!\1) # or two others marker chars.
+ ( # $2: Content
+ (?:
+ [^*_]+? # Anthing not em markers.
+ |
+ # Balence any regular emphasis inside.
+ ([*_]) (?=\S) .+? (?<=\S) \3 # $3: em char (* or _)
+ |
+ (?! \1 ) . # Allow unbalenced * and _.
+ )+?
+ )
+ (?<=\S) \1 # End mark not preceded by whitespace.
+ }sx',
+ '<strong>\2</strong>', $text);
+ # Then <em>:
+ $text = preg_replace(
+ '{ ( (?<!\*)\* | (?<!_)_ ) (?=\S) (?! \1) (.+?) (?<=\S) \1 }sx',
+ '<em>\2</em>', $text);
+
+ return $text;
+ }
+
+
+ private function _DoBlockQuotes($text) {
+ $text = preg_replace_callback('/
+ ( # Wrap whole match in $1
+ (
+ ^[ \t]*>[ \t]? # ">" at the start of a line
+ .+\n # rest of the first line
+ (.+\n)* # subsequent consecutive lines
+ \n* # blanks
+ )+
+ )
+ /xm',
+ array($this,'_DoBlockQuotes_callback'), $text);
+
+ return $text;
+ }
+ private function _DoBlockQuotes_callback($matches) {
+ $bq = $matches[1];
+ # trim one level of quoting - trim whitespace-only lines
+ $bq = preg_replace(array('/^[ \t]*>[ \t]?/m', '/^[ \t]+$/m'), '', $bq);
+ $bq = $this->_RunBlockGamut($bq); # recurse
+
+ $bq = preg_replace('/^/m', " ", $bq);
+ # These leading spaces screw with <pre> content, so we need to fix that:
+ $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
+ array($this,'_DoBlockQuotes_callback2'), $bq);
+
+ return "<blockquote>\n$bq\n</blockquote>\n\n";
+ }
+ private function _DoBlockQuotes_callback2($matches) {
+ $pre = $matches[1];
+ $pre = preg_replace('/^ /m', '', $pre);
+ return $pre;
+ }
+
+
+ private function _FormParagraphs($text) {
+ #
+ # Params:
+ # $text - string to process with html <p> tags
+ #
+ # Strip leading and trailing lines:
+ $text = preg_replace(array('/\A\n+/', '/\n+\z/'), '', $text);
+
+ $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
+
+ #
+ # Wrap <p> tags.
+ #
+ foreach ($grafs as $key => $value) {
+ if (!isset( $this->md_html_blocks[$value] )) {
+ $value = $this->_RunSpanGamut($value);
+ $value = preg_replace('/^([ \t]*)/', '<p>', $value);
+ $value .= "</p>";
+ $grafs[$key] = $value;
+ }
+ }
+
+ #
+ # Unhashify HTML blocks
+ #
+ foreach ($grafs as $key => $value) {
+ if (isset( $this->md_html_blocks[$value] )) {
+ $grafs[$key] = $this->md_html_blocks[$value];
+ }
+ }
+
+ return implode("\n\n", $grafs);
+ }
+
+
+ private function _EncodeAmpsAndAngles($text) {
+ # Smart processing for ampersands and angle brackets that need to be encoded.
+
+ # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
+ # http://bumppo.net/projects/amputator/
+ $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
+ '&amp;', $text);;
+
+ # Encode naked <'s
+ $text = preg_replace('{<(?![a-z/?\$!])}i', '&lt;', $text);
+
+ return $text;
+ }
+
+
+ private function _EncodeBackslashEscapes($text) {
+ #
+ # Parameter: String.
+ # Returns: The string, with after processing the following backslash
+ # escape sequences.
+ #
+ # Must process escaped backslashes first.
+ return str_replace(array_keys(self::$md_backslash_escape_table),
+ array_values(self::$md_backslash_escape_table), $text);
+ }
+
+
+ private function _DoAutoLinks($text) {
+ $text = preg_replace("!<((https?|ftp):[^'\">\\s]+)>!",
+ '<a href="\1">\1</a>', $text);
+
+ # Email addresses: <address@domain.foo>
+ $text = preg_replace('{
+ <
+ (?:mailto:)?
+ (
+ [-.\w]+
+ \@
+ [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
+ )
+ >
+ }exi',
+ "\$this->_EncodeEmailAddress(\$this->_UnescapeSpecialChars(\$this->_UnslashQuotes('\\1')))",
+ $text);
+
+ return $text;
+ }
+
+
+ private function _EncodeEmailAddress($addr) {
+ #
+ # Input: an email address, e.g. "foo@example.com"
+ #
+ # Output: the email address as a mailto link, with each character
+ # of the address encoded as either a decimal or hex entity, in
+ # the hopes of foiling most address harvesting spam bots. E.g.:
+ #
+ # <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
+ # x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
+ # &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
+ #
+ # Based by a filter by Matthew Wickline, posted to the BBEdit-Talk
+ # mailing list: <http://tinyurl.com/yu7ue>
+ #
+ $addr = "mailto:" . $addr;
+ $length = strlen($addr);
+
+ # leave ':' alone (to spot mailto: later)
+ $addr = preg_replace_callback('/([^\:])/',
+ array($this,'_EncodeEmailAddress_callback'), $addr);
+
+ $addr = "<a href=\"$addr\">$addr</a>";
+ # strip the mailto: from the visible part
+ $addr = preg_replace('/">.+?:/', '">', $addr);
+
+ return $addr;
+ }
+ private function _EncodeEmailAddress_callback($matches) {
+ $char = $matches[1];
+ $r = rand(0, 100);
+ # roughly 10% raw, 45% hex, 45% dec
+ # '@' *must* be encoded. I insist.
+ if ($r > 90 && $char != '@') return $char;
+ if ($r < 45) return '&#x'.dechex(ord($char)).';';
+ return '&#'.ord($char).';';
+ }
+
+
+ private function _UnescapeSpecialChars($text) {
+ #
+ # Swap back in all the special characters we've hidden.
+ #
+ return str_replace(array_values(self::$md_escape_table),
+ array_keys(self::$md_escape_table), $text);
+ }
+
+
+ # _TokenizeHTML is shared between PHP Markdown and PHP SmartyPants.
+ # We only define it if it is not already defined.
+
+ private function _TokenizeHTML($str) {
+ #
+ # Parameter: String containing HTML markup.
+ # Returns: An array of the tokens comprising the input
+ # string. Each token is either a tag (possibly with nested,
+ # tags contained therein, such as <a href="<MTFoo>">, or a
+ # run of text between tags. Each element of the array is a
+ # two-element array; the first is either 'tag' or 'text';
+ # the second is the actual value.
+ #
+ #
+ # Regular expression derived from the _tokenize() subroutine in
+ # Brad Choate's MTRegex plugin.
+ # <http://www.bradchoate.com/past/mtregex.php>
+ #
+ $index = 0;
+ $tokens = array();
+
+ $match = '(?s:<!(?:--.*?--\s*)+>)|'. # comment
+ '(?s:<\?.*?\?>)|'. # processing instruction
+ # regular tags
+ '(?:<[/!$]?[-a-zA-Z0-9:]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)';
+
+ $parts = preg_split("{($match)}", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ foreach ($parts as $part) {
+ if (++$index % 2 && $part != '')
+ $tokens[] = array('text', $part);
+ else
+ $tokens[] = array('tag', $part);
+ }
+
+ return $tokens;
+ }
+
+ private function _Outdent($text) {
+ #
+ # Remove one level of line-leading tabs or spaces
+ #
+ return preg_replace("/^(\\t|[ ]{1,".$this->md_tab_width."})/m", "", $text);
+ }
+
+
+ private function _Detab($text) {
+ #
+ # Replace tabs with the appropriate amount of space.
+ #
+ # For each line we separate the line in blocks delemited by
+ # tab characters. Then we reconstruct every line by adding the
+ # appropriate number of space between each blocks.
+
+ $lines = explode("\n", $text);
+ $text = "";
+
+ foreach ($lines as $line) {
+ # Split in blocks.
+ $blocks = explode("\t", $line);
+ # Add each blocks to the line.
+ $line = $blocks[0];
+ unset($blocks[0]); # Do not add first block twice.
+ foreach ($blocks as $block) {
+ # Calculate amount of space, insert spaces, insert block.
+ $amount = $this->md_tab_width - strlen($line) % $this->md_tab_width;
+ $line .= str_repeat(" ", $amount) . $block;
+ }
+ $text .= "$line\n";
+ }
+ return $text;
+ }
+
+
+ private function _UnslashQuotes($text) {
+ #
+ # This function is useful to remove automaticaly slashed double quotes
+ # when using preg_replace and evaluating an expression.
+ # Parameter: String.
+ # Returns: The string with any slash-double-quote (\") sequence replaced
+ # by a single double quote.
+ #
+ return str_replace('\"', '"', $text);
+ }
+}
+
+/*
+
+PHP Markdown
+============
+
+Description
+-----------
+
+This is a PHP translation of the original Markdown formatter written in
+Perl by John Gruber.
+
+Markdown is a text-to-HTML filter; it translates an easy-to-read /
+easy-to-write structured text format into HTML. Markdown's text format
+is most similar to that of plain text email, and supports features such
+as headers, *emphasis*, code blocks, blockquotes, and links.
+
+Markdown's syntax is designed not as a generic markup language, but
+specifically to serve as a front-end to (X)HTML. You can use span-level
+HTML tags anywhere in a Markdown document, and you can use block level
+HTML tags (like <div> and <table> as well).
+
+For more information about Markdown's syntax, see:
+
+<http://daringfireball.net/projects/markdown/>
+
+
+Bugs
+----
+
+To file bug reports please send email to:
+
+<michel.fortin@michelf.com>
+
+Please include with your report: (1) the example input; (2) the output you
+expected; (3) the output Markdown actually produced.
+
+
+Version History
+---------------
+
+See the readme file for detailed release notes for this version.
+
+1.0.1c - 9 Dec 2005
+
+1.0.1b - 6 Jun 2005
+
+1.0.1a - 15 Apr 2005
+
+1.0.1 - 16 Dec 2004
+
+1.0 - 21 Aug 2004
+
+
+Author & Contributors
+---------------------
+
+Original Perl version by John Gruber
+<http://daringfireball.net/>
+
+PHP port and other contributions by Michel Fortin
+<http://www.michelf.com/>
+
+
+Copyright and License
+---------------------
+
+Copyright (c) 2004-2005 Michel Fortin
+<http://www.michelf.com/>
+All rights reserved.
+
+Copyright (c) 2003-2004 John Gruber
+<http://daringfireball.net/>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name "Markdown" nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as
+is" and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed. In no event shall the copyright owner
+or contributors be liable for any direct, indirect, incidental, special,
+exemplary, or consequential damages (including, but not limited to,
+procurement of substitute goods or services; loss of use, data, or
+profits; or business interruption) however caused and on any theory of
+liability, whether in contract, strict liability, or tort (including
+negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+*/
+?>
diff --git a/framework/3rdParty/readme.html b/framework/3rdParty/readme.html
index f67526ae..590f1174 100644
--- a/framework/3rdParty/readme.html
+++ b/framework/3rdParty/readme.html
@@ -133,7 +133,15 @@ projects.
<td>Slightly modified to work nicely with E_STRICT in php 5.</td>
</tr>
+<tr>
+ <td><a href="Markdown">Markdown</a></td>
+ <td><a href="http://www.michelf.com/projects/php-markdown/">PHP Markdown</a></td>
+ <td><a href="Markdown/License.text">BSD</a></td>
+ <td>System.Web.UI.WebControls.TMarkdown</td>
+ <td>PHP5 class implementation of the PHP Markdown.</td>
+</tr>
+
</table>
</p>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/framework/I18N/TTranslate.php b/framework/I18N/TTranslate.php
index 6a30f3a6..da5876d4 100644
--- a/framework/I18N/TTranslate.php
+++ b/framework/I18N/TTranslate.php
@@ -28,19 +28,19 @@ Prado::using('System.I18N.TI18NControl');
* Depending on the culture set on the page, the phrase "Goodbye" will
* be translated.
*
- * The values of any attribute in TTranslate are consider as values for
- * substitution. Strings enclosed with "{" and "}" are consider as the
- * parameters. The following example will substitution the string
- * "{time}" with the value of the attribute "time="#time()". Note that
- * the value of the attribute time is evaluated.
+ * The {@link getParameters Parameters} property can be use to add name values pairs for
+ * substitution. Substrings enclosed with "{" and "}" in the translation message are consider as the
+ * parameter names during substitution lookup. The following example will substitute the substring
+ * "{time}" with the value of the parameter attribute "Parameters.time=<%= time() %>. Note that
+ * the value of the parameter named "time" is evaluated.
* <code>
- * <com:TTranslate time="#time()">
+ * <com:TTranslate Parameters.time=<%= time() %> >
* The unix-time is "{time}".
* </com:TTranslate>
* </code>
*
* More complex string substitution can be applied using the
- * TParam component.
+ * TTranslateParameter component.
*
* Namespace: System.I18N
*
@@ -134,6 +134,68 @@ class TTranslate extends TI18NControl
}
/**
+ * Returns the list of custom parameters.
+ * Custom parameters are name-value pairs that may subsititute translation
+ * place holders during rendering.
+ * @return TAttributeCollection the list of custom parameters
+ */
+ public function getParameters()
+ {
+ if($parameters=$this->getViewState('Parameters',null))
+ return $parameters;
+ else
+ {
+ $parameters=new TAttributeCollection;
+ $this->setViewState('Parameters',$parameters,null);
+ return $parameters;
+ }
+ }
+
+ /**
+ * @return boolean whether the named parameter exists
+ */
+ public function hasParameter($name)
+ {
+ if($parameters=$this->getViewState('Parameters',null))
+ return $parameters->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string parameter value, null if parameter does not exist
+ */
+ public function getParameter($name)
+ {
+ if($parameters=$this->getViewState('Parameters',null))
+ return $parameters->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * @param string parameter name
+ * @param string value of the parameter
+ */
+ public function setParameter($name,$value)
+ {
+ $this->getParameters()->add($name,$value);
+ }
+
+ /**
+ * Removes the named parameter.
+ * @param string the name of the parameter to be removed.
+ * @return string parameter value removed, null if parameter does not exist.
+ */
+ public function removeParameter($name)
+ {
+ if($parameters=$this->getViewState('Parameters',null))
+ return $parameters->remove($name);
+ else
+ return null;
+ }
+
+ /**
* renders the translated string.
*/
public function render($writer)
@@ -141,6 +203,8 @@ class TTranslate extends TI18NControl
$textWriter=new TTextWriter;
$htmlWriter=new THtmlWriter($textWriter);
$subs = array();
+ foreach($this->getParameters() as $key => $value)
+ $subs['{'.$key.'}'] = $value;
foreach($this->getControls() as $control)
{
if($control instanceof TTranslateParameter)
diff --git a/framework/Web/Javascripts/datepicker/datepicker.js b/framework/Web/Javascripts/datepicker/datepicker.js
index d5d9496c..e704e950 100644
--- a/framework/Web/Javascripts/datepicker/datepicker.js
+++ b/framework/Web/Javascripts/datepicker/datepicker.js
@@ -282,8 +282,11 @@ Prado.WebUI.TDatePicker.prototype =
Event.observe(this._calDiv, "mousewheel", this.mouseWheelChange.bindEvent(this));
Event.observe(calendarBody, "click", this.selectDate.bindEvent(this));
+
+ Event.observe(this.control, "blur", this.hide.bind(this));
+ Prado.Element.focus(this.control);
- },
+ },A
ieHack : function(cleanup)
{
@@ -305,7 +308,7 @@ Prado.WebUI.TDatePicker.prototype =
if (!ev) ev = document.parentWindow.event;
var kc = ev.keyCode != null ? ev.keyCode : ev.charCode;
- if(kc == Event.KEY_RETURN)
+ if(kc == Event.KEY_RETURN || kc == Event.KEY_SPACEBAR)
{
this.setSelectedDate(this.selectedDate);
Event.stop(ev);
@@ -526,6 +529,22 @@ Prado.WebUI.TDatePicker.prototype =
this.setMonth(this.selectedDate.getMonth()-1);
},
+ getDatePickerOffsetHeight : function()
+ {
+ if(this.options.InputMode == "TextBox")
+ return this.control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ if(control) return control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ if(control) return control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ if(control) return control.offsetHeight;
+ return 0;
+ },
+
show : function()
{
this.create();
@@ -534,15 +553,8 @@ Prado.WebUI.TDatePicker.prototype =
{
var pos = Position.cumulativeOffset(this.control);
- if(this.options.InputMode == "TextBox")
- pos[1] += this.control.offsetHeight;
- else
- {
- var dayList = Prado.WebUI.TDatePicker.getDayListControl(this.control);
- if(dayList)
- pos[1] += dayList.offsetHeight-1;
- }
-
+ pos[1] += this.getDatePickerOffsetHeight();
+
this._calDiv.style.display = "block";
this._calDiv.style.top = (pos[1]-1) + "px";
this._calDiv.style.left = pos[0] + "px";
diff --git a/framework/Web/Javascripts/js/datepicker.js b/framework/Web/Javascripts/js/datepicker.js
index a81bbeb4..e0bba502 100644
--- a/framework/Web/Javascripts/js/datepicker.js
+++ b/framework/Web/Javascripts/js/datepicker.js
@@ -23,10 +23,10 @@ div=document.createElement("div");div.className="calendarFooter";this._calDiv.ap
this.iePopUp.scrolling="no"
this.iePopUp.frameBorder="0"
document.body.appendChild(this.iePopUp);}
-document.body.appendChild(this._calDiv);this.update();this.updateHeader();this.ieHack(true);previousMonth.hideFocus=true;nextMonth.hideFocus=true;todayButton.hideFocus=true;Event.observe(previousMonth,"click",this.prevMonth.bindEvent(this));Event.observe(nextMonth,"click",this.nextMonth.bindEvent(this));Event.observe(todayButton,"click",this.selectToday.bindEvent(this));Event.observe(this._monthSelect,"change",this.monthSelect.bindEvent(this));Event.observe(this._yearSelect,"change",this.yearSelect.bindEvent(this));Event.observe(this._calDiv,"mousewheel",this.mouseWheelChange.bindEvent(this));Event.observe(calendarBody,"click",this.selectDate.bindEvent(this));},ieHack:function(cleanup)
+document.body.appendChild(this._calDiv);this.update();this.updateHeader();this.ieHack(true);previousMonth.hideFocus=true;nextMonth.hideFocus=true;todayButton.hideFocus=true;Event.observe(previousMonth,"click",this.prevMonth.bindEvent(this));Event.observe(nextMonth,"click",this.nextMonth.bindEvent(this));Event.observe(todayButton,"click",this.selectToday.bindEvent(this));Event.observe(this._monthSelect,"change",this.monthSelect.bindEvent(this));Event.observe(this._yearSelect,"change",this.yearSelect.bindEvent(this));Event.observe(this._calDiv,"mousewheel",this.mouseWheelChange.bindEvent(this));Event.observe(calendarBody,"click",this.selectDate.bindEvent(this));Event.observe(this.control,"blur",this.hide.bind(this));Prado.Element.focus(this.control);},ieHack:function(cleanup)
{if(this.iePopUp)
{this.iePopUp.style.display="block";this.iePopUp.style.top=(this._calDiv.offsetTop-1)+"px";this.iePopUp.style.left=(this._calDiv.offsetLeft-1)+"px";this.iePopUp.style.width=Math.abs(this._calDiv.offsetWidth-2)+"px";this.iePopUp.style.height=(this._calDiv.offsetHeight+1)+"px";if(cleanup)this.iePopUp.style.display="none";}},keyPressed:function(ev)
-{if(!this.showing)return;if(!ev)ev=document.parentWindow.event;var kc=ev.keyCode!=null?ev.keyCode:ev.charCode;if(kc==Event.KEY_RETURN)
+{if(!this.showing)return;if(!ev)ev=document.parentWindow.event;var kc=ev.keyCode!=null?ev.keyCode:ev.charCode;if(kc==Event.KEY_RETURN||kc==Event.KEY_SPACEBAR)
{this.setSelectedDate(this.selectedDate);Event.stop(ev);this.hide();}
if(kc==Event.KEY_ESC)
{Event.stop(ev);this.hide();}
@@ -88,13 +88,11 @@ this.onChange();},getElement:function()
{var d=this.newDate(this.selectedDate);d.setFullYear(year);this.setSelectedDate(d);},setMonth:function(month)
{var d=this.newDate(this.selectedDate);d.setMonth(month);this.setSelectedDate(d);},nextMonth:function()
{this.setMonth(this.selectedDate.getMonth()+1);},prevMonth:function()
-{this.setMonth(this.selectedDate.getMonth()-1);},show:function()
+{this.setMonth(this.selectedDate.getMonth()-1);},getDatePickerOffsetHeight:function()
+{if(this.options.InputMode=="TextBox")
+return this.control.offsetHeight;var control=Prado.WebUI.TDatePicker.getDayListControl(this.control);if(control)return control.offsetHeight;var control=Prado.WebUI.TDatePicker.getMonthListControl(this.control);if(control)return control.offsetHeight;var control=Prado.WebUI.TDatePicker.getYearListControl(this.control);if(control)return control.offsetHeight;return 0;},show:function()
{this.create();if(!this.showing)
-{var pos=Position.cumulativeOffset(this.control);if(this.options.InputMode=="TextBox")
-pos[1]+=this.control.offsetHeight;else
-{var dayList=Prado.WebUI.TDatePicker.getDayListControl(this.control);if(dayList)
-pos[1]+=dayList.offsetHeight-1;}
-this._calDiv.style.display="block";this._calDiv.style.top=(pos[1]-1)+"px";this._calDiv.style.left=pos[0]+"px";this.ieHack(false);this.documentClickEvent=this.hideOnClick.bindEvent(this);this.documentKeyDownEvent=this.keyPressed.bindEvent(this);Event.observe(document.body,"click",this.documentClickEvent);var date=this.getDateFromInput();if(date)
+{var pos=Position.cumulativeOffset(this.control);pos[1]+=this.getDatePickerOffsetHeight();this._calDiv.style.display="block";this._calDiv.style.top=(pos[1]-1)+"px";this._calDiv.style.left=pos[0]+"px";this.ieHack(false);this.documentClickEvent=this.hideOnClick.bindEvent(this);this.documentKeyDownEvent=this.keyPressed.bindEvent(this);Event.observe(document.body,"click",this.documentClickEvent);var date=this.getDateFromInput();if(date)
{this.selectedDate=date;this.setSelectedDate(date);}
Event.observe(document,"keydown",this.documentKeyDownEvent);this.showing=true;}},getDateFromInput:function()
{if(this.options.InputMode=="TextBox")
diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js
index aa02e98e..87fd69a6 100644
--- a/framework/Web/Javascripts/js/prado.js
+++ b/framework/Web/Javascripts/js/prado.js
@@ -111,7 +111,7 @@ this.registerFormCallbacks();else
this.registerCallback(this.element);},onElementEvent:function(){var value=this.getValue();if(this.lastValue!=value){this.callback(this.element,value);this.lastValue=value;}},registerFormCallbacks:function(){var elements=Form.getElements(this.element);for(var i=0;i<elements.length;i++)
this.registerCallback(elements[i]);},registerCallback:function(element){if(element.type){switch(element.type.toLowerCase()){case'checkbox':case'radio':Event.observe(element,'click',this.onElementEvent.bind(this));break;case'password':case'text':case'textarea':case'select-one':case'select-multiple':Event.observe(element,'change',this.onElementEvent.bind(this));break;}}}}
Form.Element.EventObserver=Class.create();Form.Element.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.Element.getValue(this.element);}});Form.EventObserver=Class.create();Form.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.serialize(this.element);}});if(!window.Event){var Event=new Object();}
-Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},pointerX:function(event){return event.pageX||(event.clientX+
+Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_SPACEBAR:32,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},pointerX:function(event){return event.pageX||(event.clientX+
(document.documentElement.scrollLeft||document.body.scrollLeft));},pointerY:function(event){return event.pageY||(event.clientY+
(document.documentElement.scrollTop||document.body.scrollTop));},stop:function(event){if(event.preventDefault){event.preventDefault();event.stopPropagation();}else{event.returnValue=false;event.cancelBubble=true;}},findElement:function(event,tagName){var element=Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
element=element.parentNode;return element;},observers:false,_observeAndCache:function(element,name,observer,useCapture){if(!this.observers)this.observers=[];if(element.addEventListener){this.observers.push([element,name,observer,useCapture]);element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){this.observers.push([element,name,observer,useCapture]);element.attachEvent('on'+name,observer);}},unloadCache:function(){if(!Event.observers)return;for(var i=0;i<Event.observers.length;i++){Event.stopObserving.apply(this,Event.observers[i]);Event.observers[i][0]=null;}
diff --git a/framework/Web/Javascripts/prototype/event.js b/framework/Web/Javascripts/prototype/event.js
index 51b9010e..4def0e4a 100644
--- a/framework/Web/Javascripts/prototype/event.js
+++ b/framework/Web/Javascripts/prototype/event.js
@@ -12,6 +12,7 @@ Object.extend(Event, {
KEY_RIGHT: 39,
KEY_DOWN: 40,
KEY_DELETE: 46,
+ KEY_SPACEBAR: 32,
element: function(event) {
return event.target || event.srcElement;
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 60ce11ca..cb05fa35 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -383,16 +383,37 @@ class TTemplate extends TApplicationComponent implements ITemplate
* @param string property name
* @param mixed property initial value
*/
+ protected function configureControl2($control,$name,$value)
+ {
+ if(strncasecmp($name,'on',2)===0) // is an event
+ $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
+ $this->configureProperty($control,$name,$value);
+ else // is a subproperty
+ {
+ $subName=substr($name,$pos+1);
+ if(strncasecmp($subName,'on',2)===0) // is an event: XXX.YYY.OnZZZ
+ {
+ $object=$control->getSubProperty(substr($name,0,$pos));
+ if(($object instanceof TControl))
+ $this->configureEvent($object,$subName,$value,$control);
+ else
+ $this->configureSubProperty($control,$name,$value);
+ }
+ else
+ $this->configureSubProperty($control,$name,$value);
+ }
+ }
+
protected function configureControl($control,$name,$value)
{
if(strncasecmp($name,'on',2)===0) // is an event
- $this->configureEvent($control,$name,$value);
- else if(strpos($name,'.')===false) // is a simple property or custom attribute
+ $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
$this->configureProperty($control,$name,$value);
else // is a subproperty
$this->configureSubProperty($control,$name,$value);
}
-
/**
* Configures a property of a non-control component.
* @param TComponent component to be configured
@@ -412,13 +433,14 @@ class TTemplate extends TApplicationComponent implements ITemplate
* @param TControl control to be configured
* @param string event name
* @param string event handler
+ * @param TControl context control
*/
- protected function configureEvent($component,$name,$value)
+ protected function configureEvent($control,$name,$value,$contextControl)
{
if(strpos($value,'.')===false)
- $component->attachEventHandler($name,array($component,'TemplateControl.'.$value));
+ $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
else
- $component->attachEventHandler($name,array($component,$value));
+ $control->attachEventHandler($name,array($contextControl,$value));
}
/**
diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php
index 0bb771bf..9e6ecbf3 100644
--- a/framework/Web/UI/WebControls/TDataBoundControl.php
+++ b/framework/Web/UI/WebControls/TDataBoundControl.php
@@ -59,7 +59,7 @@ abstract class TDataBoundControl extends TWebControl
*/
public function setDataSource($value)
{
- $this->_dataSource=$this->validateDataSource($value);;
+ $this->_dataSource=$this->validateDataSource($value);
$this->onDataSourceChanged();
}
diff --git a/framework/Web/UI/WebControls/TMarkdown.php b/framework/Web/UI/WebControls/TMarkdown.php
new file mode 100644
index 00000000..49660b4e
--- /dev/null
+++ b/framework/Web/UI/WebControls/TMarkdown.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * TMarkdown class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TMarkdown class
+ *
+ * TMarkdown is a control that produces HTML from code with markdown syntax.
+ *
+ * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
+ * you to write using an easy-to-read, easy-to-write plain text format, then
+ * convert it to structurally valid XHTML (or HTML).
+ * Further documentation regarding Markdown can be found at
+ * http://daringfireball.net/projects/markdown/
+ *
+ * To use TMarkdown, simply enclose the content to be rendered within
+ * the body of TMarkdown in a template.
+ *
+ * See http://www.pradosoft.com/demos/quickstart/?page=Markdown for
+ * details on the Markdown syntax usage.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMarkdown extends TControl
+{
+ /**
+ * @var TTextHighlighter
+ */
+ private $_highlighter;
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by removing
+ * malicious javascript code from the body content
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $textWriter=new TTextWriter;
+ parent::render(new THtmlWriter($textWriter));
+ $writer->write($this->renderMarkdown($textWriter->flush()));
+ }
+
+ /**
+ * Use MarkdownParser to render the HTML content.
+ * @param string markdown content
+ * @return string HTML content
+ */
+ protected function renderMarkdown($text)
+ {
+ $renderer = Prado::createComponent('System.3rdParty.Markdown.MarkdownParser');
+ $result = $renderer->parse($text);
+ return preg_replace_callback(
+ '/<pre><code>\[\s*(\w+)\s*\]\n+((.|\n)*?)\s*<\\/code><\\/pre>/im',
+ array($this, 'highlightCode'), $result);
+ }
+
+ /**
+ * @return TTextHighlighter source code highlighter
+ */
+ public function getTextHighlighter()
+ {
+ if(is_null($this->_highlighter))
+ $this->_highlighter = new TTextHighlighter;
+ return $this->_highlighter;
+ }
+
+
+ /**
+ * Highlights source code using TTextHighlighter
+ * @param array matches of code blocks
+ * @return string highlighted code.
+ */
+ protected function highlightCode($matches)
+ {
+ $text = new TTextWriter;
+ $writer = new THtmlWriter($text);
+ $hi = $this->getTextHighlighter();
+ if($hi->getControls()->getCount() > 0)
+ $hi->getControls()->removeAt(0);
+ $hi->addParsedObject(html_entity_decode($matches[2]));
+ $hi->setLanguage($matches[1]);
+ $hi->render($writer);
+ return $text->flush();
+ }
+
+ /**
+ * Registers css style for the highlighted result.
+ * This method overrides parent implementation.
+ * @param THtmlWriter writer
+ */
+ public function onPreRender($writer)
+ {
+ parent::onPreRender($writer);
+ $hi = $this->getTextHighlighter();
+ $this->getControls()->insertAt(0,$hi);
+ $hi->onPreRender($writer);
+ $this->getControls()->removeAt(0);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TRepeater.php b/framework/Web/UI/WebControls/TRepeater.php
index 1acdc766..9aa7af8d 100644
--- a/framework/Web/UI/WebControls/TRepeater.php
+++ b/framework/Web/UI/WebControls/TRepeater.php
@@ -11,9 +11,10 @@
*/
/**
- * Using TDataBoundControl cass
+ * Using TDataBoundControl and TDataFieldAccessor cass
*/
Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
/**
* TRepeater class
diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php
index 8148036b..cfb57c5b 100644
--- a/framework/Web/UI/WebControls/TValidationSummary.php
+++ b/framework/Web/UI/WebControls/TValidationSummary.php
@@ -223,9 +223,24 @@ class TValidationSummary extends TWebControl
{
if(!$this->getEnabled(true) || !$this->getEnableClientScript())
return;
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript('validator');
+
+ //need to register the validation manager is validation summary is alone.
+ $formID=$this->getPage()->getForm()->getClientID();
+ $scriptKey = "TBaseValidator:$formID";
+ if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey))
+ {
+ $manager['FormID'] = $formID;
+ $options = TJavaScript::encode($manager);
+ $cs->registerPradoScript('validator');
+ $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
+ }
+
+
$options=TJavaScript::encode($this->getClientScriptOptions());
$script = "new Prado.WebUI.TValidationSummary({$options});";
- $this->getPage()->getClientScript()->registerEndScript($this->getClientID(), $script);
+ $cs->registerEndScript($this->getClientID(), $script);
}
/**
diff --git a/framework/Web/UI/WebControls/TWizard.php b/framework/Web/UI/WebControls/TWizard.php
index 2d2815ba..811c4e76 100644
--- a/framework/Web/UI/WebControls/TWizard.php
+++ b/framework/Web/UI/WebControls/TWizard.php
@@ -622,7 +622,7 @@ class TWizard extends TWebControl implements INamingContainer
}
/**
- * @var TWizardNavigationContainer container of the start navigation
+ * @return TWizardNavigationContainer container of the start navigation
*/
public function getStartNavigation()
{
@@ -630,7 +630,7 @@ class TWizard extends TWebControl implements INamingContainer
}
/**
- * @var TWizardNavigationContainer container of the step navigation
+ * @return TWizardNavigationContainer container of the step navigation
*/
public function getStepNavigation()
{
@@ -638,7 +638,7 @@ class TWizard extends TWebControl implements INamingContainer
}
/**
- * @var TWizardNavigationContainer container of the finish navigation
+ * @return TWizardNavigationContainer container of the finish navigation
*/
public function getFinishNavigation()
{