Subversion Repositories smartshort

[/] [autoloads/] [eztemplatesmartshortoperator.php] - Blame information for rev 1

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1 steven.bailey
<?php
2
//
3
// Definition of eZTemplateSmartShortOperator class
4
//
5
// Created on: <19-Jan-2010 13:50:09 sbailey>
6
//
7
// SOFTWARE NAME: eZ Publish
8
// SOFTWARE RELEASE: 1.1.0
9
//
10
// COPYRIGHT NOTICE: Copyright (C) 2011 Leiden Tech
11
// SOFTWARE LICENSE: GNU General Public License v2.0
12
// NOTICE: >
13
// This program is free software; you can redistribute it and/or
14
// modify it under the terms of version 2.0  of the GNU General
15
// Public License as published by the Free Software Foundation.
16
//
17
// This program is distributed in the hope that it will be useful,
18
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
// GNU General Public License for more details.
21
//
22
// You should have received a copy of version 2.0 of the GNU General
23
// Public License along with this program; if not, write to the Free
24
// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25
// MA 02110-1301, USA.
26
//
27
//
28
 
29
/*!
30
  \class eZTemplateSmartShortOperator eztemplatesmartshortoperator.php
31
  \ingroup eZTemplateOperators
32
  \brief Display of string block  using operator "smartshort".  Will shorten strings to length without breaking tags or leaving tags open.  It will also break the text on the nearest end punctuation and failing that (it isn't within 20% of the total string length) then it will try and break the string on the nearest whitespace.
33
 
34
  The operator can take two parameters. The first is the length to cut the string,
35
  the second is what the delimeter should be.
36
 
37
\code
38
// Example template code
39
input|smartshort( [ length [, sequence ] ] )
40
 
41
\endcode
42
 
43
*/
44
class SmartShortOperator
45
{
46
    /*!
47
     Initializes the object with the name $name, default is "smartshort".
48
    */
49
    function SmartShortOperator( $name = "smartshort" )
50
    {
51
        $this->AttributeName = $name;
52
        $this->Operators = array( $name );
53
    }
54
 
55
    /*!
56
     Returns the template operators.
57
    */
58
    function operatorList()
59
    {
60
        return array( 'smartshort' );
61
    }
62
 
63
    function operatorTemplateHints()
64
    {
65
        return array( $this->AttributeName => array( 'input' => true,
66
                                                     'output' => true,
67
                                                     'parameters' => 2 ) );
68
    }
69
 
70
    /*!
71
     See eZTemplateOperator::namedParameterList()
72
    */
73
 
74
    function namedParameterList()
75
    {
76
        return array( "length" =>       array( "type" => "integer",
77
                                               "required" => false,
78
                                               "default" => "80" ),
79
                      "sequence" =>     array( "type" => "string",
80
                                               "required" => false,
81
                                               "default" => "..." )
82
                                         );
83
    }
84
 
85
    /*!
86
     Display the variable.
87
    */
88
    function modify( $tpl, $operatorName, $operatorParameters, $rootNamespace, $currentNamespace, &$operatorValue, $namedParameters )
89
    {
90
        $moduleINI = eZINI::instance( "module.ini" );
91
        $allowedDeviationSetting = $moduleINI->variable( "ModuleSettings", "AllowedDeviation" );
92
        if (!is_int($allowedDeviationSetting))
93
                $allowedDeviationSetting = 20;
94
        $length    = $namedParameters['length'];
95
        $sequence  = $namedParameters['sequence'];
96
 
97
        $allowedDeviation = $allowedDeviationSetting / 100;
98
        $outputlength=0;
99
        $prevoutputlength=0;
100
        $output="";
101
        $openTagArray=array();
102
        $punctPositions=array();
103
        $spacePositions=array();
104
        $cleanString = strip_tags($operatorValue);
105
 
106
        if(strlen($cleanString) > $length) { //if it already fits we don't have to jump through any hoops to make it fit       
107
                $punctSplit = preg_match_all('/([.!?])/i', $cleanString,$punctMatches,PREG_OFFSET_CAPTURE);
108
 
109
                foreach($punctMatches[0] as $punctArray) { //Flatten the offset capture into an array
110
                        $punctPositions[] = $punctArray[1];
111
                }
112
 
113
                $firstString=explode(" ",$cleanString);
114
                if ($length > strlen($firstString[0])) { //to check for really small length limits being passed
115
                        if (!in_array($length,$punctPositions) OR count($punctPositions) == 0) { // don't have to do this if it already ended on puctuation or has no punctuation
116
                                $current=$punctPositions[0];
117
                                foreach($punctPositions as $position) {
118
                                        if (abs($length - $position) < abs($length - $current) ) {
119
                                                $current = $position;
120
                                        }
121
                                        if ($position >= $length) {
122
                                                break;
123
                                        }
124
                                }
125
                        }
126
 
127
                        if ( $length * $allowedDeviation >= abs($length - $current)) {
128
                                $length=$current+1;
129
                        } else { //deviation is greater than allowed deviation - let's split on whitespace instead.
130
                                $spaceSplit = preg_match_all('%(\w+)%uxis', $cleanString,$spaceMatches,PREG_OFFSET_CAPTURE);
131
                                foreach($spaceMatches[0] as $spaceArray) { //Flatten the offset capture into an array
132
                                        $spacePositions[] = $spaceArray[1];
133
                                }
134
                                if (!in_array($length,$spacePositions) OR count($spacePositions) == 0) { // don't have to do this if it already ended on a space
135
                                        $current=$spacePositions[0];
136
                                        foreach($spacePositions as $position) {
137
                                                if (abs($length - $position) < abs($length - $current) ) {
138
                                                        $current = $position-1;
139
                                                }
140
                                                if ($position >= $length) {
141
                                                        break;
142
                                                }
143
                                        }
144
                                        $length=$current;
145
                                } elseif(in_array($length,$spacePositions)) {
146
                                        $length=$length-1; //get rid of self then since it's whitespace
147
                                }
148
                        }
149
                } else { //$length is less than the first string.
150
                        $current = strlen($firstString[0]);
151
                        if ( $length * $allowedDeviation >= abs($length - $current)) { //deviation is less than allowed deviation so go with the first string.
152
                                $length = $current;
153
                        } //else we split on the character - which is already what $length is set to.
154
                }
155
        }
156
        //end length calculation.
157
 
158
        if ($operatorValue == $cleanString) {  //No tags, just dump the sub string and we're done weehaw.
159
                $output = substr( $cleanString, 0, $length );
160
                if($spacePositions) { // Don't need sequence if it ended on a sentence in my humble opinion.
161
                        $output = $output.$sequence;
162
                }
163
        } else { //has tags, uh oh
164
                $tagSplit = preg_split('%(</?[\w][^>]*>)%uxis',$operatorValue,-1,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
165
                $badTagArray=$moduleINI->variable( "ModuleSettings", "HangingTags" );
166
 
167
                foreach($tagSplit as $tagChunk) {
168
                        if (preg_match('%(<[\w]+[^>]*>.*?)%uxis', $tagChunk,$tagMatches) == 1) { //open tag
169
                        //if it's a tag don't count it toward the string length since it's hidden, but do try and figure out if it's a non-self-closing tag that we'll have to find and close
170
                                $tag=explode(" ",$tagMatches[0]);
171
                                $tag=rtrim($tag[0]," >");
172
                                if (count(preg_grep("%^$tag$%uxis", $badTagArray)) > 0){
173
                                        $openTagArray[]=$tag;
174
                                }
175
                        } elseif (preg_match('%(<\/[\w]+[^>]*>.*?)%uxis', $tagChunk,$tagMatches) == 1) { //close tag
176
                                if(count($openTagArray) > 0) // better not do this unless array has content
177
                                        array_pop($openTagArray);
178
                        } else {
179
                                $outputlength = $outputlength + strlen($tagChunk);
180
                        }
181
 
182
                        if ($outputlength >= $length) {
183
                                $output = $output.substr( $tagChunk, 0, $length - $prevoutputlength );
184
                                if(count($openTagArray) != 0 ) {
185
                                //need to check if the tag needs to be closed
186
                                        foreach(array_reverse($openTagArray) as $openTag) {
187
                                                switch ($openTag) {
188
                                                default:
189
                                                        //convert <tag to </tag>
190
                                                        $openTag = ltrim($openTag,"<");
191
                                                        $openTag ="</".$openTag.">";
192
                                                        $output = $output.$openTag;
193
                                                        break;
194
                                                }
195
                                        }
196
                                }
197
                                //need to check if the tag needs to be closed
198
                                break;
199
                        }
200
                        $prevoutputlength = $outputlength;
201
                        $output = $output.$tagChunk;
202
                }
203
        }
204
 
205
        $operatorValue=$output;
206
        return;
207
    }
208
 
209
    /// The array of operators, used for registering operators
210
    public $Operators;
211
}
212
 
213
?>