Index: /extensions/skeleton/tags/2.6/admin.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin.php	(revision 28634)
@@ -0,0 +1,40 @@
+<?php
+/**
+ * This is the main administration page, if you have only one admin page you can put 
+ * directly its code here or using the tabsheet system like bellow
+ */
+
+defined('SKELETON_PATH') or die('Hacking attempt!');
+ 
+global $template, $page, $conf;
+
+
+// get current tab
+$page['tab'] = (isset($_GET['tab'])) ? $_GET['tab'] : $page['tab'] = 'home';
+
+// plugin tabsheet is not present on photo page
+if ($page['tab'] != 'photo')
+{
+  // tabsheet
+  include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+  $tabsheet = new tabsheet();
+  $tabsheet->set_id('skeleton');
+  
+  $tabsheet->add('home', l10n('Welcome'), SKELETON_ADMIN . '-home');
+  $tabsheet->add('config', l10n('Configuration'), SKELETON_ADMIN . '-config');
+  $tabsheet->select($page['tab']);
+  $tabsheet->assign();
+}
+
+// include page
+include(SKELETON_PATH . 'admin/' . $page['tab'] . '.php');
+
+// template vars
+$template->assign(array(
+  'SKELETON_PATH'=> SKELETON_PATH, // used for images, scripts, ... access
+  'SKELETON_ABS_PATH'=> realpath(SKELETON_PATH),    // used for template inclusion (Smarty needs a real path)
+  'SKELETON_ADMIN' => SKELETON_ADMIN,
+  ));
+  
+// send page content
+$template->assign_var_from_handle('ADMIN_CONTENT', 'skeleton_content');
Index: /extensions/skeleton/tags/2.6/admin/config.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin/config.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/config.php	(revision 28634)
@@ -0,0 +1,34 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+// +-----------------------------------------------------------------------+
+// | Configuration tab                                                     |
+// +-----------------------------------------------------------------------+
+
+// save config
+if (isset($_POST['save_config']))
+{
+  $conf['skeleton'] = array(
+    'option1' => intval($_POST['option1']),
+    'option2' => isset($_POST['option2']),
+    'option3' => $_POST['option3'],
+    );
+      
+  conf_update_param('skeleton', serialize($conf['skeleton']));
+  array_push($page['infos'], l10n('Information data registered in database'));
+}
+
+$select_options = array(
+  'one' => l10n('One'),
+  'two' => l10n('Two'),
+  'three' => l10n('Three'),
+  );
+  
+// send config to template
+$template->assign(array(
+  'skeleton' => $conf['skeleton'],
+  'select_options' => $select_options
+  ));
+
+// define template file
+$template->set_filename('skeleton_content', realpath(SKELETON_PATH . 'admin/template/config.tpl'));
Index: /extensions/skeleton/tags/2.6/admin/home.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin/home.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/home.php	(revision 28634)
@@ -0,0 +1,15 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+// +-----------------------------------------------------------------------+
+// | Home tab                                                              |
+// +-----------------------------------------------------------------------+
+
+// send variables to template
+$template->assign(array(
+  'skeleton' => $conf['skeleton'],
+  'INTRO_CONTENT' => load_language('intro.html', SKELETON_PATH, array('return'=>true)),
+  ));
+
+// define template file
+$template->set_filename('skeleton_content', realpath(SKELETON_PATH . 'admin/template/home.tpl'));
Index: /extensions/skeleton/tags/2.6/admin/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/index.php	(revision 28634)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/admin/photo.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin/photo.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/photo.php	(revision 28634)
@@ -0,0 +1,48 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+// +-----------------------------------------------------------------------+
+// | Photo[Skeleton] tab                                                   |
+// +-----------------------------------------------------------------------+
+
+$page['active_menu'] = get_active_menu('photo'); // force oppening "Photos" menu block
+
+/* Basic checks */
+check_status(ACCESS_ADMINISTRATOR);
+
+check_input_parameter('image_id', $_GET, false, PATTERN_ID);
+
+$admin_photo_base_url = get_root_url().'admin.php?page=photo-'.$_GET['image_id'];
+$self_url = SKELETON_ADMIN.'-photo&amp;image_id='.$_GET['image_id'];
+
+
+/* Tabs */
+// when adding a tab to an existing tabsheet you MUST reproduce the core tabsheet code
+// this way it will not break compatibility with other plugins and with core functions
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+$tabsheet = new tabsheet();
+$tabsheet->set_id('photo'); // <= don't forget tabsheet id
+$tabsheet->select('skeleton');
+$tabsheet->assign();
+
+
+/* Initialisation */
+$query = '
+SELECT *
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$_GET['image_id'].'
+;';
+$picture = pwg_db_fetch_assoc(pwg_query($query));
+
+# DO SOME STUFF HERE... or not !
+
+
+/* Template */
+$template->assign(array(
+  'F_ACTION' => $self_url,
+  'skeleton' => $conf['skeleton'],
+  'TITLE' => render_element_name($picture),
+  'TN_SRC' => DerivativeImage::thumb_url($picture),
+));
+
+$template->set_filename('skeleton_content', realpath(SKELETON_PATH . 'admin/template/photo.tpl'));
Index: /extensions/skeleton/tags/2.6/admin/template/config.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/admin/template/config.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/template/config.tpl	(revision 28634)
@@ -0,0 +1,50 @@
+{combine_css path=$SKELETON_PATH|@cat:"admin/template/style.css"}
+
+{footer_script}{literal}
+jQuery('input[name="option2"]').change(function() {
+  $('.option1').toggle();
+});
+
+jQuery(".showInfo").tipTip({
+  delay: 0,
+  fadeIn: 200,
+  fadeOut: 200,
+  maxWidth: '300px',
+  defaultPosition: 'bottom'
+});
+{/literal}{/footer_script}
+
+<div class="titrePage">
+	<h2>Skeleton</h2>
+</div>
+
+<form method="post" action="" class="properties">
+<fieldset>
+  <legend>{'Common configuration'|translate}</legend>
+  
+  <ul>
+    <li>
+      <label>
+        <input type="checkbox" name="option2" value="1" {if $skeleton.option2}checked="checked"{/if}>
+        <b>{'Checkbox'|translate}</b>
+      </label>
+      <a class="icon-info-circled-1 showInfo" title="{'Check me!'|translate}"></a>
+    </li>
+    <li class="option1" {if not $skeleton.option2}style="display:none;"{/if}>
+      <label>
+        <b>{'Integer'|translate}</b>
+        <input type="text" name="option1" value="{$skeleton.option1}" size="4">
+      </label>
+    </li>
+    <li>
+      <label>
+        <b>{'Select'|translate}</b>
+        {html_options name=option3 options=$select_options selected=$skeleton.option3}
+      </label>
+    </li>
+  </ul>
+</fieldset>
+
+<p class="formButtons"><input type="submit" name="save_config" value="{'Save Settings'|translate}"></p>
+
+</form>
Index: /extensions/skeleton/tags/2.6/admin/template/home.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/admin/template/home.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/template/home.tpl	(revision 28634)
@@ -0,0 +1,18 @@
+{combine_css path=$SKELETON_PATH|@cat:"admin/template/style.css"}
+
+{html_style}{literal}
+h4 { text-align:left !important; }
+{/literal}{/html_style}
+
+<div class="titrePage">
+	<h2>Skeleton</h2>
+</div>
+
+<form method="post" action="" class="properties">
+<fieldset>
+  <legend>{'What Skeleton can do for me?'|translate}</legend>
+  
+  {$INTRO_CONTENT}
+</fieldset>
+  
+</form>
Index: /extensions/skeleton/tags/2.6/admin/template/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/admin/template/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/template/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/admin/template/photo.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/admin/template/photo.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/template/photo.tpl	(revision 28634)
@@ -0,0 +1,18 @@
+{combine_css path=$SKELETON_PATH|@cat:"admin/template/style.css"}
+
+<h2>{$TITLE} &#8250; {'Edit photo'|translate} {$TABSHEET_TITLE}</h2>
+
+
+<form action="{$F_ACTION}" method="post" id="catModify">
+  <fieldset>
+    <legend>{'My awesome photo tab'|translate}</legend>
+
+    <p>
+      <img src="{$TN_SRC}" alt="{'Thumbnail'|translate}" class="Thumbnail">
+    </p>
+
+    <p>
+      <input class="submit" type="submit" value="{'Save'|translate}" name="save_skeleton">
+    </p>
+  </fieldset>
+</form>
Index: /extensions/skeleton/tags/2.6/admin/template/style.css
===================================================================
--- /extensions/skeleton/tags/2.6/admin/template/style.css	(revision 28634)
+++ /extensions/skeleton/tags/2.6/admin/template/style.css	(revision 28634)
@@ -0,0 +1,7 @@
+.square-list {
+  list-style:square !important;
+  margin-left:35px !important;
+}
+  .square-list li {
+    margin-bottom:0 !important;
+  }
Index: /extensions/skeleton/tags/2.6/include/admin_events.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/admin_events.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/admin_events.inc.php	(revision 28634)
@@ -0,0 +1,96 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+/**
+ * admin plugins menu link
+ */
+function skeleton_admin_plugin_menu_links($menu) 
+{
+  $menu[] = array(
+    'NAME' => l10n('Skeleton'),
+    'URL' => SKELETON_ADMIN,
+    );
+
+  return $menu;
+}
+
+/**
+ * add a tab on photo properties page
+ */
+function skeleton_tabsheet_before_select($sheets, $id)
+{
+  if ($id == 'photo')
+  {
+    $sheets['skeleton'] = array(
+      'caption' => l10n('Skeleton'),
+      'url' => SKELETON_ADMIN.'-photo&amp;image_id='.$_GET['image_id'],
+      );
+  }
+  
+  return $sheets;
+}
+
+/**
+ * add a prefilter to the Batch Downloader
+ */
+function skeleton_add_batch_manager_prefilters($prefilters)
+{
+	array_push($prefilters, array(
+    'ID' => 'skeleton',
+    'NAME' => l10n('Skeleton'),
+  ));
+	return $prefilters;
+}
+
+/**
+ * perform added prefilter
+ */
+function skeleton_perform_batch_manager_prefilters($filter_sets, $prefilter)
+{
+  if ($prefilter == 'skeleton')
+  {
+    $query = '
+SELECT id
+  FROM '.IMAGES_TABLE.'
+  ORDER BY RAND()
+  LIMIT 20
+;';
+    $filter_sets[] = array_from_query($query, 'id');
+  }
+  
+	return $filter_sets;
+}
+
+/**
+ * add an action to the Batch Manager
+ */
+function skeleton_loc_end_element_set_global()
+{
+	global $template;
+  
+	$template->append('element_set_global_plugins_actions', array(
+    'ID' => 'skeleton', 
+    'NAME' => l10n('Skeleton'), 
+    'CONTENT' => '<label><input type="checkbox" name="check_skeleton"> '.l10n('Check me!').'</label>', // this is optional
+    ));
+}
+
+/**
+ * perform added action
+ */
+function skeleton_element_set_global_action($action, $collection)
+{
+	if ($action == 'skeleton')
+  {
+    global $page;
+    
+    if (empty($_POST['check_skeleton']))
+    {
+      array_push($page['warnings'], l10n('Nothing appened, but you didn\'t check the box!'));
+    }
+    else
+    {
+      array_push($page['infos'], l10n('Nothing appened, but you checked the box!'));
+    }
+  }
+}
Index: /extensions/skeleton/tags/2.6/include/functions.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/functions.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/functions.inc.php	(revision 28634)
@@ -0,0 +1,4 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+// you can add something here :-)
Index: /extensions/skeleton/tags/2.6/include/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/include/menu_events.class.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/menu_events.class.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/menu_events.class.php	(revision 28634)
@@ -0,0 +1,78 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+/*
+ * there is two ways to use class methods as event handlers:
+ *
+ **   add_event_handler('blockmanager_apply', array('SkeletonMenu', 'blockmanager_apply'));
+ *      in this case the method 'blockmanager_apply' must be a static method of the class 'SkeletonMenu'
+ *
+ **   $myObj = new SkeletonMenu();
+ **   add_event_handler('blockmanager_apply', array(&$myObj, 'blockmanager_apply') );
+ *      in this case the method 'blockmanager_apply' must be a public method of the object '$myObj'
+ */
+
+class SkeletonMenu
+{
+  /**
+   * add link in existing menu
+   */
+  static function blockmanager_apply1($menu_ref_arr)
+  {
+    $menu = &$menu_ref_arr[0];  
+    
+    if ( ($block = $menu->get_block('mbMenu')) != null )
+    {
+      array_push($block->data, array(
+        'URL' => SKELETON_PUBLIC,
+        'TITLE' => l10n('Skeleton'),
+        'NAME' => l10n('Skeleton'),
+      ));
+    }
+  }
+
+  /**
+   * add a new menu block
+   */
+  static function blockmanager_register_blocks($menu_ref_arr)
+  {
+    $menu = &$menu_ref_arr[0];
+    
+    if ($menu->get_id() == 'menubar')
+    {
+      $menu->register_block(new RegisteredBlock('mbSkeleton', l10n('Skeleton'), 'skeleton'));
+    }
+  }
+
+  /**
+   * fill the added menu block
+   */
+  static function blockmanager_apply2($menu_ref_arr)
+  {
+    $menu = &$menu_ref_arr[0];
+    
+    if ( ($block = $menu->get_block('mbSkeleton')) != null )
+    {
+      global $template;
+      
+      $block->set_title(l10n('Skeleton'));
+      
+      $block->data['link1'] =
+        array(
+          'URL' => get_absolute_root_url(),
+          'TITLE' => l10n('First link'),
+          'NAME' => l10n('Link 1'),
+          'REL'=> 'rel="nofollow"',
+        );
+
+      $block->data['link2'] =
+        array(
+          'URL' => SKELETON_PUBLIC,
+          'TITLE' => l10n('Second link'),
+          'NAME' => l10n('Link 2'),
+        );
+      
+      $block->template = realpath(SKELETON_PATH . 'template/menubar_skeleton.tpl');
+    }
+  }
+}
Index: /extensions/skeleton/tags/2.6/include/public_events.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/public_events.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/public_events.inc.php	(revision 28634)
@@ -0,0 +1,78 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+/**
+ * detect current section
+ */
+function skeleton_loc_end_section_init()
+{
+  global $tokens, $page, $conf;
+
+  if ($tokens[0] == 'skeleton')
+  {
+    $page['section'] = 'skeleton';
+    
+    // section_title is for breadcrumb, title is for page <title>
+    $page['section_title'] = '<a href="'.get_absolute_root_url().'">'.l10n('Home').'</a>'.$conf['level_separator'].'<a href="'.SKELETON_PUBLIC.'">'.l10n('Skeleton').'</a>';
+    $page['title'] = l10n('Skeleton');
+    
+    $page['body_id'] = 'theSkeletonPage';
+    $page['is_external'] = true; // inform Piwigo that you are on a new page
+  }
+}
+
+/**
+ * include public page
+ */
+function skeleton_loc_end_page()
+{
+  global $page, $template;
+
+  if ( isset($page['section']) and $page['section']=='skeleton' )
+  {
+    include(SKELETON_PATH . 'include/skeleton_page.inc.php');
+  }
+}
+
+/*
+ * button on album and photos pages
+ */
+function skeleton_add_button()
+{
+  global $template;
+  
+  $template->assign('SKELETON_PATH', SKELETON_PATH);
+  $template->set_filename('skeleton_button', realpath(SKELETON_PATH.'template/my_button.tpl'));
+  $button = $template->parse('skeleton_button', true);
+  
+  if (script_basename()=='index')
+  {
+    $template->add_index_button($button, EVENT_HANDLER_PRIORITY_NEUTRAL);
+  }
+  else
+  {
+    $template->add_picture_button($button, EVENT_HANDLER_PRIORITY_NEUTRAL);
+  }
+}
+
+/**
+ * add a prefilter on photo page
+ */
+function skeleton_loc_end_picture()
+{
+  global $template;
+  
+  $template->set_prefilter('picture', 'skeleton_picture_prefilter');
+}
+
+function skeleton_picture_prefilter($content)
+{
+  $search = '{if $display_info.author and isset($INFO_AUTHOR)}';
+  $replace = '<div id="Skeleton" class="imageInfo">
+		<dt>{\'Skeleton\'|@translate}</dt>
+		<dd style="color:orange;">{\'Piwigo rocks\'|@translate}</dd>
+	</div>
+'.$search;
+
+  return str_replace($search, $replace, $content);
+}
Index: /extensions/skeleton/tags/2.6/include/skeleton_page.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/skeleton_page.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/skeleton_page.inc.php	(revision 28634)
@@ -0,0 +1,17 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+global $page, $template, $conf, $user, $tokens, $pwg_loaded_plugins;
+
+
+# DO SOME STUFF HERE... or not !
+
+
+$template->assign(array(
+  'INTRO_CONTENT' => load_language('intro.html', SKELETON_PATH, array('return'=>true)),
+  'SKELETON_PATH' => SKELETON_PATH,
+  'SKELETON_ABS_PATH' => realpath(SKELETON_PATH).'/',
+  ));
+
+$template->set_filename('skeleton_page', realpath(SKELETON_PATH . 'template/skeleton_page.tpl'));
+$template->assign_var_from_handle('CONTENT', 'skeleton_page');
Index: /extensions/skeleton/tags/2.6/include/ws_functions.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/include/ws_functions.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/include/ws_functions.inc.php	(revision 28634)
@@ -0,0 +1,29 @@
+<?php
+defined('SKELETON_PATH') or die('Hacking attempt!');
+
+function skeleton_ws_add_methods($arr)
+{
+  $service = &$arr[0];
+  
+  $service->addMethod(
+    'pwg.PHPinfo',
+    'ws_php_info',
+    array(
+      'what' => array('default'=>'INFO_ALL', 'info'=>'This parameter has a default value'),
+      'ids' => array('flags'=>WS_PARAM_FORCE_ARRAY, 'info'=>'This one must be an array'),
+      ),
+    'Returns phpinfo (don\'t use XML request format)',
+    null,
+    array('hidden' => false) // you can hide your method from reflection.getMethodList method
+    );
+}
+
+function ws_php_info($params, &$service)
+{
+  if (!is_admin())
+  {
+    return new PwgError(403, 'Forbidden');
+  }
+  
+  return phpinfo(constant($params['what']));
+}
Index: /extensions/skeleton/tags/2.6/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/language/en_UK/description.txt
===================================================================
--- /extensions/skeleton/tags/2.6/language/en_UK/description.txt	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/en_UK/description.txt	(revision 28634)
@@ -0,0 +1,1 @@
+This is not a plugin. It's a skeleton for future plugins.
Index: /extensions/skeleton/tags/2.6/language/en_UK/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/language/en_UK/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/en_UK/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/language/en_UK/intro.html
===================================================================
--- /extensions/skeleton/tags/2.6/language/en_UK/intro.html	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/en_UK/intro.html	(revision 28634)
@@ -0,0 +1,31 @@
+<p>
+  <h4>You are a common user?</h4>
+  If so, this plugin is totally useless and you should delete it!
+</p>
+
+<p>
+  <h4>You want to develop a Piwigo plugin?</h4>
+  This plugin is an example of a simple plugin structure, but with cool options:
+  <ul class="square-list">
+    <li>Multilingual plugin</li>
+    <li>Installation and upgrade process</li>
+    <li>Administration page</li>
+    <li>Public page</li>
+    <li>Add tabs to core admin pages</li>
+    <li>Add filters and actions to the Batch Manager</li>
+    <li>Simple template prefilter (on picture.php page)</li>
+    <li>Add new method to the API</li>
+    <li>Add a toolbar button</li>
+  </ul>
+</p>
+
+<p>
+  <h4>Important note</h4>
+  This skeleton reflects the way I (Mistic, member of the Piwigo.or team) develop, it's absolutely not a perfect and unique solution.<br>
+  You should not use the Skeleton files for your own plugin, it includes features useless for most plugins but making Piwigo slower and heavier. You should see how it works and try to implement these features whith your habits of coding and your knowledges.
+</p>
+
+<p>
+  <h4>Licensing</h4>
+  This work is in the public domain, without any license, you can entirely re-use it and say it's your own work :-)
+</p>
Index: /extensions/skeleton/tags/2.6/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/skeleton/tags/2.6/language/en_UK/plugin.lang.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/en_UK/plugin.lang.php	(revision 28634)
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * as much as possible prefer using comprehensive keys (such as "Check here") instead of
+ * formatted keys (eg "skeleton_check_button"), it would make your code more readable and help
+ * the translation team as well
+ */
+
+$lang['Skeleton'] = 'Skeleton';
+$lang['What Skeleton can do for me?'] = 'What Skeleton can do for me?';
+$lang['Check me!'] = 'Check me!';
+$lang['Nothing appened, but you didn\'t check the box!'] = 'Nothing appened, but you didn\'t check the box!';
+$lang['Nothing appened, but you checked the box!'] = 'Nothing appened, but you checked the box!';
+$lang['Common configuration'] = 'Common configuration';
+
+?>
Index: /extensions/skeleton/tags/2.6/language/fr_FR/description.txt
===================================================================
--- /extensions/skeleton/tags/2.6/language/fr_FR/description.txt	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/fr_FR/description.txt	(revision 28634)
@@ -0,0 +1,1 @@
+Ceci n'est pas un plugin. C'est un canevas pour de futurs plugins.
Index: /extensions/skeleton/tags/2.6/language/fr_FR/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/language/fr_FR/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/fr_FR/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/language/fr_FR/intro.html
===================================================================
--- /extensions/skeleton/tags/2.6/language/fr_FR/intro.html	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/fr_FR/intro.html	(revision 28634)
@@ -0,0 +1,31 @@
+<p>
+  <h4>Vous êtes utilisateur ?</h4>
+  Dans ce cas: rien, et vous feriez mieux de supprimer ce plugin !
+</p>
+
+<p>
+  <h4>Vous souhaitez développer un plugin pour Piwigo ?</h4>
+  Ce plugin est un exemple de structure basique de plugin, mais avec des fonctionnalités cool :
+  <ul class="square-list">
+    <li>Plugin multilingue</li>
+    <li>Procédure d'installation et mise à jour automatique</li>
+    <li>Page d'administration</li>
+    <li>Page publique</li>
+    <li>Ajout d'onglet sur les pages d'administration existantes</li>
+    <li>Ajout des filtres et actions au gestionnaire de lots</li>
+    <li>Préfiltre de template simple (sur page picture.php)</li>
+    <li>Ajout d'une méthode à l'API</li>
+    <li>Ajout d'un bouton dans la barre d'outils</li>
+  </ul>
+</p>
+
+<p>
+  <h4>Note importante</h4>
+  Skeleton reflète la façon dont je (Mistic, membre de l'équipe Piwigo.org) développe, ce n'est certainement pas un solution parfaite et unique.<br>
+  Vous ne devriez pas directement developper vos plugins à partir du code de Skeleton, il inclut des fonctionnalités inutiles pour la plupart des plugins mais qui rendent Piwigo plus lourd et plus lent. Préférez comprendre comment ça fonctionne et implémenter les fonctionnalités à votre façon.
+</p>
+
+<p>
+  <h4>License</h4>
+  Ce plugin est dans le domaine publique, aucune license ne s'y applique, vous pouvez sans problème vous approprier le code sans contrepartie ou mention :-)
+</p>
Index: /extensions/skeleton/tags/2.6/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/skeleton/tags/2.6/language/fr_FR/plugin.lang.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/fr_FR/plugin.lang.php	(revision 28634)
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * as much as possible prefer using comprehensive keys (such as "Check here") instead of
+ * formatted keys (eg "skeleton_check_button"), it would make your code more readable and help
+ * the translation team as well
+ */
+
+$lang['Skeleton'] = 'Skeleton';
+$lang['What Skeleton can do for me?'] = 'Qu\'est-ce que Skeleton peut faire pour moi ?';
+$lang['Check me!'] = 'Cliquez-moi !';
+$lang['Nothing appened, but you didn\'t check the box!'] = 'Rien ne s\'est passé, mais vous n\'avez pas coché la case !';
+$lang['Nothing appened, but you checked the box!'] = 'Rien ne s\'est passé, mais vous avez coché la case !';
+$lang['Common configuration'] = 'Configuration commune';
+
+?>
Index: /extensions/skeleton/tags/2.6/language/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/language/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/language/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/main.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/main.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/main.inc.php	(revision 28634)
@@ -0,0 +1,128 @@
+<?php 
+/*
+Plugin Name: skeleton
+Version: auto
+Description: This is not a plugin. It's a skeleton for future plugins.
+Plugin URI: auto
+Author: Mistic
+Author URI: http://www.strangeplanet.fr
+*/
+
+/**
+ * This is te main file of the plugin, called by Piwigo in "include/common.inc.php" line 137.
+ * At this point of the code, Piwigo is not completely initialized, so nothing should be done directly
+ * except define constants and event handlers (see http://piwigo.org/doc/doku.php?id=dev:plugins)
+ */
+
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
+
+global $prefixeTable;
+
+
+// +-----------------------------------------------------------------------+
+// | Define plugin constants                                               |
+// +-----------------------------------------------------------------------+
+define('SKELETON_ID',      basename(dirname(__FILE__)));
+define('SKELETON_PATH' ,   PHPWG_PLUGINS_PATH . SKELETON_ID . '/');
+define('SKELETON_TABLE',   $prefixeTable . 'skeleton');
+define('SKELETON_ADMIN',   get_root_url() . 'admin.php?page=plugin-' . SKELETON_ID);
+define('SKELETON_PUBLIC',  get_absolute_root_url() . make_index_url(array('section' => 'skeleton')) . '/');
+define('SKELETON_DIR',     PHPWG_ROOT_PATH . PWG_LOCAL_DIR . 'skeleton/');
+define('SKELETON_VERSION', 'auto');
+// this is automatically updated by PEM if you publish your plugin with SVN, otherwise you musn't forget to change it, as well as "Version" in the plugin header
+
+
+
+// +-----------------------------------------------------------------------+
+// | Add event handlers                                                    |
+// +-----------------------------------------------------------------------+
+// init the plugin
+add_event_handler('init', 'skeleton_init');
+
+/*
+ * this is the common way to define event functions: create a new function for each event you want to handle
+ */
+if (defined('IN_ADMIN'))
+{
+  // file containing all admin handlers functions
+  include_once(SKELETON_PATH . 'include/admin_events.inc.php');
+  
+  // admin plugins menu link
+  add_event_handler('get_admin_plugin_menu_links', 'skeleton_admin_plugin_menu_links');
+  
+  // new tab on photo page
+  add_event_handler('tabsheet_before_select', 'skeleton_tabsheet_before_select', EVENT_HANDLER_PRIORITY_NEUTRAL, 2);
+  
+  // new prefiler in Batch Manager
+  add_event_handler('get_batch_manager_prefilters', 'skeleton_add_batch_manager_prefilters');
+  add_event_handler('perform_batch_manager_prefilters', 'skeleton_perform_batch_manager_prefilters', EVENT_HANDLER_PRIORITY_NEUTRAL, 2);
+  
+  // new action in Batch Manager
+  add_event_handler('loc_end_element_set_global', 'skeleton_loc_end_element_set_global');
+  add_event_handler('element_set_global_action', 'skeleton_element_set_global_action', EVENT_HANDLER_PRIORITY_NEUTRAL, 2);
+}
+else
+{
+  // file containing all public handlers functions
+  include_once(SKELETON_PATH . 'include/public_events.inc.php');
+  
+  // add a public section
+  add_event_handler('loc_end_section_init', 'skeleton_loc_end_section_init');
+  add_event_handler('loc_end_index', 'skeleton_loc_end_page');
+  
+  // add button on album and photos pages
+  add_event_handler('loc_end_index', 'skeleton_add_button');
+  add_event_handler('loc_end_picture', 'skeleton_add_button');
+  
+  // prefilter on photo page
+  add_event_handler('loc_end_picture', 'skeleton_loc_end_picture');
+}
+
+// add API function
+add_event_handler('ws_add_methods', 'skeleton_ws_add_methods');
+
+
+/*
+ * event functions can also be wrapped in a class
+ */
+
+// file containing the class for menu handlers functions
+include_once(SKELETON_PATH . 'include/menu_events.class.php');
+
+// add item to existing menu (EVENT_HANDLER_PRIORITY_NEUTRAL+10 is for compatibility with Advanced Menu Manager plugin)
+add_event_handler('blockmanager_apply', array('SkeletonMenu', 'blockmanager_apply1'), EVENT_HANDLER_PRIORITY_NEUTRAL+10);
+
+// add a new menu block (the declaration must be done every time, in order to be able to manage the menu block in "Menus" screen and Advanced Menu Manager)
+add_event_handler('blockmanager_register_blocks', array('SkeletonMenu', 'blockmanager_register_blocks'));
+add_event_handler('blockmanager_apply', array('SkeletonMenu', 'blockmanager_apply2'));
+// NOTE: blockmanager_apply1() and blockmanager_apply2() can (must) be merged
+
+
+
+// files containing specific plugin functions
+include_once(SKELETON_PATH . 'include/functions.inc.php');
+include_once(SKELETON_PATH . 'include/ws_functions.inc.php');
+
+
+
+/**
+ * plugin initialization
+ *   - check for upgrades
+ *   - unserialize configuration
+ *   - load language
+ */
+function skeleton_init()
+{
+  global $conf;
+  
+  // apply upgrade if needed
+  include_once(SKELETON_PATH . 'maintain.inc.php');
+  $maintain = new skeleton_maintain(SKELETON_ID);
+  $maintain->autoUpdate(SKELETON_VERSION, 'install');
+  
+  // load plugin language file
+  load_language('plugin.lang', SKELETON_PATH);
+  
+  // prepare plugin configuration
+  $conf['skeleton'] = unserialize($conf['skeleton']);
+}
Index: /extensions/skeleton/tags/2.6/maintain.inc.php
===================================================================
--- /extensions/skeleton/tags/2.6/maintain.inc.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/maintain.inc.php	(revision 28634)
@@ -0,0 +1,141 @@
+<?php
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
+
+/**
+ * This class is used to expose maintenance methods to the plugins manager
+ * It must extends PluginMaintain and be named "PLUGINID_maintain"
+ * where PLUGINID is the directory name of your plugin
+ */
+class skeleton_maintain extends PluginMaintain
+{
+  /*
+   * My pattern uses a single installation method, which handles both installation
+   * and activation, where Piwigo always calls 'activate' just after 'install'
+   * As a result I use a marker in order to not execute the installation method twice
+   *
+   * The installation function is called by main.inc.php and maintain.inc.php
+   * in order to install and/or update the plugin.
+   *
+   * That's why all operations must be conditionned :
+   *    - use "if empty" for configuration vars
+   *    - use "IF NOT EXISTS" for table creation
+   */
+  private $installed = false;
+  
+  private $default_conf = array(
+    'option1' => 10,
+    'option2' => true,
+    'option3' => 'two',
+    );
+
+  /**
+   * plugin installation
+   *
+   * perform here all needed step for the plugin installation
+   * such as create default config, add database tables,
+   * add fields to existing tables, create local folders...
+   */
+  function install($plugin_version, &$errors=array())
+  {
+    global $conf, $prefixeTable;
+
+    // add config parameter
+    if (empty($conf['skeleton']))
+    {
+      $conf['skeleton'] = serialize($this->default_conf);
+      conf_update_param('skeleton', $conf['skeleton']);
+    }
+    else
+    {
+      // if you need to test the "old" configuration you must check if not yet unserialized
+      $old_conf = is_string($conf['skeleton']) ? unserialize($conf['skeleton']) : $conf['skeleton'];
+
+      if (empty($old_conf['option3']))
+      { // use case: this parameter was added in a new version
+        $old_conf['option3'] = 'two';
+      }
+
+      $conf['skeleton'] = serialize($old_conf);
+      conf_update_param('skeleton', $conf['skeleton']);
+    }
+
+    // add a new table
+    pwg_query('
+CREATE TABLE IF NOT EXISTS `'. $prefixeTable .'skeleton` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `field1` mediumint(8) DEFAULT NULL,
+  `field2` varchar(64) NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+;');
+
+    // add a new column to existing table
+    $result = pwg_query('SHOW COLUMNS FROM `'.IMAGES_TABLE.'` LIKE "skeleton";');
+    if (!pwg_db_num_rows($result))
+    {
+      pwg_query('ALTER TABLE `' . IMAGES_TABLE . '` ADD `skeleton` TINYINT(1) NOT NULL DEFAULT 0;');
+    }
+
+    // create a local directory
+    if (!file_exists(PHPWG_ROOT_PATH . PWG_LOCAL_DIR . 'skeleton/'))
+    {
+      mkdir(PHPWG_ROOT_PATH . PWG_LOCAL_DIR . 'skeleton/', 0755);
+    }
+
+    $this->installed = true;
+  }
+
+  /**
+   * plugin activation
+   *
+   * this function is triggered after installation, by manual activation
+   * or after a plugin update
+   * for this last case you must manage updates tasks of your plugin in this function
+   */
+  function activate($plugin_version, &$errors=array())
+  {
+    if (!$this->installed)
+    {
+      $this->install($plugin_version, $errors);
+    }
+  }
+
+  /**
+   * plugin deactivation
+   *
+   * triggered before uninstallation or by manual deactivation
+   */
+  function deactivate()
+  {
+  }
+
+  /**
+   * plugin uninstallation
+   *
+   * perform here all cleaning tasks when the plugin is removed
+   * you should revert all changes made by 'install'
+   */
+  function uninstall()
+  {
+    global $prefixeTable;
+
+    // delete configuration
+    conf_delete_param('skeleton');
+
+    // delete table
+    pwg_query('DROP TABLE `'. $prefixeTable .'skeleton`;');
+
+    // delete field
+    pwg_query('ALTER TABLE `'. IMAGES_TABLE .'` DROP `skeleton`;');
+
+    // delete local folder
+    // use a recursive function if you plan to have nested directories
+    $dir = PHPWG_ROOT_PATH . PWG_LOCAL_DIR . 'skeleton/';
+    foreach (scandir($dir) as $file)
+    {
+      if ($file == '.' or $file == '..') continue;
+      unlink($dir.$file);
+    }
+    rmdir($dir);
+  }
+}
Index: /extensions/skeleton/tags/2.6/template/index.php
===================================================================
--- /extensions/skeleton/tags/2.6/template/index.php	(revision 28634)
+++ /extensions/skeleton/tags/2.6/template/index.php	(revision 28634)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/skeleton/tags/2.6/template/menubar_skeleton.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/template/menubar_skeleton.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/template/menubar_skeleton.tpl	(revision 28634)
@@ -0,0 +1,9 @@
+<dt>{$block->get_title()}</dt>
+<dd>
+  {'Menublock added by Skeleton plugin'|translate}
+	<ul>{strip}
+		{foreach from=$block->data item=link}
+		<li><a href="{$link.URL}" title="{$link.TITLE}"{if isset($link.REL)} {$link.REL}{/if}>{$link.NAME}</a></li>
+		{/foreach}
+	{/strip}</ul>
+</dd>
Index: /extensions/skeleton/tags/2.6/template/my_button.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/template/my_button.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/template/my_button.tpl	(revision 28634)
@@ -0,0 +1,6 @@
+{strip}
+<a href="javascript:alert('Hello world!');" title="{'This is not the %s you are looking for'|translate:('button'|translate)}" class="pwg-state-default pwg-button" rel="nofollow">
+  <span class="pwg-icon" style="background:url('{$ROOT_URL}{$SKELETON_PATH}template/head.png') center center no-repeat;"> </span>
+  <span class="pwg-button-text">{'Skeleton'|translate}</span>
+</a>
+{/strip}
Index: /extensions/skeleton/tags/2.6/template/skeleton_page.tpl
===================================================================
--- /extensions/skeleton/tags/2.6/template/skeleton_page.tpl	(revision 28634)
+++ /extensions/skeleton/tags/2.6/template/skeleton_page.tpl	(revision 28634)
@@ -0,0 +1,27 @@
+{combine_css path=$SKELETON_PATH|@cat:"template/style.css"}
+
+{* <!-- add scripts here --> *}
+{footer_script require='jquery'}{literal}
+var reverse=0;
+$("#test").click(function() {
+  if (!reverse) {
+    $("body").css('-moz-transform','rotate(180deg)');
+    $("body").css('-webkit-transform','rotate(180deg)');
+    $("body").css('-o-transform','rotate(180deg)');
+    reverse=1;
+  } else {
+    $("body").css('-moz-transform','rotate(0deg)');
+    $("body").css('-webkit-transform','rotate(0deg)');
+    $("body").css('-o-transform','rotate(0deg)');
+    reverse=0;
+  }
+});
+{/literal}{/footer_script}
+
+{* <!-- add page content here --> *}
+<h1>{'What Skeleton can do for me?'|translate}</h1>
+<blockquote>
+  {$INTRO_CONTENT}
+</blockquote>
+
+<div id="test">{'Click for fun'|translate}</div>
Index: /extensions/skeleton/tags/2.6/template/style.css
===================================================================
--- /extensions/skeleton/tags/2.6/template/style.css	(revision 28634)
+++ /extensions/skeleton/tags/2.6/template/style.css	(revision 28634)
@@ -0,0 +1,31 @@
+#test {
+  width:400px;
+  height:30px;
+  margin:100px auto;
+  padding:30px;
+  font-size:30px;
+  text-align:center;
+  color:#fff;
+  border:5px outset #000;
+  background: #45484d;
+  background: -moz-linear-gradient(top,  #45484d 0%, #000000 100%);
+  background: -webkit-linear-gradient(top,  #45484d 0%,#000000 100%);
+  background: -o-linear-gradient(top,  #45484d 0%,#000000 100%);
+  background: -ms-linear-gradient(top,  #45484d 0%,#000000 100%);
+  background: linear-gradient(to bottom,  #45484d 0%,#000000 100%);
+  text-shadow:0 0 4px white, 0 -5px 4px #FFFF33, 2px -10px 6px #FFDD33, -2px -15px 11px #FF8800, 2px -25px 18px #FF2200;
+  border-radius:95px 5px;
+  -moz-transform:rotate(5deg);
+  -webkit-transform:rotate(5deg);
+  -o-transform:rotate(5deg);
+  transform:rotate(5deg);
+  letter-spacing:10px;
+  box-shadow:10px 10px 10px rgba(0,0,0,0.5);
+  cursor:pointer;
+}
+#test:hover {
+  -moz-transform:rotate(175deg);
+  -webkit-transform:rotate(175deg);
+  -o-transform:rotate(175deg);
+  transform:rotate(175deg);
+}
