1: <?php
2:
3: 4: 5: 6: 7:
8:
9: namespace academicpuma\citeproc;
10:
11: 12: 13: 14: 15:
16:
17: class Name extends Format {
18:
19: private $name_parts = array();
20: private $attr_init = FALSE;
21:
22: function __construct($dom_node, $citeproc = NULL) {
23:
24: $tags = $dom_node->getElementsByTagName('name-part');
25: if ($tags) {
26: foreach ($tags as $tag) {
27: $name_part = $tag->getAttribute('name');
28: $tag->removeAttribute('name');
29: for ($i = 0; $i < $tag->attributes->length; $i++) {
30: $value = $tag->attributes->item($i)->value;
31: $name = str_replace(' ', '_', $tag->attributes->item($i)->name);
32: $this->name_parts[$name_part][$name] = $value;
33: }
34: }
35: }
36:
37: parent::__construct($dom_node, $citeproc);
38: }
39:
40: function init_formatting() {
41: $this->no_op = array();
42: $this->format = array();
43: $this->base = $this->get_attributes();
44: $this->format['base'] = '';
45: $this->format['family'] = '';
46: $this->format['given'] = '';
47: $this->no_op['base'] = TRUE;
48: $this->no_op['family'] = TRUE;
49: $this->no_op['given'] = TRUE;
50:
51: if (isset($this->prefix)) {
52: $this->no_op['base'] = FALSE;
53: }
54: if (isset($this->suffix)) {
55: $this->no_op['base'] = FALSE;
56: }
57: $this->init_format($this->base);
58:
59:
60: if (!empty($this->name_parts)) {
61: foreach ($this->name_parts as $name => $formatting) {
62: $this->init_format($formatting, $name);
63: }
64: }
65: }
66:
67: function init_attrs($mode) {
68:
69: if (isset($this->citeproc)) {
70: $style_attrs = $this->citeproc->style->get_hier_attributes();
71: $mode_attrs = $this->citeproc->{$mode}->get_hier_attributes();
72: $this->attributes = array_merge($style_attrs, $mode_attrs, $this->attributes);
73: }
74: if (isset($this->and)) {
75: if ($this->and == 'text') {
76: $this->and = $this->citeproc->get_locale('term', 'and');
77: } elseif ($this->and == 'symbol') {
78: $this->and = '&';
79: }
80: }
81: if (!isset($this->delimiter)) {
82: $this->delimiter = $this->{'name-delimiter'};
83: }
84: if (!isset($this->alnum)) {
85: list($this->alnum, $this->alpha, $this->cntrl, $this->dash,
86: $this->digit, $this->graph, $this->lower, $this->print,
87: $this->punct, $this->space, $this->upper, $this->word,
88: $this->patternModifiers) = $this->get_regex_patterns();
89: }
90: $this->dpl = $this->{'delimiter-precedes-last'};
91: $this->sort_separator = isset($this->{'sort-separator'}) ? $this->{'sort-separator'} : ', ';
92:
93: $this->delimiter = isset($this->{'name-delimiter'}) ? $this->{'name-delimiter'} : (isset($this->delimiter) ? $this->delimiter : ', ');
94:
95: $this->form = isset($this->{'name-form'}) ? $this->{'name-form'} : (isset($this->form) ? $this->form : 'long');
96:
97: $this->attr_init = $mode;
98: }
99:
100: function init_format($attribs, $part = 'base') {
101: if (!isset($this->{$part})) {
102: $this->{$part} = array();
103: }
104: if (isset($attribs['quotes']) && strtolower($attribs['quotes']) == 'true') {
105: $this->{$part}['open-quote'] = $this->citeproc->get_locale('term', 'open-quote');
106: $this->{$part}['close-quote'] = $this->citeproc->get_locale('term', 'close-quote');
107: $this->{$part}['open-inner-quote'] = $this->citeproc->get_locale('term', 'open-inner-quote');
108: $this->{$part}['close-inner-quote'] = $this->citeproc->get_locale('term', 'close-inner-quote');
109: $this->no_op[$part] = FALSE;
110: }
111:
112: if (isset($attribs['prefix']))
113: $this->{$part}['prefix'] = $attribs['prefix'];
114: if (isset($attribs['suffix']))
115: $this->{$part}['suffix'] = $attribs['suffix'];
116:
117: $this->format[$part] .= (isset($attribs['font-style'])) ? 'font-style: ' . $attribs['font-style'] . ';' : '';
118: $this->format[$part] .= (isset($attribs['font-family'])) ? 'font-family: ' . $attribs['font-family'] . ';' : '';
119: $this->format[$part] .= (isset($attribs['font-weight'])) ? 'font-weight: ' . $attribs['font-weight'] . ';' : '';
120: $this->format[$part] .= (isset($attribs['font-variant'])) ? 'font-variant: ' . $attribs['font-variant'] . ';' : '';
121: $this->format[$part] .= (isset($attribs['text-decoration'])) ? 'text-decoration: ' . $attribs['text-decoration'] . ';' : '';
122: $this->format[$part] .= (isset($attribs['vertical-align'])) ? 'vertical-align: ' . $attribs['vertical-align'] . ';' : '';
123:
124: if (isset($attribs['text-case'])) {
125: $this->no_op[$part] = FALSE;
126: $this->{$part}['text-case'] = $attribs['text-case'];
127: }
128: if (!empty($this->format[$part]))
129: $this->no_op[$part] = FALSE;
130: }
131:
132: function format($text, $part = 'base') {
133:
134: if (empty($text) || $this->no_op[$part])
135: return $text;
136: if (isset($this->{$part}['text-case'])) {
137: switch ($this->{$part}['text-case']) {
138: case 'uppercase':
139: $text = mb_strtoupper($text);
140: break;
141: case 'lowercase':
142: $text = mb_strtolower($text);
143: break;
144: case 'capitalize-all':
145: $text = mb_convert_case($text, MB_CASE_TITLE);
146: break;
147: case 'capitalize-first':
148: $chr1 = mb_strtoupper(mb_substr($text, 0, 1));
149: $text = $chr1 . mb_substr($text, 1);
150: break;
151: }
152: }
153: $open_quote = isset($this->{$part}['open-quote']) ? $this->{$part}['open-quote'] : '';
154: $close_quote = isset($this->{$part}['close-quote']) ? $this->{$part}['close-quote'] : '';
155: $prefix = isset($this->{$part}['prefix']) ? $this->{$part}['prefix'] : '';
156: $suffix = isset($this->{$part}['suffix']) ? $this->{$part}['suffix'] : '';
157: if ($text[(strlen($text) - 1)] == $suffix)
158: unset($suffix);
159: if (!empty($this->format[$part])) {
160: $text = '<span style="' . $this->format[$part] . '">' . $text . '</span>';
161: }
162: return $prefix . $open_quote . $text . $close_quote . $suffix;
163: }
164:
165: function render($names, $mode = NULL) {
166: $text = '';
167: $authors = array();
168: $count = 0;
169: $auth_count = 0;
170: $et_al_triggered = FALSE;
171:
172: if (!$this->attr_init || $this->attr_init != $mode)
173: $this->init_attrs($mode);
174:
175: $initialize_with = $this->{'initialize-with'};
176:
177: foreach ($names as $rank => $name) {
178: $count++;
179:
180: if (!empty($name->given) && isset($initialize_with)) {
181: $name->given = preg_replace("/([$this->upper])[$this->lower]+/$this->patternModifiers", '\\1', $name->given);
182: $name->given = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $name->given);
183: if (isset($name->initials)) {
184: $name->initials = $name->given . $name->initials;
185: }
186: $name->initials = $name->given;
187: }
188: if (isset($name->initials)) {
189:
190: $name->initials = preg_replace("/([$this->upper])\.+/$this->patternModifiers", "\\1", $name->initials);
191:
192: $name->initials = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $name->initials);
193: if ($this->citeproc->style->{'initialize-with-hyphen'} == 'false') {
194: $name->initials = preg_replace("/-/", '', $name->initials);
195: }
196:
197: if (preg_match("/ $/", $initialize_with)) {
198:
199: }
200:
201: $name->initials = preg_replace("/([$this->upper])(?=[^$this->lower]+|$)/$this->patternModifiers", "\\1$initialize_with", $name->initials);
202:
203:
204:
205:
206: if (isset($initialize_with)) {
207: $name->given = $name->initials;
208: } elseif (!empty($name->given)) {
209: $name->given = $name->given . ' ' . $name->initials;
210: } elseif (empty($name->given)) {
211: $name->given = $name->initials;
212: }
213: }
214:
215: $ndp = (isset($name->{'non-dropping-particle'})) ? $name->{'non-dropping-particle'} . ' ' : '';
216: $suffix = (isset($name->{'suffix'})) ? ' ' . $name->{'suffix'} : '';
217:
218: if (isset($name->given)) {
219: $given = $this->format($name->given, 'given');
220: } else {
221: $given = '';
222: }
223: if (isset($name->family)) {
224: $name->family = $this->format($name->family, 'family');
225: if ($this->form == 'short') {
226: $text = $ndp . $name->family;
227: } else {
228: switch ($this->{'name-as-sort-order'}) {
229: case 'first' && $rank == 0:
230: case 'all':
231: $text = $ndp . $name->family . $this->sort_separator . $given;
232: break;
233: default:
234: $text = $given . ' ' . $ndp . $name->family . $suffix;
235: }
236: }
237: $authors[] = trim($this->format($text));
238: }
239: if (isset($this->{'et-al-min'}) && $count >= $this->{'et-al-min'})
240: break;
241: }
242: if (isset($this->{'et-al-min'}) &&
243: $count >= $this->{'et-al-min'} &&
244: isset($this->{'et-al-use-first'}) &&
245: $count >= $this->{'et-al-use-first'} &&
246: count($names) > $this->{'et-al-use-first'}) {
247: if ($this->{'et-al-use-first'} < $this->{'et-al-min'}) {
248: for ($i = $this->{'et-al-use-first'}; $i < $count; $i++) {
249: unset($authors[$i]);
250: }
251: }
252: if ($this->etal) {
253: $etal = $this->etal->render();
254: } else {
255: $etal = $this->citeproc->get_locale('term', 'et-al');
256: }
257: $et_al_triggered = TRUE;
258: }
259:
260: if (!empty($authors) && !$et_al_triggered) {
261: $auth_count = count($authors);
262: if (isset($this->and) && $auth_count > 1) {
263: $authors[$auth_count - 1] = $this->and . ' ' . $authors[$auth_count - 1];
264: }
265: }
266:
267: $text = implode($this->delimiter, $authors);
268:
269: if (!empty($authors) && $et_al_triggered) {
270: switch ($this->{'delimiter-precedes-et-al'}) {
271: case 'never':
272: $text = $text . " $etal";
273: break;
274: case 'always':
275: $text = $text . "$this->delimiter$etal";
276: break;
277: default:
278: $text = count($authors) == 1 ? $text . " $etal" : $text . "$this->delimiter$etal";
279: }
280: }
281:
282: if ($this->form == 'count') {
283: if (!$et_al_triggered) {
284: return (int) count($authors);
285: } else {
286: return (int) (count($authors) - 1);
287: }
288: }
289:
290: if (isset($this->and) && $auth_count > 1) {
291: $last_delim = strrpos($text, $this->delimiter . $this->and);
292: switch ($this->dpl) {
293: case 'always':
294: return $text;
295: break;
296: case 'never':
297: return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
298: break;
299: case 'contextual':
300: default:
301: if ($auth_count < 3) {
302: return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
303: }
304: }
305: }
306: return $text;
307: }
308:
309: function get_regex_patterns() {
310:
311: if (!@preg_match('/\pL/u', 'a')) {
312:
313: return $this->get_latin1_regex();
314: } else {
315:
316: return $this->get_utf8_regex();
317: }
318: }
319:
320: function get_latin1_regex() {
321: $alnum = "[:alnum:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
322:
323: $alpha = "[:alpha:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
324:
325: $cntrl = "[:cntrl:]";
326:
327: $dash = "-–";
328:
329: $digit = "[\d]";
330:
331: $graph = "[:graph:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
332:
333: $lower = "[:lower:]äåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
334:
335: $print = "[:print:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
336:
337: $punct = "[:punct:]";
338:
339: $space = "[\s]";
340:
341: $upper = "[:upper:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆ";
342:
343: $word = "_[:alnum:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
344:
345:
346: $patternModifiers = "";
347:
348: return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
349: $print, $punct, $space, $upper, $word, $patternModifiers);
350: }
351:
352: function get_utf8_regex() {
353:
354: $alnum = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}";
355:
356: $alpha = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}";
357:
358: $cntrl = "\p{C}";
359:
360: $dash = "\p{Pd}";
361:
362: $digit = "\p{Nd}";
363:
364: $graph = "^\p{C}\t\n\f\r\p{Z}";
365:
366: $lower = "\p{Ll}\p{M}";
367:
368: $print = "\P{C}";
369:
370: $punct = "\p{P}";
371:
372: $space = "\t\n\f\r\p{Z}";
373:
374: $upper = "\p{Lu}\p{Lt}";
375:
376: $word = "_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}";
377:
378:
379: $patternModifiers = "u";
380: return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
381: $print, $punct, $space, $upper, $word, $patternModifiers);
382: }
383:
384: }