Added popup functionality and Library

* doPopup() JavaScript call creates a centered popup div with user
    defined width, height, title, content, and calls an optional
    callback function

* Library with currently non-modifiable book list, and a popup with the
    books' details

Signed-off-by: Gergely Polonkai <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely 2012-08-08 22:15:51 +02:00
parent 624e56389e
commit 55cde1594b
19 changed files with 1128 additions and 12 deletions

17
TODO
View File

@ -1,3 +1,5 @@
PDF header fix
User User
FavouriteForumTopics FavouriteForumTopics
@ -28,7 +30,9 @@ PollAnswer
Article check if public Article check if public
UserForumViewed UserForumViewed
it should contain records that show the last viewed post in each forum topic User
ForumTopic
timestamp of last visit
BlogPost BlogPost
id id
@ -55,17 +59,6 @@ ForumPost
last edit reason last edit reason
edit count edit count
Library
id
owner
author
title
year
borrowable
borrowed by
borrower returned
commentable
Event Event
last edited by last edited by
last edited timestamp last edited timestamp

View File

@ -23,6 +23,7 @@ class AppKernel extends Kernel
new Ivory\CKEditorBundle\IvoryCKEditorBundle(), new Ivory\CKEditorBundle\IvoryCKEditorBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(), new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Io\TcpdfBundle\IoTcpdfBundle(), new Io\TcpdfBundle\IoTcpdfBundle(),
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
// Own bundles // Own bundles
new KekRozsak\FrontBundle\KekRozsakFrontBundle(), new KekRozsak\FrontBundle\KekRozsakFrontBundle(),
new KekRozsak\SecurityBundle\KekRozsakSecurityBundle(), new KekRozsak\SecurityBundle\KekRozsakSecurityBundle(),

View File

@ -0,0 +1,24 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120801224509 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120801224533 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("CREATE TABLE books (id INT AUTO_INCREMENT NOT NULL, author VARCHAR(100) NOT NULL, title VARCHAR(100) NOT NULL, year INT NOT NULL, commentable TINYINT(1) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB");
$this->addSql("CREATE TABLE book_copies (id INT AUTO_INCREMENT NOT NULL, book_id INT NOT NULL, owner_id INT NOT NULL, borrower_id INT DEFAULT NULL, owner_comment LONGTEXT NOT NULL, borrowable TINYINT(1) NOT NULL, borrower_returned TINYINT(1) NOT NULL, INDEX IDX_F0A8D81116A2B381 (book_id), INDEX IDX_F0A8D8117E3C61F9 (owner_id), UNIQUE INDEX UNIQ_F0A8D81111CE312B (borrower_id), UNIQUE INDEX UNIQ_F0A8D8117E3C61F916A2B381 (owner_id, book_id), PRIMARY KEY(id)) ENGINE = InnoDB");
$this->addSql("ALTER TABLE book_copies ADD CONSTRAINT FK_F0A8D81116A2B381 FOREIGN KEY (book_id) REFERENCES books (id)");
$this->addSql("ALTER TABLE book_copies ADD CONSTRAINT FK_F0A8D8117E3C61F9 FOREIGN KEY (owner_id) REFERENCES users (id)");
$this->addSql("ALTER TABLE book_copies ADD CONSTRAINT FK_F0A8D81111CE312B FOREIGN KEY (borrower_id) REFERENCES users (id)");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE book_copies DROP FOREIGN KEY FK_F0A8D81116A2B381");
$this->addSql("DROP TABLE books");
$this->addSql("DROP TABLE book_copies");
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120806165106 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("CREATE TABLE book_would_borrow (book_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_7ED804D216A2B381 (book_id), INDEX IDX_7ED804D2A76ED395 (user_id), PRIMARY KEY(book_id, user_id)) ENGINE = InnoDB");
$this->addSql("CREATE TABLE book_would_buy (book_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_67D6BB5216A2B381 (book_id), INDEX IDX_67D6BB52A76ED395 (user_id), PRIMARY KEY(book_id, user_id)) ENGINE = InnoDB");
$this->addSql("ALTER TABLE book_would_borrow ADD CONSTRAINT FK_7ED804D216A2B381 FOREIGN KEY (book_id) REFERENCES books (id) ON DELETE CASCADE");
$this->addSql("ALTER TABLE book_would_borrow ADD CONSTRAINT FK_7ED804D2A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE");
$this->addSql("ALTER TABLE book_would_buy ADD CONSTRAINT FK_67D6BB5216A2B381 FOREIGN KEY (book_id) REFERENCES books (id) ON DELETE CASCADE");
$this->addSql("ALTER TABLE book_would_buy ADD CONSTRAINT FK_67D6BB52A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("DROP TABLE book_would_borrow");
$this->addSql("DROP TABLE book_would_buy");
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120806165716 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE book_copies ADD buyable TINYINT(1) NOT NULL");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE book_copies DROP buyable");
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration,
Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your need!
*/
class Version20120808111846 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE book_copies CHANGE owner_comment owner_comment LONGTEXT DEFAULT NULL");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE book_copies CHANGE owner_comment owner_comment LONGTEXT NOT NULL");
}
}

