From ddb04557ee6d1e06eedc012d85951d37e237bace Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Fri, 20 Jul 2012 17:22:41 +0200 Subject: [PATCH] see #5228: adding but not enabling glossary changes --- main/glossary/access.class.php | 84 + main/glossary/ajax_controller.class.php | 108 + main/glossary/controller.class.php | 308 + main/glossary/course_import.class.php | 85 + main/glossary/csv_reader.class.php | 100 + main/glossary/csv_writer.class.php | 46 + main/glossary/glossary.class.php | 212 + main/glossary/glossary_form.class.php | 96 + main/glossary/glossary_repository.class.php | 327 + main/glossary/request.class.php | 172 + .../resources/js/jquery.dataTables.js | 11863 ++++++++++++++++ .../resources/js/jquery.dataTables.min.js | 154 + main/glossary/resources/js/proxy.js | 40 + main/glossary/resources/js/ui.js | 106 + main/glossary/upload_file_form.class.php | 94 + 15 files changed, 13795 insertions(+) create mode 100644 main/glossary/access.class.php create mode 100644 main/glossary/ajax_controller.class.php create mode 100644 main/glossary/controller.class.php create mode 100644 main/glossary/course_import.class.php create mode 100644 main/glossary/csv_reader.class.php create mode 100644 main/glossary/csv_writer.class.php create mode 100644 main/glossary/glossary.class.php create mode 100644 main/glossary/glossary_form.class.php create mode 100644 main/glossary/glossary_repository.class.php create mode 100644 main/glossary/request.class.php create mode 100644 main/glossary/resources/js/jquery.dataTables.js create mode 100644 main/glossary/resources/js/jquery.dataTables.min.js create mode 100644 main/glossary/resources/js/proxy.js create mode 100644 main/glossary/resources/js/ui.js create mode 100644 main/glossary/upload_file_form.class.php diff --git a/main/glossary/access.class.php b/main/glossary/access.class.php new file mode 100644 index 0000000000..dfff157a9f --- /dev/null +++ b/main/glossary/access.class.php @@ -0,0 +1,84 @@ + for the Univesity of Genevas + * @license /license.txt + */ +class Access extends \Access +{ + + /** + * Return the instance . + * + * @return \Access + */ + public static function instance() + { + static $result = null; + if (empty($result)) { + $result = new self(); + } + return $result; + } + + /** + * Returns true if the user has the right to edit. + * + * @return boolean + */ + public function can_edit() + { + if (Request::is_student_view()) { + return false; + } + $session_id = Request::get_session_id(); + + if ($session_id != 0 && api_is_allowed_to_session_edit(false, true) == false) { + return false; + } + + if (!api_is_allowed_to_edit(false, true, true)) { + return false; + } + return true; + } + + /** + * Returns true if the current user has the right to view + * + * @return boolean + */ + public function can_view() + { + $authorize = api_protect_course_script(true); + if (!$authorize) { + return false; + } + + $c_id = Request::get_c_id(); + if (empty($c_id)) { + return false; + } + + return true; + } + + public function authorize() + { + if (!$this->can_view()) { + return false; + } + + $c_id = Request::get_c_id(); + if (empty($c_id)) { + return false; + } + + return true; + } + +} \ No newline at end of file diff --git a/main/glossary/ajax_controller.class.php b/main/glossary/ajax_controller.class.php new file mode 100644 index 0000000000..0ec69083e9 --- /dev/null +++ b/main/glossary/ajax_controller.class.php @@ -0,0 +1,108 @@ +run(); + * + * @author Laurent Opprecht for the Univesity of Genevas + * @license /license.txt + */ +class AjaxController extends \AjaxController +{ + + const ACTION_REMOVE = 'remove'; + const ACTION_REMOVE_BY_COURSE = 'remove_by_course'; + const ACTION_FIND_BY_ID = 'find_by_id'; + + /** + * Return the instance of the controller. + * + * @return \Glossary\AjaxController + */ + public static function instance() + { + static $result = null; + if (empty($result)) { + $result = new self(Access::instance()); + } + return $result; + } + + /** + * Prepare the environment. Set up breadcrumps and raise tracking event. + */ + protected function prolog() + { + event_access_tool(TOOL_GLOSSARY); + } + + public function is_allowed_to_edit() + { + return $this->access()->can_edit(); + } + + /** + * Remove/delete a glossary entry + */ + public function remove() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $item = Request::get_item_key(); + $success = Glossary::repository()->remove($item); + $message = $success ? '' : get_lang('Error'); + + $this->response($success, $message); + } + + /** + * Remove/delete all glossary entries belonging to a course. + */ + public function remove_by_course() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $course = Request::get_course_key(); + $success = Glossary::repository()->remove_by_course($course); + $message = $success ? '' : get_lang('Error'); + + $this->response($success, $message); + } + + public function find_by_id() + { + $c_id = Request::get_c_id(); + $id = Request::get_id(); + $item = Glossary::repository()->find_one_by_id($c_id, $id); + $data = (object) array(); + if ($item) { + $data->name = $item->name; + $data->description = $item->description; + } + $this->response($success, '', $data); + } + +} \ No newline at end of file diff --git a/main/glossary/controller.class.php b/main/glossary/controller.class.php new file mode 100644 index 0000000000..a25a7d1560 --- /dev/null +++ b/main/glossary/controller.class.php @@ -0,0 +1,308 @@ +run(); + * + * @package chamilo.course_description + * @author Christian Fasanando + * @author Laurent Opprecht for the Univesity of Genevas + * @license see /license.txt + */ +class Controller extends \Controller +{ + + const ACTION_ADD = 'add'; + const ACTION_EDIT = 'edit'; + const ACTION_DELETE = 'delete'; + const ACTION_INDEX = 'index'; + const ACTION_DEFAULT = 'index'; + const ACTION_EXPORT_CSV = 'export_csv'; + const ACTION_IMPORT_CSV = 'import_csv'; + + /** + * Return the instance of the controller. + * + * @return \Glossary\Controller + */ + public static function instance() + { + static $result = null; + if (empty($result)) { + $result = new self(Access::instance()); + } + return $result; + } + + /** + * Action to perform. + * Returns the request parameter. + * + * @return string + */ + public function get_action() + { + if (Request::is_student_view()) { + return self::ACTION_INDEX; + } + + $result = parent::get_action(); + $result = $result ? $result : self::ACTION_DEFAULT; + return $result; + } + + public function is_allowed_to_edit() + { + return $this->access()->can_edit(); + } + + /** + * Prepare the environment. Set up breadcrumps and raise tracking event. + */ + protected function prolog() + { + global $interbreadcrumb; + $interbreadcrumb = array(); + $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('Glossary')); + + + global $this_section; + $this_section = SECTION_COURSES; + + global $current_course_tool; + $current_course_tool = TOOL_GLOSSARY; + + // Tracking + event_access_tool(TOOL_GLOSSARY); + } + + /** + * Returns a url for an action that the controller can process + * + * @param string $action + * @param array $params + * @return string + */ + public function url($action = '', $params = array()) + { + $url_params = Uri::course_params(); + if ($c_id = Request::get_c_id()) { + $url_params[Request::PARAM_C_ID] = $c_id; + } + if ($id = Request::get_id()) { + $url_params[Request::PARAM_ID] = $id; + } + if ($session_id = Request::get_session_id()) { + $url_params[Request::PARAM_SESSION_ID] = $session_id; + } + if ($action) { + $url_params[Request::PARAM_ACTION] = $action; + } + + foreach ($params as $key => $value) { + $url_params[$key] = $value; + } + + $result = Uri::url('/main/glossary/index.php', $url_params, false); + return $result; + } + + /** + * List course descriptions. + * + * @param array messages + */ + public function index() + { + $course = Request::get_course_key(); + $repo = Glossary::repository(); + $items = $repo->find_by_course($course); + + $view = Request::get_view(); + Session::write(Request::PARAM_VIEW, $view); + + $data = (object) array(); + $data->items = $items; + $data->sort = $sort; + $data->view = $view; + $this->render('index', $data); + } + + /** + * Performs the edit action. + */ + public function edit() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $id = Request::get_id(); + $c_id = Request::get_c_id(); + + $repo = Glossary::repository(); + $item = $repo->find_one_by_id($c_id, $id); + + $action = $this->url(self::ACTION_EDIT); + $form = GlossaryForm::create($action, $item); + + if ($form->validate()) { + $success = $repo->save($item); + + $message = $success ? get_lang('GlossaryTermUpdated') : get_lang('Error'); + + $home = $this->url(self::ACTION_DEFAULT); + Redirect::go($home); + } + + $data = (object) array(); + $data->form = $form; + $this->render('edit', $data); + } + + /** + * Perform the add action + */ + public function add() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $c_id = Request::get_c_id(); + $session_id = Request::get_session_id(); + + $item = Glossary::create(); + $item->c_id = $c_id; + $item->session_id = $session_id; + + $action = $this->url(self::ACTION_ADD); + $form = GlossaryForm::create($action, $item); + + if ($form->validate()) { + $repo = Glossary::repository(); + $success = $repo->save($item); + + $message = $success ? get_lang('GlossaryAdded') : get_lang('Error'); + + $home = $this->url(); + Redirect::go($home); + } + + $data = (object) array(); + $data->type = $type; + $data->form = $form; + $this->render('edit', $data); + } + + /** + * Performs the delete action. + * + * @see AjaxController + */ + public function delete() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $this->missing(); + } + + public function export_csv() + { + $course = Request::get_course_key(); + $items = Glossary::repository()->find_by_course($course); + + $writer = CsvWriter::create(); + $writer->add($items); + $path = $writer->get_path(); + + \DocumentManager :: file_send_for_download($path, true, get_lang('Glossary') . '.csv'); + } + + public function import_csv() + { + if (!$this->is_allowed_to_edit()) { + $this->forbidden(); + return; + } + + $action = $this->url(self::ACTION_IMPORT_CSV); + $form = UploadFileForm::create($action); + $form->init(); + if ($form->validate()) { + $delete_all = $form->get_delete_all(); + if ($delete_all) { + $course = Request::get_course_key(); + $repo = Glossary::repository(); + $repo->remove_by_course($course); + } + + $file = $form->get_file(); + $path = $file->tmp_name; + $reader = new CsvReader($path); + $items = $reader->get_items(); + + $course = Request::get_course_key(); + $import = new CourseImport($course); + $import->add($items); + $home = $this->url(self::ACTION_DEFAULT); + Redirect::go($home); + } + + $data = (object) array(); + $data->form = $form; + $this->render('upload', $data); + } + + /** + * Render a template using data. Adds a few common parameters to the data array. + * + * @see /main/template/default/course_description/ + * @param string $template + * @param array $data + */ + protected function render($template, $data) + { + $data = $data ? $data : (object) array(); + + $_user = api_get_user_info(); + $session_id = Request::get_session_id(); + $data->session_image = api_get_session_image($session_id, $_user); + + $data->sec_token = $this->access()->get_token(); + ; + + $data->root = $this->url(''); + + $data->session_id = $session_id; + $data->c_id = Request::get_c_id(); + $data->is_allowed_to_edit = $this->is_allowed_to_edit(); + parent::render("glossary/$template.tpl", $data); + } + +} \ No newline at end of file diff --git a/main/glossary/course_import.class.php b/main/glossary/course_import.class.php new file mode 100644 index 0000000000..cf241f5d4d --- /dev/null +++ b/main/glossary/course_import.class.php @@ -0,0 +1,85 @@ +c_id = xxx; + * $course->session_id = xxx; + * $import = new CourseImport($course); + * + * //create glossary entry + * $glossary_entry = (object)array(); + * $glossary_entry->name = 'xxx'; + * $glossary_entry->description = 'xxx'; + * + * //import glossary entry + * $import->add($glossary_entry); + * + * @license /licence.txt + * @author Laurent Opprecht + */ +class CourseImport +{ + + protected $course = false; + protected $update_existing_entries = false; + protected $objects_imported = 0; + protected $objects_skipped = 0; + + public function __construct($course) + { + $this->course = $course; + } + + public function get_course() + { + return $this->course; + } + + public function get_objects_imported() + { + return $this->objects_imported; + } + + public function get_objects_skipped() + { + return $this->objects_skipped; + } + + /** + * + * @param array $items + */ + public function add($items) + { + $this->objects_imported = 0; + $this->objects_skipped = 0; + + foreach ($items as $item) { + $name = $item->name; + $description = $item->description; + + if (empty($name) || empty($description)) { + $this->objects_skipped++; + continue; + } + + $item->c_id = $this->course->c_id; + $item->session_id = $this->course->session_id; + $repo = Glossary::repository(); + $success = $repo->save($item); + if ($success) { + $this->objects_imported++; + } else { + $this->objects_skipped++; + } + } + } + +} \ No newline at end of file diff --git a/main/glossary/csv_reader.class.php b/main/glossary/csv_reader.class.php new file mode 100644 index 0000000000..a62080f08c --- /dev/null +++ b/main/glossary/csv_reader.class.php @@ -0,0 +1,100 @@ + + */ +class CsvReader implements \Iterator +{ + + protected $path; + protected $items = null; + protected $index = 0; + + public function __construct($path) + { + $this->path = $path; + } + + public function get_path() + { + return $this->path; + } + + public function get_items() + { + if (is_null($this->items)) { + $this->items = $this->read(); + } + return $this->items; + } + + /** + * Read file and returns an array filled up with its' content. + * + * @return array of objects + */ + protected function read() + { + $result = array(); + + $path = $this->path; + if (!is_readable($path)) { + return array(); + } + + $items = \Import::csv_reader($path); + foreach ($items as $item) { + $item = (object) $item; + $name = isset($item->name) ? trim($item->name) : ''; + $description = isset($item->description) ? trim($item->description) : ''; + + $name = \Security::remove_XSS($name); + $description = \Security::remove_XSS($description); + + $is_blank_line = empty($name) && empty($description); + if ($is_blank_line) { + continue; + } + + $item = new Glossary(); + $item->name = $name; + $item->description = $description; + + $result[] = $item; + } + return $result; + } + + public function current() + { + $items = $this->get_items(); + return isset($items[$this->index]) ? $items[$this->index] : null; + } + + public function key() + { + return $this->index; + } + + public function next() + { + $this->index++; + } + + public function rewind() + { + $this->index = 0; + } + + public function valid() + { + $items = $this->get_items(); + return count($items) > $this->index; + } + +} \ No newline at end of file diff --git a/main/glossary/csv_writer.class.php b/main/glossary/csv_writer.class.php new file mode 100644 index 0000000000..dcd2cbdd29 --- /dev/null +++ b/main/glossary/csv_writer.class.php @@ -0,0 +1,46 @@ + + */ +class CsvWriter extends \CsvObjectWriter +{ + + /** + * + * @return \Glossary\CsvWriter + */ + public static function create($path = '', $delimiter = ';', $enclosure = '"') + { + return new self($path, $delimiter, $enclosure); + } + + protected $path = ''; + + function __construct($path = '', $delimiter = ';', $enclosure = '"') + { + $path = $path ? $path : Chamilo::temp_file(); + $this->path = $path; + $stream = new \FileWriter($path); + $map = array( + 'name' => 'name', + 'description' => 'description' + ); + parent::__construct($stream, $map, $delimiter, $enclosure); + } + + function get_path() + { + return $this->path; + } + + + +} \ No newline at end of file diff --git a/main/glossary/glossary.class.php b/main/glossary/glossary.class.php new file mode 100644 index 0000000000..c29e61c2a9 --- /dev/null +++ b/main/glossary/glossary.class.php @@ -0,0 +1,212 @@ +c_id = $value; + return $this; + } + + /** + * The course id + * + * @return integer + */ + public function get_c_id() + { + return $this->c_id; + } + + /** + * Set glossary entry id + * + * @param integer $value + * @return Glossary + */ + public function set_glossary_id($value) + { + $this->glossary_id = $value; + return $this; + } + + /** + * Get glossary_id + * + * @return integer + */ + public function get_glossary_id() + { + return $this->glossary_id; + } + + /** + * Alias for glossary id. Better to use the same naming convention + * for all classes. + * + * @return integer + */ + public function get_id() + { + return $this->glossary_id; + } + + /** + * Set glossary_id + * + * @param integer $value + * @return Glossary + */ + public function set_id($value) + { + $this->glossary_id = $value; + return $this; + } + + /** + * Set name + * + * @param string $value + * @return Glossary + */ + public function set_name($value) + { + $this->name = $value; + return $this; + } + + /** + * The name/title of the glossary entry + * + * @return string + */ + public function get_name() + { + return $this->name; + } + + /** + * Set description + * + * @param text $value + * @return Glossary + */ + public function set_description($value) + { + $this->description = $value; + return $this; + } + + /** + * The description/definition of the glossary entry + * + * @return text + */ + public function get_description() + { + return $this->description; + } + + /** + * Set display_order + * + * @param integer $value + * @return Glossary + */ + public function set_display_order($value) + { + $this->display_order = $value; + return $this; + } + + /** + * The display order. Not used. + * + * @return integer + */ + public function get_display_order() + { + return $this->display_order; + } + + /** + * Set session_id + * + * @param integer $value + * @return Glossary + */ + public function set_session_id($value) + { + $this->session_id = $value; + return $this; + } + + /** + * The session id. + * + * @return integer + */ + public function get_session_id() + { + return $this->session_id; + } +} \ No newline at end of file diff --git a/main/glossary/glossary_form.class.php b/main/glossary/glossary_form.class.php new file mode 100644 index 0000000000..d14ea03775 --- /dev/null +++ b/main/glossary/glossary_form.class.php @@ -0,0 +1,96 @@ + + */ +class GlossaryForm extends \FormValidator +{ + + /** + * + * @param string $action + * @param \Glossary\Glossary $item + * @return \Glossary\GlossaryForm + */ + static function create($action, $item = null) + { + $result = new self('glossary', 'post', $action); + if ($item) { + $result->init($item); + } + return $result; + } + + protected $glossary; + + function __construct($form_name = 'glossary', $method = 'post', $action = '', $target = '', $attributes = null, $track_submit = true) + { + parent::__construct($form_name, $method, $action, $target, $attributes, $track_submit); + } + + /** + * + * @return \Glossary\Glossary + */ + public function get_glossary() + { + return $this->glossary; + } + + public function set_glossary($value) + { + $this->glossary = $value; + } + + /** + * + * @param \Glossary\Glossary $glossary + */ + function init($glossary = null) + { + $this->set_glossary($glossary); + + $defaults = array(); + $defaults['name'] = $glossary->name; + $defaults['description'] = $glossary->description; + + $this->add_hidden('c_id', $glossary->c_id); + $this->add_hidden('id', $glossary->id); + $this->add_hidden('session_id', $glossary->session_id); + $this->add_hidden(Request::PARAM_SEC_TOKEN, Access::instance()->get_token()); + + $form_name = $glossary->id ? get_lang('TermEdit') : get_lang('TermAddNew'); + $this->add_header($form_name); + + $this->add_textfield('name', get_lang('TermName'), $required = true, array('class' => 'span3')); + $this->add_html_editor('description', get_lang('TermDefinition'), true, array('ToolbarSet' => 'Glossary', 'Width' => '90%', 'Height' => '300')); + $this->add_button('save', get_lang('Save'), array('class' => 'btn save')); + + $this->setDefaults($defaults); + } + + function update_model() + { + $values = $this->exportValues(); + $glossary = $this->get_glossary(); + $glossary->name = $values['name']; + $glossary->description = $values['description']; + } + + function validate() + { + $result = parent::validate(); + if ($result) { + $this->update_model(); + } + return $result; + } + +} \ No newline at end of file diff --git a/main/glossary/glossary_repository.class.php b/main/glossary/glossary_repository.class.php new file mode 100644 index 0000000000..a89ade4dd7 --- /dev/null +++ b/main/glossary/glossary_repository.class.php @@ -0,0 +1,327 @@ + for the University of Geneva + * @licence /license.txt + */ +class GlossaryRepository +{ + + /** + * Return the instance of the repository. + * + * @return \Glossary\GlossaryRepository + */ + public static function instance() + { + static $result = null; + if (empty($result)) { + $result = new self(); + } + return $result; + } + + /** + * + * + * @param string $where Where filter to apply + * @return array + */ + public function find($where, $orderby = '', $limit = null) + { + $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY); + $table = Database::get_course_table(TABLE_GLOSSARY); + $tool = TOOL_GLOSSARY; + + $sql = "SELECT g.*, + prop.id AS property_id, + prop.tool, + prop.insert_user_id, + prop.insert_date, + prop.lastedit_date, + prop.ref, + prop.lastedit_type, + prop.lastedit_user_id, + prop.to_group_id, + prop.to_user_id, + prop.visibility, + prop.start_visible, + prop.end_visible, + prop.id_session + FROM + $table AS g, + $table_item_property AS prop + WHERE + (g.glossary_id = prop.ref AND + g.c_id = prop.c_id AND + prop.tool = '$tool')"; + + $sql .= $where ? "AND ($where)" : ''; + $sql .= ' ORDER BY '; + $sql .= $orderby ? $orderby : 'name ASC'; + if($count){ + $from = (int)$limit->from; + $count = (int)$limit->count; + $sql .= " LIMIT $from, $count"; + } + + $rs = Database :: query($sql); + while ($data = Database::fetch_object($rs)) { + $result[] = Glossary::create($data); + } + return $result; + } + + public function count($where) + { + $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY); + $table = Database::get_course_table(TABLE_GLOSSARY); + $tool = TOOL_GLOSSARY; + + $sql = "SELECT count(*) AS val + FROM + $table AS g, + $table_item_property AS prop + WHERE + (g.glossary_id = prop.ref AND + g.c_id = prop.c_id AND + prop.tool = '$tool')"; + + $sql .= $where ? "AND ($where)" : ''; + $sql .= " ORDER BY name ASC"; + + $rs = Database :: query($sql); + while ($data = Database::fetch_object($rs)) { + return $data->val; + } + return 0; + } + + /** + * + * @param string $where + * @return \Glossary\Glossary + */ + public function find_one($where) + { + $items = $this->find($where); + foreach ($items as $item) { + return $item; + } + return null; + } + + /** + * Retrieve one course description from its ids. + * + * @param int|Course $c_id + * @param int $id + * @return \Glossary\Glossary + */ + public function find_one_by_id($c_id, $id) + { + $c_id = is_object($c_id) ? $c_id->get_id() : (int) $c_id; + return $this->find_one("g.c_id = $c_id AND g.glossary_id = $id"); + } + + /** + * Retrieve one course description from its ids. + * + * @param int|Course $c_id + * @param string name + * @return \Glossary\Glossary + */ + public function find_one_by_course_and_name($c_id, $name) + { + $c_id = is_object($c_id) ? $c_id->get_id() : (int) $c_id; + $name = Database::escape_string($name); + return $this->find_one("g.c_id = $c_id AND g.name = '$name'"); + } + + /** + * Returns the list of course descriptions belonging to a specific course and + * session. + * + * @param object $course + * @return Array + */ + public function find_by_course($course, $orderby = '', $limit = null) + { + $c_id = (int)$course->c_id; + $session_id = isset($course->session_id) ? (int)$course->session_id : 0; + if (empty($c_id)) { + return array(); + } + $condition_session = api_get_session_condition($session_id, true, true); + $where = "g.c_id = $c_id $condition_session"; + return $this->find($where, $orderby, $limit); + } + + public function count_by_course($course) + { + $c_id = (int)$course->c_id; + $session_id = isset($course->session_id) ? (int)$course->session_id : 0; + if (empty($c_id)) { + return 0; + } + $condition_session = api_get_session_condition($session_id, true, true); + $where = "g.c_id = $c_id $condition_session"; + return $this->count($where); + } + + /** + * + * @param object $glossary + * @return bool + */ + public function save($glossary) + { + $id = $glossary->id; + if (empty($id)) { + return $this->insert($glossary); + } else { + return $this->update($glossary); + } + } + + + function next_display_order($c_id) + { + $table = Database :: get_course_table(TABLE_GLOSSARY); + $sql = "SELECT MAX(display_order) FROM $table WHERE c_id = $c_id "; + $rs = Database :: query($sql); + list ($result) = Database :: fetch_row($rs); + $result = intval($result) + 1; + return $result; + } + + /** + * + * @param \Glossary\Glossary $glossary + * @return bool + */ + public function insert($glossary) + { + $c_id = (int) $glossary->c_id; + + $name = trim($glossary->name); + $name = Database::escape_string($name); + + $description = trim($glossary->description); + $description = Database::escape_string($description); + + $session_id = (int) $glossary->session_id; + $session_id = $session_id ? $session_id : '0'; + + $display_order = $this->next_display_order($c_id); + + $table = Database :: get_course_table(TABLE_GLOSSARY); + $sql = "INSERT INTO $table + (c_id, name, description, display_order, session_id) + VALUES + ($c_id , '$name', '$description', $display_order, $session_id)"; + $result = (bool) Database :: query($sql); + + if ($result) { + $id = Database::insert_id(); + $glossary->id = $id; + + $_course = api_get_course_info_by_id($c_id); + $tool = TOOL_GLOSSARY; + $user_id = api_get_user_id(); + api_item_property_update($_course, $tool, $id, 'GlossaryAdded', $user_id); + } + return $result; + } + + /** + * + * @param \Glossary\Glossary $glossary + * @return bool + */ + function update($glossary) + { + $c_id = (int) $glossary->c_id; + $id = (int) $glossary->id; + + $name = trim($glossary->name); + $name = Database::escape_string($name); + + $description = trim($glossary->description); + $description = Database::escape_string($description); + + $session_id = (int) $glossary->session_id; + $session_id = $session_id ? $session_id : '0'; + + $display_order = (int) $glossary->display_order; + + $table = Database :: get_course_table(TABLE_GLOSSARY); + $sql = "UPDATE $table SET + name = '$name', + description = '$description', + display_order = $display_order, + session_id = $session_id + WHERE + c_id = $c_id AND + glossary_id = $id"; + $result = (bool) Database :: query($sql); + + if ($result) { + $_course = api_get_course_info_by_id($c_id); + $tool = TOOL_GLOSSARY; + $user_id = api_get_user_id(); + api_item_property_update($_course, $tool, $id, 'GlossaryUpdated', $user_id); + } + return $result; + } + + /** + * + * @param object $glossary + * @return boolean + */ + public function remove($glossary) + { + $table = Database :: get_course_table(TABLE_GLOSSARY); + $c_id = (int) $glossary->c_id; + $id = (int) $glossary->id; + + if (empty($c_id) || empty($id)) { + return false; + } + + $sql = "DELETE FROM $table WHERE c_id=$c_id AND glossary_id=$id"; + $result = Database :: query($sql); + if ($result) { + $tool = TOOL_GLOSSARY; + $tbl_property = Database :: get_course_table(TABLE_ITEM_PROPERTY); + $sql = "DELETE FROM $tbl_property WHERE c_id=$c_id AND ref=$id AND tool='$tool'"; + Database :: query($sql); + } + return (bool) $result; + } + + /** + * + * @param object $course + * @return int + */ + public function remove_by_course($course) + { + $items = $this->find_by_course($course); + foreach ($items as $item) { + $success = $this->remove($item); + if ($success) { + $result++; + } + } + return $result; + } + +} \ No newline at end of file diff --git a/main/glossary/request.class.php b/main/glossary/request.class.php new file mode 100644 index 0000000000..181cc75ce7 --- /dev/null +++ b/main/glossary/request.class.php @@ -0,0 +1,172 @@ + for the Univesity of Genevas + * @license /license.txt + */ +class Request extends \Request +{ + + const PARAM_ID = 'id'; + const PARAM_IDS = 'ids'; + const PARAM_C_ID = 'c_id'; + const PARAM_SESSION_ID = 'id_session'; + const PARAM_ACTION = 'action'; + const PARAM_SEC_TOKEN = 'sec_token'; + const PARAM_IS_STUDENT_VIEW = 'isStudentView'; + const PARAM_SORT_COLUMN = 'sort_column'; + const PARAM_SORT_DIRECTION = 'sort_direction'; + const PARAM_PAGE = 'page'; + const PARAM_VIEW = 'view'; + + /** + * Action to perform. * + * @return string + */ + public static function get_action() + { + $result = Request::get(self::PARAM_ACTION, ''); + return $result; + } + + /** + * Returns the object id. + * + * @return int + */ + public static function get_id() + { + $result = \Request::get(self::PARAM_ID, 0); + $result = intval($result); + return $result; + } + + /** + * List of objet ids + * + * @return array + */ + public static function get_ids() + { + $result = Request::get(self::PARAM_IDS, array()); + if (is_array($result)) { + return $result; + } + + $result = trim($result); + if (empty($result)) { + return array(); + } + + $result = explode(',', $result); + return $result; + } + + /** + * Returns the course id. + * + * @return int + */ + public static function get_c_id() + { + $result = Request::get(self::PARAM_C_ID, 0); + $result = intval($result); + $result = $result ? $result : api_get_real_course_id(); + $result = $result ? $result : 0; + return $result; + } + + /** + * Returns the session id. + * + * @return int + */ + public static function get_session_id() + { + $result = Request::get(self::PARAM_SESSION_ID, 0); + $result = intval($result); + return $result; + } + + /** + * Returns the security token. + * + * @return string + */ + public static function get_security_token() + { + $result = Request::get(self::PARAM_SEC_TOKEN, 0); + return $result; + } + + /** + * Returns true if the user is in "student view". False otherwise. + * + * @return bool + */ + public static function is_student_view() + { + return Request::get(self::PARAM_IS_STUDENT_VIEW, false) == 'true'; + } + + /** + * Returns a course key parameters. I.e. not a real course but an + * object with the course c_id and session set up. + * + * @return object + */ + public static function get_course_key() + { + $result = (object) array(); + $result->c_id = Request::get_c_id(); + $result->session_id = Request::get_session_id(); + return $result; + } + + /** + * Returns an item key. I.e. not a real entity object but an + * object with the object keys set up. + * + * @return object + */ + public static function get_item_key() + { + $result = (object) array(); + $result->c_id = Request::get_c_id(); + $result->id = Request::get_id(); + return $result; + } + + public static function get_sort_column() + { + $result = Request::get(self::PARAM_SORT_COLUMN, 'name'); + $result = ($result == 'description') ? 'description' : 'name'; + return $result; + } + + public static function get_sort_direction(){ + $result = Request::get(self::PARAM_SORT_DIRECTION, 'name'); + $result = strtoupper($result); + $result = ($result == 'DESC') ? 'DESC' : 'ASC'; + return $result; + } + + public static function get_page(){ + $result = Request::get(self::PARAM_PAGE, 0); + return (int)$result; + } + + public static function get_view(){ + $result = Request::get(self::PARAM_VIEW); + $result = $result ? $result : Session::read(self::PARAM_VIEW, 'list'); + $result = ($result == 'table') ? 'table' : 'list'; + return $result; + } + +} \ No newline at end of file diff --git a/main/glossary/resources/js/jquery.dataTables.js b/main/glossary/resources/js/jquery.dataTables.js new file mode 100644 index 0000000000..ae5d1750d9 --- /dev/null +++ b/main/glossary/resources/js/jquery.dataTables.js @@ -0,0 +1,11863 @@ +/** + * @summary DataTables + * @description Paginate, search and sort HTML tables + * @version 1.9.2 + * @file jquery.dataTables.js + * @author Allan Jardine (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * + * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: http://www.datatables.net + */ + +/*jslint evil: true, undef: true, browser: true */ +/*globals $, jQuery,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros*/ + +(/** @lends */function($, window, document, undefined) { + /** + * DataTables is a plug-in for the jQuery Javascript library. It is a + * highly flexible tool, based upon the foundations of progressive + * enhancement, which will add advanced interaction controls to any + * HTML table. For a full list of features please refer to + * DataTables.net. + * + * Note that the DataTable object is not a global variable but is + * aliased to jQuery.fn.DataTable and jQuery.fn.dataTable through which + * it may be accessed. + * + * @class + * @param {object} [oInit={}] Configuration object for DataTables. Options + * are defined by {@link DataTable.defaults} + * @requires jQuery 1.3+ + * + * @example + * // Basic initialisation + * $(document).ready( function { + * $('#example').dataTable(); + * } ); + * + * @example + * // Initialisation with configuration options - in this case, disable + * // pagination and sorting. + * $(document).ready( function { + * $('#example').dataTable( { + * "bPaginate": false, + * "bSort": false + * } ); + * } ); + */ + var DataTable = function( oInit ) + { + + + /** + * Add a column to the list used for the table with default values + * @param {object} oSettings dataTables settings object + * @param {node} nTh The th element for this column + * @memberof DataTable#oApi + */ + function _fnAddColumn( oSettings, nTh ) + { + var oDefaults = DataTable.defaults.columns; + var iCol = oSettings.aoColumns.length; + var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { + "sSortingClass": oSettings.oClasses.sSortable, + "sSortingClassJUI": oSettings.oClasses.sSortJUI, + "nTh": nTh ? nTh : document.createElement('th'), + "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', + "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], + "mDataProp": oDefaults.mDataProp ? oDefaults.oDefaults : iCol + } ); + oSettings.aoColumns.push( oCol ); + + /* Add a column specific filter */ + if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null ) + { + oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch ); + } + else + { + var oPre = oSettings.aoPreSearchCols[ iCol ]; + + /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */ + if ( oPre.bRegex === undefined ) + { + oPre.bRegex = true; + } + + if ( oPre.bSmart === undefined ) + { + oPre.bSmart = true; + } + + if ( oPre.bCaseInsensitive === undefined ) + { + oPre.bCaseInsensitive = true; + } + } + + /* Use the column options function to initialise classes etc */ + _fnColumnOptions( oSettings, iCol, null ); + } + + + /** + * Apply options for a column + * @param {object} oSettings dataTables settings object + * @param {int} iCol column index to consider + * @param {object} oOptions object with sType, bVisible and bSearchable + * @memberof DataTable#oApi + */ + function _fnColumnOptions( oSettings, iCol, oOptions ) + { + var oCol = oSettings.aoColumns[ iCol ]; + + /* User specified column options */ + if ( oOptions !== undefined && oOptions !== null ) + { + if ( oOptions.sType !== undefined ) + { + oCol.sType = oOptions.sType; + oCol._bAutoType = false; + } + + $.extend( oCol, oOptions ); + _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); + + /* iDataSort to be applied (backwards compatibility), but aDataSort will take + * priority if defined + */ + if ( oOptions.iDataSort !== undefined ) + { + oCol.aDataSort = [ oOptions.iDataSort ]; + } + _fnMap( oCol, oOptions, "aDataSort" ); + } + + /* Cache the data get and set functions for speed */ + oCol.fnGetData = _fnGetObjectDataFn( oCol.mDataProp ); + oCol.fnSetData = _fnSetObjectDataFn( oCol.mDataProp ); + + /* Feature sorting overrides column specific when off */ + if ( !oSettings.oFeatures.bSort ) + { + oCol.bSortable = false; + } + + /* Check that the class assignment is correct for sorting */ + if ( !oCol.bSortable || + ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableNone; + oCol.sSortingClassJUI = ""; + } + else if ( oCol.bSortable || + ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) + { + oCol.sSortingClass = oSettings.oClasses.sSortable; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI; + } + else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableAsc; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed; + } + else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableDesc; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed; + } + } + + + /** + * Adjust the table column widths for new data. Note: you would probably want to + * do a redraw after calling this function! + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAdjustColumnSizing ( oSettings ) + { + /* Not interested in doing column width calculation if autowidth is disabled */ + if ( oSettings.oFeatures.bAutoWidth === false ) + { + return false; + } + + _fnCalculateColumnWidths( oSettings ); + for ( var i=0 , iLen=oSettings.aoColumns.length ; i