mirror of
https://github.com/bodyrep/bodyrep-sandpit.git
synced 2026-01-25 06:11:36 +00:00
Controllers
Authentication was moved from the member controller the new AuthController. User entity created strictly for session management Symfony config Service and parameter configuration has been switched to YAML and consolidated into app/config/config.yml Removed Twig extension from the service container (services.xml) Presentation LABJS test added Some sample js added to test inline js vs callbacks vs Twig/Angular/etc Tests New units tests for Landing, Profile, Auth and Member controllers
This commit is contained in:
45
composer.json
Normal file
45
composer.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "symfony/framework-standard-edition",
|
||||
"description": "The \"Symfony Standard Edition\" distribution",
|
||||
"autoload": {
|
||||
"psr-0": { "": "src/" }
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/symfony": "2.1.*",
|
||||
"doctrine/orm": ">=2.2.3,<2.4-dev",
|
||||
"doctrine/doctrine-bundle": "1.0.*",
|
||||
"twig/extensions": "1.0.*",
|
||||
"symfony/assetic-bundle": "2.1.*",
|
||||
"symfony/swiftmailer-bundle": "2.1.*",
|
||||
"symfony/monolog-bundle": "2.1.*",
|
||||
"sensio/distribution-bundle": "2.1.*",
|
||||
"sensio/framework-extra-bundle": "2.1.*",
|
||||
"sensio/generator-bundle": "2.1.*",
|
||||
"jms/security-extra-bundle": "1.2.*",
|
||||
"jms/di-extra-bundle": "1.1.*",
|
||||
"knplabs/doctrine-behaviors": "dev-master"
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
|
||||
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"bin-dir": "bin"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"symfony-app-dir": "app",
|
||||
"symfony-web-dir": "web"
|
||||
}
|
||||
}
|
||||
68
src/BodyRep/Controller/AuthController.php
Normal file
68
src/BodyRep/Controller/AuthController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Security\Core\SecurityContext;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
# Annotations & templates
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="_auth")
|
||||
* @Template()
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
return new RedirectResponse($this->generateUrl('_login'));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @Route("/login", name="_login")
|
||||
* @Template()
|
||||
*/
|
||||
public function loginAction()
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$session = $request->getSession();
|
||||
|
||||
// get the login error if there is one
|
||||
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
|
||||
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
} else {
|
||||
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
}
|
||||
|
||||
return $this->render('BodyRep:Auth:login.html.twig', array(
|
||||
// last username entered by the user
|
||||
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
|
||||
'error' => $error,
|
||||
));
|
||||
}
|
||||
/**
|
||||
* @Route("/login/check", name="_login_check")
|
||||
* @Template()
|
||||
*/
|
||||
public function securityCheckAction()
|
||||
{
|
||||
// The security layer will intercept this request
|
||||
}
|
||||
/**
|
||||
* @Route("/logout", name="_logout")
|
||||
* @Template()
|
||||
*/
|
||||
public function logoutAction()
|
||||
{
|
||||
// The security layer will intercept this request
|
||||
}
|
||||
|
||||
public function navbarAction()
|
||||
{
|
||||
// The security layer will intercept this request
|
||||
}
|
||||
}
|
||||
65
src/BodyRep/Controller/CommentController.php
Normal file
65
src/BodyRep/Controller/CommentController.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Security\Core\SecurityContext;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use JMS\SecurityExtraBundle\Annotation\Secure;
|
||||
|
||||
# Annotations
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/", name="_profile")
|
||||
* @Template()
|
||||
*/
|
||||
public function indexAction($username)
|
||||
{
|
||||
|
||||
if ($this->getUser()->getUsername() == $username)
|
||||
return new RedirectResponse($this->generateUrl('_member_profile'));
|
||||
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
|
||||
$query = $db->createQuery('
|
||||
SELECT p
|
||||
FROM BodyRep:Profile p
|
||||
WHERE p.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$profile = $query->getSingleResult();
|
||||
$username = $this->getUser()->getUsername();
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
|
||||
return (array('sFullName' => $profile->getFullName(), 'name' => $member->getFullName()));
|
||||
|
||||
}
|
||||
/**
|
||||
* @Route("/rep", name="_profile_reputation")
|
||||
* @Template()
|
||||
*/
|
||||
public function reputationAction($username)
|
||||
{
|
||||
return $this->indexAction($username);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ class LandingController extends Controller
|
||||
* or @Template annotation as demonstrated in DemoController.
|
||||
*
|
||||
*/
|
||||
|
||||
return $this->render('BodyRep:Landing:index.html.twig');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,50 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Controller;
|
||||
use BodyRep\Form\Profile;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
# Core requirements
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Security\Core\SecurityContext;
|
||||
# use JMS\SecurityExtraBundle\Annotation\Secure;
|
||||
|
||||
# Entities
|
||||
use BodyRep\Form\Profile;
|
||||
|
||||
# Annotations & templates
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
|
||||
use JMS\SecurityExtraBundle\Annotation\Secure;
|
||||
# Ensure container access to member object
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class MemberController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/login", name="_login")
|
||||
* @Template()
|
||||
*/
|
||||
public function loginAction()
|
||||
private $member;
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
if ($this->get('request')->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
|
||||
$error = $this->get('request')->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
} else {
|
||||
$error = $this->get('request')->getSession()->get(SecurityContext::AUTHENTICATION_ERROR);
|
||||
}
|
||||
parent::setContainer($container);
|
||||
|
||||
return array(
|
||||
'last_username' => $this->get('request')->getSession()->get(SecurityContext::LAST_USERNAME),
|
||||
'error' => $error,
|
||||
);
|
||||
}
|
||||
# Lookup member if logged in
|
||||
$user = $this->getUser();
|
||||
|
||||
/**
|
||||
* @Route("/login_check", name="_security_check")
|
||||
*/
|
||||
public function securityCheckAction()
|
||||
if (method_exists($user, 'getUsername'))
|
||||
{
|
||||
// The security layer will intercept this request
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$username = $this->getUser()->getUsername();
|
||||
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$this->member = $query->getSingleResult();
|
||||
}
|
||||
else
|
||||
trigger_error("Container cannot determine member information");
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/logout", name="_logout")
|
||||
*/
|
||||
public function logoutAction()
|
||||
|
||||
private function getMember()
|
||||
{
|
||||
return $this->member;
|
||||
}
|
||||
|
||||
public function navbarAction()
|
||||
{
|
||||
// The security layer will intercept this request
|
||||
}
|
||||
@@ -56,20 +69,9 @@ class MemberController extends Controller
|
||||
public function indexAction()
|
||||
{
|
||||
$username = $this->getUser()->getUsername();
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
|
||||
return array('name' => $member->getFullName());
|
||||
return array('name' => $this->getMember()->getFullName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,22 +93,10 @@ class MemberController extends Controller
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$profile = $query->getSingleResult();
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
|
||||
|
||||
return (array('sFullName' => $profile->getFullName(), 'name' => $member->getFullName()));
|
||||
return (array('sFullName' => $profile->getFullName(), 'name' => $this->getMember()->getFullName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/profile/edit", name="_member_profile_edit")
|
||||
* @Template()
|
||||
@@ -114,23 +104,12 @@ class MemberController extends Controller
|
||||
public function editProfileAction()
|
||||
{
|
||||
$username = $this->getUser()->getUsername();
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
$form = $this->get('form.factory')->create(new Profile(), array('fullname' => $member->getFullName()));
|
||||
$form = $this->get('form.factory')->create(new Profile(), array('fullname' => $this->getMember()->getFullName()));
|
||||
$error = '';
|
||||
|
||||
return array('form' => $form->createView(), 'error' => '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/profile/save", name="_member_profile_save")
|
||||
*/
|
||||
@@ -138,17 +117,6 @@ class MemberController extends Controller
|
||||
{
|
||||
$username = $this->getUser()->getUsername();
|
||||
$db = $this->getDoctrine()->getManager();
|
||||
$query = $db->createQuery('
|
||||
SELECT m
|
||||
FROM BodyRep:Member m
|
||||
WHERE m.username = :username')
|
||||
->setParameter('username', $username)
|
||||
->setMaxResults(1);
|
||||
|
||||
if (sizeof($query->getResult()) != 1)
|
||||
throw $this->createNotFoundException("User '".$username."' not found");
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
$json = array('result' => 0);
|
||||
|
||||
$form = $this->get('form.factory')->create(new Profile());
|
||||
@@ -156,18 +124,30 @@ class MemberController extends Controller
|
||||
|
||||
|
||||
$form->bind($request);
|
||||
$np1 = $request->get('_newpass1');
|
||||
$np2 = $request->get('_newpass2');
|
||||
// if (!empty($np1) && !$np1 != $np2)
|
||||
// $form->get("fullname")->addError(new FormError('Passwords do not match'));
|
||||
|
||||
if ($form->isValid())
|
||||
if ($form->isValid() && sizeof($_POST) > 0)
|
||||
{
|
||||
$json['result'] = 1;
|
||||
if (!empty($np1))
|
||||
{
|
||||
$factory = $this->get('security.encoder_factory');
|
||||
$encoder = $factory->getEncoder($this->getUser());
|
||||
$password = $encoder->encodePassword($np1, $this->getUser()->getSalt());
|
||||
|
||||
$this->member->setPassword($password);
|
||||
}
|
||||
$d = $form->getClientData();
|
||||
$member->setFullName($d['fullname']);
|
||||
$db->persist($member);
|
||||
$this->getMember()->setFullName($d['fullname']);
|
||||
$db->persist($this->getMember());
|
||||
$db->flush();
|
||||
}
|
||||
|
||||
$resp = new Response (json_encode($json));
|
||||
$resp->headers->set('Content-Type', 'text/plain');
|
||||
$resp->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $resp;
|
||||
}
|
||||
@@ -179,7 +159,7 @@ class MemberController extends Controller
|
||||
{
|
||||
|
||||
/*
|
||||
* Integreted suggester response
|
||||
* Integrated suggester response
|
||||
*
|
||||
*/
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
@@ -208,7 +188,5 @@ class MemberController extends Controller
|
||||
}
|
||||
else*/
|
||||
return array('search' => $res);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/{username}", name="_profile")
|
||||
* @Route("/", name="_profile")
|
||||
* @Template()
|
||||
*/
|
||||
public function indexAction($username)
|
||||
{
|
||||
|
||||
if ($this->getUser()->getUsername() == $username)
|
||||
return new RedirectResponse($this->generateUrl('_member_profile'));
|
||||
|
||||
@@ -48,10 +49,17 @@ class ProfileController extends Controller
|
||||
|
||||
$member = $query->getSingleResult();
|
||||
|
||||
|
||||
return (array('sFullName' => $profile->getFullName(), 'name' => $member->getFullName()));
|
||||
|
||||
}
|
||||
/**
|
||||
* @Route("/rep", name="_profile_reputation")
|
||||
* @Template()
|
||||
*/
|
||||
public function reputationAction($username)
|
||||
{
|
||||
return $this->indexAction($username);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
namespace BodyRep\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
#use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
#use Symfony\Component\Config\FileLocator;
|
||||
|
||||
class BodyRepExtension extends Extension
|
||||
{
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.xml');
|
||||
#$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
|
||||
#$loader->load('/data/www/br/src/BodyRep/Resources/config/services.yml');
|
||||
}
|
||||
|
||||
public function getAlias()
|
||||
|
||||
115
src/BodyRep/Entity/Comment.php
Normal file
115
src/BodyRep/Entity/Comment.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Entity;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="comments")
|
||||
*/
|
||||
class Comment
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="author", type="string", length=255)
|
||||
*/
|
||||
protected $author;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="text", type="string", length=255)
|
||||
*/
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="created", type="timestamp")
|
||||
*/
|
||||
protected $created;
|
||||
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set author
|
||||
*
|
||||
* @param string $author
|
||||
* @return Comment
|
||||
*/
|
||||
public function setAuthor($author)
|
||||
{
|
||||
$this->author = $author;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get author
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthor()
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set text
|
||||
*
|
||||
* @param string $text
|
||||
* @return Comment
|
||||
*/
|
||||
public function setText($text)
|
||||
{
|
||||
$this->text = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set created
|
||||
*
|
||||
* @param timestamp $created
|
||||
* @return Comment
|
||||
*/
|
||||
public function setCreated(\timestamp $created)
|
||||
{
|
||||
$this->created = $created;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get created
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,20 @@ class Member implements UserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set password
|
||||
*
|
||||
* @param string $password
|
||||
* @return Member
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get fullName
|
||||
*
|
||||
|
||||
110
src/BodyRep/Entity/User.php
Normal file
110
src/BodyRep/Entity/User.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Entity;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="member")
|
||||
*/
|
||||
class User implements UserInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=25, unique=true)
|
||||
*/
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="password", type="string", length=255)
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="salt", type="string", length=255)
|
||||
*/
|
||||
protected $salt;
|
||||
|
||||
protected $roles = array();
|
||||
|
||||
public function getRoles()
|
||||
{
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
public function getSalt()
|
||||
{
|
||||
return $this->salt;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function eraseCredentials()
|
||||
{
|
||||
}
|
||||
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set username
|
||||
*
|
||||
* @param string $username
|
||||
* @return User
|
||||
*/
|
||||
public function setUsername($username)
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set password
|
||||
*
|
||||
* @param string $password
|
||||
* @return User
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set salt
|
||||
*
|
||||
* @param string $salt
|
||||
* @return User
|
||||
*/
|
||||
public function setSalt($salt)
|
||||
{
|
||||
$this->salt = $salt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
15
src/BodyRep/Entity/UserRepository.php
Normal file
15
src/BodyRep/Entity/UserRepository.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\Entity;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* UserRepository
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class UserRepository extends EntityRepository
|
||||
{
|
||||
}
|
||||
32
src/BodyRep/EventListener/CommentListener.php
Normal file
32
src/BodyRep/EventListener/CommentListener.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
// FooVendor/BarBundle/EventListener/CommentListener.php
|
||||
use FooVendorBarBundleEventCommentEvent;
|
||||
|
||||
class CommentListener
|
||||
{
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(Swift_Mailer $mailer)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
public function onCommentEvent(CommentEvent $event)
|
||||
{
|
||||
$post = $event->getPost();
|
||||
$comment = $event->getComment();
|
||||
|
||||
foreach ($post->getSubscribers() as $subscriber) {
|
||||
$message = Swift_Message::newInstance()
|
||||
->setSubject('New comment posted on ' . $post->getTitle())
|
||||
->setFrom('send@example.com')
|
||||
->setTo($subscriber->getEmail())
|
||||
->setBody("Hey, somebody left a new comment on a post you're subscribed to! It says: " . $comment->getBody())
|
||||
;
|
||||
$this->mailer->send($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -23,4 +23,24 @@ class ControllerListener
|
||||
$this->extension->setController($event->getController());
|
||||
}
|
||||
}
|
||||
public function preExecute(\Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event){
|
||||
//result returned by the controller
|
||||
$data = $event->getControllerResult();
|
||||
|
||||
//Get the current route
|
||||
$route = $event->getRequest()->get('_route');
|
||||
|
||||
/* @var $request \Symfony\Component\HttpFoundation\Request */
|
||||
$request = $event->getRequest();
|
||||
$template = $request->get('_template');
|
||||
$route = $request->get('_route');
|
||||
|
||||
if(substr($route,0,7) == 'mobile_'){
|
||||
$newTemplate = str_replace('html.twig','mobile.html.twig',$template);
|
||||
|
||||
//Overwrite original template with the mobile one
|
||||
$response = $this->templating->renderResponse($newTemplate, $data);
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/BodyRep/EventListener/KernelListener.php
Normal file
20
src/BodyRep/EventListener/KernelListener.php
Normal file
@@ -0,0 +1,20 @@
|
||||
public function preExecute(\Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event){
|
||||
//result returned by the controller
|
||||
$data = $event->getControllerResult();
|
||||
|
||||
//Get the current route
|
||||
$route = $event->getRequest()->get('_route');
|
||||
|
||||
/* @var $request \Symfony\Component\HttpFoundation\Request */
|
||||
$request = $event->getRequest();
|
||||
$template = $request->get('_template');
|
||||
$route = $request->get('_route');
|
||||
|
||||
if(substr($route,0,7) == 'mobile_'){
|
||||
$newTemplate = str_replace('html.twig','mobile.html.twig',$template);
|
||||
|
||||
//Overwrite original template with the mobile one
|
||||
$response = $this->templating->renderResponse($newTemplate, $data);
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
46
src/BodyRep/EventListener/LoginListener.php
Normal file
46
src/BodyRep/EventListener/LoginListener.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace BodyRep\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\Security\Core\SecurityContext;
|
||||
use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.1.x
|
||||
// use Symfony\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.0.x
|
||||
|
||||
/**
|
||||
* Custom login listener.
|
||||
*/
|
||||
class LoginListener
|
||||
{
|
||||
/** @var \Symfony\Component\Security\Core\SecurityContext */
|
||||
private $context;
|
||||
|
||||
/** @var \Doctrine\ORM\EntityManager */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param SecurityContext $context
|
||||
* @param Doctrine $doctrine
|
||||
*/
|
||||
public function __construct(SecurityContext $context, Doctrine $doctrine)
|
||||
{
|
||||
$this->context = $context;
|
||||
$this->em = $doctrine->getEntityManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the magic.
|
||||
*
|
||||
* @param Event $event
|
||||
*/
|
||||
public function onSecurityInteractiveLogin(Event $event)
|
||||
{
|
||||
$user = $this->context->getToken()->getUser();
|
||||
|
||||
// do all your magic here
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
34
src/BodyRep/Resources/views/Auth/login.html.twig
Normal file
34
src/BodyRep/Resources/views/Auth/login.html.twig
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends 'BodyRep::layout.html.twig' %}
|
||||
{% block js %}
|
||||
$(document).ready(function()
|
||||
{
|
||||
if($('#username').val().length > 0)
|
||||
$('#password').focus();
|
||||
else
|
||||
$('#username').focus();
|
||||
});
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<h1>Login</h1>
|
||||
|
||||
{% if error %}
|
||||
<div class="error">{{ error.message }}</div>
|
||||
{% endif %}
|
||||
|
||||
<form name='login' action="{{ path("_login_check") }}" method="post" id="login">
|
||||
<div>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="_username" value="{{ last_username }}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="_password" />
|
||||
</div>
|
||||
|
||||
<input type="submit" class="btn btn-primary btn-mini" id='loginbtn' value="LOGIN" />
|
||||
</form>
|
||||
{% endblock %}
|
||||
35
src/BodyRep/Resources/views/Auth/navbar.html.twig
Normal file
35
src/BodyRep/Resources/views/Auth/navbar.html.twig
Normal file
@@ -0,0 +1,35 @@
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<img src="/img/logo-nav.png" class='pull-left' style='padding-right : 5px; margin-top : 10px;' />
|
||||
<a class="brand" href="#">BODY<b>REP</b></a>
|
||||
<div class="btn-group pull-right">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#" style="background : transparent; color : white; text-shadow : none; border : none; box-shadow : 0 0 0 #fff;">
|
||||
<i class="icon-user icon-white"></i> {{name}}
|
||||
<span class="caret" style='border-top-color : white; border-bottom-color : white;'></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ path('_member_profile') }}">Profile</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ path('_logout') }}">Sign Out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class='offset2'>
|
||||
<form class="navbar-search pull-left" id='topsearch' action="{{ path('_member_search') }}">
|
||||
<input type="text" class="search-query span4" id="topsearch" style='height : 28px;' placeholder="Search"><span id='msg_topsearch'></span>
|
||||
</form>
|
||||
</div>
|
||||
<a class="btn dropdown-toggle pull-right" data-toggle="dropdown" href="#" style="margin : 0; background : transparent; color : white; text-shadow : none; border : none; box-shadow : 0 0 0 #fff;">
|
||||
<i class='licon-calendar licon-white'></i>
|
||||
</a>
|
||||
<a class="btn dropdown-toggle pull-right" data-toggle="dropdown" href="#" style="margin : 0; background : transparent; color : white; text-shadow : none; border : none; box-shadow : 0 0 0 #fff;">
|
||||
<i class='licon-mail-new licon-white'></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,6 +20,6 @@
|
||||
<div> </div>
|
||||
|
||||
{{ form_rest(form) }}
|
||||
<input type="submit" class="btn btn-primary btn-mini" value="Save" />
|
||||
<input type="submit" class="btn btn-primary btn-small" value="Save" />
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
{% block title "Hello " ~ name %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'BodyRep:Member:navbar.html.twig' %}
|
||||
|
||||
{% include 'BodyRep:Auth:navbar.html.twig' %}
|
||||
<div class='row-fluid'>
|
||||
<h1>Member landing page</h1>
|
||||
|
||||
{{name}}
|
||||
<h3>{{name}}</h3>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block content_header '' %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'BodyRep:Member:navbar.html.twig' %}
|
||||
{% include 'BodyRep:Auth:navbar.html.twig' %}
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span2">
|
||||
|
||||
12
src/BodyRep/Resources/views/Profile/comment.html.twig
Normal file
12
src/BodyRep/Resources/views/Profile/comment.html.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{% for comment in comments %}
|
||||
<div class="user-sub-comment">
|
||||
<div class='sub-avatar user1'></div>
|
||||
<a>{{ comment.author }}</a>
|
||||
<p>{{ comment.text }} </p>
|
||||
<div class="like-comment-time">
|
||||
{{ comment.thumbs }}
|
||||
<i class="icon-comment"></i>
|
||||
<span>{{ comment.dateHuman }} </span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -1,11 +1,18 @@
|
||||
{% extends 'BodyRep::layout.html.twig' %}
|
||||
|
||||
{% block title %}BodyRep{% endblock %}
|
||||
{% block documentReady %}
|
||||
$('#rep').live('click', function() {
|
||||
$.get('{{ path("_profile_reputation", { 'username': app.request.get('username') }) }}', {}, function (data) {
|
||||
$('#mcnt').html(data);
|
||||
});
|
||||
});
|
||||
{% endblock %}
|
||||
|
||||
{% block content_header '' %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'BodyRep:Member:navbar.html.twig' %}
|
||||
{% include 'BodyRep:Auth:navbar.html.twig' %}
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span2">
|
||||
@@ -13,7 +20,7 @@
|
||||
<ul class="nav nav-list">
|
||||
<li class="nav-header">Profile</li>
|
||||
<li class="active"><a href="#">Body Stats</a></li>
|
||||
<li><a href="#">Body Reputation</a></li>
|
||||
<li><a href="#" id='rep'>Body Reputation</a></li>
|
||||
<li><a href="#">Challenges</a></li>
|
||||
<li class="nav-header">Workouts</li>
|
||||
<li class="nav-header">Meals</li>
|
||||
|
||||
10
src/BodyRep/Resources/views/Profile/reputation.html.twig
Normal file
10
src/BodyRep/Resources/views/Profile/reputation.html.twig
Normal file
@@ -0,0 +1,10 @@
|
||||
{% block js %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_header '' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row-fluid">
|
||||
Reputation page
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -17,22 +17,35 @@
|
||||
padding: 9px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('css/bootstrap-responsive.css') }}" />
|
||||
<link rel="stylesheet" href="{{ asset('css/site.css') }}" />
|
||||
<link rel="stylesheet" href="{{ asset('css/chosen.css') }}" />
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/application.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/jquery.chosen.min.js') }}"></script>
|
||||
{% block javascripts %}
|
||||
<script type="text/javascript" src="{{ asset('js/LAB.js') }}"></script>
|
||||
|
||||
<script type="text/javascript" src="{{ asset('js/bootstrap.js') }}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var loadb;
|
||||
$LAB.script('https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
|
||||
.script('//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js')
|
||||
.script("{{ asset('js/application.js') }}")
|
||||
.script("{{ asset('js/jquery.chosen.min.js') }}")
|
||||
.script("{{ asset('js/bootstrap.js') }}").wait(function() {
|
||||
|
||||
{% block documentReady %}
|
||||
|
||||
{% endblock %}
|
||||
clearTimeout(loadb);
|
||||
$('#loadmast').hide();
|
||||
$('#mast').removeClass('hidden');
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id='mast' class='hidden'>
|
||||
<div class="container-fluid symfony-content">
|
||||
|
||||
{% block content %}
|
||||
@@ -46,8 +59,9 @@
|
||||
<p>© BodyRep 2012</p>
|
||||
</footer>
|
||||
|
||||
</div><!--/.fluid-container-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id='loadmast'><img align="absmiddle" style="margin-left: 10px; margin-bottom: 3px;" src="/img/progress.gif"> Loading</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
47
src/BodyRep/Tests/Controller/AuthControllerTest.php
Normal file
47
src/BodyRep/Tests/Controller/AuthControllerTest.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Bodyrep\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
class AuthControllerTest extends WebTestCase
|
||||
{
|
||||
public function testIndex()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->followRedirects(true);
|
||||
$crawler = $client->request('GET', '/u/login');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Username")')->count() > 0);
|
||||
}
|
||||
|
||||
public function testLogin()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->followRedirects(true);
|
||||
$crawler = $client->request('GET', '/u/login');
|
||||
|
||||
|
||||
$form = $crawler->selectButton('loginbtn')->form();
|
||||
$crawler = $client->submit($form, array(
|
||||
'_username' => 'alexl',
|
||||
'_password' => 'd559ko54'
|
||||
));
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Member")')->count() > 0);
|
||||
}
|
||||
|
||||
public function testLogout()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->followRedirects(true);
|
||||
|
||||
$crawler = $client->request('GET', '/u/logout');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Landing")')->count() > 0);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
19
src/BodyRep/Tests/Controller/LandingControllerTest.php
Normal file
19
src/BodyRep/Tests/Controller/LandingControllerTest.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Bodyrep\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class LandingControllerTest extends WebTestCase
|
||||
{
|
||||
public function testIndex()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Landing Page")')->count() > 0);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
45
src/BodyRep/Tests/Controller/MemberControllerTest.php
Normal file
45
src/BodyRep/Tests/Controller/MemberControllerTest.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Bodyrep\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MemberControllerTest extends WebTestCase
|
||||
{
|
||||
private $authcrawler;
|
||||
private $authclient;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->authclient = static::createClient();
|
||||
$this->authclient->followRedirects(true);
|
||||
$this->authcrawler = $this->authclient->request('GET', '/u/login');
|
||||
|
||||
|
||||
$form = $this->authcrawler->selectButton('loginbtn')->form();
|
||||
$this->authcrawler = $this->authclient->submit($form, array(
|
||||
'_username' => 'alexl',
|
||||
'_password' => 'd559ko54'
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
public function testIndex()
|
||||
{
|
||||
$this->assertTrue($this->authcrawler->filter('html:contains("Member landing")')->count() > 0);
|
||||
|
||||
}
|
||||
|
||||
public function testEditProfile()
|
||||
{
|
||||
|
||||
|
||||
$this->authcrawler = $this->authclient->request('GET', '/m/profile');
|
||||
|
||||
$this->assertTrue($this->authcrawler->filter('html:contains("Edit Profile")')->count() > 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
51
src/BodyRep/Tests/Controller/ProfileControllerTest.php
Normal file
51
src/BodyRep/Tests/Controller/ProfileControllerTest.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Bodyrep\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ProfileControllerTest extends WebTestCase
|
||||
{
|
||||
public function testProfile()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->followRedirects(true);
|
||||
$crawler = $client->request('GET', '/u/login');
|
||||
|
||||
|
||||
$form = $crawler->selectButton('loginbtn')->form();
|
||||
$crawler = $client->submit($form, array(
|
||||
'_username' => 'alexl',
|
||||
'_password' => 'd559ko54'
|
||||
));
|
||||
|
||||
|
||||
$crawler = $client->request('GET', '/alexl');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Alex")')->count() > 0);
|
||||
|
||||
}
|
||||
|
||||
public function testEditProfile()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->followRedirects(true);
|
||||
$crawler = $client->request('GET', '/u/login');
|
||||
|
||||
|
||||
$form = $crawler->selectButton('loginbtn')->form();
|
||||
$crawler = $client->submit($form, array(
|
||||
'_username' => 'alexl',
|
||||
'_password' => 'd559ko54'
|
||||
));
|
||||
|
||||
|
||||
$crawler = $client->request('GET', '/alexl');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Alex")')->count() > 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
5
web/js/LAB-debug.min.js
vendored
Executable file
5
web/js/LAB-debug.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
5
web/js/LAB.js
Executable file
5
web/js/LAB.js
Executable file
File diff suppressed because one or more lines are too long
5
web/js/LAB.min.js
vendored
Executable file
5
web/js/LAB.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
514
web/js/LAB.src.js
Executable file
514
web/js/LAB.src.js
Executable file
@@ -0,0 +1,514 @@
|
||||
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
|
||||
v2.0.3 (c) Kyle Simpson
|
||||
MIT License
|
||||
*/
|
||||
|
||||
(function(global){
|
||||
var _$LAB = global.$LAB,
|
||||
|
||||
// constants for the valid keys of the options object
|
||||
_UseLocalXHR = "UseLocalXHR",
|
||||
_AlwaysPreserveOrder = "AlwaysPreserveOrder",
|
||||
_AllowDuplicates = "AllowDuplicates",
|
||||
_CacheBust = "CacheBust",
|
||||
/*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
|
||||
_BasePath = "BasePath",
|
||||
|
||||
// stateless variables used across all $LAB instances
|
||||
root_page = /^[^?#]*\//.exec(location.href)[0],
|
||||
root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
|
||||
append_to = document.head || document.getElementsByTagName("head"),
|
||||
|
||||
// inferences... ick, but still necessary
|
||||
opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
|
||||
|
||||
/*!START_DEBUG*/
|
||||
// console.log() and console.error() wrappers
|
||||
log_msg = function(){},
|
||||
log_error = log_msg,
|
||||
/*!END_DEBUG*/
|
||||
|
||||
// feature sniffs (yay!)
|
||||
test_script_elem = document.createElement("script"),
|
||||
explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
|
||||
real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
|
||||
script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
|
||||
|
||||
// XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
|
||||
xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
|
||||
;
|
||||
|
||||
/*!START_DEBUG*/
|
||||
// define console wrapper functions if applicable
|
||||
if (global.console && global.console.log) {
|
||||
if (!global.console.error) global.console.error = global.console.log;
|
||||
log_msg = function(msg) { global.console.log(msg); };
|
||||
log_error = function(msg,err) { global.console.error(msg,err); };
|
||||
}
|
||||
/*!END_DEBUG*/
|
||||
|
||||
// test for function
|
||||
function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
|
||||
|
||||
// test for array
|
||||
function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
|
||||
|
||||
// make script URL absolute/canonical
|
||||
function canonical_uri(src,base_path) {
|
||||
var absolute_regex = /^\w+\:\/\//;
|
||||
|
||||
// is `src` is protocol-relative (begins with // or ///), prepend protocol
|
||||
if (/^\/\/\/?/.test(src)) {
|
||||
src = location.protocol + src;
|
||||
}
|
||||
// is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
|
||||
else if (!absolute_regex.test(src) && src.charAt(0) != "/") {
|
||||
// prepend `base_path`, if any
|
||||
src = (base_path || "") + src;
|
||||
}
|
||||
// make sure to return `src` as absolute
|
||||
return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src);
|
||||
}
|
||||
|
||||
// merge `source` into `target`
|
||||
function merge_objs(source,target) {
|
||||
for (var k in source) { if (source.hasOwnProperty(k)) {
|
||||
target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
|
||||
}}
|
||||
return target;
|
||||
}
|
||||
|
||||
// does the chain group have any ready-to-execute scripts?
|
||||
function check_chain_group_scripts_ready(chain_group) {
|
||||
var any_scripts_ready = false;
|
||||
for (var i=0; i<chain_group.scripts.length; i++) {
|
||||
if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
|
||||
any_scripts_ready = true;
|
||||
chain_group.scripts[i].exec_trigger();
|
||||
chain_group.scripts[i].exec_trigger = null;
|
||||
}
|
||||
}
|
||||
return any_scripts_ready;
|
||||
}
|
||||
|
||||
// creates a script load listener
|
||||
function create_script_load_listener(elem,registry_item,flag,onload) {
|
||||
elem.onload = elem.onreadystatechange = function() {
|
||||
if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
|
||||
elem.onload = elem.onreadystatechange = null;
|
||||
onload();
|
||||
};
|
||||
}
|
||||
|
||||
// script executed handler
|
||||
function script_executed(registry_item) {
|
||||
registry_item.ready = registry_item.finished = true;
|
||||
for (var i=0; i<registry_item.finished_listeners.length; i++) {
|
||||
registry_item.finished_listeners[i]();
|
||||
}
|
||||
registry_item.ready_listeners = [];
|
||||
registry_item.finished_listeners = [];
|
||||
}
|
||||
|
||||
// make the request for a scriptha
|
||||
function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
|
||||
// setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
|
||||
setTimeout(function(){
|
||||
var script, src = script_obj.real_src, xhr;
|
||||
|
||||
// don't proceed until `append_to` is ready to append to
|
||||
if ("item" in append_to) { // check if `append_to` ref is still a live node list
|
||||
if (!append_to[0]) { // `append_to` node not yet ready
|
||||
// try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
|
||||
setTimeout(arguments.callee,25);
|
||||
return;
|
||||
}
|
||||
// reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
|
||||
append_to = append_to[0];
|
||||
}
|
||||
script = document.createElement("script");
|
||||
if (script_obj.type) script.type = script_obj.type;
|
||||
if (script_obj.charset) script.charset = script_obj.charset;
|
||||
|
||||
// should preloading be used for this script?
|
||||
if (preload_this_script) {
|
||||
// real script preloading?
|
||||
if (real_preloading) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
|
||||
registry_item.elem = script;
|
||||
if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
|
||||
script.preload = true;
|
||||
script.onpreload = onload;
|
||||
}
|
||||
else {
|
||||
script.onreadystatechange = function(){
|
||||
if (script.readyState == "loaded") onload();
|
||||
};
|
||||
}
|
||||
script.src = src;
|
||||
// NOTE: no append to DOM yet, appending will happen when ready to execute
|
||||
}
|
||||
// same-domain and XHR allowed? use XHR preloading
|
||||
else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
|
||||
xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
xhr.onreadystatechange = function(){}; // fix a memory leak in IE
|
||||
registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
|
||||
onload();
|
||||
}
|
||||
};
|
||||
xhr.open("GET",src);
|
||||
xhr.send();
|
||||
}
|
||||
// as a last resort, use cache-preloading
|
||||
else {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
|
||||
script.type = "text/cache-script";
|
||||
create_script_load_listener(script,registry_item,"ready",function() {
|
||||
append_to.removeChild(script);
|
||||
onload();
|
||||
});
|
||||
script.src = src;
|
||||
append_to.insertBefore(script,append_to.firstChild);
|
||||
}
|
||||
}
|
||||
// use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
|
||||
else if (script_ordered_async) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
|
||||
script.async = false;
|
||||
create_script_load_listener(script,registry_item,"finished",onload);
|
||||
script.src = src;
|
||||
append_to.insertBefore(script,append_to.firstChild);
|
||||
}
|
||||
// otherwise, just a normal script element
|
||||
else {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
|
||||
create_script_load_listener(script,registry_item,"finished",onload);
|
||||
script.src = src;
|
||||
append_to.insertBefore(script,append_to.firstChild);
|
||||
}
|
||||
},0);
|
||||
}
|
||||
|
||||
// create a clean instance of $LAB
|
||||
function create_sandbox() {
|
||||
var global_defaults = {},
|
||||
can_use_preloading = real_preloading || xhr_or_cache_preloading,
|
||||
queue = [],
|
||||
registry = {},
|
||||
instanceAPI
|
||||
;
|
||||
|
||||
// global defaults
|
||||
global_defaults[_UseLocalXHR] = true;
|
||||
global_defaults[_AlwaysPreserveOrder] = false;
|
||||
global_defaults[_AllowDuplicates] = false;
|
||||
global_defaults[_CacheBust] = false;
|
||||
/*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
|
||||
global_defaults[_BasePath] = "";
|
||||
|
||||
// execute a script that has been preloaded already
|
||||
function execute_preloaded_script(chain_opts,script_obj,registry_item) {
|
||||
var script;
|
||||
|
||||
function preload_execute_finished() {
|
||||
if (script != null) { // make sure this only ever fires once
|
||||
script = null;
|
||||
script_executed(registry_item);
|
||||
}
|
||||
}
|
||||
|
||||
if (registry[script_obj.src].finished) return;
|
||||
if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
|
||||
|
||||
script = registry_item.elem || document.createElement("script");
|
||||
if (script_obj.type) script.type = script_obj.type;
|
||||
if (script_obj.charset) script.charset = script_obj.charset;
|
||||
create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
|
||||
|
||||
// script elem was real-preloaded
|
||||
if (registry_item.elem) {
|
||||
registry_item.elem = null;
|
||||
}
|
||||
// script was XHR preloaded
|
||||
else if (registry_item.text) {
|
||||
script.onload = script.onreadystatechange = null; // script injection doesn't fire these events
|
||||
script.text = registry_item.text;
|
||||
}
|
||||
// script was cache-preloaded
|
||||
else {
|
||||
script.src = script_obj.real_src;
|
||||
}
|
||||
append_to.insertBefore(script,append_to.firstChild);
|
||||
|
||||
// manually fire execution callback for injected scripts, since events don't fire
|
||||
if (registry_item.text) {
|
||||
preload_execute_finished();
|
||||
}
|
||||
}
|
||||
|
||||
// process the script request setup
|
||||
function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
|
||||
var registry_item,
|
||||
registry_items,
|
||||
ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
|
||||
finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
|
||||
;
|
||||
|
||||
script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
|
||||
script_obj.real_src = script_obj.src +
|
||||
// append cache-bust param to URL?
|
||||
(chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
|
||||
;
|
||||
|
||||
if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
|
||||
registry_items = registry[script_obj.src].items;
|
||||
|
||||
// allowing duplicates, or is this the first recorded load of this script?
|
||||
if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
|
||||
registry_item = registry_items[registry_items.length] = {
|
||||
ready:false,
|
||||
finished:false,
|
||||
ready_listeners:[ready_cb],
|
||||
finished_listeners:[finished_cb]
|
||||
};
|
||||
|
||||
request_script(chain_opts,script_obj,registry_item,
|
||||
// which callback type to pass?
|
||||
(
|
||||
(preload_this_script) ? // depends on script-preloading
|
||||
function(){
|
||||
registry_item.ready = true;
|
||||
for (var i=0; i<registry_item.ready_listeners.length; i++) {
|
||||
registry_item.ready_listeners[i]();
|
||||
}
|
||||
registry_item.ready_listeners = [];
|
||||
} :
|
||||
function(){ script_executed(registry_item); }
|
||||
),
|
||||
// signal if script-preloading should be used or not
|
||||
preload_this_script
|
||||
);
|
||||
}
|
||||
else {
|
||||
registry_item = registry_items[0];
|
||||
if (registry_item.finished) {
|
||||
finished_cb();
|
||||
}
|
||||
else {
|
||||
registry_item.finished_listeners.push(finished_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
|
||||
function create_chain() {
|
||||
var chainedAPI,
|
||||
chain_opts = merge_objs(global_defaults,{}),
|
||||
chain = [],
|
||||
exec_cursor = 0,
|
||||
scripts_currently_loading = false,
|
||||
group
|
||||
;
|
||||
|
||||
// called when a script has finished preloading
|
||||
function chain_script_ready(script_obj,exec_trigger) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
|
||||
script_obj.ready = true;
|
||||
script_obj.exec_trigger = exec_trigger;
|
||||
advance_exec_cursor(); // will only check for 'ready' scripts to be executed
|
||||
}
|
||||
|
||||
// called when a script has finished executing
|
||||
function chain_script_executed(script_obj,chain_group) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
|
||||
script_obj.ready = script_obj.finished = true;
|
||||
script_obj.exec_trigger = null;
|
||||
// check if chain group is all finished
|
||||
for (var i=0; i<chain_group.scripts.length; i++) {
|
||||
if (!chain_group.scripts[i].finished) return;
|
||||
}
|
||||
// chain_group is all finished if we get this far
|
||||
chain_group.finished = true;
|
||||
advance_exec_cursor();
|
||||
}
|
||||
|
||||
// main driver for executing each part of the chain
|
||||
function advance_exec_cursor() {
|
||||
while (exec_cursor < chain.length) {
|
||||
if (is_func(chain[exec_cursor])) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
|
||||
try { chain[exec_cursor++](); } catch (err) {
|
||||
/*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (!chain[exec_cursor].finished) {
|
||||
if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
|
||||
break;
|
||||
}
|
||||
exec_cursor++;
|
||||
}
|
||||
// we've reached the end of the chain (so far)
|
||||
if (exec_cursor == chain.length) {
|
||||
scripts_currently_loading = false;
|
||||
group = false;
|
||||
}
|
||||
}
|
||||
|
||||
// setup next chain script group
|
||||
function init_script_chain_group() {
|
||||
if (!group || !group.scripts) {
|
||||
chain.push(group = {scripts:[],finished:true});
|
||||
}
|
||||
}
|
||||
|
||||
// API for $LAB chains
|
||||
chainedAPI = {
|
||||
// start loading one or more scripts
|
||||
script:function(){
|
||||
for (var i=0; i<arguments.length; i++) {
|
||||
(function(script_obj,script_list){
|
||||
var splice_args;
|
||||
|
||||
if (!is_array(script_obj)) {
|
||||
script_list = [script_obj];
|
||||
}
|
||||
for (var j=0; j<script_list.length; j++) {
|
||||
init_script_chain_group();
|
||||
script_obj = script_list[j];
|
||||
|
||||
if (is_func(script_obj)) script_obj = script_obj();
|
||||
if (!script_obj) continue;
|
||||
if (is_array(script_obj)) {
|
||||
// set up an array of arguments to pass to splice()
|
||||
splice_args = [].slice.call(script_obj); // first include the actual array elements we want to splice in
|
||||
splice_args.unshift(j,1); // next, put the `index` and `howMany` parameters onto the beginning of the splice-arguments array
|
||||
[].splice.apply(script_list,splice_args); // use the splice-arguments array as arguments for splice()
|
||||
j--; // adjust `j` to account for the loop's subsequent `j++`, so that the next loop iteration uses the same `j` index value
|
||||
continue;
|
||||
}
|
||||
if (typeof script_obj == "string") script_obj = {src:script_obj};
|
||||
script_obj = merge_objs(script_obj,{
|
||||
ready:false,
|
||||
ready_cb:chain_script_ready,
|
||||
finished:false,
|
||||
finished_cb:chain_script_executed
|
||||
});
|
||||
group.finished = false;
|
||||
group.scripts.push(script_obj);
|
||||
|
||||
do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
|
||||
scripts_currently_loading = true;
|
||||
|
||||
if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
|
||||
}
|
||||
})(arguments[i],arguments[i]);
|
||||
}
|
||||
return chainedAPI;
|
||||
},
|
||||
// force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
|
||||
wait:function(){
|
||||
if (arguments.length > 0) {
|
||||
for (var i=0; i<arguments.length; i++) {
|
||||
chain.push(arguments[i]);
|
||||
}
|
||||
group = chain[chain.length-1];
|
||||
}
|
||||
else group = false;
|
||||
|
||||
advance_exec_cursor();
|
||||
|
||||
return chainedAPI;
|
||||
}
|
||||
};
|
||||
|
||||
// the first chain link API (includes `setOptions` only this first time)
|
||||
return {
|
||||
script:chainedAPI.script,
|
||||
wait:chainedAPI.wait,
|
||||
setOptions:function(opts){
|
||||
merge_objs(opts,chain_opts);
|
||||
return chainedAPI;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// API for each initial $LAB instance (before chaining starts)
|
||||
instanceAPI = {
|
||||
// main API functions
|
||||
setGlobalDefaults:function(opts){
|
||||
merge_objs(opts,global_defaults);
|
||||
return instanceAPI;
|
||||
},
|
||||
setOptions:function(){
|
||||
return create_chain().setOptions.apply(null,arguments);
|
||||
},
|
||||
script:function(){
|
||||
return create_chain().script.apply(null,arguments);
|
||||
},
|
||||
wait:function(){
|
||||
return create_chain().wait.apply(null,arguments);
|
||||
},
|
||||
|
||||
// built-in queuing for $LAB `script()` and `wait()` calls
|
||||
// useful for building up a chain programmatically across various script locations, and simulating
|
||||
// execution of the chain
|
||||
queueScript:function(){
|
||||
queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
|
||||
return instanceAPI;
|
||||
},
|
||||
queueWait:function(){
|
||||
queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
|
||||
return instanceAPI;
|
||||
},
|
||||
runQueue:function(){
|
||||
var $L = instanceAPI, len=queue.length, i=len, val;
|
||||
for (;--i>=0;) {
|
||||
val = queue.shift();
|
||||
$L = $L[val.type].apply(null,val.args);
|
||||
}
|
||||
return $L;
|
||||
},
|
||||
|
||||
// rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
|
||||
noConflict:function(){
|
||||
global.$LAB = _$LAB;
|
||||
return instanceAPI;
|
||||
},
|
||||
|
||||
// create another clean instance of $LAB
|
||||
sandbox:function(){
|
||||
return create_sandbox();
|
||||
}
|
||||
};
|
||||
|
||||
return instanceAPI;
|
||||
}
|
||||
|
||||
// create the main instance of $LAB
|
||||
global.$LAB = create_sandbox();
|
||||
|
||||
|
||||
/* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
|
||||
NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
|
||||
|
||||
The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does
|
||||
proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked
|
||||
document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready.
|
||||
For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or
|
||||
fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
|
||||
*/
|
||||
(function(addEvent,domLoaded,handler){
|
||||
if (document.readyState == null && document[addEvent]){
|
||||
document.readyState = "loading";
|
||||
document[addEvent](domLoaded,handler = function(){
|
||||
document.removeEventListener(domLoaded,handler,false);
|
||||
document.readyState = "complete";
|
||||
},false);
|
||||
}
|
||||
})("addEventListener","DOMContentLoaded");
|
||||
|
||||
})(this);
|
||||
@@ -16,10 +16,10 @@ $(function() {
|
||||
});
|
||||
$('form#profile').live('submit', function(){
|
||||
frm = $(this);
|
||||
$.post(frm.attr('action'), frm.serialize(), function(data) {
|
||||
response = $.parseJSON(data);
|
||||
$.post(frm.attr('action'), frm.serialize(), function(response) {
|
||||
|
||||
if(response.result)
|
||||
$('#mcnt').append('Updated');
|
||||
$('#mcnt').append('<b>Updated</b>');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user