View File

@ -11,14 +11,32 @@
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="{{ asset('js/jquery-cluetip/lib/jquery.hoverIntent.js')}}"></script> <script type="text/javascript" src="{{ asset('js/jquery-cluetip/lib/jquery.hoverIntent.js')}}"></script>
<script type="text/javascript" src="{{ asset('js/jquery-cluetip/jquery.cluetip.js') }}"></script> <script type="text/javascript" src="{{ asset('js/jquery-cluetip/jquery.cluetip.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/jquery.tinyscrollbar.min.js') }}"></script>
<script type="text/javascript" src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script type="text/javascript" src="{{ path('fos_js_routing_js', {callback: 'fos.Router.setData'}) }}"></script>
{% block additional_js %}{% endblock %} {% block additional_js %}{% endblock %}
</head> </head>
<body> <body>
<div id="popup-container">
<div id="popup-close"></div>
<div id="popup-inside">
<div id="popup-title"></div>
<div id="popup-scrollable">
<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>
<div class="viewport">
<div class="overview" id="popup-content"></div>
</div>
</div>
</div>
</div>
<div id="top-line-wrapper"> <div id="top-line-wrapper">
<div id="top-line"> <div id="top-line">
{% if app.user %} {% if app.user %}
{% include ':Box:UserProfile.html.twig' %} {% include ':Box:UserProfile.html.twig' %}
{% include ':Box:Events.html.twig' %} {% include ':Box:Events.html.twig' %}
<div id="konyvtar-gomb">
<a href="{{ path('KekRozsakFrontBundle_bookList') }}">[könyvtár gomb]</a>
</div>
{% else %} {% else %}
{% include ':Box:Login.html.twig' %} {% include ':Box:Login.html.twig' %}
{% endif %} {% endif %}
@ -120,6 +138,40 @@
} }
}); });
{% endif %} {% endif %}
jQuery.fn.center = function() {
this.css('top', Math.max(0, (($(window).height() - this.outerHeight()) / 2) + $(window).scrollTop()) + 'px');
this.css('left', Math.max(0, (($(window).width() - this.outerWidth()) / 2) + $(window).scrollLeft()) + 'px');
return this;
};
$('#popup-close').click(function() { $('#popup-container').fadeOut(); });
$('#popup-scrollable').tinyscrollbar();
function doPopup(title, content, url, w, h, callback)
{
$('#popup-title').html(title);
$('#popup-content').html(content);
$('#popup-container').css('width', w + 'px');
$('#popup-container').css('height', h + 'px');
$('#popup-inside').css('width', (w - 8) + 'px');
$('#popup-inside').css('height', (h - 8) + 'px');
$('#popup-scrollable').css('width', (w - 8) + 'px');
$('#popup-scrollable .viewport').css('width', (w - 28) + 'px');
$('#popup-scrollable .viewport').css('height', (h - 54) + 'px');
$('#popup-container').center();
$('#popup-container').fadeIn();
$.ajax({
method: 'GET',
url: url
}).done(function(data) {
$('#popup-content').html(data);
$('#popup-scrollable').tinyscrollbar();
$('.userdata').cluetip();
if (callback != null)
callback();
}).error(function() {
$('#popup-content').html('Nem sikerült betölteni a könyv adatait.');
});
}
</script> </script>
{% block bottomscripts %}{% endblock %} {% block bottomscripts %}{% endblock %}
</body> </body>

View File

@ -1,3 +1,6 @@
fos_js_routing:
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml"
KekRozsakAdminBundle: KekRozsakAdminBundle:
resource: "@KekRozsakAdminBundle/Controller/" resource: "@KekRozsakAdminBundle/Controller/"
type: annotation type: annotation

View File

