diff --git a/Controller/Sequence/SequenceController.php b/Controller/Sequence/SequenceController.php new file mode 100644 index 000000000..b5d3e40be --- /dev/null +++ b/Controller/Sequence/SequenceController.php @@ -0,0 +1,109 @@ +container->get('security.context')->isGranted('OPEN', $resource->getResourceNode())) { + throw new AccessDeniedException(); + } + + return $this->render('UJMExoBundle:Sequence:view.html.twig', array( + '_resource' => $resource + ) + ); + } + + /** + * administrate an exercise player + * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="ujm_sequence_administrate") + * @Method("GET") + * @ParamConverter("Sequence", class="UJMExoBundle:Sequence\Sequence") + */ + public function administrateAction(Sequence $resource) { + if (false === $this->container->get('security.context')->isGranted('ADMINISTRATE', $resource->getResourceNode())) { + throw new AccessDeniedException(); + } + + $steps = $this->get('ujm_exo_bundle.manager.steps')->getSteps($resource); + + return $this->render('UJMExoBundle:Sequence:edit.html.twig', array( + '_resource' => $resource, + 'steps' => $steps + ) + ); + } + + /** + * update an exercise player + * @Route("/update/{id}", requirements={"id" = "\d+"}, name="ujm_sequence_update", options = {"expose" = true}) + * @Method("PUT") + * @ParamConverter("Sequence", class="UJMExoBundle:Sequence\Sequence") + * + */ + public function updateAction(Sequence $resource) { + + if (false === $this->container->get('security.context')->isGranted('EDIT', $resource->getResourceNode())) { + throw new AccessDeniedException(); + } + + $params = array( + 'method' => 'PUT', + 'csrf_protection' => false, + ); + // Create form + $form = $this->container->get('form.factory')->create('sequence_type', $resource, $params); + $request = $this->container->get('request'); + $form->submit($request); + $response = array(); + if ($form->isValid()) { + $resource = $form->getData(); + $updated = $this->get('ujm_exo_bundle.manager.sequence')->update($resource); + $response['status'] = 'success'; + $response['messages'] = array(); + $response['data'] = $updated; + } else { + $errors = $this->getFormErrors($form); + $response['status'] = 'error'; + $response['messages'] = $errors; + $response['data'] = null; + } + return new JsonResponse($response); + } + + private function getFormErrors(FormInterface $form) { + $errors = array(); + foreach ($form->getErrors() as $key => $error) { + $errors[$key] = $error->getMessage(); + } + // Get errors from children + foreach ($form->all() as $child) { + if (!$child->isValid()) { + $errors[$child->getName()] = $this->getFormErrors($child); + } + } + return $errors; + } + +} diff --git a/Controller/Sequence/StepController.php b/Controller/Sequence/StepController.php new file mode 100644 index 000000000..004a1d79e --- /dev/null +++ b/Controller/Sequence/StepController.php @@ -0,0 +1,54 @@ +container->get('security.context')->isGranted('EDIT', $resource->getResourceNode())) { + throw new AccessDeniedException(); + } + $request = $this->container->get('request'); + // get request data + $steps = $request->request->get('steps'); + + // response + $response = array(); + + // update the exercise player pages + try { + $updated = $this->get('ujm_exo_bundle.manager.steps')->updateSteps($resource, $steps); + $response['status'] = 'success'; + $response['messages'] = array(); + $response['data'] = $updated; + } catch (\Exception $ex) { + $response['status'] = 'error'; + $response['messages'] = $ex->getMessage(); + $response['data'] = null; + } + return new JsonResponse($response); + } + + + +} diff --git a/DependencyInjection/UJMExoExtension.php b/DependencyInjection/UJMExoExtension.php index 77fcc4465..48e64ffbe 100755 --- a/DependencyInjection/UJMExoExtension.php +++ b/DependencyInjection/UJMExoExtension.php @@ -15,5 +15,6 @@ public function load(array $configs, ContainerBuilder $container) $loader = new YamlFileLoader($container, $locator); $loader->load('services.yml'); $loader->load('parameters.yml'); + $loader->load('form_types.yml'); } } diff --git a/Entity/Sequence/Sequence.php b/Entity/Sequence/Sequence.php new file mode 100644 index 000000000..ab2e9f68b --- /dev/null +++ b/Entity/Sequence/Sequence.php @@ -0,0 +1,195 @@ +startDate = new \DateTime(); + $this->steps = new ArrayCollection(); + } + + /** + * Get sequence Id + * @return integer + */ + public function getId() { + return $this->id; + } + + /** + * + * @param Step $s + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function addStep(Step $s) { + $this->steps[] = $s; + return $this; + } + + /** + * + * @param Step $s + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function removePage(Step $s) { + $this->steps->removeElement($s); + return $this; + } + + /** + * + * @return ArrayCollection + */ + public function getSteps() { + return $this->steps; + } + + /** + * Set sequence name + * @param string $name + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function setName($name) { + $this->name = $name; + return $this; + } + + /** + * Get sequence name + * @return string + */ + public function getName() { + return $this->name; + } + + /** + * Set sequence startDate + * + * @param datetime $startDate + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function setStartDate($startDate) { + $this->startDate = $startDate; + return $this; + } + + /** + * Get sequence startDate + * + * @return datetime + */ + public function getStartDate() { + return $this->startDate; + } + + /** + * Set sequence endDate + * + * @param datetime $endDate + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function setEndDate($endDate) { + $this->endDate = $endDate; + return $this; + } + + /** + * Get sequence endDate + * + * @return datetime + */ + public function getEndDate() { + return $this->endDate; + } + + + /** + * Set sequence description + * + * @param text $description + * @return \UJM\ExoBundle\Entity\Sequence\Sequence + */ + public function setDescription($description) { + $this->description = $description; + return $this; + } + + /** + * Get sequence description + * + * @return text + */ + public function getDescription() { + return $this->description; + } + + public function jsonSerialize() { + + return array( + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'startDate' => !empty($this->startDate) ? $this->startDate->format('Y-m-d'): null, + 'endDate' => !empty($this->endDate) ? $this->endDate->format('Y-m-d'): null + ); + } + +} diff --git a/Entity/Sequence/Step.php b/Entity/Sequence/Step.php new file mode 100644 index 000000000..95eaad128 --- /dev/null +++ b/Entity/Sequence/Step.php @@ -0,0 +1,209 @@ +shuffle = false; + $this->isFirst = false; + $this->isLast = false; + } + + /** + * Get page Id + * @return integer + */ + public function getId() { + return $this->id; + } + + public function getDescription(){ + return $this->description; + } + + /** + * + * @param string $description + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setDescription($description){ + $this->description = $description; + return $this; + } + + /** + * + * @param Sequence $sequence + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setSequence(Sequence $sequence){ + $this->sequence = $sequence; + return $this; + } + + /** + * + * @return sequence + */ + public function getSequence(){ + return $this->sequence; + } + + /** + * + * @param integer $position + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setPosition($position) { + $this->position = $position; + return $this; + } + + /** + * + * @return integer + */ + public function getPosition(){ + return $this->position; + } + + /** + * + * @param boolean $shuffle + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setShuffle($shuffle){ + $this->shuffle = $shuffle; + return $this; + } + + /** + * + * @return boolean + */ + public function getShuffle(){ + return $this->shuffle; + } + + /** + * + * @param boolean $isLast + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setIsLast($isLast){ + $this->isLast = $isLast; + return $this; + } + + /** + * + * @return boolean + */ + public function getIsLast(){ + return $this->isLast; + } + + /** + * + * @param boolean $isFirst + * @return \UJM\ExoBundle\Entity\Sequence\Step + */ + public function setIsFirst($isFirst){ + $this->isFirst = $isFirst; + return $this; + } + + /** + * + * @return boolean + */ + public function getIsFirst(){ + return $this->isFirst; + } + + public function jsonSerialize() + { + // TODO serialize questions arraycollection + return array ( + 'id' => $this->id, + 'position' => $this->position, + 'shuffle' => $this->shuffle, + 'isFirst' => $this->isFirst, + 'isLast' => $this->isLast, + 'description' => $this->description, + 'sequenceId' => $this->sequence->getId() + ); + } + +} diff --git a/Form/Sequence/SequenceType.php b/Form/Sequence/SequenceType.php new file mode 100644 index 000000000..8d79b51da --- /dev/null +++ b/Form/Sequence/SequenceType.php @@ -0,0 +1,55 @@ +add( + 'name', 'text' + ) + ->add('description', 'tinymce', array( + 'attr' => array('data-new-tab' => 'yes'), + 'label' => 'Description', 'required' => false + ) + ) + ->add('startDate', 'datetime', array( + 'data' => new \DateTime(), + 'attr'=>array('style'=>'display:none;'), + 'widget' => 'single_text', + 'label' => ' ', + 'input' => 'datetime' + ) + ) + ->add('endDate', 'datetime', array( + 'data' => null, + 'attr'=>array('style'=>'display:none;'), + 'label' => ' ', + 'widget' => 'single_text', + 'required' => false , + 'input' => 'datetime' + ) + ); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + array( + 'data_class' => 'UJM\ExoBundle\Entity\Sequence\Sequence', + 'translation_domain' => 'ujm_sequence', + ) + ); + } + + public function getName() + { + return 'sequence_type'; + } +} diff --git a/Listener/Resource/SequenceListener.php b/Listener/Resource/SequenceListener.php new file mode 100644 index 000000000..d7f37f61b --- /dev/null +++ b/Listener/Resource/SequenceListener.php @@ -0,0 +1,123 @@ +getResource(); + $route = $this->container + ->get('router') + ->generate('ujm_sequence_administrate', array('id' => $resource->getId()) + ); + $event->setResponse(new RedirectResponse($route)); + $event->stopPropagation(); + } + + /** + * Fired when a new ResourceNode of type Sequence is opened + * @param \Claroline\CoreBundle\Event\OpenResourceEvent $event + * @throws \Exception + */ + public function onOpen(OpenResourceEvent $event) { + $resource = $event->getResource(); + //Redirection to the controller. + $route = $this->container + ->get('router') + ->generate('ujm_sequence_open', array('id' => $resource->getId())); + $event->setResponse(new RedirectResponse($route)); + $event->stopPropagation(); + } + + /** + * + * @param CreateResourceEvent $event + * @throws \Exception + */ + public function onCreate(CreateResourceEvent $event) { + // Create form + $form = $this->container->get('form.factory')->create('sequence_type', new Sequence()); + // Try to process form + $request = $this->container->get('request'); + $form->submit($request); + if ($form->isValid()) { + $resource = $form->getData(); + + $sequence = $this->container->get('ujm_exo_bundle.manager.sequence')->createFirstAndLastStep($resource); + + $event->setResources(array($sequence)); + + + } else { + $content = $this->container->get('templating')->render( + 'ClarolineCoreBundle:Resource:createForm.html.twig', array( + 'form' => $form->createView(), + 'resourceType' => 'ujm_sequence' + )); + $event->setErrorFormContent($content); + } + $event->stopPropagation(); + return; + } + + /** + * + * @param CreateFormResourceEvent $event + */ + public function onCreateForm(CreateFormResourceEvent $event) { + // Create form + $form = $this->container->get('form.factory')->create('sequence_type', new Sequence()); + + $content = $this->container->get('templating')->render( + 'ClarolineCoreBundle:Resource:createForm.html.twig', array( + 'form' => $form->createView(), + 'resourceType' => 'ujm_sequence' + )); + + $event->setResponseContent($content); + $event->stopPropagation(); + } + + /** + * Fired when a ResourceNode of type Sequence is deleted + * @param \Claroline\CoreBundle\Event\DeleteResourceEvent $event + * @throws \Exception + */ + public function onDelete(DeleteResourceEvent $event) { + $em = $this->container->get('doctrine.orm.entity_manager'); + $resource = $event->getResource(); + $em->remove($resource); + $event->stopPropagation(); + } + + /** + * Fired when a ResourceNode of type Sequence is duplicated + * @param \Claroline\CoreBundle\Event\CopyResourceEvent $event + * @throws \Exception + */ + public function onCopy(CopyResourceEvent $event) { + $toCopy = $event->getResource(); + $new = new Sequence(); + $new->setName($toCopy->getName()); + $event->setCopy($new); + $event->stopPropagation(); + } + +} diff --git a/Manager/Sequence/SequenceManager.php b/Manager/Sequence/SequenceManager.php new file mode 100644 index 000000000..498a7ea4c --- /dev/null +++ b/Manager/Sequence/SequenceManager.php @@ -0,0 +1,57 @@ +em = $em; + $this->translator = $translator; + } + + public function getRepository() { + return $this->em->getRepository('UJMExoBundle:Sequence\Sequence'); + } + + public function createFirstAndLastStep(Sequence $s) { + + // add first page + $first = new Step(); + $first->setIsFirst(true); + $first->setPosition(1); + $first->setDescription('

This is the first Step

'); + $first->setSequence($s); + $s->addStep($first); + + // add last page + $last = new Step(); + $last->setIsLast(true); + $last->setPosition(2); + $last->setDescription('

This is the last Step

'); + $last->setSequence($s); + $s->addStep($last); + + $this->em->persist($s); + $this->em->flush(); + return $s; + } + + public function update(Sequence $s) { + $this->em->persist($s); + $this->em->flush(); + return $s; + } + +} diff --git a/Manager/Sequence/StepManager.php b/Manager/Sequence/StepManager.php new file mode 100644 index 000000000..09cf8e37c --- /dev/null +++ b/Manager/Sequence/StepManager.php @@ -0,0 +1,125 @@ +em = $em; + $this->translator = $translator; + } + + public function getRepository() { + return $this->em->getRepository('UJMExoBundle:Sequence\Step'); + } + + /** + * Get all steps + * @param Sequence $s + * @return ArrayCollection + */ + public function getSteps(Sequence $s) { + $steps = $this->getRepository()->findBy(array('sequence' => $s), array('position' => 'ASC')); + return $steps; + } + + /** + * + * @param Sequence $s + * @param type $steps + */ + public function updateSteps(Sequence $s, $steps) { + + // validate data or throws exception + $this->validateStepsData($steps); + + // get original pages before update to delete unused steps + $oldSteps = $this->getSteps($s); + $this->deleteUnusedSteps($oldSteps, $steps); + + foreach ($steps as $step) { + $stepEntity = null; + $toDelete = false; + if (isset($step['id'])) { + $stepEntity = $this->getRepository()->findOneBy(array('id' => $step['id'])); + } else { + $stepEntity = new Step(); + $stepEntity->setSequence($s); + } + if (!$toDelete) { + $stepEntity->setPosition($step['position']); + $stepEntity->setDescription($step['description']); + $stepEntity->setShuffle(isset($step['shuffle']) ? $step['shuffle'] : false); + $this->em->persist($stepEntity); + } + $this->em->flush(); + } + + return $this->getSteps($s); + } + + /** + * Since we get an array from angular service we have to check the received data for each step + * @param Array $steps + * @return boolean + * @throws Exception + */ + private function validateStepsData($steps) { + $valid = true; + + if (!$valid) { + throw new Exception('error'); + } + return $valid; + } + + /** + * Compare two Step(s) collection, the old one and the new one + * if an item is in the old collection and in the new one we keep it + * if an item in the new collection has no id we also keep it + * if an item has an id but can not be found in the new collection we remove it + * @param ArrayCollection $oldCollection + * @param Array $newCollection + */ + private function deleteUnusedSteps($oldCollection, $newCollection){ + foreach ($oldCollection as $toCheck){ + $toKeep = false; + $currentId = $toCheck->getId(); + foreach($newCollection as $new){ + if(!isset($new['id']) || $new['id'] == $currentId){ + $toKeep = true; + break; + } + } + if(!$toKeep){ + $step = $this->getRepository()->findOneBy(array('id' => $currentId)); + $this->em->remove($step); + $this->em->flush(); + } + } + } + + public function addStep(Sequence $s, $step) { + + $stepEntity = new Step(); + $stepEntity->setExercisePlayer($s); + $stepEntity->setPosition($step['position']); + $stepEntity->setDescription($step['description']); + $stepEntity->setShuffle(isset($step['shuffle']) ? $step['shuffle'] : false); + $this->em->persist($stepEntity); + $this->em->flush(); + } + +} diff --git a/Migrations/pdo_mysql/Version20150702121020.php b/Migrations/pdo_mysql/Version20150702121020.php new file mode 100644 index 000000000..aa850bcc0 --- /dev/null +++ b/Migrations/pdo_mysql/Version20150702121020.php @@ -0,0 +1,45 @@ +addSql(" + CREATE TABLE ujm_exercise_player ( + id INT AUTO_INCREMENT NOT NULL, + name VARCHAR(255) NOT NULL, + description LONGTEXT DEFAULT NULL, + start_date DATETIME NOT NULL, + end_date DATETIME DEFAULT NULL, + published TINYINT(1) NOT NULL, + modified TINYINT(1) NOT NULL, + resourceNode_id INT DEFAULT NULL, + UNIQUE INDEX UNIQ_746F5F97B87FAB32 (resourceNode_id), + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB + "); + $this->addSql(" + ALTER TABLE ujm_exercise_player + ADD CONSTRAINT FK_746F5F97B87FAB32 FOREIGN KEY (resourceNode_id) + REFERENCES claro_resource_node (id) + ON DELETE CASCADE + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + DROP TABLE ujm_exercise_player + "); + } +} \ No newline at end of file diff --git a/Migrations/pdo_mysql/Version20150703141121.php b/Migrations/pdo_mysql/Version20150703141121.php new file mode 100644 index 000000000..ad105e90c --- /dev/null +++ b/Migrations/pdo_mysql/Version20150703141121.php @@ -0,0 +1,32 @@ +addSql(" + ALTER TABLE ujm_exercise_player + ADD creation DATETIME NOT NULL, + ADD modification DATETIME NOT NULL + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + ALTER TABLE ujm_exercise_player + DROP creation, + DROP modification + "); + } +} \ No newline at end of file diff --git a/Migrations/pdo_mysql/Version20150703162336.php b/Migrations/pdo_mysql/Version20150703162336.php new file mode 100644 index 000000000..7dded2c75 --- /dev/null +++ b/Migrations/pdo_mysql/Version20150703162336.php @@ -0,0 +1,50 @@ +addSql(" + CREATE TABLE ujm_exercise_page ( + id INT AUTO_INCREMENT NOT NULL, + exercise_player_id INT NOT NULL, + position SMALLINT DEFAULT NULL, + shuffle TINYINT(1) NOT NULL, + is_first_page TINYINT(1) NOT NULL, + is_last_page TINYINT(1) NOT NULL, + resourceNode_id INT DEFAULT NULL, + INDEX IDX_19F33E7D3731F335 (exercise_player_id), + UNIQUE INDEX UNIQ_19F33E7DB87FAB32 (resourceNode_id), + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB + "); + $this->addSql(" + ALTER TABLE ujm_exercise_page + ADD CONSTRAINT FK_19F33E7D3731F335 FOREIGN KEY (exercise_player_id) + REFERENCES ujm_exercise_player (id) + "); + $this->addSql(" + ALTER TABLE ujm_exercise_page + ADD CONSTRAINT FK_19F33E7DB87FAB32 FOREIGN KEY (resourceNode_id) + REFERENCES claro_resource_node (id) + ON DELETE CASCADE + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + DROP TABLE ujm_exercise_page + "); + } +} \ No newline at end of file diff --git a/Migrations/pdo_mysql/Version20150706165036.php b/Migrations/pdo_mysql/Version20150706165036.php new file mode 100644 index 000000000..82ac0253d --- /dev/null +++ b/Migrations/pdo_mysql/Version20150706165036.php @@ -0,0 +1,48 @@ +addSql(" + ALTER TABLE ujm_exercise_page + DROP FOREIGN KEY FK_19F33E7DB87FAB32 + "); + $this->addSql(" + DROP INDEX UNIQ_19F33E7DB87FAB32 ON ujm_exercise_page + "); + $this->addSql(" + ALTER TABLE ujm_exercise_page + ADD description LONGTEXT DEFAULT NULL, + DROP resourceNode_id + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + ALTER TABLE ujm_exercise_page + ADD resourceNode_id INT DEFAULT NULL, + DROP description + "); + $this->addSql(" + ALTER TABLE ujm_exercise_page + ADD CONSTRAINT FK_19F33E7DB87FAB32 FOREIGN KEY (resourceNode_id) + REFERENCES claro_resource_node (id) + ON DELETE CASCADE + "); + $this->addSql(" + CREATE UNIQUE INDEX UNIQ_19F33E7DB87FAB32 ON ujm_exercise_page (resourceNode_id) + "); + } +} \ No newline at end of file diff --git a/Migrations/pdo_mysql/Version20150707164200.php b/Migrations/pdo_mysql/Version20150707164200.php new file mode 100644 index 000000000..73beda8a9 --- /dev/null +++ b/Migrations/pdo_mysql/Version20150707164200.php @@ -0,0 +1,36 @@ +addSql(" + ALTER TABLE ujm_exercise_player + DROP published, + DROP modified, + DROP creation, + DROP modification + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + ALTER TABLE ujm_exercise_player + ADD published TINYINT(1) NOT NULL, + ADD modified TINYINT(1) NOT NULL, + ADD creation DATETIME NOT NULL, + ADD modification DATETIME NOT NULL + "); + } +} \ No newline at end of file diff --git a/Migrations/pdo_mysql/Version20150715120410.php b/Migrations/pdo_mysql/Version20150715120410.php new file mode 100644 index 000000000..452e1d886 --- /dev/null +++ b/Migrations/pdo_mysql/Version20150715120410.php @@ -0,0 +1,68 @@ +addSql(" + CREATE TABLE ujm_sequence_step ( + id INT AUTO_INCREMENT NOT NULL, + sequence_id INT NOT NULL, + description LONGTEXT DEFAULT NULL, + position SMALLINT DEFAULT NULL, + shuffle TINYINT(1) NOT NULL, + is_first TINYINT(1) NOT NULL, + is_last TINYINT(1) NOT NULL, + INDEX IDX_2AE7A31998FB19AE (sequence_id), + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB + "); + $this->addSql(" + CREATE TABLE ujm_sequence ( + id INT AUTO_INCREMENT NOT NULL, + name VARCHAR(255) NOT NULL, + description LONGTEXT DEFAULT NULL, + start_date DATETIME NOT NULL, + end_date DATETIME DEFAULT NULL, + resourceNode_id INT DEFAULT NULL, + UNIQUE INDEX UNIQ_CB11F712B87FAB32 (resourceNode_id), + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB + "); + $this->addSql(" + ALTER TABLE ujm_sequence_step + ADD CONSTRAINT FK_2AE7A31998FB19AE FOREIGN KEY (sequence_id) + REFERENCES ujm_sequence (id) + "); + $this->addSql(" + ALTER TABLE ujm_sequence + ADD CONSTRAINT FK_CB11F712B87FAB32 FOREIGN KEY (resourceNode_id) + REFERENCES claro_resource_node (id) + ON DELETE CASCADE + "); + } + + public function down(Schema $schema) + { + $this->addSql(" + ALTER TABLE ujm_sequence_step + DROP FOREIGN KEY FK_2AE7A31998FB19AE + "); + $this->addSql(" + DROP TABLE ujm_sequence_step + "); + $this->addSql(" + DROP TABLE ujm_sequence + "); + } +} \ No newline at end of file diff --git a/Resources/config/config.yml b/Resources/config/config.yml index a011c438f..9d382afa9 100755 --- a/Resources/config/config.yml +++ b/Resources/config/config.yml @@ -8,6 +8,14 @@ plugin: icon: res_exo.png activity_rules: - action: resource-ujm_exercise-exercise_evaluated + - class: UJM\ExoBundle\Entity\Sequence\Sequence + name: ujm_sequence + is_exportable: false + icon: res_exo.png + actions: + - name: administrate + menu_name: ujm_sequence_administrate + tools: - name: ujm_questions diff --git a/Resources/config/form_types.yml b/Resources/config/form_types.yml new file mode 100644 index 000000000..ee8cdabb9 --- /dev/null +++ b/Resources/config/form_types.yml @@ -0,0 +1,6 @@ +services: + # ExercisePlayer type + ujm_exo_bundle.form.type.exercise_player_type: + class: %ujm_exo_bundle.form.type.sequence_type.class% + tags: + - { name: form.type, alias: sequence_type } diff --git a/Resources/config/parameters.yml b/Resources/config/parameters.yml index dc2eee835..209410e76 100755 --- a/Resources/config/parameters.yml +++ b/Resources/config/parameters.yml @@ -4,3 +4,10 @@ parameters: ujm.param.exo_directory: "%claroline.param.uploads_directory%/ujmexo" ujm.param.qti_directory: "%ujm.param.exo_directory%/qti" + + # Form Types + ujm_exo_bundle.form.type.sequence_type.class: UJM\ExoBundle\Form\Sequence\SequenceType + + # Managers + ujm_exo_bundle.manager.sequence.class: UJM\ExoBundle\Manager\Sequence\SequenceManager + ujm_exo_bundle.manager.steps.class: UJM\ExoBundle\Manager\Sequence\StepManager diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 6520cec8b..4e98b11fd 100755 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -49,3 +49,14 @@ all_paper: all_qti: resource: "routing/all/qti.yml" prefix: /all/qti + +sequence: + resource: "@UJMExoBundle/Controller/Sequence/SequenceController.php" + type: annotation + prefix: /sequence + + +sequence_steps: + resource: "@UJMExoBundle/Controller/Sequence/StepController.php" + type: annotation + prefix: /page diff --git a/Resources/config/services.yml b/Resources/config/services.yml index dc6afcb28..f6fd7ef43 100755 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -177,3 +177,27 @@ services: scope: request tags: - { name: validator.constraint_validator, alias: ujm.exercise_isvalidqcmmark } + + ujm.listener.sequence_listener: + class: UJM\ExoBundle\Listener\Resource\SequenceListener + calls: + - [setContainer, ["@service_container"]] + tags: + - { name: kernel.event_listener, event: create_form_ujm_sequence, method: onCreateForm } + - { name: kernel.event_listener, event: create_ujm_sequence, method: onCreate } + - { name: kernel.event_listener, event: open_ujm_sequence, method: onOpen } + - { name: kernel.event_listener, event: delete_ujm_sequence, method: onDelete } + - { name: kernel.event_listener, event: copy_ujm_sequence, method: onCopy } + - { name: kernel.event_listener, event: ujm_sequence_administrate_ujm_sequence, method: onAdministrate } + + ujm_exo_bundle.manager.sequence: + class: UJM\ExoBundle\Manager\Sequence\SequenceManager + arguments: + entityManager: @doctrine.orm.entity_manager + translator: @translator + + ujm_exo_bundle.manager.steps: + class: UJM\ExoBundle\Manager\Sequence\StepManager + arguments: + entityManager: @doctrine.orm.entity_manager + translator: @translator \ No newline at end of file diff --git a/Resources/public/css/exercise-player.css b/Resources/public/css/exercise-player.css new file mode 100644 index 000000000..7802013e3 --- /dev/null +++ b/Resources/public/css/exercise-player.css @@ -0,0 +1 @@ +.exercise-player-container{width:100%;background:white;padding:15px}.exercise-player-container .page-container ul.page-list{list-style-type:none}.exercise-player-container .page-container ul.page-list li.page-list-item{display:inline-block;line-height:50px;width:50px;height:50px;vertical-align:middle;border:1px solid black;cursor:pointer;background-color:rgba(255,255,255,0.8);margin:5px;border-radius:5px}.exercise-player-container .page-container ul.page-list li.page-list-item div{display:inline-block}.exercise-player-container .page-container ul.page-list li.page-list-item.active{background-color:#428bca}.exercise-player-container .page-container ul.page-list .placeholder{display:inline-block;border:1px dotted #aaa;width:35px;line-height:50px;height:35px;vertical-align:middle;border-radius:5px;background-color:rgba(66,139,202,0.2)} \ No newline at end of file diff --git a/Resources/public/css/ujm-sequence.css b/Resources/public/css/ujm-sequence.css new file mode 100644 index 000000000..01ce00b9d --- /dev/null +++ b/Resources/public/css/ujm-sequence.css @@ -0,0 +1 @@ +.ujm-sequence-container{width:100%;background:white;padding:15px}.ujm-sequence-container .step-container ul.step-list{list-style-type:none}.ujm-sequence-container .step-container ul.step-list li.step-list-item{display:inline-block;line-height:50px;width:50px;height:50px;vertical-align:middle;border:1px solid black;cursor:pointer;background-color:rgba(255,255,255,0.8);margin:5px;border-radius:5px}.ujm-sequence-container .step-container ul.step-list li.step-list-item div{display:inline-block}.ujm-sequence-container .step-container ul.step-list li.step-list-item.active{background-color:#428bca}.ujm-sequence-container .step-container ul.step-list .placeholder{display:inline-block;border:1px dotted #aaa;width:35px;line-height:50px;height:35px;vertical-align:middle;border-radius:5px;background-color:rgba(66,139,202,0.2)} \ No newline at end of file diff --git a/Resources/public/js/sequence/Sequence/Controllers/SequenceEditCtrl.js b/Resources/public/js/sequence/Sequence/Controllers/SequenceEditCtrl.js new file mode 100644 index 000000000..421869098 --- /dev/null +++ b/Resources/public/js/sequence/Sequence/Controllers/SequenceEditCtrl.js @@ -0,0 +1,75 @@ +(function () { + 'use strict'; + + angular.module('Sequence').controller('SequenceEditCtrl', [ + 'SequenceService', + function (SequenceService) { + + this.sequence = {}; + this.isCollapsed = false; + + this.endDateIsOpened = false; + this.startDateIsOpened = false; + + this.openEndDate = function ($event) { + $event.preventDefault(); + $event.stopPropagation(); + this.startDateIsOpened = true; + }; + + this.openStartDate = function ($event) { + $event.preventDefault(); + $event.stopPropagation(); + this.endDateIsOpened = true; + }; + + // not working + this.dateOptions = { + showButtonBar: false, + closeText: 'Close Me', + showWeeks: false + }; + + + + // Tiny MCE options + this.tinymceOptions = { + relative_urls: false, + theme: 'modern', + browser_spellcheck: true, + autoresize_min_height: 100, + autoresize_max_height: 500, + plugins: [ + 'autoresize advlist autolink lists link image charmap print preview hr anchor pagebreak', + 'searchreplace wordcount visualblocks visualchars fullscreen', + 'insertdatetime media nonbreaking save table directionality', + 'template paste textcolor emoticons code' + ], + toolbar1: 'undo redo | styleselect | bold italic underline | forecolor | alignleft aligncenter alignright | preview fullscreen', + paste_preprocess: function (plugin, args) { + var link = $('
' + args.content + '
').text().trim(); //inside div because a bug of jquery + var url = link.match(/^(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)|((mailto:)?[_.\w-]+@([\w][\w\-]+\.)+[a-zA-Z]{2,3})$/); + + if (url) { + args.content = '' + link + ''; + window.Claroline.Home.generatedContent(link, function (data) { + insertContent(data); + }, false); + } + } + }; + + this.update = function () { + SequenceService.update(this.sequence); + }; + + this.setSequence = function (sequence) { + this.sequence = sequence; + }; + + this.getSequence = function () { + return this.sequence; + }; + } + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/Sequence/Directives/SequenceEditDirective.js b/Resources/public/js/sequence/Sequence/Directives/SequenceEditDirective.js new file mode 100644 index 000000000..4eadf7e75 --- /dev/null +++ b/Resources/public/js/sequence/Sequence/Directives/SequenceEditDirective.js @@ -0,0 +1,30 @@ +/** + * Activity Form directive + * Directive Documentation : https://docs.angularjs.org/guide/directive + */ +(function () { + 'use strict'; + + angular.module('Sequence').directive('sequenceEdit', [ + function () { + return { + restrict: 'E', + replace: true, + controller: 'SequenceEditCtrl', + controllerAs: 'sequenceEditCtrl', + templateUrl: AngularApp.webDir + 'bundles/ujmexo/js/sequence/Sequence/Partials/sequence.edit.html', + scope: { + sequence: '=' + }, + link: function (scope, element, attr, sequenceEditCtrl) { + // set current page to first page + console.log('sequence directive link method called'); + sequenceEditCtrl.setSequence(scope.sequence); + + } + }; + } + ]); +})(); + + diff --git a/Resources/public/js/sequence/Sequence/Partials/sequence.edit.html b/Resources/public/js/sequence/Sequence/Partials/sequence.edit.html new file mode 100644 index 000000000..fc4960f0d --- /dev/null +++ b/Resources/public/js/sequence/Sequence/Partials/sequence.edit.html @@ -0,0 +1,38 @@ +
+
+
+

{{ 'sequence_panel_title'|trans:{}:'ujm_sequence' }}

+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
\ No newline at end of file diff --git a/Resources/public/js/sequence/Sequence/Services/SequenceService.js b/Resources/public/js/sequence/Sequence/Services/SequenceService.js new file mode 100644 index 000000000..cf60e7493 --- /dev/null +++ b/Resources/public/js/sequence/Sequence/Services/SequenceService.js @@ -0,0 +1,57 @@ +/** + * Exercise player service + */ +(function () { + 'use strict'; + + angular.module('Sequence').factory('SequenceService', [ + '$http', + '$filter', + '$q', + function PlayerService($http, $filter, $q) { + + + return { + + /** + * Update the sequence + * @param sequence + * @returns + */ + update : function (sequence){ + var deferred = $q.defer(); + // sequence constructor + function Sequence(sequence){ + var ujm_sequence = { + name: sequence.name, + description: sequence.description, + startDate: new Date(sequence.startDate), + endDate: new Date(sequence.endDate) + }; + + return ujm_sequence; + } + + var updated = new Sequence(sequence); + + $http + .put( + Routing.generate('ujm_sequence_update', { id : sequence.id }), + { + sequence_type: updated + } + ) + .success(function (response){ + deferred.resolve(response); + }) + .error(function(data, status){ + console.log('sequence service, update method error'); + console.log(status); + console.log(data); + }); + return deferred; + } + }; + } + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/Sequence/module.js b/Resources/public/js/sequence/Sequence/module.js new file mode 100644 index 000000000..7ed3e012e --- /dev/null +++ b/Resources/public/js/sequence/Sequence/module.js @@ -0,0 +1,11 @@ +/** + * Page module + */ +(function () { + 'use strict'; + + angular.module('Sequence', [ + + ]); +})(); + diff --git a/Resources/public/js/sequence/Step/Controllers/StepEditCtrl.js b/Resources/public/js/sequence/Step/Controllers/StepEditCtrl.js new file mode 100644 index 000000000..6074a9c6b --- /dev/null +++ b/Resources/public/js/sequence/Step/Controllers/StepEditCtrl.js @@ -0,0 +1,138 @@ +(function () { + 'use strict'; + + angular.module('Step').controller('StepEditCtrl', [ + 'StepService', + function (StepService) { + + this.steps = {}; + this.currentStepIndex = 0; + + // options for sortable steps + this.sortableOptions = { + placeholder: "placeholder", + axis: 'x', + stop: function (e, ui) { + this.updateStepsOrder(); + }.bind(this), + cancel: ".unsortable", + items: "li:not(.unsortable)" + }; + + // Tiny MCE options + this.tinymceOptions = { + relative_urls: false, + theme: 'modern', + browser_spellcheck: true, + autoresize_min_height: 100, + autoresize_max_height: 500, + plugins: [ + 'autoresize advlist autolink lists link image charmap print preview hr anchor pagebreak', + 'searchreplace wordcount visualblocks visualchars fullscreen', + 'insertdatetime media nonbreaking save table directionality', + 'template paste textcolor emoticons code' + ], + toolbar1: 'undo redo | styleselect | bold italic underline | forecolor | alignleft aligncenter alignright | preview fullscreen', + paste_preprocess: function (plugin, args) { + var link = $('
' + args.content + '
').text().trim(); //inside div because a bug of jquery + var url = link.match(/^(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)|((mailto:)?[_.\w-]+@([\w][\w\-]+\.)+[a-zA-Z]{2,3})$/); + + if (url) { + args.content = '' + link + ''; + window.Claroline.Home.generatedContent(link, function (data) { + insertContent(data); + }, false); + } + } + }; + + // Step constructor + var my = this; + var Step = function () { + var ujm_step = { + description: '

New step default description

', + position: my.steps.length, + shuffle: false, + sequenceId: my.steps[0].sequenceId, + isLast: false, + isFirst: false + }; + return ujm_step; + }; + + this.addStep = function () { + // create a new step + var step = new Step(); + // update last step position + var last = this.steps[this.steps.length - 1]; + last.position = step.position + 1; + // add new step at the right index in steps array + this.steps.splice(this.steps.length - 1, 0, step); + }; + + this.removeStep = function () { + var current = this.steps[this.currentStepIndex]; + if (current && !current.isLast && !current.isFirst) { + var index = this.steps.indexOf(current); + // update positions... + for (var i = index; i < this.steps.length; i++) { + var step = this.steps[i]; + step.position = step.position - 1; + } + // remove step + this.steps.splice(index, 1); + } + }; + + this.update = function () { + var promise = StepService.update(this.steps); + promise.then(function (result) { + console.log('steps update success'); + }, function (error) { + console.log('steps update error'); + }); + + }; + + this.getNextStep = function () { + var newIndex = this.currentStepIndex + 1; + if (this.steps[newIndex]) { + this.currentStepIndex = newIndex; + } else { + this.currentStepIndex = 0; + } + }; + + this.getPreviousStep = function () { + var newIndex = this.currentStepIndex - 1; + if (this.steps[newIndex]) { + this.currentStepIndex = newIndex; + } else { + this.currentStepIndex = this.steps.length - 1; + } + }; + + // on dragg end + this.updateStepsOrder = function(){ + var index = 0; + for(index; index < this.steps.length; index++){ + var step = this.steps[index]; + step.position = index + 1; + } + }; + + this.setSteps = function (steps) { + this.steps = steps; + }; + + this.getSteps = function () { + return this.steps; + }; + + this.setCurrentStep = function (step) { + var index = this.steps.indexOf(step); + this.currentStepIndex = index; + }; + } + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/Step/Controllers/StepShowCtrl.js b/Resources/public/js/sequence/Step/Controllers/StepShowCtrl.js new file mode 100644 index 000000000..d61a45572 --- /dev/null +++ b/Resources/public/js/sequence/Step/Controllers/StepShowCtrl.js @@ -0,0 +1,14 @@ +(function () { + 'use strict'; + + angular.module('Step').controller('StepShowCtrl', [ + 'StepService', + function (StepService) { + + + this.sayHello = function (name) { + console.log(StepService.hello(name)); + }; + } + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/Step/Directives/StepEditDirective.js b/Resources/public/js/sequence/Step/Directives/StepEditDirective.js new file mode 100644 index 000000000..fd2799fc8 --- /dev/null +++ b/Resources/public/js/sequence/Step/Directives/StepEditDirective.js @@ -0,0 +1,27 @@ +/** + * Activity Form directive + * Directive Documentation : https://docs.angularjs.org/guide/directive + */ +(function () { + 'use strict'; + + angular.module('Step').directive('stepEdit', [ + function () { + return { + restrict: 'E', + replace: true, + controller: 'StepEditCtrl', + controllerAs: 'stepEditCtrl', + templateUrl: AngularApp.webDir + 'bundles/ujmexo/js/sequence/Step/Partials/step.edit.html', + scope: { + steps: '=' + }, + link: function (scope, element, attr, stepEditCtrl) { + // set current page to first page + console.log('step edit directive link method called'); + stepEditCtrl.setSteps(scope.steps); + } + }; + } + ]); +})(); diff --git a/Resources/public/js/sequence/Step/Directives/StepShowDirective.js b/Resources/public/js/sequence/Step/Directives/StepShowDirective.js new file mode 100644 index 000000000..f41271f68 --- /dev/null +++ b/Resources/public/js/sequence/Step/Directives/StepShowDirective.js @@ -0,0 +1,24 @@ + +(function () { + 'use strict'; + + angular.module('Step').directive('stepShow', [ + function () { + return { + restrict: 'E', + replace: true, + controller: 'StepShowCtrl', + controllerAs: 'stepShowCtrl', + templateUrl: AngularApp.webDir + 'bundles/ujmexo/js/sequence/Step/Partials/step.show.html', + scope: { + steps: '=' + }, + link: function (scope, element, attr, stepShowCtrl) { + + } + }; + } + ]); +})(); + + diff --git a/Resources/public/js/sequence/Step/Partials/step.edit.html b/Resources/public/js/sequence/Step/Partials/step.edit.html new file mode 100644 index 000000000..e690cce99 --- /dev/null +++ b/Resources/public/js/sequence/Step/Partials/step.edit.html @@ -0,0 +1,46 @@ +
+
+
+

{{ 'sequence_step_panel_title'|trans:{}:'ujm_sequence' }} {{ stepEditCtrl.currentStepIndex + 1}} / {{ stepEditCtrl.steps.length}}

+
+ + + +
+
+
+ +
+
+ +
+
+
    +
  • +
    {{ step.position }}
    +
  • +
+
+
+ +
+
+
+ + +
+
+ +
+
+
+ +
+ + +
+
+
+
\ No newline at end of file diff --git a/Resources/public/js/sequence/Step/Partials/step.show.html b/Resources/public/js/sequence/Step/Partials/step.show.html new file mode 100644 index 000000000..edfb3a15c --- /dev/null +++ b/Resources/public/js/sequence/Step/Partials/step.show.html @@ -0,0 +1,11 @@ +
+
+

This is the "show exercise player" partial panel header

+
+
+

This is the "show exercise player" partial panel body

+
+

Nothing is implemented in the player yet :(

+

Please use the administrate resource menu to see the actual exercise player interface in edit mode.

+
+
\ No newline at end of file diff --git a/Resources/public/js/sequence/Step/Services/StepService.js b/Resources/public/js/sequence/Step/Services/StepService.js new file mode 100644 index 000000000..fc913c672 --- /dev/null +++ b/Resources/public/js/sequence/Step/Services/StepService.js @@ -0,0 +1,41 @@ +/** + * Page Service + */ +(function () { + 'use strict'; + + angular.module('Step').factory('StepService', [ + '$http', + '$filter', + '$q', + function StepService($http, $filter, $q) { + + return { + + /** + * Update exercise player steps + * @param player + * @returns + */ + update : function (steps){ + var deferred = $q.defer(); + var sequenceId = steps[0].sequenceId; + $http + .post( + Routing.generate('ujm_steps_update', { id : sequenceId}), {steps: steps} + ) + .success(function (response){ + deferred.resolve(response); + }) + .error(function(data, status){ + console.log('Step service, update method error'); + console.log(status); + console.log(data); + }); + + return deferred.promise; + } + }; + } + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/Step/module.js b/Resources/public/js/sequence/Step/module.js new file mode 100644 index 000000000..d5a8a5fc9 --- /dev/null +++ b/Resources/public/js/sequence/Step/module.js @@ -0,0 +1,11 @@ +/** + * Page module + */ +(function () { + 'use strict'; + + angular.module('Step', [ + + ]); +})(); + diff --git a/Resources/public/js/sequence/editor.module.js b/Resources/public/js/sequence/editor.module.js new file mode 100644 index 000000000..cc2fb3218 --- /dev/null +++ b/Resources/public/js/sequence/editor.module.js @@ -0,0 +1,15 @@ +(function () { + 'use strict'; + + // exercise player module + angular.module('SequenceEditApp', [ + 'ngSanitize', + 'ui.bootstrap', + 'ui.sortable', + 'ui.tinymce', + 'ui.translation', + 'ui.resourcePicker', + 'Step', + 'Sequence' + ]); +})(); \ No newline at end of file diff --git a/Resources/public/js/sequence/player.module.js b/Resources/public/js/sequence/player.module.js new file mode 100644 index 000000000..8a6f19222 --- /dev/null +++ b/Resources/public/js/sequence/player.module.js @@ -0,0 +1,13 @@ +(function () { + 'use strict'; + + // exercise player module + angular.module('SequenceViewApp', [ + 'ngSanitize', + 'ui.bootstrap', + 'ui.tinymce', + 'ui.translation', + 'ui.resourcePicker', + 'Step' + ]); +})(); \ No newline at end of file diff --git a/Resources/public/less/ujm-sequence.less b/Resources/public/less/ujm-sequence.less new file mode 100644 index 000000000..bd8b85c4c --- /dev/null +++ b/Resources/public/less/ujm-sequence.less @@ -0,0 +1,45 @@ +.ujm-sequence-container{ + width: 100%; + background: white; + padding: 15px; + .player-container{ + + } + .step-container{ + + ul.step-list{ + list-style-type: none; + li.step-list-item { + display: inline-block; + line-height: 50px; + width:50px; + height: 50px; + vertical-align: middle; + border: 1px solid black; + cursor: pointer; + background-color: rgba(255, 255, 255, 0.8); + margin: 5px; + border-radius: 5px; + div { + display: inline-block; + /*padding-top: 12px;*/ + } + + } + li.step-list-item.active{ + background-color: rgba(66, 139, 202, 1); + } + .placeholder { + display: inline-block; + border: 1px dotted #aaa; + width:35px; + line-height: 50px; + height: 35px; + /*padding-top:10px;*/ + vertical-align: middle; + border-radius: 5px; + background-color: rgba(66, 139, 202, 0.2); + } + } + } +} \ No newline at end of file diff --git a/Resources/translations/resource.en.yml b/Resources/translations/resource.en.yml index f5741f66d..b6876fa64 100755 --- a/Resources/translations/resource.en.yml +++ b/Resources/translations/resource.en.yml @@ -1 +1,4 @@ +# u ujm_exercise: Exercise +ujm_sequence: UJM Sequence +ujm_sequence_administrate: Administrate sequence diff --git a/Resources/translations/resource.fr.yml b/Resources/translations/resource.fr.yml index 384d591f0..8211f11c3 100755 --- a/Resources/translations/resource.fr.yml +++ b/Resources/translations/resource.fr.yml @@ -1 +1,4 @@ +# u ujm_exercise: Exercice +ujm_sequence: Séquence UJM +ujm_sequence_administrate: Administrer la séquence diff --git a/Resources/translations/ujm_sequence.en.yml b/Resources/translations/ujm_sequence.en.yml new file mode 100644 index 000000000..9f95ccde8 --- /dev/null +++ b/Resources/translations/ujm_sequence.en.yml @@ -0,0 +1,19 @@ +# e +sequence_panel_title: Sequence +sequence_panel_hide: Hide / Show sequence informations +sequence_type_name : Sequence name +sequence_type_description : Sequence description +sequence_start_date: Start date +sequence_end_date: End date +sequence_name : Name +sequence_description : Description +sequence_step_description: Description +sequence_step_shuffle: Shuffle +sequence_step_previous: Previous step +sequence_step_next: Next step +sequence_step_view: View step +sequence_steps_save: Save steps +sequence_step_add: Add step +sequence_step_remove: Remove step +sequence_save: Save sequence +sequence_step_panel_title: Steps diff --git a/Resources/translations/ujm_sequence.fr.yml b/Resources/translations/ujm_sequence.fr.yml new file mode 100644 index 000000000..76c070eed --- /dev/null +++ b/Resources/translations/ujm_sequence.fr.yml @@ -0,0 +1,19 @@ +# e +sequence_panel_title: Séquence +sequence_panel_hide: Cacher / Montrer les informations de la séquence +sequence_type_name : Nom de la séquence +sequence_type_description : Description de la séquence +sequence_start_date: Date de début +sequence_end_date: Date de fin +sequence_name : Nom +sequence_description : Description +sequence_step_description: Description +sequence_step_shuffle: Aléatoire +sequence_step_previous: Etape précédente +sequence_step_next: Etape suivante +sequence_step_view: Voir l'étape +sequence_steps_save: Sauvegarder les étapes +sequence_step_add: Ajouter une étape +sequence_step_remove: Supprimer une étape +sequence_save: Sauvegarder la séquence +sequence_step_panel_title: Etapes \ No newline at end of file diff --git a/Resources/views/Sequence/edit.html.twig b/Resources/views/Sequence/edit.html.twig new file mode 100644 index 000000000..8c3db68d9 --- /dev/null +++ b/Resources/views/Sequence/edit.html.twig @@ -0,0 +1,39 @@ +{% extends "UJMExoBundle:Sequence:layout.html.twig" %} + +{% block breadcrumb %} + {{ parent() }} +{% endblock %} + +{% block content %} +
+ + +
+{% endblock %} + + +{% block javascripts %} + {# Load Claroline JS #} + {{ parent() }} + + {% javascripts debug=false filter='jsmin' output='vendor/ujmexo/ujm_sequence_edit.js' + + '@UJMExoBundle/Resources/public/js/sequence/Sequence/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Controllers/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Directives/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Services/*' + + '@UJMExoBundle/Resources/public/js/sequence/Step/*' + '@UJMExoBundle/Resources/public/js/sequence/Step/Controllers/*' + '@UJMExoBundle/Resources/public/js/sequence/Step/Directives/*' + '@UJMExoBundle/Resources/public/js/sequence/Step/Services/*' + + '@UJMExoBundle/Resources/public/js/sequence/editor.module.js' + %} + + {% endjavascripts %} + + +{% endblock %} + + diff --git a/Resources/views/Sequence/layout.html.twig b/Resources/views/Sequence/layout.html.twig new file mode 100644 index 000000000..a26ebf482 --- /dev/null +++ b/Resources/views/Sequence/layout.html.twig @@ -0,0 +1,60 @@ +{% extends "ClarolineCoreBundle:Workspace:layout.html.twig" %} + +{% block stylesheets %} + {# Claroline CSS #} + {{ parent() }} + + {# Exercise Player styles #} + {% stylesheets debug=false filter='lessphp, cssmin' output='bundles/ujmexo/css/ujm-sequence.css' + '@UJMExoBundle/Resources/public/less/ujm-sequence.less' + %} + + {% endstylesheets %} +{% endblock %} + +{% block content %} + +{% endblock %} + +{% block javascripts %} + {# Claroline JS #} + {{ parent() }} + + {# Translations #} + + + {# Angular JS #} + {% javascripts debug=false filter='jsmin' output='vendor/ujmexo/ujm-exo-angular-js.js' + '@InnovaAngularJSBundle/Resources/public/js/angular.min.js' + '@InnovaAngularJSBundle/Resources/public/js/angular-sanitize.min.js' + '@InnovaAngularJSBundle/Resources/public/js/angular-route.min.js' + '@InnovaAngularJSBundle/Resources/public/js/angular-resource.min.js' + '@InnovaAngularJSBundle/Resources/public/js/angular-touch.min.js' + %} + + {% endjavascripts %} + + {# Angular UI #} + {% javascripts debug=false filter='jsmin' output='vendor/ujmexo/ujm-exo-angular-ui.js' + '@InnovaAngularUIBootstrapBundle/Resources/public/js/*' + '@InnovaAngularUITinyMCEBundle/Resources/public/js/*' + '@InnovaAngularUITranslationBundle/Resources/public/js/*' + '@InnovaAngularUIResourcePickerBundle/Resources/public/js/*' + '@InnovaAngularUISortableBundle/Resources/public/js/*' + %} + + {% endjavascripts %} + + + + {# Set some vars needed by Angular parts #} + +{% endblock %} diff --git a/Resources/views/Sequence/view.html.twig b/Resources/views/Sequence/view.html.twig new file mode 100644 index 000000000..843586b0d --- /dev/null +++ b/Resources/views/Sequence/view.html.twig @@ -0,0 +1,35 @@ +{% extends "UJMExoBundle:Sequence:layout.html.twig" %} + + + +{% block breadcrumb %} + {{ parent() }} +{% endblock %} + +{% block content %} +
+ +
+{% endblock %} + + +{% block javascripts %} + {# Load Claroline JS #} + {{ parent() }} + + + + {% javascripts debug=false filter='jsmin' output='vendor/ujmexo/ujm_sequence_show.js' + + '@UJMExoBundle/Resources/public/js/sequence/Sequence/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Controllers/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Directives/*' + '@UJMExoBundle/Resources/public/js/sequence/Sequence/Services/*' + + '@UJMExoBundle/Resources/public/js/player/player.module.js' + %} + + {% endjavascripts %} + + +{% endblock %} \ No newline at end of file diff --git a/UJMExoBundle.php b/UJMExoBundle.php index 6d13090d2..a4154c24c 100755 --- a/UJMExoBundle.php +++ b/UJMExoBundle.php @@ -5,23 +5,38 @@ use Claroline\CoreBundle\Library\PluginBundle; use Claroline\KernelBundle\Bundle\ConfigurationBuilder; -class UJMExoBundle extends PluginBundle -{ +class UJMExoBundle extends PluginBundle { - public function getContainerExtension() - { + public function getContainerExtension() { return new DependencyInjection\UJMExoExtension(); } - public function getConfiguration($environment) - { + public function getConfiguration($environment) { $config = new ConfigurationBuilder(); return $config->addRoutingResource(__DIR__ . '/Resources/config/routing.yml', null, 'exercise'); } - public function getRequiredFixturesDirectory($environment) - { + public function getRequiredFixturesDirectory($environment) { return 'DataFixtures'; } + + public function suggestConfigurationFor(Bundle $bundle, $environment) { + $bundleClass = get_class($bundle); + $config = new ConfigurationBuilder(); + $emptyConfigs = array( + 'Innova\AngularJSBundle\InnovaAngularJSBundle', + 'Innova\AngularUIBootstrapBundle\InnovaAngularUIBootstrapBundle', + 'Innova\AngularUITranslationBundle\InnovaAngularUITranslationBundle', + 'Innova\AngularUIResourcePickerBundle\InnovaAngularUIResourcePickerBundle', + 'Innova\AngularUITinyMCEBundle\InnovaAngularUITinyMCEBundle', + 'Innova\AngularUIPageslideBundle\InnovaAngularUIPageslideBundle', + 'Innova\AngularUISortableBundle\AngularUISortableBundle', + ); + if (in_array($bundleClass, $emptyConfigs)) { + return $config; + } + return false; + } + } diff --git a/composer.json b/composer.json index 1c0f90886..ee927ec04 100755 --- a/composer.json +++ b/composer.json @@ -4,13 +4,17 @@ "type": "claroline-plugin", "require": { "claroline/core-bundle": "~5.0", - "icap/badge-bundle": "~5.0" + "icap/badge-bundle": "~5.0", + "innova/angular-js-bundle": "~5.1", + "innova/angular-ui-bootstrap-bundle" : "~5.0", + "innova/angular-ui-tinymce-bundle" : "~5.0", + "innova/angular-ui-translation-bundle" : "~5.0", + "innova/angular-ui-resource-picker-bundle" : "~6.0", + "innova/angular-ui-sortable-bundle" : "~5.0", + "innova/angular-ui-pageslide-bundle" : "~5.0" }, "autoload": { "psr-0": { "UJM\\ExoBundle": "" } }, - "target-dir": "UJM/ExoBundle", - "extra": { - "dbVersion": "20150416104535" - } + "target-dir": "UJM/ExoBundle" }