diff --git a/modules/favourites/controllers/admin_favourites_configure.php b/modules/favourites/controllers/admin_favourites_configure.php new file mode 100644 index 00000000..ad6af6f6 --- /dev/null +++ b/modules/favourites/controllers/admin_favourites_configure.php @@ -0,0 +1,50 @@ +validate()) { + + favourites_configuration::extractForm($form); + message::success(t("Favourites Module Configured!")); + } + } + else + { + favourites_configuration::populateForm($form); + } + + $view = new Admin_View("admin.html"); + $view->content = new View("admin_favourites_configure.html"); + + $view->content->form = $form; + + print $view; + } +} diff --git a/modules/favourites/controllers/favourites.php b/modules/favourites/controllers/favourites.php new file mode 100644 index 00000000..8d0c50be --- /dev/null +++ b/modules/favourites/controllers/favourites.php @@ -0,0 +1,206 @@ +name =="guest"){ + //login required. + url::redirect("login/html"); + return; + } + + $album = Favourites::getOrCreate()->get_as_album(); + + $page_size = module::get_var("gallery", "page_size", 9); + $input = Input::instance(); + $show = $input->get("show"); + + if ($show) { + $child = ORM::factory("item", $show); + $index = $album->get_position($child); + if ($index) { + $page = ceil($index / $page_size); + if ($page == 1) { + //url::redirect("favourites"); + } else { + //url::redirect("favourites?page=$page"); + } + } + } + + + $page = $input->get("page", "1"); + $children_count = $album->viewable()->children_count(); + $offset = ($page - 1) * $page_size; + $max_pages = max(ceil($children_count / $page_size), 1); + + + // Make sure that the page references a valid offset + if ($page < 1) { + //url::redirect($album->abs_url()); + } else if ($page > $max_pages) { + //url::redirect($album->abs_url("page=$max_pages")); + } + + + + $template = new Theme_View("page.html", "collection", "favourites"); + $template->set_global("page", $page); + $template->set_global("page_title", null); + $template->set_global("max_pages", $max_pages); + $template->set_global("page_size", $page_size); + $template->set_global("children", $album->viewable()->children($page_size, $offset)); + $template->set_global("children_count", $children_count); + $template->content = new View("dynamic.html"); + + print $template; + } + + public function view(){ + if (favourites_configuration::isUsersOnly() && identity::active_user()->name =="guest"){ + //login required. + Session::instance()->set("continue_url", url::current(true)); + $template = new Theme_View("page.html", "collection", "album"); + $template->content = new View("login_required.html"); + $template->content->login_form = new View("login_ajax.html"); + $template->content->login_form->form = auth::get_login_form("login/auth_html"); + print $template; + return; + } + + // extract details from url + $favourites = Favourites::getOrCreate(); + $favourites->clear(); + $array = func_get_args(); + foreach($array as $i=>$item){ + $favourites->toggle($item); + } + url::redirect("favourites"); + } + + private function getSaveForm(){ + + $form = new Forge("favourites/save_favourites", "", "post", array("id" => "gAddToBasketForm")); + $group = $form->group("save")->label(t("Save Favourites")); + $group->hidden("id"); + $group->input("fullname")->label(t("Name"))->id("gname") + ->error_messages("required", t("You must provide your name")) + ->error_messages("not_logged_in", t("You must be logged in to send favourites.")) + ->rules("required"); + $group->input("email")->label(t("Email Address"))->id("gemail") + ->error_messages("required", t("You must provide an email address")) + ->error_messages("valid_email", t("You must provide a valid email address")) + ->rules("valid_email") + ->rules("required"); + $group->textarea("details")->label(t("Comments"))->id("gdetails"); + + $group->submit("")->value(t("save")); + return $form; + } + public function save(){ + $view = new View("save_dialog.html"); + + // get the basket to add to + $form = self::getSaveForm(); + $view->form = $form; + + print $view; + + } + + public function save_favourites($id){ + + access::verify_csrf(); + + $form = self::getSaveForm(); + $valid = $form->validate(); + $name = $form->save->fullname->value; + $email_address = $form->save->email->value; + $comments = $form->save->details->value; + + + if (!isset($email_address ) || strlen($email_address) == 0) { + $valid=false; + $form->save->email->add_error("required", 1); + } + + if (!isset($name ) || strlen($name) == 0) { + $valid=false; + $form->save->fullname->add_error("required", 1); + } + + if (favourites_configuration::isUsersOnly() && identity::active_user()->name =="guest"){ + $valid=false; + $form->save->fullname->add_error("not_logged_in", 1); + } + + if ($valid){ + + $favourites = Favourites::getOrCreate(); + + $from = "From: ".favourites_configuration::getFromEmailAddress(); + + if (favourites_configuration::isEmailAdmin()) + { + $admin_email = $name." has chosen following photo as his or her favourites.\n"; + + // create the order items + $items = ORM::factory("item")->where("id","in", $favourites->contents)->find_all(); + foreach ($items->contents as $id=>$item){ + $admin_email = $admin_email." + ".$item->title." - ".$item->url().""; + } + $admin_email = $admin_email."\n you can view this favourite list at \n".$favourites->getUrl() + ."\n\n He or she has included the additional comments. \n".$comments + ."\n You can e-mail him or her with the following e-mail address ".$email_address; + + mail(favourites_configuration::getEmailAddress(), $name."'s favourites.", $admin_email, $from); + } + + $email = favourites_configuration::replaceStrings( + favourites_configuration::getEmailTemplate(), + Array( + "name"=>$name, + "comments"=>$comments, + "url"=>$favourites->getUrl(), + "owner"=>favourites_configuration::getOwner())); + + mail($email_address,$name."'s Favourites",$email, $from); + + print json_encode(array("result" => "success","location" => url::site("favourites"))); + return; + } + print json_encode(array("result" => "error", "form" => (string) $form)); + } + + public function toggle_favourites($id){ + $favourites = Favourites::getOrCreate(); + $infavour = $favourites ->toggle($id); + $title = $infavour?t("Remove from favourites"):t("Add to favourites"); + print json_encode(array("result" => "success", + "favourite" => $infavour, + "hasfavourites" => $favourites->hasFavourites(), + "title" => (string)$title)); + } + + public function clear_favourites(){ + Favourites::getOrCreate()->clear(); + } +} diff --git a/modules/favourites/css/favourites.css b/modules/favourites/css/favourites.css new file mode 100644 index 00000000..2f025504 --- /dev/null +++ b/modules/favourites/css/favourites.css @@ -0,0 +1,15 @@ +.icon-f{width:32px; height:32px; display:inline-block; background-image: url(../images/faves.png); position:absolute; top:20px; left:0; z-index:20} +.icon-f:hover{background-position: 0 -64px ;} +.icon-f.f-selected{background-position: 0 -32px ;} +.icon-f.f-working{background-position: 0 -96px ;} +#f-view-link {float:right;position:relative; width:50px; height:50px;} +#f-view-link a{width:64px; height:64px; display:inline-block;background-position: -96px 0px;background-image: url(../images/faves.png); position:absolute; top:15px; right:0;} +#f-view-link a:hover{background-position: -96px -64px ;} +#f-save-link {float:right;position:relative; width:64px; height:64px;} +#f-save-link a{width:64px; height:64px; display:inline-block;background-position: -32px 0px;background-image: url(../images/faves.png); position:absolute; top:15px; right:0;} +#f-save-link a:hover{background-position: -32px -64px ;} +.rtl .icon-f{right:0;left:auto;} +.rtl #f-view-link{float:left;} +.rtl #f-view-link a{left:0;right:auto;} +.rtl #f-save-link{float:left;} +.rtl #f-save-link a{left:0;right:auto;} \ No newline at end of file diff --git a/modules/favourites/helpers/favourites_configuration.php b/modules/favourites/helpers/favourites_configuration.php new file mode 100644 index 00000000..cae987f4 --- /dev/null +++ b/modules/favourites/helpers/favourites_configuration.php @@ -0,0 +1,144 @@ + "g-configure-form")); + + $group = $form->group("configure")->label(t("Configure Favourites")); + $group->dropdown("select_allow") + ->label(t("Please choose what a user can select as a favourite")) + ->options(Array(1=>t("Items only"), 2=>"albums only", 3=>"Both")); + $group->input("fromemail")->label(t("From Email address for site emails"))->id("g-from-email-address"); + $group->checkbox("email_admin")->label(t("Email site owner every saved favourites list"))->id("g-email-admin"); + $group->input("email")->label(t("Email address of Site Owner"))->id("g-owner-email-address"); + $group->input("owner")->label(t("Site Owners name"))->id("g-owner-name"); + $group->checkbox("users_only")->label(t("Only Registered users can create favourites"))->id("g-users-only"); + $group->textarea("email_template")->label(t("Email Template"))->id("g-email-template"); + $group->submit("")->value(t("Save")); + return $form; + } + + static function populateForm($form){ + $form->configure->email->value(favourites_configuration::getEmailAddress()); + $form->configure->fromemail->value(favourites_configuration::getFromEmailAddress()); + $form->configure->email_admin->checked(favourites_configuration::isEmailAdmin()); + $form->configure->users_only->checked(favourites_configuration::isUsersOnly()); + $form->configure->owner->value(favourites_configuration::getOwner()); + $form->configure->email_template->value(favourites_configuration::getEmailTemplate()); + $form->configure->select_allow->selected(favourites_configuration::getSelectAllow()); + } + + static function extractForm($form){ + $email = $form->configure->email->value; + $emailfrom = $form->configure->fromemail->value; + $owner = $form->configure->owner->value; + $is_email_admin = $form->configure->email_admin->value; + $is_users_only = $form->configure->users_only->value; + $email_template = $form->configure->email_template->value; + $select_from = $form->configure->select_allow->selected; + favourites_configuration::setEmailAddress($email); + favourites_configuration::setEmailAdmin($is_email_admin); + favourites_configuration::setFromEmailAddress($emailfrom); + favourites_configuration::setOwner($owner); + favourites_configuration::setUsersOnly($is_users_only); + favourites_configuration::setEmailTemplate($email_template); + favourites_configuration::setSelectAllow($select_from); + } + + static function replaceStrings($string, $key_values) { + // Replace x_y before replacing x. + krsort($key_values, SORT_STRING); + + $keys = array(); + $values = array(); + foreach ($key_values as $key => $value) { + $keys[] = "%$key"; + $values[] = $value; + } + return str_replace($keys, $values, $string); + } + + static function getEmailAddress(){ + return module::get_var("favourites","email"); + } + + static function setEmailAddress($email){ + module::set_var("favourites","email",$email); + } + + static function getOwner(){ + return module::get_var("favourites","owner"); + } + + static function setOwner($owner){ + module::set_var("favourites","owner",$owner); + } + + static function getFromEmailAddress(){ + return module::get_var("favourites","from_email"); + } + + static function setFromEmailAddress($fromemail){ + module::set_var("favourites","from_email",$fromemail); + } + + static function isEmailAdmin(){ + return module::get_var("favourites","email_admin"); + } + + static function setEmailAdmin($email_admin){ + module::set_var("favourites","email_admin",$email_admin); + } + + static function isUsersOnly(){ + return module::get_var("favourites","users_only"); + } + + static function setUsersOnly($users_only){ + module::set_var("favourites","users_only",$users_only); + } + + static function getSelectAllow(){ + return module::get_var("favourites","select_from",1); + } + + static function setSelectAllow($select_from){ + module::set_var("favourites","select_from",$select_from); + } + + static function getEmailTemplate(){ + return module::get_var("favourites","email_template"); + } + + static function setEmailTemplate($email_template){ + module::set_var("favourites","email_template",$email_template); + } + + static function canSelectAlbums(){ + return self::getSelectAllow()!=1; + } + + static function canSelectItems(){ + return self::getSelectAllow()!=2; + } + +} \ No newline at end of file diff --git a/modules/favourites/helpers/favourites_event.php b/modules/favourites/helpers/favourites_event.php new file mode 100644 index 00000000..a96ada02 --- /dev/null +++ b/modules/favourites/helpers/favourites_event.php @@ -0,0 +1,34 @@ +add_after("users_groups", + Menu::factory("link") + ->id("configure_favourites") + ->label(t("Favourites")) + ->url(url::site("admin/favourites_configure"))); + } + +} \ No newline at end of file diff --git a/modules/favourites/helpers/favourites_installer.php b/modules/favourites/helpers/favourites_installer.php new file mode 100644 index 00000000..91250521 --- /dev/null +++ b/modules/favourites/helpers/favourites_installer.php @@ -0,0 +1,37 @@ +css("favourites.css"); + $theme->script("favourites.js"); + } + + static function header_top($theme) { + + if (favourites_configuration::isUsersOnly() && identity::active_user()->name =="guest"){ + return; + } + + if ($theme->page_subtype=="favourites"){ + $view = new View("save_favourites.html"); + $view->favourites = Favourites::getOrCreate(); + return $view->render(); + } + else{ + $view = new View("view_favourites.html"); + $view->favourites = Favourites::getOrCreate(); + return $view->render(); + } + } + + static function photo_top($theme){ + if (!favourites_configuration::canSelectItems() || + (favourites_configuration::isUsersOnly() && identity::active_user()->name =="guest")){ + return; + } + + $view = new View("add_to_favourites.html"); + $view->item = $theme->item(); + $view->favourites = Favourites::getOrCreate(); + return $view->render(); + } + + static function thumb_top($theme, $item){ + if (favourites_configuration::isUsersOnly() && identity::active_user()->name =="guest"){ + return; + } + + if (($item->type=="album" && favourites_configuration::canSelectAlbums()) || + ($item->type!="album" && favourites_configuration::canSelectItems())){ + $view = new View("add_to_favourites.html"); + $view->item = $item; + $view->favourites = Favourites::getOrCreate(); + return $view->render(); + } + } + +} \ No newline at end of file diff --git a/modules/favourites/images/faves.png b/modules/favourites/images/faves.png new file mode 100644 index 00000000..ebcccad0 Binary files /dev/null and b/modules/favourites/images/faves.png differ diff --git a/modules/favourites/js/favourites.js b/modules/favourites/js/favourites.js new file mode 100644 index 00000000..1eac91a8 --- /dev/null +++ b/modules/favourites/js/favourites.js @@ -0,0 +1,30 @@ +$(window).load(function() { + var favlink = $("#f-view-link"); + + $(".icon-f").each(function(){ + var elem = $(this); + var href = elem.attr("href"); + function clickFavourite(e){ + elem.addClass("f-working"); + $.getJSON(href,function (data){ + elem.removeClass("f-working"); + if (data.favourite){ + elem.addClass("f-selected"); + elem.attr("title",data.title); + } + else{ + elem.removeClass("f-selected"); + elem.attr("title",data.title); + } + if (data.hasfavourites){ + favlink.css('display','block'); + }else{ + favlink.css('display','none'); + } + + }); + return false; + } + elem.bind("click",clickFavourite); + }); +}); \ No newline at end of file diff --git a/modules/favourites/libraries/Favourites.php b/modules/favourites/libraries/Favourites.php new file mode 100644 index 00000000..93af434c --- /dev/null +++ b/modules/favourites/libraries/Favourites.php @@ -0,0 +1,63 @@ +contents as $i => $value) { + if ($value==$id){ + unset($this->contents[$i]); + return false; + } + } + $this->contents[]=$id; + return true; + } + + public function contains($id){ + foreach ($this->contents as $i => $value){ + if ($value==$id) return true; + } + return false; + } + + public function hasFavourites(){ + return !empty($this->contents); + } + + public function get_as_album(){ + return Pseudo_album::create($this); + } + + public function clear(){ + $this->contents = array(); + } + + public function getUrl(){ + + $toReturn = url::site("favourites/view","http"); + + foreach ($this->contents as $i => $value){ + $toReturn = $toReturn."/".$value; + } + return $toReturn; + } + + public static function get(){ + return Session::instance()->get("favourites"); + } + + + public static function getOrCreate(){ + $session = Session::instance(); + + $favourites = $session->get("favourites"); + if (!$favourites) + { + $favourites = new Favourites(); + $session->set("favourites", $favourites); + } + return $favourites; + } +} diff --git a/modules/favourites/libraries/Pseudo_album.php b/modules/favourites/libraries/Pseudo_album.php new file mode 100644 index 00000000..b4372121 --- /dev/null +++ b/modules/favourites/libraries/Pseudo_album.php @@ -0,0 +1,396 @@ +favourites = $favourites; + // Set reasonable defaults + $this->created = time(); + $this->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + $this->thumb_dirty = 1; + $this->resize_dirty = 1; + $this->sort_column = "created"; + $this->sort_order = "ASC"; + $this->owner_id = identity::active_user()->id; + $this->parent_id = 1; + + $this->id = 1; + $this->type="album"; + $this->title=t("Favourites"); + $this->description=t("Currently selected favourites"); + } + + public function parent(){ + return ORM::factory("item")->where("id","=",1)->find(); + } + + public static function create($favourites) + { + return new Pseudo_album($favourites); + } + + public function loaded(){ + return true; + } + + public function children_count(){ + return count($this->favourites->contents); + } + + public function parents(){ + return ORM::factory("item")->where("id","=", 1)->find_all(); + } + + /** + * Add a set of restrictions to any following queries to restrict access only to items + * viewable by the active user. + * @chainable + */ + public function viewable() { + return $this; + } + + /** + * Is this item an album? + * @return true if it's an album + */ + public function is_album() { + return true; + } + + /** + * Is this item a photo? + * @return true if it's a photo + */ + public function is_photo() { + return false; + } + + /** + * Is this item a movie? + * @return true if it's a movie + */ + public function is_movie() { + return false; + } + + public function delete($ignored_id=null) { + } + + /** + * Specify the path to the data file associated with this item. To actually associate it, + * you still have to call save(). + * @chainable + */ + public function set_data_file($data_file) { + } + + /** + * Return the server-relative url to this item, eg: + * /gallery3/index.php/BobsWedding?page=2 + * /gallery3/index.php/BobsWedding/Eating-Cake.jpg + * + * @param string $query the query string (eg "show=3") + */ + public function url($query=null) { + $url = url::site("favourites"); + if ($query) { + $url .= "?$query"; + } + return $url; + } + + /** + * Return the full url to this item, eg: + * http://example.com/gallery3/index.php/BobsWedding?page=2 + * http://example.com/gallery3/index.php/BobsWedding/Eating-Cake.jpg + * + * @param string $query the query string (eg "show=3") + */ + public function abs_url($query=null) { + $url = url::abs_site("favourites"); + if ($query) { + $url .= "?$query"; + } + return $url; + } + + /** + * album: /var/albums/album1/album2 + * photo: /var/albums/album1/album2/photo.jpg + */ + public function file_path() { + return VARPATH . "albums/"; + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/ + * photo: http://example.com/gallery3/var/albums/album1/photo.jpg + */ + public function file_url($full_uri=false) { + return; + } + + /** + * album: /var/resizes/album1/.thumb.jpg + * photo: /var/albums/album1/photo.thumb.jpg + */ + public function thumb_path() { + } + + /** + * Return true if there is a thumbnail for this item. + */ + public function has_thumb() { + return false; + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/.thumb.jpg + * photo: http://example.com/gallery3/var/albums/album1/photo.thumb.jpg + */ + public function thumb_url($full_uri=false) { + } + + /** + * album: /var/resizes/album1/.resize.jpg + * photo: /var/albums/album1/photo.resize.jpg + */ + public function resize_path() { + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/.resize.jpg + * photo: http://example.com/gallery3/var/albums/album1/photo.resize.jpg + */ + public function resize_url($full_uri=false) { + } + + + /** + * Return the relative path to this item's file. Note that the components of the path are + * urlencoded so if you want to use this as a filesystem path, you need to call urldecode + * on it. + * @return string + */ + public function relative_path() { + if (!$this->loaded()) { + return; + } + + if (!isset($this->relative_path_cache)) { + $this->_build_relative_caches()->save(); + } + return $this->relative_path_cache; + } + + /** + * Return the relative url to this item's file. + * @return string + */ + public function relative_url() { + } + + + /** + * Handle any business logic necessary to create or modify an item. + * @see ORM::save() + * + * @return ORM Item_Model + */ + public function save() { + } + + /** + * Return the Item_Model representing the cover for this album. + * @return Item_Model or null if there's no cover + */ + public function album_cover() { + return null; + } + + /** + * Find the position of the given child id in this album. The resulting value is 1-indexed, so + * the first child in the album is at position 1. + */ + public function get_position($child, $where=array()) { + /* + if ($this->sort_order == "DESC") { + $comp = ">"; + } else { + $comp = "<"; + } + $db = db::build(); + + // If the comparison column has NULLs in it, we can't use comparators on it and will have to + // deal with it the hard way. + $count = $db->from("items") + ->where("parent_id", "=", $this->id) + ->where($this->sort_column, "IS", null) + ->merge_where($where) + ->count_records(); + + if (empty($count)) { + // There are no NULLs in the sort column, so we can just use it directly. + $sort_column = $this->sort_column; + + $position = $db->from("items") + ->where("parent_id", "=", $this->id) + ->where($sort_column, $comp, $child->$sort_column) + ->merge_where($where) + ->count_records(); + + // We stopped short of our target value in the sort (notice that we're using a < comparator + // above) because it's possible that we have duplicate values in the sort column. An + // equality check would just arbitrarily pick one of those multiple possible equivalent + // columns, which would mean that if you choose a sort order that has duplicates, it'd pick + // any one of them as the child's "position". + // + // Fix this by doing a 2nd query where we iterate over the equivalent columns and add them to + // our base value. + foreach ($db + ->select("id") + ->from("items") + ->where("parent_id", "=", $this->id) + ->where($sort_column, "=", $child->$sort_column) + ->merge_where($where) + ->order_by(array("id" => "ASC")) + ->execute() as $row) { + $position++; + if ($row->id == $child->id) { + break; + } + } + } else { + // There are NULLs in the sort column, so we can't use MySQL comparators. Fall back to + // iterating over every child row to get to the current one. This can be wildly inefficient + // for really large albums, but it should be a rare case that the user is sorting an album + // with null values in the sort column. + // + // Reproduce the children() functionality here using Database directly to avoid loading the + // whole ORM for each row. + $order_by = array($this->sort_column => $this->sort_order); + // Use id as a tie breaker + if ($this->sort_column != "id") { + $order_by["id"] = "ASC"; + } + + $position = 0; + foreach ($db->select("id") + ->from("items") + ->where("parent_id", "=", $this->id) + ->merge_where($where) + ->order_by($order_by) + ->execute() as $row) { + $position++; + if ($row->id == $child->id) { + break; + } + } + } + + return $position;*/ + } + + /** + * Return an tag for the thumbnail. + * @param array $extra_attrs Extra attributes to add to the img tag + * @param int (optional) $max Maximum size of the thumbnail (default: null) + * @param boolean (optional) $center_vertically Center vertically (default: false) + * @return string + */ + public function thumb_img($extra_attrs=array(), $max=null, $center_vertically=false) { + return ""; + } + + /** + * Calculate the largest width/height that fits inside the given maximum, while preserving the + * aspect ratio. + * @param int $max Maximum size of the largest dimension + * @return array + */ + public function scale_dimensions($max) { + } + + /** + * Return an tag for the resize. + * @param array $extra_attrs Extra attributes to add to the img tag + * @return string + */ + public function resize_img($extra_attrs) { + } + + /** + * Return a flowplayer