@ -26,6 +26,7 @@
"jms/di-extra-bundle": "1.0.*", "jms/di-extra-bundle": "1.0.*",
"doctrine/doctrine-migrations-bundle": "dev-master", "doctrine/doctrine-migrations-bundle": "dev-master",
"egeloen/ckeditor-bundle": "dev-master", "egeloen/ckeditor-bundle": "dev-master",
"friendsofsymfony/jsrouting-bundle": "dev-master",
"gergelypolonkai/tcpdfbundle": "dev-master" "gergelypolonkai/tcpdfbundle": "dev-master"
}, },
"scripts": { "scripts": {

View File

@ -0,0 +1,135 @@
<?php
namespace KekRozsak\FrontBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Response;
use KekRozsak\FrontBundle\Entity\Book;
use KekRozsak\FrontBundle\Entity\BookCopy;
class BookController extends Controller
{
/**
* @Route("/konyvtar", name="KekRozsakFrontBundle_bookList")
* @Template()
*/
public function listAction()
{
$query = $this->getDoctrine()->getEntityManager()->createQuery('SELECT b FROM KekRozsakFrontBundle:Book b ORDER BY b.author ASC, b.title ASC, b.year ASC');
$books = $query->getResult();
return array(
'books' => $books,
);
}
/**
* @Route("/konyvadat/{id}/ajax.{_format}", name="KekRozsakFrontBundle_bookAjaxData", defaults={"_format": "html"}, options={"expose": true})
* @Template()
* @ParamConverter("book")
*/
public function ajaxDataAction(Book $book)
{
return array(
'book' => $book,
);
}
/**
* @Route("/konyv/torles/{id}", name="KekRozsakFrontBundle_bookDeleteCopy", requirements={"id": "\d+"}, options={"expose": true})
* @ParamConverter("book")
*/
public function ajaxDeleteBookAction(Book $book)
{
$copies = $book->getUsersCopies($this->get('security.context')->getToken()->getUser());
$em = $this->getDoctrine()->getEntityManager();
$copies->forAll(function($key, $copy) use ($book, $em) {
$book->removeCopy($copy);
$em->remove($copy);
});
$em->persist($book);
$em->flush();
return new Response();
}
/**
* @Route("/konyv/ujpeldany/{id}", name="KekRozsakFrontBundle_bookAddCopy", requirements={"id": "\d+"}, options={"expose": true})
* @ParamConverter("book")
*/
public function ajaxAddBookAction(Book $book)
{
$user = $this->get('security.context')->getToken()->getUser();
$copies = $book->getUsersCopies($user);
if ($copies->count() == 0)
{
$copy = new BookCopy($book, $user);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($copy);
$em->flush();
}
return new Response();
}
/**
* @Route("/konyv/kolcsonozheto/{id}/{newValue}", name="KekRozsakFrontBundle_bookSetCopyBorrowable", requirements={"id": "\d+"}, options={"expose": true})
* @ParamConverter("book")
*/
public function ajaxSetBookCopyBorrowableAction(Book $book, $newValue)
{
$user = $this->get('security.context')->getToken()->getUser();
$copies = $book->getUsersCopies($user);
$em = $this->getDoctrine()->getEntityManager();
$copies->forAll(function($key, $copy) use ($em, $newValue) {
$copy->setBorrowable($newValue);
$em->persist($copy);
});
$em->flush();
return new Response();
}
/**
* @Route("/konyv/megveheto/{id}/{newValue}", name="KekRozsakFrontBundle_bookSetCopyForSale", requirements={"id": "\d+"}, options={"expose": true})
* @ParamConverter("book")
*/
public function ajaxSetBookCopyForSaleAction(Book $book, $newValue)
{
$user = $this->get('security.context')->getToken()->getUser();
$copies = $book->getUsersCopies($user);
$em = $this->getDoctrine()->getEntityManager();
$copies->forAll(function($key, $copy) use ($em, $newValue) {
$copy->setBuyable($newValue);
$em->persist($copy);
});
$em->flush();
return new Response();
}
/**
* @Route("/konyv/szeretnek/{id}/{wantToBuy}", name="KekRozsakFrontBundle_bookWantOne", requirements={"id": "\d+"}, options={"expose": true})
* @ParamConverter("book")
*/
public function ajaxWantABookAction(Book $book, $wantToBuy)
{
$user = $this->get('security.context')->getToken()->getUser();
if ($wantToBuy)
{
$book->addWouldBuy($user);
}
else
{
$book->addWouldBorrow($user);
}
$em = $this->getDoctrine()->getEntityManager();
$em->persist($book);
$em->flush();
return new Response();
}
}

View File

@ -0,0 +1,299 @@
<?php
namespace KekRozsak\FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
use Doctrine\Common\Collections\ArrayCollection;
use KekRozsak\SecurityBundle\Entity\User;
/**
* KekRozsak\FrontBundle\Entity\Book
*
* @ORM\Entity
* @ORM\Table(name="books")
*
* @DoctrineAssert\UniqueEntity(fields={"author", "title", "year"})
*/
class Book
{
public function __construct()
{
$this->copies = new ArrayCollection();
$this->wouldBorrow = new ArrayCollection();
$this->wouldBuy = new ArrayCollection();
}
/**
* @var integer $id
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @var Doctrine\Common\Collections\ArrayCollection $copies
*
* @ORM\OneToMany(targetEntity="BookCopy", mappedBy="book")
*/
protected $copies;
/**
* Remove a copy
*
* @param KekRozsak\FrontBundle\Entity\BookCopy $copy
* @return Book
*/
public function removeCopy(BookCopy $copy)
{
$this->copies->removeElement($copy);
}
/**
* Get copies
*
* @return Doctrine\Common\Collections\ArrayCollection
*/
public function getCopies()
{
return $this->copies;
}
public function getCopiesBorrowed()
{
return $this->copies->filter(function($copy) {
return ($copy->getBorrower() !== null);
});
}
public function getCopiesBorrowedByUser(User $user)
{
return $this->copies->filter(function($copy) use ($user) {
return ($copy->getBorrower() == $user);
});
}
public function getCopiesBorrowedReturnedByUser(User $user)
{
return $this->copies->filter(function($copy) use ($user) {
return ($copy->getBorrower() == $user) && ($copy->isBorrowerReturned());
});
}
public function getCopiesBorrowable()
{
return $this->copies->filter(function($copy) {
return $copy->isBorrowable();
});
}
public function getUsersCopies(User $user)
{
return $this->copies->filter(function ($copy) use ($user) {
return ($copy->getOwner() == $user);
});
}
public function getUsersCopiesBorrowable(User $user)
{
return $this->copies->filter(function($copy) use ($user) {
return (($copy->getOwner() == $user) && $copy->isBorrowable());
});
}
public function getUsersCopiesBuyable(User $user)
{
return $this->copies->filter(function($copy) use ($user) {
return (($copy->getOwner() == $user) && $copy->isBuyable());
});
}
/**
* @var string $author
*
* @ORM\Column(type="string", length=100, nullable=false)
*/
protected $author;
/**
* Set author
*
* @param string $author
* @return Book
*/
public function setAuthor($author)
{
$this->author = $author;
return $this;
}
/**
* Get author
*
* @return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* @var string $title
*
* @ORM\Column(type="string", length=100, nullable=false)
*/
protected $title;
/**
* Set title
*
* @param string $title
* @return Book
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @var integer $year
*
* @ORM\Column(type="integer", nullable=false)
*/
protected $year;
/**
* Set year
*
* @param integer $year
* @return Book
*/
public function setYear($year)
{
$this->year = $year;
return $this;
}
/**
* Get year
*
* @return integer
*/
public function getYear()
{
return $this->year;
}
/**
* @var boolean $commentable
*
* @ORM\Column(type="boolean", nullable=false)
*/
protected $commentable;
/**
* @var Doctrine\Common\Collections\ArrayCollection $wouldBorrow
*
* @ORM\ManyToMany(targetEntity="KekRozsak\SecurityBundle\Entity\User")
* @ORM\JoinTable(name="book_would_borrow")
*/
protected $wouldBorrow;
/**
* Add a user for want-to-borrowers
*
* @param KekRozsak\SecurityBundle\Entity\User $user
* @return Book
*/
public function addWouldBorrow(User $user)
{
$this->wouldBorrow->add($user);
return $this;
}
/**
* Get wouldBorrow list
*
* @return Doctrine\Common\Collections\ArrayCollection
*/
public function getWouldBorrow()
{
return $this->wouldBorrow;
}
/**
* Check if specified user would borrow this book
*
* @param KekRozsak\SecurityBundle\Entity\User $user
* @return boolean
*/
public function userWouldBorrow(User $user)
{
return $this->wouldBorrow->contains($user);
}
/**
* @var Doctrine\Common\Collections\ArrayCollection $wouldBuy
*
* @ORM\ManyToMany(targetEntity="KekRozsak\SecurityBundle\Entity\User")
* @ORM\JoinTable(name="book_would_buy")
*/
protected $wouldBuy;
/**
* Add a user for want-to-buyers
*
* @param KekRozsak\SecurityBundle\Entity\User $user
* @return Book
*/
public function addWouldBuy(User $user)
{
$this->wouldBuy->add($user);
return $this;
}
/**
* Get wouldBuy list
*
* @return Doctrine\Common\Collections\ArrayCollection
*/
public function getWouldBuy()
{
return $this->wouldBuy;
}
/**
* Check if specified user would buy this book
*
* @param KekRozsak\SecurityBundle\Entity\User $user
* @return boolean
*/
public function userWouldBuy(User $user)
{
return $this->wouldBuy->contains($user);
}
}

View File

@ -0,0 +1,165 @@
<?php
namespace KekRozsak\FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
use KekRozsak\FrontBundle\Entity\Book;
use KekRozsak\SecurityBundle\Entity\User;
/**
* KekRozsak\FrontBundle\Entity\BookCopy
* @ORM\Entity
* @ORM\Table(name="book_copies", uniqueConstraints={
* @ORM\UniqueConstraint(columns={"owner_id", "book_id"})
* })
*
* @DoctrineAssert\UniqueEntity(fields={"owner_id", "book_id"})
*/
class BookCopy
{
public function __construct(Book $book, User $owner)
{
$this->book = $book;
$this->owner = $owner;
$this->borrowable = false;
$this->buyable = false;
$this->borrower = null;
$this->borrowerReturned = true;
}
/**
* @var integer $id
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
/**
* @var KekRozsak\FrontBundle\Entity\Book $book
*
* @ORM\ManyToOne(targetEntity="Book", inversedBy="copies")
* @ORM\JoinColumn(nullable=false)
*/
protected $book;
/**
* @var KekRozsak\SecurityBundle\Entity\User $owner
*
* @ORM\ManyToOne(targetEntity="KekRozsak\SecurityBundle\Entity\User")
* @ORM\JoinColumn(nullable=false)
*/
protected $owner;
/**
* Get owner
*
* @return KekRozsak\SecurityBundle\Entity\User
*/
public function getOwner()
{
return $this->owner;
}
/**
* @var string $ownerComment
*
* @ORM\Column(type="text", name="owner_comment", nullable=true)
*/
protected $ownerComment;
/**
* @var boolean $borrowable
*
* @ORM\Column(type="boolean", nullable=false)
*/
protected $borrowable;
/**
* Set borrowable
*
* @param boolean $borrowable
* @return BookCopy
*/
public function setBorrowable($borrowable)
{
$this->borrowable = $borrowable;
return $this;
}
/**
* Get borrowable
*
* @return boolean
*/
public function isBorrowable()
{
return $this->borrowable;
}
/**
* @var boolean $buyable
*
* @ORM\Column(type="boolean", nullable=false)
*/
protected $buyable;
/**
* Set buyable
*
* @param boolean $buyable
* @return BookCopy
*/
public function setBuyable($buyable)
{
$this->buyable = $buyable;
return $this;
}
/**
* Get borrowable
*
* @return boolean
*/
public function isBuyable()
{
return $this->buyable;
}
/**
* @var KekRozsak\SecurityBundle\Entity\User $borrower
*
* @ORM\OneToOne(targetEntity="KekRozsak\SecurityBundle\Entity\User")
*/
protected $borrower;
/**
* Get borrower
*
* @return KekRozsak\SecurityBundle\Entity\User
*/
public function getBorrower()
{
return $this->borrower;
}
/**
* @var boolean $borrowerReturned
*
* @ORM\Column(type="boolean", nullable=false, name="borrower_returned")
*/
protected $borrowerReturned;
/**
* Get borrowerReturned
*
* @return boolean
*/
public function isBorrowerReturned()
{
return $this->borrowerReturned();
}
}

View File

@ -0,0 +1,63 @@
{# vim: ft=htmljinja
#}
<p>
<strong>Szerző:</strong> {{ book.author }}<br />
<strong>Cím:</strong> {{ book.title }}<br />
<strong>Kiadás éve:</strong> {{ book.year }}<br />
</p>
<p>
Nekem van <strong>{{ book.usersCopies(app.user)|length }}</strong>, ebből kölcsön van adva <strong>X</strong>.<br />
A teljes közösségnek összesen <strong>{{ book.copies|length }}</strong> példánya van.<br />
Kölcsönkérhető <strong>{{ book.copiesBorrowable|length }}</strong> példány, ebből <strong>{{ book.copiesBorrowedByUser(app.user)|length }}</strong> nálam van.<br />
</p>
<p>
{% if book.usersCopies(app.user)|length == 0 %}
<span class="gomb add-copy-button" id="add-copy-button-{{ book.id }}">[Nekem is van egy]</span>
{% else %}
<span class="gomb delete-copy-button" id="delete-copy-button-{{ book.id }}">[Nincs már]</span>
{# TODO
<span class="gomb">[Eladtam valakinek a körben]</span>
#}
{% if book.usersCopiesBorrowable(app.user)|length == 0 %}
<span class="gomb mine-is-borrowable-button" id="mine-is-borrowable-button-{{ book.id }}">[Az enyém is kölcsönkérhető]</span>
{% else %}
<span class="gomb mine-is-not-borrowable-button" id="mine-is-not-borrowable-button-{{ book.id }}">[Nem szeretném kölcsönadni]</span>
{% endif %}
{% endif %}
{% if book.usersCopies(app.user)|length > 0 %}
{% if book.usersCopiesBuyable(app.user)|length == 0 %}
<span class="gomb mine-is-for-sale-button" id="mine-is-for-sale-button-{{ book.id }}">[Az enyém eladó]</span>
{% else %}
<span class="gomb mine-is-not-for-sale-button" id="mine-is-not-for-sale-button-{{ book.id }}">[Nem szeretném eladni]</span>
{% endif %}
{% endif %}
{% if book.copiesBorrowedByUser(app.user)|length == 0 and book.usersCopies(app.user)|length == 0 and not book.userWouldBorrow(app.user) %}
<span class="gomb want-to-borrow-button" id="want-to-borrow-button-{{ book.id }}">[Kérek egyet kölcsön]</span>
{% endif %}
{% if book.usersCopies(app.user)|length == 0 and not book.userWouldBuy(app.user) %}
<span class="gomb want-to-buy-button" id="want-to-buy-button-{{ book.id }}">[Vennék egyet]</span>
{% endif %}
</p>
{% if book.wouldBuy|length > 0 %}
<p>
Ők szeretnének egyet kölcsönkérni:<br />
<ul>
{% for user in book.wouldBorrow %}
<li>{{ user|userdataspan }}</li>
{% endfor %}
</ul>
</p>
{% endif %}
{% if book.wouldBuy|length > 0 %}
<p>
Ők szeretnének venni egyet:<br />
<ul>
{% for user in book.wouldBuy %}
<li>{{ user|userdataspan }}</li>
{% endfor %}
</ul>
</p>
{% endif %}

View File

@ -0,0 +1,133 @@
{# vim: ft=htmljinja
#}
{% extends '::main_template.html.twig' %}
{% block title %} - Könyvtár{% endblock %}
{% block content %}
<h3>Könyvtár</h3>
[Saját könyveim] [Nálam lévő kölcsönzött könyvek]
{% if books|length > 0 %}
<table>
<thead>
<tr>
<td>Szerző</td>
<td>Cím</td>
<td>Év</td>
<td>Összes</td>
<td>Kölcsönözhető</td>
<td>Saját</td>
<td>Nálam (Vissza)</td>
</tr>
</thead>
<tbody>
{% for book in books %}
<tr class="book-row popup-opener" id="book-{{ book.id }}">
<td class="popup-opener">{{ book.author }}</td>
<td>{{ book.title }}</td>
<td>{{ book.year }}</td>
<td>{{ book.copies|length }}</td>
<td>{{ book.copiesBorrowable|length }}</td>
<td>{{ book.usersCopies(app.user)|length }}</td>
<td>{{ book.copiesBorrowedByUser(app.user)|length }} ({{ book.copiesBorrowedReturnedByUser(app.user)|length }})</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endblock %}
{% block bottomscripts %}
<script type="text/javascript">
$('.book-row').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^book-\d+$/))
return false;
bookid = $(this).attr('id').replace(/^book-/, '');
bookUrl = Routing.generate('KekRozsakFrontBundle_bookAjaxData', { id: bookid, _format: 'html' });
bookCallback = function() {
// TODO: Change alert() calls to HTML flashes
$('.delete-copy-button').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^delete-copy-button-\d+$/))
return false;
bookid = $(this).attr('id').replace(/^delete-copy-button-/, '');
url = Routing.generate('KekRozsakFrontBundle_bookDeleteCopy', { id: bookid });
$.ajax({
method: 'GET',
url: url
}).done(function() {
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
}).error(function() {
alert('Nem sikerült törölni');
});
});
$('.add-copy-button').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^add-copy-button-\d+$/))
return false;
bookid = $(this).attr('id').replace(/^add-copy-button-/, '');
url = Routing.generate('KekRozsakFrontBundle_bookAddCopy', { id: bookid });
$.ajax({
method: 'GET',
url: url
}).done(function() {
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
}).error(function() {
alert('Nem sikerült bejegyezni ezt a példányt');
});
});
$('.mine-is-borrowable-button, .mine-is-not-borrowable-button').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^mine-is-(not-)?borrowable-button-\d+$/))
return false;
isBorrowable = ($(this).attr('id').match(/^mine-is-not-borrowable-button-\d+$/)) ? 0 : 1;
bookid = $(this).attr('id').replace(/^mine-is-(not-)?borrowable-button-/, '');
url = Routing.generate('KekRozsakFrontBundle_bookSetCopyBorrowable', { id: bookid, newValue: isBorrowable });
$.ajax({
method: 'GET',
url: url
}).done(function() {
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
}).error(function() {
alert('Nem sikerült bejegyezni ezt a példányt');
});
});
$('.mine-is-for-sale-button, .mine-is-not-for-sale-button').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^mine-is-(not-)?for-sale-button-\d+$/))
return false;
isForSale = ($(this).attr('id').match(/^mine-is-not-for-sale-button-\d+$/)) ? 0 : 1;
bookid = $(this).attr('id').replace(/^mine-is-(not-)?for-sale-button-/, '');
url = Routing.generate('KekRozsakFrontBundle_bookSetCopyForSale', { id: bookid, newValue: isForSale });
$.ajax({
method: 'GET',
url: url
}).done(function() {
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
}).error(function() {
alert('Nem sikerült bejegyezni ezt a példányt');
});
});
$('.want-to-buy-button, .want-to-borrow-button').click(function() {
bookid = 0;
if (!$(this).attr('id').match(/^want-to-(buy|borrow)-button-\d+$/))
return false;
toBuy = ($(this).attr('id').match(/^want-to-buy-button-\d+$/)) ? 1 : 0;
bookid = $(this).attr('id').replace(/^want-to-(buy|borrow)-button-/, '');
url = Routing.generate('KekRozsakFrontBundle_bookWantOne', { id: bookid, wantToBuy: toBuy });
$.ajax({
method: 'GET',
url: url
}).done(function() {
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
}).error(function() {
alert('Nem sikerült bejegyezni a kérést');
});
});
};
doPopup('', 'Betöltés...', bookUrl, 400, 300, bookCallback);
});
</script>
{% endblock bottomscripts %}

