Adding multibyte support to TextHelper::truncate, fixes #5610

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@7842 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
mariano.iglesias 2008-11-08 00:07:17 +00:00
parent 5bd8dbb3ca
commit 8da2a5208f
2 changed files with 42 additions and 33 deletions

View file

@ -35,6 +35,10 @@ if (!class_exists('HtmlHelper')) {
App::import('Helper', 'Html');
}
if (!class_exists('Multibyte')) {
App::import('Core', 'Multibyte');
}
/**
* Text helper library.
*
@ -167,27 +171,27 @@ class TextHelper extends AppHelper {
extract($ending);
}
if ($considerHtml) {
if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
return $text;
}
$totalLength = strlen($ending);
$totalLength = mb_strlen($ending);
$openTags = array();
$truncate = '';
preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER);
foreach ($tags as $tag) {
if (preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
} else if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
array_unshift($openTags, $tag[2]);
} else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
$pos = array_search($closeTag[1], $openTags);
if ($pos !== false) {
array_splice($openTags, $pos, 1);
if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
array_unshift($openTags, $tag[2]);
} else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
$pos = array_search($closeTag[1], $openTags);
if ($pos !== false) {
array_splice($openTags, $pos, 1);
}
}
}
$truncate .= $tag[1];
$contentLength = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
$contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
if ($contentLength + $totalLength > $length) {
$left = $length - $totalLength;
$entitiesLength = 0;
@ -195,14 +199,14 @@ class TextHelper extends AppHelper {
foreach ($entities[0] as $entity) {
if ($entity[1] + 1 - $entitiesLength <= $left) {
$left--;
$entitiesLength += strlen($entity[0]);
$entitiesLength += mb_strlen($entity[0]);
} else {
break;
}
}
}
$truncate .= substr($tag[3], 0 , $left + $entitiesLength);
$truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength);
break;
} else {
$truncate .= $tag[3];
@ -214,17 +218,17 @@ class TextHelper extends AppHelper {
}
} else {
if (strlen($text) <= $length) {
if (mb_strlen($text) <= $length) {
return $text;
} else {
$truncate = substr($text, 0, $length - strlen($ending));
$truncate = mb_substr($text, 0, $length - strlen($ending));
}
}
if (!$exact) {
$spacepos = strrpos($truncate, ' ');
$spacepos = mb_strrpos($truncate, ' ');
if (isset($spacepos)) {
if ($considerHtml) {
$bits = substr($truncate, $spacepos);
$bits = mb_substr($truncate, $spacepos);
preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
if (!empty($droppedTags)) {
foreach ($droppedTags as $closingTag) {
@ -234,7 +238,7 @@ class TextHelper extends AppHelper {
}
}
}
$truncate = substr($truncate, 0, $spacepos);
$truncate = mb_substr($truncate, 0, $spacepos);
}
}

View file

@ -35,14 +35,14 @@ App::import('Helper', 'Text');
class TextTest extends CakeTestCase {
/**
* helper property
*
*
* @var mixed null
* @access public
*/
var $helper = null;
/**
* setUp method
*
*
* @access public
* @return void
*/
@ -51,7 +51,7 @@ class TextTest extends CakeTestCase {
}
/**
* testTruncate method
*
*
* @access public
* @return void
*/
@ -65,7 +65,9 @@ class TextTest extends CakeTestCase {
$text3 = '<b>&copy; 2005-2007, Cake Software Foundation, Inc.</b><br />written by Alexander Wegener';
$text4 = '<img src="mypic.jpg"> This image tag is not XHTML conform!<br><hr/><b>But the following image tag should be conform <img src="mypic.jpg" alt="Me, myself and I" /></b><br />Great, or?';
$text5 = '0<b>1<i>2<span class="myclass">3</span>4<u>5</u>6</i>7</b>8<b>9</b>0';
$text6 = "<p><strong>Extra dates have been announced for this year's tour.</strong></p><p>Tickets for the new shows in</p>";
$text6 = '<p><strong>Extra dates have been announced for this year\'s tour.</strong></p><p>Tickets for the new shows in</p>';
$text7 = 'El moño está en el lugar correcto. Eso fue lo que dijo la niña, ¿habrá dicho la verdad?';
$text8 = 'Vive la R'.chr(195).chr(169).'publique de France';
$this->assertIdentical($this->Text->{$m}($text1, 15), 'The quick br...');
$this->assertIdentical($this->Text->{$m}($text1, 15, '...', false), 'The quick...');
@ -87,6 +89,9 @@ class TextTest extends CakeTestCase {
$this->assertIdentical($this->Text->{$m}($text5, 6, '', true, true), '0<b>1<i>2<span class="myclass">3</span>4<u>5</u></i></b>');
$this->assertIdentical($this->Text->{$m}($text5, 20, '', true, true), $text5);
$this->assertIdentical($this->Text->{$m}($text6, 57, '...', false, true), "<p><strong>Extra dates have been announced for this year's...</strong></p>");
$this->assertIdentical($this->Text->{$m}($text7, 255), $text7);
$this->assertIdentical($this->Text->{$m}($text7, 15), 'El moño está...');
$this->assertIdentical($this->Text->{$m}($text8, 15), 'Vive la R'.chr(195).chr(169).'pu...');
if ($this->method == 'truncate') {
$this->method = 'trim';
@ -95,7 +100,7 @@ class TextTest extends CakeTestCase {
}
/**
* testHighlight method
*
*
* @access public
* @return void
*/
@ -119,7 +124,7 @@ class TextTest extends CakeTestCase {
}
/**
* testHighlightConsiderHtml method
*
*
* @access public
* @return void
*/
@ -134,7 +139,7 @@ class TextTest extends CakeTestCase {
}
/**
* testStripLinks method
*
*
* @access public
* @return void
*/
@ -161,7 +166,7 @@ class TextTest extends CakeTestCase {
}
/**
* testAutoLink method
*
*
* @access public
* @return void
*/
@ -178,7 +183,7 @@ class TextTest extends CakeTestCase {
}
/**
* testAutoLinkUrls method
*
*
* @access public
* @return void
*/
@ -216,7 +221,7 @@ class TextTest extends CakeTestCase {
}
/**
* testAutoLinkEmails method
*
*
* @access public
* @return void
*/
@ -238,7 +243,7 @@ class TextTest extends CakeTestCase {
}
/**
* testHighlightCaseInsensitivity method
*
*
* @access public
* @return void
*/
@ -254,7 +259,7 @@ class TextTest extends CakeTestCase {
}
/**
* testExcerpt method
*
*
* @access public
* @return void
*/
@ -283,7 +288,7 @@ class TextTest extends CakeTestCase {
}
/**
* testExcerptCaseInsensitivity method
*
*
* @access public
* @return void
*/
@ -300,7 +305,7 @@ class TextTest extends CakeTestCase {
}
/**
* testListGeneration method
*
*
* @access public
* @return void
*/
@ -313,7 +318,7 @@ class TextTest extends CakeTestCase {
}
/**
* tearDown method
*
*
* @access public
* @return void
*/