const COMPANIES = 'companies';
const SECTORS = 'sectors';
const JOBDESCRIPTION = 'jobdescription';
+ const JOBTERMS = 'jobterms';
const NETWORKS = 'networking';
}
// }}}
+// {{{ class DE_JobTerms
+class DE_JobTerms extends DirEnumeration
+{
+ // {{{ function getAutoComplete
+ public function getAutoComplete($text)
+ {
+ $tokens = JobTerms::tokenize($text.'%');
+ if (count($tokens) == 0) {
+ return PlIteratorUtils::fromArray(array());
+ }
+ $token_join = JobTerms::token_join_query($tokens, 'e');
+ return XDB::iterator('SELECT e.jtid AS id, e.full_name AS field, COUNT(DISTINCT p.pid) AS nb
+ FROM profile_job_term_enum AS e
+ INNER JOIN profile_job_term_relation AS r ON (r.jtid_1 = e.jtid)
+ INNER JOIN profile_job_term AS p ON (r.jtid_2 = p.jtid)
+ '.$token_join.'
+ GROUP BY e.jtid
+ ORDER BY nb DESC, field
+ LIMIT ' . self::AUTOCOMPLETE_LIMIT);
+ }
+ // }}}
+}
+// }}}
+
/** NETWORKING
*/
// {{{ class DE_Networking
--- /dev/null
+<?php
+/***************************************************************************
+ * Copyright (C) 2003-2010 Polytechnique.org *
+ * http://opensource.polytechnique.org/ *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+ ***************************************************************************/
+
+class JobTerms {
+
+ const ALL = 'all';
+ const ONLY_JOBS = 'jobs';
+ const ONLY_MENTORS = 'mentors';
+
+ static public function getSubTerms($parent_jtid, $filter = self::ALL) {
+ switch ($filter) {
+ case self::ALL:
+ default:
+ $table = '';
+ break;
+ case self::ONLY_JOBS:
+ $table = 'profile_job_term';
+ break;
+ case self::ONLY_MENTORS:
+ $table = 'profile_mentor_term';
+ break;
+ }
+ if ($table) {
+ $count = ', COUNT(DISTINCT j.pid) AS nb';
+ $join = ' INNER JOIN profile_job_term_relation AS r2 ON (r2.jtid_1 = e.jtid)
+ INNER JOIN '.$table.' AS j ON (j.jtid = r2.jtid_2)';
+ } else {
+ $count = $join = '';
+ }
+ return XDB::iterator('SELECT e.jtid, e.name, e.full_name'.$count.'
+ FROM profile_job_term_enum AS e
+ INNER JOIN profile_job_term_relation AS r ON (r.jtid_2 = e.jtid)'.$join.'
+ WHERE r.jtid_1 = {?} AND r.computed = "original"
+ GROUP BY e.jtid
+ ORDER BY e.name',
+ $parent_jtid);
+ }
+
+ /**
+ * Display a JSon page containing the sub-branches of a branch in the job terms tree.
+ * @param $page the Platal page
+ * @param $filter filter helps to display only jobterms that are contained in jobs or in mentors
+ *
+ * @param Env::i('jtid') job term id of the parent branch, if none trunk will be used
+ * @param Env::v('attrfunc') the name of a javascript function that will be called when a branch
+ * is chosen
+ * @param Env::v('treeid') tree id that will be given as first argument of attrfunc function
+ * the second argument will be the chosen job term id and the third one the chosen job's full name.
+ */
+ static public function ajaxGetBranch(&$page, $filter = self::ALL) {
+ pl_content_headers('application/json');
+ $page->changeTpl('include/jobterms.branch.tpl', NO_SKIN);
+ $subTerms = self::getSubTerms(Env::v('jtid'), $filter);
+ $page->assign('subTerms', $subTerms);
+ switch ($filter) {
+ case self::ONLY_JOBS:
+ $page->assign('filter', 'camarade');
+ break;
+ case self::ONLY_MENTORS:
+ $page->assign('filter', 'mentor');
+ break;
+ }
+ $page->assign('attrfunc', Env::v('attrfunc'));
+ $page->assign('treeid', Env::v('treeid'));
+ }
+
+ static public function jsAddTree($platalpage, $domElement = '.term_tree', $treeid = '', $attrfunc = '') {
+ return '$("'.addslashes($domElement).'").jstree({
+ "core" : {"strings":{"loading":"Chargement ..."}},
+ "plugins" : ["themes","json_data"],
+ "themes" : { "url" : platal_baseurl + "css/jstree.css" },
+ "json_data" : { "ajax" : {
+ "url" : platal_baseurl + "'.addslashes($platalpage).'",
+ "data" : function(nod) {
+ var jtid = 0;
+ if (nod != -1) {
+ jtid = nod.attr("id").replace(/^.*_([0-9]+)$/, "$1");
+ }
+ return { "jtid" : jtid, "treeid" : "'.addslashes($treeid).'", "attrfunc" : "'.addslashes($attrfunc).'" }
+ }
+ }} });';
+ }
+
+ /**
+ * Extract search token from term
+ * @param $term a utf-8 string that can contain any char
+ * @param an array of elementary tokens
+ */
+ static public function tokenize($term)
+ {
+ $term = mb_strtoupper(replace_accent($term));
+ $term = str_replace(array('/', ',', '(', ')', '"', '&', '»', '«'), ' ', $term);
+ $tokens = explode(' ', $term);
+ static $not_tokens = array('ET','AND','DE','DES','DU','D\'','OU','L\'','LA','LE','LES','PAR','AU','AUX','EN','SUR','UN','UNE','IN');
+ foreach ($tokens as &$t) {
+ $t = preg_replace(array('/^-+/','/-+$/'), '', $t);
+ if (substr($t, 1, 1) == '\'' && in_array(substr($t, 0, 2), $not_tokens)) {
+ $t = substr($t, 2);
+ }
+ if (strlen($t) == 1 || in_array($t, $not_tokens)) {
+ $t = false;
+ continue;
+ }
+ }
+ return array_filter($tokens);
+ }
+
+ /**
+ * Create the INNER JOIN query to restrict search to some job terms
+ * @param $tokens an array of the job terms to look for (LIKE comp)
+ * @param $table_alias the alias or name of the table with a jtid field to restrict
+ * @return a partial SQL query
+ */
+ static public function token_join_query(array $tokens, $table_alias) {
+ $joins = '';
+ $i = 0;
+ foreach ($tokens as $t) {
+ ++$i;
+ $joins .= ' INNER JOIN profile_job_term_search AS s'.$i.' ON(s'.$i.'.jtid = '.$table_alias.'.jtid AND s'.$i.'.search LIKE '.XDB::escape($t).')';
+ }
+ return $joins;
+ }
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
const FETCH_MENTOR_SECTOR = 0x000040;
const FETCH_MENTOR_COUNTRY = 0x000080;
const FETCH_PHONES = 0x000100;
+ const FETCH_JOB_TERMS = 0x000200;
+ const FETCH_MENTOR_TERMS = 0x000400;
const FETCH_MINIFICHES = 0x00012D; // FETCH_ADDRESSES | FETCH_EDU | FETCH_JOBS | FETCH_NETWORKING | FETCH_PHONES
- const FETCH_ALL = 0x0001FF; // OR of FETCH_*
+ const FETCH_ALL = 0x0007FF; // OR of FETCH_*
private $fetched_fields = 0x000000;
private function fetched($field)
{
- if (!array_key_exists($field, ProfileField::$fields)) {
- Platal::page()->kill("Invalid field: $field");
+ if (($fields | self::FETCH_ALL) != self::FETCH_ALL) {
+ Platal::page()->kill("Invalid fetched fields: $fields");
}
return ($this->fetched_fields & $field);
*/
private function getProfileField($field)
{
+ if (!array_key_exists($field, ProfileField::$fields)) {
+ Platal::page()->kill("Invalid field: $field");
+ }
if ($this->fetched($field)) {
return null;
} else {
if ($this->addresses != null && $this->jobs != null) {
$this->jobs->addAddresses($this->addresses);
}
+ if ($this->jobs != null && $this->jobterms != null) {
+ $this->jobs->addJobTerms($this->jobterms);
+ }
}
/* Photo
return array_pop($job);
}
+ /** JobTerms
+ */
+ private $jobterms = null;
+ public function setJobTerms(ProfileJobTerms $jobterms)
+ {
+ $this->jobterms = $jobterms;
+ $this->consolidateFields();
+ }
+
/* Mentoring
*/
private $mentor_sectors = null;
}
}
+ /** List of job terms to specify mentoring */
+ private $mentor_terms = null;
+ /**
+ * set job terms to specify mentoring
+ * @param $terms a ProfileMentoringTerms object listing terms only for this profile
+ */
+ public function setMentoringTerms(ProfileMentoringTerms $terms)
+ {
+ $this->mentor_terms = $terms;
+ }
+ /**
+ * get all job terms that specify mentoring
+ * @return an array of JobTerms objects
+ */
+ public function getMentoringTerms()
+ {
+ if ($this->mentor_terms == null && !$this->fetched(self::FETCH_MENTOR_TERMS)) {
+ $this->setMentoringTerms($this->getProfileField(self::FETCH_MENTOR_TERMS));
+ }
+
+ if ($this->mentor_terms == null) {
+ return array();
+ } else {
+ return $this->mentor_terms->get();
+ }
+ }
+
+
/* Binets
*/
public function getBinets()
private $fields;
private $visibility;
+ const FETCH_ALL = 0x000033F; // FETCH_ADDRESSES | FETCH_CORPS | FETCH_EDU | FETCH_JOBS | FETCH_MEDALS | FETCH_NETWORKING | FETCH_PHONES | FETCH_JOB_TERMS
+
public function __construct(PlIterator $it, array $pids, $fields = 0x0000, ProfileVisibility $visibility = null)
{
require_once 'profilefields.inc.php';
$callbacks[0] = PlIteratorUtils::arrayValueCallback('pid');
$cb = PlIteratorUtils::objectPropertyCallback('pid');
- if ($fields & Profile::FETCH_ADDRESSES) {
- $callbacks[Profile::FETCH_ADDRESSES] = $cb;
- $subits[Profile::FETCH_ADDRESSES] = new ProfileFieldIterator('ProfileAddresses', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_CORPS) {
- $callbacks[Profile::FETCH_CORPS] = $cb;
- $subits[Profile::FETCH_CORPS] = new ProfileFieldIterator('ProfileCorps', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_EDU) {
- $callbacks[Profile::FETCH_EDU] = $cb;
- $subits[Profile::FETCH_EDU] = new ProfileFieldIterator('ProfileEducation', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_JOBS) {
- $callbacks[Profile::FETCH_JOBS] = $cb;
- $subits[Profile::FETCH_JOBS] = new ProfileFieldIterator('ProfileJobs', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_MEDALS) {
- $callbacks[Profile::FETCH_MEDALS] = $cb;
- $subits[Profile::FETCH_MEDALS] = new ProfileFieldIterator('ProfileMedals', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_NETWORKING) {
- $callbacks[Profile::FETCH_NETWORKING] = $cb;
- $subits[Profile::FETCH_NETWORKING] = new ProfileFieldIterator('ProfileNetworking', $pids, $visibility);
- }
-
- if ($fields & Profile::FETCH_PHONES) {
- $callbacks[Profile::FETCH_PHONES] = $cb;
- $subits[Profile::FETCH_PHONES] = new ProfileFieldIterator('ProfilePhones', $pids, $visibility);
+ $fields = $fields & self::FETCH_ALL;
+ for ($field = 1; $field < $fields; $field *= 2) {
+ if (($fields & $field) ) {
+ $callbacks[$field] = $cb;
+ $subits[$field] = new ProfileFieldIterator($field, $pids, $visibility);
+ }
}
$this->iterator = PlIteratorUtils::parallelIterator($subits, $callbacks, 0);
if ($this->hasData(Profile::FETCH_JOBS, $vals)) {
$pf->setJobs($vals[Profile::FETCH_JOBS]);
}
+ if ($this->hasData(Profile::FETCH_JOB_TERMS, $vals)) {
+ $pf->setJobTerms($vals[Profile::FETCH_JOB_TERMS]);
+ }
if ($this->hasData(Profile::FETCH_CORPS, $vals)) {
$pf->setCorps($vals[Profile::FETCH_CORPS]);
}
// }}}
+// {{{ class UFC_Job_Terms
+/** Filters users based on the job terms they assigned to one of their
+ * jobs.
+ * @param $val The ID of the job term, or an array of such IDs
+ */
+class UFC_Job_Terms implements UserFilterCondition
+{
+ private $val;
+
+ public function __construct($val)
+ {
+ if (!is_array($val)) {
+ $val = array($val);
+ }
+ $this->val = $val;
+ }
+
+ public function buildCondition(PlFilter &$uf)
+ {
+ $sub = $uf->addJobTermsFilter(count($this->val));
+ $conditions = array();
+ foreach ($this->val as $i => $jtid) {
+ $conditions[] = $sub[$i] . ' = ' . XDB::escape($jtid);
+ }
+ return implode(' AND ', $conditions);
+ }
+}
+// }}}
+
// {{{ class UFC_Job_Description
/** Filters users based on their job description
* @param $description The text being searched for
* pjsse => profile_job_subsector_enum
* pjssse => profile_job_subsubsector_enum
* pja => profile_job_alternates
+ * pjt => profile_job_terms
*/
private $with_pj = false;
private $with_pje = false;
private $with_pjsse = false;
private $with_pjssse = false;
private $with_pja = false;
+ private $with_pjt = 0;
public function addJobFilter()
{
}
}
+ /**
+ * Adds a filter on job terms of profile.
+ * @param $nb the number of job terms to use
+ * @return an array of the fields to filter (one for each term).
+ * Code using this function should used returned field as is (contains table and field name).
+ */
+ public function addJobTermsFilter($nb = 1)
+ {
+ $this->with_pjt = $nb;
+ $jobtermstable = array();
+ for ($i = 1; $i <= $nb; ++$i) {
+ $jobtermstable[] = 'pjtr_'.$i.'.jtid_1';
+ }
+ return $jobtermstable;
+ }
+
protected function jobJoins()
{
$joins = array();
if ($this->with_pja) {
$joins['pja'] = PlSqlJoin::left('profile_job_alternates', '$ME.subsubsectorid = pj.subsubsectorid');
}
+ if ($this->with_pjt > 0) {
+ for ($i = 1; $i <= $this->with_pjt; ++$i) {
+ $joins['pjt_'.$i] = PlSqlJoin::left('profile_job_term', '$ME.pid = $PID');
+ $joins['pjtr_'.$i] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pjt_'.$i.'.jtid');
+ }
+ }
return $joins;
}
font-size: 90%;
}
+div.adresse ul {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ list-style-type: none;
+ padding-left: 0px;
+}
+
#fiche .medal_frame {
float: left;
width: 33%;
--- /dev/null
+/*
+ * jsTree default theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-default li,
+.jstree-default ins { background-image:url("../images/jstree.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-default li { background-position:-90px 0; background-repeat:repeat-y; }
+.jstree-default li.jstree-last { background:transparent; }
+.jstree-default .jstree-open > ins { background-position:-72px 0; }
+.jstree-default .jstree-closed > ins { background-position:-54px 0; }
+.jstree-default .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-default .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; }
+.jstree-default .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; }
+.jstree-default a .jstree-icon { background-position:-56px -19px; }
+.jstree-default a.jstree-loading .jstree-icon { background:url("../images/wait.gif") center center no-repeat !important; }
+
+.jstree-default .jstree-no-dots li,
+.jstree-default .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-default .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-default .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-default .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-default .jstree-search { font-style:italic; }
+
+.jstree-default .jstree-no-icons .jstree-checkbox { display:inline-block; }
+.jstree-default .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
+.jstree-default .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
+.jstree-default .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
+.jstree-default .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
+.jstree-default .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; }
+.jstree-default .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
+.jstree-default .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-default ins { background:transparent !important; }
+#vakata-dragged.jstree-default .jstree-ok { background:url("../images/jstree.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-default .jstree-invalid { background:url("../images/jstree.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-default { background:url("../images/jstree.png") -41px -57px no-repeat !important; }
+
+.jstree-default a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-default-context,
+#vakata-contextmenu.jstree-default-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-default-context li { }
+#vakata-contextmenu.jstree-default-context a { color:black; }
+#vakata-contextmenu.jstree-default-context a:hover,
+#vakata-contextmenu.jstree-default-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-default-context li.jstree-contextmenu-disabled a,
+#vakata-contextmenu.jstree-default-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
+#vakata-contextmenu.jstree-default-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-default-context li ul { margin-left:-4px; }
+
+/* IE6 BEGIN */
+.jstree-default li,
+.jstree-default ins,
+#vakata-dragged.jstree-default .jstree-invalid,
+#vakata-dragged.jstree-default .jstree-ok,
+#jstree-marker.jstree-default { _background-image:url("d.gif"); }
+.jstree-default .jstree-open ins { _background-position:-72px 0; }
+.jstree-default .jstree-closed ins { _background-position:-54px 0; }
+.jstree-default .jstree-leaf ins { _background-position:-36px 0; }
+.jstree-default a ins.jstree-icon { _background-position:-56px -19px; }
+#vakata-contextmenu.jstree-default-context ins { _display:none; }
+#vakata-contextmenu.jstree-default-context li { _zoom:1; }
+.jstree-default .jstree-undetermined a .jstree-checkbox { _background-position:-20px -19px; }
+.jstree-default .jstree-checked a .jstree-checkbox { _background-position:-38px -19px; }
+.jstree-default .jstree-unchecked a .jstree-checkbox { _background-position:-2px -19px; }
+/* IE6 END */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2003-2010 Polytechnique.org *
+ * http://opensource.polytechnique.org/ *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+ ***************************************************************************/
+
+/**
+ * Creates a job terms tree.
+ * @param domElement the jQuery selector string that defines the DOM element
+ * which should contain the tree.
+ * @param platalpage the base page to query for branches
+ * @param treeid an id unique for the tree in this page that will be used in
+ * clickFunc
+ * @param clickFunc name of a javascript function that will be called when a
+ * term is clicked. The three params of this function will be : treeid, the
+ * id of the job term clicked, and the full name of the job term clicked.
+ */
+function createJobTermsTree(domElement, platalpage, treeid, clickFunc)
+{
+ $(domElement).jstree({
+ "core" : {"strings":{"loading":"Chargement ..."}},
+ "plugins" : ["themes","json_data"],
+ "themes" : { "url" : platal_baseurl + "css/jstree.css" },
+ "json_data" : { "ajax" : {
+ "url" : platal_baseurl + platalpage,
+ "data" : function(nod) {
+ var jtid = 0;
+ if (nod != -1) {
+ jtid = nod.attr("id").replace(/^.*_([0-9]+)$/, "$1");
+ }
+ return { "jtid" : jtid, "treeid" : treeid, "attrfunc" : clickFunc }
+ }
+ }} });
+}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+
$('.entreprise_' + id).toggle();
}
+/**
+ * Adds a job term in job profile page
+ * @param jobid id of profile's job among his different jobs
+ * @param jtid id of job term to add
+ * @param full_name full text of job term
+ * @return false if the term already exist for this job, true otherwise
+ */
+function addJobTerm(jobid, jtid, full_name)
+{
+ var termid = 0;
+ var parentpath;
+ var formvarname;
+ if (jobid < 0) {
+ parentpath = '';
+ jobid = '';
+ formvarname = 'terms';
+ } else {
+ parentpath = '#job_'+jobid+' ';
+ formvarname = 'jobs['+jobid+'][terms]';
+ }
+ var lastJobTerm = $(parentpath + '.job_term:last');
+ if (lastJobTerm.length != 0) {
+ termid = parseInt(lastJobTerm.children('input').attr('name').replace(/^(jobs\[[0-9]+\]\[terms\]|terms)\[([0-9]+)\]\[jtid\]/, '$2')) + 1;
+ if ($('#job'+jobid+'_term'+jtid).length > 0) {
+ return false;
+ }
+ }
+ var newdiv = '<div class="job_term" id="job'+jobid+'_term'+jtid+'">'+
+ '<span>'+full_name+'</span>'+
+ '<input type="hidden" name="'+formvarname+'['+termid+'][jtid]" value="'+jtid+'" />'+
+ '<img title="Retirer ce mot-clef" alt="retirer" src="images/icons/cross.gif" />'+
+ '</div>';
+ if (lastJobTerm.length == 0) {
+ $(parentpath + '.job_terms').prepend(newdiv);
+ } else {
+ lastJobTerm.after(newdiv);
+ }
+ $('#job'+jobid+'_term'+jtid+' img').css('cursor','pointer').click(removeJobTerm);
+ return true;
+}
+
+/**
+ * Remove a job term in job profile page.
+ * Must be called from a button in a div containing the term
+ */
+function removeJobTerm()
+{
+ $(this).parent().remove();
+}
+
+/**
+ * Prepare display for autocomplete suggestions in job terms
+ * @param row an array of (title of term, id of term)
+ * @return text to display
+ * If id is negative, it is because there are too much terms to
+ * be displayed.
+ */
+function displayJobTerm(row)
+{
+ if (row[1] < 0) {
+ return '... <em>précise ta recherche</em> ...';
+ }
+ return row[0];
+}
+
+/**
+ * Function called when a job term has been selected from autocompletion
+ * in search
+ * @param li is the list item (<li>) that has been clicked
+ * The context is the jsquery autocomplete object.
+ */
+function selectJobTerm(li)
+{
+ if (li.extra[0] < 0) {
+ return;
+ }
+ var jobid = this.extraParams.jobid;
+ addJobTerm(jobid,li.extra[0],$(li).text());
+ var search_input;
+ if (jobid < 0) {
+ search_input = $('.term_search')[0];
+ } else {
+ search_input = $('#job_'+jobid+' .term_search')[0];
+ }
+ search_input.value = '';
+ search_input.focus();
+}
+
+/**
+ * Function to show or hide a terms tree in job edition
+ * @param jobid is the id of the job currently edited
+ */
+function toggleJobTermsTree(jobid)
+{
+ var treepath;
+ if (jobid < 0) {
+ treepath = '';
+ } else {
+ treepath = '#job_'+jobid+' ';
+ }
+ treepath += '.term_tree';
+ if ($(treepath + ' ul').length > 0) {
+ $(treepath).empty().removeClass().addClass('term_tree');
+ return;
+ }
+ createJobTermsTree(treepath, 'profile/ajax/tree/jobterms/all', 'job' + jobid, 'chooseJobTerm');
+}
+
+/**
+ * Function called when a job term is chosen from terms tree
+ * @param treeid is the full id of the tree (must look like job3)
+ * @param jtid is the id of the job term chosen
+ * @param fullname is the complete name (understandable without context) of the term
+ */
+function chooseJobTerm(treeid, jtid, fullname)
+{
+ addJobTerm(treeid.replace(/^job(.*)$/, '$1'), jtid, fullname);
+}
+
// {{{1 Skills
function addSkill(cat)
+++ /dev/null
-<?php
-/***************************************************************************
- * Copyright (C) 2003-2010 Polytechnique.org *
- * http://opensource.polytechnique.org/ *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program 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 *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- ***************************************************************************/
-
-
-
-function replace_ifset(&$var,$req) {
- if (Env::has($req)){
- $var = Env::v($req);
- }
-}
-
-function replace_ifset_i(&$var,$req,$i) {
- if (isset($_REQUEST[$req][$i])){
- $var[$i] = $_REQUEST[$req][$i];
- }
-}
-
-function replace_ifset_i_j(&$var,$req,$i,$j) {
- if (isset($_REQUEST[$req][$j])){
- $var[$i] = $_REQUEST[$req][$j];
- }
-}
-
-//pour rentrer qqchose dans la base
-function put_in_db($string){
- return trim($string);
-}
-
-// example of use for diff_user_details : get $b from database, $a from other site
-// calculate diff $c and add $c in database (with set_user_details)
-function diff_user_details(&$a, &$b, $view = 'private') { // compute $c = $a - $b
-// if (!isset($b) || !$b || !is_array($b) || count($b) == 0)
-// return $a;
-// if (!isset($a) || !$a || !is_array($a))
-// $c = array();
-// else
- $c = $a;
- foreach ($b as $val => $bvar) {
- if (isset($a[$val])) {
- if ($a[$val] == $bvar)
- unset($c[$val]);
- else {
- switch ($val) {
- case 'adr' : if (!($c['adr'] = diff_user_addresses($a[$val], $bvar, $view))) unset($c['adr']); break;
- case 'adr_pro' : if (!($c['adr_pro'] = diff_user_pros($a[$val], $bvar, $view))) unset($c['adr_pro']); break;
- case 'tels' : if (!($c['tels'] = diff_user_tels($a[$val], $bvar, $view))) unset($c['tels']); break;
- }
- }
- }
- }
- // don't modify freetext if you don't have the right
- if (isset($b['freetext_pub']) && !has_user_right($b['freetext_pub'], $view) && isset($c['freetext']))
- unset($c['freetext']);
- if (!count($c))
- return false;
- return $c;
-}
-
-function same_tel(&$a, &$b) {
- $numbera = format_phone_number((string) $a);
- $numberb = format_phone_number((string) $b);
- return $numbera === $numberb;
-}
-function same_address(&$a, &$b) {
- return
- (same_field($a['adr1'],$b['adr1'])) &&
- (same_field($a['adr2'],$b['adr2'])) &&
- (same_field($a['adr3'],$b['adr3'])) &&
- (same_field($a['postcode'],$b['postcode'])) &&
- (same_field($a['city'],$b['city'])) &&
- (same_field($a['countrytxt'],$b['countrytxt'])) &&
- true;
-}
-function same_pro(&$a, &$b) {
- return
- (same_field($a['entreprise'],$b['entreprise'])) &&
- (same_field($a['fonction'],$b['fonction'])) &&
- true;
-}
-function same_field(&$a, &$b) {
- if ($a == $b) return true;
- if (is_array($a)) {
- if (!is_array($b) || count($a) != count($b)) return false;
- foreach ($a as $val => $avar)
- if (!isset($b[$val]) || !same_field($avar, $b[$val])) return false;
- return true;
- } elseif (is_string($a))
- return (mb_strtoupper($a) == mb_strtoupper($b));
-}
-function diff_user_tel(&$a, &$b) {
- $c = $a;
- if (isset($b['tel_pub']) && isset($a['tel_pub']) && has_user_right($b['tel_pub'], $a['tel_pub']))
- $c['tel_pub'] = $b['tel_pub'];
- foreach ($b as $val => $bvar) {
- if (isset($a[$val])) {
- if ($a[$val] == $bvar)
- unset($c[$val]);
- }
- }
- if (!count($c))
- return false;
- $c['telid'] = $a['telid'];
- return $c;
-}
-
-function diff_user_tels(&$a, &$b)
-{
- $c = $a;
- $telids_b = array();
- foreach ($b as $i => $telb) $telids_b[$telb['telid']] = $i;
-
- foreach ($a as $j => $tela) {
- if (isset($tela['telid'])) {
- // if b has a tel with the same telid, compute diff
- if (isset($telids_b[$tela['telid']])) {
- if (!($c[$j] = diff_user_tel($tela, $b[$telids_b[$tela['adrid']]]))) {
- unset($c[$j]);
- }
- unset($telids_b[$tela['telid']]);
- }
- } else {
- // try to find a match in b
- foreach ($b as $i => $telb) {
- if (same_tel($tela['tel'], $telb['tel'])) {
- $tela['telid'] = $telb['telid'];
- if (!($c[$j] = diff_user_tel($tela, $telb))) {
- unset($c[$j]);
- }
- unset($telids_b[$tela['telid']]);
- break;
- }
- }
- }
- }
-
- foreach ($telids_b as $telidb => $i)
- $c[] = array('telid' => $telidb, 'remove' => 1);
- return $c;
-}
-
-function diff_user_address($a, $b) {
- if (isset($b['pub']) && isset($a['pub']) && has_user_right($b['pub'], $a['pub']))
- $a['pub'] = $b['pub'];
- if (isset($b['tels'])) {
- if (isset($a['tels'])) {
- $avar = $a['tels'];
- } else {
- $avar = array();
- }
- $ctels = diff_user_tels($avar, $b['tels']);
-
- if (!count($ctels)) {
- $b['tels'] = $avar;
- } else {
- $a['tels'] = $ctels;
- }
- }
-
- foreach ($a as $val => $avar) {
- if (!isset($b[$val]) || !same_field($avar,$b[$val])) {
- return $a;
- }
- }
- return false;
-}
-
-// $b need to use adrids
-function diff_user_addresses(&$a, &$b) {
- $c = $a;
- $adrids_b = array();
- foreach ($b as $i => $adrb) $adrids_b[$adrb['adrid']] = $i;
-
- foreach ($a as $j => $adra) {
- if (isset($adra['adrid'])) {
- // if b has an address with the same adrid, compute diff
- if (isset($adrids_b[$adra['adrid']])) {
- if (!($c[$j] = diff_user_address($adra, $b[$adrids_b[$adra['adrid']]])))
- unset($c[$j]);
- unset($adrids_b[$adra['adrid']]);
- }
- } else {
- // try to find a match in b
- foreach ($b as $i => $adrb) {
- if (same_address($adra, $adrb)) {
- $adra['adrid'] = $adrb['adrid'];
- if (!($c[$j] = diff_user_address($adra, $adrb)))
- unset($c[$j]);
- if ($c[$j]) $c[$j]['adrid'] = $adra['adrid'];
- unset($adrids_b[$adra['adrid']]);
- break;
- }
- }
- }
- }
-
- foreach ($adrids_b as $adridb => $i)
- $c[] = array('adrid' => $adridb, 'remove' => 1);
-
- if (!count($c)) return false;
- return $c;
-}
-
-function diff_user_pro($a, &$b, $view = 'private') {
- if (isset($b['pub']) && isset($a['pub']) && has_user_right($b['pub'], $a['pub']))
- $a['pub'] = $b['pub'];
- if (isset($b['adr_pub']) && !has_user_right($b['adr_pub'], $view)) {
- unset($a['adr1']);
- unset($a['adr2']);
- unset($a['adr3']);
- unset($a['postcode']);
- unset($a['city']);
- unset($a['countrytxt']);
- unset($a['region']);
- }
- if (isset($b['adr_pub']) && isset($a['adr_pub']) && has_user_right($b['adr_pub'], $a['adr_pub']))
- $a['adr_pub'] = $b['adr_pub'];
- if (isset($b['tels'])) {
- if (isset($a['tels']))
- $avar = $a['tels'];
- else
- $avar = array();
- $ctels = diff_user_tels($avar, $b['tels']);
-
- if (!count($ctels)) {
- $b['tels'] = $avar;
- } else
- $a['tels'] = $ctels;
- }
- if (isset($b['email_pub']) && !has_user_right($b['email_pub'], $view))
- unset($a['email']);
- if (isset($b['email_pub']) && isset($a['email_pub']) && has_user_right($b['email_pub'], $a['email_pub']))
- $a['email_pub'] = $b['email_pub'];
- foreach ($a as $val => $avar) {
- if (($avar && !isset($b[$val])) || !same_field($avar,$b[$val])) {
- return $a;
- }
- }
- return false;
-}
-
-// $b need to use entrids
-function diff_user_pros(&$a, &$b, $view = 'private') {
- $c = $a;
- $entrids_b = array();
- foreach ($b as $i => $prob) $entrids_b[$prob['entrid']] = $i;
-
- foreach ($a as $j => $proa) {
- if (isset($proa['entrid'])) {
- // if b has an address with the same adrid, compute diff
- if (isset($entrids_b[$proa['entrid']])) {
- if (!($c[$j] = diff_user_pro($proa, $b[$entrids_b[$proa['entrid']]], $view)))
- unset($c[$j]);
- unset($entrids_b[$proa['entrid']]);
- }
- } else {
- // try to find a match in b
- foreach ($b as $i => $prob) {
- if (same_pro($proa, $prob)) {
- $proa['entrid'] = $prob['entrid'];
- if (!($c[$j] = diff_user_pro($proa, $prob, $view)))
- unset($c[$j]);
- if ($c[$j]) $c[$j]['entrid'] = $proa['entrid'];
- unset($entrids_b[$proa['entrid']]);
- break;
- }
- }
- }
- }
-
- foreach ($entrids_b as $entridb => $i)
- $c[] = array('entrid' => $entridb, 'remove' => 1);
-
- if (!count($c)) return false;
- return $c;
-}
-
-function format_phone_number($tel)
-{
- $tel = trim($tel);
- if (substr($tel, 0, 3) === '(0)') {
- $tel = '33' . $tel;
- }
- $tel = preg_replace('/\(0\)/', '', $tel);
- $tel = preg_replace('/[^0-9]/', '', $tel);
- if (substr($tel, 0, 2) === '00') {
- $tel = substr($tel, 2);
- } else if(substr($tel, 0, 1) === '0') {
- $tel = '33' . substr($tel, 1);
- }
- return $tel;
-}
-
-function format_display_number($tel, &$error, $format = array('format'=>'','phoneprf'=>''))
-{
- $error = false;
- $ret = '';
- $tel_length = strlen($tel);
- if((!isset($format['phoneprf'])) || ($format['phoneprf'] == '')) {
- $res = XDB::query("SELECT phonePrefix AS phoneprf, phoneFormat AS format
- FROM geoloc_countries
- WHERE phonePrefix = {?} OR phonePrefix = {?} OR phonePrefix = {?}
- LIMIT 1",
- substr($tel, 0, 1), substr($tel, 0, 2), substr($tel, 0, 3));
- if ($res->numRows() == 0) {
- $error = true;
- return '+' . $tel;
- }
- $format = $res->fetchOneAssoc();
- }
- if ($format['format'] == '') {
- $format['format'] = '+p';
- }
- $j = 0;
- $i = strlen($format['phoneprf']);
- $length_format = strlen($format['format']);
- while (($i < $tel_length) && ($j < $length_format)){
- if ($format['format'][$j] == '#'){
- $ret .= $tel[$i];
- $i++;
- } else if ($format['format'][$j] == 'p') {
- $ret .= $format['phoneprf'];
- } else {
- $ret .= $format['format'][$j];
- }
- $j++;
- }
- for (; $i < $tel_length - 1; $i += 2) {
- $ret .= ' ' . substr($tel, $i, 2);
- }
- //appends last alone number to the last block
- if ($i < $tel_length) {
- $ret .= substr($tel, $i);
- }
- return $ret;
-}
-
-/**
- * Extract search token from term
- * @param $term a utf-8 string that can contain any char
- * @param an array of elementary tokens
- */
-function tokenize_job_term($term)
-{
- $term = mb_strtoupper(replace_accent($term));
- $term = str_replace(array('/', ',', '(', ')', '"', '&', '»', '«'), ' ', $term);
- $tokens = explode(' ', $term);
- static $not_tokens = array('ET','AND','DE','DES','DU','D\'','OU','L\'','LA','LE','LES','PAR','AU','AUX','EN','SUR','UN','UNE','IN');
- foreach ($tokens as &$t) {
- if (substr($t, 1, 1) == '\'' && in_array(substr($t, 0, 2), $not_tokens)) {
- $t = substr($t, 2);
- }
- if (strlen($t) == 1 || in_array($t, $not_tokens)) {
- $t = false;
- continue;
- }
- }
- return array_filter($tokens);
-}
-
-// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
-?>
Profile::FETCH_PHONES => 'ProfilePhones',
Profile::FETCH_MENTOR_SECTOR => 'ProfileMentoringSectors',
Profile::FETCH_MENTOR_COUNTRY => 'ProfileMentoringCountries',
+ Profile::FETCH_JOB_TERMS => 'ProfileJobTerms',
+ Profile::FETCH_MENTOR_TERMS => 'ProfileMentoringTerms',
);
/** The profile to which this field belongs
public function __construct($cls, array $pids, ProfileVisibility $visibility)
{
+ if (is_numeric($cls) && isset(ProfileField::$fields[$cls])) {
+ $cls = ProfileField::$fields[$cls];
+ }
$this->data = call_user_func(array($cls, 'fetchData'), $pids, $visibility);
$this->cls = $cls;
}
public $company = null;
public $phones = array();
public $address = null;
+ public $terms = array();
public $jobid;
$this->address = $address;
}
}
+
+ public function addTerm(JobTerm &$term)
+ {
+ $this->terms[$term->jtid] = $term;
+ }
+}
+// }}}
+// {{{ class JobTerm
+class JobTerm
+{
+ public $jtid;
+ public $full_name;
+ public $pid;
+ public $jid;
+
+ /** Fields are:
+ * pid, jid, jtid, full_name
+ */
+ public function __construct($data)
+ {
+ foreach ($data as $key => $val) {
+ $this->$key = $val;
+ }
+ }
}
// }}}
// {{{ class Address
$this->company = $companies[$job->jobid];
}
}
+
+ public function addJobTerms(ProfileJobTerms $jobterms)
+ {
+ $terms = $jobterms->get();
+ foreach ($terms as $term) {
+ if ($this->pid == $term->pid && array_key_exists($term->jid, $this->jobs)) {
+ $this->jobs[$term->jid]->addTerm(&$term);
+ }
+ }
+ }
}
// }}}
+// {{{ class ProfileJobTerms [ Field ]
+class ProfileJobTerms extends ProfileField
+{
+ private $jobterms = array();
+ public function __construct(PlInnerSubIterator $it)
+ {
+ $this->pid = $it->value();
+ while ($term = $it->next()) {
+ $this->jobterms[] = new JobTerm($term);
+ }
+ }
+
+ public function get()
+ {
+ return $this->jobterms;
+ }
+
+ public static function fetchData(array $pids, ProfileVisibility $visibility)
+ {
+ $data = XDB::iterator('SELECT jt.jtid, jte.full_name, jt.pid, jt.jid
+ FROM profile_job_term AS jt
+ INNER JOIN profile_job AS j ON (jt.pid = j.pid AND jt.jid = j.id)
+ LEFT JOIN profile_job_term_enum AS jte USING(jtid)
+ WHERE jt.pid IN {?} AND j.pub IN {?}
+ ORDER BY ' . XDB::formatCustomOrder('jt.pid', $pids),
+ $pids, $visibility->levels());
+ return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
+ }
+}
+// }}}
+// {{{ class ProfileMentoringTerms [ Field ]
+class ProfileMentoringTerms extends ProfileJobTerms
+{
+ public static function fetchData(array $pids, ProfileVisibility $visibility)
+ {
+ $data = XDB::iterator('SELECT mt.jtid, jte.full_name, mt.pid
+ FROM profile_mentor_term AS mt
+ LEFT JOIN profile_job_term_enum AS jte USING(jtid)
+ WHERE mt.pid IN {?}
+ ORDER BY ' . XDB::formatCustomOrder('mt.pid', $pids),
+ $pids);
+ return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
+ }
+}
+// }}}
// {{{ class CompanyList
class CompanyList
{
new UFBF_JobSector('sector', 'Poste'),
new UFBF_JobDescription('jobdescription', 'Fonction'),
new UFBF_JobCv('cv', 'CV'),
+ new UFBF_JobTerms('jobterm', 'Mots-clefs'),
new UFBF_Nationality('nationaliteTxt', 'nationalite', 'Nationalité'),
new UFBF_Binet('binetTxt', 'binet', 'Binet'),
}
// }}}
+// {{{ class UFBF_JobTerms
+class UFBF_JobTerms extends UFBF_Index
+{
+ protected function buildUFC(UserFilterBuilder &$ufb)
+ {
+ return new UFC_Job_Terms($this->val);
+ }
+}
+// }}}
+
// {{{ class UFBF_JobDescription
class UFBF_JobDescription extends UFBF_Text
{
'profile/ajax/skill' => $this->make_hook('ajax_skill', AUTH_COOKIE, 'user', NO_AUTH),
'profile/ajax/searchname' => $this->make_hook('ajax_searchname', AUTH_COOKIE, 'user', NO_AUTH),
'profile/ajax/buildnames' => $this->make_hook('ajax_buildnames', AUTH_COOKIE, 'user', NO_AUTH),
+ 'profile/ajax/tree/jobterms' => $this->make_hook('ajax_tree_job_terms', AUTH_COOKIE, 'user', NO_AUTH),
+ 'profile/jobterms' => $this->make_hook('jobterms', AUTH_COOKIE, 'user', NO_AUTH),
'javascript/education.js' => $this->make_hook('education_js', AUTH_COOKIE),
'javascript/grades.js' => $this->make_hook('grades_js', AUTH_COOKIE),
'profile/medal' => $this->make_hook('medal', AUTH_PUBLIC),
'referent/search' => $this->make_hook('ref_search', AUTH_COOKIE),
'referent/ssect' => $this->make_hook('ref_sect', AUTH_COOKIE, 'user', NO_AUTH),
'referent/country' => $this->make_hook('ref_country', AUTH_COOKIE, 'user', NO_AUTH),
+ 'referent/autocomplete' => $this->make_hook('ref_autocomplete', AUTH_COOKIE, 'user', NO_AUTH),
'groupes-x' => $this->make_hook('xnet', AUTH_COOKIE),
'groupes-x/logo' => $this->make_hook('xnetlogo', AUTH_PUBLIC),
$page->assign('jobpref', $jobpref);
}
}
-
function handler_ajax_sub_sector(&$page, $id, $ssect, $sssect = -1)
{
pl_content_headers("text/html");
$page->assign('sel', $sssect);
}
+ /**
+ * Page for url "profile/ajax/tree/jobterms". Display a JSon page containing
+ * the sub-branches of a branch in the job terms tree.
+ * @param $page the Platal page
+ * @param $filter filter helps to display only jobterms that are contained in jobs or in mentors
+ *
+ * @param Env::i('jtid') job term id of the parent branch, if none trunk will be used
+ * @param Env::v('attrfunc') the name of a javascript function that will be called when a branch
+ * is chosen
+ * @param Env::v('treeid') tree id that will be given as first argument of attrfunc function
+ * the second argument will be the chosen job term id and the third one the chosen job full name.
+ */
+ function handler_ajax_tree_job_terms(&$page, $filter = JobTerms::ALL)
+ {
+ JobTerms::ajaxGetBranch(&$page, $filter);
+ }
+
function handler_ajax_alternates(&$page, $id, $sssect)
{
pl_content_headers("text/html");
$page->setTitle('Emploi et Carrières');
- // Retrieval of sector names
- $sectors = XDB::fetchAllAssoc('id', 'SELECT pjse.id, pjse.name
- FROM profile_job_sector_enum AS pjse
- INNER JOIN profile_mentor_sector AS pms ON (pms.sectorid = pjse.id)
- GROUP BY pjse.id
- ORDER BY pjse.name');
- $page->assign_by_ref('sectors', $sectors);
-
// nb de mentors
- $res = XDB::query("SELECT count(*) FROM profile_mentor");
+ $res = XDB::query("SELECT count(distinct pid) FROM profile_mentor_term");
$page->assign('mentors_number', $res->fetchOneCell());
+ $page->addJsLink('jquery.autocomplete.js');
+
// On vient d'un formulaire
require_once 'ufbuilder.inc.php';
$ufb = new UFB_MentorSearch();
$page->assign('list', $it);
}
+ /**
+ * Page for url "referent/autocomplete". Display an "autocomplete" page (plain/text with values
+ * separated by "|" chars) for jobterms in referent (mentor) search.
+ * @see handler_jobterms
+ */
+ function handler_ref_autocomplete(&$page)
+ {
+ $this->handler_jobterms(&$page, 'mentor');
+ }
+
+ /**
+ * Page for url "profile/jobterms" (function also used for "referent/autocomplete" @see
+ * handler_ref_autocomplete). Displays an "autocomplete" page (plain text with values
+ * separated by "|" chars) for jobterms to add in profile.
+ * @param $page the Platal page
+ * @param $type set to 'mentor' to display the number of mentors for each term and order
+ * by descending number of mentors.
+ *
+ * @param Env::v('q') the text that has been typed and to complete automatically
+ */
+ function handler_jobterms(&$page, $type = 'nomentor')
+ {
+ pl_content_headers("text/plain");
+
+ $q = Env::v('q').'%';
+ $tokens = JobTerms::tokenize($q);
+ if (count($tokens) == 0) {
+ exit;
+ }
+ sort($tokens);
+ $q_normalized = implode(' ', $tokens);
+
+ // try to look in cached results
+ $cache = XDB::query('SELECT result
+ FROM search_autocomplete
+ WHERE name = {?} AND
+ query = {?} AND
+ generated > NOW() - INTERVAL 1 DAY',
+ $type, $q_normalized);
+ if ($res = $cache->fetchOneCell()) {
+ echo $res;
+ die();
+ }
+
+ $joins = JobTerms::token_join_query($tokens, 'e');
+ if ($type == 'mentor') {
+ $count = ', COUNT(DISTINCT pid) AS nb';
+ $countjoin = ' LEFT JOIN profile_job_term_relation AS r ON(r.jtid_1 = e.jtid) LEFT JOIN profile_mentor_term AS m ON(r.jtid_2 = m.jtid)';
+ $countorder = 'nb DESC, ';
+ } else {
+ $count = $countjoin = $countorder = '';
+ }
+ $list = XDB::iterator('SELECT e.jtid AS id, e.full_name AS field'.$count.'
+ FROM profile_job_term_enum AS e '.$joins.$countjoin.'
+ GROUP BY e.jtid
+ ORDER BY '.$countorder.'field
+ LIMIT 11');
+ $nbResults = 0;
+ $res = '';
+ while ($result = $list->next()) {
+ $nbResults++;
+ if ($nbResults == 11) {
+ $res .= $q."|-1\n";
+ } else {
+ $res .= $result['field'].'|';
+ if ($count) {
+ $res .= $result['nb'].'|';
+ }
+ $res .= $result['id'];
+ }
+ $res .= "\n";
+ }
+ XDB::query('REPLACE INTO search_autocomplete
+ VALUES ({?}, {?}, {?}, NOW())',
+ $type, $q_normalized, $res);
+ echo $res;
+ exit();
+ }
+
function handler_xnet(&$page)
{
$page->changeTpl('profile/groupesx.tpl');
'tel' => '',
'pub' => 'private',
'comment' => '',
- )),
+ ),
+ 'terms' => array()),
);
}
list($job['sector'], $job['subSector'], $job['subSubSector']) = $res->fetchOneRow();
}
}
+ if (count($job['terms'])) {
+ $termsid = array();
+ foreach ($job['terms'] as $term) {
+ if (!$term['full_name']) {
+ $termsid[] = $term['jtid'];
+ }
+ }
+ if (count($termsid)) {
+ $res = XDB::query("SELECT jtid, full_name
+ FROM profile_job_term_enum
+ WHERE jtid IN {?}",
+ $termsid);
+ $term_id_to_name = $res->fetchAllAssoc('jtid', false);
+ foreach ($job['terms'] as &$term) {
+ if (!$term['full_name']) {
+ $term['full_name'] = $term_id_to_name[$term['jtid']];
+ }
+ }
+ }
+ }
if ($job['name']) {
$res = XDB::query("SELECT id
FROM profile_job_enum
WHERE pid = {?} AND type = 'job'",
$page->pid());
Phone::deletePhones($page->pid(), Phone::LINK_JOB);
+ $terms_values = array();
foreach ($value as $id => &$job) {
if (isset($job['name']) && $job['name']) {
if (isset($job['jobid']) && $job['jobid']) {
$address = new ProfileSettingAddress();
$address->saveAddress($page->pid(), $id, $job['w_address'], 'job');
Phone::savePhones($job['w_phone'], $page->pid(), Phone::LINK_JOB, $id);
+ if (isset($job['terms'])) {
+ foreach ($job['terms'] as $term) {
+ $terms_values[] = '('.XDB::escape($page->pid()).', '. XDB::escape($id).', '.XDB::escape($term['jtid']).', "original")';
+ }
+ }
}
}
+ if (count($terms_values) > 0) {
+ XDB::execute('INSERT INTO profile_job_term (pid, jid, jtid, computed)
+ VALUES '.implode(', ', $terms_values));
+ }
}
public function getText($value) {
while ($phone = $it->next()) {
$this->values['jobs'][$phone->linkId()]['w_phone'][$phone->id()] = $phone->toFormArray();
}
+ $res = XDB::iterator("SELECT e.jtid, e.full_name, j.jid AS jobid
+ FROM profile_job_term_enum AS e
+ INNER JOIN profile_job_term AS j USING(jtid)
+ WHERE pid = {?}
+ ORDER BY j.jid",
+ $this->pid());
+ $i = 0;
+ $jobNb = count($this->values['jobs']);
+ while ($term = $res->next()) {
+ $jobid = $term['jobid'];
+ while ($i < $jobNb && $this->values['jobs'][$i]['id'] < $jobid) {
+ $i++;
+ }
+ if ($i >= $jobNb) {
+ break;
+ }
+ $job =& $this->values['jobs'][$i];
+ if ($job['id'] != $jobid) {
+ continue;
+ }
+ if (!isset($job['terms'])) {
+ $job['terms'] = array();
+ }
+ $job['terms'][] = $term;
+ }
+
foreach ($this->values['jobs'] as $id => &$job) {
$phone = new Phone();
if (!isset($job['w_phone'])) {
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
***************************************************************************/
-class ProfileSettingSectors implements ProfileSetting
+/** Terms associated to profile mentoring */
+class ProfileSettingTerms implements ProfileSetting
{
public function value(ProfilePage &$page, $field, $value, &$success)
{
$success = true;
if (is_null($value)) {
$value = array();
- $res = XDB::iterRow("SELECT m.sectorid, m.subsectorid, ss.name
- FROM profile_mentor_sector AS m
- INNER JOIN profile_job_sector_enum AS s ON (m.sectorid = s.id)
- INNER JOIN profile_job_subsector_enum AS ss ON (s.id = ss.sectorid AND m.subsectorid = ss.id)
- WHERE m.pid = {?}",
+ $res = XDB::query('SELECT e.jtid, e.full_name
+ FROM profile_mentor_term AS m
+ INNER JOIN profile_job_term_enum AS e ON (m.jtid = e.jtid)
+ WHERE m.pid = {?}',
$page->pid());
- while (list($s, $ss, $ssname) = $res->next()) {
- if (!isset($value[$s])) {
- $value[$s] = array($ss => $ssname);
- } else {
- $value[$s][$ss] = $ssname;
- }
- }
+ $value = $res->fetchAllAssoc();
} elseif (!is_array($value)) {
$value = array();
- } elseif (count($value) > 10) {
- Platal::page()->trigError("Le nombre de secteurs d'expertise est limité à 10.");
+ } elseif (count($value) > 20) {
+ Platal::page()->trigError("Le nombre de mots clefs d'expertise est limité à 20.");
$success = false;
+ } else {
+ $missing_full_names = array();
+ foreach ($value as &$term) if (empty($term['full_name'])) {
+ $missing_full_names[] = $term['jtid'];
+ }
+ if (count($missing_full_names)) {
+ $res = XDB::query('SELECT jtid, full_name
+ FROM profile_job_term_enum
+ WHERE jtid IN {?}',
+ $missing_full_names);
+ $term_id_to_name = $res->fetchAllAssoc('jtid', false);
+ foreach ($value as &$term) {
+ if (empty($term['full_name'])) {
+ $term['full_name'] = $term_id_to_name[$term['jtid']];
+ }
+ }
+ }
}
ksort($value);
foreach ($value as &$sss) {
public function save(ProfilePage &$page, $field, $value)
{
- XDB::execute("DELETE FROM profile_mentor_sector
+ XDB::execute("DELETE FROM profile_mentor_term
WHERE pid = {?}",
$page->pid());
if (!count($value)) {
return;
}
- foreach ($value as $id => $sect) {
- foreach ($sect as $sid => $name) {
- XDB::execute("INSERT INTO profile_mentor_sector (pid, sectorid, subsectorid)
- VALUES ({?}, {?}, {?})",
- $page->pid(), $id, $sid);
- }
+ $mentor_term_values = array();
+ foreach ($value as &$term) {
+ $mentor_term_values[] = '('.XDB::escape($page->pid()).', '.XDB::escape($term['jtid']).')';
}
+ XDB::execute('INSERT INTO profile_mentor_term (pid, jtid)
+ VALUES '.implode(',', $mentor_term_values));
+
}
public function getText($value) {
- $sectors = array();
- foreach ($value as $sector) {
- foreach ($sector as $subsector) {
- $sectors[] = $subsector;
- }
+ $terms = array();
+ foreach ($value as &$term) {
+ $terms[] = $term['full_name'];
}
- return implode(', ', $sectors);
+ return implode(', ', $terms);
}
}
{
parent::__construct($wiz);
$this->settings['expertise'] = null;
- $this->settings['sectors'] = new ProfileSettingSectors();
+ $this->settings['terms'] = new ProfileSettingTerms();
$this->settings['countries'] = new ProfileSettingCountry();
}
public function _prepare(PlPage &$page, $id)
{
- $page->assign('sectorList', XDB::iterator('SELECT id, name
- FROM profile_job_sector_enum'));
-
$page->assign('countryList', XDB::iterator("SELECT iso_3166_1_a2, countryFR
FROM geoloc_countries
ORDER BY countryFR"));
'city' => DirEnum::LOCALITIES,
'countryTxt' => DirEnum::COUNTRIES,
'entreprise' => DirEnum::COMPANIES,
- 'secteurTxt' => DirEnum::SECTORS,
+ 'jobtermTxt' => DirEnum::JOBTERMS,
'description' => DirEnum::JOBDESCRIPTION,
'nationaliteTxt' => DirEnum::NATIONALITIES,
'schoolTxt' => DirEnum::EDUSCHOOLS,
case 'secteur':
$ids = DirEnum::getOptionsIter(DirEnum::SECTORS);
break;
+ case 'jobterm':
+ if (Env::has('jtid')) {
+ JobTerms::ajaxGetBranch(&$page, JobTerms::ONLY_JOBS);
+ return;
+ } else {
+ pl_content_headers('text/xml');
+ echo '<div>'; // global container so that response is valid xml
+ echo '<input name="jobtermTxt" type="text" style="display:none" size="32" />';
+ echo '<input name="jobterm" type="hidden"/>';
+ echo '<div class="term_tree"></div>'; // container where to create the tree
+ echo '<script type="text/javascript" src="javascript/jquery.jstree.js"></script>';
+ echo '<script type="text/javascript" src="javascript/jobtermstree.js"></script>';
+ echo '<script type="text/javascript">createJobTermsTree(".term_tree", "search/list/jobterm", "search", "searchForJobTerm");</script>';
+ echo '</div>';
+ exit();
+ }
default: exit();
}
if (isset($idVal)) {
{if $job->user_site} [<a href='{$job->user_site}'>Page perso</a>]{/if}</strong></td>
</tr>
{/if}
- {if $job->sector}
+ {if count($job->terms)}
<tr>
- <td><em>Secteur : </em></td>
- <td><strong>{$job->sector}{if $job->subsector} ({$job->subsector}){/if}</strong></td>
+ <td><em>Mots-clefs : </em></td>
+ <td><ul>
+ {foreach from=$job->terms item=term}
+ <li><strong>{$term->full_name}</strong></li>
+ {/foreach}
+ </ul></td>
</tr>
{/if}
--- /dev/null
+{**************************************************************************}
+{* *}
+{* Copyright (C) 2003-2010 Polytechnique.org *}
+{* http://opensource.polytechnique.org/ *}
+{* *}
+{* This program is free software; you can redistribute it and/or modify *}
+{* it under the terms of the GNU General Public License as published by *}
+{* the Free Software Foundation; either version 2 of the License, or *}
+{* (at your option) any later version. *}
+{* *}
+{* This program 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 *}
+{* GNU General Public License for more details. *}
+{* *}
+{* You should have received a copy of the GNU General Public License *}
+{* along with this program; if not, write to the Free Software *}
+{* Foundation, Inc., *}
+{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *}
+{* *}
+{**************************************************************************}
+[
+{iterate from=$subTerms item=term}
+ {if $started},{/if}
+ {assign var=started value=1}
+ {ldelim}
+ "data" :
+ {ldelim}
+ "title" : "{$term.name|replace:'"':'\\"'}{if $filter} ({$term.nb} {$filter}{if $term.nb > 1}s{/if}){/if}",
+ "attr" : {ldelim}
+ {if $attrfunc}"href" : "javascript:{$attrfunc}('{$treeid}','{$term.jtid}',\"{$term.full_name|replace:'"':'\\\\\\"'}\")",{/if}
+ "title" : "{$term.full_name|replace:'"':'\\"'}"
+ {rdelim}
+ {rdelim},
+ "attr" : {ldelim} "id" : "job_terms_tree_{$treeid}_{$term.jtid}" {rdelim},
+ "state": "closed"
+ {rdelim}
+{/iterate}
+]
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
{**************************************************************************}
{javascript name=ajax}
-{assign var=sectors value=$profile->getMentoringSectors()}
+{assign var=terms value=$profile->getMentoringTerms()}
{assign var=countries value=$profile->getMentoringCountries()}
<div id="fiche">
<div id="fiche_referent">
</div>
<div class="spacer"></div>
- {if $profile->expertise != '' || $sectors|count || $countries|count }
+ {if $profile->expertise != '' || $terms|count || $countries|count }
<div id="part">
<h2>Informations de référent :</h2>
{if $profile->expertise}
<span>{$profile->expertise|nl2br}</span>
</div>
{/if}
- {if $sectors|count}
+ {if $terms|count}
<div class="rubrique_referent">
- <em>Secteurs :</em><br />
+ <em>Mots-clefs :</em><br />
<ul>
- {foreach from=$sectors item="sector" key="i"}
- <li>{$sector.sector}{if $sector.subsector != ''} ({$sector.subsector}){/if}</li>
+ {foreach from=$terms item="term"}
+ <li>{$term->full_name}</li>
{/foreach}
</ul>
</div>
{* *}
{**************************************************************************}
+<script type="text/javascript" src="javascript/jquery.jstree.js"></script>
{assign var=jobid value="job_"|cat:$i}
{assign var=jobpref value="jobs[`$i`]"}
{assign var=sector_text value="sector_text_"|cat:$i}
<td colspan="2" class="center" style="font-style: italic">Ta place dans l'entreprise</td>
</tr>
<tr class="pair {$sector_text}">
- <td class="titre">Secteur d'activité</td>
- <td>
- <input type="text" class="sectorName {if $job.sector_error}error{/if}" size="35" maxlength="100"
- name="{$jobpref}[subSubSectorName]" value="{$job.subSubSectorName}" />
- <a href="javascript:displayAllSector({$i})">{icon name="table" title="Tous les secteurs"}</a>
+ <td class="titre">Mots-clefs</td>
+ <td class="job_terms">
+ <input type="text" class="term_search" size="35"/>
+ <a href="javascript:toggleJobTermsTree({$i})">{icon name="table" title="Tous les mots-clefs"}</a>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ $(function() {ldelim}
+ {foreach from=$job.terms item=term}
+ addJobTerm("{$i}", "{$term.jtid}", "{$term.full_name|replace:'"':'\\"'}");
+ {/foreach}
+ $('#job_{$i} .term_search').autocomplete(platal_baseurl + 'profile/jobterms',
+ {ldelim}
+ "formatItem" : displayJobTerm,
+ "extraParams" : {ldelim} "jobid" : "{$i}" {rdelim},
+ "width" : $('#job_{$i} .term_search').width()*2,
+ "onItemSelect" : selectJobTerm,
+ "matchSubset" : false
+ {rdelim});
+ {rdelim});
+ /* ]]> */
+ </script>
+ </td>
+ </tr>
+ <tr class="pair">
+ <td colspan="2" class="term_tree">
</td>
</tr>
<tr class="pair {$sector}" style="display: none">
{* *}
{**************************************************************************}
+{javascript name=jobtermstree}
{foreach from=$jobs item=job key=i}
{include file="profile/jobs.job.tpl" i=$i job=$job new=false}
{/foreach}
{* *}
{**************************************************************************}
+{javascript name=jobtermstree}
+
<div>{icon name=information title="Afficher ma fiche référent"}Tu peux consulter ta <a class="popup2" href="referent/{$hrpid}">fiche référent</a> qui n'est accessible que par les X.
</div>
{if (!$expertise)||(!($sectors|@count))}
</tr>
</table>
+<script type="text/javascript" src="javascript/jquery.jstree.js"></script>
+
<table class="bicol" style="margin-bottom: 1em" summary="Profil : Mentoring">
<tr>
- <th>
+ <th colspan="2">
<div class="flags" style="float: left">
<input type="checkbox" name="accesX" checked="checked" disabled="disabled" />
{icon name="flag_red" value="privé"}
</div>
- Secteurs d'activité dans lesquels tu as beaucoup exercé
+ Mots clefs qui représentent le mieux ton expérience
</th>
</tr>
<tr>
- <td id="sectorSelection">
- <div style="float: left; width: 30%" class="titre">Secteur</div>
- <select name="sectorSelection" onchange="updateSector()">
- <option value=""> </option>
- {iterate from=$sectorList item=sector}
- <option value="{$sector.id}">{$sector.name}</option>
- {/iterate}
- </select>
- </td>
+ <td colspan="2">
+ Il est préférable de mentionner des notions précises : <em>Pizzaïolo</em> plutôt que <em>Hôtellerie</em>.
+ En effet Les recherches sur le mot-clef <em>Hôtellerie</em> te trouveront dans les deux cas mais une
+ recherche sur <em>Production culinaire</em> ou <em>Pizzaïolo</em> non.
+ <td/>
</tr>
<tr>
- <td>
- <div style="float: left; width: 30%" class="titre">Sous-secteur</div>
- <span id="subSectorSelection"></span>
+ <td class="titre" style="width:30%">Mots-clefs</td>
+ <td class="job_terms">
+ <input type="text" class="term_search" size="35"/>
+ <a href="javascript:toggleJobTermsTree(-1)">{icon name="table" title="Tous les mots-clefs"}</a>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ $(function() {ldelim}
+ {foreach from=$terms item=term}
+ addJobTerm(-1, "{$term.jtid}", "{$term.full_name|replace:'"':'\\"'}");
+ {/foreach}
+ $('.term_search').autocomplete(platal_baseurl + 'profile/jobterms',
+ {ldelim}
+ "formatItem" : displayJobTerm,
+ "extraParams" : {ldelim} "jobid" : "-1" {rdelim},
+ "width" : $('.term_search').width()*2,
+ "onItemSelect" : selectJobTerm,
+ "matchSubset" : false
+ {rdelim});
+ {rdelim});
+ /* ]]> */
+ </script>
</td>
</tr>
- <tr class="pair">
- <td id="sectors">
- {if $sectors|@count}
- {foreach from=$sectors item=sector key=s}
- {foreach from=$sector item=subSector key=ss}
- <div id="sectors_{$s}_{$ss}" style="clear: both; margin-top: 0.5em" class="titre">
- <a href="javascript:removeSector('{$s}','{$ss}')" style="display: block; float: right">
- {icon name=cross title="Supprimer ce secteur"}
- </a>
- <input type="hidden" name="sectors[{$s}][{$ss}]" value="{$subSector}" />
- {$subSector}
- </div>
- {/foreach}
- {/foreach}
- {/if}
+ <tr>
+ <td colspan="2" class="term_tree">
</td>
</tr>
</table>
</p>
{javascript name=ajax}
+{javascript name=jquery.jstree}
+{javascript name=jobtermstree}
<script type="text/javascript">//<![CDATA[
var baseurl = platal_baseurl + "referent/";
Ajax2.update_html('country_chg', baseurl + 'country/' + sect + '/' + ssect);
}
+function toggleJobTermsTree()
+{
+ $('#mentoring_terms').closest('tr').toggle();
+ return false;
+}
+
{/literal}
//]]></script>
<table cellpadding="0" cellspacing="0" summary="Formulaire de recherche de referents" class="bicol">
<tr class="impair">
<td class="titre">
- Secteur de compétence<br />du référent
+ Mot-clef :
</td>
<td>
- <select name="sector" id="sect_field" onchange="setSector(this.value)">
- <option name=""></option>
- {html_options options=$sectors selected=$sectorSelection}
- </select>
+ <input type="text" name="jobterm_text" id="term_search" size="32"/>
+ <input type="hidden" name="jobterm" />
+ <a id="jobTermsTreeToggle" href="#">{icon name=table title="Tous les mots-clefs"}</a>
</td>
</tr>
- <tr class="impair" style="display: none" id="scat">
- <td class="titre">
- Sous-secteur
- </td>
- <td id="ssect_chg">
- </td>
- </tr>
- <tr class="pair" style="display: none" id="country">
- <td class="titre">
- Pays bien connu du référent
- </td>
- <td id="country_chg">
- </td>
- </tr>
- <tr class="impair" style="display: none" id="keywords">
- <td class="titre">
- Expertise (rentre un ou plusieurs mots clés)
- </td>
- <td >
- <input type="text" name="expertise" size="30" value="{$expertise_champ}" />
+ <tr class="impair" style="display:none">
+ <td colspan="2">
+ <div id="mentoring_terms"></div>
</td>
</tr>
</table>
</form>
<script type="text/javascript">
-setSector(document.getElementById('sect_field').value);
+{literal}
+$(function() {
+ createJobTermsTree('#mentoring_terms', 'profile/ajax/tree/jobterms/mentors', 'mentor', 'searchForJobTerm');
+ $("#term_search").autocomplete(baseurl + "autocomplete",
+ {
+ "selectOnly":1,
+ "matchSubset":0,
+ "width":$("#term_search").width()
+ });
+ $('#jobTermsTreeToggle').click(toggleJobTermsTree);
+});
+{/literal}
</script>
{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
});
}
+ // when choosing a job term in tree, hide tree and set job term field
+ function searchForJobTerm(treeid, jtid, full_name) {
+ $(".term_tree").remove();
+ $("input[name='jobtermTxt']").val(full_name).addClass("hidden_valid").show();
+ $("input[name='jobterm']").val(jtid);
+ }
+
// when choosing autocomplete from list, must validate
function select_autocomplete(name) {
nameRealField = name.replace(/Txt$/, '');
<td><input type="text" class="autocomplete" name="description" size="32" value="{$smarty.request.description}" /></td>
</tr>
<tr>
- <td>Secteur</td>
+ <td>Mots-clefs</td>
<td>
- <input name="secteurTxt" type="text" class="autocomplete" style="display:none" size="32"
- value="{$smarty.request.secteurTxt}"/>
- <input name="secteur" class="autocompleteTarget" type="hidden" value="{$smarty.request.secteur}"/>
- <a href="secteur" class="autocompleteToSelect">{icon name="table" title="Tous les secteurs"}</a>
+ <input name="jobtermTxt" type="text" class="autocomplete{if $smarty.request.jobterm} hidden_valid{/if}" style="display:none" size="32"
+ value="{$smarty.request.jobtermTxt}"/>
+ <input name="jobterm" class="autocompleteTarget" type="hidden" value="{$smarty.request.jobterm}"/>
+ <a href="jobterm" class="autocompleteToSelect">{icon name="table" title="Tous les mots-clefs"}</a>
</td>
</tr>
<tr>
#!/usr/bin/php5
<?php
require_once 'connect.db.inc.php';
-require_once 'profil.func.inc.php';
+require_once 'class/jobterms.php';
$globals->debug = 0; //do not store backtraces
$terms = XDB::iterator('SELECT `jtid`, `name` FROM `profile_job_term_enum`');
while ($term = $terms->next()) {
- $tokens = array_unique(tokenize_job_term($term['name']));
+ $tokens = array_unique(JobTerms::tokenize($term['name']));
if (!count($tokens)) {
continue;
}