diff --git a/3.0/modules/about/controllers/about.php b/3.0/modules/about/controllers/about.php
new file mode 100644
index 00000000..473c99a9
--- /dev/null
+++ b/3.0/modules/about/controllers/about.php
@@ -0,0 +1,28 @@
+css("about.css");
+ $template->page_title = t("Gallery :: About");
+ $template->content = new View("about.html");
+ print $template;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/about/controllers/admin_about.php b/3.0/modules/about/controllers/admin_about.php
new file mode 100644
index 00000000..b476c925
--- /dev/null
+++ b/3.0/modules/about/controllers/admin_about.php
@@ -0,0 +1,61 @@
+_get_view();
+ }
+
+ public function handler() {
+ access::verify_csrf();
+
+ $form = $this->_get_form();
+ if ($form->validate()) {
+ module::set_var(
+ "about", "code", $form->about->about_code->value);
+ module::set_var(
+ "about", "title", $form->about->about_title->value);
+ module::set_var (
+ "about", "hidden", $form->about->about_hidden->value);
+ message::success(t("Your settings have been saved."));
+ url::redirect("admin/about");
+ }
+
+ print $this->_get_view($form);
+ }
+
+ private function _get_view($form=null) {
+ $v = new Admin_View("admin.html");
+ $v->content = new View("admin_about.html");
+ $v->content->form = empty($form) ? $this->_get_form() : $form;
+ return $v;
+ }
+
+ private function _get_form() {
+ $form = new Forge("admin/about/handler", "", "post", array("id" => "g-admin-form"));
+ $group = $form->group("about");
+ $group->input("about_title")->label(t('Enter the headline.'))->value(module::get_var("about", "title"));
+ $group->textarea("about_code")->label(t('Enter the standard HTML code you want on the page.'))->value(module::get_var("about", "code"));
+ $group->checkbox("about_hidden")->label(t("Hide link"))
+ ->checked(module::get_var("about", "hidden", false) == 1);
+ $group->submit("submit")->value(t("Save"));
+
+ return $form;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/about/css/about.css b/3.0/modules/about/css/about.css
new file mode 100644
index 00000000..17903b24
--- /dev/null
+++ b/3.0/modules/about/css/about.css
@@ -0,0 +1,2 @@
+table.about { text-align: center; width:500px; }
+table.about caption { font-size: 1.5em; padding: 0.2em; }
\ No newline at end of file
diff --git a/3.0/modules/about/helpers/about_block.php b/3.0/modules/about/helpers/about_block.php
new file mode 100644
index 00000000..9dc85457
--- /dev/null
+++ b/3.0/modules/about/helpers/about_block.php
@@ -0,0 +1,39 @@
+ t("About page"));
+ }
+
+ static function get($block_id, $theme) {
+ $block = "";
+ switch ($block_id) {
+ case "about":
+ if ($theme->item()) {
+ $block = new Block();
+ $block->css_id = "g-metadata";
+ $block->title = module::get_var("about", "title");
+ $block->content = new View("about_block.html");
+ }
+ break;
+ }
+ return $block;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/about/helpers/about_event.php b/3.0/modules/about/helpers/about_event.php
new file mode 100644
index 00000000..e63aeb97
--- /dev/null
+++ b/3.0/modules/about/helpers/about_event.php
@@ -0,0 +1,37 @@
+get("settings_menu")
+ ->append(Menu::factory("link")
+ ->id("about_menu")
+ ->label(t("About page"))
+ ->url(url::site("admin/about")));
+ }
+
+ static function site_menu($menu, $theme) {
+ if (module::get_var("about", "hidden") != true) {
+ $menu->add_after("home", Menu::factory("link")
+ ->id("about")
+ ->label(t("About"))
+ ->url(url::site("about/")));
+ }
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/about/helpers/about_installer.php b/3.0/modules/about/helpers/about_installer.php
new file mode 100644
index 00000000..9725986e
--- /dev/null
+++ b/3.0/modules/about/helpers/about_installer.php
@@ -0,0 +1,26 @@
+
+
= module::get_var("about", "title"); ?>
+= module::get_var("about", "code"); ?>
\ No newline at end of file
diff --git a/3.0/modules/about/views/about_block.html.php b/3.0/modules/about/views/about_block.html.php
new file mode 100644
index 00000000..3fecf5cc
--- /dev/null
+++ b/3.0/modules/about/views/about_block.html.php
@@ -0,0 +1,2 @@
+
+= module::get_var("about", "code"); ?>
\ No newline at end of file
diff --git a/3.0/modules/about/views/admin_about.html.php b/3.0/modules/about/views/admin_about.html.php
new file mode 100644
index 00000000..c341bdc4
--- /dev/null
+++ b/3.0/modules/about/views/admin_about.html.php
@@ -0,0 +1,5 @@
+
+
+
= t("About Page Administration") ?>
+ = $form ?>
+
diff --git a/3.0/modules/addthis/config/addthis.php b/3.0/modules/addthis/config/addthis.php
new file mode 100644
index 00000000..04e314c9
--- /dev/null
+++ b/3.0/modules/addthis/config/addthis.php
@@ -0,0 +1,29 @@
+ email address that appears as the from address
+ * line-length => word wrap length (PHP documentations suggest no larger tha 70 characters
+ * reply-to => what goes into the reply to header
+ */
+$config["ranges"] = array(
+ "Addthis1" => array("low" => "65.249.152.0", "high" => "65.249.159.255"),
+ "Addthis2" => array("low" => "208.122.55.0", "high" => "208.122.55.255")
+);
diff --git a/3.0/modules/addthis/controllers/addthis.php b/3.0/modules/addthis/controllers/addthis.php
new file mode 100644
index 00000000..6e55a17b
--- /dev/null
+++ b/3.0/modules/addthis/controllers/addthis.php
@@ -0,0 +1,123 @@
+file_url(true);
+ $thumb_url = $item->thumb_url(true);
+ } else {
+ $proxy = ORM::factory("addthis_proxy");
+ $proxy->uuid = md5(rand());
+ $proxy->item_id = $item->id;
+ $proxy->save();
+ $full_url = url::abs_site("addthis/print_proxy/full/$proxy->uuid");
+ $thumb_url = url::abs_site("addthis/print_proxy/thumb/$proxy->uuid");
+ }
+
+ $v = new View("addthis_form.html");
+ $v->order_parms = array(
+ "addthis_api_version" => "100",
+ "company_id" => module::get_var("addthis", "company_id"),
+ "event_id" => module::get_var("addthis", "event_id"),
+ "cmd" => "addimg",
+ "partner_code" => "69",
+ "return_url" => url::abs_site("addthis/close_window"),
+ "num_images" => "1",
+ "image_1" => $full_url,
+ "thumb_1" => $thumb_url,
+ "image_height_1" => $item->height,
+ "image_width_1" => $item->width,
+ "thumb_height_1" => $item->thumb_height,
+ "thumb_width_1" => $item->thumb_width,
+ "title_1" => html::purify($item->title));
+
+ print $v;
+ }
+
+ public function print_proxy($type, $id) {
+ // If its a request for the full size then make sure we are coming from an
+ // authorized address
+ if ($type == "full") {
+ $remote_addr = ip2long($this->input->server("REMOTE_ADDR"));
+ if ($remote_addr === false) {
+ Kohana::show_404();
+ }
+ $config = Kohana::config("addthis");
+
+ $authorized = false;
+ foreach ($config["ranges"] as $ip_range) {
+ $low = ip2long($ip_range["low"]);
+ $high = ip2long($ip_range["high"]);
+ $authorized = $low !== false && $high !== false &&
+ $low <= $remote_addr && $remote_addr <= $high;
+ if ($authorized) {
+ break;
+ }
+ }
+ if (!$authorized) {
+ Kohana::show_404();
+ }
+ }
+
+ $proxy = ORM::factory("addthis_proxy", array("uuid" => $id));
+ if (!$proxy->loaded || !$proxy->item->loaded) {
+ Kohana::show_404();
+ }
+
+ $file = $type == "full" ? $proxy->item->file_path() : $proxy->item->thumb_path();
+ if (!file_exists($file)) {
+ kohana::show_404();
+ }
+
+ // We don't need to save the session for this request
+ Session::abort_save();
+
+ if (!TEST_MODE) {
+ // Dump out the image
+ header("Content-Type: $proxy->item->mime_type");
+ Kohana::close_buffers(false);
+ $fd = fopen($file, "rb");
+ fpassthru($fd);
+ fclose($fd);
+
+ // If the request was for the image and not the thumb, then delete the proxy.
+ if ($type == "full") {
+ $proxy->delete();
+ }
+ }
+
+ $this->_clean_expired();
+ }
+
+ public function close_window() {
+ print "";
+ }
+
+ private function _clean_expired() {
+ Database::instance()->query(
+ "DELETE FROM {addthis_proxies} " .
+ "WHERE request_date <= (CURDATE() - INTERVAL 10 DAY) " .
+ "LIMIT 20");
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/addthis/controllers/admin_addthis.php b/3.0/modules/addthis/controllers/admin_addthis.php
new file mode 100644
index 00000000..9c537b00
--- /dev/null
+++ b/3.0/modules/addthis/controllers/admin_addthis.php
@@ -0,0 +1,26 @@
+content = new View("admin_addthis.html");
+ print $v;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/addthis/css/addthis_menu.css b/3.0/modules/addthis/css/addthis_menu.css
new file mode 100644
index 00000000..b1deae01
--- /dev/null
+++ b/3.0/modules/addthis/css/addthis_menu.css
@@ -0,0 +1,3 @@
+#g-view-menu #g-addthis-link {
+ background-image: url('../images/addthis_logo.png');
+}
diff --git a/3.0/modules/addthis/helpers/addthis_event.php b/3.0/modules/addthis/helpers/addthis_event.php
new file mode 100644
index 00000000..c0415564
--- /dev/null
+++ b/3.0/modules/addthis/helpers/addthis_event.php
@@ -0,0 +1,48 @@
+get("settings_menu")
+ ->append(Menu::factory("link")
+ ->id("addthis_menu")
+ ->label(t("AddThis"))
+ ->url(url::site("admin/addthis")));
+ }
+
+ static function photo_menu($menu, $theme) {
+ $item = $theme->item();
+ $menu->append(Menu::factory("link")
+ ->id("addthis")
+ ->label(t("Bookmark and Share: $item->title"))
+ ->url("")
+ ->css_id("g-addthis-link")
+ ->css_class("addthis_button"));
+ }
+
+ static function album_menu($menu, $theme) {
+ $item = $theme->item();
+ $menu->append(Menu::factory("link")
+ ->id("addthis")
+ ->label(t("Bookmark and Share: $item->title"))
+ ->url("")
+ ->css_id("g-addthis-link")
+ ->css_class("addthis_button"));
+ }
+}
diff --git a/3.0/modules/addthis/helpers/addthis_installer.php b/3.0/modules/addthis/helpers/addthis_installer.php
new file mode 100644
index 00000000..ac401eb6
--- /dev/null
+++ b/3.0/modules/addthis/helpers/addthis_installer.php
@@ -0,0 +1,45 @@
+query("CREATE TABLE {addthis_proxies} (
+ `id` int(9) NOT NULL AUTO_INCREMENT,
+ `uuid` char(32) NOT NULL,
+ `request_date` TIMESTAMP NOT NULL DEFAULT current_timestamp,
+ `item_id` int(9) NOT NULL,
+ PRIMARY KEY (`id`))
+ DEFAULT CHARSET=utf8;");
+
+ module::set_var("addthis", "username", "");
+ module::set_version("addthis", 1);
+ }
+
+ static function upgrade($version) {
+ if ($version == 1) {
+ module::set_version("addthis", $version = 1);
+ }
+ }
+
+ static function uninstall() {
+ Database::instance()->query("DROP TABLE IF EXISTS {addthis_proxies}");
+ module::delete("addthis");
+ }
+}
diff --git a/3.0/modules/addthis/helpers/addthis_theme.php b/3.0/modules/addthis/helpers/addthis_theme.php
new file mode 100644
index 00000000..7308954e
--- /dev/null
+++ b/3.0/modules/addthis/helpers/addthis_theme.php
@@ -0,0 +1,29 @@
+css("addthis_menu.css");
+ return "\n" .
+ "";
+ }
+}
diff --git a/3.0/modules/addthis/images/addthis_logo.png b/3.0/modules/addthis/images/addthis_logo.png
new file mode 100644
index 00000000..39372a0c
Binary files /dev/null and b/3.0/modules/addthis/images/addthis_logo.png differ
diff --git a/3.0/modules/addthis/models/addthis_proxy.php b/3.0/modules/addthis/models/addthis_proxy.php
new file mode 100644
index 00000000..dd7ff120
--- /dev/null
+++ b/3.0/modules/addthis/models/addthis_proxy.php
@@ -0,0 +1,22 @@
+
+
+ " alt="Add This logo" class="g-right"/>
+
= t("Add This Social bookmarking") ?>
+
+
+ = t("A collection of all the services and destinations available through AddThis. Some are for sharing and bookmarking, others are 'utilities' like printing and translation.
+AddThis uses services to provide an intelligent, optimized sharing menu that is designed to offer the right options at the right time and maximize distribution of your content - everywhere.") ?>
+
+
+
+ = t("You're ready to share your content!") ?>
+
+
+
+ = t("You don't need an account with Add This, but if you register with Add This and enter your addthis username in the Advanced Settings page you can get Analytics. Example data below.",
+ array("signup_url" => "http://www.addthis.com/register",
+ "advanced_settings_url" => html::mark_clean(url::site("admin/advanced_settings")))) ?>
+
+
+
+
diff --git a/3.0/modules/all_tags/controllers/all_tags.php b/3.0/modules/all_tags/controllers/all_tags.php
new file mode 100644
index 00000000..e0e1c344
--- /dev/null
+++ b/3.0/modules/all_tags/controllers/all_tags.php
@@ -0,0 +1,56 @@
+css("all_tags.css");
+ $template->page_title = t("Gallery :: All Tags");
+ $template->content = new View("all_tags.html");
+
+ $filter = Input::instance()->get("filter");
+ $template->content->filter = $filter;
+ $query = ORM::factory("tag");
+ if ($filter) {
+ $query->like("name", $filter);
+ }
+ $template->content->tags = $query->order_by("name", "ASC")->find_all();
+
+ print $template;
+ }
+}
+
+/*
+ public function index() {
+ $filter = Input::instance()->get("filter");
+
+ $view = new Admin_View("admin.html");
+ $view->page_title = t("Manage tags");
+ $view->content = new View("admin_tags.html");
+ $view->content->filter = $filter;
+
+ $query = ORM::factory("tag");
+ if ($filter) {
+ $query->like("name", $filter);
+ }
+ $view->content->tags = $query->order_by("name", "ASC")->find_all();
+ print $view;
+ }
+ */
diff --git a/3.0/modules/all_tags/css/all_tags.css b/3.0/modules/all_tags/css/all_tags.css
new file mode 100644
index 00000000..3dc93836
--- /dev/null
+++ b/3.0/modules/all_tags/css/all_tags.css
@@ -0,0 +1,2 @@
+table.all_tags { text-align: center; width:500px; }
+table.all_tags caption { font-size: 1.5em; padding: 0.2em; }
\ No newline at end of file
diff --git a/3.0/modules/all_tags/helpers/all_tags_event.php b/3.0/modules/all_tags/helpers/all_tags_event.php
new file mode 100644
index 00000000..3007f434
--- /dev/null
+++ b/3.0/modules/all_tags/helpers/all_tags_event.php
@@ -0,0 +1,29 @@
+add_after("home", Menu::factory("link")
+ ->id("all_tags")
+ ->label(t("All Tags"))
+ ->url(url::site("all_tags/")));
+ }
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/all_tags/helpers/all_tags_theme.php b/3.0/modules/all_tags/helpers/all_tags_theme.php
new file mode 100644
index 00000000..89b91e70
--- /dev/null
+++ b/3.0/modules/all_tags/helpers/all_tags_theme.php
@@ -0,0 +1,24 @@
+css("all_tags.css");
+ }
+}
diff --git a/3.0/modules/all_tags/module.info b/3.0/modules/all_tags/module.info
new file mode 100644
index 00000000..10862900
--- /dev/null
+++ b/3.0/modules/all_tags/module.info
@@ -0,0 +1,7 @@
+name = "All Tags"
+description = "All Tags page and menu item."
+version = 2
+author_name = "Undagiga"
+author_url = "http://codex.gallery2.org/User:Undagiga"
+info_url = "http://codex.gallery2.org/Gallery3:Modules:all_tags"
+discuss_url = "http://gallery.menalto.com/forum_module_all_tags"
\ No newline at end of file
diff --git a/3.0/modules/all_tags/views/all_tags.html.php b/3.0/modules/all_tags/views/all_tags.html.php
new file mode 100644
index 00000000..381ee6b6
--- /dev/null
+++ b/3.0/modules/all_tags/views/all_tags.html.php
@@ -0,0 +1,44 @@
+
+
+ $tags_per_column = $tags->count()/5 ?>
+ $column_tag_count = 0 ?>
+
+
+
= t("All Tags in the Gallery") ?>
+
+
+
+
+ = t2("There is one tag", "There are %count tags", $tags->count()) ?>
+
+
+
+ foreach ($tags as $i => $tag): ?>
+ $current_letter = strtoupper(mb_substr($tag->name, 0, 1)) ?>
+
+ if ($i == 0): /* first letter */ ?>
+ = html::clean($current_letter) ?>
+
+ elseif ($last_letter != $current_letter): /* new letter */ ?>
+
+ if ($column_tag_count > $tags_per_column): /* new column */ ?>
+ $column_tag_count = 0 ?>
+
diff --git a/3.0/modules/carousel/controllers/admin_carousel.php b/3.0/modules/carousel/controllers/admin_carousel.php
new file mode 100644
index 00000000..0852ec3f
--- /dev/null
+++ b/3.0/modules/carousel/controllers/admin_carousel.php
@@ -0,0 +1,183 @@
+_get_view();
+ }
+
+ public function handler() {
+ access::verify_csrf();
+
+ $form = $this->_get_form();
+ if ($form->validate()) {
+ module::set_var(
+ "carousel", "circular", $form->carousel->circular->value);
+ module::set_var(
+ "carousel", "autoscroll", $form->carousel->autoscroll->value);
+ module::set_var(
+ "carousel", "autostart", $form->carousel->autostart->value);
+ module::set_var(
+ "carousel", "speed", $form->carousel->speed->value);
+ module::set_var(
+ "carousel", "mousewheel", $form->carousel->mousewheel->value);
+
+ module::set_var(
+ "carousel", "title2", $form->recent->title2->value);
+ module::set_var(
+ "carousel", "thumbsize2", $form->recent->thumbsize2->value);
+ module::set_var(
+ "carousel", "visible2", $form->recent->visible2->value);
+ module::set_var(
+ "carousel", "quantity2", $form->recent->quantity2->value);
+ module::set_var(
+ "carousel", "onphoto2", $form->recent->onphoto2->value);
+ module::set_var(
+ "carousel", "onalbum2", $form->recent->onalbum2->value);
+
+ module::set_var(
+ "carousel", "title3", $form->popular->title3->value);
+ module::set_var(
+ "carousel", "thumbsize3", $form->popular->thumbsize3->value);
+ module::set_var(
+ "carousel", "visible3", $form->popular->visible3->value);
+ module::set_var(
+ "carousel", "quantity3", $form->popular->quantity3->value);
+ module::set_var(
+ "carousel", "onphoto3", $form->popular->onphoto3->value);
+ module::set_var(
+ "carousel", "onalbum3", $form->popular->onalbum3->value);
+
+ module::set_var(
+ "carousel", "title", $form->random->title->value);
+ module::set_var(
+ "carousel", "thumbsize", $form->random->thumbsize->value);
+ module::set_var(
+ "carousel", "visible", $form->random->visible->value);
+ module::set_var(
+ "carousel", "quantity", $form->random->quantity->value);
+ module::set_var(
+ "carousel", "onphoto", $form->random->onphoto->value);
+ module::set_var(
+ "carousel", "onalbum", $form->random->onalbum->value);
+
+ message::success(t("Your settings have been saved."));
+ url::redirect("admin/carousel");
+ }
+ print $this->_get_view($form);
+ }
+
+ private function _get_view($form=null) {
+ $v = new Admin_View("admin.html");
+ $v->content = new View("admin_carousel.html");
+ $v->content->form = empty($form) ? $this->_get_form() : $form;
+ return $v;
+ }
+
+ private function _get_form() {
+ for ($i = 5; $i <= 50; $i+=5) {
+ $range[$i] = "$i";
+ }
+ $shortrange = array();
+ for ($i = 1; $i < 21; $i++) {
+ $key=((float)$i / 2);
+ $shortrange["$key"] = sprintf("%.1f", (float)$i / 2);
+ }
+ if (module::get_var("carousel", "autoscroll") == true) {
+ $disableme == "false";
+ } else {
+ $disableme == "true";
+ }
+ $form = new Forge("admin/carousel/handler", "", "post", array("id" => "g-admin-form"));
+
+ $group = $form->group("carousel")->label(t("General carousel settings"));
+ $group->checkbox("circular")->label(t('Enable the carousel to be circular so it starts over again from the beggining.'))
+ ->checked(module::get_var("carousel", "circular", "0"));
+ $group->checkbox("autoscroll")->label(t('Carousel should auto scroll. Toggle value to change settings below.'))
+ ->onClick("toggle()")
+ ->id("autoscroll")
+ ->checked(module::get_var("carousel", "autoscroll", "0"));
+ $group->input("autostart")->label(t("Enter the value of the auto start. (800)"))
+ ->value(module::get_var("carousel", "autostart", "800"))
+ ->id("auto")
+ ->disabled("false")
+ ->rules("valid_numeric|length[1,5]");
+ $group->input("speed")->label(t('Enter the scrolling speed of the carousel. (1000)'))
+ ->value(module::get_var("carousel", "speed", "1000"))
+ ->id("speed")
+ ->disabled($disableme)
+ ->rules("valid_numeric|length[1,5]");
+ $group->checkbox("mousewheel")->label(t('Enable mouse wheel. Allows for mouse wheel to scroll items.'))
+ ->checked(module::get_var("carousel", "mousewheel", "0"));
+
+ $group = $form->group("recent")->label(t("Recent carousel block"));
+ $group->input("title2")->label(t('Enter the title of the recent block.'))
+ ->value(module::get_var("carousel", "title2", "Recent items"));
+ $group->input("thumbsize2")->label(t('Enter the size of the thumbs. (pixels)'))
+ ->value(module::get_var("carousel", "thumbsize2", "200"))
+ ->rules("valid_numeric|length[2,3]");
+ $group->dropdown("visible2")->label(t('Enter number of thumbs to show. (height of carousel)'))
+ ->options($shortrange)
+ ->selected(module::get_var("carousel", "visible2", "1"));
+ $group->dropdown("quantity2")->label(t("Choose the toal quantity of thumbs in recent carousel."))
+ ->options($range)
+ ->selected(module::get_var("carousel", "quantity2", "25"));
+ $group->checkbox("onalbum2")->label(t("Show on album & collection pages"))
+ ->checked(module::get_var("carousel", "onalbum2", "0"));
+ $group->checkbox("onphoto2")->label(t("Show on photo pages"))
+ ->checked(module::get_var("carousel", "onphoto2", "0"));
+
+ $group = $form->group("popular")->label(t("Popular carousel block"));
+ $group->input("title3")->label(t('Enter the title of the popular block.'))
+ ->value(module::get_var("carousel", "title3", "Popular items"));
+ $group->input("thumbsize3")->label(t('Enter the thumb size. (pixels)'))
+ ->value(module::get_var("carousel", "thumbsize3", "200"))
+ ->rules("valid_numeric|length[2,3]");
+ $group->dropdown("visible3")->label(t('Enter number of thumbs to show. (height of carousel)'))
+ ->options($shortrange)
+ ->selected(module::get_var("carousel", "visible3", "1"));
+ $group->dropdown("quantity3")->label(t("Choose the toal quantity of thumbs in popular carousel."))
+ ->options($range)
+ ->selected(module::get_var("carousel", "quantity3", "25"));
+ $group->checkbox("onalbum3")->label(t("Show on album & collection pages"))
+ ->checked(module::get_var("carousel", "onalbum3", "0"));
+ $group->checkbox("onphoto3")->label(t("Show on photo pages"))
+ ->checked(module::get_var("carousel", "onphoto3", "0"));
+
+ $group = $form->group("random")->label(t("Random carousel block. Some issues with smaller galleries."));
+ $group->input("title")->label(t('Enter the title of the random block.'))
+ ->value(module::get_var("carousel", "title", "Random items"));
+ $group->input("thumbsize")->label(t('Enter the thumb size. (pixels)'))
+ ->value(module::get_var("carousel", "thumbsize", "200"))
+ ->rules("valid_numeric|length[2,3]");
+ $group->dropdown("visible")->label(t('Enter number of thumbs to show. (height of carousel)'))
+ ->options($shortrange)
+ ->selected(module::get_var("carousel", "visible", "1"));
+ $group->dropdown("quantity")->label(t("Choose the toal quantity of thumbs in random carousel."))
+ ->options($range)
+ ->selected(module::get_var("carousel", "quantity", "25"));
+ $group->checkbox("onalbum")->label(t("Show on album & collection pages"))
+ ->checked(module::get_var("carousel", "onalbum", "0"));
+ $group->checkbox("onphoto")->label(t("Show on photo pages"))
+ ->checked(module::get_var("carousel", "onphoto", "0"));
+
+ $form->submit("submit")->value(t("Save"));
+ return $form;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/carousel/css/carousel.css b/3.0/modules/carousel/css/carousel.css
new file mode 100644
index 00000000..28b9defb
--- /dev/null
+++ b/3.0/modules/carousel/css/carousel.css
@@ -0,0 +1,30 @@
+.jcarousel-container {
+ -moz-border-radius: 10px;
+ background: #F0F6F9;
+ border: 1px solid #346F97;
+}
+
+.jcarousel-container-vertical {
+ width: 75px;
+ height: 245px;
+ padding: 40px 20px;
+}
+
+.jcarousel-clip-vertical {
+ width: 75px;
+ height: 245px;
+}
+
+.jcarousel-item {
+ width: 75px;
+ height: 75px;
+}
+
+.jcarousel-item-vertical {
+ margin-bottom: 10px;
+}
+
+.jcarousel-item-placeholder {
+ background: #fff;
+ color: #000;
+}
\ No newline at end of file
diff --git a/3.0/modules/carousel/helpers/carousel_block.php b/3.0/modules/carousel/helpers/carousel_block.php
new file mode 100644
index 00000000..6141fcae
--- /dev/null
+++ b/3.0/modules/carousel/helpers/carousel_block.php
@@ -0,0 +1,61 @@
+ t("Recent items carousel"),
+ "carousel_popular" => t("Popular items carousel"),
+ "carousel_random" => t("Random items carousel"));
+ }
+
+ static function get($block_id, $theme) {
+ $block = "";
+ switch ($block_id) {
+ case "carousel_recent":
+ if (module::get_var("carousel", "onalbum2") && $theme->page_type == "collection" ||
+ module::get_var("carousel", "onphoto2") && $theme->page_type == "item") {
+ $block = new Block();
+ $block->css_id = "g-carousel-rec";
+ $block->title = module::get_var("carousel", "title2", "Recent items");
+ $block->content = new View("carousel_recent.html");
+ }
+ break;
+ case "carousel_popular":
+ if (module::get_var("carousel", "onalbum3") && $theme->page_type == "collection" ||
+ module::get_var("carousel", "onphoto3") && $theme->page_type == "item") {
+ $block = new Block();
+ $block->css_id = "g-carousel-pop";
+ $block->title = module::get_var("carousel", "title3", "Popular items");
+ $block->content = new View("carousel_popular.html");
+ }
+ break;
+ case "carousel_random":
+ if (module::get_var("carousel", "onalbum") && $theme->page_type == "collection" ||
+ module::get_var("carousel", "onphoto") && $theme->page_type == "item") {
+ $block = new Block();
+ $block->css_id = "g-carousel-ran";
+ $block->title = module::get_var("carousel", "title", "Random items");
+ $block->content = new View("carousel_random.html");
+ }
+ break;
+ }
+ return $block;
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/carousel/helpers/carousel_event.php b/3.0/modules/carousel/helpers/carousel_event.php
new file mode 100644
index 00000000..ffe2ac69
--- /dev/null
+++ b/3.0/modules/carousel/helpers/carousel_event.php
@@ -0,0 +1,28 @@
+get("settings_menu")
+ ->append(Menu::factory("link")
+ ->id("carousel_menu")
+ ->label(t("Carousel"))
+ ->url(url::site("admin/carousel")));
+ }
+}
diff --git a/3.0/modules/carousel/helpers/carousel_theme.php b/3.0/modules/carousel/helpers/carousel_theme.php
new file mode 100644
index 00000000..fe1f9abe
--- /dev/null
+++ b/3.0/modules/carousel/helpers/carousel_theme.php
@@ -0,0 +1,24 @@
+script("jcarousellite.min.js");
+ }
+}
\ No newline at end of file
diff --git a/3.0/modules/carousel/js/jcarousellite.min.js b/3.0/modules/carousel/js/jcarousellite.min.js
new file mode 100644
index 00000000..f16734ae
--- /dev/null
+++ b/3.0/modules/carousel/js/jcarousellite.min.js
@@ -0,0 +1 @@
+(function($){$.fn.jCarouselLite=function(o){o=$.extend({btnPrev:null,btnNext:null,btnGo:null,mouseWheel:false,auto:null,speed:200,easing:null,vertical:false,circular:true,visible:3,start:0,scroll:1,beforeStart:null,afterEnd:null},o||{});return this.each(function(){var b=false,animCss=o.vertical?"top":"left",sizeCss=o.vertical?"height":"width";var c=$(this),ul=$("ul",c),tLi=$("li",ul),tl=tLi.size(),v=o.visible;if(o.circular){ul.prepend(tLi.slice(tl-v-1+1).clone()).append(tLi.slice(0,v).clone());o.start+=v}var f=$("li",ul),itemLength=f.size(),curr=o.start;c.css("visibility","visible");f.css({overflow:"hidden",float:o.vertical?"none":"left"});ul.css({margin:"0",padding:"0",position:"relative","list-style-type":"none","z-index":"1"});c.css({overflow:"hidden",position:"relative","z-index":"2",left:"0px"});var g=o.vertical?height(f):width(f);var h=g*itemLength;var j=g*v;f.css({width:f.width(),height:f.height()});ul.css(sizeCss,h+"px").css(animCss,-(curr*g));c.css(sizeCss,j+"px");if(o.btnPrev)$(o.btnPrev).click(function(){return go(curr-o.scroll)});if(o.btnNext)$(o.btnNext).click(function(){return go(curr+o.scroll)});if(o.btnGo)$.each(o.btnGo,function(i,a){$(a).click(function(){return go(o.circular?o.visible+i:i)})});if(o.mouseWheel&&c.mousewheel)c.mousewheel(function(e,d){return d>0?go(curr-o.scroll):go(curr+o.scroll)});if(o.auto)setInterval(function(){go(curr+o.scroll)},o.auto+o.speed);function vis(){return f.slice(curr).slice(0,v)};function go(a){if(!b){if(o.beforeStart)o.beforeStart.call(this,vis());if(o.circular){if(a<=o.start-v-1){ul.css(animCss,-((itemLength-(v*2))*g)+"px");curr=a==o.start-v-1?itemLength-(v*2)-1:itemLength-(v*2)-o.scroll}else if(a>=itemLength-v+1){ul.css(animCss,-((v)*g)+"px");curr=a==itemLength-v+1?v+1:v+o.scroll}else curr=a}else{if(a<0||a>itemLength-v)return;else curr=a}b=true;ul.animate(animCss=="left"?{left:-(curr*g)}:{top:-(curr*g)},o.speed,o.easing,function(){if(o.afterEnd)o.afterEnd.call(this,vis());b=false});if(!o.circular){$(o.btnPrev+","+o.btnNext).removeClass("disabled");$((curr-o.scroll<0&&o.btnPrev)||(curr+o.scroll>itemLength-v&&o.btnNext)||[]).addClass("disabled")}}return false}})};function css(a,b){return parseInt($.css(a[0],b))||0};function width(a){return a[0].offsetWidth+css(a,'marginLeft')+css(a,'marginRight')};function height(a){return a[0].offsetHeight+css(a,'marginTop')+css(a,'marginBottom')}})(jQuery);
\ No newline at end of file
diff --git a/3.0/modules/carousel/js/jcarousellite_orig.js b/3.0/modules/carousel/js/jcarousellite_orig.js
new file mode 100644
index 00000000..f68b5ed0
--- /dev/null
+++ b/3.0/modules/carousel/js/jcarousellite_orig.js
@@ -0,0 +1,364 @@
+/**
+ * jCarouselLite - jQuery plugin to navigate images/any content in a carousel style widget.
+ * @requires jQuery v1.2 or above
+ *
+ * http://gmarwaha.com/jquery/jcarousellite/
+ *
+ * Copyright (c) 2007 Ganeshji Marwaha (gmarwaha.com)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Version: 1.0.1
+ * Note: Requires jquery 1.2 or above from version 1.0.1
+ */
+
+/**
+ * Creates a carousel-style navigation widget for images/any-content from a simple HTML markup.
+ *
+ * The HTML markup that is used to build the carousel can be as simple as...
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * As you can see, this snippet is nothing but a simple div containing an unordered list of images.
+ * You don't need any special "class" attribute, or a special "css" file for this plugin.
+ * I am using a class attribute just for the sake of explanation here.
+ *
+ * To navigate the elements of the carousel, you need some kind of navigation buttons.
+ * For example, you will need a "previous" button to go backward, and a "next" button to go forward.
+ * This need not be part of the carousel "div" itself. It can be any element in your page.
+ * Lets assume that the following elements in your document can be used as next, and prev buttons...
+ *
+ *
+ *
+ *
+ * Now, all you need to do is call the carousel component on the div element that represents it, and pass in the
+ * navigation buttons as options.
+ *
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev"
+ * });
+ *
+ * That's it, you would have now converted your raw div, into a magnificient carousel.
+ *
+ * There are quite a few other options that you can use to customize it though.
+ * Each will be explained with an example below.
+ *
+ * @param an options object - You can specify all the options shown below as an options object param.
+ *
+ * @option btnPrev, btnNext : string - no defaults
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev"
+ * });
+ * @desc Creates a basic carousel. Clicking "btnPrev" navigates backwards and "btnNext" navigates forward.
+ *
+ * @option btnGo - array - no defaults
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * btnGo: [".0", ".1", ".2"]
+ * });
+ * @desc If you don't want next and previous buttons for navigation, instead you prefer custom navigation based on
+ * the item number within the carousel, you can use this option. Just supply an array of selectors for each element
+ * in the carousel. The index of the array represents the index of the element. What i mean is, if the
+ * first element in the array is ".0", it means that when the element represented by ".0" is clicked, the carousel
+ * will slide to the first element and so on and so forth. This feature is very powerful. For example, i made a tabbed
+ * interface out of it by making my navigation elements styled like tabs in css. As the carousel is capable of holding
+ * any content, not just images, you can have a very simple tabbed navigation in minutes without using any other plugin.
+ * The best part is that, the tab will "slide" based on the provided effect. :-)
+ *
+ * @option mouseWheel : boolean - default is false
+ * @example
+ * $(".carousel").jCarouselLite({
+ * mouseWheel: true
+ * });
+ * @desc The carousel can also be navigated using the mouse wheel interface of a scroll mouse instead of using buttons.
+ * To get this feature working, you have to do 2 things. First, you have to include the mouse-wheel plugin from brandon.
+ * Second, you will have to set the option "mouseWheel" to true. That's it, now you will be able to navigate your carousel
+ * using the mouse wheel. Using buttons and mouseWheel or not mutually exclusive. You can still have buttons for navigation
+ * as well. They complement each other. To use both together, just supply the options required for both as shown below.
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * mouseWheel: true
+ * });
+ *
+ * @option auto : number - default is null, meaning autoscroll is disabled by default
+ * @example
+ * $(".carousel").jCarouselLite({
+ * auto: 800,
+ * speed: 500
+ * });
+ * @desc You can make your carousel auto-navigate itself by specfying a millisecond value in this option.
+ * The value you specify is the amount of time between 2 slides. The default is null, and that disables auto scrolling.
+ * Specify this value and magically your carousel will start auto scrolling.
+ *
+ * @option speed : number - 200 is default
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * speed: 800
+ * });
+ * @desc Specifying a speed will slow-down or speed-up the sliding speed of your carousel. Try it out with
+ * different speeds like 800, 600, 1500 etc. Providing 0, will remove the slide effect.
+ *
+ * @option easing : string - no easing effects by default.
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * easing: "bounceout"
+ * });
+ * @desc You can specify any easing effect. Note: You need easing plugin for that. Once specified,
+ * the carousel will slide based on the provided easing effect.
+ *
+ * @option vertical : boolean - default is false
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * vertical: true
+ * });
+ * @desc Determines the direction of the carousel. true, means the carousel will display vertically. The next and
+ * prev buttons will slide the items vertically as well. The default is false, which means that the carousel will
+ * display horizontally. The next and prev items will slide the items from left-right in this case.
+ *
+ * @option circular : boolean - default is true
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * circular: false
+ * });
+ * @desc Setting it to true enables circular navigation. This means, if you click "next" after you reach the last
+ * element, you will automatically slide to the first element and vice versa. If you set circular to false, then
+ * if you click on the "next" button after you reach the last element, you will stay in the last element itself
+ * and similarly for "previous" button and first element.
+ *
+ * @option visible : number - default is 3
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * visible: 4
+ * });
+ * @desc This specifies the number of items visible at all times within the carousel. The default is 3.
+ * You are even free to experiment with real numbers. Eg: "3.5" will have 3 items fully visible and the
+ * last item half visible. This gives you the effect of showing the user that there are more images to the right.
+ *
+ * @option start : number - default is 0
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * start: 2
+ * });
+ * @desc You can specify from which item the carousel should start. Remember, the first item in the carousel
+ * has a start of 0, and so on.
+ *
+ * @option scrool : number - default is 1
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * scroll: 2
+ * });
+ * @desc The number of items that should scroll/slide when you click the next/prev navigation buttons. By
+ * default, only one item is scrolled, but you may set it to any number. Eg: setting it to "2" will scroll
+ * 2 items when you click the next or previous buttons.
+ *
+ * @option beforeStart, afterEnd : function - callbacks
+ * @example
+ * $(".carousel").jCarouselLite({
+ * btnNext: ".next",
+ * btnPrev: ".prev",
+ * beforeStart: function(a) {
+ * alert("Before animation starts:" + a);
+ * },
+ * afterEnd: function(a) {
+ * alert("After animation ends:" + a);
+ * }
+ * });
+ * @desc If you wanted to do some logic in your page before the slide starts and after the slide ends, you can
+ * register these 2 callbacks. The functions will be passed an argument that represents an array of elements that
+ * are visible at the time of callback.
+ *
+ *
+ * @cat Plugins/Image Gallery
+ * @author Ganeshji Marwaha/ganeshread@gmail.com
+ */
+
+(function($) { // Compliant with jquery.noConflict()
+$.fn.jCarouselLite = function(o) {
+ o = $.extend({
+ btnPrev: null,
+ btnNext: null,
+ btnGo: null,
+ mouseWheel: false,
+ auto: null,
+ hoverPause: false,
+
+ speed: 200,
+ easing: null,
+
+ vertical: false,
+ circular: true,
+ visible: 3,
+ start: 0,
+ scroll: 1,
+
+ beforeStart: null,
+ afterEnd: null
+ }, o || {});
+
+ return this.each(function() { // Returns the element collection. Chainable.
+
+ var running = false, animCss=o.vertical?"top":"left", sizeCss=o.vertical?"height":"width";
+ var div = $(this), ul = $("ul", div), tLi = $("li", ul), tl = tLi.size(), v = o.visible;
+
+ if(o.circular) {
+ ul.prepend(tLi.slice(tl-v+1).clone())
+ .append(tLi.slice(0,o.scroll).clone());
+ o.start += v-1;
+ }
+
+ var li = $("li", ul), itemLength = li.size(), curr = o.start;
+ div.css("visibility", "visible");
+
+ li.css({overflow: "hidden", float: o.vertical ? "none" : "left"});
+ ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
+ div.css({overflow: "hidden", position: "relative", "z-index": "2", left: "0px"});
+
+ var liSize = o.vertical ? height(li) : width(li); // Full li size(incl margin)-Used for animation
+ var ulSize = liSize * itemLength; // size of full ul(total length, not just for the visible items)
+ var divSize = liSize * v; // size of entire div(total length for just the visible items)
+
+ li.css({width: li.width(), height: li.height()});
+ ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
+
+ div.css(sizeCss, divSize+"px"); // Width of the DIV. length of visible images
+
+ if(o.btnPrev) {
+ $(o.btnPrev).click(function() {
+ return go(curr-o.scroll);
+ });
+ if(o.hoverPause) {
+ $(o.btnPrev).hover(function(){stopAuto();}, function(){startAuto();});
+ }
+ }
+
+
+ if(o.btnNext) {
+ $(o.btnNext).click(function() {
+ return go(curr+o.scroll);
+ });
+ if(o.hoverPause) {
+ $(o.btnNext).hover(function(){stopAuto();}, function(){startAuto();});
+ }
+ }
+
+ if(o.btnGo)
+ $.each(o.btnGo, function(i, val) {
+ $(val).click(function() {
+ return go(o.circular ? o.visible+i : i);
+ });
+ });
+
+ if(o.mouseWheel && div.mousewheel)
+ div.mousewheel(function(e, d) {
+ return d>0 ? go(curr-o.scroll) : go(curr+o.scroll);
+ });
+
+ var autoInterval;
+
+ function startAuto() {
+ stopAuto();
+ autoInterval = setInterval(function() {
+ go(curr+o.scroll);
+ }, o.auto+o.speed);
+ };
+
+ function stopAuto() {
+ clearInterval(autoInterval);
+ };
+
+ if(o.auto) {
+ if(o.hoverPause) {
+ div.hover(function(){stopAuto();}, function(){startAuto();});
+ }
+ startAuto();
+ };
+
+ function vis() {
+ return li.slice(curr).slice(0,v);
+ };
+
+ function go(to) {
+ if(!running) {
+
+ if(o.beforeStart)
+ o.beforeStart.call(this, vis());
+
+ if(o.circular) { // If circular we are in first or last, then goto the other end
+ if(to<0) { // If before range, then go around
+ ul.css(animCss, -( (curr + tl) * liSize)+"px");
+ curr = to + tl;
+ } else if(to>itemLength-v) { // If beyond range, then come around
+ ul.css(animCss, -( (curr - tl) * liSize ) + "px" );
+ curr = to - tl;
+ } else curr = to;
+ } else { // If non-circular and to points to first or last, we just return.
+ if(to<0 || to>itemLength-v) return;
+ else curr = to;
+ } // If neither overrides it, the curr will still be "to" and we can proceed.
+
+ running = true;
+
+ ul.animate(
+ animCss == "left" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing,
+ function() {
+ if(o.afterEnd)
+ o.afterEnd.call(this, vis());
+ running = false;
+ }
+ );
+ // Disable buttons when the carousel reaches the last/first, and enable when not
+ if(!o.circular) {
+ $(o.btnPrev + "," + o.btnNext).removeClass("disabled");
+ $( (curr-o.scroll<0 && o.btnPrev)
+ ||
+ (curr+o.scroll > itemLength-v && o.btnNext)
+ ||
+ []
+ ).addClass("disabled");
+ }
+
+ }
+ return false;
+ };
+ });
+};
+
+function css(el, prop) {
+ return parseInt($.css(el[0], prop)) || 0;
+};
+function width(el) {
+ return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
+};
+function height(el) {
+ return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/3.0/modules/carousel/js/jquery.mousewheel.min.js b/3.0/modules/carousel/js/jquery.mousewheel.min.js
new file mode 100644
index 00000000..05ebb0a9
--- /dev/null
+++ b/3.0/modules/carousel/js/jquery.mousewheel.min.js
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ *
+ * Requires: 1.2.2+
+ */
+(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
\ No newline at end of file
diff --git a/3.0/modules/carousel/module.info b/3.0/modules/carousel/module.info
new file mode 100644
index 00000000..0ee02423
--- /dev/null
+++ b/3.0/modules/carousel/module.info
@@ -0,0 +1,7 @@
+name = "Carousel"
+description = "Add a vertical carousel for recent & popular items in the sidebar."
+version = 1.0
+author_name = "floridave"
+author_url = "http://codex.gallery2.org/User:Floridave"
+info_url = "http://codex.gallery2.org/Gallery3:Modules:carousel"
+discuss_url = "http://gallery.menalto.com/forum_module_all_carousel"
\ No newline at end of file
diff --git a/3.0/modules/carousel/views/admin_carousel.html.php b/3.0/modules/carousel/views/admin_carousel.html.php
new file mode 100644
index 00000000..8c3197e2
--- /dev/null
+++ b/3.0/modules/carousel/views/admin_carousel.html.php
@@ -0,0 +1,23 @@
+
+
+
+
= t("Carousel Administration") ?>
+
= t("Change settings below for the different parameters.") ?>
+ = $form ?>
+
+
+
+
= t("Notes:") ?>
+
= t("Navigation buttons are hard to style and clutter the user interface.
+ Use mouse wheel to scroll thought the images.") ?>