source: trunk/patForms/Element/Pool.php @ 244

Revision 244, 16.9 KB checked in by schst, 8 years ago (diff)

added todos for the Pool element

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2/**
3 * patForms Pool element
4 *
5 * Handles value 'pools' with which a user can select among a pool of
6 * values by selecting it in a first select box, and moving it into a
7 * target box using javascript.
8 *
9 * $Id$
10 *
11 * @access      protected
12 * @package     patForms
13 * @subpackage  patForms_Element
14 * @author      gERD Schaufelberger <gerd@php-tools.net>
15 * @author      Sebastian Mordziol <argh@php-tools.net>
16 */
17
18/**
19 * Notice: no default value available for selected locale
20 */
21 define( 'PATFORMS_ELEMENT_POOL_NOTICE_NO_DEFAULT_VALUE_AVAILABLE', 'patForms:Element:Pool:01' );
22 
23/**
24 * patForms Pool element
25 *
26 * Handles value 'pools' with which a user can select among a pool of
27 * values by selecting it in a first select box, and moving it into a
28 * target box using javascript.
29 *
30 * @access      protected
31 * @package     patForms
32 * @subpackage  patForms_Element
33 * @author      gERD Schaufelberger <gerd@php-tools.net>
34 * @author      Sebastian Mordziol <argh@php-tools.net>
35 * @license     LGPL, see license.txt for details
36 *
37 * @todo        javascript must be more flexible - maybe use a doubleclick for adding/removing values
38 * @todo        implement validation, value handling, ...
39 * @todo        use the available set element to generate the select boxes to be able to use the extended functions of these elements, like auto sizing.
40 * @todo        implement renderer support for layout control
41 * @todo        this should support datasources
42 * @todo        move javascript to its own file
43 */
44class patForms_Element_Pool extends patForms_Element
45{
46   /**
47    * Stores the name of the element - this is used mainly by the patForms
48    * error management and should be set in every element class.
49    * @access   public
50    */
51    var $elementName    =   'Pool';
52
53   /**
54    * the type of the element - set this to the type of element you are creating
55    * if you want to use the {@link patForms_Element::element2html()} method to
56    * create the final HTML tag for your element.
57    *
58    * @access   public
59    * @see      patForms_Element::element2html()
60    */
61    var $elementType    =   array(  "html"  =>  "input" );
62   
63   /**
64    * set here which attributes you want to include in the element if you want to use
65    * the {@link patForms_Element::convertDefinition2Attributes()} method to automatically
66    * convert the values from your element definition into element attributes.
67    *
68    * @access   protected
69    * @see      patForms_Element::convertDefinition2Attribute()
70    */
71    var $attributeDefinition    =   array( 
72           
73            "id"            =>  array(  "required"      =>  false,
74                                        "format"        =>  "string",
75                                        "outputFormats" =>  array( "html" ),
76                                    ),
77            "name"          =>  array(  "required"      =>  true,
78                                        "format"        =>  "string",
79                                        "outputFormats" =>  array( "html" ),
80                                        "modifiers"     =>  array( "insertSpecials" => array() ),
81                                    ),
82            "title"         =>  array(  "required"      =>  false,
83                                        "format"        =>  "string",
84                                        "outputFormats" =>  array( "html" ),
85                                        "modifiers"     =>  array( "insertSpecials" => array() ),
86                                    ),
87            "description"   =>  array(  "required"      =>  false,
88                                        "format"        =>  "string",
89                                        "outputFormats" =>  array(),
90                                        "modifiers"     =>  array( "insertSpecials" => array() ),
91                                    ),
92            "default"       =>  array(  "required"      =>  false,
93                                        "format"        =>  "string",
94                                        "outputFormats" =>  array(),
95                                    ),
96            "label"         =>  array(  "required"      =>  false,
97                                        "format"        =>  "string",
98                                        "outputFormats" =>  array(),
99                                    ),
100            "display"       =>  array(  "required"      =>  false,
101                                        "format"        =>  "string",
102                                        "default"       =>  "yes",
103                                        "outputFormats" =>  array(),
104                                    ),
105            "edit"          =>  array(  "required"      =>  false,
106                                        "format"        =>  "string",
107                                        "default"       =>  "yes",
108                                        "outputFormats" =>  array(),
109                                    ),
110            "required"      =>  array(  "required"      =>  false,
111                                        "format"        =>  "string",
112                                        "default"       =>  "yes",
113                                        "outputFormats" =>  array(),
114                                    ),
115            "style"         =>  array(  "required"      =>  false,
116                                        "outputFormats" =>  array( "html" ),
117                                        "format"        =>  "string",
118                                    ),
119            "class"         =>  array(  "required"      =>  false,
120                                        "outputFormats" =>  array( "html" ),
121                                        "format"        =>  "string",
122                                    ),
123            "onchange"      =>  array(  "required"      =>  false,
124                                        "format"        =>  "string",
125                                        "outputFormats" =>  array( "html" ),
126                                        "modifiers"     =>  array( "insertSpecials" => array() ),
127                                    ),
128            "onclick"       =>  array(  "required"      =>  false,
129                                        "format"        =>  "string",
130                                        "outputFormats" =>  array( "html" ),
131                                        "modifiers"     =>  array( "insertSpecials" => array() ),
132                                    ),
133            "onfocus"       =>  array(  "required"      =>  false,
134                                        "format"        =>  "string",
135                                        "outputFormats" =>  array( "html" ),
136                                        "modifiers"     =>  array( "insertSpecials" => array() ),
137                                    ),
138            "onmouseover"   =>  array(  "required"      =>  false,
139                                        "format"        =>  "string",
140                                        "outputFormats" =>  array( "html" ),
141                                        "modifiers"     =>  array( "insertSpecials" => array() ),
142                                    ),
143            "onmouseout"    =>  array(  "required"      =>  false,
144                                        "format"        =>  "string",
145                                        "outputFormats" =>  array( "html" ),
146                                        "modifiers"     =>  array( "insertSpecials" => array() ),
147                                    ),
148            "onblur"        =>  array(  "required"      =>  false,
149                                        "format"        =>  "string",
150                                        "outputFormats" =>  array( "html" ),
151                                        "modifiers"     =>  array( "insertSpecials" => array() ),
152                                    ),
153            "accesskey"     =>  array(  "required"      =>  false,
154                                        "format"        =>  "string",
155                                        "outputFormats" =>  array( "html" ),
156                                    ),
157            "position"      =>  array(  "required"      =>  false,
158                                        "format"        =>  "int",
159                                        "outputFormats" =>  array(),
160                                    ),
161            "tabindex"      =>  array(  "required"      =>  false,
162                                        "format"        =>  "int",
163                                        "outputFormats" =>  array( "html" ),
164                                    ),
165            "format"        =>  array(  "required"      =>  false,
166                                        "format"        =>  "string",
167                                        "outputFormats" =>  array(),
168                                    ),
169            "disabled"      =>  array(  "required"      =>  false,
170                                        "format"        =>  "string",
171                                        "default"       =>  "no",
172                                        "outputFormats" =>  array( "html" ),
173                                    ),
174            "multiple"      =>  array(  "required"      =>  false,
175                                        "format"        =>  "string",
176                                        "default"       =>  "yes",
177                                        "outputFormats" =>  array( "html" ),
178                                    ),
179            "size"          =>  array(  "required"          =>  false,
180                                        "format"        =>  "int",
181                                        "default"       =>  20,
182                                        "outputFormats" =>  array( "html" ),
183                                    ),
184            "candidates"        =>  array(  "required"  =>  true,
185                                        "outputFormats" =>  array(),
186                                    ),
187            "candidatetitle"        =>  array(  "required"      =>  false,
188                                        "format"        =>  "string",
189                                        "default"       =>  false,
190                                        "outputFormats" =>  array( ),
191                                    ),
192            "membertitle"       =>  array(  "required"      =>  false,
193                                        "format"        =>  "string",
194                                        "default"       =>  false,
195                                        "outputFormats" =>  array( ),
196                                    ),
197            "titleclass"        =>  array(  "required"      =>  false,
198                                        "format"        =>  "string",
199                                        "default"       =>  false,
200                                        "outputFormats" =>  array( ),
201                                    ),
202            "toolclass"     =>  array(  "required"      =>  false,
203                                        "format"        =>  "string",
204                                        "default"       =>  false,
205                                        "outputFormats" =>  array( ),
206                                    ),
207            "tooladd"       =>  array(  "required"      =>  false,
208                                        "format"        =>  "string",
209                                        "default"       =>  "add",
210                                        "outputFormats" =>  array( ),
211                                    ),
212            "toolremove"    =>  array(  "required"      =>  false,
213                                        "format"        =>  "string",
214                                        "default"       =>  "remove",
215                                        "outputFormats" =>  array( ),
216                                    ),
217        );
218
219    /**
220     *  define error codes an messages for each form element
221     *
222     *  @access private
223     *  @var    array   $validatorErrorCodes
224     */
225    var $validatorErrorCodes  =   array(
226        "C" =>  array(
227            1   =>  "This field is required, please complete it.",
228        ),
229        "de" => array(
230            1   =>  "Pflichtfeld. Bitte vervollständigen Sie Ihre Angabe.",
231        ),
232        "fr" => array(
233            1   =>  "Ce champ est obligatoire.",
234        )
235    );
236       
237   /**
238    * element creation method for the 'HTML' format in the 'default' form mode.
239    *
240    * @access   public
241    * @param    mixed   value of the element
242    * @return   mixed   $element    The element, or false if failed.
243    */
244    function serializeHtmlDefault( $value )
245    {
246        // handle display
247        if( $this->attributes['display'] == 'no' )
248        {
249            return $this->createDisplaylessTag( $value );
250        }
251
252        $this->attributes["value"]  =   $value;
253       
254        if( $this->attributes["edit"] == "no" )
255        {
256            $this->attributes['disabled']   =   'yes';
257        }
258       
259        // create element
260        $attCollection  =   $this->getAttributesFor( $this->getFormat() );
261        $name           =   $attCollection['name'];
262       
263        $attribs        =   array(
264                                    'type'  =>  'hidden',
265                                    'name'  =>  $name,
266                                    'id'    =>  $name,
267                                    'value' =>  '----',
268                                );
269        $element        =   $this->createTag( 'input', 'full', $attribs ) . "\n";
270       
271        // add javascript class
272        if( !isset( $GLOBALS['_patForms_Element_Pool' . $name ] ) )
273        {
274            $GLOBALS['_patForms_Element_Pool' . $name ] =   true;
275            $element    .=  $this->_insertJavascript() . "\n";
276        }
277       
278        // add layout
279        $element    .=  '<table cellspacing="0" cellpadding="0" boder="0">'
280                    .   "\n<tr>";
281       
282        // add titles
283        if( $this->attributes['candidatetitle'] || $this->attributes['membertitle'] )
284        {
285            $class      =   $this->attributes['titleclass'];
286            if( $class )
287            {
288                $class  =   " class=\"$class\" ";
289            }
290       
291            $title      =   $this->attributes['candidatetitle'];
292            if( !$title )
293            {
294                $title  =   '&nbsp';
295            }
296            $element    .=  "<td$class>$title</td>";
297           
298            $title      =   $this->attributes['membertitle'];
299            if( !$title )
300            {
301                $title  =   '&nbsp';
302            }
303            $element    .=  "<td$class>$title</td>";
304           
305            $element    .=  "</tr>\n<tr>";
306        }
307       
308        // box of candidates
309        $element    .=  '<td>';
310        $attCollection['id']    =   'candidates_' . $name;
311        $attCollection['name']  =   'candidates_' . $name;
312        $element    .=  $this->createTag( 'select', 'opening', $attCollection );
313        $element    .=  $this->createTag( 'select', 'closing' );
314        $element    .=  '</td>';
315
316        // box of members
317        $element    .=  '<td>';
318        $attCollection['id']    =   'members_' . $name;
319        $attCollection['name']  =   'members_' . $name;
320        if( isset( $attCollection['accesskey'] ) )
321        {
322            unset( $attCollection['accesskey'] );
323        }
324       
325        $element    .=  $this->createTag( 'select', 'opening', $attCollection );
326        $element    .=  $this->createTag( 'select', 'closing' );
327        $element    .=  '</td>';
328       
329       
330        // add tools
331        $class      =   $this->attributes['toolclass'];
332        if( $class )
333        {
334            $class  =   "class=\"$class\" ";
335        }
336       
337        $tooladd    =   $this->attributes['tooladd'];
338        $toolremove =   $this->attributes['toolremove'];
339       
340        $element    .=  "</tr>\n<tr>";
341        $element    .=  '<td><a '.$class.'href="javascript:pool_'. $name .'.add();">'. $tooladd.'</a></td>';
342        $element    .=  '<td><a '.$class.'href="javascript:pool_'. $name .'.remove();">'. $toolremove.'</a></td>';
343        $element    .=  "</tr>\n";
344       
345        $element    .=  "</table>\n";
346                   
347        // add values to javascript
348        $element    .=  '<script language="JavaScript1.2" type="text/javascript">'
349                    .   "\npool_$name   =   new pool( '$name' );\n";
350        $element    .=  $this->_addMembers() . "\n";
351        $element    .=  $this->_addCandidates() . "\n";
352
353        $element    .=  "pool_$name.init();\n"
354                    .   "</script>\n";
355
356        // and return to sender...
357        return $element;
358    }
359
360   /**
361    * Stores the value that will be displayed in readonly mode
362    * when no entry has been selected, in the available locales.
363    *
364    * @access   private
365    * @var      array
366    */
367    var $defaultReadonlyValue  =   array(
368        "C" =>  "No selection",
369        "de" => "Keine Angabe",
370        "fr" => "Pas de sélection.",
371    );
372
373   /**
374    * element creation method for the 'HTML' format in the 'readonly' form mode.
375    * Very simple; just returns the stored element value.
376    *
377    * @access   public
378    * @param    mixed   value of the element
379    * @return   string  $value  The element's value
380    */
381    function serializeHtmlReadonly( $value )
382    {
383        $tag = $this->createDisplaylessTag( $value );
384       
385        // handle display
386        if( $this->attributes['display'] == 'no' )
387        {
388            return $tag;
389        }
390       
391        // no selection
392        if( empty( $value ) )
393        {
394            return $this->getReadonlyValue().$tag;
395        }
396       
397        // selected entries
398        $selected = explode( ',', $value );
399        $display = array();
400       
401        // we want to display the labels of the values,
402        // so we get these.
403        foreach( $this->attributes['candidates'] as $row => $candidate )
404        {
405            if( in_array( $candidate['value'], $selected ) ) 
406            {
407                array_push( $display, $candidate['label'] );
408            }
409        }
410       
411        return implode( ', ', $display ).'.'.$tag;
412    }
413
414   /**
415    * validates the element.
416    *
417    * @access   public
418    * @param    mixed   value of the element
419    * @return   bool    $isValid    True if element could be validated, false otherwise.
420    */
421    function validateElement( $value )
422    {
423        $required   =   false;
424        $empty      =   false;
425       
426        // store the required flag for easy access
427        if( $this->attributes["required"] == "yes" )
428        {
429            $required   =   true;
430        }
431       
432        if( strlen( $value ) == 0 )
433        {
434            $empty  =   true;
435        }
436           
437        if( $empty && $required )
438        {
439            $this->addValidationError( 1 );
440            return false;
441        }
442           
443        return true;
444    }
445
446   /**
447    * add preselected members
448    *
449    * @access private
450    * @param integer $id   
451    * @return boolean $result true on success
452    * @see
453    */
454    function _addMembers()
455    {
456        $value  =   $this->getValue();
457        if( empty( $value ) )
458        {
459            return '';
460        }
461
462        $name   =   $this->attributes['name'];
463        $mems   =   explode( ',', $value );
464       
465        $ele    =   array();
466        foreach( $mems as $m )
467        {
468            array_push( $ele, "pool_$name.addMember( '$m' )" );
469        }
470       
471        return implode( "\n", $ele );
472    }
473   
474   /**
475    * add candidates to list
476    *
477    * @access private
478    * @param integer $id   
479    * @return boolean $result true on success
480    * @see
481    */
482    function _addCandidates()
483    {
484        $name   =   $this->attributes['name'];
485        $cands  =   $this->attributes['candidates'];
486       
487        $ele    =   array();
488        foreach( $cands as $cand )
489        {
490            array_push( $ele, "pool_$name.addCandidate( '".$cand['value']."', '".$cand['label']."' )" );
491        }
492       
493        return implode( "\n", $ele );
494    }
495
496   /**
497    * Retrieves the default value to display in the element's readonly mode if the
498    * user has not selected any entry, according to the selected locale
499    *
500    * @access   public
501    * @return   string  $defaultValue   The default readonly value in the needed locale
502    */
503    function getReadonlyValue()
504    {   
505        $lang   =   $this->locale;
506   
507        if( !isset( $this->defaultReadonlyValue[$lang] ) )
508        {
509            patErrorManager::raiseNotice(
510                PATFORMS_ELEMENT_POOL_NOTICE_NO_DEFAULT_VALUE_AVAILABLE,
511                'There is no default readonly value available for the locale "'.$lang.'", using default locale "C" instead.'
512            );
513           
514            return $this->defaultReadonlyValue['C'];
515        }
516       
517        return $this->defaultReadonlyValue[$lang];
518    }
519   
520   /**
521    * insert javascript code that implements a pool-class
522    *
523    * @access private
524    * @param integer $id   
525    * @return boolean $result true on success
526    * @see
527    */
528    function _insertJavascript()
529    {
530        ob_start();
531        echo <<<END
532<!--
533    PatFormsElement: Pool
534    Javascript Class: pool
535-->
536<script language="JavaScript1.2" type="text/javascript">
537function pool( name )
538{
539    this.name           =   name;
540    this.formValue      =   false;
541    this.formCandidates =   false;
542    this.formMembers    =   false;
543    this.memb           =   new Array();
544    this.cand           =   new Array();
545   
546    this.addMember      =   poolAddMember;
547    this.addCandidate   =   poolAddCandidate;
548    this.add            =   poolAdd;
549    this.remove         =   poolRemove;
550    this.update         =   poolUpdate;
551    this.init           =   poolInit;
552}
553
554function candidate( id, text )
555{
556    this.id         =   id;
557    this.text       =   text;
558    this.isMember   =   false;
559}
560
561function poolAddMember( id )
562{
563    this.memb.push( id );
564}
565   
566function poolAddCandidate( id, desc )
567{
568    this.cand.push( new candidate( id, desc ) );   
569}
570
571function poolInit()
572{
573    for( var i = 0; i < this.memb.length; ++i )
574        for( var j = 0; j < this.cand.length; ++j )
575            if( this.memb[i] == this.cand[j].id )
576            {
577                this.cand[j].isMember   =   true;
578                break;
579            }
580
581    this.formValue      =   document.getElementById( this.name );
582    this.formCandidates =   document.getElementById( 'candidates_' + this.name );
583    this.formMemebers   =   document.getElementById( 'members_' + this.name );
584   
585    this.update();
586}
587
588function poolUpdate()
589{
590    for( var i = this.formCandidates.options.length; i > 0; --i )
591        this.formCandidates.options[i - 1]  =   null;
592       
593    for( var i = this.formMemebers.options.length; i > 0; --i )
594        this.formMemebers.options[i - 1]    =   null;
595   
596    this.formValue.value    =   null;
597    for( var i = 0; i < this.cand.length; ++i )
598    {
599        m   =   new Option( this.cand[i].text, this.cand[i].id, false, false );
600        if( this.cand[i].isMember )
601        {
602            this.formMemebers.options[ this.formMemebers.options.length ]   =   m;
603            if( this.formValue.value )
604                this.formValue.value += ',' + m.value;
605            else
606                this.formValue.value =   m.value;
607        }
608        else
609            this.formCandidates.options[ this.formCandidates.options.length ]   =   m;
610    }
611}
612
613function    poolAdd( )
614{
615    for( var i = 0; i < this.formCandidates.options.length; ++i )
616        if( this.formCandidates.options[i].selected )
617            for( var j = 0; j < this.cand.length; ++j )
618                if( this.formCandidates.options[i].value == this.cand[j].id )
619                    this.cand[j].isMember   =   true;
620    this.update();
621}
622
623function poolRemove()
624{
625    for( var i = 0; i < this.formMemebers.options.length; ++i )
626        if( this.formMemebers.options[i].selected )
627            for( var j = 0; j < this.cand.length; ++j )
628                if( this.formMemebers.options[i].value == this.cand[j].id )
629                    this.cand[j].isMember   =   false;
630
631    this.update();
632}
633</script>
634END;
635        $script =   ob_get_contents();
636        ob_end_clean();
637       
638        return $script;
639    }
640}
641?>
Note: See TracBrowser for help on using the repository browser.