/[drupal]/contributions/sandbox/msameer/modules/bidi/bidi.module
ViewVC logotype

Contents of /contributions/sandbox/msameer/modules/bidi/bidi.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.7 - (show annotations) (download) (as text)
Sat Dec 6 00:47:08 2008 UTC (11 months, 2 weeks ago) by msameer
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +8 -14 lines
File MIME type: text/x-php
Ported to Drupal 6
1 <?php // -*-php-*-
2 /*
3 * $Id: bidi.module,v 1.6 2007/01/19 19:38:50 msameer Exp $
4 * Original module by Alaa Abd El Fatah.
5 * Mohammed Sameer: My Modifications Copyright (c) 2004 Mohammed Sameer,
6 * under the GNU GPL v2 or later.
7 * Mohammed Sameer <msameer@foolab.org>: 2004-10-30
8 * * Ported to drupal 4.5 API.
9 * Mohammed Sameer <msameer@foolab.org>: 2005-04-10
10 * * Reworked the configuration part for 4.7
11 * * The arabic to english threshhold is now configurable.
12 * * Spelling correction: automaticaly -> automatically
13 * * Some minor code cleanups.
14 * Mohammed Sameer <msameer@foolab.org>: 2006-11-13
15 * * Replaced _get_dir() with bidi_get_dir()
16 * * bidi_get_dir() returns a direction not a css thing.
17 * * Added bidi_get_attributes to get the css attributes.
18 * * Added bidi_get_class() to get the css class
19 * Mohammed Sameer <msameer@foolab.org>: 2007-01-19
20 * * Ported to 5.0
21 * * bidi_get_{dir|class}() takes a reference.
22 * * _bidi_filter_process() should take a reference.
23 * * Started documenting the code.
24 * * added hook_menu() to load the bidi.css
25 * * Added _bidi_load_css() to load the CSS file containing our classes.
26 * Mohammed Sameer <msameer@foolab.org>: 2008-12-06
27 * * Ported to Drupal 6
28 * * _bidi_load_css() -> bidi_init()
29 */
30
31 setlocale(LC_ALL, "ar_EG.UTF-8");
32
33 define('BIDI_DIR_RTL', 1);
34 define('BIDI_DIR_LTR', 2);
35
36 /**
37 * Implementation of hook_filter()
38 */
39 function bidi_filter($op, $delta = 0, $format = -1, $text = "") {
40 switch ($op) {
41 case 'list':
42 return array(0 => t('BiDi'));
43 case 'description':
44 return t("Bidi filter");
45 case "process":
46 return _bidi_filter_process($text);
47 case "settings":
48 return _bidi_filter_settings($text);
49 default:
50 return $text;
51 }
52 }
53
54 /**
55 * Implementation of hook_init()
56 */
57 function bidi_init() {
58 $path = drupal_get_path('module', 'bidi').'/bidi.css';
59 drupal_add_css($path);
60 }
61
62 /**
63 * Get the direction of a string.
64 *
65 * @param $text a reference to the text to be scanned.
66 * @return either BIDI_DIR_RTL or BIDI_DIR_LTR
67 */
68 function bidi_get_dir(&$text) {
69 $text = strtolower($text);
70 $len = strlen($text);
71
72 $arabic = 0;
73 $english = 0;
74
75 //constants
76 $a = ord('a');
77 $z = ord('z');
78
79 //arabic UTF-8 letters have one of these values in the 1st byte
80 $ar1 = 0xd8;
81 $ar2 = 0xd9;
82
83 // this calculates the dominant language in the text, most bidi implementations just use the first letter (which may be more efficient)
84 for ($i = 0; $i < $len; ++$i) {
85 $bin = ord($text[$i]);
86
87 if ($bin == $ar1 || $bin == $ar2) {
88 ++$arabic;
89 ++$i;
90 } else if ($bin >= $a && $bin <= $z) {
91 ++$english;
92 }
93 }
94
95 if ($arabic) {
96 if ($english/$arabic < variable_get('bidi_module_threshhold', 1.5)) {
97 return BIDI_DIR_RTL;
98 }
99 }
100 return BIDI_DIR_LTR;
101 }
102
103 /**
104 * return the CSS class.
105 *
106 * return "left2right" or "right2left".
107 */
108 function bidi_get_class(&$text) {
109 return bidi_get_dir($text) == BIDI_DIR_LTR ? 'left2right' : 'right2left';
110 }
111
112 /**
113 * Get the HTML fragment to set the direction.
114 *
115 * @return the HTML fragment to set the direction.
116 */
117 function bidi_get_attributes($text) {
118 return ' class="'.bidi_get_class($text).'" ';
119 }
120
121 /**
122 * Scan the body of a node and set the correct direction.
123 *
124 * @param $text a reference to the text to be modified.
125 * @return the text after being processed.
126 */
127 function _bidi_filter_process(&$text) {
128 $output = "";
129
130 $len = strlen($text);
131 $i = 0;
132
133
134 while ($i < $len) {
135 //find next tag
136 $e = strpos(substr($text, $i), "<");
137 if ($e === FALSE) break;
138
139 $output.=substr($text, $i, $e);
140
141 $i += $e;
142
143 //find end of next tag
144 $e = strcspn(substr($text, $i), "/> ");
145 $tag = substr($text, $i+1, $e-1);
146
147 $output.=substr($text, $i, $e);
148 $i += $e;
149
150
151 switch ($tag) {
152 //single tag entity
153 case "img":
154 case "br":
155 case "hr":
156 continue;
157 break;
158
159 //nested cases
160 case "ul":
161 case "ol":
162 case "dl":
163 case "div":
164 $e = 0;
165 $j = 1; //stack counter
166
167 // if $j = 0 then stack is empty
168 while ($j > 0) {
169 $e += strpos(substr($text, $i+$e) , $tag);
170
171 //yeah I know I'm assuming certain sizes for tags, sue me
172 if ($text[$i+$e-1] == '<') { //new nested block
173 ++$j;
174 } else if ($text[$i+$e-1] == '/') { //end of block
175 --$j;
176 }
177 $e += 2; //skip current tag
178 }
179 $content = substr($text, $i+1, $e);
180 $output.= bidi_get_attributes(strip_tags($content));
181 $e += strlen($tag);
182 $output.= substr($text, $i, $e);
183 $i += $e;
184 break;
185
186
187 //block elements these get out attention
188 case "p":
189 case "blockquote":
190 case "pre":
191 case "h1":
192 case "h2":
193 case "h3":
194 case "h4":
195 case "h5":
196 case "h6":
197
198 //nested lists are proken better think of a fix
199 case "li":
200 $close_tag = "</".$tag.">";
201 //breaks on extra whitespaces, maybe I should use regexps instead
202 $e = strpos(substr($text, $i), $close_tag);
203 $content = substr($text, $i+1, $e-1);
204 //calculate directions
205 $output.= bidi_get_attributes(strip_tags($content));
206 $e += strlen($close_tag);
207 $output.= substr($text, $i, $e);
208 $i += $e;
209
210 break;
211
212 //non block tags we are not handeling
213 default:
214 $close_tag = "</".$tag.">";
215 $e = strpos(substr($text, $i), $close_tag) + strlen($close_tag);
216 $output.= substr($text, $i, $e);
217 $i += $e;
218 }
219
220 }
221
222 //any missing content
223 $output .= substr($text, $i);
224
225
226 return $output;
227 }
228
229 /**
230 * Get the settings form.
231 *
232 * @return a drupal form array.
233 */
234 function _bidi_filter_settings() {
235
236 $form['bidi_filter'] = array(
237 '#type' => 'fieldset',
238 '#title' => t('BiDi filter'),
239 '#collapsible' => TRUE,
240 '#collapsed' => FALSE,
241 );
242 $form['bidi_filter']['bidi_module_threshhold'] = array(
243 '#type' => 'textfield',
244 '#title' => t('Bidi threshhold'),
245 '#default_value' => variable_get('bidi_module_threshhold','1.5'),
246 '#description' => t('Below this threshhold text will take the right to left direction.'),
247 );
248
249 return $form;
250 }
251
252 /**
253 * Implementation of hook_filter_tips()
254 */
255 function bidi_filter_tips() {
256 return t("You may write mixed Arabic and English freely, line direction will be computed automaticaly");
257 }
258
259 ?>

  ViewVC Help
Powered by ViewVC 1.1.2