diff --git a/last_commit.txt b/last_commit.txt
new file mode 100755
index 00000000..ee47b710
--- /dev/null
+++ b/last_commit.txt
@@ -0,0 +1 @@
+Removed preload
\ No newline at end of file
diff --git a/modules/basket/controllers/admin_postage_bands.php b/modules/basket/controllers/admin_postage_bands.php
new file mode 100644
index 00000000..f843d0ca
--- /dev/null
+++ b/modules/basket/controllers/admin_postage_bands.php
@@ -0,0 +1,154 @@
+content = new View("admin_postage_bands.html");
+ $view->content->postage_bands = ORM::factory("postage_band")->orderby("name")->find_all();
+
+ print $view;
+ }
+
+ public function add_postage_band_form() {
+ print postage_band::get_add_form_admin();
+ }
+
+
+ public function add_postage_band() {
+ access::verify_csrf();
+
+ $form = postage_band::get_add_form_admin();
+ $valid = $form->validate();
+ $name = $form->add_postage->inputs["name"]->value;
+ $postage = ORM::factory("postage_band")->where("name", $name)->find();
+ if ($postage->loaded) {
+ $form->add_postage->inputs["name"]->add_error("in_use", 1);
+ $valid = false;
+ }
+
+ if ($valid) {
+ $postage = postage_band::create(
+ $name,
+ $form->add_postage->flat_rate->value,
+ $form->add_postage->per_item->value
+ );
+
+ $postage->save();
+ message::success(t("Created postage band %postage_name", array(
+ "postage_name" => html::clean($postage->name))));
+ print json_encode(array("result" => "success"));
+ } else {
+ print json_encode(array("result" => "error",
+ "form" => $form->__toString()));
+ }
+ }
+
+ public function delete_postage_band_form($id) {
+ $postage = ORM::factory("postage_band", $id);
+ if (!$postage->loaded) {
+ kohana::show_404();
+ }
+ print postage_band::get_delete_form_admin($postage);
+ }
+
+ public function delete_postage_band($id) {
+ access::verify_csrf();
+
+ if ($id == user::active()->id || $id == user::guest()->id) {
+ access::forbidden();
+ }
+
+ $postage = ORM::factory("postage_band", $id);
+ if (!$postage->loaded) {
+ kohana::show_404();
+ }
+
+ $form = postage_band::get_delete_form_admin($postage);
+ if($form->validate()) {
+ $name = $postage->name;
+ $postage->delete();
+ } else {
+ print json_encode(array("result" => "error",
+ "form" => $form->__toString()));
+ }
+
+ $message = t("Deleted user %postage_band", array("postage_band" => html::clean($name)));
+ log::success("user", $message);
+ message::success($message);
+ print json_encode(array("result" => "success"));
+ }
+
+ public function edit_postage_band($id) {
+ access::verify_csrf();
+
+ $postage = ORM::factory("postage_band", $id);
+ if (!$postage->loaded) {
+ kohana::show_404();
+ }
+
+ $form = postage_band::get_edit_form_admin($postage);
+ $valid = $form->validate();
+ if ($valid) {
+ $new_name = $form->edit_postage->inputs["name"]->value;
+ if ($new_name != $postage->name &&
+ ORM::factory("postage_band")
+ ->where("name", $new_name)
+ ->where("id !=", $postage->id)
+ ->find()
+ ->loaded) {
+ $form->edit_postage->inputs["name"]->add_error("in_use", 1);
+ $valid = false;
+ } else {
+ $postage->name = $new_name;
+ }
+ }
+
+ if ($valid) {
+ $postage->flat_rate = $form->edit_postage->flat_rate->value;
+ $postage->per_item = $form->edit_postage->per_item->value;
+ $postage->save();
+
+ message::success(t("Changed postage band %postage_name",
+ array("postage_name" => html::clean($postage->name))));
+ print json_encode(array("result" => "success"));
+ } else {
+ print json_encode(array("result" => "error",
+ "form" => $form->__toString()));
+ }
+ }
+
+ public function edit_postage_band_form($id) {
+ $postage = ORM::factory("postage_band", $id);
+ if (!$postage->loaded) {
+ kohana::show_404();
+ }
+
+ $form = postage_band::get_edit_form_admin($postage);
+
+ print $form;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/basket/controllers/admin_product_lines.php b/modules/basket/controllers/admin_product_lines.php
index 1794bc28..f063ad36 100644
--- a/modules/basket/controllers/admin_product_lines.php
+++ b/modules/basket/controllers/admin_product_lines.php
@@ -51,7 +51,11 @@ class Admin_Product_Lines_Controller extends Controller
if ($valid) {
$product = product::create(
- $name, $form->add_product->cost->value, $form->add_product->description->value);
+ $name,
+ $form->add_product->cost->value,
+ $form->add_product->description->value,
+ $form->add_product->postage_band->value
+ );
$product->save();
message::success(t("Created product %product_name", array(
@@ -83,7 +87,7 @@ class Admin_Product_Lines_Controller extends Controller
kohana::show_404();
}
- $form = user::get_delete_form_admin($product);
+ $form = product::get_delete_form_admin($product);
if($form->validate()) {
$name = $product->name;
$product->delete();
@@ -126,6 +130,7 @@ class Admin_Product_Lines_Controller extends Controller
if ($valid) {
$product->cost = $form->edit_product->cost->value;
$product->description = $form->edit_product->description->value;
+ $product->postage_band_id = $form->edit_product->postage_band->value;
$product->save();
message::success(t("Changed product %product_name",
diff --git a/modules/basket/controllers/basket.php b/modules/basket/controllers/basket.php
index 2ae4e62e..9bdbe20b 100644
--- a/modules/basket/controllers/basket.php
+++ b/modules/basket/controllers/basket.php
@@ -31,7 +31,7 @@ class Basket_Controller extends Controller {
print $template;
}
- private function getCheckoutForm(){
+ private function getCheckoutForm(){
$form = new Forge("basket/confirm", "", "post", array("id" => "checkout", "name" =>"checkout"));
$group = $form->group("contact")->label(t("Contact Details"));
$group->input("fullname")->label(t("Name"))->id("fullname");
@@ -110,6 +110,8 @@ class Basket_Controller extends Controller {
$basket = Session_Basket::get();
//$admin_address = basket::getEmailAddress();
+ $postage = $basket->postage_cost();
+ $product_cost = $basket->cost();
$admin_email = "Order for :
".$basket->name."
@@ -121,7 +123,9 @@ class Basket_Controller extends Controller {
".$basket->email."
".$basket->phone."
Placed at ".date("d F Y - H:i" ,time())."
-Total Owed ".$basket->cost()." in ".basket::getCurrency()."
+Cost of Ordered Products = ".$product_cost."
+Postage and Packaging Costs + ".$postage."
+Total Owed ".($product_cost+$postage)." Total in ".basket::getCurrency()."
Items Ordered:
diff --git a/modules/basket/helpers/basket.php b/modules/basket/helpers/basket.php
index d4993786..7bcc0060 100644
--- a/modules/basket/helpers/basket.php
+++ b/modules/basket/helpers/basket.php
@@ -42,9 +42,9 @@ class basket_Core {
static $format= array(
"AUD" => "$",
"CAD" => "$",
- "EUR" => "�",
- "GBP" => "�",
- "JPY" => "�",
+ "EUR" => "€",
+ "GBP" => "£",
+ "JPY" => "¥",
"USD" => "$",
"NZD" => "$",
"CHF" => "",
@@ -114,7 +114,7 @@ class basket_Core {
}
static function formatMoney($money){
- return self::$format[self::getCurrency()].number_format($money);
+ return self::$format[self::getCurrency()].number_format($money,2);
}
static function setEmailAddress($email){
@@ -141,6 +141,12 @@ class basket_Core {
";
+ $postage = $session_basket->postage_cost();
+ if ($postage > 0) {
+ $form = $form."
+ ";
+ }
+
$id = 1;
foreach ($session_basket->contents as $key => $basket_item){
$form = $form."
@@ -149,6 +155,7 @@ class basket_Core {
quantity\"/>";
$id++;
}
+
$form = $form."";
return $form;
diff --git a/modules/basket/helpers/basket_event.php b/modules/basket/helpers/basket_event.php
index 25b55f28..ade43e96 100644
--- a/modules/basket/helpers/basket_event.php
+++ b/modules/basket/helpers/basket_event.php
@@ -38,6 +38,11 @@ class basket_event_Core{
->id("product_line")
->label(t("Product Lines"))
->url(url::site("admin/product_lines")));
+ $basket_menu->append(
+ Menu::factory("link")
+ ->id("postage_bands")
+ ->label(t("Postage Bands"))
+ ->url(url::site("admin/postage_bands")));
}
diff --git a/modules/basket/helpers/basket_installer.php b/modules/basket/helpers/basket_installer.php
index 23c4e8f9..48c58d4b 100644
--- a/modules/basket/helpers/basket_installer.php
+++ b/modules/basket/helpers/basket_installer.php
@@ -17,14 +17,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-class basket_installer {
- static function install() {
+
+class basket_installer
+{
+ static function install(){
+
$db = Database::instance();
$db->query("CREATE TABLE IF NOT EXISTS {products} (
`id` int(9) NOT NULL auto_increment,
`name` TEXT NOT NULL,
- `cost` INTEGER(9) default 0,
+ `cost` DECIMAL(10,2) default 0,
`description` varchar(1024),
+ `postage_band_id` int(9) default 1,
PRIMARY KEY (`id`))
DEFAULT CHARSET=utf8;");
@@ -40,21 +44,57 @@ class basket_installer {
`product_override_id` int(9) NOT NULL,
`product_id` int(9) NOT NULL,
`include` BOOLEAN default false,
- `cost` INTEGER(9) default -1,
+ `cost` DECIMAL(10,2) default -1,
+ PRIMARY KEY (`id`))
+ ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+
+ $db->query("CREATE TABLE IF NOT EXISTS {postage_bands} (
+ `id` int(9) NOT NULL auto_increment,
+ `name` TEXT NOT NULL,
+ `flat_rate` DECIMAL(10,2) default 0,
+ `per_item` DECIMAL(10,2) default 0,
PRIMARY KEY (`id`))
DEFAULT CHARSET=utf8;");
- product::create("4x6",5,"4\"x6\" print");
- product::create("8x10",25,"8\"x10\" print");
- product::create("8x12",30,"8\"x12\" print");
+ postage_band::create("No Postage",0,0);
+
+ product::create("4x6",5,"4\"x6\" print",1);
+ product::create("8x10",25,"8\"x10\" print",1);
+ product::create("8x12",30,"8\"x12\" print",1);
+
+
+ module::set_version("basket", 2);
- module::set_version("basket", 1);
}
- static function uninstall() {
+ static function upgrade($version) {
+ $db = Database::instance();
+ if ($version == 1) {
+
+ // fix for allowing decimel place in money
+ $db->query("ALTER TABLE {products} CHANGE COLUMN `cost` `cost` DECIMAL(10,2) default 0;");
+ $db->query("ALTER TABLE {item_products} CHANGE COLUMN `cost` `cost` DECIMAL(10,2) default -1;");
+
+ // postage bands
+ $db->query("ALTER TABLE {products} ADD COLUMN `postage_band_id` int(9) default 1");
+ $db->query("CREATE TABLE IF NOT EXISTS {postage_bands} (
+ `id` int(9) NOT NULL auto_increment,
+ `name` TEXT NOT NULL,
+ `flat_rate` DECIMAL(10,2) default 0,
+ `per_item` DECIMAL(10,2) default 0,
+ PRIMARY KEY (`id`))
+ ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ postage_band::create("No Postage",0,0);
+
+ module::set_version("basket", $version = 2);
+ }
+ }
+
+ static function uninstall(){
$db = Database::instance();
$db->query("DROP TABLE IF EXISTS {products}");
$db->query("DROP TABLE IF EXISTS {product_overrides}");
$db->query("DROP TABLE IF EXISTS {item_products}");
+ $db->query("DROP TABLE IF EXISTS {postage_bands}");
}
}
diff --git a/modules/basket/helpers/postage_band.php b/modules/basket/helpers/postage_band.php
new file mode 100644
index 00000000..b69f84c4
--- /dev/null
+++ b/modules/basket/helpers/postage_band.php
@@ -0,0 +1,99 @@
+ "gAddPostageForm"));
+ $group = $form->group("add_postage")->label(t("Add Postage Band"));
+ $group->input("name")->label(t("Name"))->id("gPostageName")
+ ->error_messages("in_use", t("There is already a postage band with that name"));
+ $group->input("flat_rate")->label(t("Flat Rate"))->id("gFlatRate");
+ $group->input("per_item")->label(t("Per Item"))->id("gPetItem");
+ $group->submit("")->value(t("Add Postage Band"));
+ $postage = ORM::factory("postage_band");
+ $form->add_rules_from($postage);
+ return $form;
+ }
+
+ static function get_edit_form_admin($postage) {
+ $form = new Forge("admin/postage_bands/edit_postage_band/$postage->id", "", "post",
+ array("id" => "gEditPostageForm"));
+ $group = $form->group("edit_postage")->label(t("Edit Postage Band"));
+ $group->input("name")->label(t("Name"))->id("gPostageName")->value($postage->name);
+ $group->inputs["name"]->error_messages(
+ "in_use", t("There is already a postage band with that name"));
+ $group->input("flat_rate")->label(t("Flat Rate"))->id("gFlatRate")->value($postage->flat_rate);
+ $group->input("per_item")->label(t("Per Item"))->id("gPetItem")->
+ value($postage->per_item);
+
+ $group->submit("")->value(t("Modify Postage Band"));
+ $form->add_rules_from($postage);
+ return $form;
+ }
+
+
+ static function get_delete_form_admin($postage) {
+ $form = new Forge("admin/postage_bands/delete_postage_band/$postage->id", "", "post",
+ array("id" => "gDeletePostageForm"));
+ $group = $form->group("delete_postage")->label(
+ t("Are you sure you want to delete postage band %name?", array("name" => $postage->name)));
+ $group->submit("")->value(t("Delete postage band %name", array("name" => $postage->name)));
+ return $form;
+ }
+
+ /**
+ * Create a new postage band
+ *
+ * @param string $name
+ * @param string $full_name
+ * @param string $password
+ * @return User_Model
+ */
+ static function create($name, $flatrate, $peritemcost) {
+ $postage = ORM::factory("postage_band")->where("name", $name)->find();
+ if ($postage->loaded) {
+ throw new Exception("@todo postage already EXISTS $name");
+ }
+
+ $postage->name = $name;
+ $postage->flat_rate = $flatrate;
+ $postage->per_item = $peritemcost;
+
+ $postage->save();
+ return $postage;
+ }
+
+ /**
+ * returns the array of postage bands
+ * @return an array of postage bands
+ */
+ static function getPostageArray(){
+ $postagea = array();
+
+ $postages = ORM::factory("postage_band")->find_all();
+ foreach ($postages as $postage){
+ $show = true;
+ $postagea[$postage->id] = $postage->name;
+ }
+
+ return $postagea;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/basket/helpers/product.php b/modules/basket/helpers/product.php
index 34e9e745..8811d28e 100644
--- a/modules/basket/helpers/product.php
+++ b/modules/basket/helpers/product.php
@@ -24,8 +24,11 @@ class product_Core {
$group = $form->group("add_product")->label(t("Add Product"));
$group->input("name")->label(t("Name"))->id("g-product-name")
->error_messages("in_use", t("There is already a product with that name"));
- $group->input("cost")->label(t("Cost"))->id("g-cost");
+ $group->input("cost")->label(t("Cost"))->id("gCost");
$group->input("description")->label(t("Description"))->id("g-description");
+ $group->dropdown("postage_band")
+ ->label(t("Postage Band"))
+ ->options(postage_band::getPostageArray());
$group->submit("")->value(t("Add Product"));
$product = ORM::factory("product");
$form->add_rules_from($product);
@@ -42,6 +45,10 @@ class product_Core {
$group->input("cost")->label(t("Cost"))->id("g-cost")->value($product->cost);
$group->input("description")->label(t("Description"))->id("g-description")->
value($product->description);
+ $group->dropdown("postage_band")
+ ->label(t("Postage Band"))
+ ->options(postage_band::getPostageArray())
+ ->selected($product->postage_band_id);
$group->submit("")->value(t("Modify Product"));
$form->add_rules_from($product);
@@ -66,7 +73,7 @@ class product_Core {
* @param string $password
* @return User_Model
*/
- static function create($name, $cost, $description) {
+ static function create($name, $cost, $description, $postage_band) {
$product = ORM::factory("product")->where("name", $name)->find();
if ($product->loaded) {
throw new Exception("@todo USER_ALREADY_EXISTS $name");
@@ -75,7 +82,7 @@ class product_Core {
$product->name = $name;
$product->cost = $cost;
$product->description = $description;
-
+ $product->postage_band_id = $postage_band;
$product->save();
return $product;
}
diff --git a/modules/basket/libraries/Session_Basket.php b/modules/basket/libraries/Session_Basket.php
index 3aa31f12..11de4db0 100644
--- a/modules/basket/libraries/Session_Basket.php
+++ b/modules/basket/libraries/Session_Basket.php
@@ -64,6 +64,11 @@ class basket_item
return $prod->description;
}
+ public function getProduct(){
+ $prod = ORM::factory("product", $this->product);
+ return $prod;
+ }
+
public function getCode(){
$photo = ORM::factory("item", $this->item);
$prod = ORM::factory("product", $this->product);
@@ -122,6 +127,32 @@ class Session_Basket_Core {
unset($this->contents[$key]);
}
+ public function postage_cost(){
+ $postage_cost = 0;
+ $postage_bands = array();
+ $postage_quantities = array();
+ if (isset($this->contents)){
+ // create array of postage bands
+ foreach ($this->contents as $product => $basket_item){
+ $postage_band = $basket_item->getProduct()->postage_band;
+ if (isset($postage_bands[$postage_band->id]))
+ {
+ $postage_quantities[$postage_band->id] += $basket_item->quantity;
+ }
+ else
+ {
+ $postage_quantities[$postage_band->id] = $basket_item->quantity;
+ $postage_bands[$postage_band->id] = $postage_band;
+ }
+ }
+
+ foreach ($postage_bands as $id => $postage_band){
+ $postage_cost += $postage_band->flat_rate + ($postage_band->per_item * $postage_quantities[$id]);
+ }
+ }
+ return $postage_cost;
+ }
+
public function cost(){
$cost = 0;
if (isset($this->contents)){
diff --git a/modules/basket/models/postage_band.php b/modules/basket/models/postage_band.php
new file mode 100644
index 00000000..83eb6e08
--- /dev/null
+++ b/modules/basket/models/postage_band.php
@@ -0,0 +1,26 @@
+ "length[1,32]");
+
+ protected $has_many=array('products');
+
+}
diff --git a/modules/basket/models/product.php b/modules/basket/models/product.php
index c89c7254..2bd6a59b 100644
--- a/modules/basket/models/product.php
+++ b/modules/basket/models/product.php
@@ -21,4 +21,6 @@ class Product_Model extends ORM {
var $rules = array(
"name" => "length[1,32]",
"description" => "length[0,255]");
+ protected $belongs_to=array('postage_band');
+
}
diff --git a/modules/basket/module.info b/modules/basket/module.info
index 426ff687..5bf1f888 100644
--- a/modules/basket/module.info
+++ b/modules/basket/module.info
@@ -1,3 +1,3 @@
name = "Shopping Basket"
description = "Provides a simple shopping basket and checkout with paypal integration"
-version = 1
+version = 2
diff --git a/modules/basket/views/admin_postage_bands.html.php b/modules/basket/views/admin_postage_bands.html.php
new file mode 100644
index 00000000..436c2a83
--- /dev/null
+++ b/modules/basket/views/admin_postage_bands.html.php
@@ -0,0 +1,70 @@
+
+
\ No newline at end of file
diff --git a/modules/basket/views/admin_product_lines.html.php b/modules/basket/views/admin_product_lines.html.php
index b0ee1322..896f6edb 100644
--- a/modules/basket/views/admin_product_lines.html.php
+++ b/modules/basket/views/admin_product_lines.html.php
@@ -37,6 +37,7 @@
= t("Name") ?>
= t("Cost") ?>
= t("Description") ?>
+ = t("Postage Band") ?>
= t("Actions") ?>
@@ -51,6 +52,11 @@
= html::clean($product->description) ?>
+
+ = html::clean($product->postage_band->name) ?>
+
+
+
id") ?>"
open_text="= t("close") ?>"
diff --git a/modules/basket/views/confirm_order.html.php b/modules/basket/views/confirm_order.html.php
index da04a5f6..d6bbac00 100644
--- a/modules/basket/views/confirm_order.html.php
+++ b/modules/basket/views/confirm_order.html.php
@@ -51,8 +51,14 @@ function so(){document.confirm.submit();}
endforeach ?>
+ $postage = $basket->postage_cost();?>
+ if ($postage > 0):?>
">
- Total Cost = html::clean($basket->cost())?>
+ Postage and Packaging = html::clean(basket::formatMoney($postage))?>
+
+ endif;?>
+ ">
+ Total Cost = html::clean(basket::formatMoney($basket->cost() + $postage))?>
diff --git a/modules/basket/views/view_basket.html.php b/modules/basket/views/view_basket.html.php
index bb506e06..298172be 100644
--- a/modules/basket/views/view_basket.html.php
+++ b/modules/basket/views/view_basket.html.php
@@ -88,8 +88,14 @@
endforeach ?>
+ $postage = $basket->postage_cost();?>
+ if ($postage > 0):?>
">
- Total Cost = html::clean(basket::formatMoney($total))?>
+ Postage and Packaging = html::clean(basket::formatMoney($postage))?>
+
+ endif;?>
+ ">
+ Total Cost = html::clean(basket::formatMoney($total + $postage))?>
diff --git a/modules/batchtag/controllers/batchtag.php b/modules/batchtag/controllers/batchtag.php
index fc17f594..e4bbbf73 100644
--- a/modules/batchtag/controllers/batchtag.php
+++ b/modules/batchtag/controllers/batchtag.php
@@ -24,11 +24,23 @@ class BatchTag_Controller extends Controller {
// Prevent Cross Site Request Forgery
access::verify_csrf();
- // Generate an array of all non-album items in the current album.
- $children = ORM::factory("item")
- ->where("parent_id", $this->input->post("item_id"))
- ->where("type !=", "album")
- ->find_all();
+ // Figure out if the contents of sub-albums should also be tagged
+ $str_tag_subitems = Input::instance()->post("tag_subitems");
+
+ $children = "";
+ if ($str_tag_subitems == false) {
+ // Generate an array of all non-album items in the current album.
+ $children = ORM::factory("item")
+ ->where("parent_id", $this->input->post("item_id"))
+ ->where("type !=", "album")
+ ->find_all();
+ } else {
+ // Generate an array of all non-album items in the current album
+ // and any sub albums.
+ $children = ORM::factory("item", $this->input->post("item_id"))
+ ->where("type !=", "album")
+ ->descendants();
+ }
// Loop through each item in the album and make sure the user has
// access to view and edit it.
diff --git a/modules/batchtag/helpers/batchtag_theme.php b/modules/batchtag/helpers/batchtag_block.php
similarity index 71%
rename from modules/batchtag/helpers/batchtag_theme.php
rename to modules/batchtag/helpers/batchtag_block.php
index 190604f2..8bc3afc6 100644
--- a/modules/batchtag/helpers/batchtag_theme.php
+++ b/modules/batchtag/helpers/batchtag_block.php
@@ -17,20 +17,22 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-class batchtag_theme_Core {
- static function sidebar_blocks($theme) {
- // Display form for tagging in the album sidebar.
-
- // Make sure the current page belongs to an item.
- if (!$theme->item()) {
- return;
- }
-
- $item = $theme->item();
-
- // Only display the form in albums that the user has edit permission in.
- if ($item->is_album() && access::can("edit", $item)) {
+class batchtag_block_Core {
+ static function get_site_list() {
+ return array("batch_tag" => t("Batch Tag"));
+ }
+ static function get($block_id, $theme) {
+ $block = "";
+
+ // Only display on album pages that the user can edit.
+ $item = $theme->item();
+ if (!$item->is_album() || !access::can("edit", $item)) {
+ return;
+ }
+
+ switch ($block_id) {
+ case "batch_tag":
// Make a new sidebar block.
$block = new Block();
$block->css_id = "g-batch-tag";
@@ -43,12 +45,17 @@ class batchtag_theme_Core {
$label = t("Tag everything in this album:");
$group = $form->group("add_tag")->label("Add Tag");
$group->input("name")->label($label)->rules("required|length[1,64]");
+ $group->checkbox("tag_subitems")
+ ->label(t("Include sub-albums?"))
+ ->value(true)
+ ->checked(false);
+
$group->hidden("item_id")->value($item->id);
$group->submit("")->value(t("Add Tag"));
- $block->content->form = $form;
+ $block->content->batch_tag_form = $form;
- // Display the block.
- return $block;
- }
+ break;
+ }
+ return $block;
}
-}
\ No newline at end of file
+}
diff --git a/modules/batchtag/module.info b/modules/batchtag/module.info
index 398147ac..eb00345a 100644
--- a/modules/batchtag/module.info
+++ b/modules/batchtag/module.info
@@ -1,3 +1,3 @@
-name = BatchTag
-description = Automatically apply a tag to the entire contents of an album.
+name = "BatchTag"
+description = "Automatically apply a tag to the entire contents of an album."
version = 1
diff --git a/modules/batchtag/views/batchtag_block.html.php b/modules/batchtag/views/batchtag_block.html.php
index 4993189e..9f820b35 100644
--- a/modules/batchtag/views/batchtag_block.html.php
+++ b/modules/batchtag/views/batchtag_block.html.php
@@ -1,2 +1,2 @@
-= $form ?>
\ No newline at end of file
+= $batch_tag_form ?>
\ No newline at end of file
diff --git a/modules/contactowner/helpers/contactowner_block.php b/modules/contactowner/helpers/contactowner_block.php
new file mode 100644
index 00000000..bf01d338
--- /dev/null
+++ b/modules/contactowner/helpers/contactowner_block.php
@@ -0,0 +1,78 @@
+ t("Contact Owner"));
+ }
+
+ static function get($block_id, $theme) {
+ $block = "";
+
+ switch ($block_id) {
+ case "contact_owner":
+
+ // Create a new block to display the links in.
+ $block = new Block();
+ $block->css_id = "g-contact-owner";
+ $block->title = t("Contact");
+ $block->content = new View("contactowner_block.html");
+
+ // if $displayBlock is true, this block will be displayed,
+ // if there aren't any links to put in the block for whatever reason
+ // then $displayBlock will rename set to false and the
+ // block will not be displayed.
+ $displayBlock = false;
+
+ if ($theme->item()) {
+ // Locate the record for the user that created the current item.
+ // Their name will be displayed as part of the contact link.
+ $userDetails = ORM::factory("user")
+ ->where("id", $theme->item->owner_id)
+ ->find_all();
+
+ // Figure out if the contact item owner email link should be displayed.
+ // only display it if the current owner has an email address and
+ // the option for allowing item owners to be contacted is set to true.
+ if ((count($userDetails) > 0) && ($userDetails[0]->email != "") &&
+ (module::get_var("contactowner", "contact_user_link") == true)) {
+ $block->content->userLink = "item->owner_id) . "\">" . t("Contact") . " " .
+ $userDetails[0]->name . " ";
+ $displayBlock = true;
+ }
+ }
+
+ // Figure out if the contact site owner link should be displayed.
+ if (module::get_var("contactowner", "contact_owner_link")) {
+ $block->content->ownerLink = "" . t(module::get_var("contactowner", "contact_button_text")) . " ";
+ $displayBlock = true;
+ }
+
+ break;
+ }
+
+ if ($displayBlock) {
+ return $block;
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/modules/contactowner/helpers/contactowner_theme.php b/modules/contactowner/helpers/contactowner_theme.php
deleted file mode 100644
index bc243c0a..00000000
--- a/modules/contactowner/helpers/contactowner_theme.php
+++ /dev/null
@@ -1,70 +0,0 @@
-item()) {
- return;
- }
-
- // Locate the record for the user that created the current item.
- // Their name will be displayed as part of the contact link.
- $userDetails = ORM::factory("user")
- ->where("id", $theme->item->owner_id)
- ->find_all();
-
- // Create a new block to display the links in.
- $block = new Block();
- $block->css_id = "g-contact-owner";
- $block->title = t("Contact:");
- $block->content = new View("contactowner_block.html");
-
- // if $displayBlock is true, this block will be displayed,
- // if there aren't any links to put in the block for whatever reason
- // then $displayBlock will rename set to false and the
- // block will not be displayed.
- $displayBlock = false;
-
- // Figure out if the contact item owner email link should be displayed.
- // only display it if the current owner has an email address and
- // the option for allowing item owners to be contacted is set to true.
- if ((count($userDetails) > 0) && ($userDetails[0]->email != "") &&
- (module::get_var("contactowner", "contact_user_link") == true)) {
- $block->content->userLink = "item->owner_id) . "\">" . t("Contact") . " " . $userDetails[0]->name . " ";
- $displayBlock = true;
- }
-
- // Figure out if the contact site owner link should be displayed.
- if (module::get_var("contactowner", "contact_owner_link")) {
- $block->content->ownerLink = "" . t(module::get_var("contactowner", "contact_button_text")) . " ";
- $displayBlock = true;
- }
-
- if ($displayBlock) {
- return $block;
- }
- }
-}
diff --git a/modules/contactowner/module.info b/modules/contactowner/module.info
index 673023c3..1dce49be 100644
--- a/modules/contactowner/module.info
+++ b/modules/contactowner/module.info
@@ -1,3 +1,3 @@
-name = ContactOwner
-description = Allows visitors to send the website owner an email.
+name = "ContactOwner"
+description = "Allows visitors to send the website owner an email."
version = 1
diff --git a/modules/displaytags/helpers/displaytags_block.php b/modules/displaytags/helpers/displaytags_block.php
new file mode 100644
index 00000000..454ff0b6
--- /dev/null
+++ b/modules/displaytags/helpers/displaytags_block.php
@@ -0,0 +1,54 @@
+ t("Display Tags"));
+ }
+
+ static function get($block_id, $theme) {
+ $block = "";
+
+ // Make sure the current page belongs to an item.
+ if (!$theme->item()) {
+ return;
+ }
+
+ switch ($block_id) {
+ case "display_tags":
+ // Create an array of all the tags for the current item.
+ $tagsItem = ORM::factory("tag")
+ ->join("items_tags", "tags.id", "items_tags.tag_id")
+ ->where("items_tags.item_id", $theme->item->id)
+ ->find_all();
+
+ // If the current item has at least one tag, display it/them.
+ if (count($tagsItem) > 0) {
+ $block = new Block();
+ $block->css_id = "g-display-tags";
+ $block->title = t("Tags");
+ $block->content = new View("displaytags_block.html");
+ $block->content->tags = $tagsItem;
+ }
+
+ break;
+ }
+ return $block;
+ }
+}
diff --git a/modules/displaytags/module.info b/modules/displaytags/module.info
index b905a8e4..d8458f10 100644
--- a/modules/displaytags/module.info
+++ b/modules/displaytags/module.info
@@ -1,3 +1,3 @@
-name = DisplayTags
-description = Display all tags for the current photo/album.
+name = "DisplayTags"
+description = "Display all tags for the current photo/album."
version = 1
diff --git a/modules/downloadfullsize/helpers/downloadfullsize_theme.php b/modules/downloadfullsize/helpers/downloadfullsize_theme.php
index a8ab828e..6ec329dc 100644
--- a/modules/downloadfullsize/helpers/downloadfullsize_theme.php
+++ b/modules/downloadfullsize/helpers/downloadfullsize_theme.php
@@ -19,11 +19,9 @@
*/
class downloadfullsize_theme {
static function head($theme) {
- if (!$theme->item()) {
- return;
+ if ($theme->item && access::can("view_full", $theme->item)) {
+ $theme->css("downloadfullsize_menu.css");
}
-
- return new View("downloadfullsize_header_block.html");
}
static function sidebar_blocks($theme) {
diff --git a/modules/downloadfullsize/module.info b/modules/downloadfullsize/module.info
index 3f31f39a..6c732c9d 100644
--- a/modules/downloadfullsize/module.info
+++ b/modules/downloadfullsize/module.info
@@ -1,3 +1,3 @@
-name = DownloadFullsize
-description = Displays a link to download the fullsize version of the current photo.
+name = "DownloadFullsize"
+description = "Displays a link to download the fullsize version of the current photo."
version = 1
diff --git a/modules/downloadfullsize/views/downloadfullsize_header_block.html.php b/modules/downloadfullsize/views/downloadfullsize_header_block.html.php
deleted file mode 100644
index df91292b..00000000
--- a/modules/downloadfullsize/views/downloadfullsize_header_block.html.php
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
- " />
diff --git a/modules/editcreation/css/editcreation.css b/modules/editcreation/css/editcreation.css
new file mode 100644
index 00000000..6894018c
--- /dev/null
+++ b/modules/editcreation/css/editcreation.css
@@ -0,0 +1,3 @@
+select {
+ display: inline;
+}
diff --git a/modules/editcreation/helpers/editcreation_event.php b/modules/editcreation/helpers/editcreation_event.php
index 6cadc8f9..e7eeb455 100644
--- a/modules/editcreation/helpers/editcreation_event.php
+++ b/modules/editcreation/helpers/editcreation_event.php
@@ -21,10 +21,7 @@ class editcreation_event_Core {
static function item_edit_form($item, $form) {
// Add a couple of drop-down boxes to allow the user to edit the date
// that $item was created on.
-
- // Inject some css to make everything look right.
- print ("\n");
-
+
// Add the datecreated element to the form.
$form->edit_item->dateselect("datecreated")
->label(t("Created"))
diff --git a/modules/displaytags/helpers/displaytags_theme.php b/modules/editcreation/helpers/editcreation_theme.php
similarity index 55%
rename from modules/displaytags/helpers/displaytags_theme.php
rename to modules/editcreation/helpers/editcreation_theme.php
index 529ac5de..c50cd739 100644
--- a/modules/displaytags/helpers/displaytags_theme.php
+++ b/modules/editcreation/helpers/editcreation_theme.php
@@ -1,4 +1,5 @@
-item()) {
return;
}
-
- // Create an array of all the tags for the current item.
- $tagsItem = ORM::factory("tag")
- ->join("items_tags", "tags.id", "items_tags.tag_id")
- ->where("items_tags.item_id", $theme->item->id)
- ->find_all();
-
- // If the current item has at least one tag, display it/them.
- if (count($tagsItem) > 0) {
- $block = new Block();
- $block->css_id = "g-display-tags";
- $block->title = t("Tags");
- $block->content = new View("displaytags_block.html");
- $block->content->tags = $tagsItem;
- return $block;
+ $item = $theme->item();
+ if ( $item && access::can("edit", $item) ) {
+ $theme->css("editcreation.css");
}
- }
+ }
}
diff --git a/modules/embedlinks/helpers/embedlinks_block.php b/modules/embedlinks/helpers/embedlinks_block.php
new file mode 100644
index 00000000..44539854
--- /dev/null
+++ b/modules/embedlinks/helpers/embedlinks_block.php
@@ -0,0 +1,55 @@
+ t("Embed Links Dialog"), "embed_links_album" => t("Embed Links Album"));
+ }
+
+ static function get($block_id, $theme) {
+ $block = "";
+
+ switch ($block_id) {
+ case "embed_links_dialog":
+ // If displaying links in a dialog box is enabled then
+ // insert buttons into the bottom of the side bar
+ // to open up the dialog window.
+ if (module::get_var("embedlinks", "DialogLinks") && $theme->item()) {
+ $block = new Block();
+ $block->css_id = "g-embed-links-sidebar";
+ $block->title = t("Link To This Page");
+ $block->content = new View("embedlinks_sidebar.html");
+ }
+ break;
+
+ case "embed_links_album":
+ // If the current item is an album and if "In Page" links are enabled then
+ // display links to the current album in the theme sidebar.
+ if ($theme->item()->is_album() && module::get_var("embedlinks", "InPageLinks")) {
+ $block = new Block();
+ $block->css_id = "g-embed-links-album-sidebar";
+ $block->title = t("Links");
+ $block->content = new View("embedlinks_album_block.html");
+ }
+ break;
+ }
+
+ return $block;
+ }
+}
diff --git a/modules/embedlinks/helpers/embedlinks_theme.php b/modules/embedlinks/helpers/embedlinks_theme.php
index 251b7e5c..c6d9cf92 100644
--- a/modules/embedlinks/helpers/embedlinks_theme.php
+++ b/modules/embedlinks/helpers/embedlinks_theme.php
@@ -18,31 +18,6 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class embedlinks_theme_Core {
- static function sidebar_blocks($theme) {
- // If the current item is an album and if "In Page" links are enabled then
- // display links to the current album in the theme sidebar.
- if ($theme->item()->is_album() && module::get_var("embedlinks", "InPageLinks")) {
- $block = new Block();
- $block->css_id = "g-metadata";
- $block->title = t("Links");
- $block->content = new View("embedlinks_album_block.html");
- return $block;
- }
- }
-
- static function sidebar_bottom($theme) {
- // If displaying links in a dialog box is enabled then
- // insert buttons into the bottom of the side bar
- // to open up the dialog window.
- if (module::get_var("embedlinks", "DialogLinks")) {
- $block = new Block();
- $block->css_id = "g-metadata";
- $block->title = t("Link To This Page:");
- $block->content = new View("embedlinks_sidebar.html");
- return $block;
- }
- }
-
static function photo_bottom($theme) {
// If the current item is a photo and displaying "In Page" links
// is enabled, then insert HTML/BBCode links into the bottom
diff --git a/modules/embedlinks/module.info b/modules/embedlinks/module.info
index de716d1a..a2917bcd 100644
--- a/modules/embedlinks/module.info
+++ b/modules/embedlinks/module.info
@@ -1,3 +1,3 @@
-name = EmbedLinks
-description = Display BBCode and HTML code to embed links to albums/images into other web pages.
+name = "EmbedLinks"
+description = "Display BBCode and HTML code to embed links to albums/images into other web pages."
version = 1
diff --git a/modules/embedlinks/views/embedlinks_htmldialog.html.php b/modules/embedlinks/views/embedlinks_htmldialog.html.php
index 5847e8cc..46537754 100644
--- a/modules/embedlinks/views/embedlinks_htmldialog.html.php
+++ b/modules/embedlinks/views/embedlinks_htmldialog.html.php
@@ -5,7 +5,7 @@ input[type="text"] {
}
= t("HTML Code") ?>
-
+
$counter = 0; ?>
for ($i = 0; $i < count($titles); $i++): ?>
diff --git a/modules/embedlinks/views/embedlinks_photo_block.html.php b/modules/embedlinks/views/embedlinks_photo_block.html.php
index baf4c2e2..97bb51c0 100644
--- a/modules/embedlinks/views/embedlinks_photo_block.html.php
+++ b/modules/embedlinks/views/embedlinks_photo_block.html.php
@@ -7,7 +7,7 @@ input[type="text"] {
if (module::get_var("embedlinks", "HTMLCode")) { ?>
= t("HTML Links")?>
-
+
= t("Link To This Page:") ?>
diff --git a/modules/gwtorganise/.classpath b/modules/gwtorganise/.classpath
new file mode 100644
index 00000000..a240a4e4
--- /dev/null
+++ b/modules/gwtorganise/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/gwtorganise/.project b/modules/gwtorganise/.project
new file mode 100644
index 00000000..eefb6ee6
--- /dev/null
+++ b/modules/gwtorganise/.project
@@ -0,0 +1,40 @@
+
+
+ gwtorganise
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.google.gwt.eclipse.core.gwtProjectValidator
+
+
+
+
+ com.google.appengine.eclipse.core.enhancerbuilder
+
+
+
+
+ com.google.appengine.eclipse.core.projectValidator
+
+
+
+
+ com.google.gdt.eclipse.core.webAppProjectValidator
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ com.google.appengine.eclipse.core.gaeNature
+ com.google.gwt.eclipse.core.gwtNature
+ com.google.gdt.eclipse.core.webAppNature
+
+
diff --git a/modules/gwtorganise/.settings/com.google.appengine.eclipse.core.prefs b/modules/gwtorganise/.settings/com.google.appengine.eclipse.core.prefs
new file mode 100644
index 00000000..1a43c478
--- /dev/null
+++ b/modules/gwtorganise/.settings/com.google.appengine.eclipse.core.prefs
@@ -0,0 +1,3 @@
+#Sun Aug 30 20:30:24 NZST 2009
+eclipse.preferences.version=1
+filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.2.2.jar|datanucleus-appengine-1.0.2.final.jar|datanucleus-core-1.1.4-gae.jar|datanucleus-jpa-1.1.4.jar|geronimo-jpa_3.0_spec-1.1.1.jar|geronimo-jta_1.1_spec-1.1.1.jar|jdo2-api-2.3-ea.jar
diff --git a/modules/gwtorganise/.settings/com.google.gwt.eclipse.core.prefs b/modules/gwtorganise/.settings/com.google.gwt.eclipse.core.prefs
new file mode 100644
index 00000000..3e2783ad
--- /dev/null
+++ b/modules/gwtorganise/.settings/com.google.gwt.eclipse.core.prefs
@@ -0,0 +1,4 @@
+#Thu Sep 24 11:47:04 NZST 2009
+eclipse.preferences.version=1
+filesCopiedToWebInfLib=gwt-servlet.jar
+gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybV1dPjwvdm0tYXJncz48L2d3dC1jb21waWxlLXNldHRpbmdzPg\=\=
diff --git a/modules/gwtorganise/controllers/admin_gwtorganise.php b/modules/gwtorganise/controllers/admin_gwtorganise.php
new file mode 100644
index 00000000..5947b8c9
--- /dev/null
+++ b/modules/gwtorganise/controllers/admin_gwtorganise.php
@@ -0,0 +1,26 @@
+content = new View("gwtorganise_view.html");
+ print $view;
+ }
+}
diff --git a/modules/gwtorganise/controllers/json_album.php b/modules/gwtorganise/controllers/json_album.php
new file mode 100644
index 00000000..70743e3d
--- /dev/null
+++ b/modules/gwtorganise/controllers/json_album.php
@@ -0,0 +1,257 @@
+ $child->id,
+ 'title' => $child->title,
+ 'type' => $child->type,
+ 'thumb' => $child->thumb_url(),
+ 'resize' => $child->resize_url(),
+ 'sort' => $child->sort_column);
+ }
+
+ private function child_elements($item_id, $where = array()) {
+ $item = ORM::factory("item", $item_id);
+ access::required("view", $item);
+
+ $children = $item->children(null, 0, $where);
+ $encoded = array();
+ foreach ($children as $id => $child){
+ $encoded[$id] = self::child_json_encode($child);
+ }
+
+ return json_encode($encoded);
+ }
+
+ function is_admin() {
+ if (user::active()->admin) {
+ print json_encode(array("result" => "success", "csrf" => access::csrf_token()));
+ return;
+ }
+ print json_encode(array("result" => "failure"));
+
+ }
+
+ function albums($item_id) {
+
+ print $this->child_elements($item_id,array("type" => "album"));
+ }
+
+ function children($item_id){
+
+ print $this->child_elements($item_id);
+ }
+
+ function item($item_id){
+
+ $item = ORM::factory("item", $item_id);
+ access::required("view", $item);
+ print json_encode(self::child_json_encode($item));
+ }
+
+
+ function move_to($target_album_id) {
+ access::verify_csrf();
+
+ $target_album = ORM::factory("item", $target_album_id);
+
+ $js = json_decode($_REQUEST["sourceids"]);
+
+ $i = 0;
+ foreach ($js as $source_id) {
+ $source = ORM::factory("item", $source_id);
+ if (!$source->contains($target_album)) {
+ item::move($source, $target_album);
+ }
+ $i++;
+ }
+
+ print json_encode(array("result" => "success"));
+ }
+
+ function rearrange($target_id, $before_or_after) {
+ access::verify_csrf();
+ $target = ORM::factory("item", $target_id);
+ $album = $target->parent();
+ access::required("view", $album);
+ access::required("edit", $album);
+
+ $source_ids = json_decode($_REQUEST["sourceids"]);
+
+ if ($album->sort_column != "weight") {
+ $i = 0;
+ foreach ($album->children() as $child) {
+ // Do this directly in the database to avoid sending notifications
+ Database::Instance()->update("items", array("weight" => ++$i), array("id" => $child->id));
+ }
+ $album->sort_column = "weight";
+ $album->sort_order = "ASC";
+ $album->save();
+ $target->reload();
+ }
+
+ // Find the insertion point
+ $target_weight = $target->weight;
+ if ($before_or_after == "after") {
+ $target_weight++;
+ }
+
+ // Make a hole
+ $count = count($source_ids);
+ Database::Instance()->query(
+ "UPDATE {items} " .
+ "SET `weight` = `weight` + $count " .
+ "WHERE `weight` >= $target_weight AND `parent_id` = {$album->id}");
+
+ // Insert source items into the hole
+ foreach ($source_ids as $source_id) {
+ Database::Instance()->update(
+ "items", array("weight" => $target_weight++), array("id" => $source_id));
+ }
+
+ module::event("album_rearrange", $album);
+
+ print json_encode(array("result" => "success"));
+
+ }
+
+ public function start() {
+ batch::start();
+ }
+
+ public function add_photo($id) {
+ access::verify_csrf();
+ $album = ORM::factory("item", $id);
+ access::required("view", $album);
+ access::required("add", $album);
+
+
+ try {
+ $name = $_REQUEST["filename"];
+ $body = @file_get_contents('php://input');
+ //$stream = http_get_request_body();
+
+ $directory = Kohana::config('upload.directory', TRUE);
+
+ // Make sure the directory ends with a slash
+ $directory = str_replace('\\','/',$directory);
+ $directory = rtrim($directory, '/').'/';
+
+ if ( ! is_dir($directory) AND Kohana::config('upload.create_directories') === TRUE)
+ {
+ // Create the upload directory
+ mkdir($directory, 0777, TRUE);
+ }
+
+ if ( ! is_writable($directory))
+ throw new Kohana_Exception('upload.not_writable', $directory);
+
+ $temp_filename = $directory.$name;
+ $file = fopen($temp_filename,'w');
+
+ fwrite($file,$body);
+
+ fclose($file);
+
+
+
+ $title = item::convert_filename_to_title($name);
+ $path_info = @pathinfo($temp_filename);
+ if (array_key_exists("extension", $path_info) &&
+ in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) {
+ $item = movie::create($album, $temp_filename, $name, $title);
+ log::success("content", t("Added a movie"),
+ html::anchor("movies/$item->id", t("view movie")));
+ } else {
+ $item = photo::create($album, $temp_filename, $name, $title);
+ log::success("content", t("Added a photo"),
+ html::anchor("photos/$item->id", t("view photo")));
+ }
+ } catch (Exception $e) {
+ Kohana::log("alert", $e->__toString());
+ if (file_exists($temp_filename)) {
+ unlink($temp_filename);
+ }
+ header("HTTP/1.1 500 Internal Server Error");
+ print "ERROR: " . $e->getMessage();
+ return;
+ }
+ unlink($temp_filename);
+
+ print json_encode(self::child_json_encode($item));
+ }
+
+ public function make_album_cover($id) {
+ access::verify_csrf();
+
+ $item = model_cache::get("item", $id);
+ access::required("view", $item);
+ access::required("view", $item->parent());
+ access::required("edit", $item->parent());
+
+ item::make_album_cover($item);
+
+ print json_encode(array("result" => "success"));
+ }
+
+ public function rotate($id, $dir) {
+ access::verify_csrf();
+ $item = model_cache::get("item", $id);
+ access::required("view", $item);
+ access::required("edit", $item);
+
+ $degrees = 0;
+ switch($dir) {
+ case "ccw":
+ $degrees = -90;
+ break;
+
+ case "cw":
+ $degrees = 90;
+ break;
+ }
+
+ if ($degrees) {
+ graphics::rotate($item->file_path(), $item->file_path(), array("degrees" => $degrees));
+
+ list($item->width, $item->height) = getimagesize($item->file_path());
+ $item->resize_dirty= 1;
+ $item->thumb_dirty= 1;
+ $item->save();
+
+ graphics::generate($item);
+
+ $parent = $item->parent();
+ if ($parent->album_cover_item_id == $item->id) {
+ copy($item->thumb_path(), $parent->thumb_path());
+ $parent->thumb_width = $item->thumb_width;
+ $parent->thumb_height = $item->thumb_height;
+ $parent->save();
+ }
+ }
+
+ print json_encode(self::child_json_encode($item));
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/gwtorganise/helpers/gwtorganise_event.php b/modules/gwtorganise/helpers/gwtorganise_event.php
new file mode 100644
index 00000000..1259ac3b
--- /dev/null
+++ b/modules/gwtorganise/helpers/gwtorganise_event.php
@@ -0,0 +1,34 @@
+add_after("users_groups",
+ Menu::factory("link")
+ ->id("gwtorganise")
+ ->label(t("GWT Organise"))
+ ->url(url::site("admin/gwtorganise")));
+ }
+}
diff --git a/modules/gwtorganise/helpers/gwtorganise_installer.php b/modules/gwtorganise/helpers/gwtorganise_installer.php
new file mode 100644
index 00000000..f06e911d
--- /dev/null
+++ b/modules/gwtorganise/helpers/gwtorganise_installer.php
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/G3viewer.gwt.xml b/modules/gwtorganise/src/com/gloopics/g3viewer/G3viewer.gwt.xml
new file mode 100644
index 00000000..02bcf924
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/G3viewer.gwt.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/Album.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Album.java
new file mode 100644
index 00000000..7667005a
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Album.java
@@ -0,0 +1,481 @@
+package com.gloopics.g3viewer.client;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.gears.client.Factory;
+import com.google.gwt.gears.client.desktop.Desktop;
+import com.google.gwt.gears.client.desktop.File;
+import com.google.gwt.gears.client.desktop.OpenFilesHandler;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.TreeItem;
+
+/**
+ * encapsulates an album
+ * @author User
+ *
+ */
+public class Album extends TreeItem {
+
+ private final int m_ID;
+
+ private String m_Title;
+
+
+ private final G3Viewer m_Container;
+
+ private final View m_View;
+
+ private final Label m_Label;
+
+ private String m_Sort;
+
+ private final List- m_Items = new ArrayList
- ();
+
+ private final Map
m_IDtoItem = new HashMap();
+
+ private final Map m_IDtoAlbum = new HashMap();
+
+ private final LinkedList m_UploadQueue = new LinkedList();
+
+ private boolean m_Running = false;
+
+ private final AlbumTreeDropController m_DropController;
+
+ public Album(JSONObject jsonObject, G3Viewer a_Container)
+ {
+ m_ID = (int)((JSONNumber)jsonObject.get("id")).doubleValue();
+ m_Title = ((JSONString)jsonObject.get("title")).stringValue();
+ m_Sort = ((JSONString)jsonObject.get("sort")).stringValue();
+
+ m_Container = a_Container;
+ m_View = a_Container.getView();
+ m_DropController = new AlbumTreeDropController(this);
+ m_Label = initComponents();
+
+ }
+
+ public Album(G3Viewer a_Container)
+ {
+ m_ID = 1;
+ m_Title = "Root";
+ m_Container = a_Container;
+ m_View = a_Container.getView();
+ m_Sort = "Unknown";
+ m_DropController = new AlbumTreeDropController(this);
+ m_Label = initComponents();
+ refresh();
+ }
+
+ public void updateValues(JSONValue a_Jso){
+ JSONObject jso = a_Jso.isObject();
+ if (jso != null){
+ m_Title = ((JSONString)jso.get("title")).stringValue();
+ String oldSort = m_Sort;
+ m_Sort = ((JSONString)jso.get("sort")).stringValue();
+ if (!oldSort.equals(m_Sort)){
+ if (m_View.getCurrentAlbum() == this)
+ {
+ select();
+ }
+ }
+ m_Label.setText(m_Title);
+ }
+ }
+
+ public void refresh(){
+ m_Container.doJSONRequest(G3Viewer.VIEW_ITEM_URL + getId(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ updateValues(aValue);
+ }
+ },false);
+ }
+
+
+
+ public void showPopupMenu(Event event){
+ m_Label.addStyleName("popped");
+ final PopupPanel popupPanel = new PopupPanel(true);
+ popupPanel.setAnimationEnabled(true);
+ MenuBar popupMenuBar = new MenuBar(true);
+
+ MenuItem editItem = new MenuItem("Edit Album", true, new Command() {
+
+ @Override
+ public void execute() {
+ m_Container.doDialog("index.php/form/edit/albums/" + m_ID, new HttpDialogHandler() {
+ @Override
+ public void success(String aResult) {
+ refresh();
+
+ }
+ });
+ popupPanel.hide();
+
+ }
+ });
+ MenuItem uploadPhotos = new MenuItem("Upload Photos", true, new Command() {
+
+ @Override
+ public void execute() {
+ uploadFiles();
+ popupPanel.hide();
+
+ }
+ });
+ MenuItem addAlbum = new MenuItem("Add Album", true, new Command() {
+
+ @Override
+ public void execute() {
+ m_Container.doDialog("index.php/form/add/albums/" + m_ID + "?type=album", new HttpDialogHandler() {
+ @Override
+ public void success(String aResult) {
+ expand();
+ m_View.getCurrentAlbum().select();
+ }
+ });
+
+ popupPanel.hide();
+
+ }
+ });
+
+ MenuItem userPermissions = new MenuItem("User Permissions", true, new Command() {
+ @Override
+ public void execute() {
+ m_Container.doDialog("index.php/permissions/browse/" + m_ID , new HttpDialogHandler() {
+ @Override
+ public void success(String aResult) {
+ }
+ });
+
+ popupPanel.hide();
+
+ }
+ });
+
+ popupPanel.setStyleName("popup");
+ editItem.addStyleName("popup-item");
+ addAlbum.addStyleName("popup-item");
+ uploadPhotos.addStyleName("popup-item");
+ userPermissions.addStyleName("popup-item");
+
+
+ popupMenuBar.addItem(uploadPhotos);
+ popupMenuBar.addItem(editItem);
+ popupMenuBar.addItem(addAlbum);
+ popupMenuBar.addItem(userPermissions);
+
+
+ popupMenuBar.setVisible(true);
+ popupPanel.add(popupMenuBar);
+
+ int x = DOM.eventGetClientX(event);
+ int y = DOM.eventGetClientY(event);
+ popupPanel.setPopupPosition(x, y);
+ popupPanel.addCloseHandler(new CloseHandler() {
+
+ @Override
+ public void onClose(CloseEvent event) {
+
+ m_Label.removeStyleName("popped");
+ }
+ });
+
+ popupPanel.show();
+ }
+
+ private Label initComponents()
+ {
+ Label toReturn = new Label(m_Title);
+ toReturn.addStyleName("Tree-Album");
+ setWidget(toReturn);
+ m_Container.getDragController().registerDropController(m_DropController);
+ expand();
+
+ return toReturn;
+ }
+
+ public int getId()
+ {
+ return m_ID;
+ }
+
+ /*
+ * Adds the albums in the json response
+ * TreeItem.
+ */
+ private void addAlbums(JSONValue jsonValue)
+ {
+ JSONArray jsonArray = (JSONArray)jsonValue;
+ Set allAlbums = new HashSet(m_IDtoAlbum.keySet());
+ for (int i = 0; i < jsonArray.size(); ++i)
+ {
+ JSONObject jso = (JSONObject)jsonArray.get(i);
+ int id = (int)((JSONNumber)jso.get("id")).doubleValue();
+
+ if (m_IDtoAlbum.containsKey(id))
+ {
+ m_IDtoAlbum.get(id).updateValues(jso);
+ }
+ else
+ {
+ Album album = new Album(jso, m_Container);
+ m_IDtoAlbum.put(id, album);
+ addItem(album);
+ }
+ allAlbums.remove(id);
+ }
+ for (Integer id : allAlbums){
+ Album a = m_IDtoAlbum.remove(id);
+ a.cleanup();
+
+
+ removeItem(a);
+ }
+ }
+
+ public void cleanup()
+ {
+ m_Container.getDragController().unregisterDropController(m_DropController);
+ for (int i = 0; i < getChildCount(); i++){
+ ((Album) getChild(i)).cleanup();
+ }
+ }
+
+ /**
+ * moves the given array of ids to this album
+ */
+ public void moveTo(JSONArray a_Ids){
+ Loading.getInstance().loading();
+
+ m_Container.doJSONRequest(G3Viewer.MOVE_TO_ALBUM_URL + getId() + "?sourceids=" + a_Ids.toString(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ expand();
+ m_View.getCurrentAlbum().expand();
+ m_View.getCurrentAlbum().select();
+ }
+ },true);
+ }
+
+ /**
+ * rearranges the albums
+ */
+
+ public void rearrangeTo(JSONArray a_Ids, Item m_CompareTo, boolean m_Before){
+ Loading.getInstance().loading();
+ String bora = m_Before?"before":"after";
+
+ m_Container.doJSONRequest(G3Viewer.REARRANGE_URL + m_CompareTo.getID() + "/" + bora
+ + "?sourceids=" + a_Ids.toString(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ m_View.getCurrentAlbum().select();
+ }
+ },true);
+ }
+
+
+ /**
+ * returns the album with the given id
+ */
+ public void selectSubAlbum(int a_Id){
+ for (int i = 0; i < getChildCount(); i++)
+ {
+ Album ab = ((Album) getChild(i));
+ if (ab.m_ID == a_Id)
+ {
+ ab.select();
+ m_Container.getTree().ensureSelected(ab);
+ }
+ }
+ }
+
+ /*
+ * Fetch the requested URL.
+ */
+ public void expand() {
+
+ m_Container.doJSONRequest(G3Viewer.VIEW_ALBUM_URL + getId(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ addAlbums(aValue);
+ }
+ },false);
+ }
+
+
+ public void select() {
+ Loading.getInstance().loading();
+ m_Container.doJSONRequest(G3Viewer.VIEW_CHILDREN_URL + getId(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ viewAlbum(aValue);
+ }
+ },false);
+
+ }
+
+ /*
+ * view Album contents
+ */
+ private void viewAlbum(JSONValue a_Value){
+
+ JSONArray jsonArray = (JSONArray)a_Value;
+
+ Item item = null;
+ int id;
+ JSONObject jso;
+
+ m_Items.clear();
+
+ for (int i = 0; i < jsonArray.size(); ++i)
+ {
+ jso = (JSONObject)jsonArray.get(i);
+ id = (int)((JSONNumber)jso.get("id")).doubleValue();
+
+ if (m_IDtoItem.containsKey(id)){
+ item = m_IDtoItem.get(id);
+ item.updateValues(jso);
+ }
+ else
+ {
+ item =new Item(this, jso, m_Container);
+ m_IDtoItem.put(id, item);
+
+ if (item.isAlbum()){
+ linkAlbum(item);
+ }
+ }
+ m_Items.add(item);
+
+ }
+
+ m_View.setAlbum(this);
+ addPendingDownloads();
+ }
+
+ public List- getItems()
+ {
+ return m_Items;
+ }
+
+ public void linkAlbum(Item a_Item){
+ // link album
+ int id = a_Item.getID();
+ Album child;
+ for (int j = 0 ; j < getChildCount(); j++){
+ child = (Album) getChild(j);
+ if (child.m_ID == id){
+ a_Item.setLinkedAlbum(child);
+ j = getChildCount();
+ }
+
+ }
+ }
+
+ public boolean isManualSort(){
+ return m_Sort.equalsIgnoreCase("weight");
+ }
+
+ public void uploadFiles() {
+ Desktop desktop = Factory.getInstance().createDesktop();
+
+ desktop.openFiles(new OpenFilesHandler() {
+
+ public void onOpenFiles(OpenFilesEvent event) {
+ File[] files = event.getFiles();
+ UploadFile uf;
+ for (File file : files){
+ uf = new UploadFile(Album.this, file);
+ m_View.addToView(uf);
+ m_UploadQueue.addLast(uf);
+ }
+
+ if (!m_Running){
+ m_Running = true;
+ next();
+ }
+
+ }
+ }, false);
+
+ }
+
+ public void addPendingDownloads()
+ {
+ for (UploadFile uf: m_UploadQueue)
+ {
+ m_View.addToView(uf);
+ }
+ }
+
+ public void finishedUpload(UploadFile uf, JSONValue a_Return)
+ {
+ m_UploadQueue.remove(uf);
+ next();
+
+ JSONObject jo = a_Return.isObject();
+
+ if (jo != null){
+ Item item = new Item(this,jo,m_Container);
+ m_IDtoItem.put(item.getID(), item);
+ m_Items.add(item);
+
+ if (m_View.getCurrentAlbum() == this){
+ m_View.replaceInView(uf, item);
+ }
+ }
+ else
+ {
+ if (m_View.getCurrentAlbum() == this){
+ m_View.removeFromView(uf);
+ }
+ }
+
+
+ }
+
+ private void next()
+ {
+ if (m_UploadQueue.size() > 0)
+ {
+ UploadFile uf = m_UploadQueue.getFirst();
+ uf.startUpload();
+ }
+ else
+ {
+ m_Running = false;
+ }
+ }
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumItemDropContainer.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumItemDropContainer.java
new file mode 100644
index 00000000..84bc19bd
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumItemDropContainer.java
@@ -0,0 +1,73 @@
+package com.gloopics.g3viewer.client;
+
+import com.allen_sauer.gwt.dnd.client.DragContext;
+import com.allen_sauer.gwt.dnd.client.VetoDragException;
+import com.allen_sauer.gwt.dnd.client.drop.DropController;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.user.client.ui.Widget;
+
+public class AlbumItemDropContainer implements DropController{
+ /**
+ * the tree
+ */
+ private final Album m_Album;
+
+ private final Item m_Item;
+
+ public AlbumItemDropContainer(Item a_Item, Album a_Album){
+ m_Album = a_Album;
+ m_Item = a_Item;
+ }
+
+ @Override
+ public Widget getDropTarget() {
+ // TODO Auto-generated method stub
+ return m_Item;
+ }
+
+ @Override
+ public void onDrop(DragContext context) {
+ JSONArray jsa = new JSONArray();
+
+ int i = 0;
+ for (Widget widget : context.selectedWidgets){
+ if (widget instanceof Item){
+ jsa.set(i, new JSONNumber(((Item)widget).getID()));
+ i++;
+ }
+ }
+ m_Album.moveTo(jsa);
+ // context.
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onEnter(DragContext context) {
+ m_Item.addStyleName("drop-target");
+ //m_Album.g
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onLeave(DragContext context) {
+ // TODO Auto-generated method stub
+ m_Item.removeStyleName("drop-target");
+ }
+
+ @Override
+ public void onMove(DragContext context) {
+ // m_Album.
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onPreviewDrop(DragContext context) throws VetoDragException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTree.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTree.java
new file mode 100644
index 00000000..0150ac06
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTree.java
@@ -0,0 +1,101 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.TreeItem;
+
+public class AlbumTree extends Tree{
+
+ private final G3Viewer m_Container;
+
+
+ public AlbumTree(G3Viewer a_Container){
+ super();
+
+ sinkEvents(Event.ONMOUSEUP | Event.ONMOUSEDOWN | Event.ONCONTEXTMENU);
+
+ m_Container = a_Container;
+
+ addSelectionHandler(new SelectionHandler
() {
+
+ @Override
+ public void onSelection(SelectionEvent event) {
+ ((Album) event.getSelectedItem()).select();
+
+ }
+ });
+
+
+ }
+
+ public void fetchTree()
+ {
+ // fetch top album
+ Album tree = new Album(m_Container);
+ addItem(tree);
+ setSelectedItem(tree);
+ }
+
+ public void onBrowserEvent(Event event) {
+
+
+ switch (DOM.eventGetType(event)) {
+
+ case Event.ONMOUSEUP:
+ if (DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
+ event.preventDefault();
+ break;
+
+ }
+ else
+ {
+ super.onBrowserEvent(event);
+ }
+ break;
+
+ case Event.ONMOUSEDOWN:
+ if (DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
+ event.preventDefault();
+ break;
+
+ }
+ else
+ {
+ super.onBrowserEvent(event);
+ }
+ break;
+
+ case Event.ONCONTEXTMENU:
+ event.preventDefault();
+
+ popupMenu(event);
+ //GWT.log("Event.ONCONTEXTMENU", null);
+ break;
+
+ default:
+ super.onBrowserEvent(event);
+ }//end switch
+ }
+
+ public void refresh()
+ {
+ ((Album)getSelectedItem()).select();
+ }
+
+ public void ensureSelected(Album album)
+ {
+ setSelectedItem(album);
+ ensureSelectedItemVisible();
+ }
+
+
+ /* do popup
+ */
+ public void popupMenu(Event event){
+ ((Album)getSelectedItem()).showPopupMenu(event);
+ }
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTreeDropController.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTreeDropController.java
new file mode 100644
index 00000000..990ba9c7
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/AlbumTreeDropController.java
@@ -0,0 +1,72 @@
+package com.gloopics.g3viewer.client;
+
+import com.allen_sauer.gwt.dnd.client.DragContext;
+import com.allen_sauer.gwt.dnd.client.VetoDragException;
+import com.allen_sauer.gwt.dnd.client.drop.DropController;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.user.client.ui.Widget;
+
+public class AlbumTreeDropController implements DropController{
+
+ /**
+ * the tree
+ */
+ private final Album m_Album;
+
+ public AlbumTreeDropController(Album a_Album){
+ m_Album = a_Album;
+ }
+
+ @Override
+ public Widget getDropTarget() {
+ // TODO Auto-generated method stub
+ return m_Album.getWidget();
+ }
+
+ @Override
+ public void onDrop(DragContext context) {
+ JSONArray jsa = new JSONArray();
+
+ int i = 0;
+ for (Widget widget : context.selectedWidgets){
+ if (widget instanceof Item){
+ jsa.set(i, new JSONNumber(((Item)widget).getID()));
+ i++;
+ }
+ }
+ m_Album.moveTo(jsa);
+ // context.
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onEnter(DragContext context) {
+ m_Album.getWidget().addStyleName("drop-target");
+ //m_Album.g
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onLeave(DragContext context) {
+ // TODO Auto-generated method stub
+ m_Album.getWidget().removeStyleName("drop-target");
+ }
+
+ @Override
+ public void onMove(DragContext context) {
+ // m_Album.
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onPreviewDrop(DragContext context) throws VetoDragException {
+ // TODO Auto-generated method stub
+
+ }
+
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/DropZoneController.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/DropZoneController.java
new file mode 100644
index 00000000..a083cb13
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/DropZoneController.java
@@ -0,0 +1,85 @@
+package com.gloopics.g3viewer.client;
+
+import com.allen_sauer.gwt.dnd.client.DragContext;
+import com.allen_sauer.gwt.dnd.client.VetoDragException;
+import com.allen_sauer.gwt.dnd.client.drop.DropController;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+
+public class DropZoneController implements DropController{
+
+ /**
+ * the album
+ */
+ private final Album m_Album;
+
+ /**
+ * the album
+ */
+ private final HTML m_DropZone;
+
+ /**
+ * compare to
+ */
+ private final Item m_CompareTo;
+
+ /**
+ * before
+ */
+ private final boolean m_Before;
+
+ public DropZoneController(Album a_Album, HTML a_DropZone, Item a_CompareTo, boolean a_Before){
+ m_Album = a_Album;
+ m_DropZone = a_DropZone;
+ m_CompareTo = a_CompareTo;
+ m_Before = a_Before;
+ }
+
+ @Override
+ public Widget getDropTarget() {
+ // TODO Auto-generated method stub
+ return m_DropZone;
+ }
+
+ @Override
+ public void onDrop(DragContext context) {
+
+ JSONArray jsa = new JSONArray();
+
+ int i = 0;
+ for (Widget widget : context.selectedWidgets){
+ if (widget instanceof Item){
+ jsa.set(i, new JSONNumber(((Item)widget).getID()));
+ i++;
+ }
+ }
+ m_Album.rearrangeTo(jsa, m_CompareTo, m_Before);
+
+ }
+
+ @Override
+ public void onEnter(DragContext context) {
+ m_DropZone.addStyleName("drop-target");
+
+ }
+
+ @Override
+ public void onLeave(DragContext context) {
+ // TODO Auto-generated method stub
+ m_DropZone.removeStyleName("drop-target");
+ }
+
+ @Override
+ public void onMove(DragContext context) {
+
+ }
+
+ @Override
+ public void onPreviewDrop(DragContext context) throws VetoDragException {
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/G3Viewer.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/G3Viewer.java
new file mode 100644
index 00000000..a05f1f8c
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/G3Viewer.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.gloopics.g3viewer.client;
+
+
+import com.allen_sauer.gwt.dnd.client.PickupDragController;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HorizontalSplitPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+
+/**
+ * Class that acts as a client to a JSON service. Currently, this client just
+ * requests a text which contains a JSON encoding of a search result set from
+ * yahoo. We use a text file to demonstrate how the pieces work without tripping
+ * on cross-site scripting issues.
+ *
+ * If you would like to make this a more dynamic example, you can associate a
+ * servlet with this example and simply have it hit the yahoo service and return
+ * the results.
+ */
+public class G3Viewer {
+
+ private static String m_CSRF = null;
+
+ private static class ErrorDialog extends DialogBox
+ {
+
+ public ErrorDialog(String error) {
+ // Set the dialog box's caption.
+ setText("Error");
+
+ DockPanel dp = new DockPanel();
+ dp.addStyleName("error");
+ dp.add(new HTML(error), DockPanel.CENTER);
+
+
+ // DialogBox is a SimplePanel, so you have to set its widget property to
+ // whatever you want its contents to be.
+ Button ok = new Button("OK");
+ ok.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ ErrorDialog.this.hide();
+ }
+ });
+
+ dp.add(ok, DockPanel.NORTH);
+
+ setWidget(dp);
+ }
+ }
+
+ /*
+ * BASE url
+ */
+ private static String BASE_URL =
+ ((InputElement)Document.get().getElementById
+ ("baseurl")).getValue();
+
+ /*
+ * url to view album
+ */
+ public static final String VIEW_ALBUM_URL = BASE_URL + "index.php/json_album/albums/";
+
+ /*
+ * url to view album
+ */
+ public static final String MOVE_TO_ALBUM_URL = BASE_URL + "index.php/json_album/move_to/";
+
+ /*
+ * url to view album
+ */
+ public static final String VIEW_CHILDREN_URL = BASE_URL + "index.php/json_album/children/";
+
+ /*
+ * Load Item
+ */
+ public static final String VIEW_ITEM_URL = BASE_URL + "index.php/json_album/item/";
+
+ /**
+ * upload url
+ */
+ public static final String UPLOAD_URL = BASE_URL + "index.php/json_album/add_photo/";
+
+ /**
+ * upload url
+ */
+ public static final String REARRANGE_URL = BASE_URL + "index.php/json_album/rearrange/";
+
+ /**
+ * upload url
+ */
+ public static final String IS_ADMIN_URL = BASE_URL + "index.php/json_album/is_admin/";
+
+ /**
+ * upload url
+ */
+ public static final String MAKE_ALBUM_COVER_URL = BASE_URL + "index.php/json_album/make_album_cover/";
+
+ /**
+ * rotate url
+ */
+ public static final String ROTATE_URL = BASE_URL + "index.php/json_album/rotate/";
+
+ /*
+ * tree
+ */
+ private final AlbumTree m_Tree;
+
+ /**
+ * the only image dialog box
+ */
+ private final ImageDialogBox m_ImageDialogBox = new ImageDialogBox();
+
+ /**
+ * the only dialog box
+ */
+ private final HttpDialogBox m_HttpDialogBox= new HttpDialogBox();
+
+ private class SimplePanelEx extends SimplePanel
+ {
+ public SimplePanelEx()
+ {
+ super();
+ sinkEvents(Event.ONMOUSEUP | Event.ONMOUSEDOWN | Event.ONCONTEXTMENU);
+
+ }
+
+ public void onBrowserEvent(Event event) {
+
+
+ switch (DOM.eventGetType(event)) {
+
+ case Event.ONMOUSEUP:
+ if (DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
+ event.preventDefault();
+ break;
+
+ }
+ else
+ {
+ super.onBrowserEvent(event);
+ }
+ break;
+
+ case Event.ONMOUSEDOWN:
+ if (DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
+ event.preventDefault();
+ break;
+
+ }
+ else
+ {
+ super.onBrowserEvent(event);
+ }
+ break;
+
+ case Event.ONCONTEXTMENU:
+ event.preventDefault();
+ m_Tree.popupMenu(event);
+ //GWT.log("Event.ONCONTEXTMENU", null);
+ break;
+
+ default:
+ super.onBrowserEvent(event);
+ }//end switch
+ }
+
+ }
+
+ /**
+ * central split panel
+ */
+ private final HorizontalSplitPanel m_SplitPanel = new HorizontalSplitPanel();
+
+
+ /**
+ * Grid View
+ */
+ private final View m_View = new View(this);
+
+ /**
+ * the drag controller
+ */
+ private final PickupDragController m_DragController;
+
+ /**
+ * constructor
+ */
+
+ public G3Viewer(){
+ m_DragController = new PickupDragController(RootPanel.get(),false);
+ m_DragController.setBehaviorMultipleSelection(true);
+ m_DragController.setBehaviorDragStartSensitivity(5);
+ m_DragController.setBehaviorDragProxy(true);
+
+ m_Tree = new AlbumTree(this);
+
+ checkAdmin();
+ }
+
+ public static String getCSRF()
+ {
+ return m_CSRF;
+ }
+
+ private void checkAdmin(){
+
+ doJSONRequest(IS_ADMIN_URL, new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ JSONObject jso = aValue.isObject();
+ if (jso != null){
+ JSONString jss = jso.get("result").isString();
+ if (jss != null){
+ if (jss.stringValue().equals("success"))
+ {
+
+ m_CSRF = (jso.get("csrf").isString()).stringValue();
+ m_Tree.fetchTree();
+ return;
+ }
+ }
+ }
+
+ doDialog("index.php/login/ajax", new HttpDialogHandler() {
+
+ @Override
+ public void success(String aResult) {
+ // recheck admin
+ checkAdmin();
+
+ }
+ });
+ }
+ },false);
+ }
+
+
+
+ /**
+ * Entry point for this simple application. Currently, we build the
+ * application's form and wait for events.
+ */
+ public void onModuleLoad() {
+ initializeMainForm();
+ }
+
+ public static void displayError(String errorType, String errorMessage) {
+ new ErrorDialog(errorType + "\n" + errorMessage).show();
+ }
+
+ /**
+ * returns the drag controller
+ */
+ public PickupDragController getDragController(){
+ return m_DragController;
+ }
+
+ public AlbumTree getTree(){
+ return m_Tree;
+ }
+
+ public View getView(){
+ return m_View;
+ }
+
+
+
+ public void doDialog(String a_Url, HttpDialogHandler a_Handler)
+ {
+ m_HttpDialogBox.doDialog(BASE_URL + a_Url, a_Handler);
+ }
+
+ public void showImage(String a_Url)
+ {
+ m_ImageDialogBox.doDialog( a_Url);
+ }
+
+ public void doJSONRequest(final String a_URL, final HttpSuccessHandler a_Handler, final boolean a_hasParams){
+ try {
+ String url;
+ if (m_CSRF != null)
+ {
+ url = a_URL + (a_hasParams?"&csrf=":"?csrf=") + m_CSRF;
+ }
+ else
+ {
+ url = a_URL;
+ }
+ RequestBuilder requestBuilder = new RequestBuilder(
+ RequestBuilder.GET, url);
+ requestBuilder.setCallback(new JSONResponseTextHandler(
+ new JSONResponseCallback() {
+
+ @Override
+ public void onResponse(JSONValue aValue) {
+ a_Handler.success(aValue);
+ }
+
+ @Override
+ public void onError(Throwable aThrowable) {
+ displayError("Unexpected Error",
+ aThrowable.toString() + " - " + a_URL);
+ }}
+ ));
+
+ requestBuilder.send();
+ } catch (RequestException ex) {
+ displayError("Request Exception", ex.toString() + " - " + a_URL);
+ }
+ }
+
+ /**
+ * Initialize the main form's layout and content.
+ */
+ private void initializeMainForm() {
+
+ m_View.addStyleName("view");
+
+ m_Tree.setVisible(true);
+
+ m_SplitPanel.setSplitPosition("20%");
+
+ m_SplitPanel.setLeftWidget(m_Tree);
+
+ m_SplitPanel.setRightWidget(m_View);
+
+ SimplePanel sp = new SimplePanelEx();
+ sp.add(m_SplitPanel);
+
+ RootPanel.get("main").add(sp);
+ }
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogBox.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogBox.java
new file mode 100644
index 00000000..8c61e9cd
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogBox.java
@@ -0,0 +1,169 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.RequestTimeoutException;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
+import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
+
+public class HttpDialogBox extends DialogBox{
+
+ private FormPanel m_FormPanel = null;
+
+ private HttpDialogHandler m_Callback;
+
+ private final HTML m_Dialog;
+
+ public HttpDialogBox(){
+ m_Dialog = new HTML("Empty");
+ initComponents();
+ }
+
+ public void initComponents(){
+ setModal(true);
+ addStyleName("dialog");
+ setAnimationEnabled(true);
+ setText("Dialog");
+
+ Button close = new Button("Cancel", new ClickHandler() {
+
+ public void onClick(ClickEvent event) {
+ HttpDialogBox.this.hide();
+ Loading.getInstance().endLoading();
+
+ }
+ });
+
+
+ Button ok = new Button("ok", new ClickHandler() {
+
+ public void onClick(ClickEvent event) {
+ if (m_FormPanel!=null)
+ {
+ m_FormPanel.submit();
+ }
+ else
+ {
+
+ }
+ HttpDialogBox.this.hide();
+ Loading.getInstance().loading();
+ }
+ });
+
+ FlowPanel fp = new FlowPanel();
+ fp.add(ok);
+ fp.add(close);
+ fp.addStyleName("dButtons");
+ DockPanel dp = new DockPanel();
+ dp.add(m_Dialog , DockPanel.CENTER);
+ dp.add(fp, DockPanel.SOUTH);
+ dp.addStyleName("dContents");
+ add(dp);
+
+ }
+
+ private class RequestCallbackImpl implements RequestCallback {
+
+ private static final int STATUS_CODE_OK = 200;
+
+ private final String m_URL;
+
+ public RequestCallbackImpl(String a_URL){
+ m_URL = a_URL;
+ }
+
+ public void onError(Request request, Throwable exception) {
+ if (exception instanceof RequestTimeoutException) {
+ // handle a request timeout
+ } else {
+ // handle other request errors
+ }
+ showDialog("Could not get " + m_URL + " Exception thrown " + exception.toString());
+ }
+
+ public void onResponseReceived(Request request, Response response) {
+ if (STATUS_CODE_OK == response.getStatusCode()) {
+ showDialog(response.getText());
+ } else {
+ showDialog(m_URL + response.getText());
+ // handle non-OK response from the server
+ }
+ }
+ }
+
+ private void showDialog(String a_Text){
+
+ m_Dialog.setHTML(a_Text);
+
+ // hide all submits
+ NodeList inputs = this.getElement().getElementsByTagName("input");
+ Element input;
+ for (int i = 0; i < inputs.getLength(); i++){
+ input = inputs.getItem(i);
+
+ if (input.getAttribute("type").equals("submit"))
+ {
+ input.setAttribute("style", "display:none");
+ }
+ }
+
+ Loading.getInstance().hideAnimation();
+ show();
+
+ // find forms if it exists
+ NodeList forms = this.getElement().getElementsByTagName("form");
+ if (forms.getLength() > 0)
+ {
+ Element element = this.getElement().getElementsByTagName("form").getItem(0);
+ setText(element.getElementsByTagName("legend").getItem(0).getInnerText());
+
+
+ m_FormPanel = FormPanel.wrap(element, true);
+ m_FormPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
+
+ @Override
+ public void onSubmitComplete(SubmitCompleteEvent event) {
+ m_Callback.success(event.getResults());
+ Loading.getInstance().endLoading();
+ }
+ });
+
+ }
+ else
+ {
+ setText(this.getElement().getElementsByTagName("legend").getItem(0).getInnerText());
+ }
+
+ setPopupPosition(Window.getClientWidth() / 2 - this.getOffsetWidth() / 2,
+ Window.getClientHeight() / 2 - this.getOffsetHeight() / 2);
+ }
+
+ public void doDialog(String url, HttpDialogHandler a_Callback){
+ m_Callback = a_Callback;
+ Loading.getInstance().loading();
+ RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
+
+ try {
+ builder.sendRequest(null, new RequestCallbackImpl(url));
+ } catch (RequestException e) {
+ showDialog("Could not call " + url + " Exception thrown " + e.toString());
+ }
+ }
+
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogHandler.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogHandler.java
new file mode 100644
index 00000000..691ba9b2
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpDialogHandler.java
@@ -0,0 +1,7 @@
+package com.gloopics.g3viewer.client;
+
+
+public interface HttpDialogHandler {
+
+ public void success(String a_Result);
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpSuccessHandler.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpSuccessHandler.java
new file mode 100644
index 00000000..6fe3a1f2
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/HttpSuccessHandler.java
@@ -0,0 +1,7 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.json.client.JSONValue;
+
+public interface HttpSuccessHandler {
+ public void success(JSONValue a_Value);
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/ImageDialogBox.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/ImageDialogBox.java
new file mode 100644
index 00000000..49dda06a
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/ImageDialogBox.java
@@ -0,0 +1,94 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.ErrorEvent;
+import com.google.gwt.event.dom.client.ErrorHandler;
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+
+public class ImageDialogBox extends PopupPanel{
+
+ private Image m_Image = null;
+
+ public ImageDialogBox(){
+ initComponents();
+ }
+
+
+ private void initComponents()
+ {
+ setModal(true);
+ addStyleName("dialog");
+ setAnimationEnabled(true);
+
+ addDomHandler(new ClickHandler() {
+
+ @Override
+ public void onClick(ClickEvent event) {
+ ImageDialogBox.this.hide();
+
+ Loading.getInstance().endLoading();
+ }
+
+ } ,ClickEvent.getType());
+
+ }
+
+ public void doDialog(String a_Image){
+
+ Loading.getInstance().loading();
+
+ if (m_Image != null){
+ m_Image.removeFromParent();
+ }
+
+ m_Image = new Image();
+ final SimplePanel sp = new SimplePanel();
+ m_Image.addLoadHandler(new LoadHandler() {
+
+ @Override
+ public void onLoad(LoadEvent event) {
+ sp.removeFromParent();
+
+ Loading.getInstance().hideAnimation();
+
+ add(m_Image);
+ show();
+
+ setPopupPosition(Window.getClientWidth() / 2 - getOffsetWidth() / 2,
+ Window.getClientHeight() / 2 - getOffsetHeight() / 2);
+
+
+
+
+
+ }
+ });
+ m_Image.addErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void onError(ErrorEvent event) {
+ sp.removeFromParent();
+ G3Viewer.displayError("Error Loading Image", "It could be that the resized version of the image has not been built correctly.");
+ Loading.getInstance().endLoading();
+ }
+ });
+
+ sp.setSize("0px", "0px");
+ sp.setStylePrimaryName("hideme");
+ sp.setWidget(m_Image);
+ RootPanel.get().add(sp);
+
+ m_Image.setUrl(a_Image);
+
+ }
+
+
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/Item.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Item.java
new file mode 100644
index 00000000..c2c5744c
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Item.java
@@ -0,0 +1,338 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.event.dom.client.ContextMenuHandler;
+import com.google.gwt.event.dom.client.DoubleClickEvent;
+import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.HasAllMouseHandlers;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.MouseOutEvent;
+import com.google.gwt.event.dom.client.MouseOutHandler;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.event.dom.client.MouseOverHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.event.dom.client.MouseWheelEvent;
+import com.google.gwt.event.dom.client.MouseWheelHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+public class Item extends Composite implements HasAllMouseHandlers{
+
+ private final int m_ID;
+
+ private String m_Title;
+
+ private String m_Thumb;
+
+ private String m_Resized;
+
+ private final String m_Type;
+
+ private final Album m_Parent;
+
+ private Album m_LinkedAlbum = null;
+
+ private final G3Viewer m_Container;
+
+ private final boolean m_IsAlbum;
+
+ private final boolean m_IsPhoto;
+
+ private final View m_View;
+
+ private AlbumItemDropContainer m_DropContainer = null;
+
+ private final Image m_ThumbImage;
+ private final Label m_TitleLabel;
+
+ public Item(Album a_Parent, JSONObject a_Value, G3Viewer a_Container){
+ m_Container = a_Container;
+ m_View = a_Container.getView();
+ m_Parent = a_Parent;
+ m_ID = (int)((JSONNumber)a_Value.get("id")).doubleValue();
+ m_Title = ((JSONString)a_Value.get("title")).stringValue();
+ m_Thumb = ((JSONString)a_Value.get("thumb")).stringValue();
+ m_Type = ((JSONString)a_Value.get("type")).stringValue();
+ m_Resized = ((JSONString)a_Value.get("resize")).stringValue();
+ m_IsAlbum = m_Type.equals("album");
+ m_IsPhoto = m_Type.equals("photo");
+ FlowPanel dp = new FlowPanel();
+
+ m_ThumbImage = new Image(m_Thumb);
+ dp.add(m_ThumbImage);
+
+ m_TitleLabel = new Label(m_Title);
+ dp.add(m_TitleLabel);
+
+ initWidget(dp);
+
+ this.setStylePrimaryName("item");
+ this.addStyleName("i" + m_Type);
+
+ addDomHandler(new ContextMenuHandler() {
+
+ @Override
+ public void onContextMenu(ContextMenuEvent event) {
+ showPopupMenu(event);
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }, ContextMenuEvent.getType());
+
+ addDomHandler(new DoubleClickHandler() {
+
+ @Override
+ public void onDoubleClick(DoubleClickEvent event) {
+ if (isAlbum()){
+ m_Parent.selectSubAlbum(m_ID);
+ }
+ else if (isPhoto()){
+ m_Container.showImage(m_Resized);
+ }
+
+ }
+ },DoubleClickEvent.getType());
+
+ a_Container.getDragController().makeDraggable(this);
+
+ }
+
+ public void showing(){
+ if (isAlbum() && m_LinkedAlbum != null){
+ m_DropContainer = new AlbumItemDropContainer(this, m_LinkedAlbum);
+ m_Container.getDragController().registerDropController(
+ m_DropContainer);
+ }
+ }
+
+ public void hidding(){
+ if (m_DropContainer != null){
+ m_Container.getDragController().unregisterDropController(m_DropContainer);
+ }
+ }
+
+ public void updateValues(JSONValue aValue){
+ JSONObject jso = aValue.isObject();
+
+ if (jso != null) {
+ m_Title = ((JSONString)jso.get("title")).stringValue();
+ m_Thumb = ((JSONString)jso.get("thumb")).stringValue();
+ m_Resized = ((JSONString)jso.get("resize")).stringValue();
+ if (m_LinkedAlbum != null){
+ m_LinkedAlbum.updateValues(jso);
+ }
+
+ m_TitleLabel.setText(m_Title);
+ m_ThumbImage.setUrl(m_Thumb);
+ }
+ }
+
+ private void updateImages(JSONValue a_Value){
+ JSONObject jso = a_Value.isObject();
+
+ if (jso != null) {
+ m_Thumb = ((JSONString)jso.get("thumb")).stringValue();
+ m_ThumbImage.setUrl(m_Thumb);
+ m_Resized = ((JSONString)jso.get("resize")).stringValue();
+ }
+
+ }
+
+ public void refresh(){
+
+ m_Container.doJSONRequest(G3Viewer.VIEW_ITEM_URL + getID(),
+ new HttpSuccessHandler() {
+
+ @Override
+ public void success(JSONValue aValue) {
+ updateValues(aValue);
+ }
+ },false);
+
+ }
+
+ public void setLinkedAlbum(Album a_Album){
+ m_LinkedAlbum = a_Album;
+ }
+
+ public void showPopupMenu(ContextMenuEvent event){
+ this.addStyleName("popped");
+ final PopupPanel popupPanel = new PopupPanel(true);
+ popupPanel.setAnimationEnabled(true);
+ popupPanel.setStyleName("popup");
+ MenuBar popupMenuBar = new MenuBar(true);
+
+ MenuItem deleteItem = new MenuItem("Delete " + m_Type, true, new Command() {
+
+ @Override
+ public void execute() {
+ m_Container.doDialog("index.php/quick/form_delete/" + m_ID, new HttpDialogHandler() {
+ public void success(String aResult) {
+ m_View.removeFromView(Item.this);
+ if (m_LinkedAlbum != null){
+ m_LinkedAlbum.remove();
+ }
+ }
+ });
+ popupPanel.hide();
+
+ }
+ });
+ deleteItem.addStyleName("popup-item");
+ popupMenuBar.addItem(deleteItem);
+
+ MenuItem editItem = new MenuItem("Edit " + m_Type, true, new Command() {
+
+ @Override
+ public void execute() {
+ m_Container.doDialog("index.php/form/edit/" + m_Type + "s/" + m_ID,
+ new HttpDialogHandler() {
+ public void success(String aResult) {
+ refresh();
+ }
+ });
+ popupPanel.hide();
+
+ }
+ });
+ editItem.addStyleName("popup-item");
+ popupMenuBar.addItem(editItem);
+
+ MenuItem albumCover = new MenuItem("Make Album Cover", true, new Command() {
+
+ @Override
+ public void execute() {
+ m_Container.doJSONRequest(G3Viewer.MAKE_ALBUM_COVER_URL + m_ID, new HttpSuccessHandler() {
+
+ public void success(JSONValue aValue) {
+ // nothing to do
+ }
+ },false);
+ popupPanel.hide();
+ }
+ });
+ albumCover.addStyleName("popup-item");
+ popupMenuBar.addItem(albumCover);
+
+ if (isPhoto())
+ {
+ MenuItem rotateCW = new MenuItem("Rotate Clockwise", true, new Command() {
+ @Override
+ public void execute() {
+ m_ThumbImage.setUrl(Loading.URL);
+ m_Container.doJSONRequest(G3Viewer.ROTATE_URL + m_ID + "/cw", new HttpSuccessHandler() {
+
+ public void success(JSONValue aValue) {
+ updateImages(aValue);
+ }
+ },false);
+ popupPanel.hide();
+ }
+ });
+ rotateCW.addStyleName("popup-item");
+ popupMenuBar.addItem(rotateCW);
+
+ MenuItem rotateCCW = new MenuItem("Rotate Couter-Clockwise", true, new Command() {
+ @Override
+ public void execute() {
+ m_ThumbImage.setUrl(Loading.URL);
+ m_Container.doJSONRequest(G3Viewer.ROTATE_URL + m_ID + "/ccw", new HttpSuccessHandler() {
+
+ public void success(JSONValue aValue) {
+ updateImages(aValue);
+ }
+ },false);
+ popupPanel.hide();
+ }
+ });
+ rotateCCW.addStyleName("popup-item");
+ popupMenuBar.addItem(rotateCCW);
+ }
+
+
+
+ popupMenuBar.setVisible(true);
+ popupPanel.add(popupMenuBar);
+
+ int x = DOM.eventGetClientX((Event)event.getNativeEvent());
+ int y = DOM.eventGetClientY((Event)event.getNativeEvent());
+ popupPanel.setPopupPosition(x, y);
+ popupPanel.addCloseHandler(new CloseHandler() {
+
+ @Override
+ public void onClose(CloseEvent event) {
+
+ Item.this.removeStyleName("popped");
+ }
+ });
+
+ popupPanel.show();
+ }
+
+
+ public boolean isAlbum(){
+ return m_IsAlbum;
+ }
+
+ public boolean isPhoto(){
+ return m_IsPhoto;
+ }
+
+ public int getID()
+ {
+ return m_ID;
+ }
+
+ @Override
+ public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
+ return addDomHandler(handler, MouseDownEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
+ return addDomHandler(handler, MouseUpEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
+ return addDomHandler(handler, MouseOutEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
+ return addDomHandler(handler, MouseOverEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
+ return addDomHandler(handler, MouseMoveEvent.getType());
+ }
+
+ @Override
+ public HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) {
+ return addDomHandler(handler, MouseWheelEvent.getType());
+ }
+
+
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseCallback.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseCallback.java
new file mode 100644
index 00000000..f1684a49
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseCallback.java
@@ -0,0 +1,9 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.json.client.JSONValue;
+
+public interface JSONResponseCallback {
+ void onError(Throwable a_Throwable);
+
+ void onResponse(JSONValue a_Value);
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseTextHandler.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseTextHandler.java
new file mode 100644
index 00000000..fdcdb652
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/JSONResponseTextHandler.java
@@ -0,0 +1,34 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.json.client.JSONException;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONValue;
+
+public class JSONResponseTextHandler implements RequestCallback
+{
+ private final JSONResponseCallback m_Callback;
+
+ public JSONResponseTextHandler(JSONResponseCallback a_Callback){
+ m_Callback = a_Callback;
+ }
+
+ public void onError(Request request, Throwable exception) {
+ m_Callback.onError(exception);
+ }
+
+ public void onResponseReceived(Request request, Response response) {
+ //response.
+ String responseText = response.getText();
+ try {
+ JSONValue jsonValue = JSONParser.parse(responseText);
+ m_Callback.onResponse(jsonValue);
+ } catch (JSONException e) {
+ m_Callback.onError(new Throwable(response.getText(), e));
+ }catch (Exception e) {
+ m_Callback.onError(new Throwable(response.getText() + e.toString(), e));
+ }
+ }
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/Loading.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Loading.java
new file mode 100644
index 00000000..9d7fead4
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/Loading.java
@@ -0,0 +1,54 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.AbsolutePanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.RootPanel;
+
+public class Loading extends AbsolutePanel{
+
+ private static final Loading INSTANCE = new Loading();
+
+ public static final String URL = "images/loading.gif";
+
+ /**
+ * the image widget
+ */
+ private Image m_Image = new Image("images/loading.gif");
+
+ private Loading(){
+ HTML back = new HTML();
+ back.addStyleName("loading");
+ add(back, 0, 0);
+ Image.prefetch(URL);
+ }
+
+ /**
+ * get instance
+ */
+ public static Loading getInstance(){
+ return INSTANCE;
+ }
+
+ public void loading(){
+ int width = RootPanel.get().getOffsetWidth();
+ int height = RootPanel.get().getOffsetHeight();
+ height = height / 2 - 25;
+ width = width / 2 - 25;
+ add(m_Image);
+ this.setWidgetPosition(m_Image, width, height);
+ RootPanel.get().add(this);
+ }
+
+ public void endLoading(){
+ if (m_Image.isAttached()){
+ remove(m_Image);
+ }
+ RootPanel.get().remove(this);
+ }
+
+ public void hideAnimation(){
+ remove(m_Image);
+ }
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/NoGears.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/NoGears.java
new file mode 100644
index 00000000..04fdfecb
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/NoGears.java
@@ -0,0 +1,13 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.RootPanel;
+
+public class NoGears implements EntryPoint {
+ public void onModuleLoad() {
+ RootPanel rootPanel = RootPanel.get("main");
+ rootPanel.add(new HTML(
+ "This application requires Google Gears. To install please visit gears.google.com and follow the installation instructions. "));
+ }
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/UploadFile.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/UploadFile.java
new file mode 100644
index 00000000..1d858d44
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/UploadFile.java
@@ -0,0 +1,94 @@
+package com.gloopics.g3viewer.client;
+
+import com.google.gwt.user.client.ui.AbsolutePanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.gears.client.Factory;
+import com.google.gwt.gears.client.desktop.File;
+import com.google.gwt.gears.client.httprequest.HttpRequest;
+import com.google.gwt.gears.client.httprequest.ProgressEvent;
+import com.google.gwt.gears.client.httprequest.ProgressHandler;
+import com.google.gwt.gears.client.httprequest.RequestCallback;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONValue;
+
+public class UploadFile extends AbsolutePanel{
+
+ private class ProgressBar extends SimplePanel{
+ private final SimplePanel m_ProgressInner;
+ public ProgressBar(){
+ addStyleName("progressBar");
+ m_ProgressInner = new SimplePanel();
+ m_ProgressInner.addStyleName("progessInner");
+ add(m_ProgressInner);
+ }
+
+ public void setProgress(int a_Percent){
+ m_ProgressInner.setWidth( a_Percent + "%");
+
+ }
+ }
+
+ private final File m_LocalFile;
+
+ private final String m_Name;
+
+ private final Album m_Parent;
+
+ //private final Label m_PendingLabel = new Label("Upload Pending");
+ private final ProgressBar m_ProgressBar = new ProgressBar();
+
+ public UploadFile(Album a_Parent, File a_File){
+ m_Parent = a_Parent;
+ m_LocalFile = a_File;
+ m_Name = a_File.getName();
+ Label name = new Label(m_Name);
+ name.addStyleName("label");
+ add(name,5,20);
+
+ add(m_ProgressBar,0,80);
+ setStylePrimaryName("item");
+ addStyleName("iUpload");
+
+ }
+
+ public void startUpload(){
+ HttpRequest request = Factory.getInstance().createHttpRequest();
+ request.open("POST", G3Viewer.UPLOAD_URL + m_Parent.getId() + "?filename="
+ + m_Name + "&csrf=" + G3Viewer.getCSRF());
+ //request.setRequestHeader("Content-Type", "image/jpg");
+ //request.setRequestHeader("Content-Type", "image/jpg");
+
+ request.getUpload().setProgressHandler(new ProgressHandler() {
+
+ @Override
+ public void onProgress(ProgressEvent event) {
+ double pcnt = ((double) event.getLoaded() / event.getTotal());
+ m_ProgressBar.setProgress((int) Math.floor(pcnt * 100));
+
+ }
+ });
+
+ request.setCallback(new RequestCallback() {
+
+ @Override
+ public void onResponseReceived(HttpRequest request) {
+
+ if (request.getStatus() != 200)
+ {
+ G3Viewer.displayError("Upload Error", request.getResponseText() + request.getStatus() + request.getStatusText());
+ }
+ try{
+ JSONValue jv = JSONParser.parse(request.getResponseText());
+ m_Parent.finishedUpload(UploadFile.this, jv);
+ } catch (Exception e)
+ {
+ G3Viewer.displayError("Exception on Upload", e.toString() + " " + request.getResponseText());
+ }
+ }
+ });
+
+ request.send(m_LocalFile.getBlob());
+ }
+
+}
diff --git a/modules/gwtorganise/src/com/gloopics/g3viewer/client/View.java b/modules/gwtorganise/src/com/gloopics/g3viewer/client/View.java
new file mode 100644
index 00000000..602db116
--- /dev/null
+++ b/modules/gwtorganise/src/com/gloopics/g3viewer/client/View.java
@@ -0,0 +1,98 @@
+package com.gloopics.g3viewer.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+
+public class View extends FlowPanel{
+
+ /**
+ * the current album being viewed
+ */
+ private Album m_Album;
+
+ /**
+ * the list of drop zones
+ */
+ private final List m_DropZones
+ = new ArrayList();
+
+ private final G3Viewer m_Container;
+
+ public View(G3Viewer a_Container){
+ m_Container = a_Container;
+ }
+
+ private void clearView(){
+ if (m_DropZones.size() > 0){
+ for (DropZoneController dropController : m_DropZones){
+ m_Container.getDragController().unregisterDropController(dropController);
+ }
+ m_DropZones.clear();
+ }
+
+ for (Widget widget : getChildren()){
+ if (widget instanceof Item){
+ ((Item)widget).hidding();
+ }
+ }
+ clear();
+ }
+
+ public void setAlbum(Album a_Album){
+
+ clearView();
+ m_Album = a_Album;
+ Item last = null;
+ for (Item item : a_Album.getItems())
+ {
+ if (a_Album.isManualSort()){
+ addDropZone(a_Album, item, true);
+ }
+
+ addToView(item);
+
+ item.showing();
+
+ last = item;
+ }
+ if (a_Album.isManualSort() && (last != null)){
+ addDropZone(a_Album, last, false);
+ }
+
+ Loading.getInstance().endLoading();
+
+ }
+
+ private void addDropZone(Album a_Parent,Item a_CompareTo, boolean a_Before){
+ HTML drop = new HTML();
+ drop.addStyleName("DropZone");
+ DropZoneController dzp = new DropZoneController(a_Parent, drop, a_CompareTo, a_Before);
+ m_Container.getDragController().registerDropController(dzp);
+ m_DropZones.add(dzp);
+ addToView(drop);
+ }
+
+ public void addToView(Widget a_Widget){
+ add(a_Widget);
+ }
+
+ public void replaceInView(UploadFile a_Remove, Item a_Insert){
+ int index = getWidgetIndex(a_Remove);
+ insert(a_Insert, index);
+ remove(a_Remove);
+ }
+
+ public void removeFromView(Widget a_Widget){
+ remove(a_Widget);
+ }
+
+ public Album getCurrentAlbum(){
+ return m_Album;
+ }
+
+
+}
diff --git a/modules/gwtorganise/src/log4j.properties b/modules/gwtorganise/src/log4j.properties
new file mode 100644
index 00000000..d9c3edc9
--- /dev/null
+++ b/modules/gwtorganise/src/log4j.properties
@@ -0,0 +1,24 @@
+# A default log4j configuration for log4j users.
+#
+# To use this configuration, deploy it into your application's WEB-INF/classes
+# directory. You are also encouraged to edit it as you like.
+
+# Configure the console as our one appender
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
+
+# tighten logging on the DataNucleus Categories
+log4j.category.DataNucleus.JDO=WARN, A1
+log4j.category.DataNucleus.Persistence=WARN, A1
+log4j.category.DataNucleus.Cache=WARN, A1
+log4j.category.DataNucleus.MetaData=WARN, A1
+log4j.category.DataNucleus.General=WARN, A1
+log4j.category.DataNucleus.Utility=WARN, A1
+log4j.category.DataNucleus.Transaction=WARN, A1
+log4j.category.DataNucleus.Datastore=WARN, A1
+log4j.category.DataNucleus.ClassLoading=WARN, A1
+log4j.category.DataNucleus.Plugin=WARN, A1
+log4j.category.DataNucleus.ValueGeneration=WARN, A1
+log4j.category.DataNucleus.Enhancer=WARN, A1
+log4j.category.DataNucleus.SchemaTool=WARN, A1
diff --git a/modules/gwtorganise/views/gwtorganise_view.html.php b/modules/gwtorganise/views/gwtorganise_view.html.php
new file mode 100644
index 00000000..7f246ec5
--- /dev/null
+++ b/modules/gwtorganise/views/gwtorganise_view.html.php
@@ -0,0 +1,6 @@
+
+ $base = url::base(false, "http");
+ $url = "$base/modules/gwtorganise/war/index.php?url=$base";
+ ?>
+
diff --git a/modules/gwtorganise/war/G3viewer.css b/modules/gwtorganise/war/G3viewer.css
new file mode 100644
index 00000000..622f3c48
--- /dev/null
+++ b/modules/gwtorganise/war/G3viewer.css
@@ -0,0 +1,40 @@
+* {padding:0; margin:0;}
+
+#main {position:relative; width:100%; height:100%}
+
+.error {width:300px; height:200px;}
+
+.item {width:100px; height: 100px; padding:3px; border: 2px solid #FFF; overflow: hidden; float:left; text-align:center; position:relative;margin:3px;}
+.item img{max-width:96px; max-height:76px; *width:96px; *height:76px; border:2px solid #AAA;}
+.item h3{font-size:10px; font-weight:normal; position:absolute; bottom:5px; left:0px; width:100%; text-align:center; padding:0; margin:0;}
+.ialbum {background-color: #e3effb; border: 2px solid #91c0ef; }
+.popped {background-color: #e3effb;}
+.view {padding:3px;}
+.DropZone {height: 100px; width:6px; margin: 0 -3px 0 -3px; padding: 0; float:left; text-align:center; position:relative;}
+
+.loading{position:absolute; top:0px; left:0px; width:100%; height: 100%; background-color:#888; opacity: 0.3; filter: alpha(opacity = 30);}
+
+.gwt-TreeItem-selected .Tree-Album {background-color: #333; color: #FFF;}
+.Tree-Album {padding: 1px;}
+.Tree-Album:hover{text-decoration:underline;}
+.drop-target{background-color: #91c0ef; color: #000;}
+
+.popup {padding: 2px; border: 1px solid #91c0ef;background-color:#FFF}
+
+.dialog fieldset{ border: none; padding: 0px; margin: 0px;}
+.dialog legend{ display: none;}
+.dialog ul {padding:0; margin:0;}
+.dialog ul ul li {float:left;}
+.dialog li {list-style: none; padding:0;margin:0;}
+.dialog form input[type="password"], .dialog form input[type="text"], .dialog form textarea .dialog form select {border: 1px solid #000; padding: 0.2em; display:block; clear: both;}
+.dialog form input[type="password"], .dialog form input[type="text"], .dialog form textarea {width: 100%}
+.dialog form textarea {height: 12em;}
+
+.label {width:90px; text-align:center;}
+.progressBar {border: 1px solid #cccccc; width: 100px; height: 10px;}
+.progessInner {background: #34628c;width: 0px;height: 10px;}
+
+.dContents {padding: 2px 5px 2px 5px;}
+.dButtons {text-align: right}
+
+.hideme {overflow:hidden; width:0; height:0; margin:0; padding:0;}
\ No newline at end of file
diff --git a/modules/gwtorganise/war/WEB-INF/appengine-web.xml b/modules/gwtorganise/war/WEB-INF/appengine-web.xml
new file mode 100644
index 00000000..99223a5a
--- /dev/null
+++ b/modules/gwtorganise/war/WEB-INF/appengine-web.xml
@@ -0,0 +1,11 @@
+
+
+
+ 1
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/gwtorganise/war/WEB-INF/logging.properties b/modules/gwtorganise/war/WEB-INF/logging.properties
new file mode 100644
index 00000000..4a78b7f3
--- /dev/null
+++ b/modules/gwtorganise/war/WEB-INF/logging.properties
@@ -0,0 +1,28 @@
+# A default java.util.logging configuration.
+# (All App Engine logging is through java.util.logging by default).
+#
+# To use this configuration, copy it into your application's WEB-INF
+# folder and add the following to your appengine-web.xml:
+#
+#
+#
+#
+#
+
+# Set the default logging level for all loggers to WARNING
+.level = WARNING
+
+# Set the default logging level for ORM, specifically, to WARNING
+DataNucleus.JDO.level=WARNING
+DataNucleus.Persistence.level=WARNING
+DataNucleus.Cache.level=WARNING
+DataNucleus.MetaData.level=WARNING
+DataNucleus.General.level=WARNING
+DataNucleus.Utility.level=WARNING
+DataNucleus.Transaction.level=WARNING
+DataNucleus.Datastore.level=WARNING
+DataNucleus.ClassLoading.level=WARNING
+DataNucleus.Plugin.level=WARNING
+DataNucleus.ValueGeneration.level=WARNING
+DataNucleus.Enhancer.level=WARNING
+DataNucleus.SchemaTool.level=WARNING
diff --git a/modules/gwtorganise/war/WEB-INF/web.xml b/modules/gwtorganise/war/WEB-INF/web.xml
new file mode 100644
index 00000000..e552dd69
--- /dev/null
+++ b/modules/gwtorganise/war/WEB-INF/web.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ greetServlet
+ com.gloopics.g3viewer.server.GreetingServiceImpl
+
+
+
+ greetServlet
+ /g3viewer/greet
+
+
+
+
+ G3viewer.html
+
+
+
diff --git a/modules/gwtorganise/war/images/loading.gif b/modules/gwtorganise/war/images/loading.gif
new file mode 100644
index 00000000..8f56a82c
Binary files /dev/null and b/modules/gwtorganise/war/images/loading.gif differ
diff --git a/modules/gwtorganise/war/index.php b/modules/gwtorganise/war/index.php
new file mode 100644
index 00000000..965b69cd
--- /dev/null
+++ b/modules/gwtorganise/war/index.php
@@ -0,0 +1,3 @@
+
+ $url = $_REQUEST['url'];
+?>Gallery Administration
diff --git a/modules/keeporiginal/helpers/keeporiginal_event.php b/modules/keeporiginal/helpers/keeporiginal_event.php
index ca7fd91a..81e83e9c 100644
--- a/modules/keeporiginal/helpers/keeporiginal_event.php
+++ b/modules/keeporiginal/helpers/keeporiginal_event.php
@@ -69,6 +69,7 @@ class keeporiginal_event_Core {
// When updating an item, check and see if the file name is being changed.
// If so, check for and modify any corresponding file/folder in
// VARPATH/original/ as well.
+
if ($old->is_photo() || $old->is_album()) {
if ($old->file_path() != $new->file_path()) {
$old_original = VARPATH . "original/" . str_replace(VARPATH . "albums/", "", $old->file_path());
@@ -84,12 +85,26 @@ class keeporiginal_event_Core {
// When moving an item, check and see if a corresponding file exists
// in VARPATH/original/. If so, move that item to a similar directory
// in original as well.
+
if ($item->is_photo() || $item->is_album()) {
$old_item_path = $old_parent->file_path() . "/" . $item->name;
if ($item->file_path() != $old_item_path) {
$old_original = VARPATH . "original/" . str_replace(VARPATH . "albums/", "", $old_item_path);
$new_original = VARPATH . "original/" . str_replace(VARPATH . "albums/", "", $item->file_path());
+
if (file_exists($old_original)) {
+
+ // Make sure the new folder exists, create it if it doesn't.
+ $individual_dirs = split("[/\]", "original/" . str_replace(VARPATH . "albums/", "", $item->file_path()));
+ $new_img_path = VARPATH;
+ for($i = 0; $i < count($individual_dirs)-1; $i++) {
+ $new_img_path = $new_img_path . "/" . $individual_dirs[$i];
+ if(!file_exists($new_img_path)) {
+ @mkdir($new_img_path);
+ }
+ }
+
+ // Move the file to its new location.
@rename($old_original, $new_original);
}
}
diff --git a/themes/3nids/3nids/css/fix-ie.css b/themes/3nids/3nids/css/fix-ie.css
new file mode 100755
index 00000000..eee88c15
--- /dev/null
+++ b/themes/3nids/3nids/css/fix-ie.css
@@ -0,0 +1,37 @@
+/**
+ * Fix display in IE 6, 7
+ */
+
+#gBanner,
+.gBreadcrumbs,
+#gAlbumGrid,
+#gPager,
+#gViewMenu {
+ zoom: 1;
+}
+
+#gBanner {
+ z-index: 2;
+}
+
+input.submit {
+ clear: none !important;
+ display: inline !important;
+}
+
+#gAddTagForm input.textbox {
+ width: 110px;
+}
+
+#gDialog a.gCancel {
+ display: inline-block !important;
+ float: none !important;
+}
+
+.gPager .txtright {
+ width: 29%;
+}
+
+.gPager .ui-icon-right {
+ width: 60px;
+}
diff --git a/themes/3nids/3nids/css/jquery.fancybox.css b/themes/3nids/3nids/css/jquery.fancybox.css
new file mode 100755
index 00000000..4e363e1b
--- /dev/null
+++ b/themes/3nids/3nids/css/jquery.fancybox.css
@@ -0,0 +1,673 @@
+html, body {
+ height: 100%;
+}
+
+div#fancy_overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: black;
+ display: none;
+ z-index: 30;
+}
+
+* html div#fancy_overlay {
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+div#fancy_wrap {
+ text-align: middle;
+}
+
+div#fancy_loading {
+ position: absolute;
+ height: 40px;
+ width: 40px;
+ cursor: pointer;
+ display: none;
+ overflow: hidden;
+ background: transparent;
+ z-index: 100;
+}
+
+div#fancy_loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background: transparent url('../images/fancy_progress.png') no-repeat;
+}
+
+div#fancy_loading_overlay {
+ position: absolute;
+ background-color: #FFF;
+ z-index: 30;
+}
+
+div#fancy_loading_icon {
+ position: absolute;
+ background: url('../images/fancy_loading.gif') no-repeat;
+ z-index: 35;
+ width: 16px;
+ height: 16px;
+}
+
+div#fancy_outer {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 90;
+ padding: 18px 18px 20px 0px;
+ margin: 0;
+ overflow: hidden;
+ background: transparent;
+ display: none;
+}
+
+div#fancy_inner {
+ position: relative;
+ width:100%;
+ height:100%;
+ border: 1px solid #BBB;
+ background: #FFF;
+}
+
+div#fancy_content {
+ margin: 0;
+ z-index: 100;
+ position: absolute;
+}
+
+div#fancy_div {
+ background: #000;
+ color: #FFF;
+ height: 100%;
+ width: 100%;
+ z-index: 100;
+}
+
+img#fancy_img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border:0;
+ padding: 0;
+ margin: 0;
+ z-index: 100;
+ width: 100%;
+ height: 100%;
+}
+
+div#fancy_close {
+ position: absolute;
+ top: -12px;
+ right: -15px;
+ height: 30px;
+ width: 30px;
+ background: url('../images/fancy_closebox.png') top left no-repeat;
+ cursor: pointer;
+ z-index: 181;
+ display: none;
+}
+
+#fancy_frame {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: none;
+}
+
+#fancy_ajax {
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+}
+
+a#fancy_left, a#fancy_right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ z-index: 111;
+ display: none;
+ background-image: url(data:image/gif;base64,AAAA);
+ outline: none;
+}
+
+a#fancy_left {
+ left: 0px;
+}
+
+a#fancy_right {
+ right: 0px;
+}
+
+span.fancy_ico {
+ position: absolute;
+ top: 50%;
+ margin-top: -15px;
+ width: 30px;
+ height: 30px;
+ z-index: 112;
+ cursor: pointer;
+ display: block;
+}
+
+span#fancy_left_ico {
+ left: -9999px;
+ background: transparent url('../images/fancy_left.png') no-repeat;
+}
+
+span#fancy_right_ico {
+ right: -9999px;
+ background: transparent url('../images/fancy_right.png') no-repeat;
+}
+
+a#fancy_left:hover {
+ visibility: visible;
+}
+
+a#fancy_right:hover {
+ visibility: visible;
+}
+
+a#fancy_left:hover span {
+ left: 20px;
+}
+
+a#fancy_right:hover span {
+ right: 20px;
+}
+
+.fancy_bigIframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+}
+
+div#fancy_bg {
+ position: absolute;
+ top: 0; left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 70;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+div.fancy_bg {
+ position: absolute;
+ display: block;
+ z-index: 70;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+div.fancy_bg_n {
+ top: -18px;
+ width: 100%;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_n.png') repeat-x;
+}
+
+div.fancy_bg_ne {
+ top: -18px;
+ right: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_ne.png') no-repeat;
+}
+
+div.fancy_bg_e {
+ right: -13px;
+ height: 100%;
+ width: 13px;
+ background: transparent url('../images/fancy_shadow_e.png') repeat-y;
+}
+
+div.fancy_bg_se {
+ bottom: -18px;
+ right: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_se.png') no-repeat;
+}
+
+div.fancy_bg_s {
+ bottom: -18px;
+ width: 100%;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_s.png') repeat-x;
+}
+
+div.fancy_bg_sw {
+ bottom: -18px;
+ left: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_sw.png') no-repeat;
+}
+
+div.fancy_bg_w {
+ left: -13px;
+ height: 100%;
+ width: 13px;
+ background: transparent url('../images/fancy_shadow_w.png') repeat-y;
+}
+
+div.fancy_bg_nw {
+ top: -18px;
+ left: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_nw.png') no-repeat;
+}
+
+div#fancy_title {
+ position: absolute;
+ bottom: -20px;
+ left: 0;
+ z-index: 100;
+ display: none;
+}
+
+div#fancy_title div {
+ color: #FFF;
+ font: bold 10px Arial;
+ padding-bottom: 3px;
+}
+
+div#fancy_title table {
+ margin: 0 auto;
+}
+
+div#fancy_title table td {
+ padding: 0;
+ vertical-align: middle;
+}
+
+td#fancy_title_left {
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_left.png') repeat-x;
+}
+
+td#fancy_title_main {
+ height: 32px;
+ background: transparent url('../images/fancy_title_main.png') repeat-x;
+}
+
+td#fancy_title_right {
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_right.png') repeat-x;
+}
+
+div#fancy_modules {
+ position: absolute;
+ bottom: -20px;
+ right: 0px;
+ z-index: 100;
+ display: none;
+}
+div#fancy_modules div {
+ color: #FFF;
+ font: bold 10px Arial;
+ padding-bottom: 3px;
+}
+
+div#fancy_modules table {
+ margin: 0 auto;
+}
+
+div#fancy_modules table td {
+ padding: 0;
+ vertical-align: middle;
+}
+
+td#fancy_modules_left {
+ border-color: #333333;
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_left.png') repeat-x;
+}
+
+td#fancy_modules_main {
+ border-color: #333333;
+ height: 32px;
+ background: transparent url('../images/fancy_title_main.png') repeat-x;
+}
+
+td#fancy_modules_right {
+ border-color: #333333;
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_right.png') repeat-x;
+}
+
+/* ************************************************* */
+/* ************************************************* */
+/* ************************************************* */
+/* ************************************************* */
+
+div#mod_overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: black;
+ display: none;
+ z-index: 1030;
+}
+
+* html div#mod_overlay {
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+div#mod_wrap {
+ text-align: middle;
+}
+
+div#mod_loading {
+ position: absolute;
+ height: 40px;
+ width: 40px;
+ cursor: pointer;
+ display: none;
+ overflow: hidden;
+ background: transparent;
+ z-index: 10100;
+}
+
+div#mod_loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background: transparent url('../images/fancy_progress.png') no-repeat;
+}
+
+div#mod_loading_overlay {
+ position: absolute;
+ background-color: #FFF;
+ z-index: 1030;
+}
+
+div#mod_loading_icon {
+ position: absolute;
+ background: url('../images/fancy_loading.gif') no-repeat;
+ z-index: 1035;
+ width: 16px;
+ height: 16px;
+}
+
+div#mod_outer {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1090;
+ padding: 18px 18px 20px 0px;
+ margin: 0;
+ overflow: hidden;
+ background: transparent;
+ display: none;
+}
+
+div#mod_inner {
+ position: relative;
+ width:100%;
+ height:100%;
+ border: 1px solid #BBB;
+ background: #FFF;
+}
+
+div#mod_content {
+ margin: 0;
+ z-index: 10100;
+ position: absolute;
+}
+
+div#mod_div {
+ background: #000;
+ color: #FFF;
+ height: 100%;
+ width: 100%;
+ z-index: 10100;
+}
+
+img#mod_img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border:0;
+ padding: 0;
+ margin: 0;
+ z-index: 10100;
+ width: 100%;
+ height: 100%;
+}
+
+div#mod_close {
+ position: absolute;
+ top: -12px;
+ right: -15px;
+ height: 30px;
+ width: 30px;
+ background: url('../images/fancy_closebox.png') top left no-repeat;
+ cursor: pointer;
+ z-index: 10181;
+ display: none;
+}
+
+#mod_frame {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: none;
+}
+
+#mod_ajax {
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+}
+
+a#mod_left, a#mod_right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ z-index: 10111;
+ display: none;
+ background-image: url(data:image/gif;base64,AAAA);
+ outline: none;
+}
+
+a#mod_left {
+ left: 0px;
+}
+
+a#mod_right {
+ right: 0px;
+}
+
+span.mod_ico {
+ position: absolute;
+ top: 50%;
+ margin-top: -15px;
+ width: 30px;
+ height: 30px;
+ z-index: 10112;
+ cursor: pointer;
+ display: block;
+}
+
+span#mod_left_ico {
+ left: -9999px;
+ background: transparent url('../images/fancy_left.png') no-repeat;
+}
+
+span#mod_right_ico {
+ right: -9999px;
+ background: transparent url('../images/fancy_right.png') no-repeat;
+}
+
+a#mod_left:hover {
+ visibility: visible;
+}
+
+a#mod_right:hover {
+ visibility: visible;
+}
+
+a#mod_left:hover span {
+ left: 20px;
+}
+
+a#mod_right:hover span {
+ right: 20px;
+}
+
+.mod_bigIframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+}
+
+div#mod_bg {
+ position: absolute;
+ top: 0; left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1070;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+div.mod_bg {
+ position: absolute;
+ display: block;
+ z-index: 1070;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+div.mod_bg_n {
+ top: -18px;
+ width: 100%;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_n.png') repeat-x;
+}
+
+div.mod_bg_ne {
+ top: -18px;
+ right: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_ne.png') no-repeat;
+}
+
+div.mod_bg_e {
+ right: -13px;
+ height: 100%;
+ width: 13px;
+ background: transparent url('../images/fancy_shadow_e.png') repeat-y;
+}
+
+div.mod_bg_se {
+ bottom: -18px;
+ right: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_se.png') no-repeat;
+}
+
+div.mod_bg_s {
+ bottom: -18px;
+ width: 100%;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_s.png') repeat-x;
+}
+
+div.mod_bg_sw {
+ bottom: -18px;
+ left: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_sw.png') no-repeat;
+}
+
+div.mod_bg_w {
+ left: -13px;
+ height: 100%;
+ width: 13px;
+ background: transparent url('../images/fancy_shadow_w.png') repeat-y;
+}
+
+div.mod_bg_nw {
+ top: -18px;
+ left: -13px;
+ width: 13px;
+ height: 18px;
+ background: transparent url('../images/fancy_shadow_nw.png') no-repeat;
+}
+
+div#mod_title {
+ position: absolute;
+ bottom: -20px;
+ left: 0;
+ z-index: 10100;
+ display: none;
+}
+
+div#mod_title div {
+ color: #FFF;
+ font: bold 10px Arial;
+ padding-bottom: 3px;
+}
+
+div#mod_title table {
+ margin: 0 auto;
+}
+
+div#mod_title table td {
+ padding: 0;
+ vertical-align: middle;
+}
+
+td#mod_title_left {
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_left.png') repeat-x;
+}
+
+td#mod_title_main {
+ height: 32px;
+ background: transparent url('../images/fancy_title_main.png') repeat-x;
+}
+
+td#mod_title_right {
+ height: 32px;
+ width: 15px;
+ background: transparent url('../images/fancy_title_right.png') repeat-x;
+}
+
diff --git a/themes/3nids/3nids/css/screen.css b/themes/3nids/3nids/css/screen.css
new file mode 100755
index 00000000..c4abf611
--- /dev/null
+++ b/themes/3nids/3nids/css/screen.css
@@ -0,0 +1,1204 @@
+/**
+ * Gallery 3 Default Theme Screen Styles
+ *
+ * @requires YUI reset, font, grids CSS
+ *
+ * Sheet organization:
+ * 1) Basic HTML elements
+ * 2) Reusable classes
+ * 3) Reusable content blocks
+ * 4) Page layout containers
+ * 5) Content blocks in specific layout containers
+ * 6) Navigation and menus
+ * 7) Browser hacks
+ * 8) jQuery and jQuery UI
+ * 9) Right-to-left language styles
+ */
+
+/* 3nids specific */
+.gHeadMap img {
+ display: block;
+ margin: 3px;
+}
+
+.gHeadMap a {
+ float: right;
+}
+
+.gCommentThumb{
+ padding: 5px;
+ text-align: left;
+}
+
+
+/** *******************************************************************
+ * 1) Basic HTML elements
+ **********************************************************************/
+
+body, html {
+ background-color: #ccc;
+ font-family: 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
+ color: #e8e8e8;
+}
+
+.modcontent{
+ background-color: #333333;
+}
+
+#mod_frame{
+ background-color: #333333;
+ }
+
+p {
+ margin-bottom: 1em;
+}
+
+em {
+ font-style: oblique;
+}
+
+h1, h2, h3, h4, h5, strong, th {
+ font-weight: bold;
+}
+
+h1 {
+ font-size: 1.5em;
+}
+
+#gSearchResults h1 {
+ margin-bottom: 1em;
+}
+
+#gProgress h1 {
+ font-size: 1.1em;
+}
+
+h2 {
+ font-size: 1.2em;
+}
+
+#gSidebar .gBlock h2 {
+ font-size: 1.2em;
+}
+
+#gSidebar .gBlock li {
+ margin-bottom: .6em;
+}
+
+h3 {
+ font-size: 1.2em;
+}
+h4 {
+ font-size: 0.9em;
+}
+
+
+/* Links ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+a,
+.gMenu a,
+#gDialog a,
+.gButtonLink,
+.gButtonLink:hover,
+.gButtonLink:active,
+a.ui-state-hover,
+input.ui-state-hover,
+button.ui-state-hover {
+ color: #ffffcc !important;
+ cursor: pointer !important;
+ text-decoration: none;
+ -moz-outline-style: none;
+}
+
+a:hover,
+#gDialog a:hover {
+ text-decoration: underline;
+}
+
+.gMenu a:hover {
+ text-decoration: none;
+}
+
+#gDialog .gCancel {
+ clear: none;
+ float: left;
+ margin: .3em 1em;
+}
+
+#gForgotPasswordLink {
+ float: right;
+ font-size: .9em;
+}
+
+#gDialog .gCancel {
+ float: left;
+}
+
+#gDialog #gMessage li {
+ width: 400px;
+ white-space: normal;
+ padding-left: 32px;
+}
+
+/* Tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+table {
+ width: 100%;
+}
+
+#gContent table {
+ margin: 1em 0;
+}
+
+caption,
+th {
+ text-align: left;
+}
+
+th,
+td {
+ border: none;
+ border-bottom: 1px solid #ccc;
+ padding: .5em;
+ vertical-align: top;
+}
+
+/* Forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+fieldset {
+ border: 1px solid #ccc;
+ padding-bottom: .8em;
+}
+
+#gBanner fieldset,
+#gSidebar fieldset,
+.gShortForm fieldset {
+ border: none;
+}
+
+legend {
+ font-weight: bold;
+ margin-left: 1em;
+ color: #e8e8e8;
+}
+
+#gBanner legend,
+#gSidebar legend,
+#gContent #gSearchForm legend,
+input[type="hidden"],
+.gShortForm label {
+ display: none;
+}
+
+label {
+ cursor: help;
+}
+
+input[type="text"],
+input[type="password"] {
+ width: 50%;
+}
+
+input[type="text"],
+input[type="password"],
+textarea {
+ border: 1px solid #e8e8e8;
+ border-top-color: #ccc;
+ border-left-color: #ccc;
+ color: #333;
+}
+
+textarea {
+ width: 90%;
+ height: 12em;
+}
+
+input:focus,
+textarea:focus,
+option:focus {
+ background-color: #ffc;
+ color: #000;
+}
+
+/* Form layout ~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+form li {
+ margin: 0 !important;
+ padding: .3em 1.5em .3em 1em;
+}
+
+form ul ul {
+ clear: both;
+}
+
+form ul ul li {
+ float: left;
+}
+
+input,
+select,
+textarea {
+ display: block;
+ clear: both;
+ padding: .2em;
+}
+
+input[type="submit"],
+input[type="reset"] {
+ display: inline;
+ clear: none;
+ float: left;
+}
+
+/* Form validation ~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.gValidationRule {
+ font-size: 80%;
+ margin-top: .5em;
+}
+
+form.gError input[type="text"],
+li.gError input[type="text"],
+form.gError input[type="password"],
+li.gError input[type="password"],
+form.gError input[type="checkbox"],
+li.gError input[type="checkbox"],
+form.gError input[type="radio"],
+li.gError input[type="radio"],
+form.gError textarea,
+li.gError textarea,
+form.gError select,
+li.gError select {
+ border: 2px solid red;
+}
+
+/** *******************************************************************
+ * 2) Reusable generic classes
+ *********************************************************************/
+
+.inactive, .understate {
+ color: #ccc;
+ font-weight: normal;
+}
+
+.left {
+ float: left;
+ margin: 1em 1em 1em 0;
+}
+
+.right {
+ float: right;
+ margin: 1em 0 1em 1em;
+}
+
+.txtright {
+ text-align: right;
+}
+
+/** *******************************************************************
+ * 3) Reusable content blocks
+ *********************************************************************/
+
+.gBlock {
+ clear: both;
+ margin-bottom: 2.5em;
+}
+
+.gBlock h2 {
+ background-color: #333333;
+ padding: .3em .8em;
+}
+
+.gBlockContent {
+ margin-top: 1em;
+}
+
+/* Status messages ~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gMessage {
+ width: 100%;
+}
+
+#gSiteStatus li,
+#gMessage li,
+.gModuleStatus {
+ border: 1px solid #ccc;
+ margin-bottom: .4em;
+}
+
+#gSiteStatus li {
+ margin-bottom: 0;
+ border: none;
+ border-bottom: 1px solid #ccc;
+}
+
+.gModuleStatus {
+ clear: both;
+ margin-bottom: 1em;
+}
+
+.gError,
+.gInfo,
+.gSuccess,
+.gWarning {
+ background-position: .4em 50%;
+ background-repeat: no-repeat;
+ padding: .4em .5em .4em 30px;
+}
+
+.gError {
+ background-color: #f6cbca;
+ background-image: url('../images/ico-error.png');
+}
+
+.gInfo {
+ background-color: #e8e8e8;
+ background-image: url('../images/ico-info.png');
+}
+
+.gSuccess {
+ background-color: #d9efc2;
+ background-image: url('../images/ico-success.png');
+}
+
+.gWarning {
+ background-color: #fcf9ce;
+ background-image: url('../images/ico-warning.png');
+}
+
+form .gError,
+.gPager .gInfo {
+ background-color: #333333 !important;
+}
+
+.gPager .gInfo {
+ background-image: none !important;
+ padding: 0 !important;
+}
+
+/* Inline layout (forms, lists) ~~~~~~~~~~ */
+
+.gShortForm li {
+ float: left;
+ padding: .4em 0;
+}
+
+.gShortForm input[type="text"] {
+ color: #666;
+ padding: .3em .6em;
+ width: 11em;
+}
+
+/*** ******************************************************************
+ * 4) Page layout containers
+ *********************************************************************/
+
+/* View container ~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.gView {
+ background-color: #333333;
+ border: 1px solid #e8e8e8;
+ border-bottom: none;
+}
+
+/* Layout containers ~~~~~~~~~~~~~~~~~~~~~ */
+
+#gHeader {
+ margin-bottom: 1em;
+ background-color: #484848;
+ border-bottom: 1px solid #e8e8e8;
+}
+
+#gBanner {
+ background-color: #333333;
+ border-bottom: 1px solid #e8e8e8;
+ font-size: .8em;
+ min-height: 5em;
+ padding: 1em 20px;
+ position: relative;
+}
+
+#gContent {
+ font-size: 1.0em;
+ padding-left: 20px;
+ position: relative;
+ width: 600px;
+}
+
+#gSidebar {
+ background-color: #333333;
+ font-size: .9em;
+ padding: 0 20px;
+ width: 220px;
+}
+
+#gFooter {
+ background-color: #484848;
+ border-top: 1px solid #ccc;
+ font-size: .8em;
+ margin-top: 20px;
+ padding: 10px 20px;
+}
+
+/** *******************************************************************
+ * 5) Content blocks in specific layout containers
+ *********************************************************************/
+
+/* Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gBanner #gLogo img {
+ margin: 0;
+}
+
+#gBanner #gQuickSearchForm {
+ clear: right;
+ float: right;
+ margin-top: 1em;
+}
+
+#gBanner #gQuickSearchForm input[type='text'] {
+ width: 17em;
+}
+
+#gContent .gBlock h2 {
+ background-color: transparent;
+ padding-left: 0;
+}
+
+#gSidebar .gBlockContent {
+ padding-left: 1em;
+}
+
+/* Album content ~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gContent #gAlbumGrid {
+ margin: 1em 0;
+ position: relative;
+ z-index: 1;
+}
+
+#gContent #gAlbumGrid .gItem {
+ background-color: #484848;
+ border: 1px solid #e8e8e8;
+ float: left;
+ font-size: .7em;
+ height: 220px;
+ overflow: hidden;
+ padding: .6em 8px;
+ position: relative;
+ text-align: center;
+ width: 180px;
+ z-index: 1;
+}
+
+#gContent #gAlbumGrid .gItem h2 {
+ margin: 5px 0;
+}
+
+#gContent .gPhoto h2,
+#gContent .gItem .gMetadata {
+ margin-top: .2em;
+ color: #ffffcc;
+ display: none;
+}
+
+#gContent #gAlbumGrid .gAlbum {
+ background-color: #484848;
+}
+
+.gImageBlock .gParentAlbum h4 span {
+ background: transparent url('../images/ico-album.png') no-repeat top left;
+ display: inline-block;
+ height: 16px;
+ margin-right: 5px;
+ width: 16px;
+}
+
+#gContent #gAlbumGrid .gAlbum h2 span {
+ background: transparent url('../images/ico-album.png') no-repeat top left;
+ display: inline-block;
+ height: 16px;
+ margin-right: 5px;
+ width: 16px;
+}
+
+#gContent #gAlbumGrid .gHoverItem {
+ background-color: #000;
+ border: 1px solid #f9bd01;
+}
+
+#gContent .gHoverItem h2,
+#gContent .gHoverItem .gMetadata {
+ display: block;
+}
+
+/* Individual photo content ~~~~~~~~~~~~~~ */
+
+#gContent #gItem {
+ position: relative;
+ width: 99%;
+}
+
+#gContent #gPhoto {
+ position: relative;
+}
+
+#gContent #gItem .gFullSizeLink img {
+ display: block;
+ margin: 1em auto !important;
+}
+
+ .gCommentBox {
+ border-bottom: 1px solid #555;
+}
+
+.gCommentBox:hover{
+ background-color: black;
+ color: #ffffcc;
+}
+
+ .gComment {
+ margin-left: 2em;
+ margin-top: .3em;
+ margin-bottom: .5em;
+}
+
+ #gCommentDetail {
+ width: 360px;
+ height: 100%;
+ background-color: #333333;
+ padding: 10px;
+ text-align: left;
+ margin-top: 30px;
+}
+ #gComments {
+ margin-top: 2em;
+ position: relative;
+}
+
+ #gComments ul li {
+ margin: 1em 0;
+}
+
+ #gComments ul li div {
+ padding: 0 8px 8px 43px;
+}
+
+ #gComments ul li #gRecaptcha {
+ padding: 0;
+}
+
+ #gComments ul li #gRecaptcha div {
+ padding: 0;
+}
+
+#gAddCommentButton {
+ position: absolute;
+ right: 0;
+ top: 2px;
+}
+
+ #gAddCommentForm {
+ margin-top: 2em;
+}
+
+/* Footer content ~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gBanner #gLoginMenu li,
+#gFooter #gCredits li {
+ display: inline;
+}
+
+#gBanner #gLoginMenu li {
+ padding-left: 1.2em;
+}
+
+#gFooter #gCredits li {
+ padding-right: 1.2em;
+}
+
+#gContent #gSearchResults {
+ margin-top: 1em;
+ padding-top: 1em;
+}
+
+/** *******************************************************************
+ * 5) Navigation and menus
+ *********************************************************************/
+
+#gSiteMenu,
+#gTagCloud ul {
+ font-size: 1.2em;
+}
+
+/* Login menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gBanner #gLoginMenu {
+ color: #999;
+ float: right;
+}
+
+/* Site Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gSiteMenu {
+ bottom: 0;
+ display: none;
+ left: 300px;
+ position: absolute;
+}
+
+#gSiteMenu ul {
+ margin-bottom: 0 !important;
+}
+
+/* Context Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.gContextMenu {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+}
+
+.gItem .gContextMenu {
+ display: none;
+ margin-top: 2em;
+ width: 100%;
+}
+
+#gItem .gContextMenu {
+ font-size: .7em;
+}
+
+#gItem .gContextMenu ul {
+ display: none;
+}
+
+.gContextMenu li {
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
+}
+
+.gContextMenu li a {
+ display: block;
+ line-height: 1.6em;
+}
+
+.gHoverItem .gContextMenu {
+ display: block;
+}
+
+.gHoverItem .gContextMenu li {
+ text-align: left;
+}
+
+.gHoverItem .gContextMenu a:hover {
+ text-decoration: none;
+}
+
+/* View Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gViewMenu {
+ margin-bottom: 1em;
+}
+
+#gViewMenu a {
+ background-repeat: no-repeat;
+ background-position: 50% 50%;
+ height: 28px !important;
+ width: 43px !important;
+}
+
+#gViewMenu #gHybridLink {
+ background-image: url('../images/ico-view-hybrid.png');
+}
+
+#gViewMenu #gSlideshowLink {
+ background-image: url('../images/ico-view-slideshow.png');
+}
+
+#gViewMenu .gFullSizeLink {
+ background-image: url('../images/ico-view-fullsize.png');
+}
+
+#gViewMenu #gCommentsLink {
+ background-image: url('../images/ico-view-comments.png');
+}
+
+#gViewMenu #gDigibugLink {
+ background-image: url('../images/ico-print.png');
+}
+
+/* Breadcrumbs ~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+.gBreadcrumbs {
+ padding: 0 20px;
+}
+
+.gBreadcrumbs li {
+ background: transparent url('../images/ico-separator.gif') no-repeat scroll left center;
+ float: left;
+ padding: 10px 6px 10px 16px !important;
+}
+
+.gBreadcrumbs li.root {
+ background: transparent;
+}
+
+.gBreadcrumbs li a,
+.gBreadcrumbs li span {
+ display: block;
+}
+
+.gBreadcrumbs li.active,
+.gBreadcrumbs li.active span {
+ font-weight: bold;
+}
+
+#gDialog ul.gBreadcrumbs {
+ clear: both;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+#gDialog .gBreadcrumbs li {
+ font-size: .9em;
+}
+
+/* Tags and cloud ~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gTagCloud ul {
+ text-align: justify;
+}
+
+#gTagCloud ul li {
+ display: inline;
+ line-height: 1.5em;
+ text-align: justify;
+}
+
+#gTagCloud ul li a {
+ text-decoration: none;
+}
+
+#gTagCloud ul li span {
+ display: none;
+}
+
+#gTagCloud ul li.size1 a {
+ color: #9cf;
+ font-size: 80%;
+ font-weight: 100;
+}
+
+#gTagCloud ul li.size2 a {
+ color: #69f;
+ font-size: 90%;
+ font-weight: 300;
+}
+
+#gTagCloud ul li.size3 a {
+ color: #69c;
+ font-size: 100%;
+ font-weight: 500;
+}
+
+#gTagCloud ul li.size4 a {
+ color: #369;
+ font-size: 110%;
+ font-weight: 700;
+}
+
+#gTagCloud ul li.size5 a {
+ color: #0e2b52;
+ font-size: 120%;
+ font-weight: 900;
+}
+
+#gTagCloud ul li.size6 a {
+ color: #0e2b52;
+ font-size: 130%;
+ font-weight: 900;
+}
+
+#gTagCloud ul li.size7 a {
+ color: #0e2b52;
+ font-size: 140%;
+ font-weight: 900;
+}
+
+#gTagCloud ul li a:hover {
+ color: #f30;
+ text-decoration: underline;
+}
+
+#gWelcomeMessage p {
+ padding-bottom: 1em;
+}
+
+/* Pagination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.gPager {
+ clear: both;
+ margin: 0;
+ padding: 5px 0 !important;
+ width: 100%;
+}
+
+.gPager li {
+ float: left;
+ margin: 0;
+ width: 30%;
+}
+
+.gPager .gInfo {
+ text-align: center;
+ width: 40%;
+}
+
+/** *******************************************************************
+ * 6) Browser hacks
+ *********************************************************************/
+
+#gHeader:after,
+#gAlbumGrid:after,
+.gPager:after,
+#gViewMenu:after {
+ clear: both;
+ content: ".";
+ display: block;
+ height: 0;
+ visibility: hidden;
+}
+
+/** *******************************************************************
+ * 7) jQuery and jQuery UI
+ *********************************************************************/
+
+/* Superfish menu overrides ~~~~~~~~~~~~~~ */
+.sf-menu a {
+ border-left: 1px solid #e8e8e8;
+ border-top: 1px solid #e8e8e8;
+ border-right: 1px solid #e8e8e8;
+ padding: .75em 1em;
+ text-decoration:none;
+}
+.sf-menu a, .sf-menu a:visited { /* visited pseudo selector so IE6 applies text colour*/
+ color: #13a;
+}
+.sf-menu li {
+ background: #333333;
+}
+.sf-menu li li {
+ background: #333333;
+}
+.sf-menu li li li {
+ background: #333333;
+}
+.sf-menu li:hover, .sf-menu li.sfHover,
+.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active {
+ background: #484848;
+ outline: 0;
+}
+
+.sf-menu li li, .sf-menu li li ul li {
+ background-color: #333333;
+}
+
+.sf-menu li:hover {
+ background-color: #000000;
+}
+
+/* Ajax loading indicator ~~~~~~~~~~~~~~~~ */
+
+.gLoadingLarge {
+ background: #e8e8e8 url('../../../lib/images/loading-large.gif') no-repeat center center;
+ font-size: 0;
+}
+
+.gDialogLoadingLarge {
+ background: url('../../../lib/images/loading-large.gif') no-repeat center center !important;
+ font-size: 0;
+}
+
+.gLoadingSmall {
+ background: #e8e8e8 url('../../../lib/images/loading-small.gif') no-repeat center center;
+ font-size: 0;
+}
+
+.gDraggable {
+ cursor: move;
+}
+
+.gDropTarget {
+ background-color: #cfdeff;
+ border: 1px dotted #999;
+ height: 100px;
+ margin: 1em 0;
+}
+
+/* jQuery UI Dialog ~~~~~~~~~~~~~~~~~~~~~~ */
+
+.ui-widget-overlay {
+ background: #000;
+ opacity: .7;
+}
+
+#gDialog {
+ text-align: left;
+}
+
+#gDialog li {
+ padding-left: 0;
+}
+
+#gDialog form input[type="text"],
+#gDialog form input[type="password"] {
+ width: 100%;
+}
+
+#gDialog #gLoginForm,
+#gDialog #gAddUserForm,
+#gDialog #gAddGroupForm {
+ margin: 0 auto;
+ width: 270px;
+}
+
+#gDialog fieldset {
+ border: none;
+}
+
+#gDialog legend {
+ display: none;
+}
+
+#gDialog p {
+ margin: 0;
+}
+
+/* jQuery UI ThemeRoller buttons */
+
+.gButtonLink {
+ display: inline-block;
+ margin: 0 4px 0 0;
+ padding: .2em .4em;
+ outline: 0;
+}
+
+.gButtonSet {
+ padding-left: 1px;
+}
+
+.gButtonSet li {
+ float: left;
+}
+
+.gButtonSet .gButtonLink {
+ margin: 0;
+}
+
+.ui-icon-left .ui-icon {
+ float: left;
+ margin-right: .2em;
+}
+
+.ui-icon-right .ui-icon {
+ float: right;
+ margin-left: .2em;
+}
+
+.ui-icon-rotate-ccw {
+ background-position: -192px -64px;
+}
+
+.ui-icon-rotate-cw {
+ background-position: -208px -64px;
+}
+
+/* STUFF THAT NEEDS A HOME */
+
+#gMove ul {
+ padding-left: 1em;
+}
+
+#gMove .selected {
+ background: #999;
+}
+
+/* Server Add */
+
+#gServerAdd button {
+ margin-bottom: .5em;
+}
+
+#gServerAddTree {
+ cursor: pointer;
+ padding-left: 4px;
+ width: 95%;
+}
+
+#gServerAddTree li {
+ padding: 0;
+ float: none;
+}
+
+#gServerAddTree span.selected {
+ background: #ddd;
+}
+
+#gServerAddTree {
+ border: 1px solid #ccc;
+ height: 20em;
+ overflow: auto;
+ margin-bottom: .5em;
+ padding: .5em;
+}
+
+#gServerAdd ul ul li {
+ padding-left: 1.2em;
+}
+
+/* Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#gEditPermissionForm {
+ clear: both;
+}
+#gEditPermissionForm fieldset {
+ border: 1px solid #cccccc;
+ padding: 0;
+}
+
+#gPermissions .gDenied,
+#gPermissions .gAllowed {
+ text-align: center;
+ vertical-align: middle;
+}
+#gPermissions .gDenied {
+ background-color: #fcc;
+}
+#gPermissions .gAllowed {
+ background-color: #cfc;
+}
+
+/*************** STUFF THAT NEEDS A HOME ****************/
+
+.gProgressBar {
+ height: 1em;
+ width: 100%;
+ margin-top: .5em;
+ display: inline-block;
+}
+
+#gAddPhotos span {
+ clear: both;
+ display: block;
+}
+
+#gAddPhotosCanvas {
+ height: 325px;
+ width: 450px;
+ overflow: auto;
+}
+
+#gAddPhotosQueue .progressbar {
+ height: 4px;
+}
+
+#gAddPhotosQueue .title {
+ font-size: 1.25em;
+}
+
+#gAddPhotosQueue .status {
+ font-size: .75em;
+}
+
+#gAddPhotosQueue .box {
+ margin-bottom: 8px;
+ padding: 4px;
+}
+
+#gAddPhotosQueue .pending {
+ background-color: #e8e8e8;
+ border: 1px solid #d7d7d7;
+}
+
+#gAddPhotosQueue .error {
+ background-color: #fcc;
+ border: 1px solid #ebb;
+}
+
+#gAddPhotosQueue .uploading {
+ background-color: #ff9;
+ border: 1px solid #ee8;
+}
+
+#gAddPhotosQueue .complete {
+ background-color: #cfc;
+ border: 1px solid #beb;
+}
+
+#gAdminG2ImportNotes {
+ padding-bottom: 20px;
+}
+
+#gAdminG2ImportDetails {
+ padding-top: 20px;
+}
+
+#gAdminG2ImportDetails .gWarning {
+ margin-top: 4px;
+}
+
+#gAdminG2ImportDetails .gInfo {
+ padding: 2px;
+ border: 1px solid #999;
+ margin-bottom: 10px;
+}
+
+#gAdminG2ImportNotes p,
+#gAdminG2ImportDetails .gInfo p {
+ padding: 0;
+ margin: 0;
+}
+
+#gAdminG2ImportNotes ul li,
+#gAdminG2Import .gInfo ul li {
+ padding-left: 0;
+ margin-left: 20px;
+ list-style-type: disc;
+}
+
+/* Right to left styles ~~~~~~~~~~~~~~~~~~~~ */
+
+.rtl {
+ direction: rtl;
+}
+
+.rtl caption,
+.rtl th,
+.rtl #gDialog {
+ text-align: right;
+}
+
+.rtl #gHeader #gQuickSearchForm,
+.rtl #gForgotPasswordLink,
+.rtl #gHeader #gLoginMenu,
+.rtl .ui-icon-right .ui-icon {
+ clear: left;
+ float: left;
+}
+
+.rtl #gDialog .gCancel,
+.rtl form ul ul li,
+.rtl input[type="submit"],
+.rtl input[type="reset"],
+.rtl .gShortForm li,
+.rtl #gHeader #gLogo img,
+.rtl #gContent #gAlbumGrid .gItem,
+.rtl #gSiteMenu,
+.rtl .gBreadcrumbs li,
+.rtl .gPager li,
+.rtl .gButtonSet li,
+.rtl .ui-icon-left .ui-icon {
+ float: right;
+}
+
diff --git a/themes/3nids/3nids/images/avatar.jpg b/themes/3nids/3nids/images/avatar.jpg
new file mode 100755
index 00000000..d08724fc
Binary files /dev/null and b/themes/3nids/3nids/images/avatar.jpg differ
diff --git a/themes/3nids/3nids/images/fancy_closebox.png b/themes/3nids/3nids/images/fancy_closebox.png
new file mode 100755
index 00000000..4de4396d
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_closebox.png differ
diff --git a/themes/3nids/3nids/images/fancy_left.png b/themes/3nids/3nids/images/fancy_left.png
new file mode 100755
index 00000000..61494e63
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_left.png differ
diff --git a/themes/3nids/3nids/images/fancy_progress.png b/themes/3nids/3nids/images/fancy_progress.png
new file mode 100755
index 00000000..06b7c89a
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_progress.png differ
diff --git a/themes/3nids/3nids/images/fancy_right.png b/themes/3nids/3nids/images/fancy_right.png
new file mode 100755
index 00000000..0a56042f
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_right.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_e.png b/themes/3nids/3nids/images/fancy_shadow_e.png
new file mode 100755
index 00000000..5db7b2b8
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_e.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_n.png b/themes/3nids/3nids/images/fancy_shadow_n.png
new file mode 100755
index 00000000..4e20abbe
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_n.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_ne.png b/themes/3nids/3nids/images/fancy_shadow_ne.png
new file mode 100755
index 00000000..64ef7225
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_ne.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_nw.png b/themes/3nids/3nids/images/fancy_shadow_nw.png
new file mode 100755
index 00000000..9ef03377
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_nw.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_s.png b/themes/3nids/3nids/images/fancy_shadow_s.png
new file mode 100755
index 00000000..bf52bd61
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_s.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_se.png b/themes/3nids/3nids/images/fancy_shadow_se.png
new file mode 100755
index 00000000..12311ed3
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_se.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_sw.png b/themes/3nids/3nids/images/fancy_shadow_sw.png
new file mode 100755
index 00000000..923a8b50
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_sw.png differ
diff --git a/themes/3nids/3nids/images/fancy_shadow_w.png b/themes/3nids/3nids/images/fancy_shadow_w.png
new file mode 100755
index 00000000..6f808d3e
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_shadow_w.png differ
diff --git a/themes/3nids/3nids/images/fancy_title_left.png b/themes/3nids/3nids/images/fancy_title_left.png
new file mode 100755
index 00000000..1e82b6da
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_title_left.png differ
diff --git a/themes/3nids/3nids/images/fancy_title_main.png b/themes/3nids/3nids/images/fancy_title_main.png
new file mode 100755
index 00000000..5f505b00
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_title_main.png differ
diff --git a/themes/3nids/3nids/images/fancy_title_right.png b/themes/3nids/3nids/images/fancy_title_right.png
new file mode 100755
index 00000000..ef0dc201
Binary files /dev/null and b/themes/3nids/3nids/images/fancy_title_right.png differ
diff --git a/themes/3nids/3nids/images/ico-album.png b/themes/3nids/3nids/images/ico-album.png
new file mode 100755
index 00000000..e3bb4fc5
Binary files /dev/null and b/themes/3nids/3nids/images/ico-album.png differ
diff --git a/themes/3nids/3nids/images/ico-denied-gray.png b/themes/3nids/3nids/images/ico-denied-gray.png
new file mode 100755
index 00000000..56db3ff5
Binary files /dev/null and b/themes/3nids/3nids/images/ico-denied-gray.png differ
diff --git a/themes/3nids/3nids/images/ico-denied-pale.png b/themes/3nids/3nids/images/ico-denied-pale.png
new file mode 100755
index 00000000..1e992230
Binary files /dev/null and b/themes/3nids/3nids/images/ico-denied-pale.png differ
diff --git a/themes/3nids/3nids/images/ico-denied.png b/themes/3nids/3nids/images/ico-denied.png
new file mode 100755
index 00000000..08f24936
Binary files /dev/null and b/themes/3nids/3nids/images/ico-denied.png differ
diff --git a/themes/3nids/3nids/images/ico-error.png b/themes/3nids/3nids/images/ico-error.png
new file mode 100755
index 00000000..c37bd062
Binary files /dev/null and b/themes/3nids/3nids/images/ico-error.png differ
diff --git a/themes/3nids/3nids/images/ico-help.png b/themes/3nids/3nids/images/ico-help.png
new file mode 100755
index 00000000..5c870176
Binary files /dev/null and b/themes/3nids/3nids/images/ico-help.png differ
diff --git a/themes/3nids/3nids/images/ico-info.png b/themes/3nids/3nids/images/ico-info.png
new file mode 100755
index 00000000..12cd1aef
Binary files /dev/null and b/themes/3nids/3nids/images/ico-info.png differ
diff --git a/themes/3nids/3nids/images/ico-lock.png b/themes/3nids/3nids/images/ico-lock.png
new file mode 100755
index 00000000..2ebc4f6f
Binary files /dev/null and b/themes/3nids/3nids/images/ico-lock.png differ
diff --git a/themes/3nids/3nids/images/ico-print.png b/themes/3nids/3nids/images/ico-print.png
new file mode 100755
index 00000000..b82a8e1e
Binary files /dev/null and b/themes/3nids/3nids/images/ico-print.png differ
diff --git a/themes/3nids/3nids/images/ico-separator.gif b/themes/3nids/3nids/images/ico-separator.gif
new file mode 100755
index 00000000..3de2d0d3
Binary files /dev/null and b/themes/3nids/3nids/images/ico-separator.gif differ
diff --git a/themes/3nids/3nids/images/ico-success-gray.png b/themes/3nids/3nids/images/ico-success-gray.png
new file mode 100755
index 00000000..74b2032f
Binary files /dev/null and b/themes/3nids/3nids/images/ico-success-gray.png differ
diff --git a/themes/3nids/3nids/images/ico-success-pale.png b/themes/3nids/3nids/images/ico-success-pale.png
new file mode 100755
index 00000000..dc8d1ded
Binary files /dev/null and b/themes/3nids/3nids/images/ico-success-pale.png differ
diff --git a/themes/3nids/3nids/images/ico-success.png b/themes/3nids/3nids/images/ico-success.png
new file mode 100755
index 00000000..a9925a06
Binary files /dev/null and b/themes/3nids/3nids/images/ico-success.png differ
diff --git a/themes/3nids/3nids/images/ico-view-comments.png b/themes/3nids/3nids/images/ico-view-comments.png
new file mode 100755
index 00000000..e5d3630f
Binary files /dev/null and b/themes/3nids/3nids/images/ico-view-comments.png differ
diff --git a/themes/3nids/3nids/images/ico-view-fullsize.png b/themes/3nids/3nids/images/ico-view-fullsize.png
new file mode 100755
index 00000000..0be23e9b
Binary files /dev/null and b/themes/3nids/3nids/images/ico-view-fullsize.png differ
diff --git a/themes/3nids/3nids/images/ico-view-hybrid.png b/themes/3nids/3nids/images/ico-view-hybrid.png
new file mode 100755
index 00000000..ee902e55
Binary files /dev/null and b/themes/3nids/3nids/images/ico-view-hybrid.png differ
diff --git a/themes/3nids/3nids/images/ico-view-slideshow.png b/themes/3nids/3nids/images/ico-view-slideshow.png
new file mode 100755
index 00000000..82f61f63
Binary files /dev/null and b/themes/3nids/3nids/images/ico-view-slideshow.png differ
diff --git a/themes/3nids/3nids/images/ico-warning.png b/themes/3nids/3nids/images/ico-warning.png
new file mode 100755
index 00000000..628cf2da
Binary files /dev/null and b/themes/3nids/3nids/images/ico-warning.png differ
diff --git a/themes/3nids/3nids/images/map.png b/themes/3nids/3nids/images/map.png
new file mode 100755
index 00000000..1df93fb5
Binary files /dev/null and b/themes/3nids/3nids/images/map.png differ
diff --git a/themes/3nids/3nids/images/select-photos-backg.png b/themes/3nids/3nids/images/select-photos-backg.png
new file mode 100755
index 00000000..81c2d616
Binary files /dev/null and b/themes/3nids/3nids/images/select-photos-backg.png differ
diff --git a/themes/3nids/3nids/js/jquery.easing.js b/themes/3nids/3nids/js/jquery.easing.js
new file mode 100755
index 00000000..ef743210
--- /dev/null
+++ b/themes/3nids/3nids/js/jquery.easing.js
@@ -0,0 +1,205 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+jQuery.easing['jswing'] = jQuery.easing['swing'];
+
+jQuery.extend( jQuery.easing,
+{
+ def: 'easeOutQuad',
+ swing: function (x, t, b, c, d) {
+ //alert(jQuery.easing.default);
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c*(t/=d)*t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t*t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*(t/=d)*t*((s+1)*t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ if ((t/=d) < (1/2.75)) {
+ return c*(7.5625*t*t) + b;
+ } else if (t < (2/2.75)) {
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+ } else if (t < (2.5/2.75)) {
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+ } else {
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
+ }
+});
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
\ No newline at end of file
diff --git a/themes/3nids/3nids/js/jquery.fancybox.js b/themes/3nids/3nids/js/jquery.fancybox.js
new file mode 100755
index 00000000..4558c0d6
--- /dev/null
+++ b/themes/3nids/3nids/js/jquery.fancybox.js
@@ -0,0 +1,1102 @@
+/*
+ * FancyBox - simple and fancy jQuery plugin
+ * Examples and documentation at: http://fancy.klade.lv/
+ * Version: 1.2.1 (13/03/2009)
+ * Copyright (c) 2009 Janis Skarnelis
+ * Licensed under the MIT License: http://en.wikipedia.org/wiki/MIT_License
+ * Requires: jQuery v1.3+
+*/
+;(function($) {
+
+ $.fn.fixPNG = function() {
+ return this.each(function () {
+ var image = $(this).css('backgroundImage');
+
+ if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
+ image = RegExp.$1;
+ $(this).css({
+ 'backgroundImage': 'none',
+ 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=" + ($(this).css('backgroundRepeat') == 'no-repeat' ? 'crop' : 'scale') + ", src='" + image + "')"
+ }).each(function () {
+ var position = $(this).css('position');
+ if (position != 'absolute' && position != 'relative')
+ $(this).css('position', 'relative');
+ });
+ }
+ });
+ };
+
+ var elem, opts, busy = false, imagePreloader = new Image, loadingTimer, loadingFrame = 1, imageRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i;
+ var isIE = ($.browser.msie && parseInt($.browser.version.substr(0,1)) < 8);
+
+ $.fn.fancybox = function(settings) {
+ settings = $.extend({}, $.fn.fancybox.defaults, settings);
+
+ var matchedGroup = this;
+
+ function _initialize() {
+ elem = this;
+ opts = settings;
+
+ _start();
+
+ return false;
+ };
+
+ function _start() {
+ if (busy) return;
+
+ if ($.isFunction(opts.callbackOnStart)) {
+ opts.callbackOnStart();
+ }
+
+ opts.itemArray = [];
+ opts.itemCurrent = 0;
+
+ if (settings.itemArray.length > 0) {
+ opts.itemArray = settings.itemArray;
+
+ } else {
+ var item = {};
+
+ if (!elem.rel || elem.rel == '') {
+ var item = {href: elem.href, title: elem.title, modules: elem.name};
+
+ if ($(elem).children("img:first").length) {
+ item.orig = $(elem).children("img:first");
+ }
+
+ opts.itemArray.push( item );
+
+ } else {
+
+ var subGroup = $(matchedGroup).filter("a[rel=" + elem.rel + "]");
+
+ var item = {};
+
+ for (var i = 0; i < subGroup.length; i++) {
+ item = {href: subGroup[i].href, title: subGroup[i].title, modules: subGroup[i].name};
+
+ if ($(subGroup[i]).children("img:first").length) {
+ item.orig = $(subGroup[i]).children("img:first");
+ }
+
+ opts.itemArray.push( item );
+ }
+
+ while ( opts.itemArray[ opts.itemCurrent ].href != elem.href ) {
+ opts.itemCurrent++;
+ }
+ }
+ }
+
+ if (opts.overlayShow) {
+ if (isIE) {
+ $('embed, object, select').css('visibility', 'hidden');
+ }
+
+ $("#fancy_overlay").css('opacity', opts.overlayOpacity).show();
+ }
+
+ _change_item();
+ };
+
+ function _change_item() {
+ $("#fancy_right, #fancy_left, #fancy_close, #fancy_title, #fancy_modules").hide();
+
+ var href = opts.itemArray[ opts.itemCurrent ].href;
+
+ if (href.match(/#/)) {
+ var target = window.location.href.split('#')[0]; target = href.replace(target, ''); target = target.substr(target.indexOf('#'));
+
+ _set_content('' + $(target).html() + '
', opts.frameWidth, opts.frameHeight);
+
+ } else if (href.match(imageRegExp)) {
+ imagePreloader = new Image; imagePreloader.src = href;
+
+ if (imagePreloader.complete) {
+ _proceed_image();
+
+ } else {
+ $.fn.fancybox.showLoading();
+
+ $(imagePreloader).unbind().bind('load', function() {
+ $(".fancy_loading").hide();
+
+ _proceed_image();
+ });
+ }
+
+ } else if (href.match("iframe") || elem.className.indexOf("iframe") >= 0) {
+ _set_content('', opts.frameWidth, opts.frameHeight);
+
+ } else {
+ $.get(href, function(data) {
+ _set_content( '' + data + '
', opts.frameWidth, opts.frameHeight );
+ });
+ }
+ };
+
+ function _proceed_image() {
+ if (opts.imageScale) {
+ var w = $.fn.fancybox.getViewport();
+
+ var r = Math.min(Math.min(w[0] - 36, imagePreloader.width) / imagePreloader.width, Math.min(w[1] - 60, imagePreloader.height) / imagePreloader.height);
+
+ var width = Math.round(r * imagePreloader.width);
+ var height = Math.round(r * imagePreloader.height);
+
+ } else {
+ var width = imagePreloader.width;
+ var height = imagePreloader.height;
+ }
+
+ _set_content(' ', width, height);
+ };
+
+ function _preload_neighbor_images() {
+ if ((opts.itemArray.length -1) > opts.itemCurrent) {
+ var href = opts.itemArray[opts.itemCurrent + 1].href;
+
+ if (href.match(imageRegExp)) {
+ $(" ").attr("src", href);
+ }
+ }
+
+ if (opts.itemCurrent > 0) {
+ var href = opts.itemArray[opts.itemCurrent -1].href;
+
+ if (href.match(imageRegExp)) {
+ $(" ").attr("src", href);
+ }
+ }
+ };
+
+ function _set_content(value, width, height) {
+ busy = true;
+
+ var pad = opts.padding;
+
+ if (isIE) {
+ $("#fancy_content")[0].style.removeExpression("height");
+ $("#fancy_content")[0].style.removeExpression("width");
+ }
+
+ if (pad > 0) {
+ width += pad * 2;
+ height += pad * 2;
+
+ $("#fancy_content").css({
+ 'top' : pad + 'px',
+ 'right' : pad + 'px',
+ 'bottom' : pad + 'px',
+ 'left' : pad + 'px',
+ 'width' : 'auto',
+ 'height' : 'auto'
+ });
+
+ if (isIE) {
+ $("#fancy_content")[0].style.setExpression('height', '(this.parentNode.clientHeight - 20)');
+ $("#fancy_content")[0].style.setExpression('width', '(this.parentNode.clientWidth - 20)');
+ }
+
+ } else {
+ $("#fancy_content").css({
+ 'top' : 0,
+ 'right' : 0,
+ 'bottom' : 0,
+ 'left' : 0,
+ 'width' : '100%',
+ 'height' : '100%'
+ });
+ }
+
+ if ($("#fancy_outer").is(":visible") && width == $("#fancy_outer").width() && height == $("#fancy_outer").height()) {
+ $("#fancy_content").fadeOut("fast", function() {
+ $("#fancy_content").empty().append($(value)).fadeIn("normal", function() {
+ _finish();
+ });
+ });
+
+ return;
+ }
+
+ var w = $.fn.fancybox.getViewport();
+
+ var itemLeft = (width + 36) > w[0] ? w[2] : (w[2] + Math.round((w[0] - width - 36) / 2));
+ var itemTop = (height + 50) > w[1] ? w[3] : (w[3] + Math.round((w[1] - height - 50) / 2));
+
+ var itemOpts = {
+ 'left': itemLeft,
+ 'top': itemTop,
+ 'width': width + 'px',
+ 'height': height + 'px'
+ };
+
+ if ($("#fancy_outer").is(":visible")) {
+ $("#fancy_content").fadeOut("normal", function() {
+ $("#fancy_content").empty();
+ $("#fancy_outer").animate(itemOpts, opts.zoomSpeedChange, opts.easingChange, function() {
+ $("#fancy_content").append($(value)).fadeIn("normal", function() {
+ _finish();
+ });
+ });
+ });
+
+ } else {
+
+ if (opts.zoomSpeedIn > 0 && opts.itemArray[opts.itemCurrent].orig !== undefined) {
+ $("#fancy_content").empty().append($(value));
+
+ var orig_item = opts.itemArray[opts.itemCurrent].orig;
+ var orig_pos = $.fn.fancybox.getPosition(orig_item);
+
+ $("#fancy_outer").css({
+ 'left': (orig_pos.left - 18) + 'px',
+ 'top': (orig_pos.top - 18) + 'px',
+ 'width': $(orig_item).width(),
+ 'height': $(orig_item).height()
+ });
+
+ if (opts.zoomOpacity) {
+ itemOpts.opacity = 'show';
+ }
+
+ $("#fancy_outer").animate(itemOpts, opts.zoomSpeedIn, opts.easingIn, function() {
+ _finish();
+ });
+
+ } else {
+
+ $("#fancy_content").hide().empty().append($(value)).show();
+ $("#fancy_outer").css(itemOpts).fadeIn("normal", function() {
+ _finish();
+ });
+ }
+ }
+ };
+
+ function _set_navigation() {
+ if (opts.itemCurrent != 0) {
+ $("#fancy_left, #fancy_left_ico").unbind().bind("click", function(e) {
+ e.stopPropagation();
+
+ opts.itemCurrent--;
+ _change_item();
+
+ return false;
+ });
+
+ $("#fancy_left").show();
+ }
+
+ if (opts.itemCurrent != ( opts.itemArray.length -1)) {
+ $("#fancy_right, #fancy_right_ico").unbind().bind("click", function(e) {
+ e.stopPropagation();
+
+ opts.itemCurrent++;
+ _change_item();
+
+ return false;
+ });
+
+ $("#fancy_right").show();
+ }
+ };
+
+ function _finish() {
+ _set_navigation();
+
+ _preload_neighbor_images();
+
+ $(document).keydown(function(e) {
+ if (e.keyCode == 27) {
+ $.fn.fancybox.close();
+ $(document).unbind("keydown");
+
+ } else if(e.keyCode == 37 && opts.itemCurrent != 0) {
+ opts.itemCurrent--;
+ _change_item();
+ $(document).unbind("keydown");
+
+ } else if(e.keyCode == 39 && opts.itemCurrent != (opts.itemArray.length - 1)) {
+ opts.itemCurrent++;
+ _change_item();
+ $(document).unbind("keydown");
+ }
+ });
+
+ if (opts.centerOnScroll) {
+ $(window).bind("resize scroll", $.fn.fancybox.scrollBox);
+ } else {
+ $("div#fancy_outer").css("position", "absolute");
+ }
+
+ if (opts.hideOnContentClick) {
+ $("#fancy_wrap").click($.fn.fancybox.close);
+ }
+
+ $("#fancy_overlay, #fancy_close").bind("click", $.fn.fancybox.close);
+
+ $("#fancy_close").show();
+
+ if (opts.itemArray[ opts.itemCurrent ].title !== undefined && opts.itemArray[ opts.itemCurrent ].title.length > 0) {
+ $('#fancy_title div').html(opts.itemArray[ opts.itemCurrent ].title);
+ $('#fancy_title').show();
+ }
+
+ if (opts.itemArray[ opts.itemCurrent ].modules !== undefined && opts.itemArray[ opts.itemCurrent ].modules.length > 0) {
+ $('#fancy_modules').hide();
+ $('#fancy_title').hide();
+ var modules = opts.itemArray[ opts.itemCurrent ].modules;
+ var modtxt = '|';
+ var pex = modules.search('exif::');
+ if (pex != -1){
+ var exifsrc = modules.substring(pex+6);
+ var exifsrc = exifsrc.split(';;',1);
+ modtxt += " EXIF |";
+ }
+ var pco = modules.search('comment::');
+ if (pco != -1){
+ var commentsrc = modules.substring(pco+9);
+ var commentsrc = commentsrc.split(';;',1);
+ var commentcount = modules.substring(modules.search('comment_count::')+15);
+ var commentcount = commentcount.split(';;',1);
+ modtxt += " Comments (" + commentcount + ") |";
+ }
+ if (modtxt != '|'){
+ $('#fancy_modules div').html(modtxt);
+ $('#fancy_modules').show();
+ $(document).ready(function() { $(".modclass").modbox(); });
+ }
+ $('#fancy_title').show();
+ }
+
+ if (opts.overlayShow && isIE) {
+ $('embed, object, select', $('#fancy_content')).css('visibility', 'visible');
+ }
+
+ if ($.isFunction(opts.callbackOnShow)) {
+ opts.callbackOnShow();
+ }
+
+ busy = false;
+ };
+
+ return this.unbind('click').click(_initialize);
+ };
+
+ $.fn.fancybox.scrollBox = function() {
+ var pos = $.fn.fancybox.getViewport();
+
+ $("#fancy_outer").css('left', (($("#fancy_outer").width() + 36) > pos[0] ? pos[2] : pos[2] + Math.round((pos[0] - $("#fancy_outer").width() - 36) / 2)));
+ $("#fancy_outer").css('top', (($("#fancy_outer").height() + 50) > pos[1] ? pos[3] : pos[3] + Math.round((pos[1] - $("#fancy_outer").height() - 50) / 2)));
+ };
+
+ $.fn.fancybox.getNumeric = function(el, prop) {
+ return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
+ };
+
+ $.fn.fancybox.getPosition = function(el) {
+ var pos = el.offset();
+
+ pos.top += $.fn.fancybox.getNumeric(el, 'paddingTop');
+ pos.top += $.fn.fancybox.getNumeric(el, 'borderTopWidth');
+
+ pos.left += $.fn.fancybox.getNumeric(el, 'paddingLeft');
+ pos.left += $.fn.fancybox.getNumeric(el, 'borderLeftWidth');
+
+ return pos;
+ };
+
+ $.fn.fancybox.showIframe = function() {
+ $(".fancy_loading").hide();
+ $("#fancy_frame").show();
+ };
+
+ $.fn.fancybox.getViewport = function() {
+ return [$(window).width(), $(window).height(), $(document).scrollLeft(), $(document).scrollTop() ];
+ };
+
+ $.fn.fancybox.animateLoading = function() {
+ if (!$("#fancy_loading").is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $("#fancy_loading > div").css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ $.fn.fancybox.showLoading = function() {
+ clearInterval(loadingTimer);
+
+ var pos = $.fn.fancybox.getViewport();
+
+ $("#fancy_loading").css({'left': ((pos[0] - 40) / 2 + pos[2]), 'top': ((pos[1] - 40) / 2 + pos[3])}).show();
+ $("#fancy_loading").bind('click', $.fn.fancybox.close);
+
+ loadingTimer = setInterval($.fn.fancybox.animateLoading, 66);
+ };
+
+ $.fn.fancybox.close = function() {
+ busy = true;
+
+ $(imagePreloader).unbind();
+
+ $("#fancy_overlay, #fancy_close").unbind();
+
+ if (opts.hideOnContentClick) {
+ $("#fancy_wrap").unbind();
+ }
+
+ $("#fancy_close, .fancy_loading, #fancy_left, #fancy_right, #fancy_title, #fancy_modules").hide();
+
+ if (opts.centerOnScroll) {
+ $(window).unbind("resize scroll");
+ }
+
+ __cleanup = function() {
+ $("#fancy_overlay, #fancy_outer").hide();
+
+ if (opts.centerOnScroll) {
+ $(window).unbind("resize scroll");
+ }
+
+ if (isIE) {
+ $('embed, object, select').css('visibility', 'visible');
+ }
+
+ if ($.isFunction(opts.callbackOnClose)) {
+ opts.callbackOnClose();
+ }
+
+ busy = false;
+ };
+
+ if ($("#fancy_outer").is(":visible") !== false) {
+ if (opts.zoomSpeedOut > 0 && opts.itemArray[opts.itemCurrent].orig !== undefined) {
+ var orig_item = opts.itemArray[opts.itemCurrent].orig;
+ var orig_pos = $.fn.fancybox.getPosition(orig_item);
+
+ var itemOpts = {
+ 'left': (orig_pos.left - 18) + 'px',
+ 'top': (orig_pos.top - 18) + 'px',
+ 'width': $(orig_item).width(),
+ 'height': $(orig_item).height()
+ };
+
+ if (opts.zoomOpacity) {
+ itemOpts.opacity = 'hide';
+ }
+
+ $("#fancy_outer").stop(false, true).animate(itemOpts, opts.zoomSpeedOut, opts.easingOut, __cleanup);
+
+ } else {
+ $("#fancy_outer").stop(false, true).fadeOut("fast", __cleanup);
+ }
+
+ } else {
+ __cleanup();
+ }
+
+ return false;
+ };
+
+ $.fn.fancybox.build = function() {
+ var html = '';
+
+ html += '
';
+
+ html += '';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ $(html).appendTo("body");
+
+ $('').appendTo('#fancy_title');
+ $('').appendTo('#fancy_modules');
+
+ if (isIE) {
+ $("#fancy_inner").prepend('');
+ $("#fancy_close, .fancy_bg, .fancy_title, .fancy_modules, .fancy_ico").fixPNG();
+ }
+ };
+
+ $.fn.fancybox.defaults = {
+ padding : 10,
+ imageScale : true,
+ zoomOpacity : false,
+ zoomSpeedIn : 0,
+ zoomSpeedOut : 0,
+ zoomSpeedChange : 300,
+ easingIn : 'swing',
+ easingOut : 'swing',
+ easingChange : 'swing',
+ frameWidth : 425,
+ frameHeight : 355,
+ overlayShow : true,
+ overlayOpacity : 0.8,
+ hideOnContentClick : false,
+ centerOnScroll : true,
+ itemArray : [],
+ callbackOnStart : null,
+ callbackOnShow : null,
+ callbackOnClose : null
+ };
+
+ $(document).ready(function() {
+ $.fn.fancybox.build();
+ });
+
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+// *************************************************************************************************************************************
+
+ var modelem, modopts, modbusy = false, imagePreloader = new Image, loadingTimer, loadingFrame = 1, imageRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i;
+
+ $.fn.modbox = function(settings) {
+ settings = $.extend({}, $.fn.modbox.defaults, settings);
+
+ var matchedGroup = this;
+
+ function _initialize() {
+ modelem = this;
+ modopts = settings;
+
+ _start();
+
+ return false;
+ };
+
+ function _start() {
+ if (modbusy) return;
+
+ if ($.isFunction(modopts.callbackOnStart)) {
+ modopts.callbackOnStart();
+ }
+
+ modopts.itemArray = [];
+ modopts.itemCurrent = 0;
+
+ if (settings.itemArray.length > 0) {
+ modopts.itemArray = settings.itemArray;
+
+ } else {
+ var item = {};
+
+ if (!modelem.rel || modelem.rel == '') {
+ var item = {href: modelem.href, title: modelem.title};
+
+ if ($(modelem).children("img:first").length) {
+ item.orig = $(modelem).children("img:first");
+ }
+
+ modopts.itemArray.push( item );
+
+ } else {
+
+ var subGroup = $(matchedGroup).filter("a[rel=" + modelem.rel + "]");
+
+ var item = {};
+
+ for (var i = 0; i < subGroup.length; i++) {
+ item = {href: subGroup[i].href, title: subGroup[i].title};
+
+ if ($(subGroup[i]).children("img:first").length) {
+ item.orig = $(subGroup[i]).children("img:first");
+ }
+
+ modopts.itemArray.push( item );
+ }
+
+ while ( modopts.itemArray[ modopts.itemCurrent ].href != modelem.href ) {
+ modopts.itemCurrent++;
+ }
+ }
+ }
+
+ if (modopts.overlayShow) {
+ if (isIE) {
+ $('embed, object, select').css('visibility', 'hidden');
+ }
+
+ $("#mod_overlay").css('opacity', modopts.overlayOpacity).show();
+ }
+
+ _change_item();
+ };
+
+ function _change_item() {
+ $("#mod_right, #mod_left, #mod_close, #mod_title").hide();
+
+ var href = modopts.itemArray[ modopts.itemCurrent ].href;
+
+ if (href.match(/#/)) {
+ var target = window.location.href.split('#')[0]; target = href.replace(target, ''); target = target.substr(target.indexOf('#'));
+
+ _set_content('' + $(target).html() + '
', modopts.frameWidth, modopts.frameHeight);
+
+ } else if (href.match(imageRegExp)) {
+ imagePreloader = new Image; imagePreloader.src = href;
+
+ if (imagePreloader.complete) {
+ _proceed_image();
+
+ } else {
+ $.fn.modbox.showLoading();
+
+ $(imagePreloader).unbind().bind('load', function() {
+ $(".mod_loading").hide();
+
+ _proceed_image();
+ });
+ }
+
+ } else if (href.match("iframe") || modelem.className.indexOf("iframe") >= 0) {
+ _set_content('', modopts.frameWidth, modopts.frameHeight);
+
+ } else {
+ $.get(href, function(data) {
+ _set_content( '' + data + '
', modopts.frameWidth, modopts.frameHeight );
+ });
+ }
+ };
+
+ function _proceed_image() {
+ if (modopts.imageScale) {
+ var w = $.fn.modbox.getViewport();
+
+ var r = Math.min(Math.min(w[0] - 36, imagePreloader.width) / imagePreloader.width, Math.min(w[1] - 60, imagePreloader.height) / imagePreloader.height);
+
+ var width = Math.round(r * imagePreloader.width);
+ var height = Math.round(r * imagePreloader.height);
+
+ } else {
+ var width = imagePreloader.width;
+ var height = imagePreloader.height;
+ }
+
+ _set_content(' ', width, height);
+ };
+
+ function _preload_neighbor_images() {
+ if ((modopts.itemArray.length -1) > modopts.itemCurrent) {
+ var href = modopts.itemArray[modopts.itemCurrent + 1].href;
+
+ if (href.match(imageRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+
+ if (modopts.itemCurrent > 0) {
+ var href = modopts.itemArray[modopts.itemCurrent -1].href;
+
+ if (href.match(imageRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+ };
+
+ function _set_content(value, width, height) {
+ modbusy = true;
+
+ var pad = modopts.padding;
+
+ if (isIE) {
+ $("#mod_content")[0].style.removeExpression("height");
+ $("#mod_content")[0].style.removeExpression("width");
+ }
+
+ if (pad > 0) {
+ width += pad * 2;
+ height += pad * 2;
+
+ $("#mod_content").css({
+ 'top' : pad + 'px',
+ 'right' : pad + 'px',
+ 'bottom' : pad + 'px',
+ 'left' : pad + 'px',
+ 'width' : 'auto',
+ 'height' : 'auto'
+ });
+
+ if (isIE) {
+ $("#mod_content")[0].style.setExpression('height', '(this.parentNode.clientHeight - 20)');
+ $("#mod_content")[0].style.setExpression('width', '(this.parentNode.clientWidth - 20)');
+ }
+
+ } else {
+ $("#mod_content").css({
+ 'top' : 0,
+ 'right' : 0,
+ 'bottom' : 0,
+ 'left' : 0,
+ 'width' : '100%',
+ 'height' : '100%'
+ });
+ }
+
+ if ($("#mod_outer").is(":visible") && width == $("#mod_outer").width() && height == $("#mod_outer").height()) {
+ $("#mod_content").fadeOut("fast", function() {
+ $("#mod_content").empty().append($(value)).fadeIn("normal", function() {
+ _finish();
+ });
+ });
+
+ return;
+ }
+
+ var w = $.fn.modbox.getViewport();
+
+ var itemLeft = (width + 36) > w[0] ? w[2] : (w[2] + Math.round((w[0] - width - 36) / 2));
+ var itemTop = (height + 50) > w[1] ? w[3] : (w[3] + Math.round((w[1] - height - 50) / 2));
+
+ var itemOpts = {
+ 'left': itemLeft,
+ 'top': itemTop,
+ 'width': width + 'px',
+ 'height': height + 'px'
+ };
+
+ if ($("#mod_outer").is(":visible")) {
+ $("#mod_content").fadeOut("normal", function() {
+ $("#mod_content").empty();
+ $("#mod_outer").animate(itemOpts, modopts.zoomSpeedChange, modopts.easingChange, function() {
+ $("#mod_content").append($(value)).fadeIn("normal", function() {
+ _finish();
+ });
+ });
+ });
+
+ } else {
+
+ if (modopts.zoomSpeedIn > 0 && modopts.itemArray[modopts.itemCurrent].orig !== undefined) {
+ $("#mod_content").empty().append($(value));
+
+ var orig_item = modopts.itemArray[modopts.itemCurrent].orig;
+ var orig_pos = $.fn.modbox.getPosition(orig_item);
+
+ $("#mod_outer").css({
+ 'left': (orig_pos.left - 18) + 'px',
+ 'top': (orig_pos.top - 18) + 'px',
+ 'width': $(orig_item).width(),
+ 'height': $(orig_item).height()
+ });
+
+ if (modopts.zoomOpacity) {
+ itemOpts.opacity = 'show';
+ }
+
+ $("#mod_outer").animate(itemOpts, modopts.zoomSpeedIn, modopts.easingIn, function() {
+ _finish();
+ });
+
+ } else {
+
+ $("#mod_content").hide().empty().append($(value)).show();
+ $("#mod_outer").css(itemOpts).fadeIn("normal", function() {
+ _finish();
+ });
+ }
+ }
+ };
+
+ function _set_navigation() {
+ if (modopts.itemCurrent != 0) {
+ $("#mod_left, #mod_left_ico").unbind().bind("click", function(e) {
+ e.stopPropagation();
+
+ modopts.itemCurrent--;
+ _change_item();
+
+ return false;
+ });
+
+ $("#mod_left").show();
+ }
+
+ if (modopts.itemCurrent != ( modopts.itemArray.length -1)) {
+ $("#mod_right, #mod_right_ico").unbind().bind("click", function(e) {
+ e.stopPropagation();
+
+ modopts.itemCurrent++;
+ _change_item();
+
+ return false;
+ });
+
+ $("#mod_right").show();
+ }
+ };
+
+ function _finish() {
+ _set_navigation();
+
+ _preload_neighbor_images();
+
+ $(document).keydown(function(e) {
+ if (e.keyCode == 27) {
+ $.fn.modbox.close();
+ $(document).unbind("keydown");
+
+ } else if(e.keyCode == 37 && modopts.itemCurrent != 0) {
+ modopts.itemCurrent--;
+ _change_item();
+ $(document).unbind("keydown");
+
+ } else if(e.keyCode == 39 && modopts.itemCurrent != (modopts.itemArray.length - 1)) {
+ modopts.itemCurrent++;
+ _change_item();
+ $(document).unbind("keydown");
+ }
+ });
+
+ if (modopts.centerOnScroll) {
+ $(window).bind("resize scroll", $.fn.modbox.scrollBox);
+ } else {
+ $("div#mod_outer").css("position", "absolute");
+ }
+
+ if (modopts.hideOnContentClick) {
+ $("#mod_wrap").click($.fn.modbox.close);
+ }
+
+ $("#mod_overlay, #mod_close").bind("click", $.fn.modbox.close);
+
+ $("#mod_close").show();
+
+ if (modopts.itemArray[ modopts.itemCurrent ].title !== undefined && modopts.itemArray[ modopts.itemCurrent ].title.length > 0) {
+ $('#mod_title div').html(modopts.itemArray[ modopts.itemCurrent ].title);
+ $('#mod_title').show();
+ }
+
+ if (modopts.overlayShow && isIE) {
+ $('embed, object, select', $('#mod_content')).css('visibility', 'visible');
+ }
+
+ if ($.isFunction(modopts.callbackOnShow)) {
+ modopts.callbackOnShow();
+ }
+
+ modbusy = false;
+ };
+
+ return this.unbind('click').click(_initialize);
+ };
+
+ $.fn.modbox.scrollBox = function() {
+ var pos = $.fn.modbox.getViewport();
+
+ $("#mod_outer").css('left', (($("#mod_outer").width() + 36) > pos[0] ? pos[2] : pos[2] + Math.round((pos[0] - $("#mod_outer").width() - 36) / 2)));
+ $("#mod_outer").css('top', (($("#mod_outer").height() + 50) > pos[1] ? pos[3] : pos[3] + Math.round((pos[1] - $("#mod_outer").height() - 50) / 2)));
+ };
+
+ $.fn.modbox.getNumeric = function(el, prop) {
+ return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
+ };
+
+ $.fn.modbox.getPosition = function(el) {
+ var pos = el.offset();
+
+ pos.top += $.fn.modbox.getNumeric(el, 'paddingTop');
+ pos.top += $.fn.modbox.getNumeric(el, 'borderTopWidth');
+
+ pos.left += $.fn.modbox.getNumeric(el, 'paddingLeft');
+ pos.left += $.fn.modbox.getNumeric(el, 'borderLeftWidth');
+
+ return pos;
+ };
+
+ $.fn.modbox.showIframe = function() {
+ $(".mod_loading").hide();
+ $("#mod_frame").show();
+ };
+
+ $.fn.modbox.getViewport = function() {
+ return [$(window).width(), $(window).height(), $(document).scrollLeft(), $(document).scrollTop() ];
+ };
+
+ $.fn.modbox.animateLoading = function() {
+ if (!$("#mod_loading").is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $("#mod_loading > div").css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ $.fn.modbox.showLoading = function() {
+ clearInterval(loadingTimer);
+
+ var pos = $.fn.modbox.getViewport();
+
+ $("#mod_loading").css({'left': ((pos[0] - 40) / 2 + pos[2]), 'top': ((pos[1] - 40) / 2 + pos[3])}).show();
+ $("#mod_loading").bind('click', $.fn.modbox.close);
+
+ loadingTimer = setInterval($.fn.modbox.animateLoading, 66);
+ };
+
+ $.fn.modbox.close = function() {
+ modbusy = true;
+
+ $(imagePreloader).unbind();
+
+ $("#mod_overlay, #mod_close").unbind();
+
+ if (modopts.hideOnContentClick) {
+ $("#mod_wrap").unbind();
+ }
+
+ $("#mod_close, .mod_loading, #mod_left, #mod_right, #mod_title").hide();
+
+ if (modopts.centerOnScroll) {
+ $(window).unbind("resize scroll");
+ }
+
+ __cleanup = function() {
+ $("#mod_overlay, #mod_outer").hide();
+
+ if (modopts.centerOnScroll) {
+ $(window).unbind("resize scroll");
+ }
+
+ if (isIE) {
+ $('embed, object, select').css('visibility', 'visible');
+ }
+
+ if ($.isFunction(modopts.callbackOnClose)) {
+ modopts.callbackOnClose();
+ }
+
+ modbusy = false;
+ };
+
+ if ($("#mod_outer").is(":visible") !== false) {
+ if (modopts.zoomSpeedOut > 0 && modopts.itemArray[modopts.itemCurrent].orig !== undefined) {
+ var orig_item = modopts.itemArray[modopts.itemCurrent].orig;
+ var orig_pos = $.fn.modbox.getPosition(orig_item);
+
+ var itemOpts = {
+ 'left': (orig_pos.left - 18) + 'px',
+ 'top': (orig_pos.top - 18) + 'px',
+ 'width': $(orig_item).width(),
+ 'height': $(orig_item).height()
+ };
+
+ if (modopts.zoomOpacity) {
+ itemOpts.opacity = 'hide';
+ }
+
+ $("#mod_outer").stop(false, true).animate(itemOpts, modopts.zoomSpeedOut, modopts.easingOut, __cleanup);
+
+ } else {
+ $("#mod_outer").stop(false, true).fadeOut("fast", __cleanup);
+ }
+
+ } else {
+ __cleanup();
+ }
+
+ return false;
+ };
+
+ $.fn.modbox.build = function() {
+ var html = '';
+
+ html += '
';
+
+ html += '';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ html += '
';
+
+ $(html).appendTo("body");
+
+ $('').appendTo('#mod_title');
+
+ if (isIE) {
+ $("#mod_inner").prepend('');
+ $("#mod_close, .mod_bg, .mod_title, .mod_ico").fixPNG();
+ }
+ };
+
+ $.fn.modbox.defaults = {
+ padding : 10,
+ imageScale : true,
+ zoomOpacity : false,
+ zoomSpeedIn : 0,
+ zoomSpeedOut : 0,
+ zoomSpeedChange : 300,
+ easingIn : 'swing',
+ easingOut : 'swing',
+ easingChange : 'swing',
+ frameWidth : 400,
+ frameHeight : 400,
+ overlayShow : true,
+ overlayOpacity : 0.3,
+ hideOnContentClick : false,
+ centerOnScroll : true,
+ itemArray : [],
+ callbackOnStart : null,
+ callbackOnShow : null,
+ callbackOnClose : null
+ };
+
+ $(document).ready(function() {
+ $.fn.modbox.build();
+ });
+
+})(jQuery);
\ No newline at end of file
diff --git a/themes/3nids/3nids/js/ui.init.js b/themes/3nids/3nids/js/ui.init.js
new file mode 100755
index 00000000..5a3b7122
--- /dev/null
+++ b/themes/3nids/3nids/js/ui.init.js
@@ -0,0 +1,139 @@
+/**
+ * Initialize jQuery UI and Gallery Plugin elements
+ */
+
+var short_forms = new Array(
+ "#gQuickSearchForm",
+ "#gAddTagForm",
+ "#gSearchForm"
+);
+
+$(document).ready(function() {
+ $(".fancyclass").fancybox();
+
+ // Initialize Superfish menus
+ $("ul.gMenu").addClass("sf-menu");
+ $('ul.sf-menu').superfish({
+ delay: 500,
+ animation: {
+ opacity:'show',
+ height:'show'
+ },
+ speed: 'fast'
+ });
+ $("#gSiteMenu").css("display", "block");
+
+ // Initialize status message effects
+ $("#gMessage li").gallery_show_message();
+
+ // Initialize dialogs
+ $("#gLoginLink").addClass("gDialogLink");
+ $(".gDialogLink").gallery_dialog();
+
+ // Initialize view menu
+ if ($("#gViewMenu").length) {
+ $("#gViewMenu ul").removeClass("gMenu").removeClass("sf-menu");
+ $("#gViewMenu a").addClass("ui-icon");
+ }
+
+ // Initialize short forms
+ for (var i in short_forms) {
+ short_form_init(short_forms[i]);
+ $(short_forms[i]).addClass("gShortForm");
+ }
+ $(".gShortForm input[type=text]").addClass("ui-corner-left");
+ $(".gShortForm input[type=submit]").addClass("ui-state-default ui-corner-right");
+
+ // Apply jQuery UI button css to submit inputs
+ $("input[type=submit]:not(.gShortForm input)").addClass("ui-state-default ui-corner-all");
+
+ // Apply styles and icon classes to gContextMenu
+ if ($(".gContextMenu").length) {
+ $(".gContextMenu li").addClass("ui-state-default");
+ $(".gContextMenu a").addClass("gButtonLink ui-icon-left");
+ $(".gContextMenu a").prepend(" ");
+ $(".gContextMenu a span").each(function() {
+ var iconClass = $(this).parent().attr("class").match(/ui-icon-.[^\s]+/).toString();
+ $(this).addClass(iconClass);
+ });
+ }
+
+ // Album view only
+ if ($("#gAlbumGrid").length) {
+ // Vertical align thumbnails/metadata in album grid
+ $(".gItem").gallery_valign();
+
+ // Initialize context menus
+ $(".gItem").hover(
+ function(){
+ // Insert invisible placeholder to hold the item's position in the grid
+ var placeHolder = $(this).clone();
+ $(placeHolder).attr("id", "gPlaceHolder");
+ $(placeHolder).css("visibility", "hidden");
+ $(this).after($(placeHolder));
+ // Style and position the item
+ $(this).addClass("gHoverItem");
+ var position = $(this).position();
+ $(this).css("position", "absolute");
+ $(this).css("top", position.top);
+ $(this).css("left", position.left);
+ $(this).css("z-index", "1000");
+ // Initialize the contextual menu
+ $(this).gallery_context_menu();
+ // Set height based on height of descendents
+ var title = $(this).find("h2");
+ var meta = $(this).find(".gMetadata");
+ var context_label = $(this).find(".gContextMenu li:first");
+ var item_ht = $(this).height();
+ var title_ht = $(title).gallery_height();
+ var meta_ht = $(meta).gallery_height();
+ var context_label_ht = $(context_label).gallery_height();
+ $(this).height(item_ht + title_ht + meta_ht + context_label_ht);
+ $(".fancyclass").fancybox();
+ },
+ function() {
+ // Reset item height, position, and z-index
+if ($(this).next().height()) {
+ var sib_height = $(this).next().height();
+ } else {
+ var sib_height = $(this).prev().height();
+ }
+ if ($.browser.msie && $.browser.version >= 8) {
+ sib_height = sib_height + 1;
+ }
+ $(this).css("height", sib_height);
+ $(this).css("position", "relative");
+ $(this).css("top", null);
+ $(this).css("left", null);
+ $(this).css("z-index", 1);
+ // Remove the placeholder and hover class from the item
+ $("#gPlaceHolder").remove();
+ $(this).removeClass("gHoverItem");
+ $(".fancyclass").fancybox();
+ }
+ );
+ }
+
+ // Photo/Item item view
+ if ($("#gItem").length) {
+ // Ensure the resized image fits within its container
+ $("#gItem").gallery_fit_photo();
+
+ // Initialize context menus
+ var resize = $("#gItem").gallery_get_photo();
+ $(resize).hover(function(){
+ $(this).gallery_context_menu();
+ });
+
+ // Add scroll effect for links to named anchors
+ $.localScroll({
+ queue: true,
+ duration: 1000,
+ hash: true
+ });
+ }
+
+ // Initialize button hover effect
+ $.fn.gallery_hover_init();
+
+});
diff --git a/themes/3nids/3nids/theme.info b/themes/3nids/3nids/theme.info
new file mode 100755
index 00000000..3acf7b7a
--- /dev/null
+++ b/themes/3nids/3nids/theme.info
@@ -0,0 +1,6 @@
+name = "3nids theme"
+description = "Default theme modified using jquery lightbox slideshow."
+version = 1
+author = "3nids"
+site = 1
+admin = 0
diff --git a/themes/3nids/3nids/thumbnail.png b/themes/3nids/3nids/thumbnail.png
new file mode 100755
index 00000000..3b7bcfec
Binary files /dev/null and b/themes/3nids/3nids/thumbnail.png differ
diff --git a/themes/3nids/3nids/views/album.html.php b/themes/3nids/3nids/views/album.html.php
new file mode 100755
index 00000000..e29ffe45
--- /dev/null
+++ b/themes/3nids/3nids/views/album.html.php
@@ -0,0 +1,76 @@
+
+ // @todo Set hover on AlbumGrid list items for guest users ?>
+
+ = $theme->album_top() ?>
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+ $children_all = $item->viewable()->children();
+ $theme->pagination = new Pagination();
+ $theme->pagination->initialize(array("query_string" => "page","total_items" => $children_count,"items_per_page" => $page_size,"style" => "classic"));
+ $children_offset = ($theme->pagination->current_page -1) * $page_size ; ?>
+
+
+ if (count($children)): ?>
+ for($i=0;$i<$children_offset;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+ foreach ($children as $i => $child): ?>
+ $item_class = "gPhoto"; ?>
+ if ($child->is_album()): ?>
+ $item_class = "gAlbum"; ?>
+ endif ?>
+
+ = $theme->thumb_top($child) ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ = $child->thumb_img(array("class" => "gThumbnail")) ?>
+ if ($user->admin): ?>
+ view/edit
+ endif ?>
+ else: ?>
+
+ = $child->thumb_img(array("class" => "gThumbnail")) ?>
+ = html::clean($child->title) ?>
+
+ endif ?>
+ = $theme->thumb_bottom($child) ?>
+ = $theme->context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?>
+ if ($child->is_photo() && module::is_active("comment") && module::is_active("comment_3nids")) :?>
+
+ endif ?>
+
+ endforeach ?>
+ for($i=$children_offset+$page_size;$i<$children_count;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+ else: ?>
+ if ($user->admin || access::can("add", $item)): ?>
+ $addurl = url::file("index.php/simple_uploader/app/$item->id") ?>
+ = t("There aren't any photos here yet! Add some .",
+ array("attrs" => html::mark_clean("href=\"$addurl\" class=\"gDialogLink\""))) ?>
+ else: ?>
+ = t("There aren't any photos here yet!") ?>
+ endif; ?>
+ endif; ?>
+
+= $theme->album_bottom() ?>
+
+= $theme->pager() ?>
diff --git a/themes/3nids/3nids/views/block.html.php b/themes/3nids/3nids/views/block.html.php
new file mode 100755
index 00000000..e8cff833
--- /dev/null
+++ b/themes/3nids/3nids/views/block.html.php
@@ -0,0 +1,10 @@
+
+ if ($anchor): ?>
+
+ endif ?>
+
+
= $title ?>
+
+ = $content ?>
+
+
diff --git a/themes/3nids/3nids/views/comments.html.php b/themes/3nids/3nids/views/comments.html.php
new file mode 100755
index 00000000..855be150
--- /dev/null
+++ b/themes/3nids/3nids/views/comments.html.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+ = $theme->css("yui/reset-fonts-grids.css") ?>
+ = $theme->css("superfish/css/superfish.css") ?>
+ = $theme->css("themeroller/ui.base.css") ?>
+ = $theme->css("screen.css") ?>
+ = $theme->script("jquery.js") ?>
+ = $theme->script("jquery.form.js") ?>
+ = $theme->script("jquery-ui.js") ?>
+ = $theme->script("gallery.common.js") ?>
+ /* MSG_CANCEL is required by gallery.dialog.js */ ?>
+
+ = $theme->script("gallery.ajax.js") ?>
+ = $theme->script("gallery.dialog.js") ?>
+ = $theme->script("gallery.form.js") ?>
+ = $theme->script("superfish/js/superfish.js") ?>
+ = $theme->script("jquery.localscroll.js") ?>
+ = $theme->script("jquery.easing.js") ?>
+ = $theme->script("jquery.fancybox.js") ?>
+ = $theme->script("ui.init.js") ?>
+= $theme->head() ?>
+
+
+
+ " id="gAddCommentButton"
+ class="gButtonLink ui-corner-all ui-icon-left ui-state-default right">
+
+ = t("Add a comment") ?>
+
+
+
+
diff --git a/themes/3nids/3nids/views/dynamic.html.php b/themes/3nids/3nids/views/dynamic.html.php
new file mode 100755
index 00000000..6b39a29e
--- /dev/null
+++ b/themes/3nids/3nids/views/dynamic.html.php
@@ -0,0 +1,78 @@
+
+
+ $children_all = $tag->items();
+ $theme->pagination = new Pagination();
+ $theme->pagination->initialize(array("query_string" => "page","total_items" => $children_count,"items_per_page" => $page_size,"style" => "classic"));
+ $children_offset = ($theme->pagination->current_page -1) * $page_size ; ?>
+
+
+
+ for($i=0;$i<$children_offset;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+
+ foreach ($children as $i => $child): ?>
+
+
+
+ = $theme->thumb_top($child) ?>
+ if (!($child->is_album())): ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ else: ?>
+
+ endif ?>
+
+
+ = $child->parent()->title ?>
+ if ($user->admin): ?>
+ view
+ endif ?>
+ else: ?>
+
+
+ = html::clean($child->title) ?>
+
+ endif ?>
+= $theme->thumb_bottom($child) ?>
+= $theme->context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?>
+ if ($child->is_photo() && module::is_active("comment") && module::is_active("comment_3nids")) :?>
+
+ endif ?>
+
+ endforeach ?>
+ for($i=$children_offset+$page_size;$i<$children_count;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+
+= $theme->dynamic_bottom() ?>
+
+= $theme->pager() ?>
diff --git a/themes/3nids/3nids/views/exif_dialog.html.php b/themes/3nids/3nids/views/exif_dialog.html.php
new file mode 100755
index 00000000..da681bb2
--- /dev/null
+++ b/themes/3nids/3nids/views/exif_dialog.html.php
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ for ($i = 0; $i < count($details); $i++): ?>
+
+
+ = $details[$i]["caption"] ?>
+
+
+ = html::clean($details[$i]["value"]) ?>
+
+ if (!empty($details[++$i])): ?>
+
+ = $details[$i]["caption"] ?>
+
+
+ = html::clean($details[$i]["value"]) ?>
+
+ else: ?>
+
+ endif ?>
+
+ endfor ?>
+
+
+
+
+
+
diff --git a/themes/3nids/3nids/views/image_block_block.html.php b/themes/3nids/3nids/views/image_block_block.html.php
new file mode 100755
index 00000000..31d06839
--- /dev/null
+++ b/themes/3nids/3nids/views/image_block_block.html.php
@@ -0,0 +1,17 @@
+
+
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$item->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$item->id}") . ";;comment_count::" . comment_3nids::count($item) . ";;" ;} ?>
+
+
+
diff --git a/themes/3nids/3nids/views/movie.html.php b/themes/3nids/3nids/views/movie.html.php
new file mode 100755
index 00000000..def4b0cf
--- /dev/null
+++ b/themes/3nids/3nids/views/movie.html.php
@@ -0,0 +1,37 @@
+
+
+ = $theme->photo_top() ?>
+
+ /*
+
+*/ ?>
+
+ = $item->movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
+
+
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+
+ = $theme->context_menu($item, "#gMovieId-{$item->id}") ?>
+
diff --git a/themes/3nids/3nids/views/page.html.php b/themes/3nids/3nids/views/page.html.php
new file mode 100755
index 00000000..a7ad8ddb
--- /dev/null
+++ b/themes/3nids/3nids/views/page.html.php
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+ if ($page_title): ?>
+ = $page_title ?>
+ else: ?>
+ if ($theme->item()): ?>
+ if ($theme->item()->is_album()): ?>
+ = t("Gallery :: %album_title", array("album_title" => $theme->item()->title)) ?>
+ elseif ($theme->item()->is_photo()): ?>
+ = t("Gallery :: %photo_title", array("photo_title" => $theme->item()->title)) ?>
+ else: ?>
+ = t("Gallery :: %movie_title", array("movie_title" => $theme->item()->title)) ?>
+ endif ?>
+ elseif ($theme->tag()): ?>
+ = t("Gallery Tag :: %tag_title", array("tag_title" => $theme->tag()->name)) ?>
+ else: /* Not an item, not a tag, no page_title specified. Help! */ ?>
+ = t("Gallery") ?>
+ endif ?>
+ endif ?>
+
+ " type="image/x-icon" />
+ = $theme->css("yui/reset-fonts-grids.css") ?>
+ = $theme->css("superfish/css/superfish.css") ?>
+ = $theme->css("themeroller/ui.base.css") ?>
+ = $theme->css("screen.css") ?>
+ = $theme->css("jquery.fancybox.css") ?>
+
+ if ($theme->page_type == 'album'): ?>
+ if ($thumb_proportion != 1): ?>
+ $new_width = $thumb_proportion * 180 ?>
+ $new_height = $thumb_proportion * 180 ?>
+
+ endif ?>
+ endif ?>
+ = $theme->script("jquery.js") ?>
+ = $theme->script("jquery.form.js") ?>
+ = $theme->script("jquery-ui.js") ?>
+ = $theme->script("gallery.common.js") ?>
+ /* MSG_CANCEL is required by gallery.dialog.js */ ?>
+
+ = $theme->script("gallery.ajax.js") ?>
+ = $theme->script("gallery.dialog.js") ?>
+ = $theme->script("gallery.form.js") ?>
+ = $theme->script("superfish/js/superfish.js") ?>
+ = $theme->script("jquery.localscroll.js") ?>
+ = $theme->script("jquery.easing.js") ?>
+ = $theme->script("jquery.fancybox.js") ?>
+ = $theme->script("ui.init.js") ?>
+
+ /* These are page specific, but if we put them before $theme->head() they get combined */ ?>
+ if ($theme->page_type == "photo"): ?>
+ = $theme->script("jquery.scrollTo.js") ?>
+ = $theme->script("gallery.show_full_size.js") ?>
+ elseif ($theme->page_type == "movie"): ?>
+ = $theme->script("flowplayer.js") ?>
+ endif ?>
+
+ = $theme->head() ?>
+
+
+ body_attributes() ?>>
+ = $theme->page_top() ?>
+
+ = $theme->site_status() ?>
+
+
+
+
+
+ = $theme->messages() ?>
+ = $content ?>
+
+
+
+
+
+
+
+ = $theme->page_bottom() ?>
+
+
diff --git a/themes/3nids/3nids/views/pager.html.php b/themes/3nids/3nids/views/pager.html.php
new file mode 100755
index 00000000..69db1dfa
--- /dev/null
+++ b/themes/3nids/3nids/views/pager.html.php
@@ -0,0 +1,43 @@
+
+ // See http://docs.kohanaphp.com/libraries/pagination ?>
+
diff --git a/themes/3nids/3nids/views/photo.html.php b/themes/3nids/3nids/views/photo.html.php
new file mode 100755
index 00000000..d387e3ce
--- /dev/null
+++ b/themes/3nids/3nids/views/photo.html.php
@@ -0,0 +1,57 @@
+
+
+ if (access::can("view_full", $theme->item())): ?>
+
+
+ endif ?>
+
+ = $theme->photo_top() ?>
+
+
+
+
+
+
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+
+
diff --git a/themes/3nids/3nids/views/search.html.php b/themes/3nids/3nids/views/search.html.php
new file mode 100755
index 00000000..e28fa55a
--- /dev/null
+++ b/themes/3nids/3nids/views/search.html.php
@@ -0,0 +1,80 @@
+
+ // @todo Set hover on AlbumGrid list items ?>
+
+ list($children_count_true, $children_all) = search::search($q,1000,0);
+ $theme->pagination = new Pagination();
+ $theme->pagination->initialize(array("query_string" => "page","total_items" => $children_count_true,"items_per_page" => $page_size,"style" => "classic"));
+ $children_offset = ($theme->pagination->current_page -1) * $page_size ; ?>
+
+
+
= t("Results for %term ", array("term" => $q)) ?>
+
+ if (count($items)): ?>
+
+ for($i=0;$i<$children_offset;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+ foreach ($items as $child): ?>
+
+ = $theme->thumb_top($child) ?>
+ if (!($child->is_album())): ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ else: ?>
+
+ endif ?>
+
+
+ = $child->parent()->title ?>
+ if ($user->admin): ?>
+ view
+ endif ?>
+ else: ?>
+
+
+ = html::clean($child->title) ?>
+
+ endif ?>
+= $theme->thumb_bottom($child) ?>
+= $theme->context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?>
+ if ($child->is_photo() && module::is_active("comment") && module::is_active("comment_3nids")) :?>
+
+ endif ?>
+
+ endforeach ?>
+ for($i=$children_offset+$page_size;$i<$children_count;$i++): ?>
+ $child = $children_all[$i] ?>
+ if ($child->is_photo()): ?>
+ $fancymodule = ""; ?>
+ if (module::is_active("exif")){$fancymodule .= "exif::" . url::site("exif/show/{$child->id}") . ";;";} ?>
+ if (module::is_active("comment") && module::is_active("comment_3nids")){$fancymodule .= "comment::" . url::site("comments_3nids?item_id={$child->id}") . ";;comment_count::" . comment_3nids::count($child) . ";;" ;} ?>
+
+ endif ?>
+ endfor ?>
+
+ = $theme->pager() ?>
+
+ else: ?>
+
+ = t("No results found for %term ", array("term" => $q)) ?>
+
+
+ endif; ?>
+
diff --git a/themes/3nids/3nids/views/sidebar.html.php b/themes/3nids/3nids/views/sidebar.html.php
new file mode 100755
index 00000000..928ecb93
--- /dev/null
+++ b/themes/3nids/3nids/views/sidebar.html.php
@@ -0,0 +1,16 @@
+
+= $theme->sidebar_top() ?>
+
+
+
+
+= $theme->sidebar_blocks() ?>
+= $theme->sidebar_bottom() ?>
diff --git a/themes/3nids/README b/themes/3nids/README
new file mode 100755
index 00000000..f5f8756d
--- /dev/null
+++ b/themes/3nids/README
@@ -0,0 +1,33 @@
+This is a theme for gallery3.
+It uses jquery lightbox slideshow (fancybox) to display images, and includes a tagsmap module (originally from rWatcher).
+
+*********
+Demo @ http://gallery.3nids.ch
+
+*********
+Requirements:
+- Gallery 3 last experimental version @ http://github.com/gallery/gallery3
+- Tag module activated (if want to use tagsmap)
+- Comment and Comments for 3nids themes modules activated (if you want to use comments)
+
+*********
+Installation:
+
+1. Copy the theme folder (3nids) into gallery3/themes directory.
+2. Copy lib folder into gallery3 directory (it changes the themeroller).
+3. Copy modules folder into gallery3 directory. It includes tagsmap module.
+
+*********
+Use:
+This theme displays full size images. So be carefull to upload not too large images!
+The theme uses the tagsmap module which has been enhanced.
+
+If you want to separate geotag from others, name those with the "map." prefix., the "map." prefix will not be displayed on the map.
+If you want to remove the prefix in the tag cloud sidebar, wou will have to update in gallery3/modules/tag/helpers/tag.php the popular_tags function:
+ static function popular_tags($count) {
+ return ORM::factory("tag")
+ ->orderby("count", "DESC")
+ ->notregex("name","map\.")
+ ->limit($count)
+ ->find_all();
+ }
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_0_333333_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_333333_40x100.png
new file mode 100755
index 00000000..2f2c7a45
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_333333_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_0_484848_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_484848_40x100.png
new file mode 100755
index 00000000..37979abe
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_484848_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_0_aaaaaa_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100755
index 00000000..5b5dab2a
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_100_000000_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_000000_40x100.png
new file mode 100755
index 00000000..abdc0108
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_000000_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_100_333333_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_333333_40x100.png
new file mode 100755
index 00000000..2f2c7a45
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_333333_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_100_484848_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_484848_40x100.png
new file mode 100755
index 00000000..37979abe
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_484848_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_100_b30000_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_b30000_40x100.png
new file mode 100755
index 00000000..121651a0
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_100_b30000_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_flat_55_fbec88_40x100.png b/themes/3nids/lib/themeroller/images/ui-bg_flat_55_fbec88_40x100.png
new file mode 100755
index 00000000..47acaadd
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_flat_55_fbec88_40x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-bg_highlight-hard_100_333333_1x100.png b/themes/3nids/lib/themeroller/images/ui-bg_highlight-hard_100_333333_1x100.png
new file mode 100755
index 00000000..254bb228
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-bg_highlight-hard_100_333333_1x100.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-icons_333333_256x240.png b/themes/3nids/lib/themeroller/images/ui-icons_333333_256x240.png
new file mode 100755
index 00000000..379a4064
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-icons_333333_256x240.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-icons_f9bd01_256x240.png b/themes/3nids/lib/themeroller/images/ui-icons_f9bd01_256x240.png
new file mode 100755
index 00000000..1619b868
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-icons_f9bd01_256x240.png differ
diff --git a/themes/3nids/lib/themeroller/images/ui-icons_f9db01_256x240.png b/themes/3nids/lib/themeroller/images/ui-icons_f9db01_256x240.png
new file mode 100755
index 00000000..af18dccc
Binary files /dev/null and b/themes/3nids/lib/themeroller/images/ui-icons_f9db01_256x240.png differ
diff --git a/themes/3nids/lib/themeroller/ui.theme.css b/themes/3nids/lib/themeroller/ui.theme.css
new file mode 100755
index 00000000..e48cfd1e
--- /dev/null
+++ b/themes/3nids/lib/themeroller/ui.theme.css
@@ -0,0 +1,406 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&bgColorDefault=333333&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=484848&bgTextureHeader=01_flat.png&bgImgOpacityHeader=100&borderColorHeader=e8e8e8&fcHeader=e8e8e8&iconColorHeader=f9bd01&bgColorContent=333333&bgTextureContent=01_flat.png&bgImgOpacityContent=100&borderColorContent=e8e8e8&fcContent=e8e8e8&iconColorContent=f9db01&bgColorDefault=333333&bgTextureDefault=01_flat.png&bgImgOpacityDefault=100&borderColorDefault=f9db01&fcDefault=FFFFCC&iconColorDefault=f9db01&bgColorHover=000000&bgTextureHover=01_flat.png&bgImgOpacityHover=100&borderColorHover=f9db01&fcHover=e8e8e8&iconColorHover=f9db01&bgColorActive=333333&bgTextureActive=04_highlight_hard.png&bgImgOpacityActive=100&borderColorActive=e8e8e8&fcActive=e8e8e8&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=333333&fcHighlight=333333&iconColorHighlight=333333&bgColorError=b30000&bgTextureError=01_flat.png&bgImgOpacityError=100&borderColorError=f9db01&fcError=f9db01&iconColorError=f9db01&bgColorOverlay=484848&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=100&bgColorShadow=333333&bgTextureShadow=01_flat.png&bgImgOpacityShadow=100&opacityShadow=50&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #e8e8e8; background: #333333 url(images/ui-bg_flat_100_333333_40x100.png) 50% 50% repeat-x; color: #e8e8e8; }
+.ui-widget-content a { color: #e8e8e8; }
+.ui-widget-header { border: 1px solid #e8e8e8; background: #484848 url(images/ui-bg_flat_100_484848_40x100.png) 50% 50% repeat-x; color: #e8e8e8; font-weight: bold; }
+.ui-widget-header a { color: #e8e8e8; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #f9db01; background: #333333 url(images/ui-bg_flat_100_333333_40x100.png) 50% 50% repeat-x; font-weight: bold; color: #FFFFCC; outline: none; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #FFFFCC; text-decoration: none; outline: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #f9db01; background: #000000 url(images/ui-bg_flat_100_000000_40x100.png) 50% 50% repeat-x; font-weight: bold; color: #e8e8e8; outline: none; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #e8e8e8; text-decoration: none; outline: none; }
+.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #e8e8e8; background: #333333 url(images/ui-bg_highlight-hard_100_333333_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e8e8e8; outline: none; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e8e8e8; outline: none; text-decoration: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #333333; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #333333; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #333333; }
+.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #f9db01; background: #b30000 url(images/ui-bg_flat_100_b30000_40x100.png) 50% 50% repeat-x; color: #f9db01; }
+.ui-state-error a, .ui-widget-content .ui-state-error a { color: #f9db01; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #f9db01; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_f9db01_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_f9db01_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_f9db01_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_f9db01_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_333333_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_f9db01_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; }
+.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
+.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
+.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
+.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #484848 url(images/ui-bg_flat_0_484848_40x100.png) 50% 50% repeat-x; opacity: 100;filter:Alpha(Opacity=100); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #333333 url(images/ui-bg_flat_100_333333_40x100.png) 50% 50% repeat-x; opacity: .50;filter:Alpha(Opacity=50); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
+.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/* Dialog
+----------------------------------*/
+.ui-dialog { position: relative; padding: .2em; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
+----------------------------------*/
+.ui-tabs { padding: .2em; zoom: 1; }
+.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
diff --git a/themes/3nids/modules/comment_3nids/controllers/comments_3nids.php b/themes/3nids/modules/comment_3nids/controllers/comments_3nids.php
new file mode 100755
index 00000000..965762d3
--- /dev/null
+++ b/themes/3nids/modules/comment_3nids/controllers/comments_3nids.php
@@ -0,0 +1,192 @@
+input->get('item_id');
+ $item = ORM::factory("item", $item_id);
+ access::required("view", $item);
+
+ $comments = ORM::factory("comment")
+ ->where("item_id", $item->id)
+ ->where("state", "published")
+ ->orderby("created", "ASC")
+ ->find_all();
+
+ switch (rest::output_format()) {
+ case "json":
+ foreach ($comments as $comment) {
+ $data[] = array(
+ "id" => $comment->id,
+ "author_name" => html::clean($comment->author_name()),
+ "created" => $comment->created,
+ "text" => nl2br(html::purify($comment->text)));
+ }
+ print json_encode($data);
+ break;
+
+ case "html":
+ $view = new Theme_View("comments.html", "page");
+ $view->comments = $comments;
+ $view->item_id = $item_id;
+ $view->thumb = $item->thumb_url();
+ print $view;
+ break;
+ }
+ }
+
+ /**
+ * Add a new comment to the collection.
+ * @see REST_Controller::_create($resource)
+ */
+ public function _create($comment) {
+ $item = ORM::factory("item", $this->input->post("item_id"));
+ access::required("view", $item);
+
+ $form = comment_3nids::get_add_form($item);
+ $valid = $form->validate();
+ if ($valid) {
+ if (user::active()->guest && !$form->add_comment->inputs["name"]->value) {
+ $form->add_comment->inputs["name"]->add_error("missing", 1);
+ $valid = false;
+ }
+
+ if (!$form->add_comment->text->value) {
+ $form->add_comment->text->add_error("missing", 1);
+ $valid = false;
+ }
+ }
+
+ if ($valid) {
+ $comment = comment::create(
+ $item, user::active(),
+ $form->add_comment->text->value,
+ $form->add_comment->inputs["name"]->value,
+ $form->add_comment->email->value,
+ $form->add_comment->url->value);
+
+ $active = user::active();
+ if ($active->guest) {
+ $form->add_comment->inputs["name"]->value("");
+ $form->add_comment->email->value("");
+ $form->add_comment->url->value("");
+ } else {
+ $form->add_comment->inputs["name"]->value($active->full_name);
+ $form->add_comment->email->value($active->email);
+ $form->add_comment->url->value($active->url);
+ }
+ }
+ url::redirect(url::site("comments_3nids?item_id=".$item->id));
+}
+ /**
+ * Display an existing comment.
+ * @todo Set proper Content-Type in a central place (REST_Controller::dispatch?).
+ * @see REST_Controller::_show($resource)
+ */
+ public function _show($comment) {
+ $item = ORM::factory("item", $comment->item_id);
+ access::required("view", $item);
+ if ($comment->state != "published") {
+ return;
+ }
+
+ if (rest::output_format() == "json") {
+ print json_encode(
+ array("result" => "success",
+ "data" => array(
+ "id" => $comment->id,
+ "author_name" => html::clean($comment->author_name()),
+ "created" => $comment->created,
+ "text" => nl2br(html::purify($comment->text)))));
+ } else {
+ $view = new Theme_View("comment.html", "fragment");
+ $view->comment = $comment;
+ print $view;
+ }
+ }
+
+ /**
+ * Change an existing comment.
+ * @see REST_Controller::_update($resource)
+ */
+ public function _update($comment) {
+ $item = ORM::factory("item", $comment->item_id);
+ access::required("view", $item);
+ access::required("edit", $item);
+
+ $form = comment_3nids::get_edit_form($comment);
+ if ($form->validate()) {
+ $comment->guest_name = $form->edit_comment->inputs["name"]->value;
+ $comment->guest_email = $form->edit_comment->email->value;
+ $comment->url = $form->edit_comment->url->value;
+ $comment->text = $form->edit_comment->text->value;
+ $comment->save();
+
+ print json_encode(
+ array("result" => "success",
+ "resource" => url::site("comments/{$comment->id}")));
+ } else {
+ print json_encode(
+ array("result" => "error",
+ "html" => $form->__toString()));
+ }
+ }
+
+ /**
+ * Delete existing comment.
+ * @see REST_Controller::_delete($resource)
+ */
+ public function _delete($comment) {
+ $item = ORM::factory("item", $comment->item_id);
+ access::required("view", $item);
+ access::required("edit", $item);
+
+ $comment->delete();
+ print json_encode(array("result" => "success"));
+ }
+
+ /**
+ * Present a form for adding a new comment to this item or editing an existing comment.
+ * @see REST_Controller::form_add($resource)
+ */
+ public function _form_add($item_id) {
+ $item = ORM::factory("item", $item_id);
+ access::required("view", $item);
+
+ print comment_3nids::get_add_form($item);
+ }
+
+ /**
+ * Present a form for editing an existing comment.
+ * @see REST_Controller::form_edit($resource)
+ */
+ public function _form_edit($comment) {
+ if (!user::active()->admin) {
+ access::forbidden();
+ }
+ print comment_3nids::get_edit_form($comment);
+ }
+}
diff --git a/themes/3nids/modules/comment_3nids/helpers/comment_3nids.php b/themes/3nids/modules/comment_3nids/helpers/comment_3nids.php
new file mode 100755
index 00000000..a35fb450
--- /dev/null
+++ b/themes/3nids/modules/comment_3nids/helpers/comment_3nids.php
@@ -0,0 +1,128 @@
+where("item_id", $item->id)
+ ->where("state", "published")
+ ->orderby("created", "DESC")
+ ->find_all();
+
+ return $comments->count();
+ }
+
+ /**
+ * Create a new comment.
+ * @param Item_MOdel $item the parent item
+ * @param User_Model $author the author User_Model
+ * @param string $text comment body
+ * @param string $guest_name guest's name (if the author is a guest user, default empty)
+ * @param string $guest_email guest's email (if the author is a guest user, default empty)
+ * @param string $guest_url guest's url (if the author is a guest user, default empty)
+ * @return Comment_Model
+ */
+ static function create($item, $author, $text, $guest_name=null,
+ $guest_email=null, $guest_url=null) {
+ $comment = ORM::factory("comment");
+ $comment->author_id = $author->id;
+ $comment->guest_email = $guest_email;
+ $comment->guest_name = $guest_name;
+ $comment->guest_url = $guest_url;
+ $comment->item_id = $item->id;
+ $comment->text = $text;
+ $comment->state = "published";
+
+ // These values are useful for spam fighting, so save them with the comment.
+ $input = Input::instance();
+ $comment->server_http_accept = substr($input->server("HTTP_ACCEPT"), 0, 128);
+ $comment->server_http_accept_charset = substr($input->server("HTTP_ACCEPT_CHARSET"), 0, 64);
+ $comment->server_http_accept_encoding = substr($input->server("HTTP_ACCEPT_ENCODING"), 0, 64);
+ $comment->server_http_accept_language = substr($input->server("HTTP_ACCEPT_LANGUAGE"), 0, 64);
+ $comment->server_http_connection = substr($input->server("HTTP_CONNECTION"), 0, 64);
+ $comment->server_http_host = substr($input->server("HTTP_HOST"), 0, 64);
+ $comment->server_http_referer = substr($input->server("HTTP_REFERER"), 0, 255);
+ $comment->server_http_user_agent = substr($input->server("HTTP_USER_AGENT"), 0, 128);
+ $comment->server_query_string = substr($input->server("QUERY_STRING"), 0, 64);
+ $comment->server_remote_addr = substr($input->server("REMOTE_ADDR"), 0, 32);
+ $comment->server_remote_host = substr($input->server("REMOTE_HOST"), 0, 64);
+ $comment->server_remote_port = substr($input->server("REMOTE_PORT"), 0, 16);
+ $comment->save();
+
+ return $comment;
+ }
+
+ static function get_add_form($item) {
+ $form = new Forge("comments_3nids?item_id=".$item->id, "", "post", array("id" => "gAddCommentForm"));
+ $group = $form->group("add_comment")->label(t("Add comment"));
+ $group->input("name") ->label(t("Name")) ->id("gAuthor");
+ $group->input("email") ->label(t("Email (hidden)")) ->id("gEmail");
+ $group->input("url") ->label(t("Website (hidden)"))->id("gUrl");
+ $group->textarea("text")->label(t("Comment")) ->id("gText");
+ $group->hidden("item_id")->value($item->id);
+ module::event("comment_add_form", $form);
+ $group->submit("")->value(t("Add")) ->class("gButtonLink ui-corner-all ui-icon-left ui-state-default");
+
+ $active = user::active();
+ if (!$active->guest) {
+ $group->inputs["name"]->value($active->full_name)->disabled("disabled");
+ $group->email->value($active->email)->disabled("disabled");
+ $group->url->value($active->url)->disabled("disabled");
+ } else {
+ $group->inputs["name"]->error_messages("missing", t("You must provide a name"));
+ }
+ $group->text->error_messages("missing", t("You must provide a comment"));
+
+ return $form;
+ }
+
+ static function get_edit_form($comment) {
+ $form = new Forge("comments/{$comment->id}?_method=put", "", "post",
+ array("id" => "gEditCommentForm"));
+ $group = $form->group("edit_comment")->label(t("Edit comment"));
+ $group->input("name") ->label(t("Author")) ->id("gAuthor");
+ $group->input("email") ->label(t("Email (hidden)")) ->id("gEmail");
+ $group->input("url") ->label(t("Website (hidden)"))->id("gUrl");
+ $group->textarea("text")->label(t("Comment")) ->id("gText");
+ $group->submit("")->value(t("Edit"));
+
+ $group->text = $comment->text;
+ $author = $comment->author();
+ if ($author->guest) {
+ $group->inputs["name"]->value = $comment->guest_name;
+ $group->email = $comment->guest_email;
+ $group->url = $comment->guest_url;
+ } else {
+ $group->inputs["name"]->value($author->full_name)->disabled("disabled");
+ $group->email->value($author->email)->disabled("disabled");
+ $group->url->value($author->url)->disabled("disabled");
+ }
+ return $form;
+ }
+}
+
diff --git a/themes/3nids/modules/comment_3nids/module.info b/themes/3nids/modules/comment_3nids/module.info
new file mode 100755
index 00000000..5d51edfc
--- /dev/null
+++ b/themes/3nids/modules/comment_3nids/module.info
@@ -0,0 +1,3 @@
+name = "Comments for 3nids theme"
+description = "Allows the use of comments within 3nids theme"
+version = 1
diff --git a/themes/3nids/modules/tagsmap/controllers/admin_tagsmap.php b/themes/3nids/modules/tagsmap/controllers/admin_tagsmap.php
new file mode 100755
index 00000000..34ccf7bc
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/controllers/admin_tagsmap.php
@@ -0,0 +1,238 @@
+content = new View("admin_tagsmap.html");
+
+ // Generate a form for Google Maps Settings.
+ $view->content->googlemaps_form = $this->_get_googlemaps_form();
+
+ // Generate a list of tags to display.
+ $query = ORM::factory("tag");
+ $view->content->tags = $query->orderby("name", "ASC")->find_all();
+
+ // Display the page.
+ print $view;
+ }
+
+ public function edit_gps($tag_id) {
+ // Generate a new admin page to edit gps data for the tag specified by $tag_id.
+
+ // Determine the name of the tag.
+ $tagName = ORM::factory("tag")
+ ->where("id", $tag_id)
+ ->find_all();
+
+ // Set up the admin page.
+ $view = new Admin_View("admin.html");
+ $view->content = new View("admin_tagsmap_edit.html");
+ $view->content->tagsmapedit_form = $this->_get_tagsgpsedit_form($tag_id);
+ $view->content->tag_name = $tagName[0]->name;
+ print $view;
+ }
+
+ public function orphaned_tags() {
+ // Locate and delete any orphaned GPS data.
+ $int_deleted_records = 0;
+
+ // Generate a list of all tags with GPS data.
+ $existingGPS = ORM::factory("tags_gps")
+ ->find_all();
+
+ // Loop through each record and see if a corresponding tag exists.
+ foreach ($existingGPS as $oneGPS) {
+ $oneTag = ORM::factory("tag")
+ ->where("id", $oneGPS->tag_id)
+ ->find_all();
+
+ // If the tag no longer exists then delete the record.
+ if (count($oneTag) == 0) {
+ // Delete the record.
+ ORM::factory("tags_gps")
+ ->where("tag_id", $oneGPS->tag_id)
+ ->delete_all();
+ $int_deleted_records++;
+ }
+ }
+
+ // Redirect back to the main screen and display a "success" message.
+ message::success($int_deleted_records . t(" Orphaned Record(s) have been deleted."));
+ url::redirect("admin/tagsmap");
+ }
+
+ public function confirm_delete_gps($tag_id) {
+ // Make sure the user meant to hit the delete button.
+ $view = new Admin_View("admin.html");
+ $view->content = new View("admin_tagsmap_delete.html");
+ $view->content->tag_id = $tag_id;
+
+ // Determine the name of the tag.
+ $tagName = ORM::factory("tag")
+ ->where("id", $tag_id)
+ ->find_all();
+ $view->content->tag_name = $tagName[0]->name;
+
+ print $view;
+ }
+
+ public function delete_gps($tag_id) {
+ // Delete the GSP data associated with a tag.
+
+ // Delete the record.
+ ORM::factory("tags_gps")
+ ->where("tag_id", $tag_id)
+ ->delete_all();
+
+ // Redirect back to the main screen and display a "success" message.
+ message::success(t("Your Settings Have Been Saved."));
+ url::redirect("admin/tagsmap");
+ }
+
+ private function _get_tagsgpsedit_form($tag_id) {
+ // Make a new form for editing GPS data associated with a tag ($tag_id).
+ $form = new Forge("admin/tagsmap/savegps", "", "post",
+ array("id" => "gTagsMapAdminForm"));
+
+ // Add a few input boxes for GPS and Description
+ $tagsgps_group = $form->group("TagsMapGPS");
+ $tagsgps_group->hidden("tag_id")->value($tag_id);
+
+ // Check and see if this ID already has GPS data, then create
+ // input boxes to either update it or enter in new information.
+ $existingGPS = ORM::factory("tags_gps")
+ ->where("tag_id", $tag_id)
+ ->find_all();
+ if (count($existingGPS) == 0) {
+ $tagsgps_group->input("gps_latitude")->label(t("Latitude"))->value();
+ $tagsgps_group->input("gps_longitude")->label(t("Longitude"))->value();
+ $tagsgps_group->textarea("gps_description")->label(t("Description"))->value();
+ } else {
+ $tagsgps_group->input("gps_latitude")->label(t("Latitude"))->value($existingGPS[0]->latitude);
+ $tagsgps_group->input("gps_longitude")->label(t("Longitude"))->value($existingGPS[0]->longitude);
+ $tagsgps_group->textarea("gps_description")->label(t("Description"))->value($existingGPS[0]->description);
+ }
+
+ // Add a save button to the form.
+ $tagsgps_group->submit("SaveGPS")->value(t("Save"));
+
+ // Return the newly generated form.
+ return $form;
+ }
+
+ public function savegps() {
+ // Save the GPS coordinates to the database.
+
+ // Prevent Cross Site Request Forgery
+ access::verify_csrf();
+
+ // Figure out the values of the text boxes
+ $str_tagid = Input::instance()->post("tag_id");
+ $str_latitude = Input::instance()->post("gps_latitude");
+ $str_longitude = Input::instance()->post("gps_longitude");
+ $str_description = Input::instance()->post("gps_description");
+
+ // Save to database.
+ // Check and see if this ID already has GPS data,
+ // Update it if it does, create a new record if it doesn't.
+ $existingGPS = ORM::factory("tags_gps")
+ ->where("tag_id", $str_tagid)
+ ->find_all();
+ if (count($existingGPS) == 0) {
+ $newgps = ORM::factory("tags_gps");
+ $newgps->tag_id = $str_tagid;
+ $newgps->latitude = $str_latitude;
+ $newgps->longitude = $str_longitude;
+ $newgps->description = $str_description;
+ $newgps->save();
+ } else {
+ $updatedGPS = ORM::factory("tags_gps", $existingGPS[0]->id);
+ $updatedGPS->tag_id = $str_tagid;
+ $updatedGPS->latitude = $str_latitude;
+ $updatedGPS->longitude = $str_longitude;
+ $updatedGPS->description = $str_description;
+ $updatedGPS->save();
+ }
+
+ // Redirect back to the main screen and display a "success" message.
+ message::success(t("Your Settings Have Been Saved."));
+ url::redirect("admin/tagsmap");
+ }
+
+ private function _get_googlemaps_form() {
+ // Make a new form for inputing information associated with google maps.
+ $form = new Forge("admin/tagsmap/savemapprefs", "", "post",
+ array("id" => "gTagsMapAdminForm"));
+
+ // Input box for the Maps API Key
+ $googlemap_group = $form->group("GoogleMapsKey");
+ $googlemap_group->input("google_api_key")
+ ->label(t("Google Maps API Key"))
+ ->value(module::get_var("tagsmap", "googlemap_api_key"));
+
+ // Input boxes for the Maps starting location map type and zoom.
+ $startingmap_group = $form->group("GoogleMapsPos");
+ $startingmap_group->input("google_starting_latitude")
+ ->label(t("Starting Latitude"))
+ ->value(module::get_var("tagsmap", "googlemap_latitude"));
+ $startingmap_group->input("google_starting_longitude")
+ ->label(t("Starting Longitude"))
+ ->value(module::get_var("tagsmap", "googlemap_longitude"));
+ $startingmap_group->input("google_default_zoom")
+ ->label(t("Default Zoom Level"))
+ ->value(module::get_var("tagsmap", "googlemap_zoom"));
+ $startingmap_group->input("google_default_type")
+ ->label(t("Default Map Type") . " (G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP, G_PHYSICAL_MAP, G_SATELLITE_3D_MAP)")
+ ->value(module::get_var("tagsmap", "googlemap_type"));
+
+ // Add a save button to the form.
+ $form->submit("SaveSettings")->value(t("Save"));
+
+ // Return the newly generated form.
+ return $form;
+ }
+
+ public function savemapprefs() {
+ // Save information associated with Google Maps to the database.
+
+ // Prevent Cross Site Request Forgery
+ access::verify_csrf();
+
+ // Figure out the values of the text boxes
+ $str_googlekey = Input::instance()->post("google_api_key");
+ $str_googlelatitude = Input::instance()->post("google_starting_latitude");
+ $str_googlelongitude = Input::instance()->post("google_starting_longitude");
+ $str_googlezoom = Input::instance()->post("google_default_zoom");
+ $str_googlemaptype = Input::instance()->post("google_default_type");
+
+ // Save Settings.
+ module::set_var("tagsmap", "googlemap_api_key", $str_googlekey);
+ module::set_var("tagsmap", "googlemap_latitude", $str_googlelatitude);
+ module::set_var("tagsmap", "googlemap_longitude", $str_googlelongitude);
+ module::set_var("tagsmap", "googlemap_zoom", $str_googlezoom);
+ module::set_var("tagsmap", "googlemap_type", $str_googlemaptype);
+
+ // Display a success message and redirect back to the TagsMap admin page.
+ message::success(t("Your Settings Have Been Saved."));
+ url::redirect("admin/tagsmap");
+ }
+}
\ No newline at end of file
diff --git a/themes/3nids/modules/tagsmap/controllers/tagsmap.php b/themes/3nids/modules/tagsmap/controllers/tagsmap.php
new file mode 100755
index 00000000..d7985667
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/controllers/tagsmap.php
@@ -0,0 +1,62 @@
+find_all();
+
+ // Set up and display the actual page.
+ // If fullsize is true, allow the map to take up the entire browser window,
+ // if not, then display the map in the gallery theme.
+ if ($fullsize == true) {
+ $view = new View("tagsmap_googlemap.html");
+ $view->map_fullsize = true;
+
+ // Load in module preferences.
+ $view->tags_gps = $tagsGPS;
+ $view->google_map_key = module::get_var("tagsmap", "googlemap_api_key");
+ $view->google_map_latitude = module::get_var("tagsmap", "googlemap_latitude");
+ $view->google_map_longitude = module::get_var("tagsmap", "googlemap_longitude");
+ $view->google_map_zoom = module::get_var("tagsmap", "googlemap_zoom");
+ $view->google_map_type = module::get_var("tagsmap", "googlemap_type");
+
+ print $view;
+ } else {
+ $template = new Theme_View("page.html", "Contact");
+ //$template->body_attributes("onload=\"GLoad\" onunload=\"Gunload\"");
+ $template->page_title = t("Gallery :: map");
+ $template->content = new View("tagsmap_googlemap.html");
+
+ // Load in module preferences.
+ $template->content->tags_gps = $tagsGPS;
+ $template->content->google_map_key = module::get_var("tagsmap", "googlemap_api_key");
+ $template->content->google_map_latitude = module::get_var("tagsmap", "googlemap_latitude");
+ $template->content->google_map_longitude = module::get_var("tagsmap", "googlemap_longitude");
+ $template->content->google_map_zoom = module::get_var("tagsmap", "googlemap_zoom");
+ $template->content->google_map_type = module::get_var("tagsmap", "googlemap_type");
+
+ print $template;
+ }
+ }
+
+
+}
diff --git a/themes/3nids/modules/tagsmap/css/tagsmap.css b/themes/3nids/modules/tagsmap/css/tagsmap.css
new file mode 100755
index 00000000..5c7a73fc
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/css/tagsmap.css
@@ -0,0 +1,96 @@
+.tooltip{
+ position: absolute;
+ left: 10px;
+ top: 10px;
+ width: 150px;
+ background-color: #777;
+ color: #ffffcc;
+ border: 1px solid #f9db01;
+ font: bold 13px "Trebuchet MS", Verdana, Arial, sans-serif;
+ padding: 4px;
+ z-index: 20;
+ -moz-border-radius: 10px;
+ -moz-opacity: .87;
+ filter:alpha(opacity=87);
+ opacity:.87;
+}
+
+.gMapThumbTable{
+ width:200px;
+ height: 80px;
+ font-size: 0.9em;
+ font-style: normal;
+ color: #FFFFCC;
+}
+.gMapThumbImg{
+ overflow:auto;
+ position: relative;
+ height:125px;
+}
+.gMapThumbLink{
+ height: 15px;
+}
+.gMapThumbTd{
+ padding: 0;
+ text-align: center;
+}
+.gMapThumbnail{
+ height: 80px;
+}
+#gmInfo{
+ width: 230px;
+}
+#gmInfo_contents{
+ background: #3d3d3d;
+}
+#gmInfo_contents div{
+ font-style: italic;
+ vertical-align: middle;
+ margin: 0 10px;
+}
+#gmInfo_tl{
+ width: 14px;
+ height: 14px;
+ background: url('../images/gmInfo_tl.png') top left no-repeat transparent;
+}
+#gmInfo_t{
+ background: url('../images/gmInfo_t.png') top left repeat-x transparent;
+}
+#gmInfo_tr{
+ width: 14px;
+ height: 14px;
+ background: url('../images/gmInfo_tr.png') top left no-repeat transparent;
+}
+#gmInfo_l{
+ width: 14px;
+ background: url('../images/gmInfo_l.png') top left repeat-y transparent;
+}
+#gmInfo_r{
+ width: 14px;
+ background: url('../images/gmInfo_r.png') top right repeat-y transparent;
+}
+#gmInfo_bl{
+ width: 14px;
+ height: 14px;
+ background: url('../images/gmInfo_bl.png') top left no-repeat transparent;
+}
+#gmInfo_b{
+ background: url('../images/gmInfo_b.png') top left repeat-x transparent;
+}
+#gmInfo_br{
+ width: 14px;
+ height: 14px;
+ background: url('../images/gmInfo_br.png') top left no-repeat transparent;
+}
+#gmInfo_close{
+ width: 30px;
+ height: 30px;
+ background: url('../images/gmInfo_close.png') top left no-repeat transparent;
+ margin: -10px 0 0 10px;
+ cursor: pointer;
+}
+#gmInfo_beak{
+ width: 27px;
+ height: 33px;
+ background: url('../images/gmInfo_beak.png') top left no-repeat transparent;
+}
diff --git a/themes/3nids/modules/tagsmap/helpers/tagsmap_event.php b/themes/3nids/modules/tagsmap/helpers/tagsmap_event.php
new file mode 100755
index 00000000..27b47ca6
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/helpers/tagsmap_event.php
@@ -0,0 +1,43 @@
+deactivate)) {
+ site_status::warning(
+ t("The TagsMap module requires the Tags module. " .
+ "Activate the Tags module now ",
+ array("url" => url::site("admin/modules"))),
+ "tagsmap_needs_tag");
+ } else {
+ site_status::clear("tagsmap_needs_tag");
+ }
+ }
+
+ static function admin_menu($menu, $theme) {
+ // Add a link to the TagsMap admin page to the Content menu.
+ $menu->get("content_menu")
+ ->append(Menu::factory("link")
+ ->id("tagsmap")
+ ->label(t("TagsMap Settings"))
+ ->url(url::site("admin/tagsmap")));
+ }
+}
\ No newline at end of file
diff --git a/themes/3nids/modules/tagsmap/helpers/tagsmap_installer.php b/themes/3nids/modules/tagsmap/helpers/tagsmap_installer.php
new file mode 100755
index 00000000..a956ef24
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/helpers/tagsmap_installer.php
@@ -0,0 +1,48 @@
+query("CREATE TABLE IF NOT EXISTS {tags_gpses} (
+ `id` int(9) NOT NULL auto_increment,
+ `tag_id` int(9) NOT NULL,
+ `latitude` varchar(128) NOT NULL,
+ `longitude` varchar(128) NOT NULL,
+ `description` varchar(2048) default NULL,
+ PRIMARY KEY (`id`),
+ KEY(`tag_id`, `id`))
+ DEFAULT CHARSET=utf8;");
+
+ // Set the module's version number.
+ module::set_version("tagsmap", 1);
+ }
+
+ static function deactivate() {
+ site_status::clear("tagsmap_needs_tag");
+ }
+
+ static function uninstall() {
+ // Delete the GPS table before uninstalling.
+ $db = Database::instance();
+ $db->query("DROP TABLE IF EXISTS {tags_gpses};");
+ module::delete("tagsmap");
+ }
+}
diff --git a/themes/3nids/modules/tagsmap/helpers/tagsmap_theme.php b/themes/3nids/modules/tagsmap/helpers/tagsmap_theme.php
new file mode 100755
index 00000000..dc895b5b
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/helpers/tagsmap_theme.php
@@ -0,0 +1,24 @@
+css("tagsmap.css");
+ }
+}
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_b.png b/themes/3nids/modules/tagsmap/images/gmInfo_b.png
new file mode 100755
index 00000000..92aee80b
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_b.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_beak.png b/themes/3nids/modules/tagsmap/images/gmInfo_beak.png
new file mode 100755
index 00000000..240b6501
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_beak.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_bl.png b/themes/3nids/modules/tagsmap/images/gmInfo_bl.png
new file mode 100755
index 00000000..8f7ecf0f
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_bl.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_br.png b/themes/3nids/modules/tagsmap/images/gmInfo_br.png
new file mode 100755
index 00000000..919727f1
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_br.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_close.png b/themes/3nids/modules/tagsmap/images/gmInfo_close.png
new file mode 100755
index 00000000..3dda09b9
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_close.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_l.png b/themes/3nids/modules/tagsmap/images/gmInfo_l.png
new file mode 100755
index 00000000..16ffebba
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_l.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_r.png b/themes/3nids/modules/tagsmap/images/gmInfo_r.png
new file mode 100755
index 00000000..b0e42b11
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_r.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_t.png b/themes/3nids/modules/tagsmap/images/gmInfo_t.png
new file mode 100755
index 00000000..66eeda45
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_t.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_tl.png b/themes/3nids/modules/tagsmap/images/gmInfo_tl.png
new file mode 100755
index 00000000..955cffbe
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_tl.png differ
diff --git a/themes/3nids/modules/tagsmap/images/gmInfo_tr.png b/themes/3nids/modules/tagsmap/images/gmInfo_tr.png
new file mode 100755
index 00000000..44a2e07b
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/gmInfo_tr.png differ
diff --git a/themes/3nids/modules/tagsmap/images/landscape16.png b/themes/3nids/modules/tagsmap/images/landscape16.png
new file mode 100755
index 00000000..7004faaa
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/landscape16.png differ
diff --git a/themes/3nids/modules/tagsmap/images/marker_shadow.png b/themes/3nids/modules/tagsmap/images/marker_shadow.png
new file mode 100755
index 00000000..3a89759f
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/marker_shadow.png differ
diff --git a/themes/3nids/modules/tagsmap/images/markero.png b/themes/3nids/modules/tagsmap/images/markero.png
new file mode 100755
index 00000000..37780950
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/markero.png differ
diff --git a/themes/3nids/modules/tagsmap/images/markery.png b/themes/3nids/modules/tagsmap/images/markery.png
new file mode 100755
index 00000000..25aaebbe
Binary files /dev/null and b/themes/3nids/modules/tagsmap/images/markery.png differ
diff --git a/themes/3nids/modules/tagsmap/js/extinfowindow.js b/themes/3nids/modules/tagsmap/js/extinfowindow.js
new file mode 100755
index 00000000..79249423
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/js/extinfowindow.js
@@ -0,0 +1,610 @@
+/*
+* ExtInfoWindow Class, v1.0
+* Copyright (c) 2007, Joe Monahan (http://www.seejoecode.com)
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* This class lets you add an info window to the map which mimics GInfoWindow
+* and allows for users to skin it via CSS. Additionally it has options to
+* pull in HTML content from an ajax request, triggered when a user clicks on
+* the associated marker.
+*/
+
+
+/**
+ * Creates a new ExtInfoWindow that will initialize by reading styles from css
+ *
+ * @constructor
+ * @param {GMarker} marker The marker associated with the info window
+ * @param {String} windowId The DOM Id we will use to reference the info window
+ * @param {String} html The HTML contents
+ * @param {Object} opt_opts A contianer for optional arguments:
+ * {String} ajaxUrl The Url to hit on the server to request some contents
+ * {Number} paddingX The padding size in pixels that the info window will leave on
+ * the left and right sides of the map when panning is involved.
+ * {Number} paddingY The padding size in pixels that the info window will leave on
+ * the top and bottom sides of the map when panning is involved.
+ * {Number} beakOffset The repositioning offset for when aligning the beak element.
+ * This is used to make sure the beak lines up correcting if the
+ * info window styling containers a border.
+ */
+function ExtInfoWindow(marker, windowId, html, opt_opts) {
+ this.html_ = html;
+ this.marker_ = marker;
+ this.infoWindowId_ = windowId;
+
+ this.options_ = opt_opts == null ? {} : opt_opts;
+ this.ajaxUrl_ = this.options_.ajaxUrl == null ? null : this.options_.ajaxUrl;
+ this.callback_ = this.options_.ajaxCallback == null ? null : this.options_.ajaxCallback;
+
+ this.borderSize_ = this.options_.beakOffset == null ? 0 : this.options_.beakOffset;
+ this.paddingX_ = this.options_.paddingX == null ? 0 + this.borderSize_ : this.options_.paddingX + this.borderSize_;
+ this.paddingY_ = this.options_.paddingY == null ? 0 + this.borderSize_ : this.options_.paddingY + this.borderSize_;
+
+ this.map_ = null;
+
+ this.container_ = document.createElement('div');
+ this.container_.style.position = 'relative';
+ this.container_.style.display = 'none';
+
+ this.contentDiv_ = document.createElement('div');
+ this.contentDiv_.id = this.infoWindowId_ + '_contents';
+ this.contentDiv_.innerHTML = this.html_;
+ this.contentDiv_.style.display = 'block';
+ this.contentDiv_.style.visibility = 'hidden';
+
+ this.wrapperDiv_ = document.createElement('div');
+};
+
+//use the GOverlay class
+ExtInfoWindow.prototype = new GOverlay();
+
+/**
+ * Called by GMap2's addOverlay method. Creates the wrapping div for our info window and adds
+ * it to the relevant map pane. Also binds mousedown event to a private function so that they
+ * are not passed to the underlying map. Finally, performs ajax request if set up to use ajax
+ * in the constructor.
+ * @param {GMap2} map The map that has had this extInfoWindow is added to it.
+ */
+ExtInfoWindow.prototype.initialize = function(map) {
+ this.map_ = map;
+
+ this.defaultStyles = {
+ containerWidth: this.map_.getSize().width / 2,
+ borderSize: 1
+ };
+
+ this.wrapperParts = {
+ tl:{t:0, l:0, w:0, h:0, domElement: null},
+ t:{t:0, l:0, w:0, h:0, domElement: null},
+ tr:{t:0, l:0, w:0, h:0, domElement: null},
+ l:{t:0, l:0, w:0, h:0, domElement: null},
+ r:{t:0, l:0, w:0, h:0, domElement: null},
+ bl:{t:0, l:0, w:0, h:0, domElement: null},
+ b:{t:0, l:0, w:0, h:0, domElement: null},
+ br:{t:0, l:0, w:0, h:0, domElement: null},
+ beak:{t:0, l:0, w:0, h:0, domElement: null},
+ close:{t:0, l:0, w:0, h:0, domElement: null}
+ };
+
+ for (var i in this.wrapperParts ) {
+ var tempElement = document.createElement('div');
+ tempElement.id = this.infoWindowId_ + '_' + i;
+ tempElement.style.visibility = 'hidden';
+ document.body.appendChild(tempElement);
+ tempElement = document.getElementById(this.infoWindowId_ + '_' + i);
+ var tempWrapperPart = eval('this.wrapperParts.' + i);
+ tempWrapperPart.w = parseInt(this.getStyle_(tempElement, 'width'));
+ tempWrapperPart.h = parseInt(this.getStyle_(tempElement, 'height'));
+ document.body.removeChild(tempElement);
+ }
+ for (var i in this.wrapperParts) {
+ if (i == 'close' ) {
+ //first append the content so the close button is layered above it
+ this.wrapperDiv_.appendChild(this.contentDiv_);
+ }
+ var wrapperPartsDiv = null;
+ if (this.wrapperParts[i].domElement == null) {
+ wrapperPartsDiv = document.createElement('div');
+ this.wrapperDiv_.appendChild(wrapperPartsDiv);
+ } else {
+ wrapperPartsDiv = this.wrapperParts[i].domElement;
+ }
+ wrapperPartsDiv.id = this.infoWindowId_ + '_' + i;
+ wrapperPartsDiv.style.position = 'absolute';
+ wrapperPartsDiv.style.width = this.wrapperParts[i].w + 'px';
+ wrapperPartsDiv.style.height = this.wrapperParts[i].h + 'px';
+ wrapperPartsDiv.style.top = this.wrapperParts[i].t + 'px';
+ wrapperPartsDiv.style.left = this.wrapperParts[i].l + 'px';
+ this.wrapperParts[i].domElement = wrapperPartsDiv;
+ }
+
+ this.map_.getPane(G_MAP_FLOAT_PANE).appendChild(this.container_);
+ this.container_.id = this.infoWindowId_;
+ var containerWidth = this.getStyle_(document.getElementById(this.infoWindowId_), 'width');
+ this.container_.style.width = (containerWidth == null ? this.defaultStyles.containerWidth : containerWidth);
+
+ this.map_.getContainer().appendChild(this.contentDiv_);
+ this.contentWidth = this.getDimensions_(this.container_).width;
+ this.contentDiv_.style.width = this.contentWidth + 'px';
+ this.contentDiv_.style.position = 'absolute';
+
+ this.container_.appendChild(this.wrapperDiv_);
+
+ GEvent.bindDom(this.container_, 'mousedown', this,this.onClick_);
+ GEvent.bindDom(this.container_, 'dblclick', this,this.onClick_);
+ GEvent.bindDom(this.container_, 'DOMMouseScroll', this, this.onClick_);
+
+
+ GEvent.trigger(this.map_, 'extinfowindowopen');
+ if (this.ajaxUrl_ != null ) {
+ this.ajaxRequest_(this.ajaxUrl_);
+ }
+};
+
+/**
+ * Private function to steal mouse click events to prevent it from returning to the map.
+ * Without this links in the ExtInfoWindow would not work, and you could click to zoom or drag
+ * the map behind it.
+ * @private
+ * @param {MouseEvent} e The mouse event caught by this function
+ */
+ExtInfoWindow.prototype.onClick_ = function(e) {
+ if(navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
+ window.event.cancelBubble = true;
+ window.event.returnValue = false;
+ } else {
+ //e.preventDefault();
+ e.stopPropagation();
+ }
+};
+
+/**
+ * Remove the extInfoWindow container from the map pane.
+ */
+ExtInfoWindow.prototype.remove = function() {
+ if (this.map_.getExtInfoWindow() != null) {
+ GEvent.trigger(this.map_, 'extinfowindowbeforeclose');
+
+ GEvent.clearInstanceListeners(this.container_);
+ if (this.container_.outerHTML) {
+ this.container_.outerHTML = ''; //prevent pseudo-leak in IE
+ }
+ if (this.container_.parentNode) {
+ this.container_.parentNode.removeChild(this.container_);
+ }
+ this.container_ = null;
+ GEvent.trigger(this.map_, 'extinfowindowclose');
+ this.map_.setExtInfoWindow_(null);
+ }
+};
+
+/**
+ * Return a copy of this overlay, for the parent Map to duplicate itself in full. This
+ * is part of the Overlay interface and is used, for example, to copy everything in the
+ * main view into the mini-map.
+ * @return {GOverlay}
+ */
+ExtInfoWindow.prototype.copy = function() {
+ return new ExtInfoWindow(this.marker_, this.infoWindowId_, this.html_, this.options_);
+};
+
+/**
+ * Draw extInfoWindow and wrapping decorators onto the map. Resize and reposition
+ * the map as necessary.
+ * @param {Boolean} force Will be true when pixel coordinates need to be recomputed.
+ */
+ExtInfoWindow.prototype.redraw = function(force) {
+ if (!force || this.container_ == null) return;
+
+ //set the content section's height, needed so browser font resizing does not affect the window's dimensions
+ var contentHeight = this.contentDiv_.offsetHeight;
+ this.contentDiv_.style.height = contentHeight + 'px';
+
+ //reposition contents depending on wrapper parts.
+ //this is necessary for content that is pulled in via ajax
+ this.contentDiv_.style.left = this.wrapperParts.l.w + 'px';
+ this.contentDiv_.style.top = this.wrapperParts.tl.h + 'px';
+ this.contentDiv_.style.visibility = 'visible';
+
+ //Finish configuring wrapper parts that were not set in initialization
+ this.wrapperParts.tl.t = 0;
+ this.wrapperParts.tl.l = 0;
+ this.wrapperParts.t.l = this.wrapperParts.tl.w;
+ this.wrapperParts.t.w = (this.wrapperParts.l.w + this.contentWidth + this.wrapperParts.r.w) - this.wrapperParts.tl.w - this.wrapperParts.tr.w;
+ this.wrapperParts.t.h = this.wrapperParts.tl.h;
+ this.wrapperParts.tr.l = this.wrapperParts.t.w + this.wrapperParts.tl.w;
+ this.wrapperParts.l.t = this.wrapperParts.tl.h;
+ this.wrapperParts.l.h = contentHeight;
+ this.wrapperParts.r.l = this.contentWidth + this.wrapperParts.l.w;
+ this.wrapperParts.r.t = this.wrapperParts.tr.h;
+ this.wrapperParts.r.h = contentHeight;
+ this.wrapperParts.bl.t = contentHeight + this.wrapperParts.tl.h;
+ this.wrapperParts.b.l = this.wrapperParts.bl.w;
+ this.wrapperParts.b.t = contentHeight + this.wrapperParts.tl.h;
+ this.wrapperParts.b.w = (this.wrapperParts.l.w + this.contentWidth + this.wrapperParts.r.w) - this.wrapperParts.bl.w - this.wrapperParts.br.w;
+ this.wrapperParts.b.h = this.wrapperParts.bl.h;
+ this.wrapperParts.br.l = this.wrapperParts.b.w + this.wrapperParts.bl.w;
+ this.wrapperParts.br.t = contentHeight + this.wrapperParts.tr.h;
+ this.wrapperParts.close.l = this.wrapperParts.tr.l +this.wrapperParts.tr.w - this.wrapperParts.close.w - this.borderSize_;
+ this.wrapperParts.close.t = this.borderSize_;
+ this.wrapperParts.beak.l = this.borderSize_ + (this.contentWidth / 2) - (this.wrapperParts.beak.w / 2);
+ this.wrapperParts.beak.t = this.wrapperParts.bl.t + this.wrapperParts.bl.h - this.borderSize_;
+
+ //create the decoration wrapper DOM objects
+ //append the styled info window to the container
+ for (var i in this.wrapperParts) {
+ if (i == 'close' ) {
+ //first append the content so the close button is layered above it
+ this.wrapperDiv_.insertBefore(this.contentDiv_, this.wrapperParts[i].domElement);
+ }
+ var wrapperPartsDiv = null;
+ if (this.wrapperParts[i].domElement == null) {
+ wrapperPartsDiv = document.createElement('div');
+ this.wrapperDiv_.appendChild(wrapperPartsDiv);
+ } else {
+ wrapperPartsDiv = this.wrapperParts[i].domElement;
+ }
+ wrapperPartsDiv.id = this.infoWindowId_ + '_' + i;
+ wrapperPartsDiv.style.position='absolute';
+ wrapperPartsDiv.style.width = this.wrapperParts[i].w + 'px';
+ wrapperPartsDiv.style.height = this.wrapperParts[i].h + 'px';
+ wrapperPartsDiv.style.top = this.wrapperParts[i].t + 'px';
+ wrapperPartsDiv.style.left = this.wrapperParts[i].l + 'px';
+ this.wrapperParts[i].domElement = wrapperPartsDiv;
+ }
+
+ //add event handler for the close box
+ var currentMarker = this.marker_;
+ var thisMap = this.map_;
+ GEvent.addDomListener(this.wrapperParts.close.domElement, 'click',
+ function() {
+ thisMap.closeExtInfoWindow();
+ }
+ );
+
+ //position the container on the map, over the marker
+ var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());
+ this.container_.style.position = 'absolute';
+ var markerIcon = this.marker_.getIcon();
+ this.container_.style.left = (pixelLocation.x
+ - (this.contentWidth / 2)
+ - markerIcon.iconAnchor.x
+ + markerIcon.infoWindowAnchor.x
+ ) + 'px';
+
+ this.container_.style.top = (pixelLocation.y
+ - this.wrapperParts.bl.h
+ - contentHeight
+ - this.wrapperParts.tl.h
+ - this.wrapperParts.beak.h
+ - markerIcon.iconAnchor.y
+ + markerIcon.infoWindowAnchor.y
+ + this.borderSize_
+ ) + 'px';
+
+ this.container_.style.display = 'block';
+
+ if(this.map_.getExtInfoWindow() != null) {
+ this.repositionMap_();
+ }
+};
+
+/**
+ * Determine the dimensions of the contents to recalculate and reposition the
+ * wrapping decorator elements accordingly.
+ */
+ExtInfoWindow.prototype.resize = function(){
+
+ //Create temporary DOM node for new contents to get new height
+ //This is done because if you manipulate this.contentDiv_ directly it causes visual errors in IE6
+ var tempElement = this.contentDiv_.cloneNode(true);
+ tempElement.id = this.infoWindowId_ + '_tempContents';
+ tempElement.style.visibility = 'hidden';
+ tempElement.style.height = 'auto';
+ document.body.appendChild(tempElement);
+ tempElement = document.getElementById(this.infoWindowId_ + '_tempContents');
+ var contentHeight = tempElement.offsetHeight;
+ document.body.removeChild(tempElement);
+
+ //Set the new height to eliminate visual defects that can be caused by font resizing in browser
+ this.contentDiv_.style.height = contentHeight + 'px';
+
+ var contentWidth = this.contentDiv_.offsetWidth;
+ var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());
+
+ var oldWindowHeight = this.wrapperParts.t.domElement.offsetHeight + this.wrapperParts.l.domElement.offsetHeight + this.wrapperParts.b.domElement.offsetHeight;
+ var oldWindowPosTop = this.wrapperParts.t.domElement.offsetTop;
+
+ //resize info window to look correct for new height
+ this.wrapperParts.l.domElement.style.height = contentHeight + 'px';
+ this.wrapperParts.r.domElement.style.height = contentHeight + 'px';
+ var newPosTop = this.wrapperParts.b.domElement.offsetTop - contentHeight;
+ this.wrapperParts.l.domElement.style.top = newPosTop + 'px';
+ this.wrapperParts.r.domElement.style.top = newPosTop + 'px';
+ this.contentDiv_.style.top = newPosTop + 'px';
+ windowTHeight = parseInt(this.wrapperParts.t.domElement.style.height);
+ newPosTop -= windowTHeight;
+ this.wrapperParts.close.domElement.style.top = newPosTop + this.borderSize_ + 'px';
+ this.wrapperParts.tl.domElement.style.top = newPosTop + 'px';
+ this.wrapperParts.t.domElement.style.top = newPosTop + 'px';
+ this.wrapperParts.tr.domElement.style.top = newPosTop + 'px';
+
+ this.repositionMap_();
+};
+
+/**
+ * Check to see if the displayed extInfoWindow is positioned off the viewable
+ * map region and by how much. Use that information to pan the map so that
+ * the extInfoWindow is completely displayed.
+ * @private
+ */
+ExtInfoWindow.prototype.repositionMap_ = function(){
+ //pan if necessary so it shows on the screen
+ var mapNE = this.map_.fromLatLngToDivPixel(
+ this.map_.getBounds().getNorthEast()
+ );
+ var mapSW = this.map_.fromLatLngToDivPixel(
+ this.map_.getBounds().getSouthWest()
+ );
+ var markerPosition = this.map_.fromLatLngToDivPixel(
+ this.marker_.getPoint()
+ );
+
+ var panX = 0;
+ var panY = 0;
+ var paddingX = this.paddingX_;
+ var paddingY = this.paddingY_;
+ var infoWindowAnchor = this.marker_.getIcon().infoWindowAnchor;
+ var iconAnchor = this.marker_.getIcon().iconAnchor;
+
+ //test top of screen
+ var windowT = this.wrapperParts.t.domElement;
+ var windowL = this.wrapperParts.l.domElement;
+ var windowB = this.wrapperParts.b.domElement;
+ var windowR = this.wrapperParts.r.domElement;
+ var windowBeak = this.wrapperParts.beak.domElement;
+
+ var offsetTop = markerPosition.y - ( -infoWindowAnchor.y + iconAnchor.y + this.getDimensions_(windowBeak).height + this.getDimensions_(windowB).height + this.getDimensions_(windowL).height + this.getDimensions_(windowT).height + this.paddingY_);
+ if (offsetTop < mapNE.y) {
+ panY = mapNE.y - offsetTop;
+ } else {
+ //test bottom of screen
+ var offsetBottom = markerPosition.y + this.paddingY_;
+ if (offsetBottom >= mapSW.y) {
+ panY = -(offsetBottom - mapSW.y);
+ }
+ }
+
+ //test right of screen
+ var offsetRight = Math.round(markerPosition.x + this.getDimensions_(this.container_).width/2 + this.getDimensions_(windowR).width + this.paddingX_ + infoWindowAnchor.x - iconAnchor.x);
+ if (offsetRight > mapNE.x) {
+ panX = -( offsetRight - mapNE.x);
+ } else {
+ //test left of screen
+ var offsetLeft = - (Math.round( (this.getDimensions_(this.container_).width/2 - this.marker_.getIcon().iconSize.width/2) + this.getDimensions_(windowL).width + this.borderSize_ + this.paddingX_) - markerPosition.x - infoWindowAnchor.x + iconAnchor.x);
+ if( offsetLeft < mapSW.x) {
+ panX = mapSW.x - offsetLeft;
+ }
+ }
+
+ if (panX != 0 || panY != 0 && this.map_.getExtInfoWindow() != null ) {
+ this.map_.panBy(new GSize(panX,panY));
+ }
+};
+
+/**
+ * Private function that handles performing an ajax request to the server. The response
+ * information is assumed to be HTML and is placed inside this extInfoWindow's contents region.
+ * Last, check to see if the height has changed, and resize the extInfoWindow accordingly.
+ * @private
+ * @param {String} url The Url of where to make the ajax request on the server
+ */
+ExtInfoWindow.prototype.ajaxRequest_ = function(url){
+ var thisMap = this.map_;
+ var thisCallback = this.callback_;
+ GDownloadUrl(url, function(response, status){
+ var infoWindow = document.getElementById(thisMap.getExtInfoWindow().infoWindowId_ + '_contents');
+ if (response == null || status == -1 ) {
+ infoWindow.innerHTML = 'ERROR: The Ajax request failed to get HTML content from "' + url + '" ';
+ } else {
+ infoWindow.innerHTML = response;
+ }
+ if (thisCallback != null ) {
+ thisCallback();
+ }
+ thisMap.getExtInfoWindow().resize();
+ GEvent.trigger(thisMap, 'extinfowindowupdate');
+ });
+};
+
+/**
+ * Private function derived from Prototype.js to get a given element's
+ * height and width
+ * @private
+ * @param {Object} element The DOM element that will have height and
+ * width will be calculated for it.
+ * @return {Object} Object with keys: width, height
+ */
+ExtInfoWindow.prototype.getDimensions_ = function(element) {
+ var display = this.getStyle_(element, 'display');
+ if (display != 'none' && display != null) { // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+ }
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+};
+
+/**
+ * Private function derived from Prototype.js to get a given element's
+ * value that is associated with the passed style
+ * @private
+ * @param {Object} element The DOM element that will be checked.
+ * @param {String} style The style name that will be have it's value returned.
+ * @return {Object}
+ */
+ExtInfoWindow.prototype.getStyle_ = function(element, style) {
+ var found = false;
+ style = this.camelize_(style);
+ var value = element.style[style];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+ }
+ if((value == 'auto') && (style == 'width' || style == 'height') && (this.getStyle_(element, 'display') != 'none')) {
+ if( style == 'width' ) {
+ value = element.offsetWidth;
+ }else {
+ value = element.offsetHeight;
+ }
+ }
+ return (value == 'auto') ? null : value;
+};
+
+/**
+ * Private function pulled from Prototype.js that will change a hyphened
+ * style name into camel case.
+ * @private
+ * @param {String} element The string that will be parsed and made into camel case
+ * @return {String}
+ */
+ExtInfoWindow.prototype.camelize_ = function(element) {
+ var parts = element.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+ var camelized = element.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++) {
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+ }
+ return camelized;
+};
+
+GMap.prototype.ExtInfoWindowInstance_ = null;
+GMap.prototype.ClickListener_ = null;
+GMap.prototype.InfoWindowListener_ = null;
+
+/**
+ * Creates a new instance of ExtInfoWindow for the GMarker. Register the newly created
+ * instance with the map, ensuring only one window is open at a time. If this is the first
+ * ExtInfoWindow ever opened, add event listeners to the map to close the ExtInfoWindow on
+ * zoom and click, to mimic the default GInfoWindow behavior.
+ *
+ * @param {GMap} map The GMap2 object where the ExtInfoWindow will open
+ * @param {String} cssId The id we will use to reference the info window
+ * @param {String} html The HTML contents
+ * @param {Object} opt_opts A contianer for optional arguments:
+ * {String} ajaxUrl The Url to hit on the server to request some contents
+ * {Number} paddingX The padding size in pixels that the info window will leave on
+ * the left and right sides of the map when panning is involved.
+ * {Number} paddingX The padding size in pixels that the info window will leave on
+ * the top and bottom sides of the map when panning is involved.
+ * {Number} beakOffset The repositioning offset for when aligning the beak element.
+ * This is used to make sure the beak lines up correcting if the
+ * info window styling containers a border.
+ */
+GMarker.prototype.openExtInfoWindow = function(map, cssId, html, opt_opts) {
+ if (map == null) {
+ throw 'Error in GMarker.openExtInfoWindow: map cannot be null';
+ return false;
+ }
+ if (cssId == null || cssId == '') {
+ throw 'Error in GMarker.openExtInfoWindow: must specify a cssId';
+ return false;
+ }
+
+ map.closeInfoWindow();
+ if (map.getExtInfoWindow() != null) {
+ map.closeExtInfoWindow();
+ }
+ if (map.getExtInfoWindow() == null) {
+ map.setExtInfoWindow_( new ExtInfoWindow(
+ this,
+ cssId,
+ html,
+ opt_opts
+ ) );
+ if (map.ClickListener_ == null) {
+ //listen for map click, close ExtInfoWindow if open
+ map.ClickListener_ = GEvent.addListener(map, 'click',
+ function(event) {
+ if( !event && map.getExtInfoWindow() != null ){
+ map.closeExtInfoWindow();
+ }
+ }
+ );
+ }
+ if (map.InfoWindowListener_ == null) {
+ //listen for default info window open, close ExtInfoWindow if open
+ map.InfoWindowListener_ = GEvent.addListener(map, 'infowindowopen',
+ function(event) {
+ if (map.getExtInfoWindow() != null) {
+ map.closeExtInfoWindow();
+ }
+ }
+ );
+ }
+ map.addOverlay(map.getExtInfoWindow());
+ }
+};
+
+/**
+ * Remove the ExtInfoWindow instance
+ * @param {GMap2} map The map where the GMarker and ExtInfoWindow exist
+ */
+GMarker.prototype.closeExtInfoWindow = function(map) {
+ if( map.getExtInfWindow() != null ){
+ map.closeExtInfoWindow();
+ }
+};
+
+/**
+ * Get the ExtInfoWindow instance from the map
+ */
+GMap2.prototype.getExtInfoWindow = function(){
+ return this.ExtInfoWindowInstance_;
+};
+/**
+ * Set the ExtInfoWindow instance for the map
+ * @private
+ */
+GMap2.prototype.setExtInfoWindow_ = function( extInfoWindow ){
+ this.ExtInfoWindowInstance_ = extInfoWindow;
+}
+/**
+ * Remove the ExtInfoWindow from the map
+ */
+GMap2.prototype.closeExtInfoWindow = function(){
+ if( this.getExtInfoWindow() != null ){
+ this.ExtInfoWindowInstance_.remove();
+ }
+};
diff --git a/themes/3nids/modules/tagsmap/models/tags_gps.php b/themes/3nids/modules/tagsmap/models/tags_gps.php
new file mode 100755
index 00000000..c9fda760
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/models/tags_gps.php
@@ -0,0 +1,21 @@
+
+
+ = t("TagsMap Admin") ?>
+
+
+
+ = t("Google Maps Settings") ?>
+
+
You may sign up for a Google Maps API key
here .
+ = $googlemaps_form ?>
+
+
+
+
+ = t("Assign GPS Coordinates") ?>
+
+ $tags_per_column = $tags->count()/5 ?>
+ $column_tag_count = 0 ?>
+
+
+
+ = 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 */ ?>
+ = $current_letter ?>
+
+ elseif ($last_letter != $current_letter): /* new letter */ ?>
+ if ($column_tag_count > $tags_per_column): /* new column */ ?>
+
+
+ $column_tag_count = 0 ?>
+ endif ?>
+
+
+ = $current_letter ?>
+
+ endif ?>
+
+
+ // Check and see if this ID already has GPS data, display a delete button if it does.
+ $existingGPS = ORM::factory("tags_gps")
+ ->where("tag_id", $tag->id)
+ ->find_all();
+ ?>
+ if (count($existingGPS) == 0) { ?>
+
+ } ?>
+ = html::purify($tag->name) ?>
+ (= $tag->count ?>)
+
+ id") ?>">= t("Edit GPS") ?>
+
+ if (count($existingGPS) > 0) { ?>
+ | id") ?>">= t("Delete GPS") ?>
+
+ }
+ ?>
+ if (count($existingGPS) == 0) { ?>
+
+ } ?>
+
+
+ $column_tag_count++ ?>
+ $last_letter = $current_letter ?>
+ endforeach /* $tags */ ?>
+
+
+
+
+
+
+
+
+ = t("Remove Orphaned GPS Data") ?>
+
+
+
diff --git a/themes/3nids/modules/tagsmap/views/admin_tagsmap_delete.html.php b/themes/3nids/modules/tagsmap/views/admin_tagsmap_delete.html.php
new file mode 100755
index 00000000..b85641e5
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/views/admin_tagsmap_delete.html.php
@@ -0,0 +1,9 @@
+
+
+
diff --git a/themes/3nids/modules/tagsmap/views/admin_tagsmap_edit.html.php b/themes/3nids/modules/tagsmap/views/admin_tagsmap_edit.html.php
new file mode 100755
index 00000000..66795291
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/views/admin_tagsmap_edit.html.php
@@ -0,0 +1,56 @@
+
+
+
= t("Edit GPS Data for Tag ") . $tag_name ?>
+ = $tagsmapedit_form ?>
+
+
+
+
+
diff --git a/themes/3nids/modules/tagsmap/views/tagsmap_googlemap.html.php b/themes/3nids/modules/tagsmap/views/tagsmap_googlemap.html.php
new file mode 100755
index 00000000..6776dde9
--- /dev/null
+++ b/themes/3nids/modules/tagsmap/views/tagsmap_googlemap.html.php
@@ -0,0 +1,148 @@
+
+
+ if ($map_fullsize == true) { ?>
+
+
+
+ = t("Gallery :: Map") ?>
+
+
+ } ?>
+
+
+
+
+
+
+ if ($map_fullsize == true) { ?>
+
+
+ } else { ?>
+
+
+ } ?>