source: extensions/GrumPluginClasses/classes/GPCCore.class.inc.php @ 16733

Last change on this file since 16733 was 16733, checked in by grum, 8 years ago

update GPC framework

File size: 42.5 KB
Line 
1<?php
2
3/* -----------------------------------------------------------------------------
4  class name     : GPCCore
5  class version  : 1.4.1
6  plugin version : 3.5.2
7  date           : 2011-09-19
8  ------------------------------------------------------------------------------
9  author: grum at piwigo.org
10  << May the Little SpaceFrog be with you >>
11  ------------------------------------------------------------------------------
12
13  :: HISTORY
14
15| release | date       |
16| 1.0.0   | 2010/03/30 | * Update class & function names
17|         |            |
18| 1.1.0   | 2010/03/30 | * add the BBtoHTML function
19|         |            |
20| 1.2.0   | 2010/07/28 | * add the loadConfigFromFile function
21|         |            |
22| 1.3.0   | 2010/10/13 | * add the addHeaderCSS, addHeaderJS functions
23|         |            |
24| 1.3.1   | 2010/10/20 | * applyHeaderItems functions implemented with an
25|         |            |   higher priority on the 'loc_begin_page_header' event
26|         |            |
27|         |            | * implement the getUserLanguageDesc() function, using
28|         |            |   extended description function if present
29|         |            |
30|         |            | * implement the getPiwigoSystemPath() function
31|         |            |
32|         |            | * implement the rmDir() function
33|         |            |
34| 1.3.2   | 2011/01/28 | * implement the addUI() function
35|         |            |
36|         |            | * implement getMinified() & setMinifiedState() functions
37|         |            |
38| 1.3.3   | 2011/02/01 | * fix bug on loadConfig() function
39|         |            |
40|         |            | * update deleteConfig() function (allow to be used to
41|         |            |   delete the GPCCore config)
42|         |            |
43|         |            | * mantis bug:2167
44|         |            |
45| 1.3.4   | 2011/02/02 | * mantis bug:2170
46|         |            |   . File path for RBuilder registered plugins is corrupted
47|         |            |
48|         |            | * mantis bug:2178
49|         |            |   . RBuilder register function don't work
50|         |            |
51|         |            | * mantis bug:2179
52|         |            |   . JS file loaded in wrong order made incompatibility
53|         |            |     with Lightbox, GMaps & ASE plugins (and probably other)
54|         |            |
55| 1.4.0   | 2011/04/10 | * Updated for piwigo 2.2
56|         |            |
57| 1.4.1   | 2011/09/19 | * Add [var] and [form_mail] markup interpreter
58|         |            |
59|         | 2012/05/25 | * Add GPCUserAgent class
60|         |            |
61|         |            | * Compatibility with jquery 1.7.2 & jquery-ui 1.8.16
62|         |            |   . implement getMinified() & setMinifiedState() functions
63|         |            |        (let piwigo combined function manage the minified
64|         |            |         state)
65|         |            |   . add manually each component for ui functionnalities
66|         |            |
67|         |            | * Remove google translate connector (google has changed the useage
68|         |            |    and now an API key is needed)
69|         |            |
70|         |            | * Add js objects: inputDate, inputFilterBox, inputPages, inputSortBox, inputTag
71|         |            |                   dynamicTable
72|         |            |
73|         |            | * AddHeaderCSS and AddJS are ignored if called in an ajax session (AJAX_CALL defined)
74|         |            |
75|         |            |
76|         |            |
77|         |            |
78
79  ------------------------------------------------------------------------------
80    no constructor, only static function are provided
81    - static function loadConfig
82    - static function loadConfigFromFile
83    - static function saveConfig
84    - static function deleteConfig
85    - static function getRegistered
86    - static function getModulesInfos
87    - static function register
88    - static function unregister
89    - static function BBtoHTML
90    - static function VarToHTML
91    - static function TabsToHTML
92    - static function FormMailToHTML
93    - static function addHeaderCSS
94    - static function addHeaderJS
95    - static function addUI
96    - static function getUserLanguageDesc
97    - static function getPiwigoSystemPath
98    - static function formatOctet
99    - static function rmDir
100    - static function applyMarkups
101    - static function setTemplateToken
102    - static function addHeaderContent
103   ---------------------------------------------------------------------- */
104
105
106
107class GPCCore
108{
109  static private $piwigoSystemPath;
110
111  static public $pluginName = "GPCCore";
112  static protected $headerItems = array(
113    'css' => array(),
114    'js'  => array()
115  );
116
117  static public function init()
118  {
119    global $conf;
120
121    self::$piwigoSystemPath=dirname(dirname(dirname(dirname(__FILE__))));
122
123    if((isset($conf['gpc.markup.bb']) && $conf['gpc.markup.bb']) ||
124       (isset($conf['gpc.markup.var']) && $conf['gpc.markup.var']) ||
125       (isset($conf['gpc.markup.form']) && $conf['gpc.markup.form'])
126      )
127    {
128      add_event_handler('render_category_name', array('GPCCore', 'applyMarkups'), EVENT_HANDLER_PRIORITY_NEUTRAL+5);
129      add_event_handler('render_category_description', array('GPCCore', 'applyMarkups'), EVENT_HANDLER_PRIORITY_NEUTRAL+5, 2);
130      add_event_handler('render_element_description', array('GPCCore', 'applyMarkups'), EVENT_HANDLER_PRIORITY_NEUTRAL+5);
131      add_event_handler('AP_render_content', array('GPCCore', 'applyMarkups'), EVENT_HANDLER_PRIORITY_NEUTRAL+5);
132    }
133  }
134
135  /* ---------------------------------------------------------------------------
136   * grum plugin classes informations functions
137   * -------------------------------------------------------------------------*/
138  static public function getModulesInfos()
139  {
140    return(
141      Array(
142        Array('name' => "CommonPlugin", 'version' => "2.3.0"),
143        Array('name' => "GPCAjax", 'version' => "3.1.0"),
144        Array('name' => "GPCCategorySelector", 'version' => "1.0.1"),
145        Array('name' => "GPCCore", 'version' => "1.4.1"),
146        //Array('name' => "GPCCss", 'version' => "3.1.0"),  removed with v1.4.1
147        Array('name' => "GPCPagesNavigation", 'version' => "2.0.0"),
148        Array('name' => "GPCPublicIntegration", 'version' => "2.0.0"),
149        Array('name' => "GPCRequestBuilder", 'version' => "1.1.7"),
150        Array('name' => "GPCTables", 'version' => "1.5.0"),
151        Array('name' => "GPCTabSheet", 'version' => "1.1.1"),
152        Array('name' => "GPCTranslate", 'version' => "2.1.1"),
153        Array('name' => "GPCUsersGroups", 'version' => "2.1.0"),
154        Array('name' => "GPCUserAgent", 'version' => "1.0.0")
155      )
156    );
157  }
158
159
160  /* ---------------------------------------------------------------------------
161   * register oriented functions
162   * -------------------------------------------------------------------------*/
163
164  /**
165   * register a plugin using GPC
166   *
167   * @param String $pluginName : the plugin name
168   * @param String $release : the plugin version like "2.0.0"
169   * @param String $GPCNeed : the minimal version of GPC needed by the plugin to
170   *                          work
171   * @return Boolean : true if registering is Ok, otherwise false
172   */
173  static public function register($plugin, $release, $GPCneeded)
174  {
175    $config=Array();
176    if(!self::loadConfig(self::$pluginName, $config))
177    {
178      $config['registered']=array();
179    }
180
181    $config['registered'][$plugin]=Array(
182      'name' => $plugin,
183      'release' => $release,
184      'needed' => $GPCneeded,
185      'date' => date("Y-m-d"),
186    );
187    return(self::saveConfig(self::$pluginName, $config));
188  }
189
190  /**
191   * unregister a plugin using GPC
192   *
193   * assume that if the plugin was not registerd before, unregistering returns
194   * a true value
195   *
196   * @param String $pluginName : the plugin name
197   * @return Boolean : true if registering is Ok, otherwise false
198   */
199  static public function unregister($plugin)
200  {
201    $config=Array();
202    if(self::loadConfig(self::$pluginName, $config))
203    {
204      if(array_key_exists('registered', $config))
205      {
206        if(array_key_exists($plugin, $config['registered']))
207        {
208          unset($config['registered'][$plugin]);
209          return(self::saveConfig(self::$pluginName, $config));
210        }
211      }
212    }
213    // assume if the plugin was not registered before, unregistering it is OK
214    return(true);
215  }
216
217  /**
218   * return the list of registered plugins
219   * @return Array : list of registered plugins
220   */
221  static public function getRegistered()
222  {
223    $config=Array();
224    if(self::loadConfig(self::$pluginName, $config))
225    {
226      if(array_key_exists('registered', $config))
227      {
228        return($config['registered']);
229      }
230    }
231    return(Array());
232  }
233
234
235
236  /* ---------------------------------------------------------------------------
237   * config oriented functions
238   * -------------------------------------------------------------------------*/
239
240  /**
241   *  load config from CONFIG_TABLE into an array
242   *
243   * @param String $pluginName : the plugin name, must contain only alphanumerical
244   *                             character
245   * @param Array $config : array, initialized or not with default values ; the
246   *                        config values are loaded in this value
247   * @return Boolean : true if config is loaded, otherwise false
248   */
249  static public function loadConfig($pluginName, &$config=Array())
250  {
251    global $conf;
252
253    if(!isset($conf[$pluginName.'_config']))
254    {
255      return(false);
256    }
257
258    $configValues = unserialize($conf[$pluginName.'_config']);
259    reset($configValues);
260    while (list($key, $val) = each($configValues))
261    {
262      if(is_array($val))
263      {
264        foreach($val as $key2 => $val2)
265        {
266          $config[$key][$key2]=$val2;
267
268          if(isset($conf['plugin.'.$pluginName]) and isset($conf['plugin.'.$pluginName][$key]) and isset($conf['plugin.'.$pluginName][$key][$key2]))
269              $config[$key][$key2]=$conf['plugin.'.$pluginName][$key][$key2];
270        }
271      }
272      else
273      {
274        $config[$key]=$val;
275        if(isset($conf['plugin.'.$pluginName]) and isset($conf['plugin.'.$pluginName][$key]))
276            $config[$key]=$conf['plugin.'.$pluginName][$key];
277      }
278    }
279
280    $conf[$pluginName.'_config']=serialize($config);
281
282    return(true);
283  }
284
285  /**
286   *  load config from a file into an array
287   *
288   *  note : the config file is a PHP file one var $conf used as an array,
289   *  like the piwigo $conf var
290   *
291   * @param String $fileName : the file name
292   * @param Array $config : array, initialized or not with default values ; the
293   *                        config values are loaded in this value
294   * @return Boolean : true if config is loaded, otherwise false
295   */
296  static public function loadConfigFromFile($fileName, &$config=Array())
297  {
298    $conf=array();
299
300    if(!is_array($config) or !file_exists($fileName))
301    {
302      return(false);
303    }
304
305    include_once($fileName);
306
307    foreach($conf as $key=>$val)
308    {
309      $config[$key]=$val;
310    }
311    return(true);
312  }
313
314
315  /**
316   * save var $my_config into CONFIG_TABLE
317   *
318   * @param String $pluginName : the plugin name, must contain only alphanumerical
319   *                             character
320   * @param Array $config : array of configuration values
321   * @return Boolean : true if config is saved, otherwise false
322   */
323  static public function saveConfig($pluginName, $config)
324  {
325    global $conf;
326
327    $sql="REPLACE INTO ".CONFIG_TABLE."
328           VALUES('".$pluginName."_config', '"
329           .pwg_db_real_escape_string(serialize($config))."', '')";
330    $result=pwg_query($sql);
331    if($result)
332    {
333      $conf[$pluginName.'_config']=serialize($config);
334      return true;
335    }
336    else
337    {
338      return false;
339    }
340  }
341
342  /**
343   * delete config from CONFIG_TABLE
344   *
345   * @param String $pluginName : the plugin name, must contain only alphanumerical
346   *                             character ; if empty, assume GPCCore config
347   * @return Boolean : true if config is deleted, otherwise false
348   */
349  static public function deleteConfig($pluginName='')
350  {
351    if($pluginName=='') $pluginName=self::$pluginName;
352    $sql="DELETE FROM ".CONFIG_TABLE."
353          WHERE param='".$pluginName."_config'";
354    $result=pwg_query($sql);
355    if($result)
356    { return true; }
357    else
358    { return false; }
359  }
360
361
362  /**
363   * convert (light) BB tag to HTML tag
364   *
365   * all BB codes are not recognized, only :
366   *  - [ul] [/ul]
367   *  - [li] [/li]
368   *  - [b] [/b]
369   *  - [i] [/i]
370   *  - [url] [/url]
371   *  - carriage return is replaced by a <br>
372   *
373   * @param String $text : text to convert
374   * @return String : BB to HTML text
375   */
376  static public function BBtoHTML($text)
377  {
378    $patterns = Array(
379      '/\[li\](.*?)\[\/li\]\n*/im',
380      '/\[b\](.*?)\[\/b\]/ism',
381      '/\[i\](.*?)\[\/i\]/ism',
382      '/\[p\](.*?)\[\/p\]/ism',
383      '/\[url\]([\w]+?:\/\/[^ \"\n\r\t<]*?)\[\/url\]/ism',
384      '/\[url=([\w]+?:\/\/[^ \"\n\r\t<]*?)\](.*?)\[\/url\]/ism',
385      '/\n{0,1}\[ul\]\n{0,1}/im',
386      '/\n{0,1}\[\/ul\]\n{0,1}/im',
387      '/\n{0,1}\[ol\]\n{0,1}/im',
388      '/\n{0,1}\[\/ol\]\n{0,1}/im',
389      '/\n/im',
390    );
391    $replacements = Array(
392      '<li>\1</li>',
393      '<b>\1</b>',
394      '<i>\1</i>',
395      '<p>\1</p>',
396      '<a href="\1">\1</a>',
397      '<a href="\1">\2</a>',
398      '<ul>',
399      '</ul>',
400      '<ol>',
401      '</ol>',
402      '<br>',
403    );
404
405    return(preg_replace($patterns, $replacements, $text));
406  }
407
408  /**
409   * apply [var] tag
410   *
411   * [var=<name>]
412   * with <name> :
413   *  - USER
414   *  - GALLERY_TITLE
415   *  - NB_PHOTOS
416   *  - CATEGORY
417   *  - TOKEN
418   *  - IP
419   *
420   * @param String $text : text to convert
421   * @return String : processed text
422   */
423  static public function VarToHTML($text)
424  {
425    global $user, $page, $conf;
426
427    $patterns = Array(
428      '/\[var=user\]/im',
429      '/\[var=gallery_title\]/im',
430      '/\[var=nb_photos\]/im',
431      '/\[var=category\]/im',
432      '/\[var=token\]/im',
433      '/\[var=ip\]/im'
434    );
435    $replacements = Array(
436      isset($user['username'])?$user['username']:'',
437      isset($conf['gallery_title'])?$conf['gallery_title']:'',
438      isset($user['nb_total_images'])?$user['nb_total_images']:'',
439      isset($page['category']['name'])?$page['category']['name']:'',
440      get_pwg_token(),
441      $_SERVER['REMOTE_ADDR']
442    );
443
444    return(preg_replace($patterns, $replacements, $text));
445  }
446
447  /**
448   * apply [form_mail] tag
449   *
450   * @param String $text : text to convert
451   * @return String : processed text
452   */
453  static public function FormMailToHTML($text)
454  {
455    global $template;
456
457    $file=GPCCore::getPiwigoSystemPath().'/'.PWG_LOCAL_DIR.'templates/GPCFormMsg.tpl';
458    if(!file_exists($file)) $file=dirname(dirname(__FILE__))."/templates/GPCFormMsg.tpl";
459
460    $template->set_filename('gpc_form', $file);
461
462    $template->assign('token', get_pwg_token() );
463
464    $patterns = Array(
465      '/\[form_mail\]/im'
466    );
467    $replacements = Array(
468      $template->parse('gpc_form', true)
469    );
470
471    if(preg_match($patterns[0], $text)>0)
472    {
473      GPCCore::addHeaderJS('gpc.markup.formMail', GPC_PATH.'js/markup.formMail.js', array('jquery'));
474      return(preg_replace($patterns, $replacements, $text));
475    }
476    return($text);
477  }
478
479  /**
480   * apply [tab], [/tab] and [tabs] tags
481   *
482   * @param String $text : text to convert
483   * @return String : processed text
484   */
485  static public function TabsToHTML($text)
486  {
487    $result=array();
488
489    $tabs='';
490    if(preg_match_all('/\[tab=([^(;\]).]*)(?:;(default))?;([^\].]*)\]/im', $text, $result, PREG_SET_ORDER)>0)
491    {
492      foreach($result as $val)
493      {
494        $tabs.="<li class='gpcTabSeparator'><a id='iGpcTab".$val[1]."' class='".($val[2]=='default'?'gpcTabSelected':'gpcTabNotSelected')."' tabId='#iGpcTabContent".$val[1]."'>".$val[3]."</a></li>";
495      }
496      $tabs="<div id='iGpcTabs'><ul>".$tabs."</ul></div>";
497    }
498    else return($text);
499
500    $patterns = Array(
501      '/\[tabs\]/im',
502      '/\[tab=([^(;\]).]*)(?!;default);.*\]/im',
503      '/\[tab=([^(;\]).]*);default;(.*)\]/im',
504      '/\[\/tab\]/im'
505    );
506    $replacements = Array(
507      $tabs,
508      '<div id="iGpcTabContent\1" class="gpcTabContent" style="display:none;">',
509      '<div id="iGpcTabContent\1" class="gpcTabContent">',
510      '</div>'
511    );
512
513    if(preg_match($patterns[0], $text)>0)
514    {
515      GPCCore::addHeaderJS('gpc.markup.tabs', GPC_PATH.'js/markup.tabs.js', array('jquery'));
516      GPCCore::addHeaderCSS('gpc.markup.tabs', GPC_PATH.'css/gpcTabs.css');
517      return(preg_replace($patterns, $replacements, $text));
518    }
519    return($text);
520  }
521
522  /**
523   * analyze and replace markups by their value, according to $conf parameted
524   * @param String $text: text to analyze
525   * @return String: analyzed text
526   */
527  static public function applyMarkups($text)
528  {
529    global $conf;
530
531    if(isset($conf['gpc.markup.form']) && $conf['gpc.markup.form'])
532    {
533      $text=GPCCore::FormMailToHTML($text);
534    }
535
536    if(isset($conf['gpc.markup.tabs']) && $conf['gpc.markup.tabs'])
537    {
538      $text=GPCCore::TabsToHTML($text);
539    }
540
541    if(isset($conf['gpc.markup.var']) && $conf['gpc.markup.var'])
542    {
543      $text=GPCCore::VarToHTML($text);
544    }
545
546    if(isset($conf['gpc.markup.bb']) && $conf['gpc.markup.bb'])
547    {
548      $text=GPCCore::BBtoHTML($text);
549    }
550
551
552    return($text);
553  }
554
555  /**
556   * used to add a js or css directly in the header
557   *
558   * @param String $id : a unique id for the file
559   * @param String $file : the css file
560   * @param String $order: priority
561   */
562  static public function addHeaderContent($type, $content)
563  {
564    global $template;
565    $null=null;
566
567    if(defined('AJAX_CALL')) return(false); // not needed for an ajax call
568
569    switch($type)
570    {
571      case 'css':
572        $template->block_html_style(null, $content, $null, $null);
573        break;
574      case 'js':
575        $template->block_html_head(null, '<script type="text/javascript">'.$content.'</script>', $null, $null);
576        break;
577    }
578  }
579
580  /**
581   * used to add a css file in the header
582   *
583   * @param String $id : a unique id for the file
584   * @param String $file : the css file
585   * @param String $order: priority
586   */
587  static public function addHeaderCSS($id, $file, $order=0)
588  {
589    global $template;
590
591    if(defined('AJAX_CALL')) return(false); // no CSS needed for an ajax call
592    if(!array_key_exists($id, self::$headerItems['css']) and file_exists($file))
593    {
594      self::$headerItems['css'][$id]=$file;
595      $template->func_combine_css(array('path'=>$file, 'order'=>$order), $template->smarty);
596    }
597  }
598
599  /**
600   * used to add a js file in the header
601   *
602   * @param String $id : a unique id for the file
603   * @param String $file : the js file
604   * @param Array $require : list of required files
605   */
606  static public function addHeaderJS($id, $file, $require=array())
607  {
608    global $template;
609
610    if(defined('AJAX_CALL')) return(false); // no JS needed for an ajax call
611    if(!array_key_exists($id, self::$headerItems['js']) and file_exists($file))
612    {
613      self::$headerItems['js'][$id]=$file;
614      $template->scriptLoader->add($id, 'header', $require, $file, 0);
615    }
616  }
617
618  /**
619   * add a ui component ; css & js dependencies are managed
620   *
621   * @param Array $list : possibles values are
622   *                        - categorySelector
623   *                        - dynamicTable
624   *                        - inputCheckbox
625   *                        - inputColorPicker
626   *                        - inputColorsFB
627   *                        - inputConsole
628   *                        - inputDate
629   *                        - inputDotArea
630   *                        - inputFilterBox
631   *                        - inputList
632   *                        - inputNum
633   *                        - inputPosition
634   *                        - inputRadio
635   *                        - inputSortBox
636   *                        - inputStatusBar
637   *                        - inputTag
638   *                        - inputText
639   */
640  static public function addUI($list)
641  {
642    global $template;
643
644    if(is_string($list)) $list=explode(',', $list);
645    if(!is_array($list)) return(false);
646
647    if(defined('IN_ADMIN'))
648    {
649      $themeFile=GPC_PATH.'css/%s_'.$template->get_themeconf('name').'.css';
650    }
651    else
652    {
653      $themeFile='themes/'.$template->get_themeconf('name').'/css/GPC%s.css';
654    }
655
656    foreach($list as $ui)
657    {
658      switch($ui)
659      {
660        case 'gpcCSS':
661          $fileName='./plugins/'.basename(dirname(dirname(__FILE__))).'/css/gpc';
662          self::addHeaderCSS('gpc.css', $fileName.'.css', 10);
663          self::addHeaderCSS('gpc.cssT', $fileName.'_'.$template->get_themeconf('name').'.css', 15);
664          break;
665        case 'categorySelector':
666          self::addHeaderCSS('gpc.categorySelector', GPC_PATH.'css/categorySelector.css');
667          self::addHeaderCSS('gpc.categorySelectorT', sprintf($themeFile, 'categorySelector'));
668          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
669          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
670          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
671          self::addHeaderJS('gpc.categorySelector', GPC_PATH.'js/ui.categorySelector.js', array('jquery.ui.widget'));
672          break;
673        case 'inputCheckbox':
674          self::addHeaderCSS('gpc.inputCheckbox', GPC_PATH.'css/inputCheckbox.css');
675          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
676          self::addHeaderJS('gpc.inputCheckbox', GPC_PATH.'js/ui.inputCheckbox.js', array('jquery.ui'));
677          break;
678        case 'inputColorPicker':
679          self::addHeaderCSS('gpc.inputText', GPC_PATH.'css/inputText.css');
680          self::addHeaderCSS('gpc.inputNum', GPC_PATH.'css/inputNum.css');
681          self::addHeaderCSS('gpc.inputColorsFB', GPC_PATH.'css/inputColorsFB.css');
682          self::addHeaderCSS('gpc.inputDotArea', GPC_PATH.'css/inputDotArea.css');
683          self::addHeaderCSS('gpc.inputColorPicker', GPC_PATH.'css/inputColorPicker.css');
684          self::addHeaderCSS('gpc.inputTextT', sprintf($themeFile, 'inputText'));
685          self::addHeaderCSS('gpc.inputNumT', sprintf($themeFile, 'inputNum'));
686          self::addHeaderCSS('gpc.inputColorsFBT', sprintf($themeFile, 'inputColorsFB'));
687          self::addHeaderCSS('gpc.inputDotAreaT', sprintf($themeFile, 'inputDotArea'));
688          self::addHeaderCSS('gpc.inputColorPickerT', sprintf($themeFile, 'inputColorPicker'));
689          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
690          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
691          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
692          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.widget'));
693          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.widget'));
694          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.widget'));
695          self::addHeaderJS('jquery.ui.slider', 'themes/default/js/ui/jquery.ui.slider.js', array('jquery.ui.widget'));
696          self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.widget'));
697          self::addHeaderJS('gpc.inputNum', GPC_PATH.'js/ui.inputNum.js', array('jquery.ui.widget'));
698          self::addHeaderJS('gpc.inputColorsFB', GPC_PATH.'js/ui.inputColorsFB.js', array('jquery.ui.widget'));
699          self::addHeaderJS('gpc.inputDotArea', GPC_PATH.'js/ui.inputDotArea.js', array('jquery.ui.widget'));
700          self::addHeaderJS('gpc.inputColorPicker', GPC_PATH.'js/ui.inputColorPicker.js', array('jquery.ui.slider','gpc.inputText','gpc.inputNum','gpc.inputColorsFB','gpc.inputDotArea'));
701          break;
702        case 'inputColorsFB':
703          self::addHeaderCSS('gpc.inputColorsFB', GPC_PATH.'css/inputColorsFB.css');
704          self::addHeaderCSS('gpc.inputColorsFBT', sprintf($themeFile, 'inputColorsFB'));
705          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
706          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
707          self::addHeaderJS('gpc.inputColorsFB', GPC_PATH.'js/ui.inputColorsFB.js', array('jquery.ui.widget'));
708          break;
709        case 'inputConsole':
710          self::addHeaderCSS('gpc.inputConsole', GPC_PATH.'css/inputConsole.css');
711          self::addHeaderCSS('gpc.inputConsoleT', sprintf($themeFile, 'inputConsole'));
712          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
713          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
714          self::addHeaderJS('gpc.inputConsole', GPC_PATH.'js/ui.inputConsole.js', array('jquery.ui.widget'));
715          break;
716        case 'inputDate':
717          self::addHeaderCSS('gpc.inputDate', GPC_PATH.'css/inputDate.css');
718          self::addHeaderCSS('gpc.inputDateT', sprintf($themeFile, 'inputDate'));
719          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
720          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
721          self::addHeaderJS('jquery.ui.datepicker', 'themes/default/js/ui/jquery.ui.datepicker.js', array('jquery.ui.widget'));
722          self::addHeaderJS('gpc.inputDate', GPC_PATH.'js/ui.inputDate.js', array('jquery.ui.widget'));
723          break;
724        case 'inputDotArea':
725          self::addHeaderCSS('gpc.inputDotArea', GPC_PATH.'css/inputDotArea.css');
726          self::addHeaderCSS('gpc.inputDotAreaT', sprintf($themeFile, 'inputDotArea'));
727          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
728          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
729          self::addHeaderJS('gpc.inputDotArea', GPC_PATH.'js/ui.inputDotArea.js', array('jquery.ui.widget'));
730          break;
731        case 'inputFilterBox':
732          self::addHeaderCSS('gpc.inputNum', GPC_PATH.'css/inputNum.css');
733          self::addHeaderCSS('gpc.inputNumT', sprintf($themeFile, 'inputNum'));
734          self::addHeaderCSS('gpc.inputDate', GPC_PATH.'css/inputDate.css');
735          self::addHeaderCSS('gpc.inputDateT', sprintf($themeFile, 'inputDate'));
736          self::addHeaderCSS('gpc.inputText', GPC_PATH.'css/inputText.css');
737          self::addHeaderCSS('gpc.inputTextT', sprintf($themeFile, 'inputText'));
738          self::addHeaderCSS('gpc.inputList', GPC_PATH.'css/inputList.css');
739          self::addHeaderCSS('gpc.inputListT', sprintf($themeFile, 'inputList'));
740          self::addHeaderCSS('gpc.inputFilterBox', GPC_PATH.'css/inputFilterBox.css');
741          self::addHeaderCSS('gpc.inputFilterBoxT', sprintf($themeFile, 'inputFilterBox'));
742
743          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
744          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
745
746          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
747          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
748          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.mouse'));
749          self::addHeaderJS('jquery.ui.resizable', 'themes/default/js/ui/jquery.ui.resizable.js', array('jquery.ui.position'));
750          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.resizable'));
751          self::addHeaderJS('jquery.ui.sortable', 'themes/default/js/ui/jquery.ui.sortable.js', array('jquery.ui.draggable'));
752          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.sortable'));
753
754          self::addHeaderJS('gpc.inputNum', GPC_PATH.'js/ui.inputNum.js', array('jquery.ui.dialog'));
755          self::addHeaderJS('gpc.inputList', GPC_PATH.'js/ui.inputList.js', array('jquery.ui.dialog'));
756          self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.dialog'));
757          self::addHeaderJS('gpc.inputDate', GPC_PATH.'js/ui.inputDate.js', array('jquery.ui.dialog'));
758          self::addHeaderJS('gpc.inputFilterBox', GPC_PATH.'js/ui.inputFilterBox.js', array('jquery.ui.dialog'));
759          break;
760        case 'inputList':
761          self::addHeaderCSS('gpc.inputList', GPC_PATH.'css/inputList.css');
762          self::addHeaderCSS('gpc.inputListT', sprintf($themeFile, 'inputList'));
763          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
764          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
765          self::addHeaderJS('gpc.inputList', GPC_PATH.'js/ui.inputList.js', array('jquery.ui.widget'));
766          break;
767        case 'inputNum':
768          self::addHeaderCSS('gpc.inputNum', GPC_PATH.'css/inputNum.css');
769          self::addHeaderCSS('gpc.inputNumT', sprintf($themeFile, 'inputNum'));
770          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
771          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
772          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
773          self::addHeaderJS('jquery.ui.slider', 'themes/default/js/ui/jquery.ui.slider.js', array('jquery.ui.widget'));
774          self::addHeaderJS('gpc.inputNum', GPC_PATH.'js/ui.inputNum.js', array('jquery','jquery.ui.slider'));
775          break;
776        case 'inputPages':
777          self::addHeaderCSS('gpc.inputPages', GPC_PATH.'css/inputPages.css');
778          self::addHeaderCSS('gpc.inputPagesT', sprintf($themeFile, 'inputPages'));
779          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
780          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
781          self::addHeaderJS('gpc.inputPages', GPC_PATH.'js/ui.inputPages.js', array('jquery','jquery.ui.widget'));
782          break;
783        case 'inputPosition':
784          self::addHeaderCSS('gpc.inputPosition', GPC_PATH.'css/inputPosition.css');
785          self::addHeaderCSS('gpc.inputPositionT', sprintf($themeFile, 'inputPosition'));
786          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
787          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
788          self::addHeaderJS('gpc.inputPosition', GPC_PATH.'js/ui.inputPosition.js', array('jquery.ui.widget'));
789          break;
790        case 'inputRadio':
791          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
792          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
793          self::addHeaderJS('gpc.inputRadio', GPC_PATH.'js/ui.inputRadio.js', array('jquery.ui.widget'));
794          break;
795        case 'inputSortBox':
796          self::addHeaderCSS('gpc.inputSortBox', GPC_PATH.'css/inputSortBox.css');
797          self::addHeaderCSS('gpc.inputSortBoxT', sprintf($themeFile, 'inputSortBox'));
798          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
799          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
800          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
801          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.mouse'));
802          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.position'));
803          self::addHeaderJS('jquery.ui.sortable', 'themes/default/js/ui/jquery.ui.sortable.js', array('jquery.ui.draggable'));
804          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.sortable'));
805          self::addHeaderJS('gpc.inputSortBox', GPC_PATH.'js/ui.inputSortBox.js', array('jquery.ui.dialog'));
806          break;
807        case 'inputStatusBar':
808          self::addHeaderCSS('gpc.inputStatusBar', GPC_PATH.'css/inputStatusBar.css');
809          self::addHeaderCSS('gpc.inputStatusBarT', sprintf($themeFile, 'inputStatusBar'));
810          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
811          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
812          self::addHeaderJS('gpc.inputStatusBar', GPC_PATH.'js/ui.inputStatusBar.js', array('jquery.ui.widget'));
813          break;
814        case 'inputSwitchButton':
815          self::addHeaderCSS('gpc.inputSwitchButton', GPC_PATH.'css/inputSwitchButton.css');
816          self::addHeaderCSS('gpc.inputSwitchButtonT', sprintf($themeFile, 'inputSwitchButton'));
817          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
818          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
819          self::addHeaderJS('gpc.inputSwitchButton', GPC_PATH.'js/ui.inputSwitchButton.js', array('jquery.ui.widget'));
820          break;
821        case 'inputTag':
822          self::addHeaderCSS('gpc.inputTag', GPC_PATH.'css/inputTag.css');
823          self::addHeaderCSS('gpc.inputTagT', sprintf($themeFile, 'inputTag'));
824          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
825          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
826          self::addHeaderJS('gpc.inputTag', GPC_PATH.'js/ui.inputTag.js', array('jquery.ui.widget'));
827          break;
828        case 'inputText':
829          self::addHeaderCSS('gpc.inputText', GPC_PATH.'css/inputText.css');
830          self::addHeaderCSS('gpc.inputTextT', sprintf($themeFile, 'inputText'));
831          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
832          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
833          self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.widget'));
834          break;
835        case 'simpleTip':
836          self::addHeaderCSS('gpc.simpleTip', GPC_PATH.'css/simpleTip.css');
837          self::addHeaderCSS('gpc.simpleTipT', sprintf($themeFile, 'simpleTip'));
838          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
839          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
840          self::addHeaderJS('gpc.simpleTip', GPC_PATH.'js/simpleTip.js', array('jquery.ui.widget'));
841          break;
842        case 'dynamicTable':
843          self::addHeaderCSS('gpc.inputNum', GPC_PATH.'css/inputNum.css');
844          self::addHeaderCSS('gpc.inputNumT', sprintf($themeFile, 'inputNum'));
845          self::addHeaderCSS('gpc.inputDate', GPC_PATH.'css/inputDate.css');
846          self::addHeaderCSS('gpc.inputDateT', sprintf($themeFile, 'inputDate'));
847          self::addHeaderCSS('gpc.inputText', GPC_PATH.'css/inputText.css');
848          self::addHeaderCSS('gpc.inputTextT', sprintf($themeFile, 'inputText'));
849          self::addHeaderCSS('gpc.inputList', GPC_PATH.'css/inputList.css');
850          self::addHeaderCSS('gpc.inputListT', sprintf($themeFile, 'inputList'));
851          self::addHeaderCSS('gpc.inputSortBox', GPC_PATH.'css/inputSortBox.css');
852          self::addHeaderCSS('gpc.inputSortBoxT', sprintf($themeFile, 'inputSortBox'));
853          self::addHeaderCSS('gpc.inputFilterBox', GPC_PATH.'css/inputFilterBox.css');
854          self::addHeaderCSS('gpc.inputFilterBoxT', sprintf($themeFile, 'inputFilterBox'));
855          self::addHeaderCSS('gpc.inputPages', GPC_PATH.'css/inputPages.css');
856          self::addHeaderCSS('gpc.inputPagesT', sprintf($themeFile, 'inputPages'));
857          self::addHeaderCSS('gpc.inputDynamicTable', GPC_PATH.'css/inputDynamicTable.css');
858          self::addHeaderCSS('gpc.inputDynamicTableT', sprintf($themeFile, 'inputDynamicTable'));
859
860          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
861          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
862
863          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
864          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.mouse'));
865          self::addHeaderJS('jquery.ui.resizable', 'themes/default/js/ui/jquery.ui.resizable.js', array('jquery.ui.position'));
866          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.resizable'));
867          self::addHeaderJS('jquery.ui.sortable', 'themes/default/js/ui/jquery.ui.sortable.js', array('jquery.ui.draggable'));
868          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.sortable'));
869
870          self::addHeaderJS('gpc.inputNum', GPC_PATH.'js/ui.inputNum.js', array('jquery.ui.dialog'));
871          self::addHeaderJS('gpc.inputList', GPC_PATH.'js/ui.inputList.js', array('jquery.ui.dialog'));
872          self::addHeaderJS('gpc.inputText', GPC_PATH.'js/ui.inputText.js', array('jquery.ui.dialog'));
873          self::addHeaderJS('gpc.inputDate', GPC_PATH.'js/ui.inputDate.js', array('jquery.ui.dialog'));
874          self::addHeaderJS('gpc.inputFilterBox', GPC_PATH.'js/ui.inputFilterBox.js', array('jquery.ui.dialog'));
875          self::addHeaderJS('gpc.inputSortBox', GPC_PATH.'js/ui.inputSortBox.js', array('jquery.ui.dialog'));
876          self::addHeaderJS('gpc.inputPages', GPC_PATH.'js/ui.inputPages.js', array('jquery.ui.dialog'));
877          self::addHeaderJS('gpc.dynamicTable', GPC_PATH.'js/ui.dynamicTable.js', array('jquery.ui.dialog'));
878          break;
879        case 'progressArea':
880          self::addHeaderCSS('gpc.progressArea', GPC_PATH.'css/progressArea.css');
881          self::addHeaderCSS('gpc.progressAreaT', sprintf($themeFile, 'progressArea'));
882          self::addHeaderJS('jquery.ui', 'themes/default/js/ui/jquery.ui.core.js', array('jquery'));
883          self::addHeaderJS('jquery.ui.widget', 'themes/default/js/ui/jquery.ui.widget.js', array('jquery.ui'));
884          self::addHeaderJS('jquery.ui.mouse', 'themes/default/js/ui/jquery.ui.mouse.js', array('jquery.ui.widget'));
885          self::addHeaderJS('jquery.ui.position', 'themes/default/js/ui/jquery.ui.position.js', array('jquery.ui.mouse'));
886          self::addHeaderJS('jquery.ui.draggable', 'themes/default/js/ui/jquery.ui.draggable.js', array('jquery.ui.position'));
887          self::addHeaderJS('jquery.ui.sortable', 'themes/default/js/ui/jquery.ui.sortable.js', array('jquery.ui.draggable'));
888          self::addHeaderJS('jquery.ui.dialog', 'themes/default/js/ui/jquery.ui.dialog.js', array('jquery.ui.sortable'));
889          self::addHeaderJS('gpc.progressArea', GPC_PATH.'js/ui.progressArea.js', array('jquery.ui.dialog'));
890          break;
891        case 'timer':
892          self::addHeaderJS('gpc.timer', GPC_PATH.'js/ui.timer.js', array('jquery'));
893          break;
894      }
895    }
896  }
897
898
899  /**
900   * use the extended description get_user_language_desc() function if exist
901   * otherwise returns the value
902   *
903   * @param String $value : value to translate
904   * @return String : translated value
905   */
906  static public function getUserLanguageDesc($value)
907  {
908    if(function_exists('get_user_language_desc'))
909    {
910      return(get_user_language_desc($value));
911    }
912    else
913    {
914      return($value);
915    }
916  }
917
918
919  /**
920   * remove a path recursively
921   *
922   * @param String $directory : directory to remove
923   * @param Bool $removePath : if set to true, remove the path himself, if set
924   *                           to false, remove only file & sub-directories
925   * @return Bool : true if directory was succesfully removed, otherwise false
926   */
927  static public function rmDir($directory, $removePath=true)
928  {
929    $directory=rtrim($directory, '\/').'/';
930    $returned=true;
931    if(file_exists($directory) and is_dir($directory) and $directory!='./' and $directory!='../')
932    {
933      $dhandle=scandir($directory);
934      foreach($dhandle as $file)
935      {
936        if($file!='.' and $file!='..' )
937        {
938          if(is_dir($directory.$file))
939          {
940            $returned=self::rmDir($directory.$file, true) & $returned;
941          }
942          else
943          {
944            $returned=unlink($directory.$file) & $returned;
945          }
946        }
947      }
948      if($returned and $removePath) $returned=rmdir($directory);
949    }
950    return($returned);
951  }
952
953
954  /**
955   * returns the piwigo system path
956   * @return String
957   */
958  static public function getPiwigoSystemPath()
959  {
960    return(self::$piwigoSystemPath);
961  }
962
963
964 /**
965  * formats a file size into a human readable size
966  *
967  * @param String $format : "A"  : auto
968  *                         "Ai" : auto (io)
969  *                         "O"  : o
970  *                         "K"  : Ko
971  *                         "M"  : Mo
972  *                         "G"  : Go
973  *                         "Ki" : Kio
974  *                         "Mi" : Mio
975  *                         "Gi" : Gio
976  * @param String $thsep : thousand separator
977  * @param Integer $prec : number of decimals
978  * @param Bool $visible : display or not the unit
979  * @return String : a formatted file size
980  */
981 static public function formatOctet($octets, $format="Ai", $thsep="", $prec=2, $visible=true)
982 {
983  if($format=="Ai")
984  {
985   if($octets<1024)
986   { $format="O"; }
987   elseif($octets<1024000)
988   { $format="Ki"; }
989   elseif($octets<1024000000)
990   { $format="Mi"; }
991   else
992   { $format="Gi"; }
993  }
994  elseif($format=="A")
995  {
996   if($octets<1000)
997   { $format="O"; }
998   elseif($octets<1000000)
999   { $format="Ki"; }
1000   elseif($octets<1000000000)
1001   { $format="Mi"; }
1002   else
1003   { $format="Gi"; }
1004  }
1005
1006  switch($format)
1007  {
1008   case "O":
1009    $unit="o"; $div=1;
1010    break;
1011   case "K":
1012    $unit="Ko"; $div=1000;
1013    break;
1014   case "M":
1015    $unit="Mo"; $div=1000000;
1016    break;
1017   case "G":
1018    $unit="Go"; $div=1000000000;
1019    break;
1020   case "Ki":
1021    $unit="Kio"; $div=1024;
1022    break;
1023   case "Mi":
1024    $unit="Mio"; $div=1024000;
1025    break;
1026   case "Gi":
1027    $unit="Gio"; $div=1024000000;
1028    break;
1029  }
1030
1031  $returned=number_format($octets/$div, $prec, '.', $thsep);
1032  if($visible) $returned.=' '.$unit;
1033  return($returned);
1034 } //function formatOctet
1035
1036
1037 /**
1038  * affect a valid token in a template var {$token}
1039  */
1040 static public function setTemplateToken()
1041 {
1042   global $template;
1043
1044   $template->assign('token', get_pwg_token());
1045 }
1046
1047
1048} //class
1049
1050GPCCore::init();
1051
1052?>
Note: See TracBrowser for help on using the repository browser.