0byt3m1n1
Path:
/
data
/
applications
/
aps.bak
/
sugarcrm
/
6.5.16-25
/
standard
/
htdocs
/
include
/
SugarHtml
/
[
Home
]
File: SugarHtml.php
<?php if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); /********************************************************************************* * SugarCRM Community Edition is a customer relationship management program developed by * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by the * Free Software Foundation with the addition of the following permission added * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along with * this program; if not, see http://www.gnu.org/licenses or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by * SugarCRM" logo. If the display of the logo is not reasonably feasible for * technical reasons, the Appropriate Legal Notices must display the words * "Powered by SugarCRM". ********************************************************************************/ /** * SugarHtml is a static class that provides a collection of helper methods for creating HTML DOM elements. * * @auther Justin Park(jpark@sugarcrm.com) * */ class SugarHtml { const SINGLE_QUOTE = "'"; const DOUBLE_QUOTE = '"'; const ASSIGN_SIGN = "="; const HTML_TAG_BEGIN = "<"; const HTML_TAG_END = ">"; const SMARTY_TAG_BEGIN = "{"; const SMARTY_TAG_END = "}"; const CLAUSE_TAG_BEGIN = "("; const CLAUSE_TAG_END = ")"; /** * @var integer the counter for generating automatic input field names. */ public static $count=0; /** * @static * Create an open html element * * @param String $tagName - the tag name * @param array $params - the element attributes * @param bool $self_closing - whether the element is self-closing or not * @return string - generated html string */ public static function createOpenTag($tagName, $params = array(), $self_closing = false) { $self_closing_tag = ($self_closing) ? "/" : ""; if(empty($params)) return "<{$tagName}{$self_closing_tag}>"; $options = self::createAttributes($params); return "<{$tagName} {$options}{$self_closing_tag}>"; } /** * @static * Create a close html element * * @param String $tagName - the tag name * @return string - generated html string */ public static function createCloseTag($tagName) { return "</{$tagName}>"; } /** * @static * Create a html block given a cascade array tree. * Resemble the array form generated by parseHtmlTag * @see SugarHtml::parseHtmlTag * * @param array $dom_tree - Cascade array form * <pre> * 1. Simple html format * array( * 'tag' => 'div', * // all attributes are assigned in key-value form * 'id' => 'div_id', * 'class' => 'wrapper', * ... * ) * * 2. Cascade html format * array( * 'tag' => 'div', * //all subitems are assigned in container * 'container' => array( * array( * 'tag' => 'input', * 'type' => 'hidden', * ) * ) * ) * * 3. Siblings * array( * //all siblings are assigned in a parallel array form * array('tag' => 'input', 'type' => 'button', ... ), * array('tag' => 'input', 'type' => 'submit', ... ) * ) * * 4. Smarty * array( * 'smarty' => array( * array( * //smarty must contain 'template'. Container will replace with the same key value * 'template' => '{if}[CONTENT1]{else}[CONTENT2]{/if}', * //content1 will be assign on the lefthand side, and content2 will be on righthand side * '[CONTENT1]' => array( * //cascade valid array form * ) * '[CONTENT2]' => array(...) * ), * ) * ) * </pre> * * @return string - generated html string */ public static function createHtml($dom_tree = array()) { $out = ""; if(isset($dom_tree[0])) { //dom contains sibling items foreach($dom_tree as $dom) { $out .= is_array($dom) ? self::createHtml($dom) : $dom; } } else if( isset($dom_tree['tag']) ) { $tagName = $dom_tree['tag']; $self_closing = $dom_tree['self_closing']; unset($dom_tree['tag']); unset($dom_tree['self_closing']); if(isset($dom_tree['container'])) { $container = $dom_tree['container']; unset($dom_tree['container']); } $out .= self::HTML_TAG_BEGIN."{$tagName} "; if(isset($dom_tree['smarty'])) { $out .= self::createHtml(array( 'smarty' => $dom_tree['smarty'] )).' '; unset($dom_tree['smarty']); } $out .= self::createHtml($dom_tree); if($self_closing) { $out .= '/>'; } else{ $out .= self::HTML_TAG_END; $out .= (is_array($container)) ? self::createHtml($container) : $container; $out .= self::createCloseTag($tagName); } } else if( isset($dom_tree['smarty']) ) { //dom contains smarty function $count = 0; foreach($dom_tree['smarty'] as $blocks) { $template = $blocks['template']; unset($blocks['template']); $replacement = array(); foreach($blocks as $key => $value) { $replacement[$key] = is_array($value) ? self::createHtml($value) : $value; } if($count++ > 0) $out .= ' '; $out .= strtr($template, $replacement); } } else { $count = 0; foreach($dom_tree as $attr => $value) { if($count++ > 0) $out .= ' '; $out .= (empty($value)) ? $attr : $attr.'="'.$value.'"'; } } return $out; } public static function parseSugarHtml($sugar_html = array()) { $output = array(); $input_types = array( 'submit', 'button', 'hidden', 'checkbox', 'input' ); if(in_array($sugar_html['type'], $input_types)) { $sugar_html['htmlOptions']['type'] = (empty($sugar_html['htmlOptions']['type'])) ? $sugar_html['type'] : $sugar_html['htmlOptions']['type']; $sugar_html['htmlOptions']['value'] = $sugar_html['value']; $output = array_merge(array( 'tag' => 'input', 'self_closing' => true, ), $sugar_html['htmlOptions']); } if(isset($sugar_html['template'])) { $output = array( 'smarty' => array( array( 'template' => $sugar_html['template'], '[CONTENT]' => $output ) ) ); } return $output; } /** * @static * Disassemble an html string into a cascaded array form elements * * @param String $code - html string (support the mixed html string with smarty blocks) * @param array $appendTo - Precedent siblings * @return array - structual array form, can be restored in a html code by createHtml * @see SugarHtml::createHtml */ public static function parseHtmlTag($code, $appendTo = array()) { $code = ltrim($code); $start_pos = strpos($code, ' ') ? strpos($code, ' ') : strpos($code, self::HTML_TAG_END); $output = array(); if(substr($code, 0, 1) != self::HTML_TAG_BEGIN || $start_pos === false) { $offset = 0; self::parseSmartyTag($code, $output, $offset); $remainder = ltrim(substr($code, $offset)); if(!empty($remainder)) { array_push($appendTo, $output); return self::parseHtmlTag($remainder, $appendTo); } } else { $tag = substr($code, 1, $start_pos - 1); $closing_tag = '</'.$tag; $end_pos = strpos($code, $closing_tag, $start_pos + 1); $output['tag'] = $tag; if($end_pos === false) { $output['self_closing'] = true; $code = substr($code, $start_pos + 1); } else { $output['self_closing'] = false; $code = substr($code, $start_pos + 1, $end_pos - $start_pos - 1); } $remainder = self::extractAttributes($code, $output); if(!empty($remainder)) { array_push($appendTo, $output); return self::parseHtmlTag($remainder, $appendTo); } } return (empty($appendTo)) ? $output : array_merge($appendTo, array($output)); } /** * @static * Disassemble a smarty string into a cascaded array form elements * * @param String $code - smarty encoded string * @param Array $output - parsed attribute * @param int $offset * @param bool $is_attr - whether current smarty block is inside html attributes or not */ public static function parseSmartyTag($code, &$output, &$offset = 0, $is_attr = false) { if(empty($output['smarty'])) $output['smarty'] = array(); $_str = ltrim(substr($code, $offset + 1)); preg_match("/^[$\w]+/", $_str, $statement); $_smarty_closing = self::SMARTY_TAG_BEGIN.'/'.$statement[0]; $_left = strlen($statement[0]); $_right = strpos($code, $_smarty_closing, $offset); if($_right === false) { //smarty closed itself $_right = strpos($code, self::SMARTY_TAG_END, $offset); } else { preg_match_all('/\{( |)+'.substr($_str, 0, $_left).'/', substr($_str, 0, $_right), $matches); $match_count = count($matches[0]); while($match_count-- > 0) { $_right = strpos($code, $_smarty_closing, $_right + strlen($_smarty_closing)); } $_right = strpos($code, self::SMARTY_TAG_END, $_right); } $smarty_string = substr($code, $offset, $_right + 1 - $offset); $clauses = array_slice( //split into each clause preg_split("/[\{\}]/i", $smarty_string), 1, -1 //slice out the first and last items, which is empty. ); $smarty_template = array( 'template' => '', ); //Concatenate smarty variables $reserved_strings = array( '$', 'ldelim', 'rdelim' ); $reserved_functions = array( 'literal' => false, 'nocache' => false, ); $queue = 0; $is_literal = false; $current_literal_string = ''; for($seq = 0; $seq < count($clauses); $seq++) { $is_reserved = false; $current_literal_string = !empty($current_literal_string) ? $current_literal_string : (isset($reserved_functions[trim($clauses[$seq])]) ? trim($clauses[$seq]) : ''); $is_literal = $is_literal || !empty($current_literal_string); foreach($reserved_strings as $str) { if(substr(ltrim($clauses[$seq]), 0, strlen($str)) == $str) { $is_reserved = true; break; } } if($is_literal || ($seq > 0 && $is_reserved)) { if($queue == 0) $clauses[$queue] = self::SMARTY_TAG_BEGIN.$clauses[$seq].self::SMARTY_TAG_END; else $clauses[--$queue] .= self::SMARTY_TAG_BEGIN.$clauses[$seq].self::SMARTY_TAG_END; $is_literal = $is_literal && (substr(ltrim($clauses[$seq]), 0, strlen("/".$current_literal_string)) != "/".$current_literal_string); $current_literal_string = ($is_literal) ? $current_literal_string : ''; if($seq < count($clauses) - 1) { $clauses[$queue++] .= $clauses[++$seq]; } else { $queue++; } } else { $clauses[$queue++] = $clauses[$seq]; } } array_splice($clauses, $queue); //Split phrases for the conditional statement $count = 0; $queue = 0; for($seq = 0; $seq < count($clauses); $seq++) { if ($seq > 0 && substr(ltrim($clauses[$seq]), 0, 2) == 'if') { $count++; } if($count > 0) { $clauses[--$queue] .= ($seq % 2 == 0) ? self::SMARTY_TAG_BEGIN.$clauses[$seq].self::SMARTY_TAG_END : $clauses[$seq]; if($seq < count($clauses)) { $clauses[$queue++] .= $clauses[++$seq]; } } else { $clauses[$queue++] = $clauses[$seq]; } if ( $seq > 0 && substr(ltrim($clauses[$seq - 1]), 0, 3) == '/if') { $count--; } } array_splice($clauses, $queue); //resemble the smarty phases $seq = 0; foreach($clauses as $index => $clause) { if($index % 2 == 0) { if(self::SMARTY_TAG_BEGIN == substr($clause, 0, 1) && self::SMARTY_TAG_END == substr($clause, -1, 1)) $smarty_template['template'] .= $clause; else $smarty_template['template'] .= '{'.$clause.'}'; } else if( !empty($clause) ){ $key = '[CONTENT'.($seq++).']'; $smarty_template['template'] .= $key; $params = array(); if($is_attr) self::extractAttributes($clause, $params); else $params = self::parseHtmlTag($clause); $smarty_template[$key] = $params; } } $output['smarty'][] = $smarty_template; $offset = $_right + 1; } /** * @static * Disassemble an html attributes into a key-value array form * * @param String $code - attribute string (i.e. - id='form_id' name='button' value='View Detail' ...) * @param Array $output - Parsed the attribute into key-value form * @return string - Remainder string by spliting with ">" */ public static function extractAttributes($code, &$output) { $var_assign = false; $quote_encoded = false; $smarty_encoded = false; $cache = array(); $code = rtrim($code); for($i = 0; $i < strlen($code) ; $i ++) { $char = $code[$i]; if( !$smarty_encoded && ($char == self::SINGLE_QUOTE || $char == self::DOUBLE_QUOTE) ) { if(empty($quote_type)) { $quote_encoded = true; $quote_type = $char; } else if ($quote_type == $char) { if(!empty($cache)) { $string = implode('', $cache); if(empty($var_name)) { $var_name = $string; } else if($var_assign) { $output[trim($var_name)] = $string; unset($var_name); } } $quote_type = ''; $var_assign = false; $cache = array(); $quote_encoded = false; } else { array_push($cache, $char); } } else if ( $quote_encoded && $char == self::SMARTY_TAG_BEGIN ) { $smarty_encoded = true; array_push($cache, $char); } else if ( $quote_encoded && $char == self::SMARTY_TAG_END ) { $smarty_encoded = false; array_push($cache, $char); } else if ( !$quote_encoded && $char == ' ' ) { if(!empty($cache)) { $string = implode('', $cache); if(empty($var_name)) { $var_name = $string; } else if($var_assign) { $output[trim($var_name)] = $string; unset($var_name); } $quote_encoded = false; $var_assign = false; $cache = array(); } } else if ( !$quote_encoded && $char == self::ASSIGN_SIGN ) { if(!empty($var_name)) { $output[$var_name] = ''; } $string = implode('', $cache); if(trim($string) != "") { $var_name = $string; } $var_assign = true; $cache = array(); } else if ( !$quote_encoded && $char == self::SMARTY_TAG_BEGIN) { self::parseSmartyTag($code, $output, $i, true); } else if ( !$quote_encoded && $char == self::HTML_TAG_END ) { break; } else { array_push($cache, $char); } } if(!empty($cache)) { $var_name = implode('', $cache); $output[$var_name] = ''; } if(isset($output['self_closing']) && $output['self_closing'] === false) { $output['container'] = self::parseHtmlTag(substr($code, $i + 1)); return ''; } return substr($code, $i + 1); } /** * @static * Creates HTML attribute elements corresponding key-value pair. * * @param Array $params - Attributes (key-value pair) * @return string - Generated html attribute string */ public static function createAttributes($params) { $options = ""; foreach($params as $attr => $value) { if(is_numeric($attr) === false) { $attr = trim($attr); if($value) $options .= $attr.'="'.$value.'" '; elseif(!empty($attr)) $options .= $attr.' '; } } return $options; } }