View File

@ -0,0 +1,13 @@
/**
* Portions of this code are from the Google Closure Library,
* received from the Closure Authors under the Apache 2.0 license.
*
* All other code is (C) 2011 FriendsOfSymfony and subject to the MIT license.
*/
(function() {var g=this;function i(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&b!==void 0?d[e]=b:d=d[e]?d[e]:d[e]={}}
function k(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
else if(b=="function"&&typeof a.call=="undefined")return"object";return b};var l=/^[a-zA-Z0-9\-_.!~*'()]*$/;function m(a){a=""+a;return!l.test(a)?encodeURIComponent(a):a};var n=Array.prototype,p=n.forEach?function(a,b,c){n.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=typeof a=="string"?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)};function q(a){var b=0,c;for(c in a)b++;return b}function r(a){var b={},c;for(c in a)b[c]=a[c];return b};function s(a,b){this.b={};this.a=[];var c=arguments.length;if(c>1){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a){var e;if(a instanceof s){t(a);d=a.a.concat();t(a);e=[];for(c=0;c<a.a.length;c++)e.push(a.b[a.a[c]])}else{var c=[],f=0;for(d in a)c[f++]=d;d=c;c=[];f=0;for(e in a)c[f++]=a[e];e=c}for(c=0;c<d.length;c++)this.set(d[c],e[c])}}s.prototype.e=0;s.prototype.m=0;
function t(a){if(a.e!=a.a.length){for(var b=0,c=0;b<a.a.length;){var d=a.a[b];Object.prototype.hasOwnProperty.call(a.b,d)&&(a.a[c++]=d);b++}a.a.length=c}if(a.e!=a.a.length){for(var e={},c=b=0;b<a.a.length;)d=a.a[b],Object.prototype.hasOwnProperty.call(e,d)||(a.a[c++]=d,e[d]=1),b++;a.a.length=c}}s.prototype.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.b,a)?this.b[a]:b};
s.prototype.set=function(a,b){Object.prototype.hasOwnProperty.call(this.b,a)||(this.e++,this.a.push(a),this.m++);this.b[a]=b};function u(a){if(a[1]){var b=a[0],c=b.indexOf("#");c>=0&&(a.push(b.substr(c)),a[0]=b=b.substr(0,c));c=b.indexOf("?");c<0?a[1]="?":c==b.length-1&&(a[1]=void 0)}return a.join("")}function v(a,b){for(var c in b){var d=c,e=b[c],f=a;if(k(e)=="array")for(var h=0;h<e.length;h++)f.push("&",d),e[h]!==""&&f.push("=",m(e[h]));else e!=null&&(f.push("&",d),e!==""&&f.push("=",m(e)))}return a};function w(a,b){this.d=a||{c:""};this.g(b||{})}(function(a){a.f=function(){return a.l||(a.l=new a)}})(w);w.prototype.g=function(a){this.h=new s(a)};w.prototype.i=function(a){this.d.c=a};w.prototype.k=function(){return this.d.c};
w.prototype.j=function(a,b){if(!Object.prototype.hasOwnProperty.call(this.h.b,a))throw Error('The route "'+a+'" does not exist.');var c=this.h.get(a),d=b||{},e=r(d),f="",h=!0;p(c.tokens,function(b){if("text"===b[0])f=b[1]+f,h=!1;else if("variable"===b[0]){if(!1===h||!(b[3]in c.defaults)||b[3]in d&&d[b[3]]!=c.defaults[b[3]]){var j;if(b[3]in d){j=d[b[3]];var o=b[3];o in e&&delete e[o]}else if(b[3]in c.defaults)j=c.defaults[b[3]];else{if(h)return;throw Error('The route "'+a+'" requires the parameter "'+
b[3]+'".');}if(!(!0===j||!1===j||""===j)||!h)f=b[1]+encodeURIComponent(j).replace(/%2F/g,"/")+f;h=!1}}else throw Error('The token type "'+b[0]+'" is not supported.');});f===""&&(f="/");q(e)>0&&(f=u(v([f],e)));return this.d.c+f};i("fos.Router",w);i("fos.Router.setData",function(a){var b=w.f();b.i(a.base_url);b.g(a.routes)});w.getInstance=w.f;w.prototype.setRoutes=w.prototype.g;w.prototype.setBaseUrl=w.prototype.i;w.prototype.getBaseUrl=w.prototype.k;w.prototype.generate=w.prototype.j;window.Routing=w.f();})();

View File

@ -137,6 +137,16 @@ body {
padding: 5px; padding: 5px;
} }
#konyvtar-gomb {
float: left;
padding: 5px;
}
#konyvtar-gomb a {
color: inherit;
text-decoration: none;
}
#bottom-line { #bottom-line {
position: fixed; position: fixed;
left: 0; left: 0;
@ -358,3 +368,102 @@ td.uj-post p .kuldes-gomb {
font-style: italic; font-style: italic;
} }
#popup-container {
display: none;
position: fixed;
height: 300px;
width: 200px;
background: #ffffff;
z-index: 80;
}
#popup-close {
position: absolute;
width: 16px;
height: 16px;
top: -5px;
right: -5px;
background-image: url('../images/no.png');
}
#popup-inside {
border: 1px solid black;
height: 292px;
width: 192px;
margin-left: auto;
margin-right: auto;
margin-top: 3px;
}
#popup-title {
font-weight: bold;
padding: 5px;
}
#popup-content {
padding: 3px;
}
#popup-scrollable {
width: 192px;
clear: both;
margin: 20px 0 10px;
}
#popup-scrollable .viewport {
width: 172px;
height: 246px;
overflow: hidden;
position: relative;
}
#popup-scrollable .overview {
list-style: none;
position: absolute;
left: 0;
top: 0;
}
#popup-scrollable .thumb .end, #popup-scrollable .thumb {
background-color: #003D5D;
}
#popup-scrollable .scrollbar {
position: relative;
float: right;
width: 15px;
}
#popup-scrollable .track {
background-color: #D8EEFD;
height: 100%;
width: 13px;
position: relative;
padding: 0 1px;
}
#popup-scrollable .thumb {
height: 20px;
width: 13px;
cursor: pointer;
overflow: hidden;
position: absolute;
top: 0;
}
#popup-scrollable .thumb .end {
overflow: hidden;
height: 5px;
width: 13px;
}
#popup-scrollable .disable {
display: none;
}
.gomb {
background-color: #cccccc;
color: black;
white-space: nowrap;
}

BIN
web/images/no.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

1
web/js/jquery.tinyscrollbar.min.js vendored Normal file
View File

@ -0,0 +1 @@
(function(a){a.tiny=a.tiny||{};a.tiny.scrollbar={options:{axis:"y",wheel:40,scroll:true,lockscroll:true,size:"auto",sizethumb:"auto"}};a.fn.tinyscrollbar=function(d){var c=a.extend({},a.tiny.scrollbar.options,d);this.each(function(){a(this).data("tsb",new b(a(this),c))});return this};a.fn.tinyscrollbar_update=function(c){return a(this).data("tsb").update(c)};function b(q,g){var k=this,t=q,j={obj:a(".viewport",q)},h={obj:a(".overview",q)},d={obj:a(".scrollbar",q)},m={obj:a(".track",d.obj)},p={obj:a(".thumb",d.obj)},l=g.axis==="x",n=l?"left":"top",v=l?"Width":"Height",r=0,y={start:0,now:0},o={},e=("ontouchstart" in document.documentElement)?true:false;function c(){k.update();s();return k}this.update=function(z){j[g.axis]=j.obj[0]["offset"+v];h[g.axis]=h.obj[0]["scroll"+v];h.ratio=j[g.axis]/h[g.axis];d.obj.toggleClass("disable",h.ratio>=1);m[g.axis]=g.size==="auto"?j[g.axis]:g.size;p[g.axis]=Math.min(m[g.axis],Math.max(0,(g.sizethumb==="auto"?(m[g.axis]*h.ratio):g.sizethumb)));d.ratio=g.sizethumb==="auto"?(h[g.axis]/m[g.axis]):(h[g.axis]-j[g.axis])/(m[g.axis]-p[g.axis]);r=(z==="relative"&&h.ratio<=1)?Math.min((h[g.axis]-j[g.axis]),Math.max(0,r)):0;r=(z==="bottom"&&h.ratio<=1)?(h[g.axis]-j[g.axis]):isNaN(parseInt(z,10))?r:parseInt(z,10);w()};function w(){var z=v.toLowerCase();p.obj.css(n,r/d.ratio);h.obj.css(n,-r);o.start=p.obj.offset()[n];d.obj.css(z,m[g.axis]);m.obj.css(z,m[g.axis]);p.obj.css(z,p[g.axis])}function s(){if(!e){p.obj.bind("mousedown",i);m.obj.bind("mouseup",u)}else{j.obj[0].ontouchstart=function(z){if(1===z.touches.length){i(z.touches[0]);z.stopPropagation()}}}if(g.scroll&&window.addEventListener){t[0].addEventListener("DOMMouseScroll",x,false);t[0].addEventListener("mousewheel",x,false)}else{if(g.scroll){t[0].onmousewheel=x}}}function i(A){var z=parseInt(p.obj.css(n),10);o.start=l?A.pageX:A.pageY;y.start=z=="auto"?0:z;if(!e){a(document).bind("mousemove",u);a(document).bind("mouseup",f);p.obj.bind("mouseup",f)}else{document.ontouchmove=function(B){B.preventDefault();u(B.touches[0])};document.ontouchend=f}}function x(B){if(h.ratio<1){var A=B||window.event,z=A.wheelDelta?A.wheelDelta/120:-A.detail/3;r-=z*g.wheel;r=Math.min((h[g.axis]-j[g.axis]),Math.max(0,r));p.obj.css(n,r/d.ratio);h.obj.css(n,-r);if(g.lockscroll||(r!==(h[g.axis]-j[g.axis])&&r!==0)){A=a.event.fix(A);A.preventDefault()}}}function u(z){if(h.ratio<1){if(!e){y.now=Math.min((m[g.axis]-p[g.axis]),Math.max(0,(y.start+((l?z.pageX:z.pageY)-o.start))))}else{y.now=Math.min((m[g.axis]-p[g.axis]),Math.max(0,(y.start+(o.start-(l?z.pageX:z.pageY)))))}r=y.now*d.ratio;h.obj.css(n,-r);p.obj.css(n,y.now)}}function f(){a(document).unbind("mousemove",u);a(document).unbind("mouseup",f);p.obj.unbind("mouseup",f);document.ontouchmove=document.ontouchend=null}return c()}}(jQuery));